diff --git a/AUTHORS b/AUTHORS
index 0a2e5e4f..6703fd7c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -99,6 +99,7 @@
 Benjamin Dupont <bedupont@cisco.com>
 Benjamin Jemlich <pcgod99@gmail.com>
 Bernard Cafarelli <voyageur@gentoo.org>
+Bernhard M. Wiedemann <bwiedemann@suse.de>
 Bhagirathi Satpathy <bhagirathi.s@samsung.com>
 Bhanukrushana Rout <b.rout@samsung.com>
 Biljith Jayan <billy.jayan@samsung.com>
diff --git a/DEPS b/DEPS
index c8f0f1a4..6bb9bff 100644
--- a/DEPS
+++ b/DEPS
@@ -96,11 +96,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '868342d8543e907b118cf98d1e11fba88043d36a',
+  'catapult_revision': '656df4e2fcc877c34809f6018ab30ba5ddd0d623',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
-  'libfuzzer_revision': '16f5f743c188c836d32cdaf349d5d3effb8a3518',
+  'libfuzzer_revision': '6d39c6ba7f52b61664c982d6ac89d7491b6f8730',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-node-modules
   # and whatever else without interference from each other.
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
index ddf9ca0c..b12600a 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
@@ -31,6 +31,7 @@
 import org.chromium.android_webview.SafeBrowsingAction;
 import org.chromium.android_webview.test.TestAwContentsClient.OnReceivedError2Helper;
 import org.chromium.android_webview.test.util.GraphicsTestUtils;
+import org.chromium.base.LocaleUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -373,19 +374,21 @@
     }
 
     private void clickBackToSafety() {
-        final String script = "document.getElementById('primary-button').click();";
-        evaluateJavaScriptOnInterstitialOnUiThread(script, null);
+        clickLinkById("primary-button");
     }
 
     private void clickVisitUnsafePageQuietInterstitial() {
-        final String script = "document.getElementById('details-link').click();"
-                + "document.getElementById('proceed-link').click();";
-        evaluateJavaScriptOnInterstitialOnUiThread(script, null);
+        clickLinkById("details-link");
+        clickLinkById("proceed-link");
     }
 
     private void clickVisitUnsafePage() {
-        final String script = "document.getElementById('details-button').click();"
-                + "document.getElementById('proceed-link').click();";
+        clickLinkById("details-button");
+        clickLinkById("proceed-link");
+    }
+
+    private void clickLinkById(String id) {
+        final String script = "document.getElementById('" + id + "').click();";
         evaluateJavaScriptOnInterstitialOnUiThread(script, null);
     }
 
@@ -884,4 +887,80 @@
         mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(interstitialCount);
         waitForInterstitialToLoad();
     }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingClickLearnMoreLink() throws Throwable {
+        loadInterstitialAndClickLink(PHISHING_HTML_PATH, "learn-more-link",
+                appendLocale("https://support.google.com/chrome/?p=cpn_safe_browsing_wv"));
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingClickReportErrorLink() throws Throwable {
+        // Only phishing interstitials have the report-error-link
+        loadInterstitialAndClickLink(PHISHING_HTML_PATH, "report-error-link",
+                appendLocale("https://www.google.com/safebrowsing/report_error/"));
+    }
+
+    private String appendLocale(String url) throws Exception {
+        return Uri.parse(url)
+                .buildUpon()
+                .appendQueryParameter("hl", LocaleUtils.getDefaultLocaleString())
+                .toString();
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingClickDiagnosticLink() throws Throwable {
+        // Only malware interstitials have the diagnostic-link
+        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
+        final String diagnosticUrl =
+                Uri.parse("https://www.google.com/safebrowsing/diagnostic")
+                        .buildUpon()
+                        .appendQueryParameter("site", responseUrl)
+                        .appendQueryParameter("client", "chromium")
+                        .appendQueryParameter("hl", LocaleUtils.getDefaultLocaleString())
+                        .toString();
+        loadInterstitialAndClickLink(MALWARE_HTML_PATH, "diagnostic-link", diagnosticUrl);
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingClickWhitePaperLink() throws Throwable {
+        final String whitepaperUrl =
+                Uri.parse("https://www.google.com/chrome/browser/privacy/whitepaper.html")
+                        .buildUpon()
+                        .appendQueryParameter("hl", LocaleUtils.getDefaultLocaleString())
+                        .fragment("extendedreport")
+                        .toString();
+        loadInterstitialAndClickLink(PHISHING_HTML_PATH, "whitepaper-link", whitepaperUrl);
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingClickPrivacyPolicy() throws Throwable {
+        final String privacyPolicyUrl =
+                Uri.parse("https://www.google.com/chrome/browser/privacy/")
+                        .buildUpon()
+                        .appendQueryParameter("hl", LocaleUtils.getDefaultLocaleString())
+                        .fragment("safe-browsing-policies")
+                        .toString();
+        loadInterstitialAndClickLink(PHISHING_HTML_PATH, "privacy-link", privacyPolicyUrl);
+    }
+
+    private void loadInterstitialAndClickLink(String path, String linkId, String linkUrl)
+            throws Exception {
+        loadPathAndWaitForInterstitial(path);
+        waitForInterstitialToLoad();
+        int pageFinishedCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
+        clickLinkById(linkId);
+        mContentsClient.getOnPageFinishedHelper().waitForCallback(pageFinishedCount);
+        assertEquals(linkUrl, mAwContents.getUrl());
+    }
 }
diff --git a/ash/highlighter/highlighter_controller_unittest.cc b/ash/highlighter/highlighter_controller_unittest.cc
index 93e405f7..dd3b8a6 100644
--- a/ash/highlighter/highlighter_controller_unittest.cc
+++ b/ash/highlighter/highlighter_controller_unittest.cc
@@ -23,18 +23,19 @@
   void SetUp() override {
     AshTestBase::SetUp();
     controller_ = base::MakeUnique<HighlighterController>();
+    controller_test_api_ =
+        base::MakeUnique<HighlighterControllerTestApi>(controller_.get());
   }
 
   void TearDown() override {
     // This needs to be called first to remove the event handler before the
     // shell instance gets torn down.
+    controller_test_api_.reset();
     controller_.reset();
     AshTestBase::TearDown();
   }
 
  protected:
-  std::unique_ptr<HighlighterController> controller_;
-
   void TraceRect(const gfx::Rect& rect) {
     GetEventGenerator().MoveTouch(gfx::Point(rect.x(), rect.y()));
     GetEventGenerator().PressTouch();
@@ -45,6 +46,9 @@
     GetEventGenerator().ReleaseTouch();
   }
 
+  std::unique_ptr<HighlighterController> controller_;
+  std::unique_ptr<HighlighterControllerTestApi> controller_test_api_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HighlighterControllerTest);
 };
@@ -54,100 +58,96 @@
 // Test to ensure the class responsible for drawing the highlighter pointer
 // receives points from stylus movements as expected.
 TEST_F(HighlighterControllerTest, HighlighterRenderer) {
-  HighlighterControllerTestApi controller_test_api_(controller_.get());
-
   // The highlighter pointer mode only works with stylus.
   GetEventGenerator().EnterPenPointerMode();
 
   // When disabled the highlighter pointer should not be showing.
   GetEventGenerator().MoveTouch(gfx::Point(1, 1));
-  EXPECT_FALSE(controller_test_api_.IsShowingHighlighter());
+  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
 
   // Verify that by enabling the mode, the highlighter pointer should still not
   // be showing.
-  controller_test_api_.SetEnabled(true);
-  EXPECT_FALSE(controller_test_api_.IsShowingHighlighter());
+  controller_test_api_->SetEnabled(true);
+  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
 
   // Verify moving the stylus 4 times will not display the highlighter pointer.
   GetEventGenerator().MoveTouch(gfx::Point(2, 2));
   GetEventGenerator().MoveTouch(gfx::Point(3, 3));
   GetEventGenerator().MoveTouch(gfx::Point(4, 4));
   GetEventGenerator().MoveTouch(gfx::Point(5, 5));
-  EXPECT_FALSE(controller_test_api_.IsShowingHighlighter());
+  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
 
   // Verify pressing the stylus will show the highlighter pointer and add a
   // point but will not activate fading out.
   GetEventGenerator().PressTouch();
-  EXPECT_TRUE(controller_test_api_.IsShowingHighlighter());
-  EXPECT_FALSE(controller_test_api_.IsFadingAway());
-  EXPECT_EQ(1, controller_test_api_.points().GetNumberOfPoints());
+  EXPECT_TRUE(controller_test_api_->IsShowingHighlighter());
+  EXPECT_FALSE(controller_test_api_->IsFadingAway());
+  EXPECT_EQ(1, controller_test_api_->points().GetNumberOfPoints());
 
   // Verify dragging the stylus 2 times will add 2 more points.
   GetEventGenerator().MoveTouch(gfx::Point(6, 6));
   GetEventGenerator().MoveTouch(gfx::Point(7, 7));
-  EXPECT_EQ(3, controller_test_api_.points().GetNumberOfPoints());
+  EXPECT_EQ(3, controller_test_api_->points().GetNumberOfPoints());
 
   // Verify releasing the stylus still shows the highlighter pointer, which is
   // fading away.
   GetEventGenerator().ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_.IsShowingHighlighter());
-  EXPECT_TRUE(controller_test_api_.IsFadingAway());
+  EXPECT_TRUE(controller_test_api_->IsShowingHighlighter());
+  EXPECT_TRUE(controller_test_api_->IsFadingAway());
 
   // Verify that disabling the mode does not display the highlighter pointer.
-  controller_test_api_.SetEnabled(false);
-  EXPECT_FALSE(controller_test_api_.IsShowingHighlighter());
-  EXPECT_FALSE(controller_test_api_.IsFadingAway());
+  controller_test_api_->SetEnabled(false);
+  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
+  EXPECT_FALSE(controller_test_api_->IsFadingAway());
 
   // Verify that disabling the mode while highlighter pointer is displayed does
   // not display the highlighter pointer.
-  controller_test_api_.SetEnabled(true);
+  controller_test_api_->SetEnabled(true);
   GetEventGenerator().PressTouch();
   GetEventGenerator().MoveTouch(gfx::Point(6, 6));
-  EXPECT_TRUE(controller_test_api_.IsShowingHighlighter());
-  controller_test_api_.SetEnabled(false);
-  EXPECT_FALSE(controller_test_api_.IsShowingHighlighter());
+  EXPECT_TRUE(controller_test_api_->IsShowingHighlighter());
+  controller_test_api_->SetEnabled(false);
+  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
 
   // Verify that the highlighter pointer does not add points while disabled.
   GetEventGenerator().PressTouch();
   GetEventGenerator().MoveTouch(gfx::Point(8, 8));
   GetEventGenerator().ReleaseTouch();
   GetEventGenerator().MoveTouch(gfx::Point(9, 9));
-  EXPECT_FALSE(controller_test_api_.IsShowingHighlighter());
+  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
 
   // Verify that the highlighter pointer does not get shown if points are not
   // coming from the stylus, even when enabled.
   GetEventGenerator().ExitPenPointerMode();
-  controller_test_api_.SetEnabled(true);
+  controller_test_api_->SetEnabled(true);
   GetEventGenerator().PressTouch();
   GetEventGenerator().MoveTouch(gfx::Point(10, 10));
   GetEventGenerator().MoveTouch(gfx::Point(11, 11));
-  EXPECT_FALSE(controller_test_api_.IsShowingHighlighter());
+  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
   GetEventGenerator().ReleaseTouch();
 }
 
 // Test to ensure the class responsible for drawing the highlighter pointer
 // handles prediction as expected when it receives points from stylus movements.
 TEST_F(HighlighterControllerTest, HighlighterPrediction) {
-  HighlighterControllerTestApi controller_test_api_(controller_.get());
-
-  controller_test_api_.SetEnabled(true);
+  controller_test_api_->SetEnabled(true);
   // The highlighter pointer mode only works with stylus.
   GetEventGenerator().EnterPenPointerMode();
   GetEventGenerator().PressTouch();
-  EXPECT_TRUE(controller_test_api_.IsShowingHighlighter());
+  EXPECT_TRUE(controller_test_api_->IsShowingHighlighter());
 
-  EXPECT_EQ(1, controller_test_api_.points().GetNumberOfPoints());
+  EXPECT_EQ(1, controller_test_api_->points().GetNumberOfPoints());
   // Initial press event shouldn't generate any predicted points as there's no
   // history to use for prediction.
-  EXPECT_EQ(0, controller_test_api_.predicted_points().GetNumberOfPoints());
+  EXPECT_EQ(0, controller_test_api_->predicted_points().GetNumberOfPoints());
 
   // Verify dragging the stylus 3 times will add some predicted points.
   GetEventGenerator().MoveTouch(gfx::Point(10, 10));
   GetEventGenerator().MoveTouch(gfx::Point(20, 20));
   GetEventGenerator().MoveTouch(gfx::Point(30, 30));
-  EXPECT_NE(0, controller_test_api_.predicted_points().GetNumberOfPoints());
+  EXPECT_NE(0, controller_test_api_->predicted_points().GetNumberOfPoints());
   // Verify predicted points are in the right direction.
-  for (const auto& point : controller_test_api_.predicted_points().points()) {
+  for (const auto& point : controller_test_api_->predicted_points().points()) {
     EXPECT_LT(30, point.location.x());
     EXPECT_LT(30, point.location.y());
   }
@@ -155,45 +155,43 @@
 
 // Test that stylus gestures are correctly recognized by HighlighterController.
 TEST_F(HighlighterControllerTest, HighlighterGestures) {
-  HighlighterControllerTestApi controller_test_api_(controller_.get());
-
-  controller_test_api_.SetEnabled(true);
+  controller_test_api_->SetEnabled(true);
   GetEventGenerator().EnterPenPointerMode();
 
   // A non-horizontal stroke is not recognized
-  controller_test_api_.ResetSelection();
+  controller_test_api_->ResetSelection();
   GetEventGenerator().MoveTouch(gfx::Point(100, 100));
   GetEventGenerator().PressTouch();
   GetEventGenerator().MoveTouch(gfx::Point(200, 200));
   GetEventGenerator().ReleaseTouch();
-  EXPECT_FALSE(controller_test_api_.handle_selection_called());
+  EXPECT_FALSE(controller_test_api_->handle_selection_called());
 
   // An almost horizontal stroke is recognized
-  controller_test_api_.ResetSelection();
+  controller_test_api_->ResetSelection();
   GetEventGenerator().MoveTouch(gfx::Point(100, 100));
   GetEventGenerator().PressTouch();
   GetEventGenerator().MoveTouch(gfx::Point(300, 102));
   GetEventGenerator().ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_.handle_selection_called());
+  EXPECT_TRUE(controller_test_api_->handle_selection_called());
 
   // Horizontal stroke selection rectangle should:
   //   have the same horizontal center line as the stroke bounding box,
   //   be 4dp wider than the stroke bounding box,
   //   be exactly 14dp high.
-  EXPECT_EQ("98,94 204x14", controller_test_api_.selection().ToString());
+  EXPECT_EQ("98,94 204x14", controller_test_api_->selection().ToString());
 
   // An insufficiently closed C-like shape is not recognized
-  controller_test_api_.ResetSelection();
+  controller_test_api_->ResetSelection();
   GetEventGenerator().MoveTouch(gfx::Point(100, 0));
   GetEventGenerator().PressTouch();
   GetEventGenerator().MoveTouch(gfx::Point(0, 0));
   GetEventGenerator().MoveTouch(gfx::Point(0, 100));
   GetEventGenerator().MoveTouch(gfx::Point(100, 100));
   GetEventGenerator().ReleaseTouch();
-  EXPECT_FALSE(controller_test_api_.handle_selection_called());
+  EXPECT_FALSE(controller_test_api_->handle_selection_called());
 
   // An almost closed G-like shape is recognized
-  controller_test_api_.ResetSelection();
+  controller_test_api_->ResetSelection();
   GetEventGenerator().MoveTouch(gfx::Point(200, 0));
   GetEventGenerator().PressTouch();
   GetEventGenerator().MoveTouch(gfx::Point(0, 0));
@@ -201,11 +199,11 @@
   GetEventGenerator().MoveTouch(gfx::Point(200, 100));
   GetEventGenerator().MoveTouch(gfx::Point(200, 20));
   GetEventGenerator().ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_.handle_selection_called());
-  EXPECT_EQ("0,0 200x100", controller_test_api_.selection().ToString());
+  EXPECT_TRUE(controller_test_api_->handle_selection_called());
+  EXPECT_EQ("0,0 200x100", controller_test_api_->selection().ToString());
 
   // A closed diamond shape is recognized
-  controller_test_api_.ResetSelection();
+  controller_test_api_->ResetSelection();
   GetEventGenerator().MoveTouch(gfx::Point(100, 0));
   GetEventGenerator().PressTouch();
   GetEventGenerator().MoveTouch(gfx::Point(200, 150));
@@ -213,15 +211,13 @@
   GetEventGenerator().MoveTouch(gfx::Point(0, 150));
   GetEventGenerator().MoveTouch(gfx::Point(100, 0));
   GetEventGenerator().ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_.handle_selection_called());
-  EXPECT_EQ("0,0 200x300", controller_test_api_.selection().ToString());
+  EXPECT_TRUE(controller_test_api_->handle_selection_called());
+  EXPECT_EQ("0,0 200x300", controller_test_api_->selection().ToString());
 }
 
 // Test that stylus gesture recognition correctly handles display scaling
 TEST_F(HighlighterControllerTest, HighlighterGesturesScaled) {
-  HighlighterControllerTestApi controller_test_api_(controller_.get());
-
-  controller_test_api_.SetEnabled(true);
+  controller_test_api_->SetEnabled(true);
   GetEventGenerator().EnterPenPointerMode();
 
   const gfx::Rect original_rect(200, 100, 400, 300);
@@ -244,11 +240,11 @@
       SCOPED_TRACE(display_spec);
       UpdateDisplay(display_spec);
 
-      controller_test_api_.ResetSelection();
+      controller_test_api_->ResetSelection();
       TraceRect(original_rect);
-      EXPECT_TRUE(controller_test_api_.handle_selection_called());
+      EXPECT_TRUE(controller_test_api_->handle_selection_called());
 
-      const gfx::Rect selection = controller_test_api_.selection();
+      const gfx::Rect selection = controller_test_api_->selection();
       EXPECT_TRUE(inflated.Contains(selection));
       EXPECT_TRUE(selection.Contains(original_rect));
     }
@@ -257,40 +253,38 @@
 
 // Test that stylus gesture recognition correctly handles display rotation
 TEST_F(HighlighterControllerTest, HighlighterGesturesRotated) {
-  HighlighterControllerTestApi controller_test_api_(controller_.get());
-
-  controller_test_api_.SetEnabled(true);
+  controller_test_api_->SetEnabled(true);
   GetEventGenerator().EnterPenPointerMode();
 
   const gfx::Rect trace(200, 100, 400, 300);
 
   // No rotation
   UpdateDisplay("1500x1000");
-  controller_test_api_.ResetSelection();
+  controller_test_api_->ResetSelection();
   TraceRect(trace);
-  EXPECT_TRUE(controller_test_api_.handle_selection_called());
-  EXPECT_EQ("200,100 400x300", controller_test_api_.selection().ToString());
+  EXPECT_TRUE(controller_test_api_->handle_selection_called());
+  EXPECT_EQ("200,100 400x300", controller_test_api_->selection().ToString());
 
   // Rotate to 90 degrees
   UpdateDisplay("1500x1000/r");
-  controller_test_api_.ResetSelection();
+  controller_test_api_->ResetSelection();
   TraceRect(trace);
-  EXPECT_TRUE(controller_test_api_.handle_selection_called());
-  EXPECT_EQ("100,899 300x400", controller_test_api_.selection().ToString());
+  EXPECT_TRUE(controller_test_api_->handle_selection_called());
+  EXPECT_EQ("100,899 300x400", controller_test_api_->selection().ToString());
 
   // Rotate to 180 degrees
   UpdateDisplay("1500x1000/u");
-  controller_test_api_.ResetSelection();
+  controller_test_api_->ResetSelection();
   TraceRect(trace);
-  EXPECT_TRUE(controller_test_api_.handle_selection_called());
-  EXPECT_EQ("899,599 400x300", controller_test_api_.selection().ToString());
+  EXPECT_TRUE(controller_test_api_->handle_selection_called());
+  EXPECT_EQ("899,599 400x300", controller_test_api_->selection().ToString());
 
   // Rotate to 270 degrees
   UpdateDisplay("1500x1000/l");
-  controller_test_api_.ResetSelection();
+  controller_test_api_->ResetSelection();
   TraceRect(trace);
-  EXPECT_TRUE(controller_test_api_.handle_selection_called());
-  EXPECT_EQ("599,200 300x400", controller_test_api_.selection().ToString());
+  EXPECT_TRUE(controller_test_api_->handle_selection_called());
+  EXPECT_EQ("599,200 300x400", controller_test_api_->selection().ToString());
 }
 
 }  // namespace ash
diff --git a/ash/public/interfaces/shutdown.mojom b/ash/public/interfaces/shutdown.mojom
index 4785e773..11437eb 100644
--- a/ash/public/interfaces/shutdown.mojom
+++ b/ash/public/interfaces/shutdown.mojom
@@ -11,4 +11,8 @@
   // when the user initiates a shutdown via an UI element. Used in enterprise
   // environments for devices that should not be shut down.
   SetRebootOnShutdown(bool reboot_on_shutdown);
+
+  // Triggers an animated shutdown after the login screen shutdown button was
+  // pressed.
+  RequestShutdownFromLoginScreen();
 };
diff --git a/ash/shutdown_controller.cc b/ash/shutdown_controller.cc
index d4db1493..cb87a47 100644
--- a/ash/shutdown_controller.cc
+++ b/ash/shutdown_controller.cc
@@ -9,6 +9,7 @@
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/shutdown_reason.h"
+#include "ash/wm/lock_state_controller.h"
 #include "base/sys_info.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager_client.h"
@@ -43,6 +44,11 @@
   reboot_on_shutdown_ = reboot_on_shutdown;
 }
 
+void ShutdownController::RequestShutdownFromLoginScreen() {
+  Shell::Get()->lock_state_controller()->RequestShutdown(
+      ShutdownReason::LOGIN_SHUT_DOWN_BUTTON);
+}
+
 void ShutdownController::BindRequest(mojom::ShutdownControllerRequest request) {
   bindings_.AddBinding(this, std::move(request));
 }
diff --git a/ash/shutdown_controller.h b/ash/shutdown_controller.h
index d9bf176c..0e46284 100644
--- a/ash/shutdown_controller.h
+++ b/ash/shutdown_controller.h
@@ -36,6 +36,7 @@
  private:
   // mojom::ShutdownController:
   void SetRebootOnShutdown(bool reboot_on_shutdown) override;
+  void RequestShutdownFromLoginScreen() override;
 
   // Cached copy of the DeviceRebootOnShutdown policy from chrome.
   bool reboot_on_shutdown_ = false;
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc
index 5e53490b..ec6b4786 100644
--- a/ash/system/palette/palette_tray_unittest.cc
+++ b/ash/system/palette/palette_tray_unittest.cc
@@ -5,6 +5,8 @@
 #include "ash/system/palette/palette_tray.h"
 
 #include "ash/ash_switches.h"
+#include "ash/highlighter/highlighter_controller.h"
+#include "ash/highlighter/highlighter_controller_test_api.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/config.h"
 #include "ash/session/test_session_controller_client.h"
@@ -66,6 +68,10 @@
   }
 
  protected:
+  TestPaletteDelegate* test_palette_delegate() {
+    return static_cast<TestPaletteDelegate*>(Shell::Get()->palette_delegate());
+  }
+
   PaletteTray* palette_tray_ = nullptr;  // not owned
   TestingPrefServiceSimple pref_service_;
 
@@ -184,6 +190,76 @@
   EXPECT_FALSE(palette_tray_->is_active());
 }
 
+TEST_F(PaletteTrayTest, MetalayerToolActivatesHighlighter) {
+  HighlighterController highlighter_controller;
+  HighlighterControllerTestApi highlighter_test_api(&highlighter_controller);
+  test_palette_delegate()->set_highlighter_test_api(&highlighter_test_api);
+  GetEventGenerator().EnterPenPointerMode();
+
+  test_palette_delegate()->SetMetalayerSupported(true);
+
+  // Press/drag does not activate the highlighter unless the palette tool is
+  // activated.
+  GetEventGenerator().MoveTouch(gfx::Point(1, 1));
+  GetEventGenerator().PressTouch();
+  EXPECT_FALSE(highlighter_test_api.IsShowingHighlighter());
+  GetEventGenerator().MoveTouch(gfx::Point(2, 2));
+  EXPECT_FALSE(highlighter_test_api.IsShowingHighlighter());
+  GetEventGenerator().ReleaseTouch();
+
+  // Activate the palette tool, still no highlighter.
+  test_api_->GetPaletteToolManager()->ActivateTool(PaletteToolId::METALAYER);
+  EXPECT_FALSE(highlighter_test_api.IsShowingHighlighter());
+
+  // Press over a regular (non-palette) location. This should activate the
+  // highlighter.
+  EXPECT_FALSE(palette_utils::PaletteContainsPointInScreen(gfx::Point(1, 1)));
+  GetEventGenerator().MoveTouch(gfx::Point(1, 1));
+  GetEventGenerator().PressTouch();
+  EXPECT_TRUE(highlighter_test_api.IsShowingHighlighter());
+  GetEventGenerator().ReleaseTouch();
+
+  // Disable/enable the palette tool to hide the highlighter.
+  test_api_->GetPaletteToolManager()->DeactivateTool(PaletteToolId::METALAYER);
+  test_api_->GetPaletteToolManager()->ActivateTool(PaletteToolId::METALAYER);
+  EXPECT_FALSE(highlighter_test_api.IsShowingHighlighter());
+
+  // Press/drag over the palette button. This should not activate the
+  // highlighter.
+  gfx::Point palette_point = palette_tray_->GetBoundsInScreen().CenterPoint();
+  EXPECT_TRUE(palette_utils::PaletteContainsPointInScreen(palette_point));
+  GetEventGenerator().MoveTouch(palette_point);
+  GetEventGenerator().PressTouch();
+  EXPECT_FALSE(highlighter_test_api.IsShowingHighlighter());
+  palette_point += gfx::Vector2d(1, 1);
+  EXPECT_TRUE(palette_utils::PaletteContainsPointInScreen(palette_point));
+  GetEventGenerator().MoveTouch(palette_point);
+  EXPECT_FALSE(highlighter_test_api.IsShowingHighlighter());
+  GetEventGenerator().ReleaseTouch();
+
+  // The previous gesture should have disabled the palette tool.
+  EXPECT_FALSE(test_api_->GetPaletteToolManager()->IsToolActive(
+      PaletteToolId::METALAYER));
+
+  // Disabling metalayer support in the delegate should disable the palette
+  // tool.
+  test_api_->GetPaletteToolManager()->ActivateTool(PaletteToolId::METALAYER);
+  test_palette_delegate()->SetMetalayerSupported(false);
+  EXPECT_FALSE(test_api_->GetPaletteToolManager()->IsToolActive(
+      PaletteToolId::METALAYER));
+
+  // With the metalayer disabled again, press/drag does not activate the
+  // highlighter.
+  GetEventGenerator().MoveTouch(gfx::Point(1, 1));
+  GetEventGenerator().PressTouch();
+  EXPECT_FALSE(highlighter_test_api.IsShowingHighlighter());
+  GetEventGenerator().MoveTouch(gfx::Point(2, 2));
+  EXPECT_FALSE(highlighter_test_api.IsShowingHighlighter());
+  GetEventGenerator().ReleaseTouch();
+
+  test_palette_delegate()->set_highlighter_test_api(nullptr);
+}
+
 // Base class for tests that need to simulate an internal stylus.
 class PaletteTrayTestWithInternalStylus : public PaletteTrayTest {
  public:
diff --git a/ash/system/palette/test_palette_delegate.cc b/ash/system/palette/test_palette_delegate.cc
index 99e43ec..fa68435 100644
--- a/ash/system/palette/test_palette_delegate.cc
+++ b/ash/system/palette/test_palette_delegate.cc
@@ -4,12 +4,21 @@
 
 #include "ash/system/palette/test_palette_delegate.h"
 
+#include "ash/highlighter/highlighter_controller_test_api.h"
+#include "base/callback_helpers.h"
+
 namespace ash {
 
 TestPaletteDelegate::TestPaletteDelegate() {}
 
 TestPaletteDelegate::~TestPaletteDelegate() {}
 
+void TestPaletteDelegate::SetMetalayerSupported(bool supported) {
+  is_metalayer_supported_ = supported;
+  if (!is_metalayer_supported_ && !metalayer_closed_.is_null())
+    base::ResetAndReturn(&metalayer_closed_).Run();
+}
+
 std::unique_ptr<PaletteDelegate::EnableListenerSubscription>
 TestPaletteDelegate::AddPaletteEnableListener(
     const EnableListener& on_state_changed) {
@@ -51,10 +60,15 @@
 void TestPaletteDelegate::ShowMetalayer(const base::Closure& closed) {
   ++show_metalayer_count_;
   metalayer_closed_ = closed;
+  if (highlighter_test_api_)
+    highlighter_test_api_->SetEnabled(true);
 }
 
 void TestPaletteDelegate::HideMetalayer() {
   ++hide_metalayer_count_;
+  metalayer_closed_ = base::Closure();
+  if (highlighter_test_api_)
+    highlighter_test_api_->SetEnabled(false);
 }
 
 }  // namespace ash
diff --git a/ash/system/palette/test_palette_delegate.h b/ash/system/palette/test_palette_delegate.h
index 39e3fa4..a4bb26d 100644
--- a/ash/system/palette/test_palette_delegate.h
+++ b/ash/system/palette/test_palette_delegate.h
@@ -10,6 +10,8 @@
 
 namespace ash {
 
+class HighlighterControllerTestApi;
+
 // A simple test double for a PaletteDelegate.
 class TestPaletteDelegate : public PaletteDelegate {
  public:
@@ -40,9 +42,7 @@
     should_show_palette_ = should_show_palette;
   }
 
-  void set_is_metalayer_supported(bool is_metalayer_supported) {
-    is_metalayer_supported_ = is_metalayer_supported;
-  }
+  void SetMetalayerSupported(bool is_metalayer_supported);
 
   int show_metalayer_count() const { return show_metalayer_count_; }
 
@@ -50,7 +50,11 @@
 
   base::Closure metalayer_closed() const { return metalayer_closed_; }
 
- private:
+  void set_highlighter_test_api(HighlighterControllerTestApi* api) {
+    highlighter_test_api_ = api;
+  }
+
+ protected:
   // PaletteDelegate:
   std::unique_ptr<EnableListenerSubscription> AddPaletteEnableListener(
       const EnableListener& on_state_changed) override;
@@ -78,6 +82,8 @@
   int hide_metalayer_count_ = 0;
   base::Closure metalayer_closed_;
 
+  HighlighterControllerTestApi* highlighter_test_api_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(TestPaletteDelegate);
 };
 
diff --git a/ash/system/palette/tools/metalayer_unittest.cc b/ash/system/palette/tools/metalayer_unittest.cc
index 1785dbc..1c999dc 100644
--- a/ash/system/palette/tools/metalayer_unittest.cc
+++ b/ash/system/palette/tools/metalayer_unittest.cc
@@ -49,11 +49,11 @@
 
 // The metalayer tool is only visible when the delegate supports metalayer.
 TEST_F(MetalayerToolTest, ViewOnlyCreatedWhenMetalayerIsSupported) {
-  test_palette_delegate()->set_is_metalayer_supported(false);
+  test_palette_delegate()->SetMetalayerSupported(false);
   EXPECT_FALSE(tool_->CreateView());
   tool_->OnViewDestroyed();
 
-  test_palette_delegate()->set_is_metalayer_supported(true);
+  test_palette_delegate()->SetMetalayerSupported(true);
   std::unique_ptr<views::View> view = base::WrapUnique(tool_->CreateView());
   EXPECT_TRUE(view);
   tool_->OnViewDestroyed();
@@ -85,4 +85,15 @@
   test_palette_delegate()->metalayer_closed().Run();
 }
 
+// Verifies that disabling the metalayer support in the delegate disables the
+// tool.
+TEST_F(MetalayerToolTest, MetalayerUnsupportedDisablesPaletteTool) {
+  test_palette_delegate()->SetMetalayerSupported(true);
+  tool_->OnEnable();
+  // Disabling the metalayer support in the delegate will disable the tool.
+  EXPECT_CALL(*palette_tool_delegate_.get(),
+              DisableTool(PaletteToolId::METALAYER));
+  test_palette_delegate()->SetMetalayerSupported(false);
+}
+
 }  // namespace ash
diff --git a/base/debug/stack_trace_fuchsia.cc b/base/debug/stack_trace_fuchsia.cc
index 42810fc..a94821e 100644
--- a/base/debug/stack_trace_fuchsia.cc
+++ b/base/debug/stack_trace_fuchsia.cc
@@ -108,7 +108,7 @@
     DPLOG(WARNING)
         << "Couldn't get name, falling back to 'app' for program name: "
         << status;
-    strlcpy(app_name, "app", sizeof(app_name));
+    strlcat(app_name, "app", sizeof(app_name));
   }
 
   // Retrieve the debug info struct.
@@ -139,8 +139,7 @@
 
     next_entry->addr = reinterpret_cast<void*>(lmap->l_addr);
     char* name_to_use = lmap->l_name[0] ? lmap->l_name : app_name;
-    size_t name_len = strnlen(name_to_use, MX_MAX_NAME_LEN);
-    strncpy(next_entry->name, name_to_use, name_len + 1);
+    strlcpy(next_entry->name, name_to_use, sizeof(next_entry->name));
     lmap = lmap->l_next;
   }
 
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 3682733..19891b8b 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -662,17 +662,19 @@
 
   if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
                               &declared_max, &bucket_count, &range_checksum)) {
-    return NULL;
+    return nullptr;
   }
 
   // Find or create the local version of the histogram in this process.
   HistogramBase* histogram = Histogram::FactoryGet(
       histogram_name, declared_min, declared_max, bucket_count, flags);
+  if (!histogram)
+    return nullptr;
 
-  if (!ValidateRangeChecksum(*histogram, range_checksum)) {
-    // The serialized histogram might be corrupted.
-    return NULL;
-  }
+  // The serialized histogram might be corrupted.
+  if (!ValidateRangeChecksum(*histogram, range_checksum))
+    return nullptr;
+
   return histogram;
 }
 
@@ -886,8 +888,8 @@
                                            Sample maximum,
                                            uint32_t bucket_count,
                                            int32_t flags) {
-  return FactoryGetWithRangeDescription(
-      name, minimum, maximum, bucket_count, flags, NULL);
+  return FactoryGetWithRangeDescription(name, minimum, maximum, bucket_count,
+                                        flags, nullptr);
 }
 
 HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
@@ -1023,14 +1025,14 @@
 
   if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
                               &declared_max, &bucket_count, &range_checksum)) {
-    return NULL;
+    return nullptr;
   }
 
   HistogramBase* histogram = LinearHistogram::FactoryGet(
       histogram_name, declared_min, declared_max, bucket_count, flags);
   if (!ValidateRangeChecksum(*histogram, range_checksum)) {
     // The serialized histogram might be corrupted.
-    return NULL;
+    return nullptr;
   }
   return histogram;
 }
@@ -1115,14 +1117,14 @@
 
   if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
                               &declared_max, &bucket_count, &range_checksum)) {
-    return NULL;
+    return nullptr;
   }
 
   HistogramBase* histogram = BooleanHistogram::FactoryGet(
       histogram_name, flags);
   if (!ValidateRangeChecksum(*histogram, range_checksum)) {
     // The serialized histogram might be corrupted.
-    return NULL;
+    return nullptr;
   }
   return histogram;
 }
@@ -1267,7 +1269,7 @@
 
   if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
                               &declared_max, &bucket_count, &range_checksum)) {
-    return NULL;
+    return nullptr;
   }
 
   // First and last ranges are not serialized.
@@ -1275,14 +1277,14 @@
 
   for (uint32_t i = 0; i < sample_ranges.size(); ++i) {
     if (!iter->ReadInt(&sample_ranges[i]))
-      return NULL;
+      return nullptr;
   }
 
   HistogramBase* histogram = CustomHistogram::FactoryGet(
       histogram_name, sample_ranges, flags);
   if (!ValidateRangeChecksum(*histogram, range_checksum)) {
     // The serialized histogram might be corrupted.
-    return NULL;
+    return nullptr;
   }
   return histogram;
 }
diff --git a/base/threading/platform_thread_fuchsia.cc b/base/threading/platform_thread_fuchsia.cc
index 075a8ad..6a9ed18 100644
--- a/base/threading/platform_thread_fuchsia.cc
+++ b/base/threading/platform_thread_fuchsia.cc
@@ -9,6 +9,7 @@
 
 #include "base/threading/platform_thread_internal_posix.h"
 #include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
 
 namespace base {
 
@@ -50,8 +51,9 @@
 // static
 void PlatformThread::SetName(const std::string& name) {
   // TODO(fuchsia): There's no system-level API to communicate a thread name
-  // (for the debugger, etc.), so for now only set to our internal mechanism.
+  // (for the debugger, etc.), so for now only set to our internal mechanisms.
   ThreadIdNameManager::GetInstance()->SetName(pthread_self(), name);
+  tracked_objects::ThreadData::InitializeThreadContext(name);
 }
 
 }  // namespace base
diff --git a/build/android/adb_gdb b/build/android/adb_gdb
index 9c20e4dd..7b9e491 100755
--- a/build/android/adb_gdb
+++ b/build/android/adb_gdb
@@ -824,14 +824,6 @@
   fi
 fi
 
-# Extract the system libraries from the device if necessary.
-if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
-  echo "Extracting system libraries into: $PULL_LIBS_DIR"
-fi
-
-mkdir -p "$PULL_LIBS_DIR"
-fail_panic "Can't create --libs-dir directory: $PULL_LIBS_DIR"
-
 # If requested, work for M-x gdb.  The gdb indirections make it
 # difficult to pass --annotate=3 to the gdb binary itself.
 GDB_ARGS=
@@ -906,6 +898,9 @@
 log "Command prefix: '$COMMAND_PREFIX'"
 log "Command suffix: '$COMMAND_SUFFIX'"
 
+mkdir -p "$PULL_LIBS_DIR"
+fail_panic "Can't create --libs-dir directory: $PULL_LIBS_DIR"
+
 # Pull device's system libraries that are mapped by our process.
 # Pulling all system libraries is too long, so determine which ones
 # we need by looking at /proc/$PID/maps instead
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 47f5ed26e64..971edb0d 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1205,6 +1205,11 @@
         # TODO(thakis ): https://crbug.com/683349
         "-Wno-user-defined-warnings",
       ]
+
+      if (llvm_force_head_revision) {
+        # TODO(thakis): https://crbug.com/753973
+        cflags += [ "-Wno-enum-compare-switch" ]
+      }
     } else if (use_xcode_clang && xcode_version_int >= 830) {
       # This is necessary to allow a progressive transition from using xcode 8.0
       # to 8.3 or more recent. Remove when all bots are migrated to 8.3.
diff --git a/build/config/ui.gni b/build/config/ui.gni
index ce384b5..77e18f5 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -27,11 +27,11 @@
   # Indicates if Ozone is enabled. Ozone is a low-level library layer for Linux
   # that does not require X11. Enabling this feature disables use of glib, x11,
   # Pango, and Cairo. Default to false on non-Chromecast builds.
-  use_ozone = is_chromeos || (is_chromecast && !is_android)
+  use_ozone = is_chromeos || (is_chromecast && !is_android) || is_fuchsia
 
   # Indicates if Aura is enabled. Aura is a low-level windowing library, sort
   # of a replacement for GDI or GTK.
-  use_aura = is_win || is_linux
+  use_aura = is_win || is_linux || is_fuchsia
 
   # Whether we should use glib, a low level C utility library.
   use_glib = is_linux
@@ -39,8 +39,8 @@
 
 declare_args() {
   # True means the UI is built using the "views" framework.
-  toolkit_views =
-      (is_mac || is_win || is_chromeos || use_aura) && !is_chromecast
+  toolkit_views = (is_mac || is_win || is_chromeos || use_aura) &&
+                  !is_chromecast && !is_fuchsia
 }
 
 # Additional dependent variables -----------------------------------------------
diff --git a/cc/base/filter_operation.cc b/cc/base/filter_operation.cc
index 5966ea4..70fe172 100644
--- a/cc/base/filter_operation.cc
+++ b/cc/base/filter_operation.cc
@@ -82,7 +82,7 @@
   memset(matrix_, 0, sizeof(matrix_));
 }
 
-FilterOperation::FilterOperation(FilterType type, SkScalar matrix[20])
+FilterOperation::FilterOperation(FilterType type, const Matrix& matrix)
     : type_(type),
       amount_(0),
       outer_threshold_(0),
@@ -171,8 +171,7 @@
       return FilterOperation::CreateDropShadowFilter(gfx::Point(0, 0), 0.f,
                                                      SK_ColorTRANSPARENT);
     case FilterOperation::COLOR_MATRIX: {
-      SkScalar matrix[20];
-      memset(matrix, 0, 20 * sizeof(SkScalar));
+      FilterOperation::Matrix matrix = {};
       matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
       return FilterOperation::CreateColorMatrixFilter(matrix);
     }
diff --git a/cc/base/filter_operation.h b/cc/base/filter_operation.h
index b04980b8..ff23a24 100644
--- a/cc/base/filter_operation.h
+++ b/cc/base/filter_operation.h
@@ -30,6 +30,7 @@
 
 class CC_BASE_EXPORT FilterOperation {
  public:
+  using Matrix = SkScalar[20];
   enum FilterType {
     GRAYSCALE,
     SEPIA,
@@ -83,7 +84,7 @@
     return image_filter_;
   }
 
-  const SkScalar* matrix() const {
+  const Matrix& matrix() const {
     DCHECK_EQ(type_, COLOR_MATRIX);
     return matrix_;
   }
@@ -148,7 +149,7 @@
     return FilterOperation(DROP_SHADOW, offset, std_deviation, color);
   }
 
-  static FilterOperation CreateColorMatrixFilter(SkScalar matrix[20]) {
+  static FilterOperation CreateColorMatrixFilter(const Matrix& matrix) {
     return FilterOperation(COLOR_MATRIX, matrix);
   }
 
@@ -211,7 +212,7 @@
     image_filter_ = std::move(image_filter);
   }
 
-  void set_matrix(const SkScalar matrix[20]) {
+  void set_matrix(const Matrix& matrix) {
     DCHECK_EQ(type_, COLOR_MATRIX);
     for (unsigned i = 0; i < 20; ++i)
       matrix_[i] = matrix[i];
@@ -264,7 +265,7 @@
                   float stdDeviation,
                   SkColor color);
 
-  FilterOperation(FilterType, SkScalar matrix[20]);
+  FilterOperation(FilterType, const Matrix& matrix);
 
   FilterOperation(FilterType type, float amount, int inset);
 
@@ -281,7 +282,7 @@
   gfx::Point drop_shadow_offset_;
   SkColor drop_shadow_color_;
   sk_sp<SkImageFilter> image_filter_;
-  SkScalar matrix_[20];
+  Matrix matrix_;
   int zoom_inset_;
   SkRegion region_;
   SkBlurImageFilter::TileMode blur_tile_mode_;
diff --git a/cc/ipc/filter_operation_struct_traits.h b/cc/ipc/filter_operation_struct_traits.h
index 8dec54d..cfc2f2ea 100644
--- a/cc/ipc/filter_operation_struct_traits.h
+++ b/cc/ipc/filter_operation_struct_traits.h
@@ -93,8 +93,6 @@
 
 }  // namespace
 
-using FilterOperationMatrix = CArray<float>;
-
 template <>
 struct StructTraits<cc::mojom::FilterOperationDataView, cc::FilterOperation> {
   static cc::mojom::FilterType type(const cc::FilterOperation& op) {
@@ -128,12 +126,10 @@
     return operation.image_filter();
   }
 
-  static FilterOperationMatrix matrix(const cc::FilterOperation& operation) {
+  static ConstCArray<float> matrix(const cc::FilterOperation& operation) {
     if (operation.type() != cc::FilterOperation::COLOR_MATRIX)
-      return FilterOperationMatrix();
-    constexpr size_t MATRIX_SIZE = 20;
-    return {MATRIX_SIZE, MATRIX_SIZE,
-            const_cast<float*>(&operation.matrix()[0])};
+      return ConstCArray<float>();
+    return ConstCArray<float>(operation.matrix());
   }
 
   static int32_t zoom_inset(const cc::FilterOperation& operation) {
@@ -184,11 +180,8 @@
       case cc::FilterOperation::COLOR_MATRIX: {
         // TODO(fsamuel): It would be nice to modify cc::FilterOperation to
         // avoid this extra copy.
-        constexpr size_t MATRIX_SIZE = 20;
-        float matrix_buffer[MATRIX_SIZE];
-        memset(&matrix_buffer[0], 0, sizeof(matrix_buffer));
-        FilterOperationMatrix matrix = {MATRIX_SIZE, MATRIX_SIZE,
-                                        &matrix_buffer[0]};
+        cc::FilterOperation::Matrix matrix_buffer = {};
+        CArray<float> matrix(matrix_buffer);
         if (!data.ReadMatrix(&matrix))
           return false;
         out->set_matrix(matrix_buffer);
diff --git a/cc/ipc/quads_struct_traits.cc b/cc/ipc/quads_struct_traits.cc
index dae21dd..a6deb5a9 100644
--- a/cc/ipc/quads_struct_traits.cc
+++ b/cc/ipc/quads_struct_traits.cc
@@ -161,7 +161,7 @@
     return false;
   }
   quad->background_color = data.background_color();
-  CArray<float> vertex_opacity_array = {4, 4, &quad->vertex_opacity[0]};
+  CArray<float> vertex_opacity_array(quad->vertex_opacity);
   if (!data.ReadVertexOpacity(&vertex_opacity_array))
     return false;
 
diff --git a/cc/ipc/quads_struct_traits.h b/cc/ipc/quads_struct_traits.h
index d0ec09d..38dde8a 100644
--- a/cc/ipc/quads_struct_traits.h
+++ b/cc/ipc/quads_struct_traits.h
@@ -280,9 +280,9 @@
     return quad->background_color;
   }
 
-  static CArray<float> vertex_opacity(const cc::DrawQuad& input) {
+  static ConstCArray<float> vertex_opacity(const cc::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
-    return {4, 4, const_cast<float*>(&quad->vertex_opacity[0])};
+    return quad->vertex_opacity;
   }
 
   static bool y_flipped(const cc::DrawQuad& input) {
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index b57d100..7d878f7 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -1419,7 +1419,8 @@
 
 void Layer::SetElementId(ElementId id) {
   DCHECK(IsPropertyChangeAllowed());
-  if (inputs_.element_id == id)
+  if ((layer_tree_host_ && layer_tree_host_->GetSettings().use_layer_lists) ||
+      inputs_.element_id == id)
     return;
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("compositor-worker"),
                "Layer::SetElementId", "element", id.AsValue().release());
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 5762d14..3fd9556a 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -1434,7 +1434,7 @@
   EXPECT_EQ(MutableProperty::kTransform, impl_layer->mutable_properties());
 }
 
-TEST_F(LayerTest, NotUsingLayerListsManagesElementId) {
+TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) {
   scoped_refptr<Layer> test_layer = Layer::Create();
   ElementId element_id = ElementId(2);
   test_layer->SetElementId(element_id);
@@ -1459,6 +1459,28 @@
   EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
 }
 
+TEST_F(LayerTest, SetElementIdNotUsingLayerLists) {
+  scoped_refptr<Layer> test_layer = Layer::Create();
+  test_layer->SetLayerTreeHost(layer_tree_host_.get());
+
+  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2);
+  ElementId element_id = ElementId(2);
+  EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
+
+  test_layer->SetElementId(element_id);
+  // Layer should now be registered by element id.
+  EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id));
+
+  ElementId other_element_id = ElementId(3);
+  test_layer->SetElementId(other_element_id);
+  // The layer should have been unregistered from the original element
+  // id and registered with the new one.
+  EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
+  EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(other_element_id));
+
+  test_layer->SetLayerTreeHost(nullptr);
+}
+
 class LayerTestWithLayerLists : public LayerTest {
  protected:
   void SetUp() override {
@@ -1467,7 +1489,8 @@
   }
 };
 
-TEST_F(LayerTestWithLayerLists, UsingLayerListsDoesNotManageElementId) {
+TEST_F(LayerTestWithLayerLists,
+       SetLayerTreeHostUsingLayerListsDoesNotManageElementId) {
   scoped_refptr<Layer> test_layer = Layer::Create();
   ElementId element_id = ElementId(2);
   test_layer->SetElementId(element_id);
@@ -1491,5 +1514,14 @@
   EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
 }
 
+TEST_F(LayerTestWithLayerLists, SetElementIdUsingLayerLists) {
+  scoped_refptr<Layer> test_layer = Layer::Create();
+  ElementId element_id = ElementId(2);
+  test_layer->SetElementId(element_id);
+
+  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0);
+  EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h
index 8c855bd56..8e0420d 100644
--- a/cc/paint/display_item_list.h
+++ b/cc/paint/display_item_list.h
@@ -73,19 +73,6 @@
     paint_op_buffer_.push<T>(std::forward<Args>(args)...);
   }
 
-  template <typename T, typename M, typename... Args>
-  void push_with_array(const void* data,
-                       size_t bytes,
-                       const M* array,
-                       size_t count,
-                       Args&&... args) {
-    DCHECK(in_painting_);
-    if (usage_hint_ == kTopLevelDisplayItemList)
-      offsets_.push_back(paint_op_buffer_.next_op_offset());
-    paint_op_buffer_.push_with_array<T>(data, bytes, array, count,
-                                        std::forward<Args>(args)...);
-  }
-
   void EndPaintOfUnpaired(const gfx::Rect& visual_rect) {
     in_painting_ = false;
     if (usage_hint_ == kToBeReleasedAsPaintOpBuffer)
diff --git a/cc/paint/paint_canvas.h b/cc/paint/paint_canvas.h
index 689d5406..57ee5a1 100644
--- a/cc/paint/paint_canvas.h
+++ b/cc/paint/paint_canvas.h
@@ -155,10 +155,6 @@
     drawBitmap(bitmap, left, top, nullptr);
   }
 
-  virtual void drawPosText(const void* text,
-                           size_t byte_length,
-                           const SkPoint pos[],
-                           const PaintFlags& flags) = 0;
   virtual void drawTextBlob(sk_sp<SkTextBlob> blob,
                             SkScalar x,
                             SkScalar y,
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index 904a972..16175bb 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -192,7 +192,6 @@
   M(DrawLineOp)       \
   M(DrawOvalOp)       \
   M(DrawPathOp)       \
-  M(DrawPosTextOp)    \
   M(DrawRecordOp)     \
   M(DrawRectOp)       \
   M(DrawRRectOp)      \
@@ -373,8 +372,6 @@
       return "DrawOval";
     case PaintOpType::DrawPath:
       return "DrawPath";
-    case PaintOpType::DrawPosText:
-      return "DrawPosText";
     case PaintOpType::DrawRecord:
       return "DrawRecord";
     case PaintOpType::DrawRect:
@@ -589,20 +586,6 @@
   return helper.size();
 }
 
-size_t DrawPosTextOp::Serialize(const PaintOp* base_op,
-                                void* memory,
-                                size_t size,
-                                const SerializeOptions& options) {
-  auto* op = static_cast<const DrawPosTextOp*>(base_op);
-  PaintOpWriter helper(memory, size);
-  helper.Write(op->flags);
-  helper.Write(op->count);
-  helper.Write(op->bytes);
-  helper.WriteArray(op->count, op->GetArray());
-  helper.WriteData(op->bytes, op->GetData());
-  return helper.size();
-}
-
 size_t DrawRecordOp::Serialize(const PaintOp* op,
                                void* memory,
                                size_t size,
@@ -743,7 +726,7 @@
                                  size_t input_size,
                                  void* output,
                                  size_t output_size) {
-  CHECK_GE(output_size, sizeof(AnnotateOp));
+  DCHECK_GE(output_size, sizeof(AnnotateOp));
   AnnotateOp* op = new (output) AnnotateOp;
 
   PaintOpReader helper(input, input_size);
@@ -763,6 +746,7 @@
                                        size_t input_size,
                                        void* output,
                                        size_t output_size) {
+  DCHECK_GE(output_size, sizeof(ClipDeviceRectOp));
   return SimpleDeserialize<ClipDeviceRectOp>(input, input_size, output,
                                              output_size);
 }
@@ -771,7 +755,7 @@
                                  size_t input_size,
                                  void* output,
                                  size_t output_size) {
-  CHECK_GE(output_size, sizeof(ClipPathOp));
+  DCHECK_GE(output_size, sizeof(ClipPathOp));
   ClipPathOp* op = new (output) ClipPathOp;
 
   PaintOpReader helper(input, input_size);
@@ -791,6 +775,7 @@
                                  size_t input_size,
                                  void* output,
                                  size_t output_size) {
+  DCHECK_GE(output_size, sizeof(ClipRectOp));
   return SimpleDeserialize<ClipRectOp>(input, input_size, output, output_size);
 }
 
@@ -798,6 +783,7 @@
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
+  DCHECK_GE(output_size, sizeof(ClipRRectOp));
   return SimpleDeserialize<ClipRRectOp>(input, input_size, output, output_size);
 }
 
@@ -805,6 +791,7 @@
                                size_t input_size,
                                void* output,
                                size_t output_size) {
+  DCHECK_GE(output_size, sizeof(ConcatOp));
   return SimpleDeserialize<ConcatOp>(input, input_size, output, output_size);
 }
 
@@ -812,7 +799,7 @@
                                 size_t input_size,
                                 void* output,
                                 size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawArcOp));
+  DCHECK_GE(output_size, sizeof(DrawArcOp));
   DrawArcOp* op = new (output) DrawArcOp;
 
   PaintOpReader helper(input, input_size);
@@ -833,7 +820,7 @@
                                    size_t input_size,
                                    void* output,
                                    size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawCircleOp));
+  DCHECK_GE(output_size, sizeof(DrawCircleOp));
   DrawCircleOp* op = new (output) DrawCircleOp;
 
   PaintOpReader helper(input, input_size);
@@ -853,6 +840,7 @@
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
+  DCHECK_GE(output_size, sizeof(DrawColorOp));
   return SimpleDeserialize<DrawColorOp>(input, input_size, output, output_size);
 }
 
@@ -860,7 +848,7 @@
                                    size_t input_size,
                                    void* output,
                                    size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawDRRectOp));
+  DCHECK_GE(output_size, sizeof(DrawDRRectOp));
   DrawDRRectOp* op = new (output) DrawDRRectOp;
 
   PaintOpReader helper(input, input_size);
@@ -879,7 +867,7 @@
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawImageOp));
+  DCHECK_GE(output_size, sizeof(DrawImageOp));
   DrawImageOp* op = new (output) DrawImageOp;
 
   PaintOpReader helper(input, input_size);
@@ -899,7 +887,7 @@
                                       size_t input_size,
                                       void* output,
                                       size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawImageRectOp));
+  DCHECK_GE(output_size, sizeof(DrawImageRectOp));
   DrawImageRectOp* op = new (output) DrawImageRectOp;
 
   PaintOpReader helper(input, input_size);
@@ -920,7 +908,7 @@
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawIRectOp));
+  DCHECK_GE(output_size, sizeof(DrawIRectOp));
   DrawIRectOp* op = new (output) DrawIRectOp;
 
   PaintOpReader helper(input, input_size);
@@ -938,7 +926,7 @@
                                  size_t input_size,
                                  void* output,
                                  size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawLineOp));
+  DCHECK_GE(output_size, sizeof(DrawLineOp));
   DrawLineOp* op = new (output) DrawLineOp;
 
   PaintOpReader helper(input, input_size);
@@ -959,7 +947,7 @@
                                  size_t input_size,
                                  void* output,
                                  size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawOvalOp));
+  DCHECK_GE(output_size, sizeof(DrawOvalOp));
   DrawOvalOp* op = new (output) DrawOvalOp;
 
   PaintOpReader helper(input, input_size);
@@ -977,7 +965,7 @@
                                  size_t input_size,
                                  void* output,
                                  size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawPathOp));
+  DCHECK_GE(output_size, sizeof(DrawPathOp));
   DrawPathOp* op = new (output) DrawPathOp;
 
   PaintOpReader helper(input, input_size);
@@ -991,40 +979,6 @@
   return op;
 }
 
-PaintOp* DrawPosTextOp::Deserialize(const void* input,
-                                    size_t input_size,
-                                    void* output,
-                                    size_t output_size) {
-  // TODO(enne): This is a bit of a weird condition, but to avoid the code
-  // complexity of every Deserialize function being able to (re)allocate
-  // an aligned buffer of the right size, this function asserts that it
-  // will have enough size for the extra data.  It's guaranteed that any extra
-  // memory is at most |input_size| so that plus the op size is an upper bound.
-  // The caller has to awkwardly do this allocation though, sorry.
-  CHECK_GE(output_size, sizeof(DrawPosTextOp) + input_size);
-  DrawPosTextOp* op = new (output) DrawPosTextOp;
-
-  PaintOpReader helper(input, input_size);
-  helper.Read(&op->flags);
-  helper.Read(&op->count);
-  helper.Read(&op->bytes);
-  if (helper.valid()) {
-    helper.ReadArray(op->count, op->GetArray());
-    helper.ReadData(op->bytes, op->GetData());
-  }
-  if (!helper.valid() || !op->IsValid()) {
-    op->~DrawPosTextOp();
-    return nullptr;
-  }
-
-  op->type = static_cast<uint8_t>(PaintOpType::DrawPosText);
-  op->skip = MathUtil::UncheckedRoundUp(
-      sizeof(DrawPosTextOp) + op->bytes + sizeof(SkPoint) * op->count,
-      PaintOpBuffer::PaintOpAlign);
-
-  return op;
-}
-
 PaintOp* DrawRecordOp::Deserialize(const void* input,
                                    size_t input_size,
                                    void* output,
@@ -1038,7 +992,7 @@
                                  size_t input_size,
                                  void* output,
                                  size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawRectOp));
+  DCHECK_GE(output_size, sizeof(DrawRectOp));
   DrawRectOp* op = new (output) DrawRectOp;
 
   PaintOpReader helper(input, input_size);
@@ -1056,7 +1010,7 @@
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawRRectOp));
+  DCHECK_GE(output_size, sizeof(DrawRRectOp));
   DrawRRectOp* op = new (output) DrawRRectOp;
 
   PaintOpReader helper(input, input_size);
@@ -1074,7 +1028,7 @@
                                      size_t input_size,
                                      void* output,
                                      size_t output_size) {
-  CHECK_GE(output_size, sizeof(DrawTextBlobOp));
+  DCHECK_GE(output_size, sizeof(DrawTextBlobOp));
   DrawTextBlobOp* op = new (output) DrawTextBlobOp;
 
   PaintOpReader helper(input, input_size);
@@ -1094,6 +1048,7 @@
                              size_t input_size,
                              void* output,
                              size_t output_size) {
+  DCHECK_GE(output_size, sizeof(NoopOp));
   return SimpleDeserialize<NoopOp>(input, input_size, output, output_size);
 }
 
@@ -1101,6 +1056,7 @@
                                 size_t input_size,
                                 void* output,
                                 size_t output_size) {
+  DCHECK_GE(output_size, sizeof(RestoreOp));
   return SimpleDeserialize<RestoreOp>(input, input_size, output, output_size);
 }
 
@@ -1108,6 +1064,7 @@
                                size_t input_size,
                                void* output,
                                size_t output_size) {
+  DCHECK_GE(output_size, sizeof(RotateOp));
   return SimpleDeserialize<RotateOp>(input, input_size, output, output_size);
 }
 
@@ -1115,6 +1072,7 @@
                              size_t input_size,
                              void* output,
                              size_t output_size) {
+  DCHECK_GE(output_size, sizeof(SaveOp));
   return SimpleDeserialize<SaveOp>(input, input_size, output, output_size);
 }
 
@@ -1122,7 +1080,7 @@
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
-  CHECK_GE(output_size, sizeof(SaveLayerOp));
+  DCHECK_GE(output_size, sizeof(SaveLayerOp));
   SaveLayerOp* op = new (output) SaveLayerOp;
 
   PaintOpReader helper(input, input_size);
@@ -1140,6 +1098,7 @@
                                        size_t input_size,
                                        void* output,
                                        size_t output_size) {
+  DCHECK_GE(output_size, sizeof(SaveLayerAlphaOp));
   return SimpleDeserialize<SaveLayerAlphaOp>(input, input_size, output,
                                              output_size);
 }
@@ -1148,6 +1107,8 @@
                               size_t input_size,
                               void* output,
                               size_t output_size) {
+  DCHECK_GE(output_size, sizeof(ScaleOp));
+
   return SimpleDeserialize<ScaleOp>(input, input_size, output, output_size);
 }
 
@@ -1155,6 +1116,7 @@
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
+  DCHECK_GE(output_size, sizeof(SetMatrixOp));
   return SimpleDeserialize<SetMatrixOp>(input, input_size, output, output_size);
 }
 
@@ -1162,6 +1124,7 @@
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
+  DCHECK_GE(output_size, sizeof(TranslateOp));
   return SimpleDeserialize<TranslateOp>(input, input_size, output, output_size);
 }
 
@@ -1361,14 +1324,6 @@
   canvas->drawPath(op->path, paint);
 }
 
-void DrawPosTextOp::RasterWithFlags(const DrawPosTextOp* op,
-                                    const PaintFlags* flags,
-                                    SkCanvas* canvas,
-                                    const PlaybackParams& params) {
-  SkPaint paint = flags->ToSkPaint();
-  canvas->drawPosText(op->GetData(), op->bytes, op->GetArray(), paint);
-}
-
 void DrawRecordOp::Raster(const DrawRecordOp* op,
                           SkCanvas* canvas,
                           const PlaybackParams& params) {
@@ -1505,7 +1460,7 @@
                               size_t input_size,
                               void* output,
                               size_t output_size) {
-  // TODO(enne): assert that output_size is big enough.
+  DCHECK_GE(output_size, sizeof(LargestPaintOp));
   const PaintOp* serialized = reinterpret_cast<const PaintOp*>(input);
   uint32_t skip = serialized->skip;
   if (input_size < skip)
@@ -1585,8 +1540,6 @@
       rect->sort();
       return true;
     }
-    case PaintOpType::DrawPosText:
-      return false;
     case PaintOpType::DrawRect: {
       auto* rect_op = static_cast<const DrawRectOp*>(op);
       *rect = rect_op->rect;
@@ -1717,15 +1670,6 @@
 
 DrawImageRectOp::~DrawImageRectOp() = default;
 
-DrawPosTextOp::DrawPosTextOp() = default;
-
-DrawPosTextOp::DrawPosTextOp(size_t bytes,
-                             size_t count,
-                             const PaintFlags& flags)
-    : PaintOpWithArray(flags, bytes, count) {}
-
-DrawPosTextOp::~DrawPosTextOp() = default;
-
 DrawRecordOp::DrawRecordOp() = default;
 
 DrawRecordOp::DrawRecordOp(sk_sp<const PaintRecord> record)
@@ -1968,11 +1912,10 @@
   reserved_ = new_size;
 }
 
-std::pair<void*, size_t> PaintOpBuffer::AllocatePaintOp(size_t sizeof_op,
-                                                        size_t bytes) {
+std::pair<void*, size_t> PaintOpBuffer::AllocatePaintOp(size_t sizeof_op) {
   // Compute a skip such that all ops in the buffer are aligned to the
   // maximum required alignment of all ops.
-  size_t skip = MathUtil::UncheckedRoundUp(sizeof_op + bytes, PaintOpAlign);
+  size_t skip = MathUtil::UncheckedRoundUp(sizeof_op, PaintOpAlign);
   DCHECK_LT(skip, PaintOp::kMaxSkip);
   if (used_ + skip > reserved_) {
     // Start reserved_ at kInitialBufferSize and then double.
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h
index ffcf593b..fb3a773 100644
--- a/cc/paint/paint_op_buffer.h
+++ b/cc/paint/paint_op_buffer.h
@@ -72,7 +72,6 @@
   DrawLine,
   DrawOval,
   DrawPath,
-  DrawPosText,
   DrawRecord,
   DrawRect,
   DrawRRect,
@@ -217,73 +216,6 @@
   PaintOpWithFlags() = default;
 };
 
-class CC_PAINT_EXPORT PaintOpWithArrayBase : public PaintOpWithFlags {
- public:
-  explicit PaintOpWithArrayBase(const PaintFlags& flags)
-      : PaintOpWithFlags(flags) {}
-
- protected:
-  PaintOpWithArrayBase() = default;
-};
-
-template <typename M>
-class CC_PAINT_EXPORT PaintOpWithArray : public PaintOpWithArrayBase {
- public:
-  // Paint op that has a M[count] and a char[bytes].
-  // Array data is stored first so that it can be aligned with T's alignment
-  // with the arbitrary unaligned char data after it.
-  // Memory layout here is: | op | M[count] | char[bytes] | padding | next op |
-  // Next op is located at (char*)(op) + op->skip.
-  PaintOpWithArray(const PaintFlags& flags, size_t bytes, size_t count)
-      : PaintOpWithArrayBase(flags), bytes(bytes), count(count) {}
-
-  size_t bytes;
-  size_t count;
-
- protected:
-  PaintOpWithArray() = default;
-
-  template <typename T>
-  const void* GetDataForThis(const T* op) const {
-    static_assert(std::is_convertible<T, PaintOpWithArrayBase>::value,
-                  "T is not a PaintOpWithArray");
-    const char* start_array =
-        reinterpret_cast<const char*>(GetArrayForThis(op));
-    return start_array + sizeof(M) * count;
-  }
-
-  template <typename T>
-  void* GetDataForThis(T* op) {
-    return const_cast<void*>(
-        const_cast<const PaintOpWithArray*>(this)->GetDataForThis(
-            const_cast<T*>(op)));
-  }
-
-  template <typename T>
-  const M* GetArrayForThis(const T* op) const {
-    static_assert(std::is_convertible<T, PaintOpWithArrayBase>::value,
-                  "T is not a PaintOpWithArray");
-    // As an optimization to not have to store an additional offset,
-    // assert that T has the same or more alignment requirements than M.  Thus,
-    // if T is aligned, and M's alignment needs are a multiple of T's size, then
-    // M will also be aligned when placed immediately after T.
-    static_assert(
-        sizeof(T) % alignof(M) == 0,
-        "T must be padded such that an array of M is aligned after it");
-    static_assert(
-        alignof(T) >= alignof(M),
-        "T must have not have less alignment requirements than the array data");
-    return reinterpret_cast<const M*>(op + 1);
-  }
-
-  template <typename T>
-  M* GetArrayForThis(T* op) {
-    return const_cast<M*>(
-        const_cast<const PaintOpWithArray*>(this)->GetArrayForThis(
-            const_cast<T*>(op)));
-  }
-};
-
 class CC_PAINT_EXPORT AnnotateOp final : public PaintOp {
  public:
   enum class AnnotationType {
@@ -643,28 +575,6 @@
   DrawPathOp() = default;
 };
 
-class CC_PAINT_EXPORT DrawPosTextOp final : public PaintOpWithArray<SkPoint> {
- public:
-  static constexpr PaintOpType kType = PaintOpType::DrawPosText;
-  static constexpr bool kIsDrawOp = true;
-  DrawPosTextOp(size_t bytes, size_t count, const PaintFlags& flags);
-  ~DrawPosTextOp();
-  static void RasterWithFlags(const DrawPosTextOp* op,
-                              const PaintFlags* flags,
-                              SkCanvas* canvas,
-                              const PlaybackParams& params);
-  bool IsValid() const { return flags.IsValid(); }
-  HAS_SERIALIZATION_FUNCTIONS();
-
-  const void* GetData() const { return GetDataForThis(this); }
-  void* GetData() { return GetDataForThis(this); }
-  const SkPoint* GetArray() const { return GetArrayForThis(this); }
-  SkPoint* GetArray() { return GetArrayForThis(this); }
-
- private:
-  DrawPosTextOp();
-};
-
 class CC_PAINT_EXPORT DrawRecordOp final : public PaintOp {
  public:
   static constexpr PaintOpType kType = PaintOpType::DrawRecord;
@@ -944,40 +854,16 @@
   template <typename T, typename... Args>
   void push(Args&&... args) {
     static_assert(std::is_convertible<T, PaintOp>::value, "T not a PaintOp.");
-    static_assert(!std::is_convertible<T, PaintOpWithArrayBase>::value,
-                  "Type needs to use push_with_array");
-    push_internal<T>(0, std::forward<Args>(args)...);
-  }
+    static_assert(alignof(T) <= PaintOpAlign, "");
 
-  template <typename T, typename M, typename... Args>
-  void push_with_array(const void* data,
-                       size_t bytes,
-                       const M* array,
-                       size_t count,
-                       Args&&... args) {
-    static_assert(std::is_convertible<T, PaintOpWithArray<M>>::value,
-                  "T is not a PaintOpWithArray");
-    size_t array_size = sizeof(M) * count;
-    size_t total_size = bytes + array_size;
-    T* op =
-        push_internal<T>(total_size, bytes, count, std::forward<Args>(args)...);
-    memcpy(op->GetData(), data, bytes);
-    memcpy(op->GetArray(), array, array_size);
+    auto pair = AllocatePaintOp(sizeof(T));
+    T* op = reinterpret_cast<T*>(pair.first);
+    size_t skip = pair.second;
 
-#if DCHECK_IS_ON()
-    // Double check data and array don't clobber op, next op, or each other
-    char* op_start = reinterpret_cast<char*>(op);
-    char* op_end = op_start + sizeof(T);
-    char* array_start = reinterpret_cast<char*>(op->GetArray());
-    char* array_end = array_start + array_size;
-    char* data_start = reinterpret_cast<char*>(op->GetData());
-    char* data_end = data_start + bytes;
-    char* next_op = op_start + op->skip;
-    DCHECK_GE(array_start, op_end);
-    DCHECK_LE(array_start, data_start);
-    DCHECK_GE(data_start, array_end);
-    DCHECK_LE(data_end, next_op);
-#endif
+    new (op) T{std::forward<Args>(args)...};
+    op->type = static_cast<uint32_t>(T::kType);
+    op->skip = skip;
+    AnalyzeAddedOp(op);
   }
 
   class CC_PAINT_EXPORT Iterator {
@@ -1175,22 +1061,7 @@
   void ReallocBuffer(size_t new_size);
   // Returns the allocated op and the number of bytes to skip in |data_| to get
   // to the next op.
-  std::pair<void*, size_t> AllocatePaintOp(size_t sizeof_op, size_t bytes);
-
-  template <typename T, typename... Args>
-  T* push_internal(size_t bytes, Args&&... args) {
-    static_assert(alignof(T) <= PaintOpAlign, "");
-
-    auto pair = AllocatePaintOp(sizeof(T), bytes);
-    T* op = reinterpret_cast<T*>(pair.first);
-    size_t skip = pair.second;
-
-    new (op) T{std::forward<Args>(args)...};
-    op->type = static_cast<uint32_t>(T::kType);
-    op->skip = skip;
-    AnalyzeAddedOp(op);
-    return op;
-  }
+  std::pair<void*, size_t> AllocatePaintOp(size_t sizeof_op);
 
   template <typename T>
   void AnalyzeAddedOp(const T* op) {
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index 9bcbc7c..8a91197 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -268,55 +268,6 @@
   VerifyOps(&original);
 }
 
-// Verify that PaintOps with arrays are stored properly.
-TEST(PaintOpBufferTest, PaintOpArray) {
-  PaintOpBuffer buffer;
-  buffer.push<SaveOp>();
-
-  // arbitrary data
-  std::string texts[] = {"xyz", "abcdefg", "thingerdoo"};
-  SkPoint point1[] = {SkPoint::Make(1, 2), SkPoint::Make(2, 3),
-                      SkPoint::Make(3, 4)};
-  SkPoint point2[] = {SkPoint::Make(8, -12)};
-  SkPoint point3[] = {SkPoint::Make(0, 0),   SkPoint::Make(5, 6),
-                      SkPoint::Make(-1, -1), SkPoint::Make(9, 9),
-                      SkPoint::Make(50, 50), SkPoint::Make(100, 100)};
-  SkPoint* points[] = {point1, point2, point3};
-  size_t counts[] = {arraysize(point1), arraysize(point2), arraysize(point3)};
-
-  for (size_t i = 0; i < arraysize(texts); ++i) {
-    PaintFlags flags;
-    flags.setAlpha(i);
-    buffer.push_with_array<DrawPosTextOp>(texts[i].c_str(), texts[i].length(),
-                                          points[i], counts[i], flags);
-  }
-
-  PaintOpBuffer::Iterator iter(&buffer);
-  PaintOp* save_op = *iter;
-  EXPECT_EQ(save_op->GetType(), PaintOpType::Save);
-  ++iter;
-
-  for (size_t i = 0; i < arraysize(texts); ++i) {
-    ASSERT_EQ(iter->GetType(), PaintOpType::DrawPosText);
-    DrawPosTextOp* op = static_cast<DrawPosTextOp*>(*iter);
-
-    EXPECT_EQ(op->flags.getAlpha(), i);
-
-    EXPECT_EQ(op->bytes, texts[i].length());
-    const void* data = op->GetData();
-    EXPECT_EQ(memcmp(data, texts[i].c_str(), op->bytes), 0);
-
-    EXPECT_EQ(op->count, counts[i]);
-    const SkPoint* op_points = op->GetArray();
-    for (size_t k = 0; k < op->count; ++k)
-      EXPECT_EQ(op_points[k], points[i][k]);
-
-    ++iter;
-  }
-
-  EXPECT_FALSE(iter);
-}
-
 // Verify that a SaveLayerAlpha / Draw / Restore can be optimized to just
 // a draw with opacity.
 TEST(PaintOpBufferTest, SaveDrawRestore) {
@@ -1793,19 +1744,6 @@
     buffer->push<DrawPathOp>(test_paths[i], test_flags[i]);
 }
 
-void PushDrawPosTextOps(PaintOpBuffer* buffer) {
-  size_t len = std::min(std::min(test_flags.size(), test_strings.size()),
-                        test_point_arrays.size());
-  for (size_t i = 0; i < len; ++i) {
-    // Make sure empty array works fine.
-    SkPoint* array =
-        test_point_arrays[i].size() > 0 ? &test_point_arrays[i][0] : nullptr;
-    buffer->push_with_array<DrawPosTextOp>(
-        test_strings[i].c_str(), test_strings[i].size() + 1, array,
-        test_point_arrays[i].size(), test_flags[i]);
-  }
-}
-
 void PushDrawRectOps(PaintOpBuffer* buffer) {
   size_t len = std::min(test_rects.size(), test_flags.size());
   for (size_t i = 0; i < len; ++i)
@@ -2036,19 +1974,6 @@
   EXPECT_TRUE(original->path == written->path);
 }
 
-void CompareDrawPosTextOp(const DrawPosTextOp* original,
-                          const DrawPosTextOp* written) {
-  EXPECT_TRUE(original->IsValid());
-  EXPECT_TRUE(written->IsValid());
-  CompareFlags(original->flags, written->flags);
-  ASSERT_EQ(original->bytes, written->bytes);
-  EXPECT_EQ(std::string(static_cast<const char*>(original->GetData())),
-            std::string(static_cast<const char*>(written->GetData())));
-  ASSERT_EQ(original->count, written->count);
-  for (size_t i = 0; i < original->count; ++i)
-    EXPECT_EQ(original->GetArray()[i], written->GetArray()[i]);
-}
-
 void CompareDrawRectOp(const DrawRectOp* original, const DrawRectOp* written) {
   EXPECT_TRUE(original->IsValid());
   EXPECT_TRUE(written->IsValid());
@@ -2226,9 +2151,6 @@
       case PaintOpType::DrawPath:
         PushDrawPathOps(&buffer_);
         break;
-      case PaintOpType::DrawPosText:
-        PushDrawPosTextOps(&buffer_);
-        break;
       case PaintOpType::DrawRecord:
         // Not supported.
         break;
@@ -2342,10 +2264,6 @@
         CompareDrawPathOp(static_cast<const DrawPathOp*>(original),
                           static_cast<const DrawPathOp*>(written));
         break;
-      case PaintOpType::DrawPosText:
-        CompareDrawPosTextOp(static_cast<const DrawPosTextOp*>(original),
-                             static_cast<const DrawPosTextOp*>(written));
-        break;
       case PaintOpType::DrawRecord:
         // Not supported.
         break;
diff --git a/cc/paint/record_paint_canvas.cc b/cc/paint/record_paint_canvas.cc
index 8dc19e1..aaa02a9e 100644
--- a/cc/paint/record_paint_canvas.cc
+++ b/cc/paint/record_paint_canvas.cc
@@ -303,16 +303,6 @@
             left, top, flags);
 }
 
-void RecordPaintCanvas::drawPosText(const void* text,
-                                    size_t byte_length,
-                                    const SkPoint pos[],
-                                    const PaintFlags& flags) {
-  // TODO(enne): implement countText in PaintFlags??
-  SkPaint paint = flags.ToSkPaint();
-  size_t count = paint.countText(text, byte_length);
-  list_->push_with_array<DrawPosTextOp>(text, byte_length, pos, count, flags);
-}
-
 void RecordPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
                                      SkScalar x,
                                      SkScalar y,
diff --git a/cc/paint/record_paint_canvas.h b/cc/paint/record_paint_canvas.h
index d09bff626..de10644 100644
--- a/cc/paint/record_paint_canvas.h
+++ b/cc/paint/record_paint_canvas.h
@@ -102,10 +102,6 @@
                   SkScalar top,
                   const PaintFlags* flags) override;
 
-  void drawPosText(const void* text,
-                   size_t byte_length,
-                   const SkPoint pos[],
-                   const PaintFlags& flags) override;
   void drawTextBlob(sk_sp<SkTextBlob> blob,
                     SkScalar x,
                     SkScalar y,
diff --git a/cc/paint/skia_paint_canvas.cc b/cc/paint/skia_paint_canvas.cc
index 33e0d3e..967ea16 100644
--- a/cc/paint/skia_paint_canvas.cc
+++ b/cc/paint/skia_paint_canvas.cc
@@ -269,14 +269,6 @@
   }
 }
 
-void SkiaPaintCanvas::drawPosText(const void* text,
-                                  size_t byte_length,
-                                  const SkPoint pos[],
-                                  const PaintFlags& flags) {
-  SkPaint paint = flags.ToSkPaint();
-  canvas_->drawPosText(text, byte_length, pos, paint);
-}
-
 void SkiaPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
                                    SkScalar x,
                                    SkScalar y,
diff --git a/cc/paint/skia_paint_canvas.h b/cc/paint/skia_paint_canvas.h
index f162cdd..6ce174b 100644
--- a/cc/paint/skia_paint_canvas.h
+++ b/cc/paint/skia_paint_canvas.h
@@ -110,10 +110,6 @@
                   SkScalar top,
                   const PaintFlags* flags) override;
 
-  void drawPosText(const void* text,
-                   size_t byte_length,
-                   const SkPoint pos[],
-                   const PaintFlags& flags) override;
   void drawTextBlob(sk_sp<SkTextBlob> blob,
                     SkScalar x,
                     SkScalar y,
diff --git a/cc/paint/solid_color_analyzer.cc b/cc/paint/solid_color_analyzer.cc
index 21513cd8..7b556e0 100644
--- a/cc/paint/solid_color_analyzer.cc
+++ b/cc/paint/solid_color_analyzer.cc
@@ -206,7 +206,6 @@
       case PaintOpType::DrawLine:
       case PaintOpType::DrawOval:
       case PaintOpType::DrawPath:
-      case PaintOpType::DrawPosText:
         return base::nullopt;
       // TODO(vmpstr): Add more tests on exceeding max_ops_to_analyze.
       case PaintOpType::DrawRRect: {
diff --git a/chrome/android/java/res/drawable/bottom_toolbar_background.xml b/chrome/android/java/res/drawable/bottom_toolbar_background.xml
new file mode 100644
index 0000000..cbb1b325
--- /dev/null
+++ b/chrome/android/java/res/drawable/bottom_toolbar_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+    <solid android:color="@color/default_primary_color" />
+    <size
+        android:width="@dimen/bottom_toolbar_background_size"
+        android:height="@dimen/bottom_toolbar_background_size" />
+    <corners android:radius="@dimen/bottom_toolbar_background_corner_radius" />
+    <padding
+        android:top="0dp"
+        android:bottom="0dp"
+        android:left="@dimen/bottom_toolbar_background_lateral_inset"
+        android:right="@dimen/bottom_toolbar_background_lateral_inset" />
+</shape>
\ No newline at end of file
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index 9d8e041..86e8292 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -147,6 +147,7 @@
 
     <!-- Theme colors. Also used for toolbar background -->
     <color name="incognito_primary_color">#505050</color>
+    <color name="modern_primary_color">@android:color/white</color>
 
     <!-- LocationBar colors -->
     <color name="locationbar_dark_hint_text">@color/black_alpha_54</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 343b488..d24eff56 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -199,8 +199,6 @@
     <!-- Should match toolbar_height_no_shadow -->
     <dimen name="control_container_height">56dp</dimen>
     <dimen name="bottom_control_container_height">56dp</dimen>
-    <dimen name="bottom_toolbar_top_margin">2dp</dimen>
-    <dimen name="bottom_toolbar_url_bar_top_margin">3.5dp</dimen>
     <dimen name="custom_tabs_control_container_height">56dp</dimen>
     <dimen name="webapp_control_container_height">22dp</dimen>
 
@@ -266,6 +264,14 @@
     <dimen name="tablet_toolbar_end_padding">6dp</dimen>
     <dimen name="location_bar_status_separator_width">1dp</dimen>
 
+    <!-- Bottom toolbar dimensions -->
+    <dimen name="bottom_toolbar_top_margin">2dp</dimen>
+    <dimen name="bottom_toolbar_url_bar_top_margin">3.5dp</dimen>
+    <dimen name="bottom_toolbar_background_size">36dp</dimen>
+    <dimen name="bottom_toolbar_background_corner_radius">18dp</dimen>
+    <dimen name="bottom_toolbar_background_lateral_inset">2dp</dimen>
+    <dimen name="bottom_toolbar_background_focused_left_margin">6dp</dimen>
+
     <!-- Omnibox suggestions -->
     <dimen name="omnibox_suggestion_height">60dp</dimen>
     <dimen name="omnibox_suggestion_answer_height">72dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SwipeRefreshHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/SwipeRefreshHandler.java
index 36b7230..3a596bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/SwipeRefreshHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/SwipeRefreshHandler.java
@@ -11,6 +11,7 @@
 import org.chromium.base.TraceEvent;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.third_party.android.swiperefresh.SwipeRefreshLayout;
 import org.chromium.ui.OverscrollRefreshHandler;
@@ -124,6 +125,14 @@
 
     @Override
     public boolean start() {
+        FullscreenManager manager = mTab.getFullscreenManager();
+
+        // If the controls are at the bottom and hidden, allow cc to handle the scroll event to show
+        // them.
+        if (manager.areBrowserControlsAtBottom() && manager.getBrowserControlHiddenRatio() > 0) {
+            return false;
+        }
+
         attachSwipeRefreshLayoutIfNecessary();
         return mSwipeRefreshLayout.start();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerDocument.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerDocument.java
index 7028fe88..5d4c8fe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerDocument.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerDocument.java
@@ -12,6 +12,7 @@
 import android.view.ViewGroup;
 
 import org.chromium.chrome.browser.ChromeApplication;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelContentViewDelegate;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager;
@@ -235,10 +236,13 @@
                 tab.getContentViewCore() != null && !tab.isShowingSadTab() && !isNativePage;
 
         boolean isNtp = tab.getNativePage() instanceof NewTabPage;
+        boolean useModernDesign = tab.getActivity() != null
+                && tab.getActivity().getBottomSheet() != null && ChromeFeatureList.isInitialized()
+                && ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT);
         boolean needsUpdate = layoutTab.initFromHost(tab.getBackgroundColor(), tab.shouldStall(),
                 canUseLiveTexture, themeColor,
                 ColorUtils.getTextBoxColorForToolbarBackground(
-                        mContext.getResources(), isNtp, themeColor),
+                        mContext.getResources(), isNtp, themeColor, useModernDesign),
                 ColorUtils.getTextBoxAlphaForToolbarBackground(tab));
         if (needsUpdate) requestUpdate();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
index 10ae9a7f..82f5995 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
@@ -11,6 +11,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
@@ -33,10 +34,10 @@
      * let them be rendered on the screen.  This should only be called when the Compositor has
      * disabled ScheduleComposite calls as this will change the tree and could subsequently cause
      * unnecessary follow up renders.
-     * @param context         The {@link Context} to use to query device information.
-     * @param viewport        The viewport for the screen.
+     * @param context The {@link Context} to use to query device information.
+     * @param viewport The viewport for the screen.
      * @param contentViewport The visible viewport.
-     * @param layout          The {@link Layout} to push to the screen.
+     * @param layout The {@link Layout} to push to the screen.
      * @param layerTitleCache An object for accessing tab layer titles.
      * @param tabContentManager An object for accessing tab content.
      * @param resourceManager An object for accessing static and dynamic resources.
@@ -64,9 +65,12 @@
             assert t.isVisible() : "LayoutTab in that list should be visible";
             final float decoration = t.getDecorationAlpha();
 
-            int defaultThemeColor = t.isIncognito()
-                    ? ApiCompatibilityUtils.getColor(res, R.color.incognito_primary_color)
-                    : ApiCompatibilityUtils.getColor(res, R.color.default_primary_color);
+            boolean useModernDesign = fullscreenManager.areBrowserControlsAtBottom()
+                    && ChromeFeatureList.isInitialized()
+                    && ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT);
+
+            int defaultThemeColor =
+                    ColorUtils.getDefaultThemeColor(res, useModernDesign, t.isIncognito());
 
             int toolbarBackgroundColor = t.getToolbarBackgroundColor();
             int textBoxBackgroundColor = t.getTextBoxBackgroundColor();
@@ -74,8 +78,10 @@
             if (t.getForceDefaultThemeColor()) {
                 toolbarBackgroundColor = defaultThemeColor;
                 textBoxBackgroundColor = ColorUtils.getTextBoxColorForToolbarBackground(
-                        res, false, toolbarBackgroundColor);
-                textBoxAlpha = t.isIncognito() ? textBoxAlpha : 1f;
+                        res, false, toolbarBackgroundColor, useModernDesign);
+                // In the modern design, the text box is always drawn in the Java layer rather
+                // than the compositor layer.
+                textBoxAlpha = useModernDesign ? 0.f : t.isIncognito() ? textBoxAlpha : 1f;
             }
 
             int closeButtonColor =
@@ -139,12 +145,16 @@
     }
 
     private native long nativeInit();
+
     private native void nativeBeginBuildingFrame(long nativeTabListSceneLayer);
+
     private native void nativeFinishBuildingFrame(long nativeTabListSceneLayer);
+
     private native void nativeUpdateLayer(long nativeTabListSceneLayer, int backgroundColor,
             float viewportX, float viewportY, float viewportWidth, float viewportHeight,
             LayerTitleCache layerTitleCache, TabContentManager tabContentManager,
             ResourceManager resourceManager);
+
     private native void nativePutTabLayer(long nativeTabListSceneLayer, int id,
             int toolbarResourceId, int closeButtonResourceId, int shadowResourceId,
             int contourResourceId, int backLogoResourceId, int borderResourceId,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
index 39c1b35e..1c6f7627 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
@@ -9,6 +9,7 @@
 
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
 import org.chromium.chrome.browser.compositor.layouts.Layout.ViewportMode;
 import org.chromium.chrome.browser.compositor.layouts.LayoutProvider;
@@ -155,6 +156,14 @@
             if (!fullscreenManager.getTab().isIncognito()) alpha = 1f;
         }
 
+        boolean useModernDesign = fullscreenManager.areBrowserControlsAtBottom()
+                && ChromeFeatureList.isInitialized()
+                && ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT);
+
+        // In the modern design, the url bar is always drawn in the Java layer rather than the
+        // compositor layer.
+        if (useModernDesign) alpha = 0;
+
         update(color, alpha, mLayoutProvider.getFullscreenManager(), resourceManager,
                 forceHideBrowserControlsAndroidView, viewportMode, DeviceFormFactor.isTablet(),
                 viewport.height());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
index 632e93fb..f8da09a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -214,9 +214,7 @@
         updateControlOffset();
     }
 
-    /**
-     * @return Whether or not the browser controls are attached to the bottom of the screen.
-     */
+    @Override
     public boolean areBrowserControlsAtBottom() {
         return mIsBottomControls;
     }
@@ -313,11 +311,8 @@
         };
     }
 
-    /**
-     * @return The ratio that the browser controls are off screen; this will be a number [0,1]
-     *         where 1 is completely hidden and 0 is completely shown.
-     */
-    private float getBrowserControlHiddenRatio() {
+    @Override
+    public float getBrowserControlHiddenRatio() {
         return mControlOffsetRatio;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenManager.java
index d3044e10..9849a5cd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenManager.java
@@ -50,6 +50,17 @@
     public abstract int getTopControlsHeight();
 
     /**
+     * @return Whether or not the browser controls are attached to the bottom of the screen.
+     */
+    public abstract boolean areBrowserControlsAtBottom();
+
+    /**
+     * @return The ratio that the browser controls are off screen; this will be a number [0,1]
+     *         where 1 is completely hidden and 0 is completely shown.
+     */
+    public abstract float getBrowserControlHiddenRatio();
+
+    /**
      * @return The offset of the content from the top of the screen.
      */
     public abstract float getContentOffset();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index 38d49ab6..83b44a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -8,6 +8,7 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.SystemClock;
 import android.support.annotation.WorkerThread;
 import android.view.View;
@@ -402,6 +403,13 @@
                 BackgroundTaskSchedulerFactory.getScheduler().checkForOSUpgrade(application);
             }
         });
+
+        deferredStartupHandler.addDeferredTask(new Runnable() {
+            @Override
+            public void run() {
+                logEGLShaderCacheSizeHistogram();
+            }
+        });
     }
 
     private void initChannelsAsync() {
@@ -643,4 +651,53 @@
             RecordHistogram.recordBooleanHistogram("InputMethod.MatchesSystemLanguage", match);
         }
     }
+
+    /**
+     * Logs a histogram with the size of the Android EGL shader cache.
+     */
+    private static void logEGLShaderCacheSizeHistogram() {
+        // To simplify logic, only log this value on Android N+.
+        if (Build.VERSION.SDK_INT < 24) {
+            return;
+        }
+        final Context cacheContext =
+                ContextUtils.getApplicationContext().createDeviceProtectedStorageContext();
+
+        // Must log async, as we're doing a file access.
+        new AsyncTask<Void, Void, Void>() {
+            // Record file sizes between 1-2560KB. Expected range is 1-2048KB, so this gives
+            // us a bit of buffer. These values cannot be changed, as doing so will alter
+            // histogram bucketing and confuse the dashboard.
+            private static final int MIN_CACHE_FILE_SIZE_KB = 1;
+            private static final int MAX_CACHE_FILE_SIZE_KB = 2560;
+
+            @Override
+            protected Void doInBackground(Void... unused) {
+                File codeCacheDir = cacheContext.getCodeCacheDir();
+                if (codeCacheDir == null) {
+                    return null;
+                }
+                // This filename is defined in core/java/android/view/HardwareRenderer.java,
+                // and has been located in the codeCacheDir since Android M.
+                File cacheFile = new File(codeCacheDir, "com.android.opengl.shaders_cache");
+                if (!cacheFile.exists()) {
+                    return null;
+                }
+                long cacheFileSizeKb = cacheFile.length() / 1024;
+                // Clamp size to [minFileSizeKb, maxFileSizeKb). This also guarantees that the
+                // int-cast below is safe.
+                if (cacheFileSizeKb < MIN_CACHE_FILE_SIZE_KB) {
+                    cacheFileSizeKb = MIN_CACHE_FILE_SIZE_KB;
+                }
+                if (cacheFileSizeKb >= MAX_CACHE_FILE_SIZE_KB) {
+                    cacheFileSizeKb = MAX_CACHE_FILE_SIZE_KB - 1;
+                }
+                String histogramName = "Memory.Experimental.Browser.EGLShaderCacheSize.Android";
+                RecordHistogram.recordCustomCountHistogram(histogramName, (int) cacheFileSizeKb,
+                        MIN_CACHE_FILE_SIZE_KB, MAX_CACHE_FILE_SIZE_KB, 50);
+                return null;
+            }
+        }
+                .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/printing/TabPrinter.java b/chrome/android/java/src/org/chromium/chrome/browser/printing/TabPrinter.java
index ca66ebe..b97c89d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/printing/TabPrinter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/printing/TabPrinter.java
@@ -34,11 +34,9 @@
 
     @Override
     public boolean print(int renderProcessId, int renderFrameId) {
+        if (!canPrint()) return false;
         Tab tab = mTab.get();
-        if (tab == null || !tab.isInitialized()) {
-            Log.d(TAG, "Tab not ready, unable to start printing.");
-            return false;
-        }
+        assert tab != null && tab.isInitialized();
         return tab.print(renderProcessId, renderFrameId);
     }
 
@@ -55,4 +53,15 @@
 
         return mDefaultTitle;
     }
+
+    @Override
+    public boolean canPrint() {
+        Tab tab = mTab.get();
+        if (tab == null || !tab.isInitialized()) {
+            // tab.isInitialized() will be false if tab is in destroy process.
+            Log.d(TAG, "Tab is not avaliable for printing.");
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
index 2bd7af8..670a80b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -53,7 +53,6 @@
                                                       BottomSheetNewTabController.Observer,
                                                       TemplateUrlServiceObserver {
     private final View mView;
-    private final FadingShadowView mShadowView;
     private final SuggestionsRecyclerView mRecyclerView;
     private final ContextMenuManager mContextMenuManager;
     private final SuggestionsUiDelegateImpl mSuggestionsUiDelegate;
@@ -173,17 +172,7 @@
             }
         };
 
-        mShadowView = (FadingShadowView) mView.findViewById(R.id.shadow);
-        mShadowView.init(ApiCompatibilityUtils.getColor(resources, R.color.toolbar_shadow_color),
-                FadingShadow.POSITION_TOP);
-
-        mRecyclerView.addOnScrollListener(new OnScrollListener() {
-            @Override
-            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-                boolean shadowVisible = mRecyclerView.canScrollVertically(-1);
-                mShadowView.setVisibility(shadowVisible ? View.VISIBLE : View.GONE);
-            }
-        });
+        initializeShadow();
 
         final LocationBar locationBar = (LocationBar) sheet.findViewById(R.id.location_bar);
         mRecyclerView.setOnTouchListener(new View.OnTouchListener() {
@@ -271,6 +260,27 @@
         updateLogoTransition();
     }
 
+    private void initializeShadow() {
+        final FadingShadowView shadowView = (FadingShadowView) mView.findViewById(R.id.shadow);
+
+        if (SuggestionsConfig.useModern()) {
+            ((ViewGroup) mView).removeView(shadowView);
+            return;
+        }
+
+        shadowView.init(
+                ApiCompatibilityUtils.getColor(mView.getResources(), R.color.toolbar_shadow_color),
+                FadingShadow.POSITION_TOP);
+
+        mRecyclerView.addOnScrollListener(new OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                boolean shadowVisible = mRecyclerView.canScrollVertically(-1);
+                shadowView.setVisibility(shadowVisible ? View.VISIBLE : View.GONE);
+            }
+        });
+    }
+
     private void maybeUpdateContextualSuggestions() {
         if (mSuggestionsCarousel == null) return;
         assert ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_CAROUSEL);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 134f6907..8c7a50b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -28,7 +28,6 @@
 import android.widget.FrameLayout.LayoutParams;
 import android.widget.PopupWindow.OnDismissListener;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ObserverList;
@@ -491,11 +490,15 @@
         mWindowAndroid = window;
         mLaunchType = type;
         if (mLaunchType == TabLaunchType.FROM_DETACHED) mIsDetached = true;
+
+        boolean useModernDesign = getActivity() != null && getActivity().getBottomSheet() != null
+                && ChromeFeatureList.isInitialized()
+                && ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT);
+
         Resources resources = mThemedApplicationContext.getResources();
         mIdealFaviconSize = resources.getDimensionPixelSize(R.dimen.default_favicon_size);
-        mDefaultThemeColor = mIncognito
-                ? ApiCompatibilityUtils.getColor(resources, R.color.incognito_primary_color)
-                : ApiCompatibilityUtils.getColor(resources, R.color.default_primary_color);
+        mDefaultThemeColor =
+                ColorUtils.getDefaultThemeColor(resources, useModernDesign, mIncognito);
         mThemeColor = calculateThemeColor(false);
 
         // Restore data from the TabState, if it existed.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
index cca52e7..ef9c536 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -8,7 +8,9 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
@@ -22,6 +24,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.tab.Tab;
@@ -175,6 +178,23 @@
     /** Whether the menu button should be shown while the sheet is open. */
     private boolean mShowMenuButtonWhenSheetOpen;
 
+    /** Whether to use the "modern" visual design. */
+    private boolean mUseModernDesign;
+
+    /**
+     * The float used to inset the rect returned by {@link #getLocationBarContentRect(Rect)}
+     * when {@link #mUseModernDesign} is true. When the modern layout is used, this extra
+     * vertical inset is needed to ensure the anonymize layer doesn't draw outside of the
+     * background bounds.
+     */
+    private float mLocationBarContentVerticalInset;
+
+    /**
+     * The extra margin to apply to the left side of the location bar when it is focused and
+     * {@link #mUseModernDesign} is true.
+     */
+    private int mLocationBarExtraFocusedLeftMargin;
+
     /**
      * Constructs a BottomToolbarPhone object.
      * @param context The Context in which this View object is created.
@@ -371,27 +391,83 @@
     }
 
     @Override
+    public void getLocationBarContentRect(Rect outRect) {
+        super.getLocationBarContentRect(outRect);
+
+        if (mUseModernDesign) {
+            outRect.left += mLocationBarBackgroundPadding.left;
+            outRect.top += mLocationBarContentVerticalInset;
+            outRect.right -= mLocationBarBackgroundPadding.right;
+            outRect.bottom -= mLocationBarContentVerticalInset;
+        }
+    }
+
+    @Override
+    protected int getFocusedLocationBarWidth(int containerWidth, int priorVisibleWidth) {
+        if (!mUseModernDesign) {
+            return super.getFocusedLocationBarWidth(containerWidth, priorVisibleWidth);
+        }
+
+        return super.getFocusedLocationBarWidth(containerWidth, priorVisibleWidth)
+                - mLocationBarExtraFocusedLeftMargin - mLocationBarBackgroundPadding.left
+                - mLocationBarBackgroundPadding.right;
+    }
+
+    @Override
+    protected int getFocusedLocationBarLeftMargin(int priorVisibleWidth) {
+        if (!mUseModernDesign) return super.getFocusedLocationBarLeftMargin(priorVisibleWidth);
+
+        int baseMargin = mToolbarSidePadding + mLocationBarExtraFocusedLeftMargin;
+        if (ApiCompatibilityUtils.isLayoutRtl(mLocationBar)) {
+            return baseMargin - mLocationBarBackgroundPadding.right;
+        } else {
+            return baseMargin - priorVisibleWidth + mLocationBarBackgroundPadding.left;
+        }
+    }
+
+    @Override
+    protected int getLocationBarBackgroundVerticalMargin(float expansion) {
+        if (!mUseModernDesign) return super.getLocationBarBackgroundVerticalMargin(expansion);
+
+        return mLocationBarVerticalMargin;
+    }
+
+    @Override
     protected int getLeftPositionOfLocationBarBackground(VisualState visualState) {
         if (!mAnimatingToolbarButtonAppearance && !mAnimatingToolbarButtonDisappearance) {
             return super.getLeftPositionOfLocationBarBackground(visualState);
-        } else {
-            int targetPosition = getViewBoundsLeftOfLocationBar(visualState);
-            int currentPosition = targetPosition + getLocationBarBackgroundLeftOffset();
-            return (int) MathUtils.interpolate(
-                    targetPosition, currentPosition, mToolbarButtonVisibilityPercent);
         }
+
+        int currentPosition = getViewBoundsLeftOfLocationBar(visualState);
+        int targetPosition = currentPosition + getLocationBarBackgroundLeftOffset();
+        return (int) MathUtils.interpolate(
+                currentPosition, targetPosition, mToolbarButtonVisibilityPercent);
+    }
+
+    @Override
+    protected int getFocusedLeftPositionOfLocationBarBackground() {
+        if (!mUseModernDesign) return super.getFocusedLeftPositionOfLocationBarBackground();
+
+        return mToolbarSidePadding;
     }
 
     @Override
     protected int getRightPositionOfLocationBarBackground(VisualState visualState) {
         if (!mAnimatingToolbarButtonAppearance && !mAnimatingToolbarButtonDisappearance) {
             return super.getRightPositionOfLocationBarBackground(visualState);
-        } else {
-            int targetPosition = getViewBoundsRightOfLocationBar(visualState);
-            int currentPosition = targetPosition - getLocationBarBackgroundRightOffset();
-            return (int) MathUtils.interpolate(
-                    targetPosition, currentPosition, mToolbarButtonVisibilityPercent);
         }
+
+        int currentPosition = getViewBoundsRightOfLocationBar(visualState);
+        int targetPosition = currentPosition - getLocationBarBackgroundRightOffset();
+        return (int) MathUtils.interpolate(
+                currentPosition, targetPosition, mToolbarButtonVisibilityPercent);
+    }
+
+    @Override
+    protected int getFocusedRightPositionOfLocationBarBackground() {
+        if (!mUseModernDesign) return super.getFocusedRightPositionOfLocationBarBackground();
+
+        return getWidth() - mToolbarSidePadding;
     }
 
     private int getToolbarButtonsWidthForBackgroundOffset() {
@@ -473,6 +549,13 @@
     }
 
     @Override
+    protected boolean shouldDrawLocationBarBackground() {
+        if (!mUseModernDesign) return super.shouldDrawLocationBarBackground();
+
+        return mLocationBar.getAlpha() > 0 || mForceDrawLocationBarBackground;
+    }
+
+    @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
 
@@ -487,6 +570,7 @@
     public void onNativeLibraryReady() {
         super.onNativeLibraryReady();
 
+        mUseModernDesign = ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT);
         mUseToolbarHandle = !FeatureUtilities.isChromeHomeExpandButtonEnabled();
 
         if (!mUseToolbarHandle) {
@@ -494,6 +578,47 @@
         } else {
             updateContentDescription();
         }
+
+        if (mUseModernDesign) initModernDesign();
+    }
+
+    /**
+     * Initializes the location bar background and changes parameters to match the "modern" visual
+     * design.
+     */
+    private void initModernDesign() {
+        // TODO(twellington): Move this to the constructor/XML after the modern design is on by
+        //                    default.
+        Resources res = getResources();
+        mLocationBarBackground =
+                ApiCompatibilityUtils.getDrawable(res, R.drawable.bottom_toolbar_background);
+        mLocationBarBackgroundCornerRadius =
+                res.getDimensionPixelSize(R.dimen.bottom_toolbar_background_corner_radius);
+        mLocationBarExtraFocusedLeftMargin =
+                res.getDimensionPixelSize(R.dimen.bottom_toolbar_background_focused_left_margin);
+
+        mLocationBarBackground.getPadding(mLocationBarBackgroundPadding);
+        mLocationBar.setPadding(mLocationBarBackgroundPadding.left,
+                mLocationBarBackgroundPadding.top, mLocationBarBackgroundPadding.right,
+                mLocationBarBackgroundPadding.bottom);
+
+        // The location bar content rect is used when anonymizing the URL. The anonymize rect
+        // must be inset so that it doesn't extend past the rounded corners of the toolbar
+        // background.
+        mLocationBarContentVerticalInset = (mLocationBarBackgroundCornerRadius / 2)
+                - res.getDimensionPixelSize(R.dimen.bottom_toolbar_background_lateral_inset);
+
+        mToolbarShadowPermanentlyHidden = true;
+        mToolbarShadow.setVisibility(View.GONE);
+
+        // TODO(twellington): remove or fix incognito chip before making the modern layout the
+        //                    default.
+
+        updateToolbarBackground(mVisualState);
+        updateVisualsForToolbarState();
+
+        invalidate();
+        requestLayout();
     }
 
     /**
@@ -544,6 +669,13 @@
             updateButtonsContainerVisibilityAndTranslation();
             updateMenuButtonClickableState();
         }
+
+        if (mUseModernDesign) {
+            mLocationBarBackground.setTint(isIncognito()
+                            ? Color.WHITE
+                            : ApiCompatibilityUtils.getColor(
+                                      getResources(), R.color.default_primary_color));
+        }
     }
 
     @Override
@@ -557,7 +689,7 @@
         super.updateLocationBarBackgroundBounds(out, visualState);
 
         // Allow the location bar to expand to the full height of the control container.
-        out.top -= getExtraTopMargin() * mUrlExpansionPercent;
+        if (!mUseModernDesign) out.top -= getExtraTopMargin() * mUrlExpansionPercent;
     }
 
     @Override
@@ -642,10 +774,10 @@
 
     @Override
     protected float getUrlActionsTranslationXForExpansionAnimation(
-            boolean isLocationBarRtl, boolean isRtl, float locationBarBaseTranslationX) {
+            boolean isLocationBarRtl, float locationBarBaseTranslationX) {
         if (!mHidingSomeToolbarButtons) {
             return super.getUrlActionsTranslationXForExpansionAnimation(
-                    isLocationBarRtl, isRtl, locationBarBaseTranslationX);
+                    isLocationBarRtl, locationBarBaseTranslationX);
         }
 
         float urlActionsTranslationX = 0;
@@ -661,6 +793,7 @@
         } else {
             urlActionsTranslationX += urlActionsTranslationXOffset;
         }
+
         return urlActionsTranslationX;
     }
 
@@ -789,6 +922,15 @@
         updateMenuButtonClickableState();
     }
 
+    @Override
+    protected int getToolbarColorForVisualState(final VisualState visualState) {
+        if (mUseModernDesign && visualState == VisualState.NORMAL) {
+            return ApiCompatibilityUtils.getColor(getResources(), R.color.modern_primary_color);
+        }
+
+        return super.getToolbarColorForVisualState(visualState);
+    }
+
     private void updateToolbarButtonVisibility() {
         boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModelImpl.java
index 4fb14026..7eb8d89 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModelImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModelImpl.java
@@ -5,12 +5,14 @@
 package org.chromium.chrome.browser.toolbar;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.dom_distiller.DomDistillerServiceFactory;
 import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
 import org.chromium.chrome.browser.ntp.NewTabPage;
@@ -18,6 +20,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.toolbar.ToolbarModel.ToolbarModelDelegate;
+import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
 import org.chromium.components.dom_distiller.core.DomDistillerService;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
@@ -167,10 +170,10 @@
     @Override
     public int getPrimaryColor() {
         if (mBottomSheet != null) {
-            int colorId =
-                    isIncognito() ? R.color.incognito_primary_color : R.color.default_primary_color;
-            return ApiCompatibilityUtils.getColor(
-                    ContextUtils.getApplicationContext().getResources(), colorId);
+            boolean useModernDesign = ChromeFeatureList.isInitialized()
+                    && ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT);
+            Resources res = ContextUtils.getApplicationContext().getResources();
+            return ColorUtils.getDefaultThemeColor(res, useModernDesign, isIncognito());
         }
         return mPrimaryColor;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 273d26f..1218b24 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -123,7 +123,8 @@
     private TintedImageButton mHomeButton;
     private TextView mUrlBar;
     protected View mUrlActionContainer;
-    private ImageView mToolbarShadow;
+    protected ImageView mToolbarShadow;
+    protected boolean mToolbarShadowPermanentlyHidden;
 
     private final int mProgressBackBackgroundColorWhite;
 
@@ -197,9 +198,9 @@
     protected ColorDrawable mToolbarBackground;
 
     /** The omnibox background (white with a shadow). */
-    private Drawable mLocationBarBackground;
+    protected Drawable mLocationBarBackground;
 
-    private boolean mForceDrawLocationBarBackground;
+    protected boolean mForceDrawLocationBarBackground;
     private TabSwitcherDrawable mTabSwitcherButtonDrawable;
     private TabSwitcherDrawable mTabSwitcherButtonDrawableLight;
 
@@ -207,9 +208,9 @@
     private final int mDarkModeDefaultColor;
 
     /** The boundaries of the omnibox, without the NTP-specific offset applied. */
-    private final Rect mLocationBarBackgroundBounds = new Rect();
+    protected final Rect mLocationBarBackgroundBounds = new Rect();
 
-    private final Rect mLocationBarBackgroundPadding = new Rect();
+    protected final Rect mLocationBarBackgroundPadding = new Rect();
     private final Rect mBackgroundOverlayBounds = new Rect();
 
     /** Offset applied to the bounds of the omnibox if we are showing a New Tab Page. */
@@ -228,7 +229,7 @@
     protected final Point mNtpSearchBoxTranslation = new Point();
 
     protected final int mToolbarSidePadding;
-    private final int mLocationBarBackgroundCornerRadius;
+    protected int mLocationBarBackgroundCornerRadius;
     protected int mLocationBarVerticalMargin;
 
     private ValueAnimator mBrandColorTransitionAnimation;
@@ -343,9 +344,9 @@
         mLocationBarBackground =
                 ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.card_single);
         mLocationBarBackground.getPadding(mLocationBarBackgroundPadding);
-        mLocationBar.setPadding(
-                mLocationBarBackgroundPadding.left, mLocationBarBackgroundPadding.top,
-                mLocationBarBackgroundPadding.right, mLocationBarBackgroundPadding.bottom);
+        mLocationBar.setPadding(mLocationBarBackgroundPadding.left,
+                mLocationBarBackgroundPadding.top, mLocationBarBackgroundPadding.right,
+                mLocationBarBackgroundPadding.bottom);
 
         setLayoutTransition(null);
 
@@ -609,12 +610,8 @@
                 priorVisibleWidth += child.getMeasuredWidth();
             }
 
-            width = containerWidth - (2 * mToolbarSidePadding) + priorVisibleWidth;
-            if (ApiCompatibilityUtils.isLayoutRtl(mLocationBar)) {
-                leftMargin = mToolbarSidePadding;
-            } else {
-                leftMargin = -priorVisibleWidth + mToolbarSidePadding;
-            }
+            width = getFocusedLocationBarWidth(containerWidth, priorVisibleWidth);
+            leftMargin = getFocusedLocationBarLeftMargin(priorVisibleWidth);
         } else {
             width = mUnfocusedLocationBarLayoutWidth;
             leftMargin = mUnfocusedLocationBarLayoutLeft;
@@ -633,6 +630,27 @@
     }
 
     /**
+     * @param containerWidth The width of the view containing the location bar.
+     * @param priorVisibleWidth The width of any visible views prior to the location bar.
+     * @return The width of the location bar when it has focus.
+     */
+    protected int getFocusedLocationBarWidth(int containerWidth, int priorVisibleWidth) {
+        return containerWidth - (2 * mToolbarSidePadding) + priorVisibleWidth;
+    }
+
+    /**
+     * @param priorVisibleWidth The width of any visible views prior to the location bar.
+     * @return The left margin of the location bar when it has focus.
+     */
+    protected int getFocusedLocationBarLeftMargin(int priorVisibleWidth) {
+        if (ApiCompatibilityUtils.isLayoutRtl(mLocationBar)) {
+            return mToolbarSidePadding;
+        } else {
+            return -priorVisibleWidth + mToolbarSidePadding;
+        }
+    }
+
+    /**
      * @param visualState The current {@link VisualState} of the toolbar.
      * @return The left bounds of the location bar, accounting for any buttons on the left side
      *         of the toolbar.
@@ -785,7 +803,7 @@
         // - The right most visible location bar child view.
         // - The bottom of the viewport is aligned with the bottom of the location bar.
         // Additional padding can be applied for use during animations.
-        int verticalMargin = (int) MathUtils.interpolate(mLocationBarVerticalMargin, 0, expansion);
+        int verticalMargin = getLocationBarBackgroundVerticalMargin(expansion);
         out.set(leftViewPosition,
                 mLocationBar.getTop() + verticalMargin,
                 rightViewPosition,
@@ -793,6 +811,15 @@
     }
 
     /**
+     * @param expansion The current url expansion percent.
+     * @return The vertical margin to apply to the location bar background. The margin is used to
+     *         clip the background.
+     */
+    protected int getLocationBarBackgroundVerticalMargin(float expansion) {
+        return (int) MathUtils.interpolate(mLocationBarVerticalMargin, 0, expansion);
+    }
+
+    /**
      * @param visualState The current {@link VisualState} of the toolbar.
      * @return The left drawing position for the location bar background.
      */
@@ -800,11 +827,19 @@
         float expansion = getExpansionPercentForVisualState(visualState);
         int leftViewPosition =
                 (int) MathUtils.interpolate(getViewBoundsLeftOfLocationBar(visualState),
-                        -mLocationBarBackgroundCornerRadius, expansion);
+                        getFocusedLeftPositionOfLocationBarBackground(), expansion);
         return leftViewPosition;
     }
 
     /**
+     * @return The left drawing position for the location bar background when the location bar
+     *         has focus.
+     */
+    protected int getFocusedLeftPositionOfLocationBarBackground() {
+        return -mLocationBarBackgroundCornerRadius;
+    }
+
+    /**
      * @param visualState The current {@link VisualState} of the toolbar.
      * @return The right drawing position for the location bar background.
      */
@@ -812,11 +847,19 @@
         float expansion = getExpansionPercentForVisualState(visualState);
         int rightViewPosition =
                 (int) MathUtils.interpolate(getViewBoundsRightOfLocationBar(visualState),
-                        getWidth() + mLocationBarBackgroundCornerRadius, expansion);
+                        getFocusedRightPositionOfLocationBarBackground(), expansion);
 
         return rightViewPosition;
     }
 
+    /**
+     * @return The right drawing position for the location bar background when the location bar
+     *         has focus.
+     */
+    protected int getFocusedRightPositionOfLocationBarBackground() {
+        return getWidth() + mLocationBarBackgroundCornerRadius;
+    }
+
     private float getExpansionPercentForVisualState(VisualState visualState) {
         return visualState == VisualState.NEW_TAB_NORMAL ? 1 : mUrlExpansionPercent;
     }
@@ -899,12 +942,10 @@
             }
         }
 
-        boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this);
-
         float locationBarTranslationX;
         // Get the padding straight from the location bar instead of
         // |mLocationBarBackgroundPadding|, because it might be different in incognito mode.
-        if (isRtl) {
+        if (isLocationBarRtl) {
             locationBarTranslationX = locationBarBaseTranslationX
                     + mLocationBarNtpOffsetRight - mLocationBar.getPaddingRight();
         } else {
@@ -914,7 +955,7 @@
 
         mLocationBar.setTranslationX(locationBarTranslationX);
         mUrlActionContainer.setTranslationX(getUrlActionsTranslationXForExpansionAnimation(
-                isLocationBarRtl, isRtl, locationBarBaseTranslationX));
+                isLocationBarRtl, locationBarBaseTranslationX));
         mLocationBar.setUrlFocusChangePercent(mUrlExpansionPercent);
 
         // Force an invalidation of the location bar to properly handle the clipping of the URL
@@ -928,13 +969,13 @@
      * animation.
      *
      * @param isLocationBarRtl Whether the location bar layout is RTL.
-     * @param isRtl Whether the toolbar layout is RTL.
      * @param locationBarBaseTranslationX The base location bar translation for the URL expansion
      *                                    animation.
      * @return The translation X for the URL actions container.
      */
     protected float getUrlActionsTranslationXForExpansionAnimation(
-            boolean isLocationBarRtl, boolean isRtl, float locationBarBaseTranslationX) {
+            boolean isLocationBarRtl, float locationBarBaseTranslationX) {
+        boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this);
         float urlActionsTranslationX = 0;
         if (!isLocationBarRtl || isRtl) {
             // Negate the location bar translation to keep the URL action container in the same
@@ -963,7 +1004,7 @@
             mToolbarButtonsContainer.setTranslationY(0);
             mHomeButton.setTranslationY(0);
         }
-        mToolbarShadow.setAlpha(1f);
+        if (!mToolbarShadowPermanentlyHidden) mToolbarShadow.setAlpha(1f);
         mLocationBar.setAlpha(1);
         mForceDrawLocationBarBackground = false;
         mLocationBarBackgroundAlpha = 255;
@@ -986,7 +1027,7 @@
         if (mTabSwitcherState == TAB_SWITCHER || mTabSwitcherState == ENTERING_TAB_SWITCHER) return;
 
         setAncestorsShouldClipChildren(mUrlExpansionPercent == 0f);
-        mToolbarShadow.setAlpha(0f);
+        if (!mToolbarShadowPermanentlyHidden) mToolbarShadow.setAlpha(0f);
 
         NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
         ntp.getSearchBoxBounds(mNtpSearchBoxBounds, mNtpSearchBoxTranslation);
@@ -1261,8 +1302,7 @@
             }
             mLocationBarBackground.setAlpha(backgroundAlpha);
 
-            if ((mLocationBar.getAlpha() > 0 || mForceDrawLocationBarBackground)
-                    && !mTextureCaptureMode) {
+            if (shouldDrawLocationBarBackground()) {
                 mLocationBarBackground.setBounds(
                         mLocationBarBackgroundBounds.left + mLocationBarBackgroundNtpOffset.left
                                 - mLocationBarBackgroundPadding.left,
@@ -1312,6 +1352,15 @@
         return retVal;
     }
 
+    /**
+     * @return Whether the location bar background should be drawn in
+     *         {@link #drawLocationBar(Canvas, long)}.
+     */
+    protected boolean shouldDrawLocationBarBackground() {
+        return (mLocationBar.getAlpha() > 0 || mForceDrawLocationBarBackground)
+                && !mTextureCaptureMode;
+    }
+
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         mBackgroundOverlayBounds.set(0, 0, w, h);
@@ -1321,6 +1370,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
+
         mToolbarShadow = (ImageView) getRootView().findViewById(R.id.toolbar_shadow);
 
         // This is a workaround for http://crbug.com/574928. Since Jelly Bean is the lowest version
@@ -1503,7 +1553,7 @@
         assert mTextureCaptureMode != textureMode;
         mTextureCaptureMode = textureMode;
         if (mTextureCaptureMode) {
-            mToolbarShadow.setVisibility(VISIBLE);
+            if (!mToolbarShadowPermanentlyHidden) mToolbarShadow.setVisibility(VISIBLE);
             mPreTextureCaptureAlpha = getAlpha();
             setAlpha(1);
         } else {
@@ -1852,6 +1902,8 @@
 
         triggerUrlFocusAnimation(hasFocus);
 
+        if (mToolbarShadowPermanentlyHidden) return;
+
         TransitionDrawable shadowDrawable = (TransitionDrawable) mToolbarShadow.getDrawable();
         if (hasFocus) {
             dismissTabSwitcherCallout();
@@ -2078,6 +2130,9 @@
     @Override
     protected void handleFindToolbarStateChange(boolean showing) {
         setVisibility(showing ? View.GONE : View.VISIBLE);
+
+        if (mToolbarShadowPermanentlyHidden) return;
+
         TransitionDrawable shadowDrawable = (TransitionDrawable) mToolbarShadow.getDrawable();
         if (showing) {
             shadowDrawable.startTransition(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
@@ -2092,6 +2147,8 @@
     }
 
     private void updateShadowVisibility() {
+        if (mToolbarShadowPermanentlyHidden) return;
+
         boolean shouldDrawShadow = shouldDrawShadow();
         int shadowVisibility = shouldDrawShadow ? View.VISIBLE : View.INVISIBLE;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/ColorUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/util/ColorUtils.java
index 2605a86..c9da56273 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/ColorUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/ColorUtils.java
@@ -53,15 +53,33 @@
     }
 
     /**
+     * Determines the default theme color based on the provided parameters.
+     * @param res {@link Resources} used to retrieve colors.
+     * @param useModernDesign Whether to use the "modern" visual design.
+     * @param isIncognito Whether to retrieve the default theme color for incognito mode.
+     * @return The default theme color.
+     */
+    public static int getDefaultThemeColor(
+            Resources res, boolean useModernDesign, boolean isIncognito) {
+        return isIncognito ? ApiCompatibilityUtils.getColor(res, R.color.incognito_primary_color)
+                : useModernDesign
+                    ? ApiCompatibilityUtils.getColor(res, R.color.modern_primary_color)
+                    : ApiCompatibilityUtils.getColor(res, R.color.default_primary_color);
+    }
+
+    /**
      * @return The base color for the textbox given a toolbar background color.
      */
-    public static int getTextBoxColorForToolbarBackground(Resources res, boolean isNtp, int color) {
+    public static int getTextBoxColorForToolbarBackground(
+            Resources res, boolean isNtp, int color, boolean useModernDesign) {
         if (shouldUseOpaqueTextboxBackground(color)) {
             // NTP should have no visible textbox in the toolbar, so just return the toolbar's
             // background color.
             if (isNtp) return ApiCompatibilityUtils.getColor(res, R.color.ntp_bg);
 
-            return Color.WHITE;
+            return useModernDesign
+                    ? ApiCompatibilityUtils.getColor(res, R.color.default_primary_color)
+                    : Color.WHITE;
         }
         return getColorWithOverlay(color, Color.WHITE, LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
index bf9dee6..7c83d75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
@@ -269,6 +269,11 @@
 
     @Override
     public boolean onNavigationItemSelected(MenuItem item) {
+        if (mBottomSheet.getSheetState() == BottomSheet.SHEET_STATE_PEEK
+                && !mShouldOpenSheetOnNextContentChange) {
+            return false;
+        }
+
         if (mSelectedItemId == item.getItemId()) return false;
 
         mBottomSheet.defocusOmnibox();
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index ecaf16ad..104323d 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -267,9 +267,6 @@
         <message name="IDS_UNINSTALL_CLOSE_APP" desc="Message to user when uninstall detects other app instance running">
           Please close all Chromium windows and try again.
         </message>
-        <message name="IDS_UNINSTALL_CLOSE_APP_IMMERSIVE" desc="Message to user when uninstall detects other app instance running, possibly in the Windows 8 immersive mode">
-          Please close all Chromium windows (including those in Windows 8 mode) and try again.
-        </message>
         <message name="IDS_UNINSTALL_VERIFY" desc="Message to confirm user wants to uninstall">
           Are you sure you want to uninstall Chromium?
         </message>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index f2d4eff..60985aa 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -271,9 +271,6 @@
         <message name="IDS_UNINSTALL_CLOSE_APP" desc="Message to user when uninstall detects other app instance running">
           Please close all Google Chrome windows and try again.
         </message>
-        <message name="IDS_UNINSTALL_CLOSE_APP_IMMERSIVE" desc="Message to user when uninstall detects other app instance running, possibly in the Windows 8 immersive mode">
-          Please close all Google Chrome windows (including those in Windows 8 mode) and try again.
-        </message>
         <message name="IDS_UNINSTALL_VERIFY" desc="Message to confirm user wants to uninstall">
           Are you sure you want to uninstall Google Chrome?
         </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 5c94611..0844a81 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2876,6 +2876,10 @@
      flag_descriptions::kEnableAutofillCreditCardUploadCvcPromptDescription,
      kOsDesktop,
      FEATURE_VALUE_TYPE(autofill::kAutofillUpstreamRequestCvcIfMissing)},
+    {"enable-autofill-credit-card-upload-new-ui",
+     flag_descriptions::kEnableAutofillCreditCardUploadNewUiName,
+     flag_descriptions::kEnableAutofillCreditCardUploadNewUiDescription,
+     kOsDesktop, FEATURE_VALUE_TYPE(autofill::kAutofillUpstreamShowNewUi)},
     {"enable-autofill-credit-card-bank-name-display",
      flag_descriptions::kEnableAutofillCreditCardBankNameDisplayName,
      flag_descriptions::kEnableAutofillCreditCardBankNameDisplayDescription,
diff --git a/chrome/browser/android/compositor/layer/toolbar_layer.cc b/chrome/browser/android/compositor/layer/toolbar_layer.cc
index e2389b8b..a76f335 100644
--- a/chrome/browser/android/compositor/layer/toolbar_layer.cc
+++ b/chrome/browser/android/compositor/layer/toolbar_layer.cc
@@ -71,7 +71,8 @@
       gfx::PointF(resource->toolbar_rect().origin()));
   toolbar_background_layer_->SetBackgroundColor(toolbar_background_color);
 
-  bool url_bar_visible = (resource->location_bar_content_rect().width() != 0);
+  bool url_bar_visible =
+      (resource->location_bar_content_rect().width() != 0) && url_bar_alpha > 0;
   url_bar_background_layer_->SetHideLayerAndSubtree(!url_bar_visible);
   if (url_bar_visible) {
     ui::NinePatchResource* url_bar_background_resource =
diff --git a/chrome/browser/android/history_report/delta_file_backend_leveldb.cc b/chrome/browser/android/history_report/delta_file_backend_leveldb.cc
index 4dff7767..a16f47a 100644
--- a/chrome/browser/android/history_report/delta_file_backend_leveldb.cc
+++ b/chrome/browser/android/history_report/delta_file_backend_leveldb.cc
@@ -91,7 +91,7 @@
 DeltaFileBackend::~DeltaFileBackend() {}
 
 bool DeltaFileBackend::Init() {
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = true;
   options.max_open_files = 0;  // Use minimum number of files.
   options.comparator = leveldb_cmp_.get();
diff --git a/chrome/browser/android/history_report/usage_reports_buffer_backend.cc b/chrome/browser/android/history_report/usage_reports_buffer_backend.cc
index 6a1aa49a..f7f6ea7 100644
--- a/chrome/browser/android/history_report/usage_reports_buffer_backend.cc
+++ b/chrome/browser/android/history_report/usage_reports_buffer_backend.cc
@@ -33,7 +33,7 @@
 UsageReportsBufferBackend::~UsageReportsBufferBackend() {}
 
 bool UsageReportsBufferBackend::Init() {
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = true;
   options.max_open_files = 0;  // Use minimum number of files.
   std::string path = db_file_name_.value();
diff --git a/chrome/browser/android/vr_shell/vr_shell_delegate.cc b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
index 7a76d7c6..15d50ea 100644
--- a/chrome/browser/android/vr_shell/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
@@ -108,10 +108,7 @@
   }
 
   if (pending_successful_present_request_) {
-    gvr_delegate_->ConnectPresentingService(
-        std::move(submit_client_), std::move(presentation_provider_request_));
-    base::ResetAndReturn(&present_callback_).Run(true);
-    pending_successful_present_request_ = false;
+    SetPresentResult(true);
   }
   JNIEnv* env = AttachCurrentThread();
   std::unique_ptr<VrCoreInfo> vr_core_info = MakeVrCoreInfo(env);
@@ -129,25 +126,30 @@
 void VrShellDelegate::SetPresentResult(JNIEnv* env,
                                        const JavaParamRef<jobject>& obj,
                                        jboolean success) {
+  SetPresentResult(static_cast<bool>(success));
+}
+
+void VrShellDelegate::SetPresentResult(bool success) {
   CHECK(!present_callback_.is_null());
+  if (!success) {
+    pending_successful_present_request_ = false;
+    base::ResetAndReturn(&present_callback_).Run(false);
+    return;
+  }
+
   if (!gvr_delegate_) {
-    if (success) {
-      // We have to wait until the GL thread is ready since we have to pass it
-      // the VRSubmitFrameClient.
-      pending_successful_present_request_ = true;
-    }
+    // We have to wait until the GL thread is ready since we have to pass it
+    // the VRSubmitFrameClient.
+    pending_successful_present_request_ = true;
     return;
   }
 
-  if (success) {
-    gvr_delegate_->ConnectPresentingService(
-        std::move(submit_client_), std::move(presentation_provider_request_));
-  }
+  gvr_delegate_->ConnectPresentingService(
+      std::move(submit_client_), std::move(presentation_provider_request_));
 
-  base::ResetAndReturn(&present_callback_).Run(success);
+  base::ResetAndReturn(&present_callback_).Run(true);
   pending_successful_present_request_ = false;
-  if (!success)
-    return;
+
   device::VRDisplayImpl* presenting_display =
       device_provider_->Device()->GetPresentingDisplay();
   CHECK(presenting_display);
diff --git a/chrome/browser/android/vr_shell/vr_shell_delegate.h b/chrome/browser/android/vr_shell/vr_shell_delegate.h
index 7e20aa8..440f81cf 100644
--- a/chrome/browser/android/vr_shell/vr_shell_delegate.h
+++ b/chrome/browser/android/vr_shell/vr_shell_delegate.h
@@ -97,6 +97,7 @@
   void OnFocusedAndActivatable(device::VRDisplayImpl* display);
   void OnLostFocusedAndActivatable();
   void SetListeningForActivate(bool listening);
+  void SetPresentResult(bool success);
 
   std::unique_ptr<VrCoreInfo> MakeVrCoreInfo(JNIEnv* env);
 
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc
index 37e0a13..90172b82 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.cc
+++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -44,6 +44,7 @@
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "services/service_manager/public/cpp/service.h"
+#include "services/ui/common/image_cursors_set.h"
 #include "services/ui/public/interfaces/constants.mojom.h"
 #include "services/ui/service.h"
 
@@ -292,9 +293,10 @@
 
   if (chromeos::GetAshConfig() == ash::Config::MUS) {
     service_manager::EmbeddedServiceInfo info;
+    image_cursors_set_ = base::MakeUnique<ui::ImageCursorsSet>();
     info.factory = base::Bind(&CreateEmbeddedUIService,
                               base::ThreadTaskRunnerHandle::Get(),
-                              image_cursors_set_.GetWeakPtr(),
+                              image_cursors_set_->GetWeakPtr(),
                               content::GetDiscardableSharedMemoryManager());
     info.use_own_thread = true;
     info.message_loop_type = base::MessageLoop::TYPE_UI;
@@ -313,6 +315,10 @@
   system_clock_.reset();
 }
 
+void BrowserProcessPlatformPart::DestroyImageCursorsSet() {
+  image_cursors_set_.reset();
+}
+
 void BrowserProcessPlatformPart::AddCompatibleCrOSComponent(
     const std::string& name) {
   compatible_cros_components_.insert(name);
diff --git a/chrome/browser/browser_process_platform_part_chromeos.h b/chrome/browser/browser_process_platform_part_chromeos.h
index 6aaaed8..69dbb7b 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.h
+++ b/chrome/browser/browser_process_platform_part_chromeos.h
@@ -13,7 +13,6 @@
 #include "base/macros.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/browser_process_platform_part_base.h"
-#include "services/ui/common/image_cursors_set.h"
 
 namespace chromeos {
 class ChromeSessionManager;
@@ -38,6 +37,7 @@
 }
 
 namespace ui {
+class ImageCursorsSet;
 class InputDeviceControllerClient;
 }
 
@@ -105,6 +105,8 @@
   chromeos::system::SystemClock* GetSystemClock();
   void DestroySystemClock();
 
+  void DestroyImageCursorsSet();
+
   void AddCompatibleCrOSComponent(const std::string& name);
 
   bool IsCompatibleCrOSComponent(const std::string& name);
@@ -142,7 +144,7 @@
   base::flat_set<std::string> compatible_cros_components_;
 
   // Used by the UI Service.
-  ui::ImageCursorsSet image_cursors_set_;
+  std::unique_ptr<ui::ImageCursorsSet> image_cursors_set_;
 
 #if defined(USE_OZONE)
   std::unique_ptr<ui::InputDeviceControllerClient>
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index c2702d8..50e605a 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -33,7 +33,6 @@
 #include "base/win/pe_image.h"
 #include "base/win/registry.h"
 #include "base/win/win_util.h"
-#include "base/win/windows_version.h"
 #include "base/win/wrapped_window_proc.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/conflicts/enumerate_input_method_editors_win.h"
@@ -47,7 +46,6 @@
 #include "chrome/browser/safe_browsing/chrome_cleaner/settings_resetter_win.h"
 #include "chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h"
 #include "chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_controller.h"
-#include "chrome/browser/shell_integration.h"
 #include "chrome/browser/ui/simple_message_box.h"
 #include "chrome/browser/ui/uninstall_browser_prompt.h"
 #include "chrome/browser/win/browser_util.h"
@@ -243,15 +241,9 @@
 }
 
 void ShowCloseBrowserFirstMessageBox() {
-  int message_id = IDS_UNINSTALL_CLOSE_APP;
-  if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
-      (shell_integration::GetDefaultBrowser() ==
-       shell_integration::IS_DEFAULT)) {
-    message_id = IDS_UNINSTALL_CLOSE_APP_IMMERSIVE;
-  }
-  chrome::ShowWarningMessageBox(NULL,
-                                l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
-                                l10n_util::GetStringUTF16(message_id));
+  chrome::ShowWarningMessageBox(
+      nullptr, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+      l10n_util::GetStringUTF16(IDS_UNINSTALL_CLOSE_APP));
 }
 
 void MaybePostSettingsResetPrompt() {
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
index c9136c83..520f2a3 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.cc
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/app_launch_controller.h"
 
+#include "ash/shell.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
@@ -29,6 +30,7 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chromeos/settings/cros_settings_names.h"
@@ -39,6 +41,7 @@
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/common/features/feature_session_type.h"
 #include "net/base/network_change_notifier.h"
+#include "ui/keyboard/keyboard_util.h"
 
 namespace chromeos {
 
@@ -310,6 +313,15 @@
   // This is needed to trigger input method extensions being loaded.
   profile_->InitChromeOSPreferences();
 
+  // Reset virtual keyboard to use IME engines in app profile early.
+  if (!ash_util::IsRunningInMash()) {
+    if (keyboard::IsKeyboardEnabled())
+      ash::Shell::Get()->CreateKeyboard();
+  } else {
+    // TODO(xiyuan): Update with mash VK work http://crbug.com/648733
+    NOTIMPLEMENTED();
+  }
+
   kiosk_profile_loader_.reset();
   startup_app_launcher_.reset(
       new StartupAppLauncher(profile_, app_id_, diagnostic_mode_, this));
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 719356c1..990d3a5 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -251,8 +251,18 @@
 void ChromeDownloadManagerDelegate::SetNextId(uint32_t next_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!profile_->IsOffTheRecord());
-  DCHECK_NE(content::DownloadItem::kInvalidId, next_id);
-  next_download_id_ = next_id;
+
+  // |content::DownloadItem::kInvalidId| will be returned only when download
+  // database failed to initialize.
+  bool download_db_available = (next_id != content::DownloadItem::kInvalidId);
+  RecordDatabaseAvailability(download_db_available);
+  if (download_db_available) {
+    next_download_id_ = next_id;
+  } else {
+    // Still download files without download database, all download history in
+    // this browser session will not be persisted.
+    next_download_id_ = content::DownloadItem::kInvalidId + 1;
+  }
 
   IdCallbackVector callbacks;
   id_callbacks_.swap(callbacks);
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index 9bb046c..dc59b507 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -152,8 +152,11 @@
       uint32_t download_id,
       const base::Closure& user_complete_callback);
 
+  // Sets the next download id based on download database records, and runs all
+  // cached id callbacks.
   void SetNextId(uint32_t id);
 
+  // Runs the |callback| with next id. Results in the download being started.
   void ReturnNextId(const content::DownloadIdCallback& callback);
 
   void OnDownloadTargetDetermined(
@@ -172,7 +175,14 @@
                                               bool show_download_in_folder);
 
   Profile* profile_;
+
+  // Incremented by one for each download, the first available download id is
+  // assigned from history database or 1 when history database fails to
+  // intialize.
   uint32_t next_download_id_;
+
+  // The |GetNextId| callbacks that may be cached before loading the download
+  // database.
   IdCallbackVector id_callbacks_;
   std::unique_ptr<DownloadPrefs> download_prefs_;
 
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
index 9661b63..bb93527 100644
--- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -243,12 +243,16 @@
   DownloadPrefs* download_prefs();
   PrefService* pref_service();
 
+  const std::vector<uint32_t>& download_ids() const { return download_ids_; }
+  void GetNextId(uint32_t next_id) { download_ids_.emplace_back(next_id); }
+
  private:
   sync_preferences::TestingPrefServiceSyncable* pref_service_;
   base::ScopedTempDir test_download_dir_;
   std::unique_ptr<content::MockDownloadManager> download_manager_;
   std::unique_ptr<TestChromeDownloadManagerDelegate> delegate_;
   MockWebContentsDelegate web_contents_delegate_;
+  std::vector<uint32_t> download_ids_;
 };
 
 ChromeDownloadManagerDelegateTest::ChromeDownloadManagerDelegateTest()
@@ -615,6 +619,30 @@
   VerifyAndClearExpectations();
 }
 
+TEST_F(ChromeDownloadManagerDelegateTest, WithoutHistoryDbNextId) {
+  content::DownloadIdCallback id_callback = base::Bind(
+      &ChromeDownloadManagerDelegateTest::GetNextId, base::Unretained(this));
+  delegate()->GetNextId(id_callback);
+  delegate()->GetNextId(id_callback);
+  // When download database fails to initialize, id will be set to
+  // |content::DownloadItem::kInvalidId|.
+  delegate()->GetDownloadIdReceiverCallback().Run(
+      content::DownloadItem::kInvalidId);
+  std::vector<uint32_t> expected_ids = std::vector<uint32_t>{1u, 2u};
+  EXPECT_EQ(expected_ids, download_ids());
+}
+
+TEST_F(ChromeDownloadManagerDelegateTest, WithHistoryDbNextId) {
+  content::DownloadIdCallback id_callback = base::Bind(
+      &ChromeDownloadManagerDelegateTest::GetNextId, base::Unretained(this));
+  delegate()->GetNextId(id_callback);
+  delegate()->GetNextId(id_callback);
+  // Simulates a valid download database with no records.
+  delegate()->GetDownloadIdReceiverCallback().Run(1u);
+  std::vector<uint32_t> expected_ids = std::vector<uint32_t>{1u, 2u};
+  EXPECT_EQ(expected_ids, download_ids());
+}
+
 #if defined(FULL_SAFE_BROWSING)
 namespace {
 
diff --git a/chrome/browser/download/download_stats.cc b/chrome/browser/download/download_stats.cc
index 6477de7d..bed151aa 100644
--- a/chrome/browser/download/download_stats.cc
+++ b/chrome/browser/download/download_stats.cc
@@ -50,3 +50,7 @@
                             open_method,
                             DOWNLOAD_OPEN_METHOD_LAST_ENTRY);
 }
+
+void RecordDatabaseAvailability(bool is_available) {
+  UMA_HISTOGRAM_BOOLEAN("Download.Database.IsAvailable", is_available);
+}
diff --git a/chrome/browser/download/download_stats.h b/chrome/browser/download/download_stats.h
index cec8776..495b783 100644
--- a/chrome/browser/download/download_stats.h
+++ b/chrome/browser/download/download_stats.h
@@ -90,4 +90,8 @@
 // Record how a download was opened.
 void RecordDownloadOpenMethod(ChromeDownloadOpenMethod open_method);
 
+// Record if the database is available to provide the next download id before
+// starting all downloads.
+void RecordDatabaseAvailability(bool is_available);
+
 #endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_STATS_H_
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index bb23cb3..4557c3d 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -252,6 +252,8 @@
     "api/image_writer_private/removable_storage_provider_chromeos.cc",
     "api/image_writer_private/removable_storage_provider_mac.cc",
     "api/image_writer_private/removable_storage_provider_win.cc",
+    "api/image_writer_private/unzip_helper.cc",
+    "api/image_writer_private/unzip_helper.h",
     "api/image_writer_private/write_from_file_operation.cc",
     "api/image_writer_private/write_from_file_operation.h",
     "api/image_writer_private/write_from_url_operation.cc",
diff --git a/chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation.cc b/chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation.cc
index 6e62c6e..b28d8c9 100644
--- a/chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation.cc
+++ b/chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation.cc
@@ -27,6 +27,7 @@
 DestroyPartitionsOperation::~DestroyPartitionsOperation() {}
 
 void DestroyPartitionsOperation::StartImpl() {
+  DCHECK(IsRunningInCorrectSequence());
   if (!base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &image_path_)) {
     Error(error::kTempFileError);
     return;
@@ -41,8 +42,7 @@
     return;
   }
 
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
+  PostTask(
       base::BindOnce(&DestroyPartitionsOperation::Write, this,
                      base::Bind(&DestroyPartitionsOperation::Finish, this)));
 }
diff --git a/chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation_unittest.cc b/chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation_unittest.cc
index 491ff82..5bc4932b 100644
--- a/chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation_unittest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation_unittest.cc
@@ -24,6 +24,20 @@
   TestingProfile profile;
   MockOperationManager manager(&profile);
 
+#if !defined(OS_CHROMEOS)
+  auto set_up_utility_client_progress_simulation =
+      [](FakeImageWriterClient* client) {
+        std::vector<int> progress_list{0, 50, 100};
+        bool will_succeed = true;
+        client->SimulateProgressOnWrite(progress_list, will_succeed);
+        client->SimulateProgressOnVerifyWrite(progress_list, will_succeed);
+      };
+  // Sets up client for simulating Operation::Progress() on Operation::Write and
+  // Operation::VerifyWrite.
+  test_utils_.RunOnUtilityClientCreation(
+      base::BindOnce(set_up_utility_client_progress_simulation));
+#endif
+
   scoped_refptr<DestroyPartitionsOperation> operation(
       new DestroyPartitionsOperation(
           manager.AsWeakPtr(),
@@ -47,18 +61,8 @@
   EXPECT_CALL(manager, OnComplete(kDummyExtensionId)).Times(1);
   EXPECT_CALL(manager, OnError(kDummyExtensionId, _, _, _)).Times(0);
 
-  operation->Start();
-
-  base::RunLoop().RunUntilIdle();
-
-#if !defined(OS_CHROMEOS)
-  test_utils_.GetUtilityClient()->Progress(0);
-  test_utils_.GetUtilityClient()->Progress(50);
-  test_utils_.GetUtilityClient()->Progress(100);
-  test_utils_.GetUtilityClient()->Success();
-
-  base::RunLoop().RunUntilIdle();
-#endif
+  operation->PostTask(base::Bind(&Operation::Start, operation));
+  content::RunAllBlockingPoolTasksUntilIdle();
 }
 
 } // namespace
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
index 6031be4..2c4dc2e 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
@@ -67,26 +67,6 @@
     FileSystemChooseEntryFunction::StopSkippingPickerForTest();
   }
 
-#if !defined(OS_CHROMEOS)
-  void ImageWriterUtilityClientCall() {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&FakeImageWriterClient::Progress,
-                       test_utils_.GetUtilityClient(), 0));
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&FakeImageWriterClient::Progress,
-                       test_utils_.GetUtilityClient(), 50));
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&FakeImageWriterClient::Progress,
-                       test_utils_.GetUtilityClient(), 100));
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&FakeImageWriterClient::Success,
-                       test_utils_.GetUtilityClient()));
-  }
-#endif
 
  protected:
   base::MessageLoopForUI message_loop_;
@@ -107,12 +87,16 @@
       &selected_image);
 
 #if !defined(OS_CHROMEOS)
-  test_utils_.GetUtilityClient()->SetWriteCallback(base::Bind(
-      &ImageWriterPrivateApiTest::ImageWriterUtilityClientCall,
-      base::Unretained(this)));
-  test_utils_.GetUtilityClient()->SetVerifyCallback(base::Bind(
-      &ImageWriterPrivateApiTest::ImageWriterUtilityClientCall,
-      base::Unretained(this)));
+  auto set_up_utility_client_callbacks = [](FakeImageWriterClient* client) {
+    std::vector<int> progress_list{0, 50, 100};
+    client->SimulateProgressOnWrite(progress_list, true);
+    client->SimulateProgressOnVerifyWrite(progress_list, true);
+  };
+
+  // Sets up client for simulating Operation::Progress() on Operation::Write and
+  // Operation::VerifyWrite.
+  test_utils_.RunOnUtilityClientCreation(
+      base::BindOnce(set_up_utility_client_callbacks));
 #endif
 
   ASSERT_TRUE(RunPlatformAppTest("image_writer_private/write_from_file"))
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.cc
index 3ad3e5d..295ade13 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.cc
@@ -9,8 +9,7 @@
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/optional.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/common/extensions/removable_storage_writer.mojom.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_thread.h"
@@ -18,6 +17,14 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "ui/base/l10n/l10n_util.h"
 
+namespace extensions {
+namespace image_writer {
+
+namespace {
+ImageWriterUtilityClient::ImageWriterUtilityClientFactory*
+    g_factory_for_testing = nullptr;
+}  // namespace
+
 class ImageWriterUtilityClient::RemovableStorageWriterClientImpl
     : public extensions::mojom::RemovableStorageWriterClient {
  public:
@@ -26,7 +33,7 @@
       extensions::mojom::RemovableStorageWriterClientPtr* interface)
       : binding_(this, mojo::MakeRequest(interface)),
         image_writer_utility_client_(owner) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+    base::ThreadRestrictions::AssertIOAllowed();
 
     binding_.set_connection_error_handler(
         base::BindOnce(&ImageWriterUtilityClient::UtilityProcessError,
@@ -59,12 +66,25 @@
 
 ImageWriterUtilityClient::~ImageWriterUtilityClient() = default;
 
+// static
+scoped_refptr<ImageWriterUtilityClient> ImageWriterUtilityClient::Create() {
+  if (g_factory_for_testing)
+    return g_factory_for_testing->Run();
+  return make_scoped_refptr(new ImageWriterUtilityClient());
+}
+
+// static
+void ImageWriterUtilityClient::SetFactoryForTesting(
+    ImageWriterUtilityClientFactory* factory) {
+  g_factory_for_testing = factory;
+}
+
 void ImageWriterUtilityClient::Write(const ProgressCallback& progress_callback,
                                      const SuccessCallback& success_callback,
                                      const ErrorCallback& error_callback,
                                      const base::FilePath& source,
                                      const base::FilePath& target) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!removable_storage_writer_client_);
 
   progress_callback_ = progress_callback;
@@ -86,7 +106,7 @@
                                       const ErrorCallback& error_callback,
                                       const base::FilePath& source,
                                       const base::FilePath& target) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!removable_storage_writer_client_);
 
   progress_callback_ = progress_callback;
@@ -104,22 +124,22 @@
 }
 
 void ImageWriterUtilityClient::Cancel(const CancelCallback& cancel_callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(cancel_callback);
 
   ResetRequest();
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancel_callback);
+  base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancel_callback);
 }
 
 void ImageWriterUtilityClient::Shutdown() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   ResetRequest();
   utility_process_mojo_client_.reset();
 }
 
 void ImageWriterUtilityClient::StartUtilityProcessIfNeeded() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (utility_process_mojo_client_)
     return;
@@ -140,7 +160,7 @@
 }
 
 void ImageWriterUtilityClient::UtilityProcessError() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   OperationFailed("Utility process crashed or failed.");
   utility_process_mojo_client_.reset();
@@ -173,3 +193,6 @@
   success_callback_.Reset();
   error_callback_.Reset();
 }
+
+}  // namespace image_writer
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h
index 0df6304..183c073 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h
@@ -11,10 +11,13 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequence_checker.h"
 #include "chrome/common/extensions/removable_storage_writer.mojom.h"
 #include "content/public/browser/utility_process_mojo_client.h"
 
+namespace extensions {
+namespace image_writer {
+
 // Writes a disk image to a device inside the utility process. This
 // class lives on the FILE thread.
 class ImageWriterUtilityClient
@@ -24,8 +27,12 @@
   typedef base::Callback<void()> SuccessCallback;
   typedef base::Callback<void(int64_t)> ProgressCallback;
   typedef base::Callback<void(const std::string&)> ErrorCallback;
+  using ImageWriterUtilityClientFactory =
+      base::Callback<scoped_refptr<ImageWriterUtilityClient>()>;
 
-  ImageWriterUtilityClient();
+  static scoped_refptr<ImageWriterUtilityClient> Create();
+
+  static void SetFactoryForTesting(ImageWriterUtilityClientFactory* factory);
 
   // Starts the write operation.
   // |progress_callback|: Called periodically with the count of bytes processed.
@@ -61,7 +68,9 @@
 
  protected:
   friend class base::RefCountedThreadSafe<ImageWriterUtilityClient>;
+  friend class ImageWriterUtilityClientTest;
 
+  ImageWriterUtilityClient();
   virtual ~ImageWriterUtilityClient();
 
  private:
@@ -87,7 +96,12 @@
   std::unique_ptr<RemovableStorageWriterClientImpl>
       removable_storage_writer_client_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(ImageWriterUtilityClient);
 };
 
+}  // namespace image_writer
+}  // namespace extensions
+
 #endif  // CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_IMAGE_WRITER_UTILITY_CLIENT_H_
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client_browsertest.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client_browsertest.cc
index b81800d..dc42c2d 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client_browsertest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client_browsertest.cc
@@ -11,13 +11,20 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_restrictions.h"
+#include "chrome/browser/extensions/api/image_writer_private/operation.h"
 #include "chrome/common/extensions/removable_storage_writer.mojom.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/browser_thread.h"
 
+namespace extensions {
+namespace image_writer {
+
+namespace {
 constexpr int64_t kTestFileSize = 1 << 15;  // 32 kB
+}  // namespace
 
 class ImageWriterUtilityClientTest : public InProcessBrowserTest {
  public:
@@ -62,10 +69,9 @@
     verify_ = (option == VERIFY);
     cancel_ = (option == CANCEL);
 
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::Bind(&ImageWriterUtilityClientTest::StartWriteTest,
-                   base::Unretained(this)));
+    CreateTaskRunner()->PostTask(
+        FROM_HERE, base::Bind(&ImageWriterUtilityClientTest::StartWriteTest,
+                              base::Unretained(this)));
     run_loop.Run();
 
     EXPECT_TRUE(quit_called_);
@@ -77,11 +83,10 @@
 
     ASSERT_NE(option, WRITE);  // Verify tests do not WRITE.
     cancel_ = (option == CANCEL);
-
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::Bind(&ImageWriterUtilityClientTest::StartVerifyTest,
-                   base::Unretained(this)));
+    CreateTaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&ImageWriterUtilityClientTest::StartVerifyTest,
+                       base::Unretained(this)));
     run_loop.Run();
 
     EXPECT_TRUE(quit_called_);
@@ -93,7 +98,7 @@
 
  private:
   void StartWriteTest() {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+    DCHECK(IsRunningInCorrectSequence());
 
     if (!image_writer_utility_client_)
       image_writer_utility_client_ = new ImageWriterUtilityClient();
@@ -111,7 +116,7 @@
   }
 
   void Progress(int64_t progress) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+    DCHECK(IsRunningInCorrectSequence());
 
     progress_ = progress;
     if (!cancel_)
@@ -122,7 +127,7 @@
   }
 
   void Success() {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+    DCHECK(IsRunningInCorrectSequence());
 
     EXPECT_EQ(kTestFileSize, progress_);
     EXPECT_FALSE(cancel_);
@@ -133,14 +138,13 @@
       return;
     }
 
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::Bind(&ImageWriterUtilityClientTest::Shutdown,
-                   base::Unretained(this)));
+    GetTaskRunner()->PostTask(
+        FROM_HERE, base::Bind(&ImageWriterUtilityClientTest::Shutdown,
+                              base::Unretained(this)));
   }
 
   void StartVerifyTest() {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+    DCHECK(IsRunningInCorrectSequence());
 
     if (!image_writer_utility_client_)
       image_writer_utility_client_ = new ImageWriterUtilityClient();
@@ -158,33 +162,31 @@
   }
 
   void Failure(const std::string& error) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+    DCHECK(IsRunningInCorrectSequence());
 
     EXPECT_FALSE(error.empty());
     success_ = false;
     error_ = error;
 
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::Bind(&ImageWriterUtilityClientTest::Shutdown,
-                   base::Unretained(this)));
+    GetTaskRunner()->PostTask(
+        FROM_HERE, base::Bind(&ImageWriterUtilityClientTest::Shutdown,
+                              base::Unretained(this)));
   }
 
   void Verified() {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+    DCHECK(IsRunningInCorrectSequence());
 
     EXPECT_EQ(kTestFileSize, progress_);
     EXPECT_FALSE(cancel_);
     success_ = !cancel_;
 
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::Bind(&ImageWriterUtilityClientTest::Shutdown,
-                   base::Unretained(this)));
+    GetTaskRunner()->PostTask(
+        FROM_HERE, base::Bind(&ImageWriterUtilityClientTest::Shutdown,
+                              base::Unretained(this)));
   }
 
   void Cancelled() {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+    DCHECK(IsRunningInCorrectSequence());
 
     EXPECT_TRUE(cancel_);
     success_ = cancel_;
@@ -195,7 +197,7 @@
   }
 
   void Shutdown() {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+    DCHECK(IsRunningInCorrectSequence());
 
     image_writer_utility_client_->Shutdown();
 
@@ -209,6 +211,24 @@
     EXPECT_TRUE(base::WriteFile(path, fill.data(), kTestFileSize));
   }
 
+  base::SequencedTaskRunner* CreateTaskRunner() {
+    DCHECK(!task_runner_.get());
+    task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
+        Operation::blocking_task_traits());
+    return task_runner_.get();
+  }
+
+  base::SequencedTaskRunner* GetTaskRunner() {
+    DCHECK(task_runner_.get())
+        << "Called GetTaskRunner before creating TaskRunner.";
+    return task_runner_.get();
+  }
+
+  bool IsRunningInCorrectSequence() const {
+    base::ThreadRestrictions::AssertIOAllowed();
+    return task_runner_->RunsTasksInCurrentSequence();
+  }
+
   base::ScopedTempDir temp_dir_;
   base::FilePath test_device_;
   base::FilePath device_;
@@ -217,12 +237,14 @@
   base::Closure quit_closure_;
   bool quit_called_ = false;
 
+  // Lives on |task_runner_|.
   scoped_refptr<ImageWriterUtilityClient> image_writer_utility_client_;
   int64_t progress_ = 0;
   bool success_ = false;
   bool verify_ = false;
   bool cancel_ = false;
   std::string error_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(ImageWriterUtilityClientTest);
 };
@@ -318,3 +340,6 @@
   EXPECT_TRUE(success());
   EXPECT_TRUE(error().empty());
 }
+
+}  // namespace image_writer
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/operation.cc b/chrome/browser/extensions/api/image_writer_private/operation.cc
index e1a0dc1..0fedb395 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation.cc
@@ -8,24 +8,23 @@
 
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
-#include "base/lazy_instance.h"
+#include "base/task_scheduler/post_task.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h"
+#include "chrome/browser/extensions/api/image_writer_private/unzip_helper.h"
 #include "content/public/browser/browser_thread.h"
-#include "third_party/zlib/google/zip_reader.h"
 
 namespace extensions {
 namespace image_writer {
 
 using content::BrowserThread;
 
+namespace {
+
 const int kMD5BufferSize = 1024;
 
-#if !defined(OS_CHROMEOS)
-static base::LazyInstance<scoped_refptr<ImageWriterUtilityClient>>::
-    DestructorAtExit g_utility_client = LAZY_INSTANCE_INITIALIZER;
-#endif
+}  // namespace
 
 Operation::Operation(base::WeakPtr<OperationManager> manager,
                      const ExtensionId& extension_id,
@@ -40,14 +39,15 @@
 #endif
       stage_(image_writer_api::STAGE_UNKNOWN),
       progress_(0),
-      zip_reader_(new zip::ZipReader),
-      download_folder_(download_folder) {
+      download_folder_(download_folder),
+      task_runner_(
+          base::CreateSequencedTaskRunnerWithTraits(blocking_task_traits())) {
 }
 
 Operation::~Operation() {}
 
 void Operation::Cancel() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
 
   stage_ = image_writer_api::STAGE_NONE;
 
@@ -55,6 +55,7 @@
 }
 
 void Operation::Abort() {
+  DCHECK(IsRunningInCorrectSequence());
   Error(error::kAborted);
 }
 
@@ -66,15 +67,12 @@
   return stage_;
 }
 
-#if !defined(OS_CHROMEOS)
-// static
-void Operation::SetUtilityClientForTesting(
-    scoped_refptr<ImageWriterUtilityClient> client) {
-  g_utility_client.Get() = client;
+void Operation::PostTask(base::OnceClosure task) {
+  task_runner_->PostTask(FROM_HERE, std::move(task));
 }
-#endif
 
 void Operation::Start() {
+  DCHECK(IsRunningInCorrectSequence());
 #if defined(OS_CHROMEOS)
   if (download_folder_.empty() ||
       !temp_dir_.CreateUniqueTempDirUnderPath(download_folder_)) {
@@ -86,62 +84,40 @@
   }
 
   AddCleanUpFunction(
-      base::Bind(base::IgnoreResult(&base::ScopedTempDir::Delete),
-                 base::Unretained(&temp_dir_)));
+      base::BindOnce(base::IgnoreResult(&base::ScopedTempDir::Delete),
+                     base::Unretained(&temp_dir_)));
 
   StartImpl();
 }
 
+void Operation::OnUnzipOpenComplete(const base::FilePath& image_path) {
+  DCHECK(IsRunningInCorrectSequence());
+  image_path_ = image_path;
+}
+
 void Operation::Unzip(const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
   if (IsCancelled()) {
     return;
   }
 
   if (image_path_.Extension() != FILE_PATH_LITERAL(".zip")) {
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
+    PostTask(continuation);
     return;
   }
 
   SetStage(image_writer_api::STAGE_UNZIP);
 
-  if (!(zip_reader_->Open(image_path_) && zip_reader_->AdvanceToNextEntry() &&
-        zip_reader_->OpenCurrentEntryInZip())) {
-    Error(error::kUnzipGenericError);
-    return;
-  }
-
-  if (zip_reader_->HasMore()) {
-    Error(error::kUnzipInvalidArchive);
-    return;
-  }
-
-  // Create a new target to unzip to.  The original file is opened by the
-  // zip_reader_.
-  zip::ZipReader::EntryInfo* entry_info = zip_reader_->current_entry_info();
-  if (entry_info) {
-    image_path_ =
-        temp_dir_.GetPath().Append(entry_info->file_path().BaseName());
-  } else {
-    Error(error::kTempDirError);
-    return;
-  }
-
-  zip_reader_->ExtractCurrentEntryToFilePathAsync(
-      image_path_,
+  auto unzip_helper = make_scoped_refptr(new UnzipHelper(
+      task_runner(), base::Bind(&Operation::OnUnzipOpenComplete, this),
       base::Bind(&Operation::CompleteAndContinue, this, continuation),
       base::Bind(&Operation::OnUnzipFailure, this),
-      base::Bind(&Operation::OnUnzipProgress,
-                 this,
-                 zip_reader_->current_entry_info()->original_size()));
+      base::Bind(&Operation::OnUnzipProgress, this)));
+  unzip_helper->Unzip(image_path_, temp_dir_.GetPath());
 }
 
 void Operation::Finish() {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                            base::BindOnce(&Operation::Finish, this));
-    return;
-  }
+  DCHECK(IsRunningInCorrectSequence());
 
   CleanUp();
 
@@ -151,12 +127,7 @@
 }
 
 void Operation::Error(const std::string& error_message) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
-    BrowserThread::PostTask(
-        BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&Operation::Error, this, error_message));
-    return;
-  }
+  DCHECK(IsRunningInCorrectSequence());
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
@@ -167,12 +138,7 @@
 }
 
 void Operation::SetProgress(int progress) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
-    BrowserThread::PostTask(
-        BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&Operation::SetProgress, this, progress));
-    return;
-  }
+  DCHECK(IsRunningInCorrectSequence());
 
   if (progress <= progress_) {
     return;
@@ -191,15 +157,10 @@
 }
 
 void Operation::SetStage(image_writer_api::Stage stage) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                            base::BindOnce(&Operation::SetStage, this, stage));
-    return;
-  }
+  DCHECK(IsRunningInCorrectSequence());
 
-  if (IsCancelled()) {
+  if (IsCancelled())
     return;
-  }
 
   stage_ = stage;
   progress_ = 0;
@@ -211,42 +172,38 @@
 }
 
 bool Operation::IsCancelled() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
 
   return stage_ == image_writer_api::STAGE_NONE;
 }
 
-void Operation::AddCleanUpFunction(const base::Closure& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  cleanup_functions_.push_back(callback);
+void Operation::AddCleanUpFunction(base::OnceClosure callback) {
+  DCHECK(IsRunningInCorrectSequence());
+  cleanup_functions_.push_back(std::move(callback));
 }
 
 void Operation::CompleteAndContinue(const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
   SetProgress(kProgressComplete);
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
+  PostTask(continuation);
 }
 
 #if !defined(OS_CHROMEOS)
 void Operation::StartUtilityClient() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  if (g_utility_client.Get().get()) {
-    image_writer_client_ = g_utility_client.Get();
-    return;
-  }
+  DCHECK(IsRunningInCorrectSequence());
   if (!image_writer_client_.get()) {
-    image_writer_client_ = new ImageWriterUtilityClient();
-    AddCleanUpFunction(base::Bind(&Operation::StopUtilityClient, this));
+    image_writer_client_ = ImageWriterUtilityClient::Create();
+    AddCleanUpFunction(base::BindOnce(&Operation::StopUtilityClient, this));
   }
 }
 
 void Operation::StopUtilityClient() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
   image_writer_client_->Shutdown();
 }
 
 void Operation::WriteImageProgress(int64_t total_bytes, int64_t curr_bytes) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
   if (IsCancelled()) {
     return;
   }
@@ -264,7 +221,8 @@
     int64_t file_size,
     int progress_offset,
     int progress_scale,
-    const base::Callback<void(const std::string&)>& callback) {
+    base::OnceCallback<void(const std::string&)> callback) {
+  DCHECK(IsRunningInCorrectSequence());
   if (IsCancelled()) {
     return;
   }
@@ -285,10 +243,14 @@
     }
   }
 
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&Operation::MD5Chunk, this, Passed(std::move(file)), 0,
-                     file_size, progress_offset, progress_scale, callback));
+  PostTask(base::BindOnce(&Operation::MD5Chunk, this, Passed(std::move(file)),
+                          0, file_size, progress_offset, progress_scale,
+                          std::move(callback)));
+}
+
+bool Operation::IsRunningInCorrectSequence() const {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return task_runner_->RunsTasksInCurrentSequence();
 }
 
 void Operation::MD5Chunk(
@@ -297,7 +259,8 @@
     int64_t bytes_total,
     int progress_offset,
     int progress_scale,
-    const base::Callback<void(const std::string&)>& callback) {
+    base::OnceCallback<void(const std::string&)> callback) {
+  DCHECK(IsRunningInCorrectSequence());
   if (IsCancelled())
     return;
 
@@ -311,7 +274,7 @@
     // Nothing to read, we are done.
     base::MD5Digest digest;
     base::MD5Final(&digest, &md5_context_);
-    callback.Run(base::MD5DigestToBase16(digest));
+    std::move(callback).Run(base::MD5DigestToBase16(digest));
   } else {
     int len = file.Read(bytes_processed, buffer.get(), read_size);
 
@@ -323,11 +286,10 @@
           progress_offset;
       SetProgress(percent_curr);
 
-      BrowserThread::PostTask(
-          BrowserThread::FILE, FROM_HERE,
-          base::BindOnce(&Operation::MD5Chunk, this, Passed(std::move(file)),
-                         bytes_processed + len, bytes_total, progress_offset,
-                         progress_scale, callback));
+      PostTask(base::BindOnce(&Operation::MD5Chunk, this,
+                              Passed(std::move(file)), bytes_processed + len,
+                              bytes_total, progress_offset, progress_scale,
+                              std::move(callback)));
       // Skip closing the file.
       return;
     } else {
@@ -337,25 +299,22 @@
   }
 }
 
-void Operation::OnUnzipFailure() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  Error(error::kUnzipGenericError);
+void Operation::OnUnzipFailure(const std::string& error) {
+  DCHECK(IsRunningInCorrectSequence());
+  Error(error);
 }
 
 void Operation::OnUnzipProgress(int64_t total_bytes, int64_t progress_bytes) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
 
   int progress_percent = kProgressComplete * progress_bytes / total_bytes;
   SetProgress(progress_percent);
 }
 
 void Operation::CleanUp() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-  for (std::vector<base::Closure>::iterator it = cleanup_functions_.begin();
-       it != cleanup_functions_.end();
-       ++it) {
-    it->Run();
-  }
+  DCHECK(IsRunningInCorrectSequence());
+  for (base::OnceClosure& cleanup_function : cleanup_functions_)
+    std::move(cleanup_function).Run();
   cleanup_functions_.clear();
 }
 
diff --git a/chrome/browser/extensions/api/image_writer_private/operation.h b/chrome/browser/extensions/api/image_writer_private/operation.h
index b6d49387..52efeef1 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation.h
+++ b/chrome/browser/extensions/api/image_writer_private/operation.h
@@ -15,7 +15,8 @@
 #include "base/md5.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/weak_ptr.h"
-#include "base/task/cancelable_task_tracker.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task_scheduler/task_traits.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h"
 #include "chrome/common/extensions/api/image_writer_private.h"
@@ -27,10 +28,6 @@
 class FilePath;
 }  // namespace base
 
-namespace zip {
-class ZipReader;
-}
-
 namespace extensions {
 namespace image_writer {
 
@@ -44,19 +41,20 @@
 // then the Cancel method will stop it.  The operation will call back to the
 // OperationManager periodically or on any significant event.
 //
-// Each stage of the operation is generally divided into three phases: Start,
-// Run, Complete.  Start and Complete run on the UI thread and are responsible
-// for advancing to the next stage and other UI interaction.  The Run phase does
-// the work on the FILE thread and calls SendProgress or Error as appropriate.
+// Each stage of the operation is generally divided into multiple phases with
+// Start() being the first phase and Complete() being the last. All phases
+// except Complete() run on blocking thread and Complete() runs on the UI
+// thread.
 //
 // TODO(haven): This class is current refcounted because it is owned by the
-// OperationManager on the UI thread but needs to do work on the FILE thread.
+// OperationManager on the UI thread but needs to do work on blocking threads.
 // There is probably a better way to organize this so that it can be represented
 // by a WeakPtr, but those are not thread-safe.  Additionally, if destruction is
 // done on the UI thread then that causes problems if any of the fields were
-// allocated/accessed on the FILE thread.  http://crbug.com/344713
+// allocated/accessed on the blocking thread.  http://crbug.com/344713
 class Operation : public base::RefCountedThreadSafe<Operation> {
  public:
+  // TODO(lazyboy): Turn these into base::OnceCallback. http://crbug.com/749865.
   typedef base::Callback<void(bool, const std::string&)> StartWriteCallback;
   typedef base::Callback<void(bool, const std::string&)> CancelWriteCallback;
 
@@ -80,17 +78,16 @@
   int GetProgress();
   image_writer_api::Stage GetStage();
 
-#if !defined(OS_CHROMEOS)
-  // Set an ImageWriterClient to use.  Should be called only when testing.  This
-  // does not set up automatic shutdown of the client and it must be shutdown
-  // manually.
-  static void SetUtilityClientForTesting(
-      scoped_refptr<ImageWriterUtilityClient> client);
-#endif
+  // Posts |task| to Operation's |task_runner_|.
+  void PostTask(base::OnceClosure task);
 
  protected:
   virtual ~Operation();
 
+  scoped_refptr<base::SequencedTaskRunner> task_runner() {
+    return task_runner_;
+  }
+
   // This function should be overriden by subclasses to set up the work of the
   // operation.  It will be called from Start().
   virtual void StartImpl() = 0;
@@ -111,7 +108,7 @@
   // Generates an error.
   // |error_message| is used to create an OnWriteError event which is
   // sent to the extension
-  virtual void Error(const std::string& error_message);
+  void Error(const std::string& error_message);
 
   // Set |progress_| and send an event.  Progress should be in the interval
   // [0,100]
@@ -125,8 +122,8 @@
 
   // Adds a callback that will be called during clean-up, whether the operation
   // is aborted, encounters and error, or finishes successfully.  These
-  // functions will be run on the FILE thread.
-  void AddCleanUpFunction(const base::Closure& callback);
+  // functions will be run on |task_runner_|.
+  void AddCleanUpFunction(base::OnceClosure callback);
 
   // Completes the current operation (progress set to 100) and runs the
   // continuation.
@@ -138,12 +135,13 @@
   // a scale of 50 means it will increment from 0 to 50 over the course of the
   // sum.  |progress_offset| is an percentage that will be added to the progress
   // of the MD5 sum before updating |progress_| but after scaling.
-  void GetMD5SumOfFile(
-      const base::FilePath& file,
-      int64_t file_size,
-      int progress_offset,
-      int progress_scale,
-      const base::Callback<void(const std::string&)>& callback);
+  void GetMD5SumOfFile(const base::FilePath& file,
+                       int64_t file_size,
+                       int progress_offset,
+                       int progress_scale,
+                       base::OnceCallback<void(const std::string&)> callback);
+
+  bool IsRunningInCorrectSequence() const;
 
   base::WeakPtr<OperationManager> manager_;
   const ExtensionId extension_id_;
@@ -156,6 +154,9 @@
 
  private:
   friend class base::RefCountedThreadSafe<Operation>;
+  friend class OperationForTest;
+  friend class ImageWriterUtilityClientTest;
+  friend class WriteFromUrlOperationForTest;
 
 #if !defined(OS_CHROMEOS)
   // Ensures the client is started.  This may be called many times but will only
@@ -198,11 +199,12 @@
                 int64_t bytes_total,
                 int progress_offset,
                 int progress_scale,
-                const base::Callback<void(const std::string&)>& callback);
+                const base::OnceCallback<void(const std::string&)> callback);
 
-  // Callbacks for zip::ZipReader.
-  void OnUnzipFailure();
+  // Callbacks for UnzipHelper.
+  void OnUnzipOpenComplete(const base::FilePath& image_path);
   void OnUnzipProgress(int64_t total_bytes, int64_t progress_bytes);
+  void OnUnzipFailure(const std::string& error);
 
   // Runs all cleanup functions.
   void CleanUp();
@@ -216,18 +218,28 @@
   // memory here.  This requires that we only do one MD5 sum at a time.
   base::MD5Context md5_context_;
 
-  // Zip reader for unzip operations. The reason for using a pointer is that we
-  // don't want to include zip_reader.h here which can mangle definitions in
-  // jni.h when included in the same file. See crbug.com/554199.
-  std::unique_ptr<zip::ZipReader> zip_reader_;
+  // Cleanup operations that must be run.  All these functions are run on
+  // |task_runner_|.
+  std::vector<base::OnceClosure> cleanup_functions_;
 
-  // CleanUp operations that must be run.  All these functions are run on the
-  // FILE thread.
-  std::vector<base::Closure> cleanup_functions_;
+  static constexpr base::TaskTraits blocking_task_traits() {
+    return {
+        // Requires I/O.
+        base::MayBlock(),
+        // Apps (e.g. Chromebook Recovery Utility) present UI feedback based on
+        // an operation, but it's not on critical path.
+        base::TaskPriority::USER_VISIBLE,
+        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
+    };
+  }
 
   // The download folder on Chrome OS.
   const base::FilePath download_folder_;
 
+  // Sequenced task runner where all I/O operation will be performed.
+  // Most of the methods of this class run in this task runner.
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
   DISALLOW_COPY_AND_ASSIGN(Operation);
 };
 
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc b/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc
index 79ad1be..56b8332 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc
@@ -35,7 +35,7 @@
 }  // namespace
 
 void Operation::Write(const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
   SetStage(image_writer_api::STAGE_WRITE);
 
   // Note this has to be run on the FILE thread to avoid concurrent access.
@@ -47,7 +47,7 @@
 }
 
 void Operation::VerifyWrite(const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
 
   // No verification is available in Chrome OS currently.
   continuation.Run();
@@ -66,7 +66,7 @@
 
   if (!success) {
     LOG(ERROR) << "Volume unmounting failed.";
-    Error(error::kUnmountVolumesError);
+    PostTask(base::Bind(&Operation::Error, this, error::kUnmountVolumesError));
     return;
   }
 
@@ -77,7 +77,7 @@
 
   if (iter == disks.end()) {
     LOG(ERROR) << "Disk not found in disk list after unmounting volumes.";
-    Error(error::kUnmountVolumesError);
+    PostTask(base::Bind(&Operation::Error, this, error::kUnmountVolumesError));
     return;
   }
 
@@ -106,11 +106,12 @@
                                bool success,
                                const std::string& error) {
   if (success) {
-    SetProgress(kProgressComplete);
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
+    PostTask(base::BindOnce(&Operation::SetProgress, this, kProgressComplete));
+    PostTask(continuation);
   } else {
     DLOG(ERROR) << "Error encountered while burning: " << error;
-    Error(error::kChromeOSImageBurnerError);
+    PostTask(base::BindOnce(&Operation::Error, this,
+                            error::kChromeOSImageBurnerError));
   }
 }
 
@@ -118,11 +119,12 @@
                                int64_t num_bytes_burnt,
                                int64_t total_size) {
   int progress = kProgressComplete * num_bytes_burnt / total_size;
-  SetProgress(progress);
+  PostTask(base::BindOnce(&Operation::SetProgress, this, progress));
 }
 
 void Operation::OnBurnError() {
-  Error(error::kChromeOSImageBurnerError);
+  PostTask(base::BindOnce(&Operation::Error, this,
+                          error::kChromeOSImageBurnerError));
 }
 
 }  // namespace image_writer
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_manager.cc b/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
index c01110bc..0e00781 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
@@ -60,8 +60,8 @@
   for (OperationMap::iterator iter = operations_.begin();
        iter != operations_.end();
        iter++) {
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                            base::BindOnce(&Operation::Abort, iter->second));
+    scoped_refptr<Operation> operation = iter->second;
+    operation->PostTask(base::BindOnce(&Operation::Abort, operation));
   }
 }
 
@@ -92,8 +92,8 @@
       device_path,
       GetAssociatedDownloadFolder()));
   operations_[extension_id] = operation;
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::BindOnce(&Operation::Start, operation));
+  operation->PostTask(base::BindOnce(&Operation::Start, operation));
+
   callback.Run(true, "");
 }
 
@@ -117,8 +117,7 @@
       weak_factory_.GetWeakPtr(), extension_id, path, device_path,
       GetAssociatedDownloadFolder()));
   operations_[extension_id] = operation;
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::BindOnce(&Operation::Start, operation));
+  operation->PostTask(base::BindOnce(&Operation::Start, operation));
   callback.Run(true, "");
 }
 
@@ -130,8 +129,7 @@
   if (existing_operation == NULL) {
     callback.Run(false, error::kNoOperationInProgress);
   } else {
-    BrowserThread::PostTask(
-        BrowserThread::FILE, FROM_HERE,
+    existing_operation->PostTask(
         base::BindOnce(&Operation::Cancel, existing_operation));
     DeleteOperation(extension_id);
     callback.Run(true, "");
@@ -152,8 +150,7 @@
       weak_factory_.GetWeakPtr(), extension_id, device_path,
       GetAssociatedDownloadFolder()));
   operations_[extension_id] = operation;
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::BindOnce(&Operation::Start, operation));
+  operation->PostTask(base::BindOnce(&Operation::Start, operation));
   callback.Run(true, "");
 }
 
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc b/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc
index 5580e87..d020f25 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc
@@ -104,7 +104,7 @@
   EXPECT_TRUE(cancel_success_);
   EXPECT_EQ("", cancel_error_);
 
-  base::RunLoop().RunUntilIdle();
+  content::RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(ImageWriterOperationManagerTest, DestroyPartitions) {
@@ -129,7 +129,7 @@
   EXPECT_TRUE(cancel_success_);
   EXPECT_EQ("", cancel_error_);
 
-  base::RunLoop().RunUntilIdle();
+  content::RunAllBlockingPoolTasksUntilIdle();
 }
 
 } // namespace
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_nonchromeos.cc b/chrome/browser/extensions/api/image_writer_private/operation_nonchromeos.cc
index bf8fac46..dc78b16 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_nonchromeos.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_nonchromeos.cc
@@ -17,7 +17,7 @@
 using content::BrowserThread;
 
 void Operation::Write(const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
   if (IsCancelled()) {
     return;
   }
@@ -38,7 +38,7 @@
 }
 
 void Operation::VerifyWrite(const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
 
   if (IsCancelled()) {
     return;
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_unittest.cc b/chrome/browser/extensions/api/image_writer_private/operation_unittest.cc
index 5d74e69..2e8654e 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_unittest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_unittest.cc
@@ -29,6 +29,19 @@
 using testing::Gt;
 using testing::Lt;
 
+#if !defined(OS_CHROMEOS)
+
+void SetUpUtilityClientProgressOnVerifyWrite(
+    const std::vector<int>& progress_list,
+    bool will_succeed,
+    FakeImageWriterClient* client) {
+  client->SimulateProgressOnVerifyWrite(progress_list, will_succeed);
+}
+
+#endif  // !defined(OS_CHROMEOS)
+
+}  // namespace
+
 // This class gives us a generic Operation with the ability to set or inspect
 // the current path to the image file.
 class OperationForTest : public Operation {
@@ -42,18 +55,23 @@
   void StartImpl() override {}
 
   // Expose internal stages for testing.
+  // Also wraps Operation's methods to run on correct sequence.
   void Unzip(const base::Closure& continuation) {
-    Operation::Unzip(continuation);
+    PostTask(base::BindOnce(&Operation::Unzip, this, continuation));
   }
 
   void Write(const base::Closure& continuation) {
-    Operation::Write(continuation);
+    PostTask(base::BindOnce(&Operation::Write, this, continuation));
   }
 
   void VerifyWrite(const base::Closure& continuation) {
-    Operation::VerifyWrite(continuation);
+    PostTask(base::BindOnce(&Operation::VerifyWrite, this, continuation));
   }
 
+  void Start() { PostTask(base::BindOnce(&Operation::Start, this)); }
+
+  void Cancel() { PostTask(base::BindOnce(&Operation::Cancel, this)); }
+
   // Helpers to set-up state for intermediate stages.
   void SetImagePath(const base::FilePath image_path) {
     image_path_ = image_path;
@@ -93,7 +111,10 @@
 
   void TearDown() override {
     // Ensure all callbacks have been destroyed and cleanup occurs.
+
+    // Cancel() will ensure we Shutdown() FakeImageWriterClient.
     operation_->Cancel();
+    scoped_task_environment_.RunUntilIdle();
 
     ImageWriterUnitTestBase::TearDown();
   }
@@ -107,8 +128,6 @@
   scoped_refptr<OperationForTest> operation_;
 };
 
-} // namespace
-
 // Unizpping a non-zip should do nothing.
 TEST_F(ImageWriterOperationTest, UnzipNonZipFile) {
   EXPECT_CALL(manager_, OnProgress(kDummyExtensionId, _, _)).Times(0);
@@ -118,12 +137,9 @@
   EXPECT_CALL(manager_, OnComplete(kDummyExtensionId)).Times(0);
 
   operation_->Start();
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&OperationForTest::Unzip, operation_,
-                     base::Bind(&base::DoNothing)));
-
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop run_loop;
+  operation_->Unzip(run_loop.QuitClosure());
+  run_loop.Run();
 }
 
 TEST_F(ImageWriterOperationTest, UnzipZipFile) {
@@ -141,18 +157,26 @@
   operation_->SetImagePath(zip_file_);
 
   operation_->Start();
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&OperationForTest::Unzip, operation_,
-                     base::Bind(&base::DoNothing)));
-
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop run_loop;
+  operation_->Unzip(run_loop.QuitClosure());
+  run_loop.Run();
 
   EXPECT_TRUE(base::ContentsEqual(image_path_, operation_->GetImagePath()));
 }
 
 #if defined(OS_LINUX)
 TEST_F(ImageWriterOperationTest, WriteImageToDevice) {
+#if !defined(OS_CHROMEOS)
+  auto set_up_utility_client_progress =
+      [](const std::vector<int>& progress_list, bool will_succeed,
+         FakeImageWriterClient* client) {
+        client->SimulateProgressOnWrite(progress_list, will_succeed);
+      };
+  // Sets up client for simulating Operation::Progress() on Operation::Write.
+  std::vector<int> progress_list{0, kTestFileSize / 2, kTestFileSize};
+  test_utils_.RunOnUtilityClientCreation(base::BindOnce(
+      set_up_utility_client_progress, progress_list, true /* will_succeed */));
+#endif
   EXPECT_CALL(manager_, OnError(kDummyExtensionId, _, _, _)).Times(0);
   EXPECT_CALL(manager_,
               OnProgress(kDummyExtensionId, image_writer_api::STAGE_WRITE, _))
@@ -165,29 +189,23 @@
       .Times(AtLeast(1));
 
   operation_->Start();
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&OperationForTest::Write, operation_,
-                     base::Bind(&base::DoNothing)));
-
-  base::RunLoop().RunUntilIdle();
-
-#if !defined(OS_CHROMEOS)
-  test_utils_.GetUtilityClient()->Progress(0);
-  test_utils_.GetUtilityClient()->Progress(kTestFileSize / 2);
-  test_utils_.GetUtilityClient()->Progress(kTestFileSize);
-  test_utils_.GetUtilityClient()->Success();
-
-  base::RunLoop().RunUntilIdle();
-#endif
+  base::RunLoop run_loop;
+  operation_->Write(run_loop.QuitClosure());
+  run_loop.Run();
 }
-#endif
+#endif  // defined(OS_LINUX)
 
 #if !defined(OS_CHROMEOS)
 // Chrome OS doesn't support verification in the ImageBurner, so these two tests
 // are skipped.
 
 TEST_F(ImageWriterOperationTest, VerifyFileSuccess) {
+  // Sets up client for simulating Operation::Progress() on
+  // Operation::VerifyWrite.
+  std::vector<int> progress_list{0, kTestFileSize / 2, kTestFileSize};
+  test_utils_.RunOnUtilityClientCreation(
+      base::BindOnce(&SetUpUtilityClientProgressOnVerifyWrite, progress_list,
+                     true /* will_succeed */));
   EXPECT_CALL(manager_, OnError(kDummyExtensionId, _, _, _)).Times(0);
   EXPECT_CALL(
       manager_,
@@ -206,24 +224,18 @@
       test_utils_.GetDevicePath(), kImagePattern, kTestFileSize);
 
   operation_->Start();
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&OperationForTest::VerifyWrite, operation_,
-                     base::Bind(&base::DoNothing)));
-
-  base::RunLoop().RunUntilIdle();
-
-#if !defined(OS_CHROMEOS)
-  test_utils_.GetUtilityClient()->Progress(0);
-  test_utils_.GetUtilityClient()->Progress(kTestFileSize / 2);
-  test_utils_.GetUtilityClient()->Progress(kTestFileSize);
-  test_utils_.GetUtilityClient()->Success();
-#endif
-
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop run_loop;
+  operation_->VerifyWrite(run_loop.QuitClosure());
+  run_loop.Run();
 }
 
 TEST_F(ImageWriterOperationTest, VerifyFileFailure) {
+  // Sets up client for simulating Operation::Progress() on
+  // Operation::VerifyWrite. Also simulates failure.
+  std::vector<int> progress_list{0, kTestFileSize / 2};
+  test_utils_.RunOnUtilityClientCreation(
+      base::BindOnce(&SetUpUtilityClientProgressOnVerifyWrite, progress_list,
+                     false /* will_succeed */));
   EXPECT_CALL(
       manager_,
       OnProgress(kDummyExtensionId, image_writer_api::STAGE_VERIFYWRITE, _))
@@ -242,20 +254,10 @@
       test_utils_.GetDevicePath(), kDevicePattern, kTestFileSize);
 
   operation_->Start();
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&OperationForTest::VerifyWrite, operation_,
-                     base::Bind(&base::DoNothing)));
-
-  base::RunLoop().RunUntilIdle();
-
-  test_utils_.GetUtilityClient()->Progress(0);
-  test_utils_.GetUtilityClient()->Progress(kTestFileSize / 2);
-  test_utils_.GetUtilityClient()->Error(error::kVerificationFailed);
-
-  base::RunLoop().RunUntilIdle();
+  operation_->VerifyWrite(base::Bind(&base::DoNothing));
+  content::RunAllBlockingPoolTasksUntilIdle();
 }
-#endif
+#endif  // !defined(OS_CHROMEOS)
 
 // Tests that on creation the operation_ has the expected state.
 TEST_F(ImageWriterOperationTest, Creation) {
diff --git a/chrome/browser/extensions/api/image_writer_private/test_utils.cc b/chrome/browser/extensions/api/image_writer_private/test_utils.cc
index 17f9f497..3b77a7d8 100644
--- a/chrome/browser/extensions/api/image_writer_private/test_utils.cc
+++ b/chrome/browser/extensions/api/image_writer_private/test_utils.cc
@@ -11,6 +11,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -60,7 +61,6 @@
 } // namespace
 #endif
 
-MockOperationManager::MockOperationManager() : OperationManager(NULL) {}
 MockOperationManager::MockOperationManager(content::BrowserContext* context)
     : OperationManager(context) {}
 MockOperationManager::~MockOperationManager() {}
@@ -77,9 +77,29 @@
 }
 #endif
 
+SimulateProgressInfo::SimulateProgressInfo(
+    const std::vector<int>& progress_list,
+    bool will_succeed)
+    : progress_list(progress_list), will_succeed(will_succeed) {}
+
+SimulateProgressInfo::~SimulateProgressInfo() {}
+SimulateProgressInfo::SimulateProgressInfo(const SimulateProgressInfo&) =
+    default;
+
 FakeImageWriterClient::FakeImageWriterClient() {}
 FakeImageWriterClient::~FakeImageWriterClient() {}
 
+void FakeImageWriterClient::SimulateProgressAndCompletion(
+    const SimulateProgressInfo& info) {
+  for (int progress : info.progress_list)
+    Progress(progress);
+  if (info.will_succeed) {
+    Success();
+  } else {
+    Error(error::kVerificationFailed);
+  }
+}
+
 void FakeImageWriterClient::Write(const ProgressCallback& progress_callback,
                                   const SuccessCallback& success_callback,
                                   const ErrorCallback& error_callback,
@@ -89,8 +109,10 @@
   success_callback_ = success_callback;
   error_callback_ = error_callback;
 
-  if (!write_callback_.is_null())
-    write_callback_.Run();
+  if (simulate_on_write_) {
+    SimulateProgressAndCompletion(*simulate_on_write_);
+    simulate_on_write_.reset();
+  }
 }
 
 void FakeImageWriterClient::Verify(const ProgressCallback& progress_callback,
@@ -102,8 +124,10 @@
   success_callback_ = success_callback;
   error_callback_ = error_callback;
 
-  if (!verify_callback_.is_null())
-    verify_callback_.Run();
+  if (simulate_on_verify_) {
+    SimulateProgressAndCompletion(*simulate_on_verify_);
+    simulate_on_verify_.reset();
+  }
 }
 
 void FakeImageWriterClient::Cancel(const CancelCallback& cancel_callback) {
@@ -117,18 +141,20 @@
   error_callback_.Reset();
   cancel_callback_.Reset();
 
-  write_callback_.Reset();
-  verify_callback_.Reset();
+  simulate_on_write_.reset();
+  simulate_on_verify_.reset();
 }
 
-void FakeImageWriterClient::SetWriteCallback(
-    const base::Closure& write_callback) {
-  write_callback_ = write_callback;
+void FakeImageWriterClient::SimulateProgressOnWrite(
+    const std::vector<int>& progress_list,
+    bool will_succeed) {
+  simulate_on_write_ = SimulateProgressInfo(progress_list, will_succeed);
 }
 
-void FakeImageWriterClient::SetVerifyCallback(
-    const base::Closure& verify_callback) {
-  verify_callback_ = verify_callback;
+void FakeImageWriterClient::SimulateProgressOnVerifyWrite(
+    const std::vector<int>& progress_list,
+    bool will_succeed) {
+  simulate_on_verify_ = SimulateProgressInfo(progress_list, will_succeed);
 }
 
 void FakeImageWriterClient::Progress(int64_t progress) {
@@ -151,11 +177,43 @@
     cancel_callback_.Run();
 }
 
-ImageWriterTestUtils::ImageWriterTestUtils() {
+#if !defined(OS_CHROMEOS)
+scoped_refptr<ImageWriterUtilityClient> CreateFakeImageWriterUtilityClient(
+    ImageWriterTestUtils* utils) {
+  auto* client = new FakeImageWriterClient();
+  utils->OnUtilityClientCreated(client);
+  return make_scoped_refptr(client);
+}
+#endif  // !defined(OS_CHROMEOS)
+
+ImageWriterTestUtils::ImageWriterTestUtils()
+#if !defined(OS_CHROMEOS)
+    : utility_client_factory_(
+          base::Bind(&CreateFakeImageWriterUtilityClient, this))
+#endif
+{
 }
 ImageWriterTestUtils::~ImageWriterTestUtils() {
 }
 
+#if !defined(OS_CHROMEOS)
+void ImageWriterTestUtils::OnUtilityClientCreated(
+    FakeImageWriterClient* client) {
+  DCHECK(!client_.get())
+      << "Single FakeImageWriterClient instance per test case expected.";
+  client_ = client;
+  if (!client_creation_callback_.is_null())
+    std::move(client_creation_callback_).Run(client);
+}
+#endif
+
+#if !defined(OS_CHROMEOS)
+void ImageWriterTestUtils::RunOnUtilityClientCreation(
+    base::OnceCallback<void(FakeImageWriterClient*)> closure) {
+  client_creation_callback_ = std::move(closure);
+}
+#endif
+
 void ImageWriterTestUtils::SetUp() {
   SetUp(false);
 }
@@ -201,8 +259,7 @@
       false);
   disk_manager->SetupDefaultReplies();
 #else
-  client_ = new FakeImageWriterClient();
-  image_writer::Operation::SetUtilityClientForTesting(client_);
+  ImageWriterUtilityClient::SetFactoryForTesting(&utility_client_factory_);
 #endif
 }
 
@@ -213,8 +270,7 @@
   }
   chromeos::disks::DiskMountManager::Shutdown();
 #else
-  image_writer::Operation::SetUtilityClientForTesting(NULL);
-  client_->Shutdown();
+  ImageWriterUtilityClient::SetFactoryForTesting(nullptr);
 #endif
 }
 
@@ -230,12 +286,6 @@
   return test_device_path_;
 }
 
-#if !defined(OS_CHROMEOS)
-FakeImageWriterClient* ImageWriterTestUtils::GetUtilityClient() {
-  return client_.get();
-}
-#endif
-
 bool ImageWriterTestUtils::ImageWrittenToDevice() {
   std::unique_ptr<char[]> image_buffer(new char[kTestFileSize]);
   std::unique_ptr<char[]> device_buffer(new char[kTestFileSize]);
@@ -265,8 +315,9 @@
 }
 
 ImageWriterUnitTestBase::ImageWriterUnitTestBase()
-    : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
-}
+    : scoped_task_environment_(
+          base::test::ScopedTaskEnvironment::MainThreadType::UI),
+      thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
 ImageWriterUnitTestBase::~ImageWriterUnitTestBase() {
 }
 
diff --git a/chrome/browser/extensions/api/image_writer_private/test_utils.h b/chrome/browser/extensions/api/image_writer_private/test_utils.h
index 2ccac3d7..b5c4e81 100644
--- a/chrome/browser/extensions/api/image_writer_private/test_utils.h
+++ b/chrome/browser/extensions/api/image_writer_private/test_utils.h
@@ -11,6 +11,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h"
 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h"
@@ -40,7 +41,6 @@
 // are non-virtual methods on this class that should not be called in tests.
 class MockOperationManager : public OperationManager {
  public:
-  MockOperationManager();
   explicit MockOperationManager(content::BrowserContext* context);
   virtual ~MockOperationManager();
 
@@ -74,6 +74,15 @@
 };
 #endif
 
+struct SimulateProgressInfo {
+  SimulateProgressInfo(const std::vector<int>& progress_list,
+                       bool will_succeed);
+  ~SimulateProgressInfo();
+  SimulateProgressInfo(const SimulateProgressInfo&);
+  std::vector<int> progress_list;
+  bool will_succeed;
+};
+
 class FakeImageWriterClient : public ImageWriterUtilityClient {
  public:
   FakeImageWriterClient();
@@ -94,10 +103,14 @@
 
   void Shutdown() override;
 
-  // Sets a callback for when a Write call is made.
-  void SetWriteCallback(const base::Closure& write_callback);
-  // Sets a callback for when a Verify call is made.
-  void SetVerifyCallback(const base::Closure& verify_callback);
+  // Issues Operation::Progress() calls with items in |progress_list| on
+  // Operation Write(). Sends Operation::Success() iff |will_succeed| is true,
+  // otherwise issues an error.
+  void SimulateProgressOnWrite(const std::vector<int>& progress_list,
+                               bool will_succeed);
+  // Same as SimulateProgressOnWrite, but applies to Operation::VerifyWrite().
+  void SimulateProgressOnVerifyWrite(const std::vector<int>& progress_list,
+                                     bool will_succeed);
 
   // Triggers the progress callback.
   void Progress(int64_t progress);
@@ -108,16 +121,19 @@
   // Triggers the cancel callback.
   void Cancel();
 
- private:
+ protected:
   ~FakeImageWriterClient() override;
 
+ private:
+  void SimulateProgressAndCompletion(const SimulateProgressInfo& info);
+
   ProgressCallback progress_callback_;
   SuccessCallback success_callback_;
   ErrorCallback error_callback_;
   CancelCallback cancel_callback_;
 
-  base::Closure write_callback_;
-  base::Closure verify_callback_;
+  base::Optional<SimulateProgressInfo> simulate_on_write_;
+  base::Optional<SimulateProgressInfo> simulate_on_verify_;
 };
 
 class ImageWriterTestUtils {
@@ -125,6 +141,15 @@
   ImageWriterTestUtils();
   virtual ~ImageWriterTestUtils();
 
+#if !defined(OS_CHROMEOS)
+  using UtilityClientCreationCallback =
+      base::OnceCallback<void(FakeImageWriterClient*)>;
+  void RunOnUtilityClientCreation(UtilityClientCreationCallback callback);
+
+  // Called when an instance of utility client is created.
+  void OnUtilityClientCreated(FakeImageWriterClient* client);
+#endif
+
   // Verifies that the data in image_path was written to the file at
   // device_path.  This is different from base::ContentsEqual because the device
   // may be larger than the image.
@@ -152,10 +177,6 @@
   const base::FilePath& GetImagePath();
   const base::FilePath& GetDevicePath();
 
-#if !defined(OS_CHROMEOS)
-  FakeImageWriterClient* GetUtilityClient();
-#endif
-
  protected:
   base::ScopedTempDir temp_dir_;
   base::FilePath test_image_path_;
@@ -163,6 +184,9 @@
 
 #if !defined(OS_CHROMEOS)
   scoped_refptr<FakeImageWriterClient> client_;
+  ImageWriterUtilityClient::ImageWriterUtilityClientFactory
+      utility_client_factory_;
+  base::OnceCallback<void(FakeImageWriterClient*)> client_creation_callback_;
 #endif
 };
 
@@ -177,6 +201,8 @@
 
   ImageWriterTestUtils test_utils_;
 
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+
  private:
   content::TestBrowserThreadBundle thread_bundle_;
 };
diff --git a/chrome/browser/extensions/api/image_writer_private/unzip_helper.cc b/chrome/browser/extensions/api/image_writer_private/unzip_helper.cc
new file mode 100644
index 0000000..39f27d64
--- /dev/null
+++ b/chrome/browser/extensions/api/image_writer_private/unzip_helper.cc
@@ -0,0 +1,92 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/image_writer_private/unzip_helper.h"
+
+#include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_scheduler/post_task.h"
+#include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
+#include "third_party/zlib/google/zip_reader.h"
+
+namespace extensions {
+namespace image_writer {
+
+UnzipHelper::UnzipHelper(
+    scoped_refptr<base::SequencedTaskRunner> owner_task_runner,
+    const base::Callback<void(const base::FilePath&)>& open_callback,
+    const base::Closure& complete_callback,
+    const base::Callback<void(const std::string&)>& failure_callback,
+    const base::Callback<void(int64_t, int64_t)>& progress_callback)
+    : owner_task_runner_(owner_task_runner),
+      open_callback_(open_callback),
+      complete_callback_(complete_callback),
+      failure_callback_(failure_callback),
+      progress_callback_(progress_callback),
+      zip_reader_(base::MakeUnique<zip::ZipReader>()) {}
+
+UnzipHelper::~UnzipHelper() {}
+
+void UnzipHelper::Unzip(const base::FilePath& image_path,
+                        const base::FilePath& temp_dir_path) {
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      base::CreateSingleThreadTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
+  task_runner->PostTask(FROM_HERE, base::Bind(&UnzipHelper::UnzipImpl, this,
+                                              image_path, temp_dir_path));
+}
+
+void UnzipHelper::UnzipImpl(const base::FilePath& image_path,
+                            const base::FilePath& temp_dir_path) {
+  if (!zip_reader_->Open(image_path) || !zip_reader_->AdvanceToNextEntry() ||
+      !zip_reader_->OpenCurrentEntryInZip()) {
+    OnError(error::kUnzipGenericError);
+    return;
+  }
+
+  if (zip_reader_->HasMore()) {
+    OnError(error::kUnzipInvalidArchive);
+    return;
+  }
+
+  // Create a new target to unzip to.  The original file is opened by
+  // |zip_reader_|.
+  zip::ZipReader::EntryInfo* entry_info = zip_reader_->current_entry_info();
+
+  if (!entry_info) {
+    OnError(error::kTempDirError);
+    return;
+  }
+
+  base::FilePath out_image_path =
+      temp_dir_path.Append(entry_info->file_path().BaseName());
+  OnOpenSuccess(out_image_path);
+
+  zip_reader_->ExtractCurrentEntryToFilePathAsync(
+      out_image_path, base::Bind(&UnzipHelper::OnComplete, this),
+      base::Bind(&UnzipHelper::OnError, this, error::kUnzipGenericError),
+      base::Bind(&UnzipHelper::OnProgress, this, entry_info->original_size()));
+}
+
+void UnzipHelper::OnError(const std::string& error) {
+  owner_task_runner_->PostTask(FROM_HERE, base::Bind(failure_callback_, error));
+}
+
+void UnzipHelper::OnOpenSuccess(const base::FilePath& image_path) {
+  owner_task_runner_->PostTask(FROM_HERE,
+                               base::Bind(open_callback_, image_path));
+}
+
+void UnzipHelper::OnComplete() {
+  owner_task_runner_->PostTask(FROM_HERE, complete_callback_);
+}
+
+void UnzipHelper::OnProgress(int64_t total_bytes, int64_t curr_bytes) {
+  owner_task_runner_->PostTask(
+      FROM_HERE, base::Bind(progress_callback_, total_bytes, curr_bytes));
+}
+
+}  // namespace image_writer
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/unzip_helper.h b/chrome/browser/extensions/api/image_writer_private/unzip_helper.h
new file mode 100644
index 0000000..984b037c
--- /dev/null
+++ b/chrome/browser/extensions/api/image_writer_private/unzip_helper.h
@@ -0,0 +1,71 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_UNZIP_HELPER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_UNZIP_HELPER_H_
+
+#include "base/memory/ref_counted_memory.h"
+#include "base/sequenced_task_runner.h"
+#include "build/build_config.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace zip {
+class ZipReader;
+}
+
+namespace extensions {
+namespace image_writer {
+
+// A helper to provide Unzip operation.
+// Currently ZipReader requires SingleThreadTaskRunner, this class is
+// responsible for running ZipReader on a SingleThreadTaskRunner. Unzip
+// should be called from sequences (|owner_task_runner_|) and all the
+// callbacks of this class is called on that task runner.
+// TODO(satorux/lazyboy): Make ZipReader Sequence friendly and remove
+// SingleThreadTaskRunner from this class. https://crbug.com/752702.
+class UnzipHelper : public base::RefCountedThreadSafe<UnzipHelper> {
+ public:
+  explicit UnzipHelper(
+      scoped_refptr<base::SequencedTaskRunner> owner_task_runner,
+      const base::Callback<void(const base::FilePath&)>& open_callback,
+      const base::Closure& complete_callback,
+      const base::Callback<void(const std::string&)>& failure_callback,
+      const base::Callback<void(int64_t, int64_t)>& progress_callback);
+
+  void Unzip(const base::FilePath& image_path,
+             const base::FilePath& temp_dir_path);
+
+ private:
+  friend class base::RefCountedThreadSafe<UnzipHelper>;
+  ~UnzipHelper();
+
+  void UnzipImpl(const base::FilePath& image_path,
+                 const base::FilePath& temp_dir);
+  void OnError(const std::string& error);
+  void OnOpenSuccess(const base::FilePath& image_path);
+  void OnComplete();
+  void OnProgress(int64_t total_bytes, int64_t curr_bytes);
+
+  scoped_refptr<base::SequencedTaskRunner> owner_task_runner_;
+
+  base::Callback<void(const base::FilePath&)> open_callback_;
+  base::Closure complete_callback_;
+  base::Callback<void(const std::string&)> failure_callback_;
+  base::Callback<void(int64_t, int64_t)> progress_callback_;
+
+  // Zip reader for unzip operations. The reason for using a pointer is that we
+  // don't want to include zip_reader.h here which can mangle definitions in
+  // jni.h when included in the same file. See crbug.com/554199.
+  std::unique_ptr<zip::ZipReader> zip_reader_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnzipHelper);
+};
+
+}  // namespace image_writer
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_UNZIP_HELPER_H_
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.cc b/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.cc
index 4136c1a..cc9ff46 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.cc
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.cc
@@ -25,20 +25,19 @@
 WriteFromFileOperation::~WriteFromFileOperation() {}
 
 void WriteFromFileOperation::StartImpl() {
+  DCHECK(IsRunningInCorrectSequence());
   if (!base::PathExists(image_path_) || base::DirectoryExists(image_path_)) {
     DLOG(ERROR) << "Source must exist and not be a directory.";
     Error(error::kImageInvalid);
     return;
   }
 
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(
-          &WriteFromFileOperation::Unzip, this,
-          base::Bind(
-              &WriteFromFileOperation::Write, this,
-              base::Bind(&WriteFromFileOperation::VerifyWrite, this,
-                         base::Bind(&WriteFromFileOperation::Finish, this)))));
+  PostTask(base::BindOnce(
+      &WriteFromFileOperation::Unzip, this,
+      base::Bind(
+          &WriteFromFileOperation::Write, this,
+          base::Bind(&WriteFromFileOperation::VerifyWrite, this,
+                     base::Bind(&WriteFromFileOperation::Finish, this)))));
 }
 
 }  // namespace image_writer
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_file_operation_unittest.cc b/chrome/browser/extensions/api/image_writer_private/write_from_file_operation_unittest.cc
index 3c6fb91..2a79bf45 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_file_operation_unittest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_file_operation_unittest.cc
@@ -16,6 +16,19 @@
 using testing::AnyNumber;
 using testing::AtLeast;
 
+namespace {
+
+#if !defined(OS_CHROMEOS)
+void SetUpImageWriteClientProgressSimulation(FakeImageWriterClient* client) {
+  std::vector<int> progress_list{0, 50, 100};
+  bool will_succeed = true;
+  client->SimulateProgressOnWrite(progress_list, will_succeed);
+  client->SimulateProgressOnVerifyWrite(progress_list, will_succeed);
+}
+#endif
+
+}  // namespace
+
 class ImageWriterFromFileTest : public ImageWriterUnitTestBase {
  protected:
   ImageWriterFromFileTest()
@@ -42,13 +55,18 @@
                       0,
                       error::kImageInvalid)).Times(1);
 
-  op->Start();
-
-  base::RunLoop().RunUntilIdle();
+  op->PostTask(base::BindOnce(&Operation::Start, op));
+  content::RunAllBlockingPoolTasksUntilIdle();
 }
 
 // Runs the entire WriteFromFile operation.
 TEST_F(ImageWriterFromFileTest, WriteFromFileEndToEnd) {
+#if !defined(OS_CHROMEOS)
+  // Sets up simulating Operation::Progress() and Operation::Success().
+  test_utils_.RunOnUtilityClientCreation(
+      base::BindOnce(&SetUpImageWriteClientProgressSimulation));
+#endif
+
   scoped_refptr<WriteFromFileOperation> op =
       new WriteFromFileOperation(manager_.AsWeakPtr(),
                                  kDummyExtensionId,
@@ -84,21 +102,8 @@
   EXPECT_CALL(manager_, OnComplete(kDummyExtensionId)).Times(1);
   EXPECT_CALL(manager_, OnError(kDummyExtensionId, _, _, _)).Times(0);
 
-  op->Start();
-
-  base::RunLoop().RunUntilIdle();
-#if !defined(OS_CHROMEOS)
-  test_utils_.GetUtilityClient()->Progress(0);
-  test_utils_.GetUtilityClient()->Progress(50);
-  test_utils_.GetUtilityClient()->Progress(100);
-  test_utils_.GetUtilityClient()->Success();
-  base::RunLoop().RunUntilIdle();
-  test_utils_.GetUtilityClient()->Progress(0);
-  test_utils_.GetUtilityClient()->Progress(50);
-  test_utils_.GetUtilityClient()->Progress(100);
-  test_utils_.GetUtilityClient()->Success();
-  base::RunLoop().RunUntilIdle();
-#endif
+  op->PostTask(base::BindOnce(&Operation::Start, op));
+  content::RunAllBlockingPoolTasksUntilIdle();
 }
 
 }  // namespace image_writer
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
index a417ff76..ca700e1 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
@@ -33,28 +33,22 @@
 }
 
 void WriteFromUrlOperation::StartImpl() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
 
-  GetDownloadTarget(base::Bind(
-      &WriteFromUrlOperation::Download,
-      this,
-      base::Bind(
-          &WriteFromUrlOperation::VerifyDownload,
-          this,
-          base::Bind(
-              &WriteFromUrlOperation::Unzip,
-              this,
-              base::Bind(&WriteFromUrlOperation::Write,
-                         this,
-                         base::Bind(&WriteFromUrlOperation::VerifyWrite,
-                                    this,
+  GetDownloadTarget(base::BindOnce(
+      &WriteFromUrlOperation::Download, this,
+      base::BindOnce(
+          &WriteFromUrlOperation::VerifyDownload, this,
+          base::BindOnce(
+              &WriteFromUrlOperation::Unzip, this,
+              base::Bind(&WriteFromUrlOperation::Write, this,
+                         base::Bind(&WriteFromUrlOperation::VerifyWrite, this,
                                     base::Bind(&WriteFromUrlOperation::Finish,
                                                this)))))));
 }
 
-void WriteFromUrlOperation::GetDownloadTarget(
-    const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+void WriteFromUrlOperation::GetDownloadTarget(base::OnceClosure continuation) {
+  DCHECK(IsRunningInCorrectSequence());
   if (IsCancelled()) {
     return;
   }
@@ -70,17 +64,17 @@
     image_path_ = temp_dir_.GetPath().Append(file_name);
   }
 
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
+  PostTask(std::move(continuation));
 }
 
-void WriteFromUrlOperation::Download(const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+void WriteFromUrlOperation::Download(base::OnceClosure continuation) {
+  DCHECK(IsRunningInCorrectSequence());
 
   if (IsCancelled()) {
     return;
   }
 
-  download_continuation_ = continuation;
+  download_continuation_ = std::move(continuation);
 
   SetStage(image_writer_api::STAGE_DOWNLOAD);
 
@@ -117,11 +111,10 @@
                                          traffic_annotation);
 
   url_fetcher_->SetRequestContext(request_context_);
-  url_fetcher_->SaveResponseToFileAtPath(
-      image_path_, BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE));
+  url_fetcher_->SaveResponseToFileAtPath(image_path_, task_runner());
 
   AddCleanUpFunction(
-      base::Bind(&WriteFromUrlOperation::DestroyUrlFetcher, this));
+      base::BindOnce(&WriteFromUrlOperation::DestroyUrlFetcher, this));
 
   url_fetcher_->Start();
 }
@@ -140,7 +133,7 @@
     int64_t current,
     int64_t total,
     int64_t current_network_bytes) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
 
   if (IsCancelled()) {
     url_fetcher_.reset(NULL);
@@ -152,22 +145,19 @@
 }
 
 void WriteFromUrlOperation::OnURLFetchComplete(const net::URLFetcher* source) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
 
   if (source->GetStatus().is_success() && source->GetResponseCode() == 200) {
     SetProgress(kProgressComplete);
 
-    download_continuation_.Run();
-
-    // Remove the reference to ourselves in this closure.
-    download_continuation_ = base::Closure();
+    std::move(download_continuation_).Run();
   } else {
     Error(error::kDownloadInterrupted);
   }
 }
 
-void WriteFromUrlOperation::VerifyDownload(const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+void WriteFromUrlOperation::VerifyDownload(base::OnceClosure continuation) {
+  DCHECK(IsRunningInCorrectSequence());
 
   if (IsCancelled()) {
     return;
@@ -175,45 +165,39 @@
 
   // Skip verify if no hash.
   if (hash_.empty()) {
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
+    PostTask(std::move(continuation));
     return;
   }
 
   SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD);
 
-  GetMD5SumOfFile(
-      image_path_,
-      0,
-      0,
-      kProgressComplete,
-      base::Bind(
-          &WriteFromUrlOperation::VerifyDownloadCompare, this, continuation));
+  GetMD5SumOfFile(image_path_, 0, 0, kProgressComplete,
+                  base::BindOnce(&WriteFromUrlOperation::VerifyDownloadCompare,
+                                 this, std::move(continuation)));
 }
 
 void WriteFromUrlOperation::VerifyDownloadCompare(
-    const base::Closure& continuation,
+    base::OnceClosure continuation,
     const std::string& download_hash) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(IsRunningInCorrectSequence());
   if (download_hash != hash_) {
     Error(error::kDownloadHashError);
     return;
   }
 
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&WriteFromUrlOperation::VerifyDownloadComplete, this,
-                     continuation));
+  PostTask(base::BindOnce(&WriteFromUrlOperation::VerifyDownloadComplete, this,
+                          std::move(continuation)));
 }
 
 void WriteFromUrlOperation::VerifyDownloadComplete(
-    const base::Closure& continuation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+    base::OnceClosure continuation) {
+  DCHECK(IsRunningInCorrectSequence());
   if (IsCancelled()) {
     return;
   }
 
   SetProgress(kProgressComplete);
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
+  PostTask(std::move(continuation));
 }
 
 } // namespace image_writer
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h
index b653bbfb..47c98f8 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h
@@ -34,18 +34,21 @@
   void StartImpl() override;
 
  protected:
+  friend class OperationForTest;
+  friend class WriteFromUrlOperationForTest;
+
   ~WriteFromUrlOperation() override;
 
   // Sets the image_path to the correct location to download to.
-  void GetDownloadTarget(const base::Closure& continuation);
+  void GetDownloadTarget(base::OnceClosure continuation);
 
   // Downloads the |url| to the currently configured |image_path|.  Should not
   // be called without calling |GetDownloadTarget| first.
-  void Download(const base::Closure& continuation);
+  void Download(base::OnceClosure continuation);
 
   // Verifies the download matches |hash|.  If the hash is empty, this stage is
   // skipped.
-  void VerifyDownload(const base::Closure& continuation);
+  void VerifyDownload(base::OnceClosure continuation);
 
  private:
   // Destroys the URLFetcher.  The URLFetcher needs to be destroyed on the same
@@ -63,9 +66,9 @@
                                 int64_t current,
                                 int64_t total) override;
 
-  void VerifyDownloadCompare(const base::Closure& continuation,
+  void VerifyDownloadCompare(base::OnceClosure continuation,
                              const std::string& download_hash);
-  void VerifyDownloadComplete(const base::Closure& continuation);
+  void VerifyDownloadComplete(base::OnceClosure continuation);
 
   // Arguments
   net::URLRequestContextGetter* request_context_;
@@ -74,7 +77,7 @@
 
   // Local state
   std::unique_ptr<net::URLFetcher> url_fetcher_;
-  base::Closure download_continuation_;
+  base::OnceClosure download_continuation_;
 };
 
 } // namespace image_writer
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation_unittest.cc b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation_unittest.cc
index 28ca08a3..98680a7 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation_unittest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation_unittest.cc
@@ -27,17 +27,19 @@
 
 typedef net::LocalHostTestURLRequestInterceptor GetInterceptor;
 
+}  // namespace
+
 // This class gives us a generic Operation with the ability to set or inspect
 // the current path to the image file.
-class OperationForTest : public WriteFromUrlOperation {
+class WriteFromUrlOperationForTest : public WriteFromUrlOperation {
  public:
-  OperationForTest(base::WeakPtr<OperationManager> manager_,
-                   const ExtensionId& extension_id,
-                   net::URLRequestContextGetter* request_context,
-                   GURL url,
-                   const std::string& hash,
-                   const std::string& storage_unit_id)
-      : WriteFromUrlOperation(manager_,
+  WriteFromUrlOperationForTest(base::WeakPtr<OperationManager> manager,
+                               const ExtensionId& extension_id,
+                               net::URLRequestContextGetter* request_context,
+                               GURL url,
+                               const std::string& hash,
+                               const std::string& storage_unit_id)
+      : WriteFromUrlOperation(manager,
                               extension_id,
                               request_context,
                               url,
@@ -47,17 +49,29 @@
 
   void StartImpl() override {}
 
-  // Expose stages for testing.
+  // Following methods let us:
+  // 1. Expose stages for testing.
+  // 2. Make sure Operation methods are invoked on its task runner.
+  void Start() {
+    PostTask(base::BindOnce(&WriteFromUrlOperation::Start, this));
+  }
   void GetDownloadTarget(const base::Closure& continuation) {
-    WriteFromUrlOperation::GetDownloadTarget(continuation);
+    PostTask(base::BindOnce(&WriteFromUrlOperation::GetDownloadTarget, this,
+                            continuation));
   }
 
   void Download(const base::Closure& continuation) {
-    WriteFromUrlOperation::Download(continuation);
+    PostTask(
+        base::BindOnce(&WriteFromUrlOperation::Download, this, continuation));
   }
 
   void VerifyDownload(const base::Closure& continuation) {
-    WriteFromUrlOperation::VerifyDownload(continuation);
+    PostTask(base::BindOnce(&WriteFromUrlOperation::VerifyDownload, this,
+                            continuation));
+  }
+
+  void Cancel() {
+    PostTask(base::BindOnce(&WriteFromUrlOperation::Cancel, this));
   }
 
   // Helpers to set-up state for intermediate stages.
@@ -68,7 +82,7 @@
   base::FilePath GetImagePath() { return image_path_; }
 
  private:
-  ~OperationForTest() override {}
+  ~WriteFromUrlOperationForTest() override {}
 };
 
 class ImageWriterWriteFromUrlOperationTest : public ImageWriterUnitTestBase {
@@ -92,15 +106,14 @@
     ImageWriterUnitTestBase::TearDown();
   }
 
-  scoped_refptr<OperationForTest> CreateOperation(const GURL& url,
-                                                  const std::string& hash) {
-    scoped_refptr<OperationForTest> operation(
-        new OperationForTest(manager_.AsWeakPtr(),
-                             kDummyExtensionId,
-                             test_profile_.GetRequestContext(),
-                             url,
-                             hash,
-                             test_utils_.GetDevicePath().AsUTF8Unsafe()));
+  scoped_refptr<WriteFromUrlOperationForTest> CreateOperation(
+      const GURL& url,
+      const std::string& hash) {
+    scoped_refptr<WriteFromUrlOperationForTest> operation(
+        new WriteFromUrlOperationForTest(
+            manager_.AsWeakPtr(), kDummyExtensionId,
+            test_profile_.GetRequestContext(), url, hash,
+            test_utils_.GetDevicePath().AsUTF8Unsafe()));
     operation->Start();
     return operation;
   }
@@ -112,22 +125,27 @@
 };
 
 TEST_F(ImageWriterWriteFromUrlOperationTest, SelectTargetWithoutExtension) {
-  scoped_refptr<OperationForTest> operation =
+  scoped_refptr<WriteFromUrlOperationForTest> operation =
       CreateOperation(GURL("http://localhost/foo/bar"), "");
 
-  operation->GetDownloadTarget(base::Bind(&base::DoNothing));
+  base::RunLoop run_loop;
+  operation->GetDownloadTarget(run_loop.QuitClosure());
+  run_loop.Run();
 
   EXPECT_EQ(FILE_PATH_LITERAL("bar"),
             operation->GetImagePath().BaseName().value());
 
   operation->Cancel();
+  content::RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(ImageWriterWriteFromUrlOperationTest, SelectTargetWithExtension) {
-  scoped_refptr<OperationForTest> operation =
+  scoped_refptr<WriteFromUrlOperationForTest> operation =
       CreateOperation(GURL("http://localhost/foo/bar.zip"), "");
 
-  operation->GetDownloadTarget(base::Bind(&base::DoNothing));
+  base::RunLoop run_loop;
+  operation->GetDownloadTarget(run_loop.QuitClosure());
+  run_loop.Run();
 
   EXPECT_EQ(FILE_PATH_LITERAL("bar.zip"),
             operation->GetImagePath().BaseName().value());
@@ -140,9 +158,8 @@
   // message queues while waiting for IO, thus we have to run until the
   // operation completes.
   base::RunLoop runloop;
-  base::Closure quit_closure = runloop.QuitClosure();
   base::FilePath download_target_path;
-  scoped_refptr<OperationForTest> operation =
+  scoped_refptr<WriteFromUrlOperationForTest> operation =
       CreateOperation(GURL(kTestImageUrl), "");
 
   EXPECT_TRUE(base::CreateTemporaryFileInDir(test_utils_.GetTempDir(),
@@ -162,11 +179,9 @@
       OnProgress(kDummyExtensionId, image_writer_api::STAGE_DOWNLOAD, 100))
       .Times(AnyNumber());
 
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&OperationForTest::Download, operation, quit_closure));
-
+  operation->Download(runloop.QuitClosure());
   runloop.Run();
+  content::RunAllBlockingPoolTasksUntilIdle();
 
   EXPECT_TRUE(base::ContentsEqual(test_utils_.GetImagePath(),
                                   operation->GetImagePath()));
@@ -183,7 +198,7 @@
   base::MD5Sum(data_buffer.get(), kTestFileSize, &expected_digest);
   std::string expected_hash = base::MD5DigestToBase16(expected_digest);
 
-  scoped_refptr<OperationForTest> operation =
+  scoped_refptr<WriteFromUrlOperationForTest> operation =
       CreateOperation(GURL(""), expected_hash);
 
   EXPECT_CALL(
@@ -200,17 +215,14 @@
                          100)).Times(AtLeast(1));
 
   operation->SetImagePath(test_utils_.GetImagePath());
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&OperationForTest::VerifyDownload, operation,
-                     base::Bind(&base::DoNothing)));
-
-  base::RunLoop().RunUntilIdle();
+  {
+    base::RunLoop run_loop;
+    operation->VerifyDownload(run_loop.QuitClosure());
+    run_loop.Run();
+  }
 
   operation->Cancel();
 }
 
-}  // namespace
-
 }  // namespace image_writer
 }  // namespace extensions
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index c76b85d..0442d4d19 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -203,13 +203,12 @@
 
 void ChromeInternalLogSource::PopulateExtensionInfoLogs(
     SystemLogsResponse* response) {
-  Profile* primary_profile =
-      g_browser_process->profile_manager()->GetPrimaryUserProfile();
-  if (!primary_profile)
+  Profile* profile = ProfileManager::GetLastUsedProfile();
+  if (!profile)
     return;
 
   extensions::ExtensionRegistry* extension_registry =
-      extensions::ExtensionRegistry::Get(primary_profile);
+      extensions::ExtensionRegistry::Get(profile);
   std::string extensions_list;
   for (const scoped_refptr<const extensions::Extension>& extension :
        extension_registry->enabled_extensions()) {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 8588062d..8a91c48 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -255,6 +255,12 @@
     "If enabled, requests missing CVC when offering to upload credit cards to "
     "Google Payments.";
 
+const char kEnableAutofillCreditCardUploadNewUiName[] =
+    "Enable updated UI for Autofill credit card upload";
+const char kEnableAutofillCreditCardUploadNewUiDescription[] =
+    "If enabled, displays a new save card bubble/infobar design when offering "
+    "to upload credit cards to Google Payments.";
+
 const char kEnableBreakingNewsPushName[] = "Breaking News Push";
 const char kEnableBreakingNewsPushDescription[] =
     "Listen for breaking news content suggestions (e.g. for New Tab Page) "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 7e86e338..d5487e7 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -181,6 +181,9 @@
 extern const char kEnableAutofillCreditCardUploadCvcPromptName[];
 extern const char kEnableAutofillCreditCardUploadCvcPromptDescription[];
 
+extern const char kEnableAutofillCreditCardUploadNewUiName[];
+extern const char kEnableAutofillCreditCardUploadNewUiDescription[];
+
 extern const char kEnableBreakingNewsPushName[];
 extern const char kEnableBreakingNewsPushDescription[];
 
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.html b/chrome/browser/resources/settings/appearance_page/appearance_page.html
index 0e7f31a..3d35317 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.html
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.html
@@ -104,9 +104,10 @@
           </div>
 </if>
         </div>
-        <div class="settings-box"
+        <div class="settings-box" id="homeButton"
             hidden="[[!pageVisibility.homeButton]]">
-          <settings-toggle-button class="start" elide-label
+          <settings-toggle-button action-target="[[$$('#homeButton')]]"
+              class="start" elide-label
               pref="{{prefs.browser.show_home_button}}"
               label="$i18n{showHomeButton}"
               sub-label="[[getShowHomeSubLabel_(
@@ -144,9 +145,10 @@
             </settings-radio-group>
           </div>
         </template>
-        <div class="settings-box"
+        <div class="settings-box" id="bookmarksBar"
             hidden="[[!pageVisibility.bookmarksBar]]">
           <settings-toggle-button class="start"
+              action-target="[[$$('#bookmarksBar')]]"
               pref="{{prefs.bookmark_bar.show_on_all_tabs}}"
               label="$i18n{showBookmarksBar}">
           </settings-toggle-button>
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.js b/chrome/browser/resources/settings/appearance_page/appearance_page.js
index e8decc0..1b36b3b 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.js
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.js
@@ -14,14 +14,6 @@
 /**
  * 'settings-appearance-page' is the settings page containing appearance
  * settings.
- *
- * Example:
- *
- *    <iron-animated-pages>
- *      <settings-appearance-page prefs="{{prefs}}">
- *      </settings-appearance-page>
- *      ... other pages ...
- *    </iron-animated-pages>
  */
 Polymer({
   is: 'settings-appearance-page',
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.html b/chrome/browser/resources/settings/controls/settings_toggle_button.html
index a783800d..612396ba 100644
--- a/chrome/browser/resources/settings/controls/settings_toggle_button.html
+++ b/chrome/browser/resources/settings/controls/settings_toggle_button.html
@@ -41,7 +41,6 @@
     </style>
     <div id="outerRow" noSubLabel$="[[!subLabel]]">
       <div class="flex" id="labelWrapper" on-tap="onLabelWrapperTap_"
-          actionable$="[[!controlDisabled_(disabled, pref.*)]]"
           hidden="[[!label]]">
         <div id="label" class="label">[[label]]</div>
         <div id="subLabel" class="secondary label">[[subLabel]]</div>
@@ -54,7 +53,8 @@
       <paper-toggle-button id="control" checked="{{checked}}"
           on-change="notifyChangedByUserInteraction" aria-labelledby="label"
           aria-describedby="subLabel" on-up="resetTrackLock_"
-          disabled="[[controlDisabled_(disabled, pref)]]">
+          disabled="[[controlDisabled_(disabled, pref)]]"
+          on-tap="onToggleTap_">
       </paper-toggle-button>
     </div>
   </template>
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.js b/chrome/browser/resources/settings/controls/settings_toggle_button.js
index 5b4c77f..a58265e 100644
--- a/chrome/browser/resources/settings/controls/settings_toggle_button.js
+++ b/chrome/browser/resources/settings/controls/settings_toggle_button.js
@@ -16,20 +16,73 @@
       type: Boolean,
       reflectToAttribute: true,
     },
+
+    /**
+     * Which element will trigger state changes. Defaults to |this|.
+     * @type {HTMLElement}
+     */
+    actionTarget: {
+      observer: 'onActionTargetChange_',
+      type: Object,
+      value: function() {
+        return this;
+      },
+    },
   },
 
+  observers: [
+    'onDisableOrPrefChange_(disabled, pref.*, actionTarget)',
+  ],
+
   /** @override */
   focus: function() {
     this.$.control.focus();
   },
 
   /** @private */
-  onLabelWrapperTap_: function() {
+  onActionTargetChange_: function(current, prior) {
+    if (prior) {
+      this.unlisten(prior, 'tap', 'onLabelWrapperTap_');
+    }
+    if (current) {
+      this.listen(current, 'tap', 'onLabelWrapperTap_');
+    }
+  },
+
+  /**
+   * Handle taps directly on the toggle (see: onLabelWrapperTap_ for non-toggle
+   * taps).
+   * @param {!Event} e
+   * @private
+   */
+  onToggleTap_: function(e) {
+    // Stop the event from propagating to avoid firing two 'changed' events.
+    e.stopPropagation();
+  },
+
+  /** @private */
+  onDisableOrPrefChange_: function() {
+    if (this.controlDisabled_()) {
+      this.actionTarget.removeAttribute('actionable');
+    } else {
+      this.actionTarget.setAttribute('actionable', '');
+    }
+  },
+
+  /**
+   * Handle non-toggle button taps (see: onToggleTap_ for toggle taps).
+   * @param {!Event} e
+   * @private
+   */
+  onLabelWrapperTap_: function(e) {
+    // Stop the event from propagating to avoid firing two 'changed' events.
+    e.stopPropagation();
     if (this.controlDisabled_())
       return;
 
     this.checked = !this.checked;
     this.notifyChangedByUserInteraction();
+    this.fire('change');
   },
 
   /**
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html
index ed0b0c0..a58fdfd8 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -146,8 +146,8 @@
             </div>
           </div>
           <div class="settings-box first">
-            <settings-toggle-button id="offerTranslateOtherLangs" class="start"
-                pref="{{prefs.translate.enabled}}"
+            <settings-toggle-button id="offerTranslateOtherLanguages"
+                class="start" pref="{{prefs.translate.enabled}}"
                 label="$i18n{offerToEnableTranslate}">
             </settings-toggle-button>
           </div>
diff --git a/chrome/browser/ssl/captive_portal_blocking_page.cc b/chrome/browser/ssl/captive_portal_blocking_page.cc
index f3295a6..0d1e7f2 100644
--- a/chrome/browser/ssl/captive_portal_blocking_page.cc
+++ b/chrome/browser/ssl/captive_portal_blocking_page.cc
@@ -240,10 +240,10 @@
           safe_browsing::SBER_OPTIN_SITE_SECURITY_INTERSTITIAL);
       break;
     case security_interstitials::CMD_OPEN_REPORTING_PRIVACY:
-      controller()->OpenExtendedReportingPrivacyPolicy();
+      controller()->OpenExtendedReportingPrivacyPolicy(true);
       break;
     case security_interstitials::CMD_OPEN_WHITEPAPER:
-      controller()->OpenExtendedReportingWhitepaper();
+      controller()->OpenExtendedReportingWhitepaper(true);
       break;
     case security_interstitials::CMD_ERROR:
     case security_interstitials::CMD_TEXT_FOUND:
diff --git a/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc b/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc
index d5006b7..57d6c1e 100644
--- a/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc
@@ -76,7 +76,7 @@
  private:
   void InitializeLevelDB() {
     std::unique_ptr<leveldb::DB> db;
-    leveldb::Options options;
+    leveldb_env::Options options;
     options.create_if_missing = true;
     options.max_open_files = 0;  // Use minimum.
     options.env = in_memory_env_.get();
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
index d7a2b2e..8c39c28 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
@@ -215,11 +215,10 @@
   DCHECK(created);
   DCHECK(path.IsAbsolute());
 
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = true;
   options.paranoid_checks = true;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   if (env_override)
     options.env = env_override;
   std::unique_ptr<leveldb::DB> db;
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc
index 9c5414e..bab5501b 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc
@@ -118,7 +118,7 @@
 
   std::unique_ptr<LevelDBWrapper> InitializeLevelDB() {
     std::unique_ptr<leveldb::DB> db;
-    leveldb::Options options;
+    leveldb_env::Options options;
     options.create_if_missing = true;
     options.max_open_files = 0;  // Use minimum.
     options.env = in_memory_env_.get();
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc
index eb808178..b086bb5 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc
@@ -83,7 +83,7 @@
  private:
   void InitializeLevelDB() {
     std::unique_ptr<leveldb::DB> db;
-    leveldb::Options options;
+    leveldb_env::Options options;
     options.create_if_missing = true;
     options.max_open_files = 0;  // Use minimum.
     options.env = in_memory_env_.get();
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
index 53e47124..63ed69c 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
@@ -273,7 +273,7 @@
 
   std::unique_ptr<LevelDBWrapper> InitializeLevelDB() {
     std::unique_ptr<leveldb::DB> db;
-    leveldb::Options options;
+    leveldb_env::Options options;
     options.create_if_missing = true;
     options.max_open_files = 0;  // Use minimum.
     options.env = in_memory_env_.get();
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
index 4e62bab..6988a21 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
@@ -76,7 +76,7 @@
   base::ScopedTempDir base_dir;
   ASSERT_TRUE(base_dir.CreateUniqueTempDir());
   {
-    leveldb::Options options;
+    leveldb_env::Options options;
     options.create_if_missing = true;
     std::string db_dir =
         storage::FilePathToString(base_dir.GetPath().Append(kDatabaseName));
diff --git a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
index 1748a98..bf27b24 100644
--- a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
@@ -82,7 +82,7 @@
  protected:
   std::unique_ptr<LevelDBWrapper> OpenLevelDB() {
     std::unique_ptr<leveldb::DB> db;
-    leveldb::Options options;
+    leveldb_env::Options options;
     options.create_if_missing = true;
     options.env = in_memory_env_.get();
     leveldb::Status status = leveldb_env::OpenDB(
diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker.cc b/chrome/browser/sync_file_system/local/local_file_change_tracker.cc
index 9b81b83..7a6771b2 100644
--- a/chrome/browser/sync_file_system/local/local_file_change_tracker.cc
+++ b/chrome/browser/sync_file_system/local/local_file_change_tracker.cc
@@ -486,10 +486,9 @@
 
   std::string path =
       storage::FilePathToString(base_path_.Append(kDatabaseName));
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = true;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   if (env_override_)
     options.env = env_override_;
   leveldb::Status status = leveldb_env::OpenDB(options, path, &db_);
@@ -520,7 +519,8 @@
   DCHECK(!db_.get());
   LOG(WARNING) << "Attempting to repair TrackerDB.";
 
-  leveldb::Options options;
+  leveldb_env::Options options;
+  options.reuse_logs = false;  // Compact log file if repairing.
   options.max_open_files = 0;  // Use minimum.
   if (leveldb::RepairDB(db_path, options).ok() &&
       Init(FAIL_ON_CORRUPTION) == SYNC_STATUS_OK) {
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index 6ae06f8..c1d0e5b 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.h"
 #include "chrome/browser/ui/app_list/search/webstore/webstore_provider.h"
 #include "chrome/common/chrome_switches.h"
+#include "components/arc/arc_util.cc"
 #include "ui/app_list/app_list_features.h"
 #include "ui/app_list/app_list_model.h"
 #include "ui/app_list/app_list_switches.h"
@@ -91,7 +92,7 @@
           model->top_level_item_list()));
   controller->AddProvider(omnibox_group_id, base::MakeUnique<OmniboxProvider>(
                                                 profile, list_controller));
-  if (!features::IsPlayStoreAppSearchEnabled()) {
+  if (arc::IsWebstoreSearchEnabled()) {
     controller->AddProvider(
         webstore_group_id,
         base::MakeUnique<WebstoreProvider>(profile, list_controller));
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc
index 692ea91..d2e58288 100644
--- a/chrome/browser/ui/ash/ash_init.cc
+++ b/chrome/browser/ui/ash/ash_init.cc
@@ -161,6 +161,11 @@
 }
 
 AshInit::~AshInit() {
+  // ImageCursorsSet may indirectly hold a reference to CursorDataFactoryOzone,
+  // which is indirectly owned by Shell. Make sure we destroy the
+  // ImageCursorsSet before the Shell to avoid potential use after free.
+  g_browser_process->platform_part()->DestroyImageCursorsSet();
+
   // |window_manager_| deletes the Shell.
   if (!window_manager_ && ash::Shell::HasInstance()) {
     ash::Shell::DeleteInstance();
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
index f028e30..80108c4 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_constants.h"
@@ -108,6 +109,7 @@
     save_card_bubble_view_->Hide();
     save_card_bubble_view_ = nullptr;
   }
+  show_upload_confirm_title_ = false;
 }
 
 void SaveCardBubbleControllerImpl::ReshowBubble() {
@@ -135,15 +137,30 @@
 }
 
 base::string16 SaveCardBubbleControllerImpl::GetWindowTitle() const {
-  return l10n_util::GetStringUTF16(
-      is_uploading_ ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD
-                    : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL);
+  if (is_uploading_) {
+    if (show_upload_confirm_title_) {
+      return l10n_util::GetStringFUTF16(
+          IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC_TITLE,
+          card_.NetworkAndLastFourDigits());
+    } else if (IsAutofillUpstreamShowNewUiExperimentEnabled()) {
+      return l10n_util::GetStringUTF16(
+          IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V2);
+    }
+    return l10n_util::GetStringUTF16(
+        IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD);
+  }
+  return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL);
 }
 
 base::string16 SaveCardBubbleControllerImpl::GetExplanatoryMessage() const {
-  return is_uploading_ ? l10n_util::GetStringUTF16(
-                             IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION)
-                       : base::string16();
+  if (is_uploading_) {
+    return IsAutofillUpstreamShowNewUiExperimentEnabled()
+               ? l10n_util::GetStringUTF16(
+                     IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V2)
+               : l10n_util::GetStringUTF16(
+                     IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION);
+  }
+  return base::string16();
 }
 
 const CreditCard SaveCardBubbleControllerImpl::GetCard() const {
@@ -215,6 +232,7 @@
 void SaveCardBubbleControllerImpl::OnBubbleClosed() {
   save_card_bubble_view_ = nullptr;
   UpdateIcon();
+  show_upload_confirm_title_ = false;
 }
 
 const LegalMessageLines& SaveCardBubbleControllerImpl::GetLegalMessageLines()
@@ -222,6 +240,11 @@
   return legal_message_lines_;
 }
 
+void SaveCardBubbleControllerImpl::SetShowUploadConfirmTitle(
+    bool show_upload_confirm_title) {
+  show_upload_confirm_title_ = show_upload_confirm_title;
+}
+
 bool SaveCardBubbleControllerImpl::InputCvcIsValid(
     const base::string16& input_text) const {
   base::string16 trimmed_text;
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
index aa63349..248284d 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
@@ -66,6 +66,7 @@
   void OnBubbleClosed() override;
 
   const LegalMessageLines& GetLegalMessageLines() const override;
+  void SetShowUploadConfirmTitle(bool show_upload_confirm_title) override;
 
   // Used to check if an entered CVC value is a valid CVC for the current card.
   // Valid CVCs are a certain length for their card type (4 for AMEX, 3
@@ -105,17 +106,21 @@
   base::Closure save_card_callback_;
 
   // Governs whether the upload or local save version of the UI should be shown.
-  bool is_uploading_{false};
+  bool is_uploading_ = false;
 
   // Whether ReshowBubble() has been called since ShowBubbleFor*() was called.
-  bool is_reshow_{false};
+  bool is_reshow_ = false;
 
   // Whether the upload save version of the UI should ask the user for CVC.
-  bool should_cvc_be_requested_{false};
+  bool should_cvc_be_requested_ = false;
 
   // The value of the CVC entered by the user (if it was requested).
   base::string16 cvc_entered_by_user_;
 
+  // Whether the normal "Save this card?" title or the secondary
+  // "Confirm [card]" title should be shown during upload save.
+  bool show_upload_confirm_title_ = false;
+
   // Contains the details of the card that will be saved if the user accepts.
   CreditCard card_;
 
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
index eb7e503..4153bcd0 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
@@ -12,11 +12,13 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "chrome/browser/ui/autofill/save_card_bubble_view.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/credit_card.h"
@@ -534,6 +536,10 @@
 }
 
 TEST_F(SaveCardBubbleControllerImplTest, Metrics_Upload_FirstShow_LearnMore) {
+  // Learn More link only appears on upload if new UI is disabled.
+  base::test::ScopedFeatureList scoped_feature_list_;
+  scoped_feature_list_.InitAndDisableFeature(kAutofillUpstreamShowNewUi);
+
   ShowUploadBubble();
 
   base::HistogramTester histogram_tester;
@@ -545,6 +551,10 @@
 }
 
 TEST_F(SaveCardBubbleControllerImplTest, Metrics_Upload_Reshows_LearnMore) {
+  // Learn More link only appears on upload if new UI is disabled.
+  base::test::ScopedFeatureList scoped_feature_list_;
+  scoped_feature_list_.InitAndDisableFeature(kAutofillUpstreamShowNewUi);
+
   ShowUploadBubble();
   CloseAndReshowBubble();
 
diff --git a/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm b/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm
index e8e200c..a78b37c 100644
--- a/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm
@@ -56,6 +56,7 @@
     return lines_;
   }
 
+  MOCK_METHOD1(SetShowUploadConfirmTitle, void(bool show_upload_confirm_title));
   MOCK_CONST_METHOD1(InputCvcIsValid, bool(const base::string16& input_text));
 
   // Testing state.
diff --git a/chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.mm b/chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.mm
index d6b8435e..ace75e3 100644
--- a/chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.mm
@@ -11,20 +11,36 @@
 #include "chrome/browser/favicon/favicon_utils.h"
 #include "skia/ext/skia_utils_mac.h"
 #include "ui/base/material_design/material_design_controller.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia_util_mac.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/resources/grit/ui_resources.h"
 
 namespace {
 
 const CGFloat kVectorIconSize = 16;
 
+bool HasDefaultFavicon(content::WebContents* contents) {
+  gfx::Image favicon = favicon::TabFaviconFromWebContents(contents);
+  if (favicon.IsEmpty())
+    return false;
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  const gfx::ImageSkia* default_favicon =
+      rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
+
+  return favicon.ToImageSkia()->BackedBySameObjectAs(*default_favicon);
+}
+
 }  // namespace
 
 namespace mac {
 
 NSImage* FaviconForWebContents(content::WebContents* contents, SkColor color) {
-  if (contents) {
+  // If |contents| is using the default favicon, it needs to be drawn in
+  // |color|, which means this function can't necessarily reuse the existing
+  // favicon.
+  if (contents && !HasDefaultFavicon(contents)) {
     NSImage* image = favicon::TabFaviconFromWebContents(contents).AsNSImage();
 
     // The |image| could be nil if the bitmap is null. In that case, fallback
diff --git a/chrome/browser/ui/omnibox/OWNERS b/chrome/browser/ui/omnibox/OWNERS
index 8a44467..b98866d 100644
--- a/chrome/browser/ui/omnibox/OWNERS
+++ b/chrome/browser/ui/omnibox/OWNERS
@@ -1,5 +1,6 @@
 jdonnelly@chromium.org
 pkasting@chromium.org
 sky@chromium.org
+tommycli@chromium.org
 
 # COMPONENT: UI>Browser>Omnibox
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
index c418d39a..172c67a 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/autofill/view_util.h"
 #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/legal_message_line.h"
 #include "components/autofill/core/browser/ui/save_card_bubble_controller.h"
@@ -61,8 +62,6 @@
   chrome::RecordDialogCreation(chrome::DialogIdentifier::SAVE_CARD);
 }
 
-SaveCardBubbleViews::~SaveCardBubbleViews() {}
-
 void SaveCardBubbleViews::Show(DisplayReason reason) {
   ShowForReason(reason);
 }
@@ -73,6 +72,11 @@
 }
 
 views::View* SaveCardBubbleViews::CreateExtraView() {
+  if (GetCurrentFlowStep() != LOCAL_SAVE_ONLY_STEP &&
+      IsAutofillUpstreamShowNewUiExperimentEnabled())
+    return nullptr;
+  // Learn More link is only shown on local save bubble or when the new UI
+  // experiment is disabled.
   DCHECK(!learn_more_link_);
   learn_more_link_ = new views::Link(l10n_util::GetStringUTF16(IDS_LEARN_MORE));
   learn_more_link_->SetUnderline(false);
@@ -85,14 +89,22 @@
     return nullptr;
 
   // Use BoxLayout to provide insets around the label.
-  View* view = new View();
-  view->SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical));
+  footnote_view_ = new View();
+  footnote_view_->SetLayoutManager(
+      new views::BoxLayout(views::BoxLayout::kVertical));
 
   // Add a StyledLabel for each line of the legal message.
-  for (const LegalMessageLine& line : controller_->GetLegalMessageLines())
-    view->AddChildView(CreateLegalMessageLineLabel(line, this).release());
+  for (const LegalMessageLine& line : controller_->GetLegalMessageLines()) {
+    footnote_view_->AddChildView(
+        CreateLegalMessageLineLabel(line, this).release());
+  }
 
-  return view;
+  // If on the first step of the 2-step upload flow, hide the footer area until
+  // it's time to actually accept the dialog and ToS.
+  if (GetCurrentFlowStep() == UPLOAD_SAVE_CVC_FIX_FLOW_STEP_1_OFFER_UPLOAD)
+    footnote_view_->SetVisible(false);
+
+  return footnote_view_;
 }
 
 bool SaveCardBubbleViews::Accept() {
@@ -102,12 +114,18 @@
   // and that if it *does* have 2, it's because CVC is being requested.
   DCHECK_LE(view_stack_->size(), 2U);
   DCHECK(view_stack_->size() == 1 || controller_->ShouldRequestCvcFromUser());
-  if (controller_->ShouldRequestCvcFromUser() && view_stack_->size() == 1) {
+  if (GetCurrentFlowStep() == UPLOAD_SAVE_CVC_FIX_FLOW_STEP_1_OFFER_UPLOAD) {
     // If user accepted upload but more info is needed, push the next view onto
-    // the stack.
+    // the stack and update the bubble.
+    DCHECK(controller_);
+    controller_->SetShowUploadConfirmTitle(true);
+    GetWidget()->UpdateWindowTitle();
     view_stack_->Push(CreateRequestCvcView(), /*animate=*/true);
     // Disable the Save button until a valid CVC is entered:
     GetDialogClientView()->UpdateDialogButtons();
+    // Make the legal messaging footer appear:
+    DCHECK(footnote_view_);
+    footnote_view_->SetVisible(true);
     // Resize the bubble if it's grown larger:
     SizeToContents();
     return false;
@@ -132,17 +150,67 @@
   return true;
 }
 
+int SaveCardBubbleViews::GetDialogButtons() const {
+  if (GetCurrentFlowStep() == LOCAL_SAVE_ONLY_STEP ||
+      !IsAutofillUpstreamShowNewUiExperimentEnabled())
+    return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+  // For upload save when the new UI experiment is enabled, don't show the
+  // [No thanks] cancel option; use the top-right [X] close button for that.
+  return ui::DIALOG_BUTTON_OK;
+}
+
 base::string16 SaveCardBubbleViews::GetDialogButtonLabel(
     ui::DialogButton button) const {
-  return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK
-                                       ? IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT
-                                       : IDS_NO_THANKS);
+  if (!IsAutofillUpstreamShowNewUiExperimentEnabled()) {
+    // New UI experiment disabled:
+    return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK
+                                         ? IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT
+                                         : IDS_NO_THANKS);
+  }
+  // New UI experiment enabled:
+  switch (GetCurrentFlowStep()) {
+    // Local save has two buttons:
+    case LOCAL_SAVE_ONLY_STEP:
+      return l10n_util::GetStringUTF16(
+          button == ui::DIALOG_BUTTON_OK ? IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT
+                                         : IDS_NO_THANKS);
+    // Upload save has one button but it can say three different things:
+    case UPLOAD_SAVE_ONLY_STEP:
+      DCHECK(button == ui::DIALOG_BUTTON_OK);
+      return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT);
+    case UPLOAD_SAVE_CVC_FIX_FLOW_STEP_1_OFFER_UPLOAD:
+      DCHECK(button == ui::DIALOG_BUTTON_OK);
+      return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_NEXT);
+    case UPLOAD_SAVE_CVC_FIX_FLOW_STEP_2_REQUEST_CVC:
+      DCHECK(button == ui::DIALOG_BUTTON_OK);
+      return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_CONFIRM);
+    default:
+      NOTREACHED();
+      return base::string16();
+  }
+}
+
+bool SaveCardBubbleViews::IsDialogButtonEnabled(ui::DialogButton button) const {
+  if (button == ui::DIALOG_BUTTON_CANCEL)
+    return true;
+
+  DCHECK_EQ(ui::DIALOG_BUTTON_OK, button);
+  return !cvc_textfield_ ||
+         controller_->InputCvcIsValid(cvc_textfield_->text());
 }
 
 gfx::Size SaveCardBubbleViews::CalculatePreferredSize() const {
   return gfx::Size(kBubbleWidth, GetHeightForWidth(kBubbleWidth));
 }
 
+bool SaveCardBubbleViews::ShouldShowCloseButton() const {
+  // Local save and Upload save on the old UI should have a [No thanks] button,
+  // but Upload save on the new UI should surface the top-right [X] close button
+  // instead.
+  return GetCurrentFlowStep() != LOCAL_SAVE_ONLY_STEP &&
+         IsAutofillUpstreamShowNewUiExperimentEnabled();
+}
+
 base::string16 SaveCardBubbleViews::GetWindowTitle() const {
   return controller_ ? controller_->GetWindowTitle() : base::string16();
 }
@@ -184,6 +252,32 @@
   NOTREACHED();
 }
 
+void SaveCardBubbleViews::ContentsChanged(views::Textfield* sender,
+                                          const base::string16& new_contents) {
+  DCHECK_EQ(cvc_textfield_, sender);
+  GetDialogClientView()->UpdateDialogButtons();
+}
+
+SaveCardBubbleViews::~SaveCardBubbleViews() {}
+
+SaveCardBubbleViews::CurrentFlowStep SaveCardBubbleViews::GetCurrentFlowStep()
+    const {
+  // No legal messages means this is not upload save.
+  if (controller_->GetLegalMessageLines().empty())
+    return LOCAL_SAVE_ONLY_STEP;
+  // If we're not requesting CVC, this is the only step on the upload path.
+  if (!controller_->ShouldRequestCvcFromUser())
+    return UPLOAD_SAVE_ONLY_STEP;
+  // Must be on the CVC fix flow on the upload path.
+  if (view_stack_->size() == 1)
+    return UPLOAD_SAVE_CVC_FIX_FLOW_STEP_1_OFFER_UPLOAD;
+  if (view_stack_->size() == 2)
+    return UPLOAD_SAVE_CVC_FIX_FLOW_STEP_2_REQUEST_CVC;
+  // CVC fix flow should never have more than 3 views on the stack.
+  NOTREACHED();
+  return UNKNOWN_STEP;
+}
+
 // Create view containing everything except for the footnote.
 std::unique_ptr<views::View> SaveCardBubbleViews::CreateMainContentView() {
   auto view = base::MakeUnique<views::View>();
@@ -193,6 +287,16 @@
       views::BoxLayout::kVertical, gfx::Insets(),
       provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
 
+  // If applicable, add the upload explanation label.  Appears above the card
+  // info when new UI experiment is enabled.
+  base::string16 explanation = controller_->GetExplanatoryMessage();
+  if (!explanation.empty() && IsAutofillUpstreamShowNewUiExperimentEnabled()) {
+    views::Label* explanation_label = new views::Label(explanation);
+    explanation_label->SetMultiLine(true);
+    explanation_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    view->AddChildView(explanation_label);
+  }
+
   // Add the card type icon, last four digits and expiration date.
   views::View* description_view = new views::View();
   description_view->SetLayoutManager(new views::BoxLayout(
@@ -211,14 +315,21 @@
       views::CreateSolidBorder(1, SkColorSetA(SK_ColorBLACK, 10)));
   description_view->AddChildView(card_type_icon);
 
-  description_view->AddChildView(new views::Label(
-      base::string16(kMidlineEllipsis) + card.LastFourDigits()));
-  description_view->AddChildView(
-      new views::Label(card.AbbreviatedExpirationDateForDisplay()));
+  // Old UI shows last four digits and expiration.  New UI shows network and
+  // last four digits, but no expiration.
+  if (IsAutofillUpstreamShowNewUiExperimentEnabled()) {
+    description_view->AddChildView(
+        new views::Label(card.NetworkAndLastFourDigits()));
+  } else {
+    description_view->AddChildView(new views::Label(
+        base::string16(kMidlineEllipsis) + card.LastFourDigits()));
+    description_view->AddChildView(
+        new views::Label(card.AbbreviatedExpirationDateForDisplay()));
+  }
 
-  // Optionally add label that will contain an explanation for upload.
-  base::string16 explanation = controller_->GetExplanatoryMessage();
-  if (!explanation.empty()) {
+  // If applicable, add the upload explanation label.  Appears below the card
+  // info when new UI experiment is disabled.
+  if (!explanation.empty() && !IsAutofillUpstreamShowNewUiExperimentEnabled()) {
     views::Label* explanation_label = new views::Label(explanation);
     explanation_label->SetMultiLine(true);
     explanation_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -230,48 +341,43 @@
 
 std::unique_ptr<views::View> SaveCardBubbleViews::CreateRequestCvcView() {
   auto request_cvc_view = base::MakeUnique<views::View>();
+  ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
+
+  request_cvc_view->SetLayoutManager(new views::BoxLayout(
+      views::BoxLayout::kVertical, gfx::Insets(),
+      provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
   request_cvc_view->SetBackground(views::CreateThemedSolidBackground(
       request_cvc_view.get(), ui::NativeTheme::kColorId_BubbleBackground));
-  views::BoxLayout* layout =
-      new views::BoxLayout(views::BoxLayout::kHorizontal, gfx::Insets(),
-                           ChromeLayoutProvider::Get()->GetDistanceMetric(
-                               views::DISTANCE_RELATED_BUTTON_HORIZONTAL));
+
+  views::Label* explanation_label = new views::Label(l10n_util::GetStringUTF16(
+      IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC_EXPLANATION));
+  explanation_label->SetMultiLine(true);
+  explanation_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  request_cvc_view->AddChildView(explanation_label);
+
+  views::View* cvc_entry_view = new views::View();
+  views::BoxLayout* layout = new views::BoxLayout(
+      views::BoxLayout::kHorizontal, gfx::Insets(),
+      provider->GetDistanceMetric(views::DISTANCE_RELATED_BUTTON_HORIZONTAL));
   layout->set_cross_axis_alignment(
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
-  request_cvc_view->SetLayoutManager(layout);
+  cvc_entry_view->SetLayoutManager(layout);
 
   DCHECK(!cvc_textfield_);
   cvc_textfield_ = CreateCvcTextfield();
   cvc_textfield_->set_controller(this);
-  request_cvc_view->AddChildView(cvc_textfield_);
+  cvc_entry_view->AddChildView(cvc_textfield_);
 
   views::ImageView* cvc_image = new views::ImageView();
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   cvc_image->SetImage(
       rb.GetImageSkiaNamed(controller_->GetCvcImageResourceId()));
-  request_cvc_view->AddChildView(cvc_image);
+  cvc_entry_view->AddChildView(cvc_image);
 
-  request_cvc_view->AddChildView(new views::Label(
-      l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC)));
-
+  request_cvc_view->AddChildView(cvc_entry_view);
   return request_cvc_view;
 }
 
-bool SaveCardBubbleViews::IsDialogButtonEnabled(ui::DialogButton button) const {
-  if (button == ui::DIALOG_BUTTON_CANCEL)
-    return true;
-
-  DCHECK_EQ(ui::DIALOG_BUTTON_OK, button);
-  return !cvc_textfield_ ||
-         controller_->InputCvcIsValid(cvc_textfield_->text());
-}
-
-void SaveCardBubbleViews::ContentsChanged(views::Textfield* sender,
-                                          const base::string16& new_contents) {
-  DCHECK_EQ(cvc_textfield_, sender);
-  GetDialogClientView()->UpdateDialogButtons();
-}
-
 void SaveCardBubbleViews::Init() {
   SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical));
   view_stack_ = new ViewStack();
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.h b/chrome/browser/ui/views/autofill/save_card_bubble_views.h
index 797d05d..3c102bb 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views.h
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.h
@@ -42,48 +42,64 @@
 
   void Show(DisplayReason reason);
 
-  // SaveCardBubbleView
+  // SaveCardBubbleView:
   void Hide() override;
 
-  // views::BubbleDialogDelegateView
+  // views::BubbleDialogDelegateView:
   views::View* CreateExtraView() override;
   views::View* CreateFootnoteView() override;
   bool Accept() override;
   bool Cancel() override;
   bool Close() override;
+  int GetDialogButtons() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   bool IsDialogButtonEnabled(ui::DialogButton button) const override;
 
-  // views::View
+  // views::View:
   gfx::Size CalculatePreferredSize() const override;
 
-  // views::WidgetDelegate
+  // views::WidgetDelegate:
+  bool ShouldShowCloseButton() const override;
   base::string16 GetWindowTitle() const override;
   void WindowClosing() override;
 
-  // views::LinkListener
+  // views::LinkListener:
   void LinkClicked(views::Link* source, int event_flags) override;
 
-  // views::StyledLabelListener
+  // views::StyledLabelListener:
   void StyledLabelLinkClicked(views::StyledLabel* label,
                               const gfx::Range& range,
                               int event_flags) override;
 
-  // views::TextfieldController
+  // views::TextfieldController:
   void ContentsChanged(views::Textfield* sender,
                        const base::string16& new_contents) override;
 
  private:
+  // The current step of the save card flow.  Accounts for:
+  //  1) Local save vs. Upload save
+  //  2) Upload save can have all information or be missing CVC
+  enum CurrentFlowStep {
+    UNKNOWN_STEP,
+    LOCAL_SAVE_ONLY_STEP,
+    UPLOAD_SAVE_ONLY_STEP,
+    UPLOAD_SAVE_CVC_FIX_FLOW_STEP_1_OFFER_UPLOAD,
+    UPLOAD_SAVE_CVC_FIX_FLOW_STEP_2_REQUEST_CVC,
+  };
+
   ~SaveCardBubbleViews() override;
 
+  CurrentFlowStep GetCurrentFlowStep() const;
   std::unique_ptr<views::View> CreateMainContentView();
   std::unique_ptr<views::View> CreateRequestCvcView();
 
-  // views::BubbleDialogDelegateView
+  // views::BubbleDialogDelegateView:
   void Init() override;
 
   SaveCardBubbleController* controller_;  // Weak reference.
 
+  views::View* footnote_view_ = nullptr;
+
   ViewStack* view_stack_ = nullptr;
 
   views::Textfield* cvc_textfield_ = nullptr;
diff --git a/chrome/browser/ui/views/omnibox/OWNERS b/chrome/browser/ui/views/omnibox/OWNERS
index 392e67cf..e1d70054 100644
--- a/chrome/browser/ui/views/omnibox/OWNERS
+++ b/chrome/browser/ui/views/omnibox/OWNERS
@@ -1,4 +1,5 @@
 jdonnelly@chromium.org
 pkasting@chromium.org
+tommycli@chromium.org
 
 # COMPONENT: UI>Browser>Omnibox
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.cc b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
index 17707a4..b0142001 100644
--- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -186,7 +186,8 @@
     PaymentRequestSpec* spec,
     PaymentRequestState* state,
     PaymentRequestDialogView* dialog)
-    : PaymentRequestSheetController(spec, state, dialog) {
+    : PaymentRequestSheetController(spec, state, dialog),
+      payment_method_list_(dialog) {
   const std::vector<std::unique_ptr<PaymentInstrument>>& available_instruments =
       state->available_instruments();
   for (const auto& instrument : available_instruments) {
@@ -232,7 +233,7 @@
                            kPaymentRequestButtonSpacing));
 
   views::LabelButton* button = views::MdTextButton::CreateSecondaryUiButton(
-      this, l10n_util::GetStringUTF16(IDS_AUTOFILL_ADD_CREDITCARD_CAPTION));
+      this, l10n_util::GetStringUTF16(IDS_PAYMENTS_ADD_CARD));
   button->set_tag(static_cast<int>(
       PaymentMethodViewControllerTags::ADD_CREDIT_CARD_BUTTON));
   button->set_id(
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/payment_method_view_controller_browsertest.cc
index fdfe04f..2d32a181 100644
--- a/chrome/browser/ui/views/payments/payment_method_view_controller_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_method_view_controller_browsertest.cc
@@ -100,15 +100,11 @@
   OpenPaymentMethodScreen();
   list_view = dialog_view()->GetViewByID(
       static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW));
-  // Clicking on the second card again should not modify any state.
-  ClickOnDialogViewAndWait(list_view->child_at(1));
 
-  checkmark_view = list_view->child_at(0)->GetViewByID(
-      static_cast<int>(DialogViewID::CHECKMARK_VIEW));
-  checkmark_view2 = list_view->child_at(1)->GetViewByID(
-      static_cast<int>(DialogViewID::CHECKMARK_VIEW));
-  EXPECT_FALSE(checkmark_view->visible());
-  EXPECT_TRUE(checkmark_view2->visible());
+  ResetEventObserver(DialogEvent::BACK_NAVIGATION);
+  // Clicking on the second card again should not modify any state, and should
+  // return to the main payment sheet.
+  ClickOnDialogViewAndWait(list_view->child_at(1));
 
   EXPECT_EQ(request->state()->available_instruments().back().get(),
             request->state()->selected_instrument());
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.cc b/chrome/browser/ui/views/payments/payment_request_item_list.cc
index 4ca139e..5dd65a90 100644
--- a/chrome/browser/ui/views/payments/payment_request_item_list.cc
+++ b/chrome/browser/ui/views/payments/payment_request_item_list.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/ui/views/payments/payment_request_item_list.h"
 
+#include <utility>
+
+#include "chrome/browser/ui/views/payments/payment_request_dialog_view.h"
 #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
 #include "chrome/browser/ui/views/payments/payment_request_views_util.h"
 #include "components/payments/content/payment_request_state.h"
@@ -152,6 +155,10 @@
                                                  const ui::Event& event) {
   if (sender->id() == static_cast<int>(DialogViewID::EDIT_ITEM_BUTTON)) {
     EditButtonPressed();
+  } else if (selected_) {
+    // |dialog()| may be null in tests
+    if (list_->dialog())
+      list_->dialog()->GoBack();
   } else if (CanBeSelected()) {
     list()->SelectItem(this);
   } else {
@@ -170,7 +177,8 @@
   SetAccessibleName(accessible_content);
 }
 
-PaymentRequestItemList::PaymentRequestItemList() : selected_item_(nullptr) {}
+PaymentRequestItemList::PaymentRequestItemList(PaymentRequestDialogView* dialog)
+    : selected_item_(nullptr), dialog_(dialog) {}
 
 PaymentRequestItemList::~PaymentRequestItemList() {}
 
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.h b/chrome/browser/ui/views/payments/payment_request_item_list.h
index 5e085c5..38d7e36 100644
--- a/chrome/browser/ui/views/payments/payment_request_item_list.h
+++ b/chrome/browser/ui/views/payments/payment_request_item_list.h
@@ -19,6 +19,7 @@
 
 namespace payments {
 
+class PaymentRequestDialogView;
 class PaymentRequestSpec;
 class PaymentRequestState;
 
@@ -123,7 +124,7 @@
     DISALLOW_COPY_AND_ASSIGN(Item);
   };
 
-  PaymentRequestItemList();
+  explicit PaymentRequestItemList(PaymentRequestDialogView* dialog);
   virtual ~PaymentRequestItemList();
 
   // Adds an item to this list. |item->list()| should return this object.
@@ -140,6 +141,8 @@
   // Deselects the currently selected item and selects |item| instead.
   void SelectItem(Item* item);
 
+  PaymentRequestDialogView* dialog() { return dialog_; }
+
  private:
   // Unselects the currently selected item. This is private so that the list can
   // use it when selecting a new item while avoiding consumers of this class
@@ -148,6 +151,7 @@
 
   std::vector<std::unique_ptr<Item>> items_;
   Item* selected_item_;
+  PaymentRequestDialogView* dialog_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentRequestItemList);
 };
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc b/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc
index 832d0fa..24373b8 100644
--- a/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc
@@ -59,7 +59,7 @@
 }  // namespace
 
 TEST(PaymentRequestItemListTest, TestAddItem) {
-  PaymentRequestItemList list;
+  PaymentRequestItemList list(nullptr);
 
   std::unique_ptr<views::View> list_view = list.CreateListView();
   EXPECT_FALSE(list_view->has_children());
@@ -90,7 +90,7 @@
 }
 
 TEST(PaymentRequestItemListTest, TestSelectItemResultsInSingleItemSelected) {
-  PaymentRequestItemList list;
+  PaymentRequestItemList list(nullptr);
 
   std::vector<std::unique_ptr<TestListItem>> items;
   items.push_back(base::MakeUnique<TestListItem>(&list, false));
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index 8e759e6b..fefe9d4b 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -40,6 +40,7 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/geometry/insets.h"
@@ -947,9 +948,12 @@
   default_style.color = data_source_label->GetNativeTheme()->GetSystemColor(
       ui::NativeTheme::kColorId_LabelDisabledColor);
   data_source_label->SetDefaultStyle(default_style);
+
+  views::StyledLabel::RangeStyleInfo link_style =
+      views::StyledLabel::RangeStyleInfo::CreateForLink();
+  link_style.color = gfx::kGoogleBlue700;
   data_source_label->AddStyleRange(
-      gfx::Range(link_begin, link_begin + link_length),
-      views::StyledLabel::RangeStyleInfo::CreateForLink());
+      gfx::Range(link_begin, link_begin + link_length), link_style);
   data_source_label->SizeToFit(0);
   content_view->AddChildView(data_source_label.release());
   return content_view;
diff --git a/chrome/browser/ui/views/payments/profile_list_view_controller.cc b/chrome/browser/ui/views/payments/profile_list_view_controller.cc
index 7346985..96322d8 100644
--- a/chrome/browser/ui/views/payments/profile_list_view_controller.cc
+++ b/chrome/browser/ui/views/payments/profile_list_view_controller.cc
@@ -368,7 +368,7 @@
     PaymentRequestSpec* spec,
     PaymentRequestState* state,
     PaymentRequestDialogView* dialog)
-    : PaymentRequestSheetController(spec, state, dialog) {}
+    : PaymentRequestSheetController(spec, state, dialog), list_(dialog) {}
 
 ProfileListViewController::~ProfileListViewController() {}
 
diff --git a/chrome/browser/ui/views/payments/shipping_option_view_controller.cc b/chrome/browser/ui/views/payments/shipping_option_view_controller.cc
index 99d1edf..22d7b2b 100644
--- a/chrome/browser/ui/views/payments/shipping_option_view_controller.cc
+++ b/chrome/browser/ui/views/payments/shipping_option_view_controller.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/payments/shipping_option_view_controller.h"
 
+#include <memory>
+
 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h"
 #include "chrome/browser/ui/views/payments/payment_request_views_util.h"
 #include "components/payments/content/payment_request_spec.h"
@@ -82,7 +84,8 @@
     PaymentRequestSpec* spec,
     PaymentRequestState* state,
     PaymentRequestDialogView* dialog)
-    : PaymentRequestSheetController(spec, state, dialog) {
+    : PaymentRequestSheetController(spec, state, dialog),
+      shipping_option_list_(dialog) {
   spec->AddObserver(this);
   for (const auto& option : spec->GetShippingOptions()) {
     shipping_option_list_.AddItem(base::MakeUnique<ShippingOptionItem>(
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index ee9978a..adcbea8b 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -11,11 +11,11 @@
 
 #include "ash/login/ui/login_constants.h"
 #include "ash/public/interfaces/constants.mojom.h"
+#include "ash/public/interfaces/shutdown.mojom.h"
 #include "ash/public/interfaces/tray_action.mojom.h"
 #include "ash/shell.h"
 #include "ash/shutdown_reason.h"
 #include "ash/system/devicetype_utils.h"
-#include "ash/wm/lock_state_controller.h"
 #include "base/bind.h"
 #include "base/i18n/number_formatting.h"
 #include "base/location.h"
@@ -1186,8 +1186,12 @@
 }
 
 void SigninScreenHandler::HandleShutdownSystem() {
-  ash::Shell::Get()->lock_state_controller()->RequestShutdown(
-      ash::ShutdownReason::LOGIN_SHUT_DOWN_BUTTON);
+  ash::mojom::ShutdownControllerPtr shutdown_controller;
+  content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->BindInterface(ash::mojom::kServiceName, &shutdown_controller);
+
+  shutdown_controller->RequestShutdownFromLoginScreen();
 }
 
 void SigninScreenHandler::HandleRebootSystem() {
diff --git a/chrome/common/extensions/media_parser_struct_traits.h b/chrome/common/extensions/media_parser_struct_traits.h
index 00cf5d44..f53fa22 100644
--- a/chrome/common/extensions/media_parser_struct_traits.h
+++ b/chrome/common/extensions/media_parser_struct_traits.h
@@ -24,7 +24,7 @@
     // TODO(dcheng): perhaps metadata::AttachedImage should consider passing the
     // image data around in a std::vector<uint8_t>.
     return ConstCArray<uint8_t>(
-        image.data.size(), reinterpret_cast<const uint8_t*>(image.data.data()));
+        reinterpret_cast<const uint8_t*>(image.data.data()), image.data.size());
   }
 
   static bool Read(extensions::mojom::AttachedImageDataView view,
diff --git a/chrome/installer/linux/debian/expected_deps_x64 b/chrome/installer/linux/debian/expected_deps_x64
index 2315179a3..fc7e2fd0 100644
--- a/chrome/installer/linux/debian/expected_deps_x64
+++ b/chrome/installer/linux/debian/expected_deps_x64
@@ -1,7 +1,7 @@
 gconf-service
 libasound2 (>= 1.0.16)
 libatk1.0-0 (>= 1.12.4)
-libc6 (>= 2.17)
+libc6 (>= 2.15)
 libcairo2 (>= 1.6.0)
 libcups2 (>= 1.4.0)
 libdbus-1-3 (>= 1.2.14)
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64
index fe6ca3e..f14195dc 100644
--- a/chrome/installer/linux/rpm/expected_deps_x86_64
+++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -18,7 +18,6 @@
 libc.so.6(GLIBC_2.11)(64bit)
 libc.so.6(GLIBC_2.14)(64bit)
 libc.so.6(GLIBC_2.15)(64bit)
-libc.so.6(GLIBC_2.17)(64bit)
 libc.so.6(GLIBC_2.2.5)(64bit)
 libc.so.6(GLIBC_2.3)(64bit)
 libc.so.6(GLIBC_2.3.2)(64bit)
diff --git a/chrome/installer/zucchini/buffer_view.h b/chrome/installer/zucchini/buffer_view.h
index b01d4c3..08ca499a 100644
--- a/chrome/installer/zucchini/buffer_view.h
+++ b/chrome/installer/zucchini/buffer_view.h
@@ -13,6 +13,15 @@
 #include "base/logging.h"
 
 namespace zucchini {
+
+// Describes a region within a buffer, with starting offset and size.
+struct BufferRegion {
+  // size_t is used to match BufferViewBase::size_type, which is used when
+  // indexing in a buffer view.
+  size_t offset;
+  size_t size;
+};
+
 namespace internal {
 
 // BufferViewBase should not be used directly; it is an implementation used for
@@ -55,6 +64,9 @@
 
   // Element access
 
+  // Returns a BufferRegion describing the full view.
+  BufferRegion region() const { return BufferRegion{0, size()}; }
+
   // Returns the raw value at specified location |pos|.
   // If |pos| is not within the range of the buffer, the process is terminated.
   reference operator[](size_type pos) const {
@@ -62,6 +74,13 @@
     return first_[pos];
   }
 
+  // Returns a sub-buffer described by |region|.
+  BufferViewBase operator[](BufferRegion region) const {
+    DCHECK_LE(region.offset, size());
+    DCHECK_LE(region.size, size() - region.offset);
+    return {begin() + region.offset, region.size};
+  }
+
   template <class U>
   const U& read(size_type pos) const {
     CHECK_LE(pos + sizeof(U), size());
diff --git a/chrome/installer/zucchini/buffer_view_unittest.cc b/chrome/installer/zucchini/buffer_view_unittest.cc
index d51b07d..5b0e157d 100644
--- a/chrome/installer/zucchini/buffer_view_unittest.cc
+++ b/chrome/installer/zucchini/buffer_view_unittest.cc
@@ -52,6 +52,14 @@
       ConstBufferView::FromRange(std::begin(bytes_) + 1, std::begin(bytes_)));
 }
 
+TEST_F(BufferViewTest, Region) {
+  ConstBufferView view(std::begin(bytes_), kLen);
+
+  BufferRegion region = view.region();
+  EXPECT_EQ(0U, region.offset);
+  EXPECT_EQ(kLen, region.size);
+}
+
 TEST_F(BufferViewTest, Subscript) {
   ConstBufferView view(std::begin(bytes_), kLen);
 
@@ -66,6 +74,14 @@
   EXPECT_EQ(42, mutable_view[0]);
 }
 
+TEST_F(BufferViewTest, SubRegion) {
+  ConstBufferView view(std::begin(bytes_), kLen);
+
+  ConstBufferView sub_view = view[{2, 4}];
+  EXPECT_EQ(view.begin() + 2, sub_view.begin());
+  EXPECT_EQ(size_t(4), sub_view.size());
+}
+
 TEST_F(BufferViewTest, Shrink) {
   ConstBufferView buffer =
       ConstBufferView::FromRange(std::begin(bytes_), std::end(bytes_));
diff --git a/chrome/installer/zucchini/image_utils.h b/chrome/installer/zucchini/image_utils.h
index e9bd79d..9f88378 100644
--- a/chrome/installer/zucchini/image_utils.h
+++ b/chrome/installer/zucchini/image_utils.h
@@ -7,7 +7,9 @@
 
 #include <stdint.h>
 
+#include "base/numerics/safe_conversions.h"
 #include "base/optional.h"
+#include "chrome/installer/zucchini/buffer_view.h"
 #include "chrome/installer/zucchini/typed_value.h"
 
 namespace zucchini {
@@ -136,9 +138,18 @@
 // |exe_type| can be kExeTypeNoOp, in which case the Element descibes a region
 // of raw data.
 struct Element {
+  Element() = default;
+  constexpr Element(ExecutableType exe_type, offset_t offset, offset_t length)
+      : exe_type(exe_type), offset(offset), length(length) {}
+  constexpr explicit Element(BufferRegion region)
+      : exe_type(kExeTypeNoOp),
+        offset(base::checked_cast<offset_t>(region.offset)),
+        length(base::checked_cast<offset_t>(region.size)) {}
+
   ExecutableType exe_type;
   offset_t offset;
   offset_t length;
+  // TODO(huangs): Use BufferRegion.
 
   // Returns the end offset of this element.
   offset_t EndOffset() const { return offset + length; }
@@ -148,6 +159,8 @@
   bool FitsIn(offset_t total_size) const {
     return offset <= total_size && total_size - offset >= length;
   }
+
+  BufferRegion region() const { return {offset, length}; }
 };
 
 // A matched pair of Elements.
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index f807582..a99fb82 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -76,6 +76,7 @@
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1819
     'ChromeExtensionsCapabilityTest.testIFrameWithExtensionsSource',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1918
+    'ChromeDriverTest.testWindowMaximize',
     'ChromeDriverTest.testWindowPosition',
     'ChromeDriverTest.testWindowSize',
     'ChromeLoggingCapabilityTest.testPerformanceLogger',
diff --git a/chrome/test/data/webui/settings/category_default_setting_tests.js b/chrome/test/data/webui/settings/category_default_setting_tests.js
index 74d49a9..4927b2e 100644
--- a/chrome/test/data/webui/settings/category_default_setting_tests.js
+++ b/chrome/test/data/webui/settings/category_default_setting_tests.js
@@ -48,7 +48,7 @@
           assertEquals(category, contentType);
           assertEquals(expectedEnabled, testElement.categoryEnabled);
           browserProxy.resetResolver('setDefaultValueForContentType');
-          MockInteractions.tap(testElement.$.toggle.$.control);
+          MockInteractions.tap(testElement.$.toggle.actionTarget);
           return browserProxy.whenCalled('setDefaultValueForContentType');
         })
         .then(function(args) {
@@ -158,7 +158,7 @@
           assertTrue(secondaryToggle.checked);
 
           browserProxy.resetResolver('setDefaultValueForContentType');
-          MockInteractions.tap(testElement.$.toggle.$.control);
+          MockInteractions.tap(testElement.$.toggle.actionTarget);
           return browserProxy.whenCalled('setDefaultValueForContentType');
         })
         .then(function(args) {
@@ -172,7 +172,7 @@
           assertTrue(secondaryToggle.checked);
 
           browserProxy.resetResolver('setDefaultValueForContentType');
-          MockInteractions.tap(testElement.$.toggle.$.control);
+          MockInteractions.tap(testElement.$.toggle.actionTarget);
           return browserProxy.whenCalled('setDefaultValueForContentType');
         })
         .then(function(args) {
@@ -186,7 +186,7 @@
           assertTrue(secondaryToggle.checked);
 
           browserProxy.resetResolver('setDefaultValueForContentType');
-          MockInteractions.tap(secondaryToggle.$.control);
+          MockInteractions.tap(secondaryToggle.actionTarget);
           return browserProxy.whenCalled('setDefaultValueForContentType');
         })
         .then(function(args) {
@@ -200,7 +200,7 @@
           assertFalse(secondaryToggle.checked);
 
           browserProxy.resetResolver('setDefaultValueForContentType');
-          MockInteractions.tap(testElement.$.toggle.$.control);
+          MockInteractions.tap(testElement.$.toggle.actionTarget);
           return browserProxy.whenCalled('setDefaultValueForContentType');
         })
         .then(function(args) {
@@ -214,7 +214,7 @@
           assertFalse(secondaryToggle.checked);
 
           browserProxy.resetResolver('setDefaultValueForContentType');
-          MockInteractions.tap(testElement.$.toggle.$.control);
+          MockInteractions.tap(testElement.$.toggle.actionTarget);
           return browserProxy.whenCalled('setDefaultValueForContentType');
         })
         .then(function(args) {
@@ -228,7 +228,7 @@
           assertFalse(secondaryToggle.checked);
 
           browserProxy.resetResolver('setDefaultValueForContentType');
-          MockInteractions.tap(secondaryToggle.$.control);
+          MockInteractions.tap(secondaryToggle.actionTarget);
           return browserProxy.whenCalled('setDefaultValueForContentType');
         })
         .then(function(args) {
diff --git a/chrome/test/data/webui/settings/google_assistant_page_test.js b/chrome/test/data/webui/settings/google_assistant_page_test.js
index b2b41b2..f070923 100644
--- a/chrome/test/data/webui/settings/google_assistant_page_test.js
+++ b/chrome/test/data/webui/settings/google_assistant_page_test.js
@@ -66,7 +66,7 @@
     assertFalse(button.checked);
 
     // Tap the enable toggle button and ensure the state becomes enabled.
-    MockInteractions.tap(button.$.control);
+    MockInteractions.tap(button.actionTarget);
     Polymer.dom.flush();
     assertTrue(button.checked);
     return browserProxy.whenCalled('setGoogleAssistantEnabled')
@@ -85,7 +85,7 @@
     assertFalse(button.disabled);
     assertFalse(button.checked);
 
-    MockInteractions.tap(button.$.control);
+    MockInteractions.tap(button.actionTarget);
     Polymer.dom.flush();
     assertTrue(button.checked);
     return browserProxy.whenCalled('setGoogleAssistantContextEnabled')
diff --git a/chrome/test/data/webui/settings/languages_page_tests.js b/chrome/test/data/webui/settings/languages_page_tests.js
index 5215421..762e4f6 100644
--- a/chrome/test/data/webui/settings/languages_page_tests.js
+++ b/chrome/test/data/webui/settings/languages_page_tests.js
@@ -261,18 +261,17 @@
       });
 
       test('test translate.enable toggle', function() {
-        var settingsToggle = languagesPage.$.offerTranslateOtherLangs;
+        var settingsToggle = languagesPage.$.offerTranslateOtherLanguages;
         assertTrue(!!settingsToggle);
-        var paperToggle = settingsToggle.$$('paper-toggle-button');
-        assertTrue(!!paperToggle);
+        assertTrue(!!settingsToggle.actionTarget);
 
         // Clicking on the toggle switches it to false.
-        MockInteractions.tap(paperToggle);
+        MockInteractions.tap(settingsToggle.actionTarget);
         var newToggleValue = languageHelper.prefs.translate.enabled.value;
         assertFalse(newToggleValue);
 
         // Clicking on the toggle switches it to true again.
-        MockInteractions.tap(paperToggle);
+        MockInteractions.tap(settingsToggle.actionTarget);
         newToggleValue = languageHelper.prefs.translate.enabled.value;
         assertTrue(newToggleValue);
       });
diff --git a/chrome/test/data/webui/settings/settings_toggle_button_tests.js b/chrome/test/data/webui/settings/settings_toggle_button_tests.js
index e8a46c5..8cd3472 100644
--- a/chrome/test/data/webui/settings/settings_toggle_button_tests.js
+++ b/chrome/test/data/webui/settings/settings_toggle_button_tests.js
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 /** @fileoverview Suite of tests for settings-toggle-button. */
-cr.define('settings_toggle_button', function() {
-  suite('SettingsToggleButton', function() {
+cr.define('settings_toggle_button', () => {
+  suite('SettingsToggleButton', () => {
     /**
      * Toggle button created before each test.
      * @type {SettingsCheckbox}
@@ -12,7 +12,7 @@
     var testElement;
 
     // Initialize a checked control before each test.
-    setup(function() {
+    setup(() => {
       /**
        * Pref value used in tests, should reflect the 'checked' attribute.
        * Create a new pref for each test() to prevent order (state)
@@ -30,21 +30,39 @@
       document.body.appendChild(testElement);
     });
 
-    test('value changes on tap', function() {
+    test('value changes on tap', () => {
       assertTrue(testElement.checked);
       assertTrue(testElement.pref.value);
 
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertFalse(testElement.checked);
       assertFalse(testElement.pref.value);
 
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertTrue(testElement.checked);
       assertTrue(testElement.pref.value);
     });
 
-    test('fires a change event', function(done) {
-      testElement.addEventListener('change', function() {
+    test('fires a change event for action-target', (done) => {
+      testElement.addEventListener('change', () => {
+        assertFalse(testElement.checked);
+        done();
+      });
+      assertTrue(testElement.checked);
+      MockInteractions.tap(testElement.actionTarget);
+    });
+
+    test('fires a change event for label', (done) => {
+      testElement.addEventListener('change', () => {
+        assertFalse(testElement.checked);
+        done();
+      });
+      assertTrue(testElement.checked);
+      MockInteractions.tap(testElement.$.labelWrapper);
+    });
+
+    test('fires a change event for toggle', (done) => {
+      testElement.addEventListener('change', () => {
         assertFalse(testElement.checked);
         done();
       });
@@ -52,18 +70,31 @@
       MockInteractions.tap(testElement.$.control);
     });
 
-    test('does not change when disabled', function() {
+    test('fires a single change event per tap', () => {
+      counter = 0
+      testElement.addEventListener('change', () => {
+        ++counter;
+      });
+      MockInteractions.tap(testElement.actionTarget);
+      assertEquals(1, counter);
+      MockInteractions.tap(testElement.$.labelWrapper);
+      assertEquals(2, counter);
+      MockInteractions.tap(testElement.$.control);
+      assertEquals(3, counter);
+    });
+
+    test('does not change when disabled', () => {
       testElement.checked = false;
       testElement.setAttribute('disabled', '');
       assertTrue(testElement.disabled);
       assertTrue(testElement.$.control.disabled);
 
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertFalse(testElement.checked);
       assertFalse(testElement.$.control.checked);
     });
 
-    test('inverted', function() {
+    test('inverted', () => {
       testElement.inverted = true;
       testElement.set('pref', {
         key: 'test',
@@ -74,16 +105,16 @@
       assertTrue(testElement.pref.value);
       assertFalse(testElement.checked);
 
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertFalse(testElement.pref.value);
       assertTrue(testElement.checked);
 
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertTrue(testElement.pref.value);
       assertFalse(testElement.checked);
     });
 
-    test('numerical pref', function() {
+    test('numerical pref', () => {
       var prefNum = {
         key: 'test',
         type: chrome.settingsPrivate.PrefType.NUMBER,
@@ -93,16 +124,16 @@
       testElement.set('pref', prefNum);
       assertTrue(testElement.checked);
 
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertFalse(testElement.checked);
       assertEquals(0, prefNum.value);
 
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertTrue(testElement.checked);
       assertEquals(1, prefNum.value);
     });
 
-    test('numerical pref with custom values', function() {
+    test('numerical pref with custom values', () => {
       var prefNum = {
         key: 'test',
         type: chrome.settingsPrivate.PrefType.NUMBER,
@@ -114,16 +145,16 @@
       testElement.set('pref', prefNum);
       assertFalse(testElement.checked);
 
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertTrue(testElement.checked);
       assertEquals(1, prefNum.value);
 
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertFalse(testElement.checked);
       assertEquals(5, prefNum.value);
     });
 
-    test('numerical pref with unknown inital value', function() {
+    test('numerical pref with unknown initial value', () => {
       var prefNum = {
         key: 'test',
         type: chrome.settingsPrivate.PrefType.NUMBER,
@@ -141,17 +172,17 @@
       assertEquals(3, prefNum.value);
 
       // Unchecking should still send the unchecked value to prefs.
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertFalse(testElement.checked);
       assertEquals(5, prefNum.value);
 
       // Checking should still send the normal checked value to prefs.
-      MockInteractions.tap(testElement.$.control);
+      MockInteractions.tap(testElement.actionTarget);
       assertTrue(testElement.checked);
       assertEquals(1, prefNum.value);
     });
 
-    test('shows controlled indicator when pref is controlled', function() {
+    test('shows controlled indicator when pref is controlled', () => {
       assertFalse(!!testElement.$$('cr-policy-pref-indicator'));
 
       var pref = {
@@ -168,7 +199,7 @@
       assertTrue(!!testElement.$$('cr-policy-pref-indicator'));
     });
 
-    test('no indicator with no-extension-indicator flag', function() {
+    test('no indicator with no-extension-indicator flag', () => {
       assertFalse(!!testElement.$$('cr-policy-pref-indicator'));
 
       testElement.noExtensionIndicator = true;
diff --git a/chromecast/android/BUILD.gn b/chromecast/android/BUILD.gn
index 4510858..732f9f7 100644
--- a/chromecast/android/BUILD.gn
+++ b/chromecast/android/BUILD.gn
@@ -42,6 +42,20 @@
     "//skia",
   ]
 
+  # Explicit dependencies required for JNI registration to be able to find the
+  # native side functions.
+  if (is_component_build) {
+    deps += [
+      "//device/bluetooth",
+      "//device/gamepad",
+      "//device/sensors",
+      "//media/midi",
+      "//ui/android",
+      "//ui/events/devices",
+      "//ui/shell_dialogs",
+    ]
+  }
+
   if (chromecast_branding == "public") {
     sources += [ "platform_jni_loader_stub.cc" ]
   }
diff --git a/chromecast/app/android/cast_jni_loader.cc b/chromecast/app/android/cast_jni_loader.cc
index 01aebfe..9c75510b 100644
--- a/chromecast/app/android/cast_jni_loader.cc
+++ b/chromecast/app/android/cast_jni_loader.cc
@@ -20,6 +20,9 @@
     return -1;
   }
 
+  if (!content::android::OnJNIOnLoadInit())
+    return false;
+
   content::Compositor::Initialize();
   content::SetContentMainDelegate(new chromecast::shell::CastMainDelegate);
   return JNI_VERSION_1_4;
diff --git a/components/arc/arc_util.cc b/components/arc/arc_util.cc
index b7fa6e6e..0ebc98c 100644
--- a/components/arc/arc_util.cc
+++ b/components/arc/arc_util.cc
@@ -66,8 +66,19 @@
   // TODO(hidehiko): Remove this and clean up whole this function, when
   // session_manager supports a new flag.
   return command_line->HasSwitch(chromeos::switches::kEnableArc) ||
-      (command_line->HasSwitch(chromeos::switches::kArcAvailable) &&
-       base::FeatureList::IsEnabled(kEnableArcFeature));
+         (command_line->HasSwitch(chromeos::switches::kArcAvailable) &&
+          base::FeatureList::IsEnabled(kEnableArcFeature));
+}
+
+bool IsWebstoreSearchEnabled() {
+  const auto* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(chromeos::switches::kArcAvailability)) {
+    const std::string value =
+        command_line->GetSwitchValueASCII(chromeos::switches::kArcAvailability);
+
+    return value == kAvailabilityNone;
+  }
+  return true;
 }
 
 bool IsPlayStoreAvailable() {
diff --git a/components/arc/arc_util.h b/components/arc/arc_util.h
index 625260b..3214545 100644
--- a/components/arc/arc_util.h
+++ b/components/arc/arc_util.h
@@ -34,6 +34,10 @@
 // check, so it is ok to access them directly.
 bool IsArcAvailable();
 
+// Returns true if ARC is not installed and the current device is not supported
+// to run ARC.
+bool IsWebstoreSearchEnabled();
+
 // Returns true if ARC image has Play Store package.
 bool IsPlayStoreAvailable();
 
diff --git a/components/arc/bitmap/bitmap_struct_traits.h b/components/arc/bitmap/bitmap_struct_traits.h
index 7aefb77f..e8aacf3 100644
--- a/components/arc/bitmap/bitmap_struct_traits.h
+++ b/components/arc/bitmap/bitmap_struct_traits.h
@@ -16,8 +16,8 @@
     const SkImageInfo& info = r.info();
     DCHECK_EQ(info.colorType(), kRGBA_8888_SkColorType);
 
-    return mojo::CArray<uint8_t>(
-        r.getSize(), r.getSize(), static_cast<uint8_t*>(r.getPixels()));
+    return mojo::CArray<uint8_t>(static_cast<uint8_t*>(r.getPixels()),
+                                 r.getSize());
   }
   static uint32_t width(const SkBitmap& r) { return r.width(); }
   static uint32_t height(const SkBitmap& r) { return r.height(); }
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc
index 6466e07..fdf7e93 100644
--- a/components/autofill/core/browser/autofill_experiments.cc
+++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -42,6 +42,8 @@
     "AutofillSuppressDisusedAddresses", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kAutofillUpstreamRequestCvcIfMissing{
     "AutofillUpstreamRequestCvcIfMissing", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillUpstreamShowNewUi{
+    "AutofillUpstreamShowNewUi", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kAutofillUpstreamUseAutofillProfileComparator{
     "AutofillUpstreamUseAutofillProfileComparator",
     base::FEATURE_ENABLED_BY_DEFAULT};
@@ -263,6 +265,14 @@
 #endif
 }
 
+bool IsAutofillUpstreamShowNewUiExperimentEnabled() {
+#if defined(OS_ANDROID)
+  return false;
+#else
+  return base::FeatureList::IsEnabled(kAutofillUpstreamShowNewUi);
+#endif
+}
+
 base::TimeDelta GetMaxTimeSinceAutofillProfileUseForCardUpload() {
   int value;
   const std::string param_value = variations::GetVariationParamValueByFeature(
diff --git a/components/autofill/core/browser/autofill_experiments.h b/components/autofill/core/browser/autofill_experiments.h
index 0ae7639..0a2f5c36 100644
--- a/components/autofill/core/browser/autofill_experiments.h
+++ b/components/autofill/core/browser/autofill_experiments.h
@@ -34,6 +34,7 @@
 extern const base::Feature kAutofillOfferLocalSaveIfServerCardManuallyEntered;
 extern const base::Feature kAutofillSuppressDisusedAddresses;
 extern const base::Feature kAutofillUpstreamRequestCvcIfMissing;
+extern const base::Feature kAutofillUpstreamShowNewUi;
 extern const base::Feature kAutofillUpstreamUseAutofillProfileComparator;
 extern const base::Feature kAutofillUpstreamUseNotRecentlyUsedAutofillProfile;
 extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
@@ -125,6 +126,10 @@
 // in the offer to save bubble if it was not detected during the checkout flow.
 bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled();
 
+// Returns whether the experiment is enabled where Chrome Upstream displays a
+// new save card bubble/infobar design.
+bool IsAutofillUpstreamShowNewUiExperimentEnabled();
+
 // Returns the maximum time that could have elapsed since an address profile's
 // most recent use for the adress profile to be included in the candidate set
 // for card upload. Returns 0 if the experiment is not enabled.
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 9a399a0b..b29e5c2 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -1326,6 +1326,11 @@
       return;
     }
 
+    if (IsAutofillUpstreamShowNewUiExperimentEnabled()) {
+      upload_request_.active_experiments.push_back(
+          kAutofillUpstreamShowNewUi.name);
+    }
+
     // All required data is available, start the upload process.
     payments_client_->GetUploadDetails(upload_request_.profiles,
                                        upload_request_.active_experiments,
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index c224044f..edf404f 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -1081,6 +1081,10 @@
         kAutofillUpstreamRequestCvcIfMissing);
   }
 
+  void EnableAutofillUpstreamShowNewUiExperiment() {
+    scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamShowNewUi);
+  }
+
   void DisableAutofillUpstreamUseAutofillProfileComparator() {
     scoped_feature_list_.InitAndDisableFeature(
         kAutofillUpstreamUseAutofillProfileComparator);
@@ -5302,6 +5306,83 @@
   ExpectCardUploadDecisionUkm(AutofillMetrics::CVC_FIELD_NOT_FOUND);
 }
 
+// kAutofillUpstreamShowNewUi flag is currently not available on Android.
+#if !defined(OS_ANDROID)
+TEST_F(AutofillManagerTest,
+       UploadCreditCard_AddNewUiFlagStateToRequestIfExperimentOn) {
+  EnableAutofillUpstreamShowNewUiExperiment();
+  personal_data_.ClearAutofillProfiles();
+  autofill_manager_->set_credit_card_upload_enabled(true);
+
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, and submit.
+  credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("11");
+  credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+  base::HistogramTester histogram_tester;
+
+  // Confirm upload happened and the new UI flag was sent in the request.
+  EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+  FormSubmitted(credit_card_form);
+  EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
+  EXPECT_THAT(
+      autofill_manager_->GetActiveExperiments(),
+      UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name,
+                           kAutofillUpstreamShowNewUi.name));
+}
+
+TEST_F(AutofillManagerTest,
+       UploadCreditCard_DoNotAddNewUiFlagStateToRequestIfExperimentOff) {
+  personal_data_.ClearAutofillProfiles();
+  autofill_manager_->set_credit_card_upload_enabled(true);
+
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, and submit.
+  credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("11");
+  credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+  base::HistogramTester histogram_tester;
+
+  // Confirm upload happened and the new UI flag was sent in the request.
+  EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+  FormSubmitted(credit_card_form);
+  EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
+  EXPECT_THAT(
+      autofill_manager_->GetActiveExperiments(),
+      UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name));
+}
+#endif
+
 TEST_F(AutofillManagerTest, UploadCreditCard_NoProfileAvailable) {
   personal_data_.ClearAutofillProfiles();
   autofill_manager_->set_credit_card_upload_enabled(true);
diff --git a/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h b/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
index ce040ae..85814827 100644
--- a/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
+++ b/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
@@ -26,6 +26,7 @@
   MOCK_METHOD1(OnLegalMessageLinkClicked, void(const GURL& url));
   MOCK_METHOD0(OnBubbleClosed, void());
   MOCK_CONST_METHOD0(GetLegalMessageLines, const LegalMessageLines&());
+  MOCK_METHOD1(SetShowUploadConfirmTitle, void(bool show_upload_confirm_title));
   MOCK_CONST_METHOD1(InputCvcIsValid, bool(const base::string16& input_text));
 
   base::string16 GetCvcEnteredByUser() const override;
diff --git a/components/autofill/core/browser/ui/save_card_bubble_controller.h b/components/autofill/core/browser/ui/save_card_bubble_controller.h
index f01cac3..5b56b1fa 100644
--- a/components/autofill/core/browser/ui/save_card_bubble_controller.h
+++ b/components/autofill/core/browser/ui/save_card_bubble_controller.h
@@ -58,6 +58,10 @@
   // Returns empty vector if no legal message should be shown.
   virtual const LegalMessageLines& GetLegalMessageLines() const = 0;
 
+  // Sets whether the normal title or the "Confirm [card]" title shown be shown
+  // during upload save.
+  virtual void SetShowUploadConfirmTitle(bool show_upload_confirm_title) = 0;
+
   // Utilities.
   virtual bool InputCvcIsValid(const base::string16& input_text) const = 0;
 
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index ab81481..2ebefff 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -191,6 +191,12 @@
   <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT" desc="Text to show for the Autofill save credit card prompt accept button. The prompt can be either a bubble or an infobar.">
     Save
   </message>
+  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_NEXT" desc="Text to show for the Autofill upload save credit card prompt accept button when more information (e.g., CVC) is needed in order to save the card.">
+    Next
+  </message>
+  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_CONFIRM" desc="Text to show for the Autofill upload save credit card prompt accept button when more information (e.g., CVC) was needed in order to save the card and was entered.">
+    Confirm
+  </message>
   <if expr="_google_chrome">
     <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt when the card is to be saved locally. The prompt can be either a bubble or an infobar.">
       Do you want Chrome to save this card?
@@ -208,17 +214,34 @@
       </message>
     </then>
     <else>
-      <!-- TODO(crbug/714920): Rename IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD to IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_AND_LOCAL -->
       <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD" desc="Title text for the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar.">
         Do you want to save this card to your Google Account and on this device?
       </message>
     </else>
   </if>
+  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V2" desc="Title text for the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to June 2017 UI guidelines. The prompt can be either a bubble or an infobar.">
+    Save this card for faster checkout?
+  </message>
   <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar.">
     Pay quickly on sites and apps across devices using cards you have saved with Google.
   </message>
-  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC" desc="Text displayed in the Autofill save credit card prompt explaining that the card needs additional CVC information in order to be saved to Google Payments.">
-    Please verify your CVC
+  <if expr="is_linux and not is_chromeos">
+    <then>
+      <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V2" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to June 2017 UI guidelines. The prompt will be shown in a bubble below the omnibox.">
+        Your card will be saved in your Google Account
+      </message>
+    </then>
+    <else>
+      <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V2" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally, according to June 2017 UI guidelines. The prompt can be either a bubble or an infobar.">
+        Your card will be saved in your Google Account and on this device
+      </message>
+    </else>
+  </if>
+  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC_TITLE" desc="Title text to show for the Autofill upload save credit card prompt when more information (e.g., CVC) is needed in order to save the card.  It will display the network and last four digits of the card to be saved.">
+    Confirm <ph name="CREDIT_CARD">$1<ex>Visa - 5678</ex></ph>
+  </message>
+  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC_EXPLANATION" desc="Text displayed in the Autofill save credit card prompt explaining the usage of the additional CVC information needed in order to save the card to Google Payments.">
+    The CVC is used to validate your card and won't be saved in your account
   </message>
 
   <!-- Autofill credit card suggestion popup -->
diff --git a/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.cc b/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.cc
index d15c172..a24fe408 100644
--- a/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.cc
+++ b/components/chrome_cleaner/public/typemaps/chrome_prompt_struct_traits.cc
@@ -12,8 +12,8 @@
     const base::FilePath& file_path) {
 #if defined(OS_WIN)
   return ConstCArray<uint16_t>(
-      file_path.value().size(),
-      reinterpret_cast<const uint16_t*>(file_path.value().data()));
+      reinterpret_cast<const uint16_t*>(file_path.value().data()),
+      file_path.value().size());
 #else
   NOTREACHED();
   return ConstCArray<uint16_t>();
diff --git a/components/data_reduction_proxy/core/browser/data_store_impl.cc b/components/data_reduction_proxy/core/browser/data_store_impl.cc
index 564b70b7..37b69fe 100644
--- a/components/data_reduction_proxy/core/browser/data_store_impl.cc
+++ b/components/data_reduction_proxy/core/browser/data_store_impl.cc
@@ -114,7 +114,7 @@
 DataStore::Status DataStoreImpl::OpenDB() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = true;
   options.paranoid_checks = true;
   // Deletes to buckets not found are stored in the log. Use a new log so that
diff --git a/components/drive/resource_metadata_storage.cc b/components/drive/resource_metadata_storage.cc
index 7d601a1..52e5bcd 100644
--- a/components/drive/resource_metadata_storage.cc
+++ b/components/drive/resource_metadata_storage.cc
@@ -270,10 +270,9 @@
 
   // Open DB.
   std::unique_ptr<leveldb::DB> resource_map;
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = false;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   leveldb::Status status = leveldb_env::OpenDB(
       options, resource_map_path.AsUTF8Unsafe(), &resource_map);
   if (!status.ok())
@@ -553,10 +552,9 @@
   }
 
   // Try to open the existing DB.
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = false;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
 
   DBInitStatus open_existing_result = DB_INIT_NOT_FOUND;
   leveldb::Status status;
@@ -604,10 +602,10 @@
     MoveIfPossible(resource_map_path, preserved_resource_map_path);
 
     // Create DB.
+    options = leveldb_env::Options();
     options.max_open_files = 0;  // Use minimum.
     options.create_if_missing = true;
     options.error_if_exists = true;
-    options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
 
     status = leveldb_env::OpenDB(options, resource_map_path.AsUTF8Unsafe(),
                                  &resource_map_);
@@ -660,10 +658,10 @@
   if (!base::PathExists(trashed_resource_map_path))
     return;
 
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = false;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
+  options.reuse_logs = false;
 
   // Trashed DB may be broken, repair it first.
   leveldb::Status status;
diff --git a/components/leveldb/leveldb_service_impl.cc b/components/leveldb/leveldb_service_impl.cc
index a640616..ad2c64c 100644
--- a/components/leveldb/leveldb_service_impl.cc
+++ b/components/leveldb/leveldb_service_impl.cc
@@ -47,14 +47,13 @@
         memory_dump_id,
     leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
     OpenCallback callback) {
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = open_options->create_if_missing;
   options.error_if_exists = open_options->error_if_exists;
   options.paranoid_checks = open_options->paranoid_checks;
   options.write_buffer_size = open_options->write_buffer_size;
   options.max_open_files = open_options->max_open_files;
 
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   options.compression = leveldb::kSnappyCompression;
 
   // Register our directory with the file thread.
@@ -86,7 +85,7 @@
         memory_dump_id,
     leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
     OpenCallback callback) {
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = true;
   options.max_open_files = 0;  // Use minimum.
 
@@ -110,7 +109,7 @@
 void LevelDBServiceImpl::Destroy(filesystem::mojom::DirectoryPtr directory,
                                  const std::string& dbname,
                                  DestroyCallback callback) {
-  leveldb::Options options;
+  leveldb_env::Options options;
   // Register our directory with the file thread.
   LevelDBMojoProxy::OpaqueDir* dir =
       thread_->RegisterDirectory(std::move(directory));
diff --git a/components/leveldb_proto/leveldb_database.cc b/components/leveldb_proto/leveldb_database.cc
index 073dbec..9fa1e43 100644
--- a/components/leveldb_proto/leveldb_database.cc
+++ b/components/leveldb_proto/leveldb_database.cc
@@ -36,7 +36,7 @@
 // static
 bool LevelDB::Destroy(const base::FilePath& database_dir) {
   const leveldb::Status s =
-      leveldb::DestroyDB(database_dir.AsUTF8Unsafe(), leveldb::Options());
+      leveldb::DestroyDB(database_dir.AsUTF8Unsafe(), leveldb_env::Options());
   return s.ok();
 }
 
@@ -57,7 +57,7 @@
 }
 
 bool LevelDB::InitWithOptions(const base::FilePath& database_dir,
-                              const leveldb::Options& options) {
+                              const leveldb_env::Options& options) {
   DFAKE_SCOPED_LOCK(thread_checker_);
 
   std::string path = database_dir.AsUTF8Unsafe();
@@ -91,10 +91,9 @@
 }
 
 bool LevelDB::Init(const leveldb_proto::Options& options) {
-  leveldb::Options leveldb_options;
+  leveldb_env::Options leveldb_options;
   leveldb_options.create_if_missing = true;
   leveldb_options.max_open_files = 0;  // Use minimum.
-  leveldb_options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
 
   static leveldb::Cache* default_block_cache =
       leveldb::NewLRUCache(DefaultBlockCacheSize());
diff --git a/components/leveldb_proto/leveldb_database.h b/components/leveldb_proto/leveldb_database.h
index 562e6a5..78b03571 100644
--- a/components/leveldb_proto/leveldb_database.h
+++ b/components/leveldb_proto/leveldb_database.h
@@ -15,6 +15,7 @@
 #include "base/threading/thread_collision_warner.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "components/leveldb_proto/options.h"
+#include "third_party/leveldatabase/env_chromium.h"
 
 namespace base {
 class FilePath;
@@ -60,7 +61,7 @@
 
  protected:
   virtual bool InitWithOptions(const base::FilePath& database_dir,
-                               const leveldb::Options& options);
+                               const leveldb_env::Options& options);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(ProtoDatabaseImplLevelDBTest, TestDBInitFail);
diff --git a/components/leveldb_proto/proto_database_impl_unittest.cc b/components/leveldb_proto/proto_database_impl_unittest.cc
index 691d774..6e1bea1 100644
--- a/components/leveldb_proto/proto_database_impl_unittest.cc
+++ b/components/leveldb_proto/proto_database_impl_unittest.cc
@@ -24,6 +24,7 @@
 #include "components/leveldb_proto/testing/proto/test.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/include/leveldb/options.h"
 
 using base::MessageLoop;
@@ -596,7 +597,7 @@
   ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = false;
   std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
 
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index ad2f57a..09b2698 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -92,10 +92,14 @@
 
   background_task_ = std::move(background_task);
 
-  // TODO(dimich): add QueueReconcilers() here when at least one is implemented.
+  QueueReconcileTasks();
   QueueActionTasks();
 }
 
+void PrefetchDispatcherImpl::QueueReconcileTasks() {
+  // TODO(dimich): add Reconcile tasks here.
+}
+
 void PrefetchDispatcherImpl::QueueActionTasks() {
   std::unique_ptr<Task> get_operation_task = base::MakeUnique<GetOperationTask>(
       service_->GetPrefetchStore(),
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
index 0404fa0..57b256b0 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
@@ -63,9 +63,18 @@
                         const std::string& operation_name,
                         const std::vector<RenderPageInfo>& pages);
 
-  // Adds the Action tasks to the queue. See PrefetchDispatcher interface
-  // declaration for Action tasks definition.
-  void QueueActionTasks();
+   // Adds the Reconcile tasks to the TaskQueue. These look for error/stuck
+   // processing conditions that happen as result of Chrome being evicted
+   // or network failures of certain kind. They are run on periodic wakeup
+   // (BeginBackgroundTask()). See PrefetchDispatcher interface
+   // declaration for Reconcile tasks definition.
+   void QueueReconcileTasks();
+   // Adds the Action tasks to the queue. See PrefetchDispatcher interface
+   // declaration for Action tasks definition.
+   // Action tasks can be added to the queue either in response to periodic
+   // wakeup (when BeginBackgroundTask() is called) or any time TaskQueue is
+   // becomes idle and any task called SchedulePipelineProcessing() before.
+   void QueueActionTasks();
 
   PrefetchService* service_;
   TaskQueue task_queue_;
diff --git a/components/omnibox/OWNERS b/components/omnibox/OWNERS
index 509133c2..8e9f2fec 100644
--- a/components/omnibox/OWNERS
+++ b/components/omnibox/OWNERS
@@ -1,6 +1,7 @@
 jdonnelly@chromium.org
 mpearson@chromium.org
 pkasting@chromium.org
+tommycli@chromium.org
 
 per-file clipboard_url_provider.*=jif@chromium.org
 
diff --git a/components/rlz/rlz_tracker.cc b/components/rlz/rlz_tracker.cc
index 4efb733..3b57da1c 100644
--- a/components/rlz/rlz_tracker.cc
+++ b/components/rlz/rlz_tracker.cc
@@ -170,7 +170,7 @@
       app_list_used_(false),
       min_init_delay_(kMinInitDelay),
       background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
-          {base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
+          {base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN, base::MayBlock(),
            base::WithBaseSyncPrimitives(), base::TaskPriority::BACKGROUND})) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
diff --git a/components/security_interstitials/core/bad_clock_ui.cc b/components/security_interstitials/core/bad_clock_ui.cc
index dafdd14..0bbd451 100644
--- a/components/security_interstitials/core/bad_clock_ui.cc
+++ b/components/security_interstitials/core/bad_clock_ui.cc
@@ -105,10 +105,10 @@
       controller_->LaunchDateAndTimeSettings();
       break;
     case CMD_OPEN_REPORTING_PRIVACY:
-      controller_->OpenExtendedReportingPrivacyPolicy();
+      controller_->OpenExtendedReportingPrivacyPolicy(true);
       break;
     case CMD_OPEN_WHITEPAPER:
-      controller_->OpenExtendedReportingWhitepaper();
+      controller_->OpenExtendedReportingWhitepaper(true);
       break;
     case CMD_PROCEED:
     case CMD_OPEN_HELP_CENTER:
diff --git a/components/security_interstitials/core/controller_client.cc b/components/security_interstitials/core/controller_client.cc
index e146d72..09fa690c 100644
--- a/components/security_interstitials/core/controller_client.cc
+++ b/components/security_interstitials/core/controller_client.cc
@@ -42,20 +42,30 @@
              : MetricsHelper::SET_EXTENDED_REPORTING_DISABLED);
 }
 
-void ControllerClient::OpenExtendedReportingPrivacyPolicy() {
+void ControllerClient::OpenExtendedReportingPrivacyPolicy(
+    bool open_links_in_new_tab) {
   metrics_helper_->RecordUserInteraction(MetricsHelper::SHOW_PRIVACY_POLICY);
   GURL privacy_url(kSafeBrowsingPrivacyPolicyUrl);
   privacy_url =
       google_util::AppendGoogleLocaleParam(privacy_url, GetApplicationLocale());
-  OpenUrlInNewForegroundTab(privacy_url);
+  OpenURL(open_links_in_new_tab, privacy_url);
 }
 
-void ControllerClient::OpenExtendedReportingWhitepaper() {
+void ControllerClient::OpenExtendedReportingWhitepaper(
+    bool open_links_in_new_tab) {
   metrics_helper_->RecordUserInteraction(MetricsHelper::SHOW_WHITEPAPER);
   GURL whitepaper_url(kSafeBrowsingWhitePaperUrl);
   whitepaper_url = google_util::AppendGoogleLocaleParam(whitepaper_url,
                                                         GetApplicationLocale());
-  OpenUrlInNewForegroundTab(whitepaper_url);
+  OpenURL(open_links_in_new_tab, whitepaper_url);
+}
+
+void ControllerClient::OpenURL(bool open_links_in_new_tab, const GURL& url) {
+  if (open_links_in_new_tab) {
+    OpenUrlInNewForegroundTab(url);
+  } else {
+    OpenUrlInCurrentTab(url);
+  }
 }
 
 GURL ControllerClient::GetBaseHelpCenterUrl() const {
diff --git a/components/security_interstitials/core/controller_client.h b/components/security_interstitials/core/controller_client.h
index ea3e214..c9a0daa 100644
--- a/components/security_interstitials/core/controller_client.h
+++ b/components/security_interstitials/core/controller_client.h
@@ -61,8 +61,13 @@
 
   // Handle the user's reporting preferences.
   void SetReportingPreference(bool report);
-  void OpenExtendedReportingPrivacyPolicy();
-  void OpenExtendedReportingWhitepaper();
+
+  void OpenExtendedReportingPrivacyPolicy(bool open_links_in_new_tab);
+  void OpenExtendedReportingWhitepaper(bool open_links_in_new_tab);
+
+  // Helper method which either opens a URL in a new tab or a the current tab
+  // based on the display options setting.
+  void OpenURL(bool open_links_in_new_tab, const GURL& url);
 
   // If available, open the operating system's date/time settings.
   virtual bool CanLaunchDateAndTimeSettings() = 0;
diff --git a/components/security_interstitials/core/safe_browsing_loud_error_ui.cc b/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
index 85a5dfa..f34abee 100644
--- a/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
+++ b/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
@@ -169,7 +169,7 @@
           learn_more_url, "p", get_help_center_article_link());
       learn_more_url =
           google_util::AppendGoogleLocaleParam(learn_more_url, app_locale());
-      OpenURL(learn_more_url);
+      controller()->OpenURL(should_open_links_in_new_tab(), learn_more_url);
       break;
     }
     case CMD_RELOAD: {
@@ -180,11 +180,13 @@
     }
     case CMD_OPEN_REPORTING_PRIVACY: {
       // User pressed on the SB Extended Reporting "privacy policy" link.
-      controller()->OpenExtendedReportingPrivacyPolicy();
+      controller()->OpenExtendedReportingPrivacyPolicy(
+          should_open_links_in_new_tab());
       break;
     }
     case CMD_OPEN_WHITEPAPER: {
-      controller()->OpenExtendedReportingWhitepaper();
+      controller()->OpenExtendedReportingWhitepaper(
+          should_open_links_in_new_tab());
       break;
     }
     case CMD_OPEN_DIAGNOSTIC: {
@@ -196,7 +198,7 @@
       GURL diagnostic_url(diagnostic);
       diagnostic_url =
           google_util::AppendGoogleLocaleParam(diagnostic_url, app_locale());
-      OpenURL(diagnostic_url);
+      controller()->OpenURL(should_open_links_in_new_tab(), diagnostic_url);
       break;
     }
     case CMD_REPORT_PHISHING_ERROR: {
@@ -205,7 +207,7 @@
       GURL phishing_error_url(kReportPhishingErrorUrl);
       phishing_error_url = google_util::AppendGoogleLocaleParam(
           phishing_error_url, app_locale());
-      OpenURL(phishing_error_url);
+      controller()->OpenURL(should_open_links_in_new_tab(), phishing_error_url);
       break;
     }
     case CMD_OPEN_DATE_SETTINGS:
@@ -305,14 +307,6 @@
                              is_extended_reporting_enabled());
 }
 
-void SafeBrowsingLoudErrorUI::OpenURL(const GURL& url) {
-  if (should_open_links_in_new_tab()) {
-    controller()->OpenUrlInNewForegroundTab(url);
-  } else {
-    controller()->OpenUrlInCurrentTab(url);
-  }
-}
-
 int SafeBrowsingLoudErrorUI::GetHTMLTemplateId() const {
   return IDR_SECURITY_INTERSTITIAL_HTML;
 };
diff --git a/components/security_interstitials/core/safe_browsing_loud_error_ui.h b/components/security_interstitials/core/safe_browsing_loud_error_ui.h
index 4f1c1bd7..d5a1e6a 100644
--- a/components/security_interstitials/core/safe_browsing_loud_error_ui.h
+++ b/components/security_interstitials/core/safe_browsing_loud_error_ui.h
@@ -48,10 +48,6 @@
   void PopulateHarmfulLoadTimeData(base::DictionaryValue* load_time_data);
   void PopulatePhishingLoadTimeData(base::DictionaryValue* load_time_data);
 
-  // Helper method which either opens a URL in a new tab or a the current tab
-  // based on the display options setting.
-  void OpenURL(const GURL& url);
-
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingLoudErrorUI);
 };
 
diff --git a/components/security_interstitials/core/ssl_error_ui.cc b/components/security_interstitials/core/ssl_error_ui.cc
index d4f74ae..90734a0 100644
--- a/components/security_interstitials/core/ssl_error_ui.cc
+++ b/components/security_interstitials/core/ssl_error_ui.cc
@@ -199,10 +199,10 @@
       controller_->Reload();
       break;
     case CMD_OPEN_REPORTING_PRIVACY:
-      controller_->OpenExtendedReportingPrivacyPolicy();
+      controller_->OpenExtendedReportingPrivacyPolicy(true);
       break;
     case CMD_OPEN_WHITEPAPER:
-      controller_->OpenExtendedReportingWhitepaper();
+      controller_->OpenExtendedReportingWhitepaper(true);
       break;
     case CMD_OPEN_DATE_SETTINGS:
     case CMD_OPEN_DIAGNOSTIC:
diff --git a/components/sync/engine/attachments/on_disk_attachment_store.cc b/components/sync/engine/attachments/on_disk_attachment_store.cc
index 15a83a25..6554e4b 100644
--- a/components/sync/engine/attachments/on_disk_attachment_store.cc
+++ b/components/sync/engine/attachments/on_disk_attachment_store.cc
@@ -360,9 +360,8 @@
   base::FilePath leveldb_path = path.Append(kLeveldbDirectory);
 
   std::unique_ptr<leveldb::DB> db;
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = true;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   // TODO(pavely): crbug/424287 Consider adding info_log, block_cache and
   // filter_policy to options.
   leveldb::Status status =
diff --git a/components/sync/engine/attachments/on_disk_attachment_store_unittest.cc b/components/sync/engine/attachments/on_disk_attachment_store_unittest.cc
index 3554c4e..e6c94995 100644
--- a/components/sync/engine/attachments/on_disk_attachment_store_unittest.cc
+++ b/components/sync/engine/attachments/on_disk_attachment_store_unittest.cc
@@ -105,7 +105,7 @@
 
   std::unique_ptr<leveldb::DB> OpenLevelDB() {
     std::unique_ptr<leveldb::DB> db;
-    leveldb::Options options;
+    leveldb_env::Options options;
     options.create_if_missing = true;
     leveldb::Status s =
         leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db);
diff --git a/components/sync/model_impl/model_type_store_backend.cc b/components/sync/model_impl/model_type_store_backend.cc
index 45ff1bc..4c0fedc 100644
--- a/components/sync/model_impl/model_type_store_backend.cc
+++ b/components/sync/model_impl/model_type_store_backend.cc
@@ -178,9 +178,8 @@
 
 leveldb::Status ModelTypeStoreBackend::OpenDatabase(const std::string& path,
                                                     leveldb::Env* env) {
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = true;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   options.paranoid_checks = true;
   if (env)
     options.env = env;
@@ -190,7 +189,7 @@
 
 leveldb::Status ModelTypeStoreBackend::DestroyDatabase(const std::string& path,
                                                        leveldb::Env* env) {
-  leveldb::Options options;
+  leveldb_env::Options options;
   if (env)
     options.env = env;
   return leveldb::DestroyDB(path, options);
diff --git a/components/sync/model_impl/model_type_store_backend_unittest.cc b/components/sync/model_impl/model_type_store_backend_unittest.cc
index 183c71f..e9be2573 100644
--- a/components/sync/model_impl/model_type_store_backend_unittest.cc
+++ b/components/sync/model_impl/model_type_store_backend_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/test/histogram_tester.h"
 #include "components/sync/protocol/model_type_store_schema_descriptor.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/env.h"
 #include "third_party/leveldatabase/src/include/leveldb/options.h"
@@ -295,7 +296,7 @@
 
   // Cleanup directory after the test.
   backend = nullptr;
-  s = leveldb::DestroyDB(path, leveldb::Options());
+  s = leveldb::DestroyDB(path, leveldb_env::Options());
   EXPECT_TRUE(s.ok()) << s.ToString();
 
   // Check that both recovery and consecutive initialization are recorded in
diff --git a/components/url_formatter/OWNERS b/components/url_formatter/OWNERS
index 907aaa2..3336b55a 100644
--- a/components/url_formatter/OWNERS
+++ b/components/url_formatter/OWNERS
@@ -1,4 +1,5 @@
 pkasting@chromium.org
+tommycli@chromium.org
 
 # Backup reviewer
 brettw@chromium.org
diff --git a/content/browser/android/dialog_overlay_impl.cc b/content/browser/android/dialog_overlay_impl.cc
index d3d63d8..29271e2 100644
--- a/content/browser/android/dialog_overlay_impl.cc
+++ b/content/browser/android/dialog_overlay_impl.cc
@@ -36,6 +36,10 @@
   if (!rfhi->IsCurrent() || web_contents_impl->IsHidden())
     return 0;
 
+  // Dialog-based overlays are not supported for persistent video.
+  if (web_contents_impl->HasPersistentVideo())
+    return 0;
+
   ContentViewCore* cvc = ContentViewCore::FromWebContents(web_contents_impl);
 
   if (!cvc)
diff --git a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
index 9bd47a3..1059a0fa 100644
--- a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
@@ -977,7 +977,7 @@
     // Mess up version number in database.
     leveldb_env::ChromiumEnv env;
     std::unique_ptr<leveldb::DB> db;
-    leveldb::Options options;
+    leveldb_env::Options options;
     options.env = &env;
     base::FilePath db_path =
         temp_path().Append(test_path).Append(FILE_PATH_LITERAL("leveldb"));
diff --git a/content/browser/dom_storage/session_storage_database.cc b/content/browser/dom_storage/session_storage_database.cc
index 2e3d8f7..6a42f037 100644
--- a/content/browser/dom_storage/session_storage_database.cc
+++ b/content/browser/dom_storage/session_storage_database.cc
@@ -89,7 +89,7 @@
       // No other operations are ongoing and the data is bad -> delete it now.
       session_storage_database_->db_.reset();
       leveldb::DestroyDB(session_storage_database_->file_path_.AsUTF8Unsafe(),
-                         leveldb::Options());
+                         leveldb_env::Options());
       session_storage_database_->invalid_db_deleted_ = true;
     }
   }
@@ -432,13 +432,12 @@
 
 leveldb::Status SessionStorageDatabase::TryToOpen(
     std::unique_ptr<leveldb::DB>* db) {
-  leveldb::Options options;
+  leveldb_env::Options options;
   // The directory exists but a valid leveldb database might not exist inside it
   // (e.g., a subset of the needed files might be missing). Handle this
   // situation gracefully by creating the database now.
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = true;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   // Default write_buffer_size is 4 MB but that might leave a 3.999
   // memory allocation in RAM from a log file recovery.
   options.write_buffer_size = 64 * 1024;
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index c4682bd5..c2f3a0ec 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/frame_host/frame_tree_node.h"
 
+#include <math.h>
+
 #include <queue>
 #include <utility>
 
@@ -13,6 +15,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/stl_util.h"
+#include "base/strings/string_util.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/frame_host/navigator.h"
@@ -42,8 +45,44 @@
 const double kLoadingProgressMinimum = 0.1;
 const double kLoadingProgressDone = 1.0;
 
-void RecordUniqueNameLength(size_t length) {
-  UMA_HISTOGRAM_COUNTS("SessionRestore.FrameUniqueNameLength", length);
+void RecordUniqueNameSize(FrameTreeNode* node) {
+  const auto& unique_name = node->current_replication_state().unique_name;
+
+  // Don't record numbers for the root node, which always has an empty unique
+  // name.
+  if (!node->parent()) {
+    DCHECK(unique_name.empty());
+    return;
+  }
+
+  // The original requested name is derived from the browsing context name and
+  // is essentially unbounded in size...
+  UMA_HISTOGRAM_COUNTS_1M(
+      "SessionRestore.FrameUniqueNameOriginalRequestedNameSize",
+      node->current_replication_state().name.size());
+  // If the name is a frame path, attempt to normalize the statistics based on
+  // the number of frames in the frame path.
+  if (base::StartsWith(unique_name, "<!--framePath //",
+                       base::CompareCase::SENSITIVE)) {
+    size_t depth = 1;
+    while (node->parent()) {
+      ++depth;
+      node = node->parent();
+    }
+    // The max possible size of a unique name is 80 characters, so the expected
+    // size per component shouldn't be much more than that.
+    UMA_HISTOGRAM_COUNTS_100(
+        "SessionRestore.FrameUniqueNameWithFramePathSizePerComponent",
+        round(unique_name.size() / static_cast<float>(depth)));
+    // Blink allows a maximum of ~1024 subframes in a document, so this should
+    // be less than (80 character name + 1 character delimiter) * 1024.
+    UMA_HISTOGRAM_COUNTS_100000(
+        "SessionRestore.FrameUniqueNameWithFramePathSize", unique_name.size());
+  } else {
+    UMA_HISTOGRAM_COUNTS_100(
+        "SessionRestore.FrameUniqueNameFromRequestedNameSize",
+        unique_name.size());
+  }
 }
 
 }  // namespace
@@ -124,7 +163,7 @@
           std::make_pair(frame_tree_node_id_, this));
   CHECK(result.second);
 
-  RecordUniqueNameLength(unique_name.size());
+  RecordUniqueNameSize(this);
 
   // Note: this should always be done last in the constructor.
   blame_context_.Initialize();
@@ -286,7 +325,10 @@
     DCHECK(unique_name.empty());
   }
 
-  RecordUniqueNameLength(unique_name.size());
+  // Note the unique name should only be able to change before the first real
+  // load is committed, but that's not strongly enforced here.
+  if (unique_name != replication_state_.unique_name)
+    RecordUniqueNameSize(this);
   render_manager_.OnDidUpdateName(name, unique_name);
   replication_state_.name = name;
   replication_state_.unique_name = unique_name;
diff --git a/content/browser/indexed_db/leveldb/leveldb_database.cc b/content/browser/indexed_db/leveldb/leveldb_database.cc
index bc05c95d..58218d6 100644
--- a/content/browser/indexed_db/leveldb/leveldb_database.cc
+++ b/content/browser/indexed_db/leveldb/leveldb_database.cc
@@ -118,12 +118,11 @@
     std::unique_ptr<leveldb::DB>* db,
     std::unique_ptr<const leveldb::FilterPolicy>* filter_policy) {
   filter_policy->reset(leveldb::NewBloomFilterPolicy(10));
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.comparator = comparator;
   options.create_if_missing = true;
   options.paranoid_checks = true;
   options.filter_policy = filter_policy->get();
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   options.compression = leveldb::kSnappyCompression;
   options.write_buffer_size =
       leveldb_env::WriteBufferSize(base::SysInfo::AmountOfTotalDiskSpace(path));
@@ -288,7 +287,7 @@
 
 // static
 leveldb::Status LevelDBDatabase::Destroy(const base::FilePath& file_name) {
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.env = LevelDBEnv::Get();
   // ChromiumEnv assumes UTF8, converts back to FilePath before using.
   return leveldb::DestroyDB(file_name.AsUTF8Unsafe(), options);
diff --git a/content/browser/media/media_browsertest.cc b/content/browser/media/media_browsertest.cc
index 239bfb2..1345092 100644
--- a/content/browser/media/media_browsertest.cc
+++ b/content/browser/media/media_browsertest.cc
@@ -241,6 +241,15 @@
 IN_PROC_BROWSER_TEST_F(MediaTest, VideoBearRotated270) {
   RunVideoSizeTest("bear_rotate_270.mp4", 720, 1280);
 }
+
+// Android can't reliably load lots of videos on a page.
+// See http://crbug.com/749265
+#if !defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(MediaTest, LoadManyVideos) {
+  base::StringPairs query_params;
+  RunMediaTestPage("load_many_videos.html", query_params, kEnded, true);
+}
+#endif  // !defined(OS_ANDROID)
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
 #if defined(OS_CHROMEOS)
diff --git a/content/browser/notifications/notification_database.cc b/content/browser/notifications/notification_database.cc
index 9b00a53..ced1d2191 100644
--- a/content/browser/notifications/notification_database.cc
+++ b/content/browser/notifications/notification_database.cc
@@ -122,10 +122,9 @@
 
   filter_policy_.reset(leveldb::NewBloomFilterPolicy(10));
 
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = create_if_missing;
   options.paranoid_checks = true;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   options.filter_policy = filter_policy_.get();
   if (IsInMemoryDatabase()) {
     env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
@@ -256,7 +255,7 @@
 NotificationDatabase::Status NotificationDatabase::Destroy() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
-  leveldb::Options options;
+  leveldb_env::Options options;
   if (IsInMemoryDatabase()) {
     if (!env_)
       return STATUS_OK;  // The database has not been initialized.
diff --git a/content/browser/payments/payment_app_browsertest.cc b/content/browser/payments/payment_app_browsertest.cc
index 3f1f9c6..8765aa27 100644
--- a/content/browser/payments/payment_app_browsertest.cc
+++ b/content/browser/payments/payment_app_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "content/browser/storage_partition_impl.h"
+#include "content/common/service_worker/service_worker_types.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/payment_app_provider.h"
 #include "content/public/browser/web_contents.h"
@@ -39,10 +40,10 @@
   done_callback.Run();
 }
 
-void CanMakePaymentCallback(const base::Closure& done_callback,
-                            bool* out_can_make_payment,
-                            bool can_make_payment) {
-  *out_can_make_payment = can_make_payment;
+void PaymentEventResultCallback(const base::Closure& done_callback,
+                                bool* out_payment_event_result,
+                                bool payment_event_result) {
+  *out_payment_event_result = payment_event_result;
   done_callback.Run();
 }
 
@@ -110,17 +111,29 @@
     return registrationIds;
   }
 
+  bool AbortPayment(int64_t registration_id) {
+    base::RunLoop run_loop;
+    bool payment_aborted = false;
+    PaymentAppProvider::GetInstance()->AbortPayment(
+        shell()->web_contents()->GetBrowserContext(), registration_id,
+        base::Bind(&PaymentEventResultCallback, run_loop.QuitClosure(),
+                   &payment_aborted));
+    run_loop.Run();
+
+    return payment_aborted;
+  }
+
   bool CanMakePaymentWithTestData(int64_t registration_id,
                                   const std::string& supported_method) {
     CanMakePaymentEventDataPtr event_data =
         CreateCanMakePaymentEventData(supported_method);
 
     base::RunLoop run_loop;
-    bool can_make_payment;
+    bool can_make_payment = false;
     PaymentAppProvider::GetInstance()->CanMakePayment(
         shell()->web_contents()->GetBrowserContext(), registration_id,
         std::move(event_data),
-        base::Bind(&CanMakePaymentCallback, run_loop.QuitClosure(),
+        base::Bind(&PaymentEventResultCallback, run_loop.QuitClosure(),
                    &can_make_payment));
     run_loop.Run();
 
@@ -220,6 +233,31 @@
   DISALLOW_COPY_AND_ASSIGN(PaymentAppBrowserTest);
 };
 
+IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest,
+                       AbortPaymentWithInvalidRegistrationId) {
+  RegisterPaymentApp();
+
+  std::vector<int64_t> registrationIds = GetAllPaymentAppRegistrationIDs();
+  ASSERT_EQ(1U, registrationIds.size());
+
+  bool payment_aborted = AbortPayment(kInvalidServiceWorkerRegistrationId);
+  ASSERT_FALSE(payment_aborted);
+
+  ClearStoragePartitionData();
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, AbortPayment) {
+  RegisterPaymentApp();
+
+  std::vector<int64_t> registrationIds = GetAllPaymentAppRegistrationIDs();
+  ASSERT_EQ(1U, registrationIds.size());
+
+  bool payment_aborted = AbortPayment(registrationIds[0]);
+  ASSERT_TRUE(payment_aborted);
+
+  ClearStoragePartitionData();
+}
+
 IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, CanMakePayment) {
   RegisterPaymentApp();
 
diff --git a/content/browser/payments/payment_app_content_unittest_base.cc b/content/browser/payments/payment_app_content_unittest_base.cc
index 91c943b..e28ae7c 100644
--- a/content/browser/payments/payment_app_content_unittest_base.cc
+++ b/content/browser/payments/payment_app_content_unittest_base.cc
@@ -97,6 +97,14 @@
         std::move(callback));
   }
 
+  void OnAbortPaymentEvent(
+      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      mojom::ServiceWorkerEventDispatcher::DispatchCanMakePaymentEventCallback
+          callback) override {
+    EmbeddedWorkerTestHelper::OnAbortPaymentEvent(std::move(response_callback),
+                                                  std::move(callback));
+  }
+
   int64_t last_sw_registration_id_;
   GURL last_sw_scope_;
 
diff --git a/content/browser/payments/payment_app_provider_impl.cc b/content/browser/payments/payment_app_provider_impl.cc
index 9b49dfac..172fa4e 100644
--- a/content/browser/payments/payment_app_provider_impl.cc
+++ b/content/browser/payments/payment_app_provider_impl.cc
@@ -43,9 +43,9 @@
   RespondWithCallbacks(
       ServiceWorkerMetrics::EventType event_type,
       scoped_refptr<ServiceWorkerVersion> service_worker_version,
-      PaymentAppProvider::CanMakePaymentCallback callback)
+      PaymentAppProvider::PaymentEventResultCallback callback)
       : service_worker_version_(service_worker_version),
-        can_make_payment_callback_(std::move(callback)),
+        payment_event_result_callback_(std::move(callback)),
         binding_(this),
         weak_ptr_factory_(this) {
     request_id_ = service_worker_version->StartRequest(
@@ -80,11 +80,23 @@
                                            std::move(dispatch_event_time));
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
-        base::BindOnce(std::move(can_make_payment_callback_),
+        base::BindOnce(std::move(payment_event_result_callback_),
                        can_make_payment));
     delete this;
   }
 
+  void OnResponseForAbortPayment(bool payment_aborted,
+                                 base::Time dispatch_event_time) override {
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    service_worker_version_->FinishRequest(request_id_, false,
+                                           std::move(dispatch_event_time));
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(std::move(payment_event_result_callback_),
+                       payment_aborted));
+    delete this;
+  }
+
   void OnErrorStatus(ServiceWorkerStatusCode service_worker_status) {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
     DCHECK(service_worker_status != SERVICE_WORKER_OK);
@@ -95,12 +107,12 @@
           base::BindOnce(std::move(invoke_payment_app_callback_),
                          payments::mojom::PaymentHandlerResponse::New()));
     } else if (event_type_ ==
-               ServiceWorkerMetrics::EventType::CAN_MAKE_PAYMENT) {
+                   ServiceWorkerMetrics::EventType::CAN_MAKE_PAYMENT ||
+               event_type_ == ServiceWorkerMetrics::EventType::ABORT_PAYMENT) {
       BrowserThread::PostTask(
           BrowserThread::UI, FROM_HERE,
-          base::BindOnce(std::move(can_make_payment_callback_), false));
+          base::BindOnce(std::move(payment_event_result_callback_), false));
     }
-
     delete this;
   }
 
@@ -113,7 +125,7 @@
   ServiceWorkerMetrics::EventType event_type_;
   scoped_refptr<ServiceWorkerVersion> service_worker_version_;
   PaymentAppProvider::InvokePaymentAppCallback invoke_payment_app_callback_;
-  PaymentAppProvider::CanMakePaymentCallback can_make_payment_callback_;
+  PaymentAppProvider::PaymentEventResultCallback payment_event_result_callback_;
   mojo::Binding<payments::mojom::PaymentHandlerResponseCallback> binding_;
 
   base::WeakPtrFactory<RespondWithCallbacks> weak_ptr_factory_;
@@ -138,9 +150,37 @@
       base::BindOnce(&DidGetAllPaymentAppsOnIO, std::move(callback)));
 }
 
+void DispatchAbortPaymentEvent(
+    PaymentAppProvider::PaymentEventResultCallback callback,
+    scoped_refptr<ServiceWorkerVersion> active_version,
+    ServiceWorkerStatusCode service_worker_status) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  if (service_worker_status != SERVICE_WORKER_OK) {
+    std::move(callback).Run(false);
+    return;
+  }
+
+  DCHECK(active_version);
+
+  int event_finish_id = active_version->StartRequest(
+      ServiceWorkerMetrics::EventType::CAN_MAKE_PAYMENT,
+      base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+
+  // This object self-deletes after either success or error callback is invoked.
+  RespondWithCallbacks* invocation_callbacks =
+      new RespondWithCallbacks(ServiceWorkerMetrics::EventType::ABORT_PAYMENT,
+                               active_version, std::move(callback));
+
+  active_version->event_dispatcher()->DispatchAbortPaymentEvent(
+      invocation_callbacks->request_id(),
+      invocation_callbacks->CreateInterfacePtrAndBind(),
+      active_version->CreateSimpleEventCallback(event_finish_id));
+}
+
 void DispatchCanMakePaymentEvent(
     payments::mojom::CanMakePaymentEventDataPtr event_data,
-    PaymentAppProvider::CanMakePaymentCallback callback,
+    PaymentAppProvider::PaymentEventResultCallback callback,
     scoped_refptr<ServiceWorkerVersion> active_version,
     ServiceWorkerStatusCode service_worker_status) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -297,7 +337,7 @@
     BrowserContext* browser_context,
     int64_t registration_id,
     payments::mojom::CanMakePaymentEventDataPtr event_data,
-    CanMakePaymentCallback callback) {
+    PaymentEventResultCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   StartServiceWorkerForDispatch(
@@ -307,6 +347,17 @@
                      std::move(callback)));
 }
 
+void PaymentAppProviderImpl::AbortPayment(BrowserContext* browser_context,
+                                          int64_t registration_id,
+                                          PaymentEventResultCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  StartServiceWorkerForDispatch(
+      ServiceWorkerMetrics::EventType::ABORT_PAYMENT, browser_context,
+      registration_id,
+      base::BindOnce(&DispatchAbortPaymentEvent, std::move(callback)));
+}
+
 PaymentAppProviderImpl::PaymentAppProviderImpl() {}
 
 PaymentAppProviderImpl::~PaymentAppProviderImpl() {}
diff --git a/content/browser/payments/payment_app_provider_impl.h b/content/browser/payments/payment_app_provider_impl.h
index 04110d1e..52a7ddd 100644
--- a/content/browser/payments/payment_app_provider_impl.h
+++ b/content/browser/payments/payment_app_provider_impl.h
@@ -27,7 +27,10 @@
   void CanMakePayment(BrowserContext* browser_context,
                       int64_t registration_id,
                       payments::mojom::CanMakePaymentEventDataPtr event_data,
-                      CanMakePaymentCallback callback) override;
+                      PaymentEventResultCallback callback) override;
+  void AbortPayment(BrowserContext* browser_context,
+                    int64_t registration_id,
+                    PaymentEventResultCallback callback) override;
 
  private:
   PaymentAppProviderImpl();
diff --git a/content/browser/payments/payment_app_provider_impl_unittest.cc b/content/browser/payments/payment_app_provider_impl_unittest.cc
index 92b451f5..7472f79 100644
--- a/content/browser/payments/payment_app_provider_impl_unittest.cc
+++ b/content/browser/payments/payment_app_provider_impl_unittest.cc
@@ -40,8 +40,9 @@
   *called = true;
 }
 
-void CanMakePaymentCallback(bool* out_can_make_payment, bool can_make_payment) {
-  *out_can_make_payment = can_make_payment;
+void PaymentEventResultCallback(bool* out_payment_event_result,
+                                bool payment_event_result) {
+  *out_payment_event_result = payment_event_result;
 }
 
 }  // namespace
@@ -80,17 +81,43 @@
 
   void CanMakePayment(int64_t registration_id,
                       payments::mojom::CanMakePaymentEventDataPtr event_data,
-                      PaymentAppProvider::CanMakePaymentCallback callback) {
+                      PaymentAppProvider::PaymentEventResultCallback callback) {
     PaymentAppProviderImpl::GetInstance()->CanMakePayment(
         browser_context(), registration_id, std::move(event_data),
         std::move(callback));
     base::RunLoop().RunUntilIdle();
   }
 
+  void AbortPayment(int64_t registration_id,
+                    PaymentAppProvider::PaymentEventResultCallback callback) {
+    PaymentAppProviderImpl::GetInstance()->AbortPayment(
+        browser_context(), registration_id, std::move(callback));
+    base::RunLoop().RunUntilIdle();
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(PaymentAppProviderTest);
 };
 
+TEST_F(PaymentAppProviderTest, AbortPaymentTest) {
+  PaymentManager* manager = CreatePaymentManager(
+      GURL("https://example.com"), GURL("https://example.com/script.js"));
+
+  PaymentHandlerStatus status;
+  SetPaymentInstrument(manager, "payment_instrument_key",
+                       payments::mojom::PaymentInstrument::New(),
+                       base::Bind(&SetPaymentInstrumentCallback, &status));
+
+  PaymentAppProvider::PaymentApps apps;
+  GetAllPaymentApps(base::Bind(&GetAllPaymentAppsCallback, &apps));
+  ASSERT_EQ(1U, apps.size());
+
+  bool payment_aborted = false;
+  AbortPayment(last_sw_registration_id(),
+               base::BindOnce(&PaymentEventResultCallback, &payment_aborted));
+  ASSERT_TRUE(payment_aborted);
+}
+
 TEST_F(PaymentAppProviderTest, CanMakePaymentTest) {
   PaymentManager* manager = CreatePaymentManager(
       GURL("https://example.com"), GURL("https://example.com/script.js"));
@@ -112,8 +139,9 @@
   event_data->method_data.push_back(std::move(methodData));
 
   bool can_make_payment = false;
-  CanMakePayment(last_sw_registration_id(), std::move(event_data),
-                 base::BindOnce(&CanMakePaymentCallback, &can_make_payment));
+  CanMakePayment(
+      last_sw_registration_id(), std::move(event_data),
+      base::BindOnce(&PaymentEventResultCallback, &can_make_payment));
   ASSERT_TRUE(can_make_payment);
 }
 
diff --git a/content/browser/service_worker/browser_side_service_worker_event_dispatcher.cc b/content/browser/service_worker/browser_side_service_worker_event_dispatcher.cc
index 1f202c4..acf3b16 100644
--- a/content/browser/service_worker/browser_side_service_worker_event_dispatcher.cc
+++ b/content/browser/service_worker/browser_side_service_worker_event_dispatcher.cc
@@ -108,6 +108,13 @@
   NOTREACHED();
 }
 
+void BrowserSideServiceWorkerEventDispatcher::DispatchAbortPaymentEvent(
+    int payment_request_id,
+    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+    DispatchAbortPaymentEventCallback callback) {
+  NOTREACHED();
+}
+
 void BrowserSideServiceWorkerEventDispatcher::DispatchCanMakePaymentEvent(
     int payment_request_id,
     payments::mojom::CanMakePaymentEventDataPtr event_data,
diff --git a/content/browser/service_worker/browser_side_service_worker_event_dispatcher.h b/content/browser/service_worker/browser_side_service_worker_event_dispatcher.h
index c1067fb..23939172 100644
--- a/content/browser/service_worker/browser_side_service_worker_event_dispatcher.h
+++ b/content/browser/service_worker/browser_side_service_worker_event_dispatcher.h
@@ -83,6 +83,10 @@
       const std::string& tag,
       blink::mojom::BackgroundSyncEventLastChance last_chance,
       DispatchSyncEventCallback callback) override;
+  void DispatchAbortPaymentEvent(
+      int payment_request_id,
+      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      DispatchAbortPaymentEventCallback callback) override;
   void DispatchCanMakePaymentEvent(
       int payment_request_id,
       payments::mojom::CanMakePaymentEventDataPtr event_data,
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 1591ff2..9591747d 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -257,6 +257,16 @@
     NOTIMPLEMENTED();
   }
 
+  void DispatchAbortPaymentEvent(
+      int payment_request_id,
+      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      DispatchAbortPaymentEventCallback callback) override {
+    if (!helper_)
+      return;
+    helper_->OnAbortPaymentEventStub(std::move(response_callback),
+                                     std::move(callback));
+  }
+
   void DispatchCanMakePaymentEvent(
       int payment_request_id,
       payments::mojom::CanMakePaymentEventDataPtr event_data,
@@ -542,6 +552,14 @@
   std::move(callback).Run(SERVICE_WORKER_OK, base::Time::Now());
 }
 
+void EmbeddedWorkerTestHelper::OnAbortPaymentEvent(
+    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+    mojom::ServiceWorkerEventDispatcher::DispatchAbortPaymentEventCallback
+        callback) {
+  response_callback->OnResponseForAbortPayment(true, base::Time::Now());
+  std::move(callback).Run(SERVICE_WORKER_OK, base::Time::Now());
+}
+
 void EmbeddedWorkerTestHelper::OnCanMakePaymentEvent(
     payments::mojom::CanMakePaymentEventDataPtr event_data,
     payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
@@ -817,6 +835,16 @@
                             payload, base::Passed(&callback)));
 }
 
+void EmbeddedWorkerTestHelper::OnAbortPaymentEventStub(
+    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+    mojom::ServiceWorkerEventDispatcher::DispatchAbortPaymentEventCallback
+        callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&EmbeddedWorkerTestHelper::OnAbortPaymentEvent, AsWeakPtr(),
+                 base::Passed(&response_callback), base::Passed(&callback)));
+}
+
 void EmbeddedWorkerTestHelper::OnCanMakePaymentEventStub(
     payments::mojom::CanMakePaymentEventDataPtr event_data,
     payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index 8bd3a2ce..bafd228 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -241,6 +241,10 @@
   virtual void OnPushEvent(
       const PushEventPayload& payload,
       mojom::ServiceWorkerEventDispatcher::DispatchPushEventCallback callback);
+  virtual void OnAbortPaymentEvent(
+      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      mojom::ServiceWorkerEventDispatcher::DispatchAbortPaymentEventCallback
+          callback);
   virtual void OnCanMakePaymentEvent(
       payments::mojom::CanMakePaymentEventDataPtr data,
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
@@ -330,6 +334,10 @@
   void OnPushEventStub(
       const PushEventPayload& payload,
       mojom::ServiceWorkerEventDispatcher::DispatchPushEventCallback callback);
+  void OnAbortPaymentEventStub(
+      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      mojom::ServiceWorkerEventDispatcher::DispatchAbortPaymentEventCallback
+          callback);
   void OnCanMakePaymentEventStub(
       payments::mojom::CanMakePaymentEventDataPtr data,
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc
index 93480c4..e135cdf 100644
--- a/content/browser/service_worker/service_worker_database.cc
+++ b/content/browser/service_worker/service_worker_database.cc
@@ -1220,9 +1220,8 @@
     }
   }
 
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = create_if_missing;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   if (IsDatabaseInMemory()) {
     env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
     options.env = env_.get();
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc
index 5efdbeb..db50d53 100644
--- a/content/browser/service_worker/service_worker_metrics.cc
+++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -91,6 +91,8 @@
       return "_NAVIGATION_HINT";
     case ServiceWorkerMetrics::EventType::CAN_MAKE_PAYMENT:
       return "_CAN_MAKE_PAYMENT";
+    case ServiceWorkerMetrics::EventType::ABORT_PAYMENT:
+      return "_ABORT_PAYMENT";
     case ServiceWorkerMetrics::EventType::NUM_TYPES:
       NOTREACHED() << static_cast<int>(event_type);
   }
@@ -336,6 +338,8 @@
       return "Navigation Hint";
     case EventType::CAN_MAKE_PAYMENT:
       return "Can Make Payment";
+    case ServiceWorkerMetrics::EventType::ABORT_PAYMENT:
+      return "Abort Payment";
     case EventType::NUM_TYPES:
       break;
   }
@@ -736,6 +740,9 @@
       UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.CanMakePaymentEvent.Time",
                                  time);
       break;
+    case EventType::ABORT_PAYMENT:
+      UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.AbortPaymentEvent.Time", time);
+      break;
 
     case EventType::NAVIGATION_HINT:
     // The navigation hint should not be sent as an event.
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h
index 526390d..f733146 100644
--- a/content/browser/service_worker/service_worker_metrics.h
+++ b/content/browser/service_worker/service_worker_metrics.h
@@ -128,6 +128,7 @@
     BACKGROUND_FETCHED = 26,
     NAVIGATION_HINT = 27,
     CAN_MAKE_PAYMENT = 28,
+    ABORT_PAYMENT = 29,
     // Add new events to record here.
     NUM_TYPES
   };
diff --git a/content/common/message_port.cc b/content/common/message_port.cc
index 75f51b9..769db84 100644
--- a/content/common/message_port.cc
+++ b/content/common/message_port.cc
@@ -55,7 +55,7 @@
 
   MessagePortMessage msg;
   msg.encoded_message =
-      mojo::ConstCArray<uint8_t>(encoded_message_size, encoded_message);
+      mojo::ConstCArray<uint8_t>(encoded_message, encoded_message_size);
   msg.ports.resize(ports.size());
   for (size_t i = 0; i < ports.size(); ++i)
     msg.ports[i] = ports[i].ReleaseHandle();
diff --git a/content/common/message_port_message_struct_traits.cc b/content/common/message_port_message_struct_traits.cc
index adbe333..31cb5e0 100644
--- a/content/common/message_port_message_struct_traits.cc
+++ b/content/common/message_port_message_struct_traits.cc
@@ -15,7 +15,7 @@
     return false;
 
   out->encoded_message = mojo::ConstCArray<uint8_t>(
-      out->owned_encoded_message.size(), out->owned_encoded_message.data());
+      out->owned_encoded_message.data(), out->owned_encoded_message.size());
   return true;
 }
 
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index c4289a5..412aa43a 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -15,6 +15,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "content/common/unique_name_helper.h"
 #include "content/public/common/resource_request_body.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
@@ -197,12 +198,13 @@
 // 22: Add scroll restoration type.
 // 23: Remove frame sequence number, there are easier ways.
 // 24: Add did save scroll or scale state.
+// 25: Limit the length of unique names: https://crbug.com/626202
 //
 // NOTE: If the version is -1, then the pickle contains only a URL string.
 // See ReadPageState.
 //
 const int kMinVersion = 11;
-const int kCurrentVersion = 24;
+const int kCurrentVersion = 25;
 
 // A bunch of convenience functions to read/write to SerializeObjects.  The
 // de-serializers assume the input data will be in the correct format and fall
@@ -550,8 +552,11 @@
     WriteFrameState(children[i], obj, false);
 }
 
-void ReadFrameState(SerializeObject* obj, bool is_top,
-                    ExplodedFrameState* state) {
+void ReadFrameState(
+    SerializeObject* obj,
+    bool is_top,
+    std::vector<UniqueNameHelper::Replacement>* unique_name_replacements,
+    ExplodedFrameState* state) {
   if (obj->version < 14 && !is_top)
     ReadInteger(obj);  // Skip over redundant version field.
 
@@ -561,6 +566,13 @@
     ReadString(obj);  // Skip obsolete original url string field.
 
   state->target = ReadString(obj);
+  if (obj->version < 25 && !state->target.is_null()) {
+    state->target = base::NullableString16(
+        base::UTF8ToUTF16(UniqueNameHelper::UpdateLegacyNameFromV24(
+            base::UTF16ToUTF8(state->target.string()),
+            unique_name_replacements)),
+        false);
+  }
   if (obj->version < 15) {
     ReadString(obj);  // Skip obsolete parent field.
     ReadString(obj);  // Skip obsolete title field.
@@ -660,7 +672,7 @@
       ReadAndValidateVectorSize(obj, sizeof(ExplodedFrameState));
   state->children.resize(num_children);
   for (size_t i = 0; i < num_children; ++i)
-    ReadFrameState(obj, false, &state->children[i]);
+    ReadFrameState(obj, false, unique_name_replacements, &state->children[i]);
 }
 
 void WritePageState(const ExplodedPageState& state, SerializeObject* obj) {
@@ -689,7 +701,8 @@
   if (obj->version >= 14)
     ReadStringVector(obj, &state->referenced_files);
 
-  ReadFrameState(obj, true, &state->top);
+  std::vector<UniqueNameHelper::Replacement> unique_name_replacements;
+  ReadFrameState(obj, true, &unique_name_replacements, &state->top);
 
   if (obj->version < 14)
     RecursivelyAppendReferencedFiles(state->top, &state->referenced_files);
@@ -763,13 +776,25 @@
   return !obj.parse_error;
 }
 
-void EncodePageState(const ExplodedPageState& exploded, std::string* encoded) {
+static void EncodePageStateInternal(const ExplodedPageState& exploded,
+                                    int version,
+                                    std::string* encoded) {
   SerializeObject obj;
-  obj.version = kCurrentVersion;
+  obj.version = version;
   WritePageState(exploded, &obj);
   *encoded = obj.GetAsString();
 }
 
+void EncodePageState(const ExplodedPageState& exploded, std::string* encoded) {
+  EncodePageStateInternal(exploded, kCurrentVersion, encoded);
+}
+
+void EncodePageStateForTesting(const ExplodedPageState& exploded,
+                               int version,
+                               std::string* encoded) {
+  EncodePageStateInternal(exploded, version, encoded);
+}
+
 #if defined(OS_ANDROID)
 bool DecodePageStateWithDeviceScaleFactorForTesting(
     const std::string& encoded,
diff --git a/content/common/page_state_serialization.h b/content/common/page_state_serialization.h
index d7a0bf3..808a421 100644
--- a/content/common/page_state_serialization.h
+++ b/content/common/page_state_serialization.h
@@ -74,6 +74,9 @@
                                     ExplodedPageState* exploded);
 CONTENT_EXPORT void EncodePageState(const ExplodedPageState& exploded,
                                     std::string* encoded);
+CONTENT_EXPORT void EncodePageStateForTesting(const ExplodedPageState& exploded,
+                                              int version,
+                                              std::string* encoded);
 
 #if defined(OS_ANDROID)
 CONTENT_EXPORT bool DecodePageStateWithDeviceScaleFactorForTesting(
diff --git a/content/common/page_state_serialization_unittest.cc b/content/common/page_state_serialization_unittest.cc
index bd44937..25375870 100644
--- a/content/common/page_state_serialization_unittest.cc
+++ b/content/common/page_state_serialization_unittest.cc
@@ -443,5 +443,9 @@
   TestBackwardsCompat(23);
 }
 
+TEST_F(PageStateSerializationTest, BackwardsCompat_v24) {
+  TestBackwardsCompat(24);
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc
index 4b81aca..a1772e7 100644
--- a/content/common/sandbox_win.cc
+++ b/content/common/sandbox_win.cc
@@ -623,14 +623,11 @@
 // TODO(jschuh): Need get these restrictions applied to NaCl and Pepper.
 // Just have to figure out what needs to be warmed up first.
 sandbox::ResultCode AddBaseHandleClosePolicy(sandbox::TargetPolicy* policy) {
-  if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
-    if (base::FeatureList::IsEnabled(kEnableCsrssLockdownFeature)) {
-      // Close all ALPC ports.
-      sandbox::ResultCode ret =
-          policy->AddKernelObjectToClose(L"ALPC Port", NULL);
-      if (ret != sandbox::SBOX_ALL_OK) {
-        return ret;
-      }
+  if (base::FeatureList::IsEnabled(kEnableCsrssLockdownFeature)) {
+    // Close all ALPC ports.
+    sandbox::ResultCode ret = policy->SetDisconnectCsrss();
+    if (ret != sandbox::SBOX_ALL_OK) {
+      return ret;
     }
   }
 
diff --git a/content/common/service_worker/service_worker_event_dispatcher.mojom b/content/common/service_worker/service_worker_event_dispatcher.mojom
index 96ec145..ff23366e 100644
--- a/content/common/service_worker/service_worker_event_dispatcher.mojom
+++ b/content/common/service_worker/service_worker_event_dispatcher.mojom
@@ -138,6 +138,11 @@
                     blink.mojom.BackgroundSyncEventLastChance last_chance)
       => (blink.mojom.ServiceWorkerEventStatus status,
           mojo.common.mojom.Time dispatch_event_time);
+  DispatchAbortPaymentEvent(
+      int32 event_id,
+      payments.mojom.PaymentHandlerResponseCallback result_of_abort_payment)
+          => (blink.mojom.ServiceWorkerEventStatus status,
+              mojo.common.mojom.Time dispatch_event_time);
   DispatchCanMakePaymentEvent(
       int32 event_id,
       payments.mojom.CanMakePaymentEventData event_data,
diff --git a/content/common/unique_name_helper.cc b/content/common/unique_name_helper.cc
index a6a135b..20992fc0 100644
--- a/content/common/unique_name_helper.cc
+++ b/content/common/unique_name_helper.cc
@@ -5,10 +5,13 @@
 #include "content/common/unique_name_helper.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
+#include "crypto/sha2.h"
 
 namespace content {
 
@@ -22,7 +25,7 @@
 
   // FrameAdapter overrides:
   bool IsMainFrame() const override { return false; }
-  bool IsCandidateUnique(const std::string& name) const override {
+  bool IsCandidateUnique(base::StringPiece name) const override {
     return parent_->IsCandidateUnique(name);
   }
   int GetSiblingCount() const override {
@@ -54,6 +57,11 @@
 constexpr int kFramePathPrefixLength = 15;
 constexpr int kFramePathSuffixLength = 3;
 
+// 80% of unique names are shorter than this, and it also guarantees that this
+// won't ever increase the length of a unique name, as a hashed unique name is
+// exactly 80 characters.
+constexpr size_t kMaxRequestedNameSize = 80;
+
 bool IsNameWithFramePath(base::StringPiece name) {
   return name.starts_with(kFramePathPrefix) && name.ends_with("-->") &&
          (kFramePathPrefixLength + kFramePathSuffixLength) < name.size();
@@ -130,10 +138,10 @@
   return candidate;
 }
 
-std::string CalculateNewName(const FrameAdapter* frame,
-                             const std::string& name) {
+std::string CalculateNameInternal(const FrameAdapter* frame,
+                                  base::StringPiece name) {
   if (!name.empty() && frame->IsCandidateUnique(name) && name != "_blank")
-    return name;
+    return name.as_string();
 
   std::string candidate = GenerateCandidate(frame);
   if (frame->IsCandidateUnique(candidate))
@@ -143,10 +151,39 @@
   return AppendUniqueSuffix(frame, candidate, likely_unique_suffix);
 }
 
+std::string CalculateFrameHash(base::StringPiece name) {
+  DCHECK_GT(name.size(), kMaxRequestedNameSize);
+
+  std::string hashed_name;
+  uint8_t result[crypto::kSHA256Length];
+  crypto::SHA256HashString(name, result, arraysize(result));
+  hashed_name += "<!--frameHash";
+  hashed_name += base::HexEncode(result, arraysize(result));
+  hashed_name += "-->";
+  return hashed_name;
+}
+
+std::string CalculateNewName(const FrameAdapter* frame,
+                             base::StringPiece name) {
+  std::string hashed_name;
+  // By default, |name| is the browsing context name, which can be arbitrarily
+  // long. Since the generated name is part of history entries and FrameState,
+  // hash pathologically long names to avoid using a lot of memory.
+  if (name.size() > kMaxRequestedNameSize) {
+    hashed_name = CalculateFrameHash(name);
+    name = hashed_name;
+  }
+  return CalculateNameInternal(frame, name);
+}
+
 }  // namespace
 
 UniqueNameHelper::FrameAdapter::~FrameAdapter() {}
 
+UniqueNameHelper::Replacement::Replacement(std::string old_name,
+                                           std::string new_name)
+    : old_name(std::move(old_name)), new_name(std::move(new_name)) {}
+
 UniqueNameHelper::UniqueNameHelper(FrameAdapter* frame) : frame_(frame) {}
 
 UniqueNameHelper::~UniqueNameHelper() {}
@@ -167,4 +204,74 @@
   unique_name_ = CalculateNewName(frame_, name);
 }
 
+// |replacements| is used for two purposes:
+// - when processing a non-frame path unique name that exceeds the max size,
+//   this collection records the original name and the hashed name.
+// - when processing a frame path unique name, this collection is used to fix up
+//   ancestor frames in the frame path with an updated unique name.
+//
+std::string UniqueNameHelper::UpdateLegacyNameFromV24(
+    std::string legacy_name,
+    std::vector<Replacement>* replacements) {
+  if (IsNameWithFramePath(legacy_name)) {
+    // Frame paths can embed ancestor's unique names. Since the contract of this
+    // function is that names must be updated beginning from the root of the
+    // tree and go down from there, it is impossible for a frame path to contain
+    // a unique name (which needs a replacement) that has not already been seen
+    // and inserted into |replacements|.
+    size_t index = 0;
+    for (const auto& replacement : *replacements) {
+      size_t next_index = legacy_name.find(replacement.old_name);
+      if (next_index == std::string::npos)
+        continue;
+      legacy_name.replace(next_index, replacement.old_name.size(),
+                          replacement.new_name);
+      index = next_index -
+              (replacement.old_name.size() - replacement.new_name.size());
+    }
+    return legacy_name;
+  }
+
+  if (legacy_name.size() > kMaxRequestedNameSize) {
+    std::string hashed_name = CalculateFrameHash(legacy_name);
+    // Suppose 'aaa' and 'caaab' are unique names in the same tree. A
+    // hypothetical frame path might look like:
+    //   <!--framePath //aaa/caaab/<!--frame0-->-->
+    //
+    // In this case, it's important to avoid matching 'aaa' against the
+    // substring in 'caaab'. To try to avoid this, the search and the
+    // replacement strings are wrapped in '/' to try to match the path delimiter
+    // in generated frame paths.
+    //
+    // However, nothing prevents a browsing context name from containing a
+    // literal '/', which could lead to an ambiguous parse. Consider the case
+    // where 'aaa', 'bbb', and 'aaa/bbb' are unique names in the same tree. The
+    // following frame path is ambiguous:
+    //   <!--framePath //aaa/bbb/<!--frame0-->-->
+    //
+    // While it's possible to use the depth of the frame tree as a hint for
+    // disambiguating this, the number of ways to split up the frame path
+    // quickly becomes quite large. This code takes the simple approach and
+    // simply aims to implement a best effort update, accepting that there may
+    // be some names that are updated incorrectly.
+    std::string original_string = "/";
+    original_string += legacy_name;
+    original_string += "/";
+    std::string new_string = "/";
+    new_string += hashed_name;
+    new_string += "/";
+    replacements->emplace_back(std::move(original_string),
+                               std::move(new_string));
+    return hashed_name;
+  }
+
+  return legacy_name;
+}
+
+std::string UniqueNameHelper::CalculateLegacyNameForTesting(
+    const FrameAdapter* frame,
+    const std::string& name) {
+  return CalculateNameInternal(frame, name);
+}
+
 }  // namespace content
diff --git a/content/common/unique_name_helper.h b/content/common/unique_name_helper.h
index dccea5c..d816305 100644
--- a/content/common/unique_name_helper.h
+++ b/content/common/unique_name_helper.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
+#include "content/common/content_export.h"
 
 namespace content {
 
@@ -64,17 +65,17 @@
 //                   [ framePosition-forParent? ]
 //
 // retryNumber ::= smallest non-negative integer resulting in unique name
-class UniqueNameHelper {
+class CONTENT_EXPORT UniqueNameHelper {
  public:
   // Adapter class so UniqueNameHelper can be used with both RenderFrameImpl and
   // ExplodedFrameState.
-  class FrameAdapter {
+  class CONTENT_EXPORT FrameAdapter {
    public:
     FrameAdapter() {}
     virtual ~FrameAdapter();
 
     virtual bool IsMainFrame() const = 0;
-    virtual bool IsCandidateUnique(const std::string& name) const = 0;
+    virtual bool IsCandidateUnique(base::StringPiece name) const = 0;
     // Returns the number of sibling frames of this frame. Note this should not
     // include this frame in the count.
     virtual int GetSiblingCount() const = 0;
@@ -106,6 +107,13 @@
     DISALLOW_COPY_AND_ASSIGN(FrameAdapter);
   };
 
+  struct Replacement {
+    Replacement(std::string old_name, std::string new_name);
+
+    const std::string old_name;
+    const std::string new_name;
+  };
+
   explicit UniqueNameHelper(FrameAdapter* frame);
   ~UniqueNameHelper();
 
@@ -134,6 +142,19 @@
   // history navigations. See https://crbug.com/607205.
   void UpdateName(const std::string& name);
 
+  // Helper to update legacy names generated for PageState v24 and earlier. This
+  // function should be invoked starting from the root of the tree, traversing
+  // downwards. The exact traversal order is unimportant as long as this
+  // function has been called on all ancestor frames of the node associated with
+  // |legacy_name|. A single instance of |replacements| should be used per frame
+  // tree.
+  static std::string UpdateLegacyNameFromV24(
+      std::string legacy_name,
+      std::vector<Replacement>* replacements);
+
+  static std::string CalculateLegacyNameForTesting(const FrameAdapter* frame,
+                                                   const std::string& name);
+
  private:
   FrameAdapter* const frame_;
   std::string unique_name_;
diff --git a/content/common/unique_name_helper_unittest.cc b/content/common/unique_name_helper_unittest.cc
new file mode 100644
index 0000000..ddf240d4
--- /dev/null
+++ b/content/common/unique_name_helper_unittest.cc
@@ -0,0 +1,411 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/unique_name_helper.h"
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/auto_reset.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/strings/nullable_string16.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/common/page_state_serialization.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+// Requested names longer than this (that are unique) should be hashed.
+constexpr size_t kMaxSize = 80;
+
+class TestFrameAdapter : public UniqueNameHelper::FrameAdapter {
+ public:
+  // |virtual_index_in_parent| is the virtual index of this frame in the
+  // parent's list of children, as unique name generation should see it. Note
+  // that this may differ from the actual index of this adapter in
+  // |parent_->children_|.
+  explicit TestFrameAdapter(TestFrameAdapter* parent,
+                            int virtual_index_in_parent,
+                            const std::string& requested_name)
+      : parent_(parent),
+        virtual_index_in_parent_(virtual_index_in_parent),
+        unique_name_helper_(this) {
+    if (parent_)
+      parent_->children_.push_back(this);
+    unique_name_helper_.UpdateName(requested_name);
+    CalculateLegacyName(requested_name);
+  }
+
+  ~TestFrameAdapter() override {
+    if (parent_) {
+      parent_->children_.erase(std::find(parent_->children_.begin(),
+                                         parent_->children_.end(), this));
+    }
+  }
+
+  bool IsMainFrame() const override { return !parent_; }
+
+  bool IsCandidateUnique(base::StringPiece name) const override {
+    auto* top = this;
+    while (top->parent_)
+      top = top->parent_;
+    return top->CheckUniqueness(name);
+  }
+
+  int GetSiblingCount() const override { return virtual_index_in_parent_; }
+
+  int GetChildCount() const override {
+    ADD_FAILURE()
+        << "GetChildCount() should not be triggered by unit test code!";
+    return 0;
+  }
+
+  std::vector<base::StringPiece> CollectAncestorNames(
+      BeginPoint begin_point,
+      bool (*should_stop)(base::StringPiece)) const override {
+    EXPECT_EQ(BeginPoint::kParentFrame, begin_point);
+    std::vector<base::StringPiece> result;
+    for (auto* adapter = parent_; adapter; adapter = adapter->parent_) {
+      result.push_back(adapter->GetNameForCurrentMode());
+      if (should_stop(result.back()))
+        break;
+    }
+    return result;
+  }
+
+  std::vector<int> GetFramePosition(BeginPoint begin_point) const override {
+    EXPECT_EQ(BeginPoint::kParentFrame, begin_point);
+    std::vector<int> result;
+    for (auto* adapter = this; adapter->parent_; adapter = adapter->parent_)
+      result.push_back(adapter->virtual_index_in_parent_);
+    return result;
+  }
+
+  // Returns the new style name with a max size limit.
+  const std::string& GetUniqueName() const {
+    return unique_name_helper_.value();
+  }
+
+  // Calculate and return the legacy style name with no max size limit.
+  const std::string& GetLegacyName() const { return legacy_name_; }
+
+  // Populate a tree of FrameState with legacy unique names. The order of
+  // FrameState children is guaranteed to match the order of TestFrameAdapter
+  // children.
+  void PopulateLegacyFrameState(ExplodedFrameState* frame_state) const {
+    frame_state->target =
+        base::NullableString16(base::UTF8ToUTF16(GetLegacyName()), false);
+    frame_state->children.resize(children_.size());
+    for (size_t i = 0; i < children_.size(); ++i)
+      children_[i]->PopulateLegacyFrameState(&frame_state->children[i]);
+  }
+
+  // Recursively verify that FrameState and its children have matching unique
+  // names to this TestFrameAdapter.
+  void VerifyUpdatedFrameState(const ExplodedFrameState& frame_state) const {
+    EXPECT_EQ(GetUniqueName(), base::UTF16ToUTF8(frame_state.target.string()));
+
+    ASSERT_EQ(children_.size(), frame_state.children.size());
+    for (size_t i = 0; i < children_.size(); ++i) {
+      children_[i]->VerifyUpdatedFrameState(frame_state.children[i]);
+    }
+  }
+
+ private:
+  // Global toggle for the style of name to generate. Used to ensure that test
+  // code can consistently trigger the legacy generation path when needed.
+  static bool generate_legacy_name_;
+
+  const std::string& GetNameForCurrentMode() const {
+    return generate_legacy_name_ ? GetLegacyName() : GetUniqueName();
+  }
+
+  void CalculateLegacyName(const std::string& requested_name) {
+    // Manually skip the main frame so its legacy name is always empty: this
+    // is needed in the test as that logic lives at a different layer in
+    // UniqueNameHelper.
+    if (!IsMainFrame()) {
+      base::AutoReset<bool> enable_legacy_mode(&generate_legacy_name_, true);
+      legacy_name_ =
+          UniqueNameHelper::CalculateLegacyNameForTesting(this, requested_name);
+    }
+  }
+
+  bool CheckUniqueness(base::StringPiece name) const {
+    if (name == GetNameForCurrentMode())
+      return false;
+    for (auto* child : children_) {
+      if (!child->CheckUniqueness(name))
+        return false;
+    }
+    return true;
+  }
+
+  TestFrameAdapter* const parent_;
+  std::vector<TestFrameAdapter*> children_;
+  const int virtual_index_in_parent_;
+  UniqueNameHelper unique_name_helper_;
+  std::string legacy_name_;
+};
+
+bool TestFrameAdapter::generate_legacy_name_ = false;
+
+// Test helper that verifies that legacy unique names in versions of PageState
+// prior to 25 are correctly updated when deserialized.
+void VerifyPageStateForTargetUpdate(const TestFrameAdapter& main_frame) {
+  ExplodedPageState in_state;
+  main_frame.PopulateLegacyFrameState(&in_state.top);
+
+  // Version 24 is the last version with unlimited size unique names.
+  std::string encoded_state;
+  EncodePageStateForTesting(in_state, 24, &encoded_state);
+
+  ExplodedPageState out_state;
+  DecodePageState(encoded_state, &out_state);
+
+  main_frame.VerifyUpdatedFrameState(out_state.top);
+}
+
+TEST(UniqueNameHelper, Basic) {
+  // Main frames should always have an empty unique name.
+  TestFrameAdapter main_frame(nullptr, -1, "my main frame");
+  EXPECT_EQ("", main_frame.GetUniqueName());
+  EXPECT_EQ("", main_frame.GetLegacyName());
+
+  // A child frame with a requested name that is unique should use the requested
+  // name.
+  TestFrameAdapter frame_0(&main_frame, 0, "child frame with name");
+  EXPECT_EQ("child frame with name", frame_0.GetUniqueName());
+  EXPECT_EQ("child frame with name", frame_0.GetLegacyName());
+
+  // A child frame with no requested name should receive a generated unique
+  // name.
+  TestFrameAdapter frame_7(&main_frame, 7, "");
+  EXPECT_EQ("<!--framePath //<!--frame7-->-->", frame_7.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame7-->-->", frame_7.GetLegacyName());
+
+  // Naming collision should force a fallback to using a generated unique name.
+  TestFrameAdapter frame_2(&main_frame, 2, "child frame with name");
+  EXPECT_EQ("<!--framePath //<!--frame2-->-->", frame_2.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame2-->-->", frame_2.GetLegacyName());
+
+  // Index collision should also force a fallback to using a generated unique
+  // name.
+  TestFrameAdapter frame_2a(&main_frame, 2, "");
+  EXPECT_EQ("<!--framePath //<!--frame2-->--><!--framePosition-2/0-->",
+            frame_2a.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame2-->--><!--framePosition-2/0-->",
+            frame_2a.GetLegacyName());
+
+  // A child of a frame with a unique naming collision will incorporate the
+  // frame position marker as part of its frame path, though it will look a bit
+  // strange...
+  TestFrameAdapter frame_2a_5(&frame_2a, 5, "");
+  EXPECT_EQ(
+      "<!--framePath //<!--frame2-->--><!--framePosition-2/0/<!--frame5-->-->",
+      frame_2a_5.GetUniqueName());
+  EXPECT_EQ(
+      "<!--framePath //<!--frame2-->--><!--framePosition-2/0/<!--frame5-->-->",
+      frame_2a_5.GetLegacyName());
+
+  // Index and name collision should also force a fallback to using a generated
+  // unique name.
+  TestFrameAdapter frame_2b(&main_frame, 2, "child frame with name");
+  EXPECT_EQ("<!--framePath //<!--frame2-->--><!--framePosition-2/1-->",
+            frame_2b.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame2-->--><!--framePosition-2/1-->",
+            frame_2b.GetLegacyName());
+
+  VerifyPageStateForTargetUpdate(main_frame);
+}
+
+TEST(UniqueNameHelper, Hashing) {
+  // Main frames should always have an empty unique name.
+  TestFrameAdapter main_frame(nullptr, -1, "my main frame");
+  EXPECT_EQ("", main_frame.GetUniqueName());
+  EXPECT_EQ("", main_frame.GetLegacyName());
+
+  // A child frame with a requested name that is unique but too long should fall
+  // back to hashing.
+  const std::string too_long_name(kMaxSize + 1, 'a');
+  TestFrameAdapter frame_0(&main_frame, 0, too_long_name);
+  EXPECT_EQ(
+      "<!--"
+      "frameHash8C48280D57FB88F161ADF34D9F597D93CA32B7EDFCD23B2AFE64C3789B3F785"
+      "5-->",
+      frame_0.GetUniqueName());
+  EXPECT_EQ(too_long_name, frame_0.GetLegacyName());
+
+  // A child frame with no requested name should receive a generated unique
+  // name.
+  TestFrameAdapter frame_7(&main_frame, 7, "");
+  EXPECT_EQ("<!--framePath //<!--frame7-->-->", frame_7.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame7-->-->", frame_7.GetLegacyName());
+
+  // Verify that a requested name that's over the limit collides with the hashed
+  // version of its requested name.
+  TestFrameAdapter frame_2(&main_frame, 2, too_long_name);
+  EXPECT_EQ("<!--framePath //<!--frame2-->-->", frame_2.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame2-->-->", frame_2.GetLegacyName());
+
+  // Index collision should also force a fallback to using a generated unique
+  // name.
+  TestFrameAdapter frame_2a(&main_frame, 2, "");
+  EXPECT_EQ("<!--framePath //<!--frame2-->--><!--framePosition-2/0-->",
+            frame_2a.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame2-->--><!--framePosition-2/0-->",
+            frame_2a.GetLegacyName());
+
+  // A child of a frame with a unique naming collision will incorporate the
+  // frame position marker as part of its frame path, though it will look a bit
+  // strange...
+  TestFrameAdapter frame_2a_5(&frame_2a, 5, "");
+  EXPECT_EQ(
+      "<!--framePath //<!--frame2-->--><!--framePosition-2/0/<!--frame5-->-->",
+      frame_2a_5.GetUniqueName());
+  EXPECT_EQ(
+      "<!--framePath //<!--frame2-->--><!--framePosition-2/0/<!--frame5-->-->",
+      frame_2a_5.GetLegacyName());
+
+  // Index and name collision should also force a fallback to using a generated
+  // unique name.
+  TestFrameAdapter frame_2b(&main_frame, 2, too_long_name);
+  EXPECT_EQ("<!--framePath //<!--frame2-->--><!--framePosition-2/1-->",
+            frame_2b.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame2-->--><!--framePosition-2/1-->",
+            frame_2b.GetLegacyName());
+
+  VerifyPageStateForTargetUpdate(main_frame);
+}
+
+// Verify that basic frame path generation always includes the full path from
+// the root.
+TEST(UniqueNameHelper, BasicGeneratedFramePath) {
+  TestFrameAdapter main_frame(nullptr, -1, "my main frame");
+  EXPECT_EQ("", main_frame.GetUniqueName());
+  EXPECT_EQ("", main_frame.GetLegacyName());
+
+  TestFrameAdapter frame_2(&main_frame, 2, "");
+  EXPECT_EQ("<!--framePath //<!--frame2-->-->", frame_2.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame2-->-->", frame_2.GetLegacyName());
+
+  TestFrameAdapter frame_2_3(&frame_2, 3, "named grandchild");
+  EXPECT_EQ("named grandchild", frame_2_3.GetUniqueName());
+  EXPECT_EQ("named grandchild", frame_2_3.GetLegacyName());
+
+  // Even though the parent frame has a unique name, the frame path should
+  // include the full path from the root.
+  TestFrameAdapter frame_2_3_5(&frame_2_3, 5, "");
+  EXPECT_EQ("<!--framePath //<!--frame2-->/named grandchild/<!--frame5-->-->",
+            frame_2_3_5.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame2-->/named grandchild/<!--frame5-->-->",
+            frame_2_3_5.GetLegacyName());
+
+  VerifyPageStateForTargetUpdate(main_frame);
+}
+
+TEST(UniqueNameHelper, GeneratedFramePathHashing) {
+  TestFrameAdapter main_frame(nullptr, -1, "my main frame");
+  EXPECT_EQ("", main_frame.GetUniqueName());
+  EXPECT_EQ("", main_frame.GetLegacyName());
+
+  TestFrameAdapter frame_0(&main_frame, 0, "");
+  EXPECT_EQ("<!--framePath //<!--frame0-->-->", frame_0.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame0-->-->", frame_0.GetLegacyName());
+
+  // At the limit, so the hashing fallback should not be triggered.
+  const std::string just_fits_name(kMaxSize, 'a');
+  TestFrameAdapter frame_0_0(&frame_0, 0, just_fits_name);
+  EXPECT_EQ(just_fits_name, frame_0_0.GetUniqueName());
+  EXPECT_EQ(just_fits_name, frame_0_0.GetLegacyName());
+
+  // But anything over should trigger hashing.
+  const std::string too_long_name(kMaxSize + 1, 'a');
+  TestFrameAdapter frame_0_1(&frame_0, 1, too_long_name);
+  EXPECT_EQ(
+      "<!--"
+      "frameHash8C48280D57FB88F161ADF34D9F597D93CA32B7EDFCD23B2AFE64C3789B3F785"
+      "5-->",
+      frame_0_1.GetUniqueName());
+  EXPECT_EQ(too_long_name, frame_0_1.GetLegacyName());
+
+  // A child frame should incorporate the parent's hashed requested name into
+  // its frame path.
+  TestFrameAdapter frame_0_1_0(&frame_0_1, 0, "");
+  EXPECT_EQ(
+      "<!--framePath "
+      "//<!--frame0-->/"
+      "<!--"
+      "frameHash8C48280D57FB88F161ADF34D9F597D93CA32B7EDFCD23B2AFE64C3789B3F785"
+      "5-->/<!--frame0-->-->",
+      frame_0_1_0.GetUniqueName());
+  EXPECT_EQ(
+      "<!--framePath "
+      "//<!--frame0-->/" +
+          too_long_name + "/<!--frame0-->-->",
+      frame_0_1_0.GetLegacyName());
+
+  // Make sure that name replacement during legacy name updates don't
+  // accidentally match on substrings: the name here is intentionally chosen so
+  // that too_long_name is a substring.
+  const std::string too_long_name2(kMaxSize + 10, 'a');
+  TestFrameAdapter frame_0_2(&frame_0, 2, too_long_name2);
+  EXPECT_EQ(
+      "<!--"
+      "frameHash6B2EC79170F50EA57B886DC81A2CF78721C651A002C8365A524019A7ED5A8A4"
+      "0-->",
+      frame_0_2.GetUniqueName());
+  EXPECT_EQ(too_long_name2, frame_0_2.GetLegacyName());
+
+  // Make sure that legacy name updates correctly handle multiple replacements.
+  // An unnamed frame is used as the deepest descendant to ensure the requested
+  // names from ancestors appear in the frame path. Begin with a named
+  // grandparent:
+  const std::string too_long_name3(kMaxSize * 2, 'b');
+  TestFrameAdapter frame_0_1_1(&frame_0_1, 1, too_long_name3);
+  EXPECT_EQ(
+      "<!--"
+      "frameHash3A0B065A4255F95EF6E206B11004B8805FB631A68F468A72CE26F7592C88C27"
+      "A-->",
+      frame_0_1_1.GetUniqueName());
+  EXPECT_EQ(too_long_name3, frame_0_1_1.GetLegacyName());
+
+  // And a named parent:
+  const std::string too_long_name4(kMaxSize * 3, 'c');
+  TestFrameAdapter frame_0_1_1_0(&frame_0_1_1, 0, too_long_name4);
+  EXPECT_EQ(
+      "<!--"
+      "frameHashE00D028A784E645656638F4D461B81E779E5225CA9824C8E09664956CF4DAE3"
+      "1-->",
+      frame_0_1_1_0.GetUniqueName());
+  EXPECT_EQ(too_long_name4, frame_0_1_1_0.GetLegacyName());
+
+  // And finally an unnamed child to trigger fallback to the frame path:
+  TestFrameAdapter frame_0_1_1_0_0(&frame_0_1_1_0, 0, "");
+  EXPECT_EQ(
+      "<!--framePath "
+      "//<!--frame0-->/"
+      "<!--"
+      "frameHash8C48280D57FB88F161ADF34D9F597D93CA32B7EDFCD23B2AFE64C3789B3F785"
+      "5-->/"
+      "<!--"
+      "frameHash3A0B065A4255F95EF6E206B11004B8805FB631A68F468A72CE26F7592C88C27"
+      "A-->/"
+      "<!--"
+      "frameHashE00D028A784E645656638F4D461B81E779E5225CA9824C8E09664956CF4DAE3"
+      "1-->/<!--frame0-->-->",
+      frame_0_1_1_0_0.GetUniqueName());
+  EXPECT_EQ("<!--framePath //<!--frame0-->/" + too_long_name + "/" +
+                too_long_name3 + "/" + too_long_name4 + "/<!--frame0-->-->",
+            frame_0_1_1_0_0.GetLegacyName());
+
+  VerifyPageStateForTargetUpdate(main_frame);
+}
+
+}  // namespace
+}  // namespace content
diff --git a/content/public/browser/payment_app_provider.h b/content/public/browser/payment_app_provider.h
index d6a97261..0fd5d2c 100644
--- a/content/public/browser/payment_app_provider.h
+++ b/content/public/browser/payment_app_provider.h
@@ -36,7 +36,7 @@
   using GetAllPaymentAppsCallback = base::OnceCallback<void(PaymentApps)>;
   using InvokePaymentAppCallback =
       base::OnceCallback<void(payments::mojom::PaymentHandlerResponsePtr)>;
-  using CanMakePaymentCallback = base::OnceCallback<void(bool)>;
+  using PaymentEventResultCallback = base::OnceCallback<void(bool)>;
 
   // Should be accessed only on the UI thread.
   virtual void GetAllPaymentApps(BrowserContext* browser_context,
@@ -50,7 +50,10 @@
       BrowserContext* browser_context,
       int64_t registration_id,
       payments::mojom::CanMakePaymentEventDataPtr event_data,
-      CanMakePaymentCallback callback) = 0;
+      PaymentEventResultCallback callback) = 0;
+  virtual void AbortPayment(BrowserContext* browser_context,
+                            int64_t registration_id,
+                            PaymentEventResultCallback callback) = 0;
 
  protected:
   virtual ~PaymentAppProvider() {}
diff --git a/content/renderer/accessibility/blink_ax_enum_conversion.cc b/content/renderer/accessibility/blink_ax_enum_conversion.cc
index 1903b96..8b2d3a5 100644
--- a/content/renderer/accessibility/blink_ax_enum_conversion.cc
+++ b/content/renderer/accessibility/blink_ax_enum_conversion.cc
@@ -439,6 +439,8 @@
       return ui::AX_MARKER_TYPE_TEXT_MATCH;
     case blink::kWebAXMarkerTypeActiveSuggestion:
       return ui::AX_MARKER_TYPE_ACTIVE_SUGGESTION;
+    case blink::kWebAXMarkerTypeSuggestion:
+      return ui::AX_MARKER_TYPE_SUGGESTION;
   }
   NOTREACHED();
   return ui::AX_MARKER_TYPE_NONE;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 913f1a89..f2ba6ec 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -874,7 +874,7 @@
 }
 
 bool RenderFrameImpl::UniqueNameFrameAdapter::IsCandidateUnique(
-    const std::string& name) const {
+    base::StringPiece name) const {
   // This method is currently O(N), where N = number of frames in the tree.
   DCHECK(!name.empty());
 
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 1f9d303..d679223 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -1199,7 +1199,7 @@
 
     // FrameAdapter overrides:
     bool IsMainFrame() const override;
-    bool IsCandidateUnique(const std::string& name) const override;
+    bool IsCandidateUnique(base::StringPiece name) const override;
     int GetSiblingCount() const override;
     int GetChildCount() const override;
     std::vector<base::StringPiece> CollectAncestorNames(
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index a0f1feac..d875f68 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -383,6 +383,16 @@
   // Pending callbacks for Background Sync Events.
   SyncEventCallbacksMap sync_event_callbacks;
 
+  // Pending callbacks for result of AbortPayment.
+  std::map<int /* abort_payment_event_id */,
+           payments::mojom::PaymentHandlerResponseCallbackPtr>
+      abort_payment_result_callbacks;
+
+  // Pending callbacks for AbortPayment Events.
+  std::map<int /* abort_payment_event_id */,
+           DispatchCanMakePaymentEventCallback>
+      abort_payment_event_callbacks;
+
   // Pending callbacks for result of CanMakePayment.
   std::map<int /* can_make_payment_event_id */,
            payments::mojom::PaymentHandlerResponseCallbackPtr>
@@ -1113,6 +1123,28 @@
   context_->sync_event_callbacks.Remove(request_id);
 }
 
+void ServiceWorkerContextClient::RespondToAbortPaymentEvent(
+    int event_id,
+    bool payment_aborted,
+    double dispatch_event_time) {
+  const payments::mojom::PaymentHandlerResponseCallbackPtr& result_callback =
+      context_->abort_payment_result_callbacks[event_id];
+  result_callback->OnResponseForAbortPayment(
+      payment_aborted, base::Time::FromDoubleT(dispatch_event_time));
+  context_->abort_payment_result_callbacks.erase(event_id);
+}
+
+void ServiceWorkerContextClient::DidHandleAbortPaymentEvent(
+    int event_id,
+    blink::WebServiceWorkerEventResult result,
+    double dispatch_event_time) {
+  DispatchAbortPaymentEventCallback callback =
+      std::move(context_->abort_payment_event_callbacks[event_id]);
+  std::move(callback).Run(EventResultToStatus(result),
+                          base::Time::FromDoubleT(dispatch_event_time));
+  context_->abort_payment_event_callbacks.erase(event_id);
+}
+
 void ServiceWorkerContextClient::RespondToCanMakePaymentEvent(
     int event_id,
     bool can_make_payment,
@@ -1267,6 +1299,19 @@
                             web_last_chance);
 }
 
+void ServiceWorkerContextClient::DispatchAbortPaymentEvent(
+    int event_id,
+    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+    DispatchAbortPaymentEventCallback callback) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::DispatchAbortPaymentEvent");
+  context_->abort_payment_result_callbacks.insert(
+      std::make_pair(event_id, std::move(response_callback)));
+  context_->abort_payment_event_callbacks.insert(
+      std::make_pair(event_id, std::move(callback)));
+  proxy_->DispatchAbortPaymentEvent(event_id);
+}
+
 void ServiceWorkerContextClient::DispatchCanMakePaymentEvent(
     int event_id,
     payments::mojom::CanMakePaymentEventDataPtr eventData,
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 91e9bdf5..0546f1a 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -207,6 +207,12 @@
   void DidHandleSyncEvent(int request_id,
                           blink::WebServiceWorkerEventResult result,
                           double dispatch_event_time) override;
+  void RespondToAbortPaymentEvent(int event_id,
+                                  bool payment_aborted,
+                                  double dispatch_event_time) override;
+  void DidHandleAbortPaymentEvent(int event_id,
+                                  blink::WebServiceWorkerEventResult result,
+                                  double dispatch_event_time) override;
   void RespondToCanMakePaymentEvent(int event_id,
                                     bool can_make_payment,
                                     double dispatch_event_time) override;
@@ -303,6 +309,10 @@
       const std::string& tag,
       blink::mojom::BackgroundSyncEventLastChance last_chance,
       DispatchSyncEventCallback callback) override;
+  void DispatchAbortPaymentEvent(
+      int payment_request_id,
+      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      DispatchAbortPaymentEventCallback callback) override;
   void DispatchCanMakePaymentEvent(
       int payment_request_id,
       payments::mojom::CanMakePaymentEventDataPtr event_data,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index ddc1ae3..bf29c0b 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1457,6 +1457,7 @@
     "../common/service_manager/service_manager_connection_impl_unittest.cc",
     "../common/service_worker/service_worker_utils_unittest.cc",
     "../common/throttling_url_loader_unittest.cc",
+    "../common/unique_name_helper_unittest.cc",
     "../common/webplugininfo_unittest.cc",
     "../network/network_context_unittest.cc",
     "../network/network_service_unittest.cc",
diff --git a/content/test/data/page_state/serialized_v24.dat b/content/test/data/page_state/serialized_v24.dat
new file mode 100644
index 0000000..ed726d5
--- /dev/null
+++ b/content/test/data/page_state/serialized_v24.dat
@@ -0,0 +1,17 @@
+tAMAABgAAAABAAAAEAAAAGYAaQBsAGUALgB0AHgAdAAoAAAAaAB0AHQAcAA6AC8ALwBjAGgAcgBv
+AG0AaQB1AG0ALgBvAHIAZwAvAAwAAAB0AGEAcgBnAGUAdAABAAAAKgAAANb///8kAAAAaAB0AHQA
+cAA6AC8ALwBnAG8AbwBnAGwAZQAuAGMAbwBtAC8ACAAAAGAAAAAKAA0APwAlACAAVwBlAGIASwBp
+AHQAIABzAGUAcgBpAGEAbABpAHoAZQBkACAAZgBvAHIAbQAgAHMAdABhAHQAZQAgAHYAZQByAHMA
+aQBvAG4AIAA4ACAACgANAD0AJgAQAAAAZgBvAHIAbQAgAGsAZQB5AAIAAAAxAAAABgAAAGYAbwBv
+AAAACAAAAGYAaQBsAGUAAgAAADIAAAAQAAAAZgBpAGwAZQAuAHQAeAB0ABYAAABkAGkAcwBwAGwA
+YQB5AE4AYQBtAGUAAAAIAAAAAAAAAAAAAEB7AAAAAAAAAMgBAAAAAAAAAQAAAAgAAAAAAAAAAADw
+vwgAAAAAAAAAAADwvwAAAAAAAAAAAQAAAAMAAAAAAAAAEAAAAGZpcnN0IGRhdGEgYmxvY2sBAAAA
+EAAAAGYAaQBsAGUALgB0AHgAdAAAAAAAAAAAAP//////////CAAAAAAAAAAAAAAAAAAAAA8AAABk
+YXRhIHRoZSBzZWNvbmQAFQMAAAAAAAAAAAAADgAAAGYAbwBvAC8AYgBhAHIAAAABAAAAKAAAAGgA
+dAB0AHAAOgAvAC8AYwBoAHIAbwBtAGkAdQBtAC4AbwByAGcALwD/////AQAAACoAAADW////JAAA
+AGgAdAB0AHAAOgAvAC8AZwBvAG8AZwBsAGUALgBjAG8AbQAvAAgAAABgAAAACgANAD8AJQAgAFcA
+ZQBiAEsAaQB0ACAAcwBlAHIAaQBhAGwAaQB6AGUAZAAgAGYAbwByAG0AIABzAHQAYQB0AGUAIAB2
+AGUAcgBzAGkAbwBuACAAOAAgAAoADQA9ACYAEAAAAGYAbwByAG0AIABrAGUAeQACAAAAMQAAAAYA
+AABmAG8AbwAAAAgAAABmAGkAbABlAAIAAAAyAAAAEAAAAGYAaQBsAGUALgB0AHgAdAAWAAAAZABp
+AHMAcABsAGEAeQBOAGEAbQBlAAAACAAAAAAAAAAAAABAewAAAAAAAADIAQAAAAAAAAEAAAAIAAAA
+AAAAAAAA8L8IAAAAAAAAAAAA8L8AAAAAAAAAAAAAAAD/////AAAAAA==
diff --git a/content/test/data/payments/payment_app.js b/content/test/data/payments/payment_app.js
index eef2509a..6b30285 100644
--- a/content/test/data/payments/payment_app.js
+++ b/content/test/data/payments/payment_app.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+self.addEventListener('abortpayment', e => {
+  e.respondWith(true);
+});
+
 self.addEventListener('canmakepayment', e => {
   // Note that the following postMessage operations are not normal usage
   // in CanMakePaymentEvent. They are only used for testing purpose.
diff --git a/device/gamepad/public/interfaces/gamepad_struct_traits.cc b/device/gamepad/public/interfaces/gamepad_struct_traits.cc
index 2a97cea..2b95544b 100644
--- a/device/gamepad/public/interfaces/gamepad_struct_traits.cc
+++ b/device/gamepad/public/interfaces/gamepad_struct_traits.cc
@@ -137,7 +137,8 @@
   while (id_length < device::Gamepad::kIdLengthCap && r.id[id_length] != 0) {
     id_length++;
   }
-  return {id_length, reinterpret_cast<const uint16_t*>(&r.id[0])};
+  return ConstCArray<uint16_t>(reinterpret_cast<const uint16_t*>(r.id),
+                               id_length);
 }
 
 // static
@@ -149,7 +150,8 @@
          r.mapping[mapping_length] != 0) {
     mapping_length++;
   }
-  return {mapping_length, reinterpret_cast<const uint16_t*>(&r.mapping[0])};
+  return ConstCArray<uint16_t>(reinterpret_cast<const uint16_t*>(r.mapping),
+                               mapping_length);
 }
 
 // static
@@ -158,34 +160,32 @@
     device::Gamepad* out) {
   out->connected = data.connected();
 
-  memset(&out->id[0], 0, device::Gamepad::kIdLengthCap * sizeof(device::UChar));
-  CArray<uint16_t> id = {0, device::Gamepad::kIdLengthCap,
-                         reinterpret_cast<uint16_t*>(&out->id[0])};
+  memset(out->id, 0, sizeof(out->id));
+  CArray<uint16_t> id(reinterpret_cast<uint16_t*>(out->id),
+                      device::Gamepad::kIdLengthCap);
   if (!data.ReadId(&id)) {
     return false;
   }
 
   out->timestamp = data.timestamp();
 
-  CArray<double> axes = {0, device::Gamepad::kAxesLengthCap, &out->axes[0]};
+  CArray<double> axes(out->axes);
   if (!data.ReadAxes(&axes)) {
     return false;
   }
   // static_cast is safe when "data.ReadAxes(&axes)" above returns true.
-  out->axes_length = static_cast<unsigned>(axes.size);
+  out->axes_length = static_cast<unsigned>(axes.size());
 
-  CArray<device::GamepadButton> buttons = {
-      0, device::Gamepad::kButtonsLengthCap, &out->buttons[0]};
+  CArray<device::GamepadButton> buttons(out->buttons);
   if (!data.ReadButtons(&buttons)) {
     return false;
   }
   // static_cast is safe when "data.ReadButtons(&buttons)" above returns true.
-  out->buttons_length = static_cast<unsigned>(buttons.size);
+  out->buttons_length = static_cast<unsigned>(buttons.size());
 
-  memset(&out->mapping[0], 0,
-         device::Gamepad::kMappingLengthCap * sizeof(device::UChar));
-  CArray<uint16_t> mapping = {0, device::Gamepad::kMappingLengthCap,
-                              reinterpret_cast<uint16_t*>(&out->mapping[0])};
+  memset(out->mapping, 0, sizeof(out->mapping));
+  CArray<uint16_t> mapping(reinterpret_cast<uint16_t*>(out->mapping),
+                           device::Gamepad::kMappingLengthCap);
   if (!data.ReadMapping(&mapping)) {
     return false;
   }
diff --git a/device/gamepad/public/interfaces/gamepad_struct_traits.h b/device/gamepad/public/interfaces/gamepad_struct_traits.h
index 9d02f52..20b136b 100644
--- a/device/gamepad/public/interfaces/gamepad_struct_traits.h
+++ b/device/gamepad/public/interfaces/gamepad_struct_traits.h
@@ -92,10 +92,10 @@
   static bool connected(const device::Gamepad& r) { return r.connected; }
   static uint64_t timestamp(const device::Gamepad& r) { return r.timestamp; }
   static ConstCArray<double> axes(const device::Gamepad& r) {
-    return {r.axes_length, &r.axes[0]};
+    return ConstCArray<double>(r.axes, r.axes_length);
   }
   static ConstCArray<device::GamepadButton> buttons(const device::Gamepad& r) {
-    return {r.buttons_length, &r.buttons[0]};
+    return ConstCArray<device::GamepadButton>(r.buttons, r.buttons_length);
   }
   static const device::GamepadPose& pose(const device::Gamepad& r) {
     return r.pose;
diff --git a/docs/security/faq.md b/docs/security/faq.md
index 63898e71..db567b9 100644
--- a/docs/security/faq.md
+++ b/docs/security/faq.md
@@ -65,6 +65,43 @@
 bugs related to deleting browsing data are not considered under the security
 VRP. The Chrome Privacy team tracks them as functional bugs.
 
+<a name="TOC-Timing-Attacks"></a>
+## Are timing attacks considered security vulnerabilities?
+
+Some timing attacks are considered security vulnerabilities, and some are
+considered privacy vulnerabilities. Timing attacks vary significantly in terms
+of impact, reliability, and exploitability.
+
+Some timing attacks weaken mitigations like ASLR (e.g.
+[Issue 665930](https://crbug.com/665930)). Others attempt to circumvent the same
+origin policy, for instance, by using SVG filters to read pixels
+cross-origin (e.g. [Issue 686253](https://crbug.com/686253) and
+[Issue 615851](https://crbug.com/615851)).
+
+Many timing attacks rely upon the availability of high-resolution timing
+information [Issue 508166](https://crbug.com/508166); such timing data often has
+legitimate usefulness in non-attack scenarios making it unappealing to remove.
+
+Timing attacks against the browser's HTTP Cache (like
+[Issue 74987](https://crbug.com/74987)) can potentially leak information about
+which sites the user has previously loaded. The browser could attempt to protect
+against such attacks (e.g. by bypassing the cache) at the cost of performance
+and thus user-experience. To mitigate against such timing attacks, end-users can
+delete browsing history and/or browse sensitive sites using Chrome's Incognito
+or Guest browsing modes.
+
+Other timing attacks can be mitigated via clever design changes. For instance,
+[Issue 544765](https://crbug.com/544765) describes an attack whereby an attacker
+can probe for the presence of HSTS rules (set by prior site visits) by timing
+the load of resources with URLs "fixed-up" by HSTS. HSTS rules are shared
+between regular browsing and Incognito mode, making the attack more interesting.
+The attack was mitigated by changing Content-Security-Policy such that secure
+URLs will match rules demanding non-secure HTTP urls, a fix that has also proven
+useful to help to unblock migrations to HTTPS. Similarly,
+[Issue 707071](https://crbug.com/707071) describes a timing attack in which an
+attacker could determine what Android applications are installed; the attack was
+mitigated by introducing randomness in the execution time of the affected API.
+
 <a name="TOC-What-are-the-security-and-privacy-guarantees-of-Incognito-mode-"></a>
 ## What are the security and privacy guarantees of Incognito mode?
 
@@ -540,13 +577,10 @@
 ## What is the security story for Service Workers?
 
 See our dedicated [Service Worker Security
-FAQ](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/security-faq/service-worker-security-faq).
+FAQ](https://chromium.googlesource.com/chromium/src/+/master/docs/security/service-worker-security-faq.md).
 
 ## TODO
 
 *    Move https://www.chromium.org/developers/severity-guidelines into MD as
      well, and change links here to point to it.
 *    https://dev.chromium.org/Home/chromium-security/client-identification-mechanisms
-     also
-*    https://sites.google.com/a/chromium.org/dev/Home/chromium-security/security-faq/service-worker-security-faq
-     also
diff --git a/extensions/browser/value_store/lazy_leveldb.cc b/extensions/browser/value_store/lazy_leveldb.cc
index 3eed60b..52efc487 100644
--- a/extensions/browser/value_store/lazy_leveldb.cc
+++ b/extensions/browser/value_store/lazy_leveldb.cc
@@ -64,10 +64,9 @@
 
 LazyLevelDb::LazyLevelDb(const std::string& uma_client_name,
                          const base::FilePath& path)
-    : db_path_(path) {
+    : db_path_(path), open_options_(leveldb_env::Options()) {
   open_options_.create_if_missing = true;
   open_options_.paranoid_checks = true;
-  open_options_.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
 
   read_options_.verify_checksums = true;
 
@@ -175,7 +174,8 @@
   ValueStore::BackingStoreRestoreStatus restore_status =
       ValueStore::RESTORE_NONE;
 
-  leveldb::Options repair_options;
+  leveldb_env::Options repair_options;
+  repair_options.reuse_logs = false;
   repair_options.create_if_missing = true;
   repair_options.paranoid_checks = true;
 
diff --git a/extensions/browser/value_store/lazy_leveldb.h b/extensions/browser/value_store/lazy_leveldb.h
index 551a6ea..d27dd47 100644
--- a/extensions/browser/value_store/lazy_leveldb.h
+++ b/extensions/browser/value_store/lazy_leveldb.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/metrics/histogram_base.h"
 #include "extensions/browser/value_store/value_store.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 
 namespace leveldb {
@@ -80,7 +81,7 @@
   // The path to the underlying leveldb.
   const base::FilePath db_path_;
   // The options to be used when this database is lazily opened.
-  leveldb::Options open_options_;
+  leveldb_env::Options open_options_;
   // The options to be used for all database read operations.
   leveldb::ReadOptions read_options_;
   // The options to be used for all database write operations.
diff --git a/google_apis/gcm/engine/gcm_store_impl.cc b/google_apis/gcm/engine/gcm_store_impl.cc
index cb5e9d6..6ac63d4a 100644
--- a/google_apis/gcm/engine/gcm_store_impl.cc
+++ b/google_apis/gcm/engine/gcm_store_impl.cc
@@ -299,9 +299,8 @@
     return STORE_DOES_NOT_EXIST;
   }
 
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.create_if_missing = open_mode == CREATE_IF_MISSING;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   options.paranoid_checks = true;
   leveldb::Status status =
       leveldb_env::OpenDB(options, path_.AsUTF8Unsafe(), &db_);
@@ -414,7 +413,7 @@
   DVLOG(1) << "Destroying GCM store.";
   db_.reset();
   const leveldb::Status s =
-      leveldb::DestroyDB(path_.AsUTF8Unsafe(), leveldb::Options());
+      leveldb::DestroyDB(path_.AsUTF8Unsafe(), leveldb_env::Options());
   if (s.ok()) {
     foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
     return;
diff --git a/gpu/ipc/common/mailbox_struct_traits.cc b/gpu/ipc/common/mailbox_struct_traits.cc
index 4f73996e..df56cc5d 100644
--- a/gpu/ipc/common/mailbox_struct_traits.cc
+++ b/gpu/ipc/common/mailbox_struct_traits.cc
@@ -7,17 +7,10 @@
 namespace mojo {
 
 // static
-MailboxName StructTraits<gpu::mojom::MailboxDataView, gpu::Mailbox>::name(
-    const gpu::Mailbox& mailbox) {
-  return {GL_MAILBOX_SIZE_CHROMIUM, GL_MAILBOX_SIZE_CHROMIUM,
-          const_cast<int8_t*>(&mailbox.name[0])};
-}
-
-// static
 bool StructTraits<gpu::mojom::MailboxDataView, gpu::Mailbox>::Read(
     gpu::mojom::MailboxDataView data,
     gpu::Mailbox* out) {
-  MailboxName mailbox_name = {0, GL_MAILBOX_SIZE_CHROMIUM, &out->name[0]};
+  CArray<int8_t> mailbox_name(out->name);
   return data.ReadName(&mailbox_name);
 }
 
diff --git a/gpu/ipc/common/mailbox_struct_traits.h b/gpu/ipc/common/mailbox_struct_traits.h
index 50c5b61..9004723 100644
--- a/gpu/ipc/common/mailbox_struct_traits.h
+++ b/gpu/ipc/common/mailbox_struct_traits.h
@@ -11,13 +11,11 @@
 
 namespace mojo {
 
-// A buffer used to read bytes directly from MailboxDataView to gpu::Mailbox
-// name.
-using MailboxName = CArray<int8_t>;
-
 template <>
 struct StructTraits<gpu::mojom::MailboxDataView, gpu::Mailbox> {
-  static MailboxName name(const gpu::Mailbox& mailbox);
+  static ConstCArray<int8_t> name(const gpu::Mailbox& mailbox) {
+    return mailbox.name;
+  }
   static bool Read(gpu::mojom::MailboxDataView data, gpu::Mailbox* out);
 };
 
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 5ba57c0..6fefea52 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -117,6 +117,7 @@
     "//google_apis",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/drag_and_drop",
     "//ios/chrome/browser/ssl:features",
     "//ios/chrome/browser/sync/glue",
     "//ios/chrome/common",
diff --git a/ios/chrome/browser/drag_and_drop/BUILD.gn b/ios/chrome/browser/drag_and_drop/BUILD.gn
new file mode 100644
index 0000000..1ca0922
--- /dev/null
+++ b/ios/chrome/browser/drag_and_drop/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("drag_and_drop") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "drop_and_navigate_delegate.h",
+    "drop_and_navigate_interaction.h",
+    "drop_and_navigate_interaction.mm",
+  ]
+  deps = [
+    "//base",
+    "//net:net",
+    "//url:url",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "drop_and_navigate_interaction_unittest.mm",
+  ]
+  deps = [
+    ":drag_and_drop",
+    "//base",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/drag_and_drop/OWNERS b/ios/chrome/browser/drag_and_drop/OWNERS
new file mode 100644
index 0000000..d2e1add
--- /dev/null
+++ b/ios/chrome/browser/drag_and_drop/OWNERS
@@ -0,0 +1 @@
+jif@chromium.org
diff --git a/ios/chrome/browser/drag_and_drop/drop_and_navigate_delegate.h b/ios/chrome/browser/drag_and_drop/drop_and_navigate_delegate.h
new file mode 100644
index 0000000..be7b8c5
--- /dev/null
+++ b/ios/chrome/browser/drag_and_drop/drop_and_navigate_delegate.h
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_DRAG_AND_DROP_DROP_AND_NAVIGATE_DELEGATE_H_
+#define IOS_CHROME_BROWSER_DRAG_AND_DROP_DROP_AND_NAVIGATE_DELEGATE_H_
+
+class GURL;
+
+// Protocol to implement to be notified by a DropAndNavigationInteraction that
+// a drop event that can trigger a navigation occurs.
+@protocol DropAndNavigateDelegate
+
+// Called when a drop event containing |url| occured.
+- (void)URLWasDropped:(GURL const&)url;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_DRAG_AND_DROP_DROP_AND_NAVIGATE_DELEGATE_H_
diff --git a/ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.h b/ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.h
new file mode 100644
index 0000000..829d5613
--- /dev/null
+++ b/ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.h
@@ -0,0 +1,29 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_DRAG_AND_DROP_DROP_AND_NAVIGATE_INTERACTION_H_
+#define IOS_CHROME_BROWSER_DRAG_AND_DROP_DROP_AND_NAVIGATE_INTERACTION_H_
+
+#import <UIKit/UIKit.h>
+
+#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
+
+@protocol DropAndNavigateDelegate;
+
+// A UIDropManager that notifies it's DropAndNavigateDelegate whenever an object
+// that can trigger a navigation is dropped.
+API_AVAILABLE(ios(11.0))
+@interface DropAndNavigateInteraction : UIDropInteraction
+
+// Default initializer. Notifies |navigationDelegate| whenever an item
+// that can trigger a navigation was dropped. |navigationDelegate| is not
+// retained.
+- (instancetype)initWithDelegate:(id<DropAndNavigateDelegate>)navigationDelegate
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
+#endif
+
+#endif  // IOS_CHROME_BROWSER_DRAG_AND_DROP_DROP_AND_NAVIGATE_INTERACTION_H_
diff --git a/ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.mm b/ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.mm
new file mode 100644
index 0000000..29587eb
--- /dev/null
+++ b/ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.mm
@@ -0,0 +1,75 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.h"
+
+#include "ios/chrome/browser/drag_and_drop/drop_and_navigate_delegate.h"
+#import "net/base/mac/url_conversions.h"
+#include "url/gurl.h"
+
+#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface DropAndNavigateInteraction ()<UIDropInteractionDelegate> {
+  __weak id<DropAndNavigateDelegate> _navigationDelegate;
+}
+
+// Returns whether |session| contains an object that can generate a navigation.
+- (BOOL)canAcceptDropSession:(id<UIDropSession>)session;
+
+@end
+
+@implementation DropAndNavigateInteraction
+
+- (instancetype)initWithDelegate:
+    (id<DropAndNavigateDelegate>)navigationDelegate {
+  if (self = [super initWithDelegate:self]) {
+    _navigationDelegate = navigationDelegate;
+  }
+  return self;
+}
+
+#pragma mark - UIDropInteractionDelegate
+
+- (void)dropInteraction:(UIDropInteraction*)interaction
+            performDrop:(id<UIDropSession>)session API_AVAILABLE(ios(11.0)) {
+  if ([session canLoadObjectsOfClass:[NSURL class]]) {
+    [session loadObjectsOfClass:[NSURL class]
+                     completion:^(NSArray<NSURL*>* objects) {
+                       GURL url = net::GURLWithNSURL([objects firstObject]);
+                       if (url.is_valid()) {
+                         [_navigationDelegate URLWasDropped:url];
+                       }
+                     }];
+  }
+  // TODO(crbug.com/753424): Accept NSString drops: generate a search query.
+}
+
+- (BOOL)dropInteraction:(UIDropInteraction*)interaction
+       canHandleSession:(id<UIDropSession>)session {
+  return [self canAcceptDropSession:session];
+}
+
+- (UIDropProposal*)dropInteraction:(UIDropInteraction*)interaction
+                  sessionDidUpdate:(id<UIDropSession>)session {
+  UIDropOperation dropOperation = UIDropOperationCancel;
+  if ([self canAcceptDropSession:session]) {
+    dropOperation = UIDropOperationCopy;
+  }
+  return [[UIDropProposal alloc] initWithDropOperation:dropOperation];
+}
+
+#pragma mark - Private
+
+- (BOOL)canAcceptDropSession:(id<UIDropSession>)session {
+  // TODO(crbug.com/753424): Accept NSString drops: generate a search query.
+  return [session canLoadObjectsOfClass:[NSURL class]];
+}
+
+@end
+
+#endif
diff --git a/ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction_unittest.mm b/ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction_unittest.mm
new file mode 100644
index 0000000..2344cd7f
--- /dev/null
+++ b/ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction_unittest.mm
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/logging.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+TEST(DropAndNavigateTest, Instantiation) {
+#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
+  if (@available(iOS 11, *)) {
+    DropAndNavigateInteraction* interaction =
+        [[DropAndNavigateInteraction alloc] initWithDelegate:nil];
+    DCHECK(interaction.delegate);
+  }
+#endif
+}
+
+}  // namespace
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm
index 2882a1f..954d335 100644
--- a/ios/chrome/browser/payments/payment_request.mm
+++ b/ios/chrome/browser/payments/payment_request.mm
@@ -392,7 +392,6 @@
 void PaymentRequest::CreateNativeAppPaymentMethods() {
   if (!base::FeatureList::IsEnabled(
           payments::features::kWebPaymentsNativeApps)) {
-    url_payment_method_identifiers_ = std::vector<GURL>();
     PopulatePaymentMethodCache(
         std::vector<std::unique_ptr<IOSPaymentInstrument>>());
     return;
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
index f417e5dc..b1e944a 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
@@ -154,7 +154,9 @@
   BOOL totalValueChanged =
       (_paymentRequest->payment_details().total != paymentDetails.total);
   [_mediator setTotalValueChanged:totalValueChanged];
-  // Update the payment summary item.
+
+  _paymentRequest->UpdatePaymentDetails(paymentDetails);
+
   [_viewController updatePaymentSummaryItem];
 
   if (totalValueChanged) {
@@ -168,8 +170,6 @@
                                repeats:NO];
   }
 
-  _paymentRequest->UpdatePaymentDetails(paymentDetails);
-
   // If a shipping address has been selected and there are available shipping
   // options, set it as the selected shipping address.
   if (_pendingShippingAddress && !_paymentRequest->shipping_options().empty()) {
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index 54fd157..45f06b6 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -10,6 +10,7 @@
 #include <string>
 #include <unordered_map>
 
+#include "base/feature_list.h"
 #include "base/ios/block_types.h"
 #include "base/ios/ios_util.h"
 #include "base/json/json_reader.h"
@@ -26,6 +27,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/ios/browser/autofill_driver_ios.h"
 #include "components/payments/core/can_make_payment_query.h"
+#include "components/payments/core/features.h"
 #include "components/payments/core/journey_logger.h"
 #include "components/payments/core/payment_address.h"
 #include "components/payments/core/payment_instrument.h"
@@ -444,7 +446,9 @@
   }
 
   if (paymentRequest->supported_card_networks().empty() &&
-      paymentRequest->url_payment_method_identifiers().empty()) {
+      (!base::FeatureList::IsEnabled(
+           payments::features::kWebPaymentsNativeApps) ||
+       paymentRequest->url_payment_method_identifiers().empty())) {
     paymentRequest->journey_logger().SetNotShown(
         payments::JourneyLogger::NOT_SHOWN_REASON_NO_SUPPORTED_PAYMENT_METHOD);
     // TODO(crbug.com/602666): Reject the promise with an error of
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn
index ea25fb25..011f19fe 100644
--- a/ios/chrome/browser/ui/toolbar/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -54,6 +54,7 @@
     "//ios/chrome/browser/autocomplete",
     "//ios/chrome/browser/bookmarks",
     "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/drag_and_drop",
     "//ios/chrome/browser/reading_list",
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/ssl",
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index 1df09fe..d636742 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -30,6 +30,8 @@
 #include "ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/browser/drag_and_drop/drop_and_navigate_delegate.h"
+#include "ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.h"
 #include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
@@ -229,13 +231,14 @@
 // TODO(crbug.com/619982) Remove this block and add CAAnimationDelegate when we
 // switch the main bots to Xcode 8.
 #if defined(__IPHONE_10_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0)
-@interface WebToolbarController ()<CAAnimationDelegate,
-                                   ToolbarAssistiveKeyboardDelegate>
+@interface WebToolbarController ()<CAAnimationDelegate>
 @end
 #endif
 
-@interface WebToolbarController ()<LocationBarDelegate,
+@interface WebToolbarController ()<DropAndNavigateDelegate,
+                                   LocationBarDelegate,
                                    OmniboxPopupPositioner,
+                                   ToolbarAssistiveKeyboardDelegate,
                                    ToolbarFrameDelegate> {
   // Top-level view for web content.
   UIView* _webToolbar;
@@ -286,6 +289,10 @@
   // back or forward button. nil if not visible.
   TabHistoryPopupController* _tabHistoryPopupController;
 
+#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
+  API_AVAILABLE(ios(11.0)) DropAndNavigateInteraction* _dropInteraction;
+#endif
+
   // The current browser state.
   ios::ChromeBrowserState* _browserState;  // weak
 }
@@ -676,6 +683,13 @@
   }
   [self.view setDelegate:self];
 
+#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
+  if (@available(iOS 11, *)) {
+    _dropInteraction =
+        [[DropAndNavigateInteraction alloc] initWithDelegate:self];
+    [self.view addInteraction:_dropInteraction];
+  }
+#endif
   return self;
 }
 
@@ -1495,6 +1509,18 @@
 }
 
 #pragma mark -
+#pragma mark DropAndNavigateDelegate
+
+- (void)URLWasDropped:(GURL const&)gurl {
+  ui::PageTransition transition =
+      ui::PageTransitionFromInt(ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+  [self.urlLoader loadURL:gurl
+                 referrer:web::Referrer()
+               transition:transition
+        rendererInitiated:NO];
+}
+
+#pragma mark -
 #pragma mark Private methods.
 
 - (UIButton*)cancelButton {
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 76368a95..fef97a6 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -136,6 +136,7 @@
     "//ios/chrome/browser/content_suggestions:unit_tests",
     "//ios/chrome/browser/crash_report:unit_tests",
     "//ios/chrome/browser/device_sharing:unit_tests",
+    "//ios/chrome/browser/drag_and_drop:unit_tests",
     "//ios/chrome/browser/favicon:unit_tests",
     "//ios/chrome/browser/find_in_page:unit_tests",
     "//ios/chrome/browser/geolocation:unit_tests",
diff --git a/media/blink/buffered_data_source_host_impl.cc b/media/blink/buffered_data_source_host_impl.cc
index 1b4f872..8569558 100644
--- a/media/blink/buffered_data_source_host_impl.cc
+++ b/media/blink/buffered_data_source_host_impl.cc
@@ -57,12 +57,9 @@
 void BufferedDataSourceHostImpl::AddBufferedByteRange(int64_t start,
                                                       int64_t end) {
   int64_t new_bytes = UnloadedBytesInInterval(Interval<int64_t>(start, end));
-  if (new_bytes == 0) {
-    // No change
-    return;
-  }
+  if (new_bytes > 0)
+    did_loading_progress_ = true;
   buffered_byte_ranges_.SetInterval(start, end, 1);
-  did_loading_progress_ = true;
 
   base::TimeTicks now = tick_clock_->NowTicks();
   int64_t bytes_so_far = 0;
diff --git a/media/blink/multibuffer_data_source.cc b/media/blink/multibuffer_data_source.cc
index d793c69..3f29a1c 100644
--- a/media/blink/multibuffer_data_source.cc
+++ b/media/blink/multibuffer_data_source.cc
@@ -116,7 +116,7 @@
       stop_signal_received_(false),
       media_has_played_(false),
       single_origin_(true),
-      cancel_on_defer_(false),
+      cancel_on_defer_(true),
       preload_(AUTO),
       bitrate_(0),
       playback_rate_(0.0),
@@ -414,6 +414,7 @@
 }
 
 void MultibufferDataSource::StopInternal_Locked() {
+  DVLOG(1) << __func__;
   lock_.AssertAcquired();
   if (stop_signal_received_)
     return;
@@ -443,6 +444,7 @@
 /////////////////////////////////////////////////////////////////////////////
 // BufferedResourceLoader callback methods.
 void MultibufferDataSource::StartCallback() {
+  DVLOG(1) << __func__;
   DCHECK(render_task_runner_->BelongsToCurrentThread());
 
   if (init_cb_.is_null()) {
@@ -493,6 +495,8 @@
     media_log_->SetBooleanProperty("range_header_supported",
                                    url_data_->range_supported());
   }
+  if (!url_data_->range_supported())
+    cancel_on_defer_ = false;
 
   render_task_runner_->PostTask(
       FROM_HERE, base::Bind(base::ResetAndReturn(&init_cb_), success));
@@ -536,7 +540,8 @@
     bool loading = is_loading || force_loading;
 
     if (!loading && cancel_on_defer_) {
-      if (read_op_) {
+      DVLOG(2) << "Cancel on defer";
+      if (read_op_ || !init_cb_.is_null()) {
         // We can't destroy the reader if a read operation is pending.
         // UpdateLoadingState_Locked will be called again when the read
         // operation is done.
diff --git a/media/blink/multibuffer_data_source_unittest.cc b/media/blink/multibuffer_data_source_unittest.cc
index 32f2663..712d8c6 100644
--- a/media/blink/multibuffer_data_source_unittest.cc
+++ b/media/blink/multibuffer_data_source_unittest.cc
@@ -389,18 +389,21 @@
   }
 
   void CheckCapacityDefer() {
-    EXPECT_EQ(2 << 20, preload_low());
-    EXPECT_EQ(3 << 20, preload_high());
+    if (loader()) {
+      EXPECT_EQ(2 << 20, preload_low());
+      EXPECT_EQ(3 << 20, preload_high());
+    } else {
+      EXPECT_EQ(preload(), MultibufferDataSource::AUTO);
+    }
   }
 
   void CheckReadThenDefer() {
-    EXPECT_EQ(0, preload_low());
-    EXPECT_EQ(0, preload_high());
-  }
-
-  void CheckNeverDefer() {
-    EXPECT_EQ(1LL << 40, preload_low());
-    EXPECT_EQ(1LL << 40, preload_high());
+    if (loader()) {
+      EXPECT_EQ(0, preload_low());
+      EXPECT_EQ(0, preload_high());
+    } else {
+      EXPECT_EQ(preload(), MultibufferDataSource::METADATA);
+    }
   }
 
   // Accessors for private variables on |data_source_|.
@@ -1185,15 +1188,20 @@
   set_preload(MultibufferDataSource::METADATA);
   InitializeWith206Response();
 
-  EXPECT_EQ(MultibufferDataSource::METADATA, preload());
+  data_source_->MediaIsPlaying();
+  data_source_->SetPreload(MultibufferDataSource::METADATA);
   EXPECT_FALSE(is_local_source());
   EXPECT_TRUE(data_source_->range_supported());
   CheckReadThenDefer();
 
-  // Read a bit from the beginning.
+  // Read next block. (Needed to start up the loader again.)
   EXPECT_CALL(*this, ReadCallback(kDataSize));
-  ReadAt(0);
+  ReadAt(kDataSize);
+  Respond(response_generator_->Generate206(kDataSize));
+  EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 2));
+  ReceiveData(kDataSize);
 
+  // After reading, we should be in a deferred state.
   ASSERT_TRUE(active_loader());
   EXPECT_TRUE(data_provider()->deferred());
 }
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index e7a9391..cffb6ae 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -938,6 +938,16 @@
   if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
     return false;
 
+  // To suspend before we reach kReadyStateHaveCurrentData is only ok
+  // if we know we're going to get woken up when we get more data, which
+  // will only happen if the network is in the "Loading" state.
+  // This happens when the network is fast, but multiple videos are loading
+  // and multiplexing gets held up waiting for available threads.
+  if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
+      network_state_ != WebMediaPlayer::kNetworkStateLoading) {
+    return true;
+  }
+
   if (preroll_attempt_pending_)
     return true;
 
@@ -2549,11 +2559,24 @@
 
 void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
   if (IsHidden()) {
-    if (ShouldPauseVideoWhenHidden())
+    if (ShouldPauseVideoWhenHidden()) {
       PauseVideoIfNeeded();
-    else
-      DisableVideoTrackIfNeeded();
+    } else if (update_background_status_cb_.IsCancelled()) {
+      // Only trigger updates when we don't have one already scheduled.
+      update_background_status_cb_.Reset(
+          base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
+                     base::Unretained(this)));
+
+      // Defer disable track until we're sure the clip will be backgrounded for
+      // some time. Resuming may take half a second, so frequent tab switches
+      // will yield a poor user experience otherwise. http://crbug.com/709302
+      // may also cause AV sync issues if disable/enable happens too fast.
+      main_task_runner_->PostDelayedTask(
+          FROM_HERE, update_background_status_cb_.callback(),
+          base::TimeDelta::FromSeconds(10));
+    }
   } else {
+    update_background_status_cb_.Cancel();
     EnableVideoTrackIfNeeded();
   }
 }
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 60b21577..d6054dd 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -807,6 +807,8 @@
 
   OverlayInfo overlay_info_;
 
+  base::CancelableClosure update_background_status_cb_;
+
   mojom::WatchTimeRecorderProvider* watch_time_recorder_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index 116f8f1e..014a2d3 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -270,6 +270,9 @@
   }
 
  protected:
+  void SetNetworkState(blink::WebMediaPlayer::NetworkState state) {
+    wmpi_->SetNetworkState(state);
+  }
   void SetReadyState(blink::WebMediaPlayer::ReadyState state) {
     wmpi_->SetReadyState(state);
   }
@@ -421,11 +424,9 @@
   EXPECT_FALSE(IsSuspended());
 }
 
-TEST_F(WebMediaPlayerImplTest, IdleSuspendIsEnabledBeforeLoadingBegins) {
+TEST_F(WebMediaPlayerImplTest, IdleSuspendBeforeLoadingBegins) {
   InitializeWebMediaPlayerImpl();
-  EXPECT_TRUE(delegate_.ExpireForTesting());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(IsSuspended());
+  EXPECT_FALSE(delegate_.ExpireForTesting());
 }
 
 TEST_F(WebMediaPlayerImplTest,
@@ -445,6 +446,7 @@
 
 TEST_F(WebMediaPlayerImplTest, IdleSuspendIsEnabledIfLoadingHasStalled) {
   InitializeWebMediaPlayerImpl();
+  SetNetworkState(blink::WebMediaPlayer::kNetworkStateLoading);
   base::SimpleTestTickClock* clock = new base::SimpleTestTickClock();
   clock->Advance(base::TimeDelta::FromSeconds(1));
   SetTickClock(clock);
@@ -460,6 +462,7 @@
 TEST_F(WebMediaPlayerImplTest, DidLoadingProgressTriggersResume) {
   // Same setup as IdleSuspendIsEnabledBeforeLoadingBegins.
   InitializeWebMediaPlayerImpl();
+  SetNetworkState(blink::WebMediaPlayer::kNetworkStateLoading);
   EXPECT_TRUE(delegate_.ExpireForTesting());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsSuspended());
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc
index 655fad8d..29f9d7a3 100644
--- a/media/gpu/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -188,10 +188,6 @@
     L"mf.dll", L"mfplat.dll", L"msmpeg2vdec.dll",
 };
 
-// Vectored exception handlers are global to the entire process, so use TLS to
-// ensure only the thread with the ScopedExceptionCatcher dumps anything.
-base::ThreadLocalStorage::StaticSlot g_catcher_tls_slot = TLS_INITIALIZER;
-
 uint64_t GetCurrentQPC() {
   LARGE_INTEGER perf_counter_now = {};
   // Use raw QueryPerformanceCounter to avoid grabbing locks or allocating
@@ -200,48 +196,10 @@
   return perf_counter_now.QuadPart;
 }
 
-// This is information about the last exception. Writing into it may be racy,
-// but that should be ok because the information is only used for debugging.
-DWORD g_last_exception_code;
-uint64_t g_last_exception_time;
 uint64_t g_last_process_output_time;
 HRESULT g_last_unhandled_error;
 HRESULT g_last_device_removed_reason;
 
-LONG CALLBACK VectoredCrashHandler(EXCEPTION_POINTERS* exception_pointers) {
-  if (g_catcher_tls_slot.Get()) {
-    g_last_exception_code = exception_pointers->ExceptionRecord->ExceptionCode;
-    g_last_exception_time = GetCurrentQPC();
-  }
-  return EXCEPTION_CONTINUE_SEARCH;
-}
-
-// The MS VP9 MFT swallows driver exceptions and later hangs because it gets
-// into a weird state. Add a vectored exception handler so information about
-// the exception can be retrieved. See http://crbug.com/636158
-class ScopedExceptionCatcher {
- public:
-  explicit ScopedExceptionCatcher(bool handle_exception) {
-    if (handle_exception) {
-      DCHECK(g_catcher_tls_slot.initialized());
-      g_catcher_tls_slot.Set(static_cast<void*>(this));
-      handler_ = AddVectoredExceptionHandler(1, &VectoredCrashHandler);
-    }
-  }
-
-  ~ScopedExceptionCatcher() {
-    if (handler_) {
-      g_catcher_tls_slot.Set(nullptr);
-      RemoveVectoredExceptionHandler(handler_);
-    }
-  }
-
- private:
-  void* handler_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedExceptionCatcher);
-};
-
 }  // namespace
 
 namespace media {
@@ -1250,7 +1208,6 @@
 
 // static
 void DXVAVideoDecodeAccelerator::PreSandboxInitialization() {
-  g_catcher_tls_slot.Initialize(nullptr);
   for (const wchar_t* mfdll : kMediaFoundationVideoDecoderDLLs)
     ::LoadLibrary(mfdll);
   ::LoadLibrary(L"dxva2.dll");
@@ -1809,13 +1766,10 @@
     MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0};
     DWORD status = 0;
     HRESULT hr;
-    {
-      ScopedExceptionCatcher catcher(using_ms_vp9_mft_);
-      g_last_process_output_time = GetCurrentQPC();
-      hr = decoder_->ProcessOutput(0,  // No flags
-                                   1,  // # of out streams to pull from
-                                   &output_data_buffer, &status);
-    }
+    g_last_process_output_time = GetCurrentQPC();
+    hr = decoder_->ProcessOutput(0,  // No flags
+                                 1,  // # of out streams to pull from
+                                 &output_data_buffer, &status);
     IMFCollection* events = output_data_buffer.pEvents;
     if (events != NULL) {
       DVLOG(1) << "Got events from ProcessOuput, but discarding";
@@ -2069,9 +2023,6 @@
 void DXVAVideoDecodeAccelerator::StopDecoderThread() {
   // Try to determine what, if any exception last happened before a hang. See
   // http://crbug.com/613701
-  DWORD last_exception_code = g_last_exception_code;
-  HRESULT last_unhandled_error = g_last_unhandled_error;
-  uint64_t last_exception_time = g_last_exception_time;
   uint64_t last_process_output_time = g_last_process_output_time;
   HRESULT last_device_removed_reason = g_last_device_removed_reason;
   LARGE_INTEGER perf_frequency;
@@ -2086,9 +2037,6 @@
       stale_output_picture_buffers_.size();
   PictureBufferMechanism mechanism = GetPictureBufferMechanism();
 
-  base::debug::Alias(&last_exception_code);
-  base::debug::Alias(&last_unhandled_error);
-  base::debug::Alias(&last_exception_time);
   base::debug::Alias(&last_process_output_time);
   base::debug::Alias(&last_device_removed_reason);
   base::debug::Alias(&perf_frequency.QuadPart);
@@ -2292,10 +2240,7 @@
                              this);
   }
   inputs_before_decode_++;
-  {
-    ScopedExceptionCatcher catcher(using_ms_vp9_mft_);
-    hr = decoder_->ProcessInput(0, sample.Get(), 0);
-  }
+  hr = decoder_->ProcessInput(0, sample.Get(), 0);
   // As per msdn if the decoder returns MF_E_NOTACCEPTING then it means that it
   // has enough data to produce one or more output samples. In this case the
   // recommended options are to
diff --git a/media/test/data/load_many_videos.html b/media/test/data/load_many_videos.html
new file mode 100644
index 0000000..0eacf6f
--- /dev/null
+++ b/media/test/data/load_many_videos.html
@@ -0,0 +1,64 @@
+<!--
+Loads lots of videos to make sure that we don't deadlock somewhere
+while loading lots of videos. We try a variety of video formats and
+containers to try to cover different read patterns.
+-->
+<html>
+<body onload="RunTest();">
+<video controls preload=audo src="bear-320x180-hi10p.mp4"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?A"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?B"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?C"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?D"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?E"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?F"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?G"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?H"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?I"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?J"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?K"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?L"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?M"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?N"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?O"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?P"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?Q"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?R"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?S"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?T"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?U"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?V"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?W"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?X"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?Y"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?Z"></video><br>
+<video controls preload=audo src="bear-1280x720.mp4"></video><br>
+<video controls preload=audo src="bear-320x240.webm"></video><br>
+<video controls preload=audo src="bear.mp4"></video><br>
+<video controls preload=audo src="bear-vp8a.webm"></video><br>
+<video controls preload=audo src="bear-320x240-video-only.webm"></video><br>
+<video controls preload=audo src="bear-320x240-vp9_profile2.webm"></video><br>
+<video controls preload=audo src="bear-320x180-hi12p-vp9.webm"></video><br>
+<video controls preload=audo src="bbb-320x240-2video-2audio.mp4"></video><br>
+<video controls preload=audo src="bear-1280x720-av_with-aud-nalus_frag.mp4"></video><br>
+<video controls preload=audo src="bear-vp8-webvtt.webm"></video><br>
+</body>
+
+<script>
+  function CheckIfDone() {
+    console.log("Done?");
+    var players = document.getElementsByTagName("video");
+    for (var i = 0; i < players.length; i++) {
+      if (players[i].readyState < 4) return;
+    }
+    document.title = "ENDED";
+  }
+  function RunTest() {
+    var players = document.getElementsByTagName("video");
+    for (var i = 0; i < players.length; i++) {
+      players[i].addEventListener('canplaythrough', function(e) { CheckIfDone(); });
+    }
+    CheckIfDone();
+  }
+</script>
+</html>
diff --git a/mojo/common/common_custom_types_struct_traits.h b/mojo/common/common_custom_types_struct_traits.h
index e5c46c73..b805d00f 100644
--- a/mojo/common/common_custom_types_struct_traits.h
+++ b/mojo/common/common_custom_types_struct_traits.h
@@ -27,8 +27,8 @@
 template <>
 struct StructTraits<common::mojom::String16DataView, base::StringPiece16> {
   static ConstCArray<uint16_t> data(base::StringPiece16 str) {
-    return ConstCArray<uint16_t>(str.size(),
-                                 reinterpret_cast<const uint16_t*>(str.data()));
+    return ConstCArray<uint16_t>(reinterpret_cast<const uint16_t*>(str.data()),
+                                 str.size());
   }
 };
 
diff --git a/mojo/common/values_struct_traits.h b/mojo/common/values_struct_traits.h
index 950cf30..6ca7289 100644
--- a/mojo/common/values_struct_traits.h
+++ b/mojo/common/values_struct_traits.h
@@ -183,8 +183,8 @@
     if (!value.is_blob())
       NOTREACHED();
     return mojo::ConstCArray<uint8_t>(
-        value.GetBlob().size(),
-        reinterpret_cast<const uint8_t*>(value.GetBlob().data()));
+        reinterpret_cast<const uint8_t*>(value.GetBlob().data()),
+        value.GetBlob().size());
   }
 
   static const base::ListValue& list_value(const base::Value& value) {
diff --git a/mojo/public/cpp/bindings/array_traits_carray.h b/mojo/public/cpp/bindings/array_traits_carray.h
index 3a9bd8c1..e4458ec 100644
--- a/mojo/public/cpp/bindings/array_traits_carray.h
+++ b/mojo/public/cpp/bindings/array_traits_carray.h
@@ -6,53 +6,85 @@
 #define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_CARRAY_H_
 
 #include <cstddef>
+
 #include "mojo/public/cpp/bindings/array_traits.h"
 
 namespace mojo {
 
 template <typename T>
-struct CArray {
-  CArray() : size(0), max_size(0), data(nullptr) {}
-  CArray(size_t size, size_t max_size, T* data)
-      : size(size), max_size(max_size), data(data) {}
-  size_t size;
-  const size_t max_size;
-  T* data;
+class CArray {
+ public:
+  constexpr CArray() noexcept : size_(0), data_(nullptr) {}
+  constexpr CArray(T* data, size_t size) noexcept : size_(size), data_(data) {}
+  template <size_t N>
+  constexpr CArray(T (&array)[N]) noexcept : size_(N), data_(array) {}
+
+  constexpr size_t size() const noexcept { return size_; }
+  constexpr T* data() const noexcept { return data_; }
+
+  constexpr CArray subspan(size_t pos, size_t count) const {
+    // Note: ideally this would DCHECK, but it requires fairly horrible
+    // contortions.
+    return CArray(data_ + pos, count);
+  }
+
+ private:
+  size_t size_;
+  T* data_;
 };
 
+// TODO(dcheng): Not sure if this is needed. Maybe code should just use
+// CArray<const T> rather than ConstCArray<T>?
 template <typename T>
-struct ConstCArray {
-  ConstCArray() : size(0), data(nullptr) {}
-  ConstCArray(size_t size, const T* data) : size(size), data(data) {}
-  size_t size;
-  const T* data;
+class ConstCArray {
+ public:
+  constexpr ConstCArray() noexcept : size_(0), data_(nullptr) {}
+  constexpr ConstCArray(const T* data, size_t size) noexcept
+      : size_(size), data_(data) {}
+  template <size_t N>
+  constexpr ConstCArray(const T (&array)[N]) noexcept
+      : size_(N), data_(array) {}
+
+  constexpr size_t size() const noexcept { return size_; }
+  constexpr const T* data() const noexcept { return data_; }
+
+  constexpr ConstCArray subspan(size_t pos, size_t count) const {
+    // Note: ideally this would DCHECK, but it requires fairly horrible
+    // contortions.
+    return ConstCArray(data_ + pos, count);
+  }
+
+ private:
+  size_t size_;
+  const T* data_;
 };
 
 template <typename T>
 struct ArrayTraits<CArray<T>> {
   using Element = T;
 
-  static bool IsNull(const CArray<T>& input) { return !input.data; }
+  static bool IsNull(const CArray<T>& input) { return !input.data(); }
 
-  static void SetToNull(CArray<T>* output) { output->data = nullptr; }
+  static void SetToNull(CArray<T>* output) { *output = CArray<T>(); }
 
-  static size_t GetSize(const CArray<T>& input) { return input.size; }
+  static size_t GetSize(const CArray<T>& input) { return input.size(); }
 
-  static T* GetData(CArray<T>& input) { return input.data; }
+  static T* GetData(CArray<T>& input) { return input.data(); }
 
-  static const T* GetData(const CArray<T>& input) { return input.data; }
+  static const T* GetData(const CArray<T>& input) { return input.data(); }
 
-  static T& GetAt(CArray<T>& input, size_t index) { return input.data[index]; }
+  static T& GetAt(CArray<T>& input, size_t index) {
+    return input.data()[index];
+  }
 
   static const T& GetAt(const CArray<T>& input, size_t index) {
-    return input.data[index];
+    return input.data()[index];
   }
 
   static bool Resize(CArray<T>& input, size_t size) {
-    if (size > input.max_size)
+    if (size > input.size())
       return false;
-
-    input.size = size;
+    input = input.subspan(0, size);
     return true;
   }
 };
@@ -61,14 +93,16 @@
 struct ArrayTraits<ConstCArray<T>> {
   using Element = T;
 
-  static bool IsNull(const ConstCArray<T>& input) { return !input.data; }
+  static bool IsNull(const ConstCArray<T>& input) { return !input.data(); }
 
-  static size_t GetSize(const ConstCArray<T>& input) { return input.size; }
+  static void SetToNull(ConstCArray<T>* output) { *output = ConstCArray<T>(); }
 
-  static const T* GetData(const ConstCArray<T>& input) { return input.data; }
+  static size_t GetSize(const ConstCArray<T>& input) { return input.size(); }
+
+  static const T* GetData(const ConstCArray<T>& input) { return input.data(); }
 
   static const T& GetAt(const ConstCArray<T>& input, size_t index) {
-    return input.data[index];
+    return input.data()[index];
   }
 };
 
diff --git a/mojo/public/cpp/bindings/message.h b/mojo/public/cpp/bindings/message.h
index 765f02c..421aa34c 100644
--- a/mojo/public/cpp/bindings/message.h
+++ b/mojo/public/cpp/bindings/message.h
@@ -348,7 +348,7 @@
 // Reports the currently dispatching Message as bad. Note that this is only
 // legal to call from directly within the stack frame of a message dispatch. If
 // you need to do asynchronous work before you can determine the legitimacy of
-// a message, use TakeBadMessageCallback() and retain its result until you're
+// a message, use GetBadMessageCallback() and retain its result until you're
 // ready to invoke or discard it.
 MOJO_CPP_BINDINGS_EXPORT
 void ReportBadMessage(const std::string& error);
diff --git a/mojo/public/tools/fuzzers/BUILD.gn b/mojo/public/tools/fuzzers/BUILD.gn
index 226567c..12d1b9f0 100644
--- a/mojo/public/tools/fuzzers/BUILD.gn
+++ b/mojo/public/tools/fuzzers/BUILD.gn
@@ -20,10 +20,28 @@
 
 fuzzer_test("mojo_parse_message_fuzzer") {
   sources = [
+    "fuzz_impl.cc",
     "mojo_parse_message_fuzzer.cc",
   ]
   deps = [
     ":fuzz_mojom",
     "//mojo/edk/system",
   ]
+  seed_corpus = "//mojo/public/tools/fuzzers/message_corpus"
+}
+
+# MessageDumper is not meant to work on Windows.
+if (!is_win) {
+  executable("mojo_fuzzer_message_dump") {
+    sources = [
+      "fuzz_impl.cc",
+      "mojo_fuzzer_message_dump.cc",
+    ]
+    deps = [
+      ":fuzz_mojom",
+      "//base",
+      "//build/config:exe_and_shlib_deps",
+      "//mojo/edk/system",
+    ]
+  }
 }
diff --git a/mojo/public/tools/fuzzers/fuzz_impl.cc b/mojo/public/tools/fuzzers/fuzz_impl.cc
new file mode 100644
index 0000000..313327c5
--- /dev/null
+++ b/mojo/public/tools/fuzzers/fuzz_impl.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "mojo/public/tools/fuzzers/fuzz.mojom.h"
+#include "mojo/public/tools/fuzzers/fuzz_impl.h"
+
+FuzzImpl::FuzzImpl(fuzz::mojom::FuzzInterfaceRequest request)
+    : binding_(this, std::move(request)) {}
+
+FuzzImpl::~FuzzImpl() {}
+
+void FuzzImpl::FuzzBasic() {}
+
+void FuzzImpl::FuzzBasicResp(FuzzBasicRespCallback callback) {
+  std::move(callback).Run();
+}
+
+void FuzzImpl::FuzzBasicSyncResp(FuzzBasicSyncRespCallback callback) {
+  std::move(callback).Run();
+}
+
+void FuzzImpl::FuzzArgs(fuzz::mojom::FuzzStructPtr a,
+                        fuzz::mojom::FuzzStructPtr b) {}
+
+void FuzzImpl::FuzzArgsResp(fuzz::mojom::FuzzStructPtr a,
+                            fuzz::mojom::FuzzStructPtr b,
+                            FuzzArgsRespCallback callback) {
+  std::move(callback).Run();
+}
+
+void FuzzImpl::FuzzArgsSyncResp(fuzz::mojom::FuzzStructPtr a,
+                                fuzz::mojom::FuzzStructPtr b,
+                                FuzzArgsSyncRespCallback callback) {
+  std::move(callback).Run();
+}
diff --git a/mojo/public/tools/fuzzers/fuzz_impl.h b/mojo/public/tools/fuzzers/fuzz_impl.h
new file mode 100644
index 0000000..f2d4774
--- /dev/null
+++ b/mojo/public/tools/fuzzers/fuzz_impl.h
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_PUBLIC_TOOLS_FUZZERS_FUZZ_IMPL_H_
+#define MOJO_PUBLIC_TOOLS_FUZZERS_FUZZ_IMPL_H_
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/tools/fuzzers/fuzz.mojom.h"
+
+class FuzzImpl : public fuzz::mojom::FuzzInterface {
+ public:
+  explicit FuzzImpl(fuzz::mojom::FuzzInterfaceRequest request);
+  ~FuzzImpl() override;
+
+  void FuzzBasic() override;
+  void FuzzBasicResp(FuzzBasicRespCallback callback) override;
+  void FuzzBasicSyncResp(FuzzBasicSyncRespCallback callback) override;
+  void FuzzArgs(fuzz::mojom::FuzzStructPtr a,
+                fuzz::mojom::FuzzStructPtr b) override;
+
+  void FuzzArgsResp(fuzz::mojom::FuzzStructPtr a,
+                    fuzz::mojom::FuzzStructPtr b,
+                    FuzzArgsRespCallback callback) override;
+  void FuzzArgsSyncResp(fuzz::mojom::FuzzStructPtr a,
+                        fuzz::mojom::FuzzStructPtr b,
+                        FuzzArgsSyncRespCallback callback) override;
+
+  /* Expose the binding to the fuzz harness. */
+  mojo::Binding<FuzzInterface> binding_;
+};
+
+#endif  // MOJO_PUBLIC_TOOLS_FUZZERS_FUZZ_IMPL_H_
diff --git a/mojo/public/tools/fuzzers/message_corpus/message_0.mojomsg b/mojo/public/tools/fuzzers/message_corpus/message_0.mojomsg
new file mode 100644
index 0000000..7b5b302
--- /dev/null
+++ b/mojo/public/tools/fuzzers/message_corpus/message_0.mojomsg
Binary files differ
diff --git a/mojo/public/tools/fuzzers/message_corpus/message_1.mojomsg b/mojo/public/tools/fuzzers/message_corpus/message_1.mojomsg
new file mode 100644
index 0000000..945b63c4
--- /dev/null
+++ b/mojo/public/tools/fuzzers/message_corpus/message_1.mojomsg
Binary files differ
diff --git a/mojo/public/tools/fuzzers/message_corpus/message_2.mojomsg b/mojo/public/tools/fuzzers/message_corpus/message_2.mojomsg
new file mode 100644
index 0000000..41715c8
--- /dev/null
+++ b/mojo/public/tools/fuzzers/message_corpus/message_2.mojomsg
Binary files differ
diff --git a/mojo/public/tools/fuzzers/message_corpus/message_3.mojomsg b/mojo/public/tools/fuzzers/message_corpus/message_3.mojomsg
new file mode 100644
index 0000000..d050371
--- /dev/null
+++ b/mojo/public/tools/fuzzers/message_corpus/message_3.mojomsg
Binary files differ
diff --git a/mojo/public/tools/fuzzers/message_corpus/message_4.mojomsg b/mojo/public/tools/fuzzers/message_corpus/message_4.mojomsg
new file mode 100644
index 0000000..380c391
--- /dev/null
+++ b/mojo/public/tools/fuzzers/message_corpus/message_4.mojomsg
Binary files differ
diff --git a/mojo/public/tools/fuzzers/message_corpus/message_5.mojomsg b/mojo/public/tools/fuzzers/message_corpus/message_5.mojomsg
new file mode 100644
index 0000000..1bf4b45
--- /dev/null
+++ b/mojo/public/tools/fuzzers/message_corpus/message_5.mojomsg
Binary files differ
diff --git a/mojo/public/tools/fuzzers/message_corpus/message_6.mojomsg b/mojo/public/tools/fuzzers/message_corpus/message_6.mojomsg
new file mode 100644
index 0000000..8cffad65
--- /dev/null
+++ b/mojo/public/tools/fuzzers/message_corpus/message_6.mojomsg
Binary files differ
diff --git a/mojo/public/tools/fuzzers/message_corpus/message_7.mojomsg b/mojo/public/tools/fuzzers/message_corpus/message_7.mojomsg
new file mode 100644
index 0000000..aeff3d60
--- /dev/null
+++ b/mojo/public/tools/fuzzers/message_corpus/message_7.mojomsg
Binary files differ
diff --git a/mojo/public/tools/fuzzers/message_corpus/message_8.mojomsg b/mojo/public/tools/fuzzers/message_corpus/message_8.mojomsg
new file mode 100644
index 0000000..019f9e6
--- /dev/null
+++ b/mojo/public/tools/fuzzers/message_corpus/message_8.mojomsg
Binary files differ
diff --git a/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc b/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc
new file mode 100644
index 0000000..9f2c5077c1
--- /dev/null
+++ b/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc
@@ -0,0 +1,262 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task_scheduler/task_scheduler.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/public/tools/fuzzers/fuzz.mojom.h"
+#include "mojo/public/tools/fuzzers/fuzz_impl.h"
+
+/* Environment for the executable. Initializes the mojo EDK and sets up a
+ * TaskScheduler, because Mojo messages must be sent and processed from
+ * TaskRunners. */
+struct Environment {
+  Environment() : message_loop() {
+    base::TaskScheduler::CreateAndStartWithDefaultParams(
+        "MojoFuzzerMessageDumpProcess");
+    mojo::edk::Init();
+  }
+
+  /* Message loop to send messages on. */
+  base::MessageLoop message_loop;
+
+  /* Impl to be created. Stored in environment to keep it alive after
+   * DumpMessages returns. */
+  std::unique_ptr<FuzzImpl> impl;
+};
+
+Environment* env = new Environment();
+
+/* MessageReceiver which dumps raw message bytes to disk in the provided
+ * directory. */
+class MessageDumper : public mojo::MessageReceiver {
+ public:
+  explicit MessageDumper(std::string directory)
+      : directory_(directory), count_(0) {}
+
+  bool Accept(mojo::Message* message) override {
+    base::FilePath path = directory_.Append(FILE_PATH_LITERAL("message_") +
+                                            base::IntToString(count_++) +
+                                            FILE_PATH_LITERAL(".mojomsg"));
+
+    base::File file(path,
+                    base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+    if (!file.IsValid()) {
+      LOG(ERROR) << "Failed to create mojo message file: " << path.value();
+      return false;
+    }
+
+    size_t size = message->data_num_bytes();
+    const char* data = reinterpret_cast<const char*>(message->data());
+    int ret = file.WriteAtCurrentPos(data, size);
+    if (ret != static_cast<int>(size)) {
+      LOG(ERROR) << "Failed to write " << size << " bytes.";
+      return false;
+    }
+    return true;
+  }
+
+  base::FilePath directory_;
+  int count_;
+};
+
+/* Returns a FuzzUnion with fuzz_bool initialized. */
+auto GetBoolFuzzUnion() {
+  fuzz::mojom::FuzzUnionPtr union_bool = fuzz::mojom::FuzzUnion::New();
+  union_bool->set_fuzz_bool(true);
+  return union_bool;
+}
+
+/* Returns a FuzzUnion with fuzz_struct_map initialized. Takes in a
+ * FuzzDummyStructPtr to use within the fuzz_struct_map value. */
+auto GetStructMapFuzzUnion(fuzz::mojom::FuzzDummyStructPtr in) {
+  fuzz::mojom::FuzzUnionPtr union_struct_map = fuzz::mojom::FuzzUnion::New();
+  std::unordered_map<std::string, fuzz::mojom::FuzzDummyStructPtr> struct_map;
+  struct_map["fuzz"] = std::move(in);
+  union_struct_map->set_fuzz_struct_map(std::move(struct_map));
+  return union_struct_map;
+}
+
+/* Returns a FuzzUnion with fuzz_complex initialized. Takes in a FuzzUnionPtr
+ * to use within the fuzz_complex value. */
+auto GetComplexFuzzUnion(fuzz::mojom::FuzzUnionPtr in) {
+  std::remove_reference<decltype(in->get_fuzz_complex())>::type complex_map;
+  std::remove_reference<decltype(complex_map.value()[0])>::type outer;
+  std::remove_reference<decltype(
+      outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0])>::type inner;
+  std::remove_reference<decltype(inner['z'])>::type center;
+
+  center.emplace();
+  center.value().push_back(std::move(in));
+  inner['z'] = std::move(center);
+  outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0] = std::move(inner);
+  complex_map.emplace();
+  complex_map.value().push_back(std::move(outer));
+
+  fuzz::mojom::FuzzUnionPtr union_complex = fuzz::mojom::FuzzUnion::New();
+  union_complex->set_fuzz_complex(std::move(complex_map));
+  return union_complex;
+}
+
+/* Returns a populated value for FuzzStruct->fuzz_primitive_array. */
+auto GetFuzzStructPrimitiveArrayValue() {
+  decltype(fuzz::mojom::FuzzStruct::fuzz_primitive_array) primitive_array;
+  primitive_array = {'f', 'u', 'z', 'z'};
+  return primitive_array;
+}
+
+/* Returns a populated value for FuzzStruct->fuzz_primitive_map. */
+auto GetFuzzStructPrimitiveMapValue() {
+  decltype(fuzz::mojom::FuzzStruct::fuzz_primitive_map) primitive_map;
+  primitive_map["fuzz"] = 'z';
+  return primitive_map;
+}
+
+/* Returns a populated value for FuzzStruct->fuzz_array_map. */
+auto GetFuzzStructArrayMapValue() {
+  decltype(fuzz::mojom::FuzzStruct::fuzz_array_map) array_map;
+  array_map["fuzz"] = {"fuzz1", "fuzz2"};
+  return array_map;
+}
+
+/* Returns a populated value for FuzzStruct->fuzz_union_map. Takes in a
+ * FuzzUnionPtr to use within the fuzz_union_map value.*/
+auto GetFuzzStructUnionMapValue(fuzz::mojom::FuzzUnionPtr in) {
+  decltype(fuzz::mojom::FuzzStruct::fuzz_union_map) union_map;
+  union_map[fuzz::mojom::FuzzEnum::FUZZ_VALUE1] = std::move(in);
+  return union_map;
+}
+
+/* Returns a populated value for FuzzStruct->fuzz_union_array. Takes in a
+ * FuzzUnionPtr to use within the fuzz_union_array value.*/
+auto GetFuzzStructUnionArrayValue(fuzz::mojom::FuzzUnionPtr in) {
+  decltype(fuzz::mojom::FuzzStruct::fuzz_union_array) union_array;
+  union_array.push_back(std::move(in));
+  return union_array;
+}
+
+/* Returns a populated value for FuzzStruct->fuzz_struct_array. Takes in a
+ * FuzzStructPtr to use within the fuzz_struct_array value. */
+auto GetFuzzStructStructArrayValue(fuzz::mojom::FuzzStructPtr in) {
+  decltype(fuzz::mojom::FuzzStruct::fuzz_struct_array) struct_array;
+  struct_array.push_back(std::move(in));
+  return struct_array;
+}
+
+/* Returns a populated value for FuzzStruct->fuzz_nullable_array. */
+auto GetFuzzStructNullableArrayValue() {
+  decltype(fuzz::mojom::FuzzStruct::fuzz_nullable_array) nullable_array;
+  return nullable_array;
+}
+
+/* Returns a populated value for FuzzStruct->fuzz_complex. */
+auto GetFuzzStructComplexValue() {
+  decltype(fuzz::mojom::FuzzStruct::fuzz_complex) complex_map;
+  std::remove_reference<decltype(complex_map.value()[0])>::type outer;
+  std::remove_reference<decltype(
+      outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0])>::type inner;
+  std::remove_reference<decltype(inner['z'])>::type center;
+
+  center.emplace();
+  center.value().push_back(fuzz::mojom::FuzzStruct::New());
+  inner['z'] = std::move(center);
+  outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0] = std::move(inner);
+  complex_map.emplace();
+  complex_map.value().push_back(std::move(outer));
+  return complex_map;
+}
+
+/* Returns a FuzzStruct with its fields populated. */
+fuzz::mojom::FuzzStructPtr GetPopulatedFuzzStruct() {
+  /* Make some populated Unions. */
+  auto union_bool = GetBoolFuzzUnion();
+  auto union_struct_map =
+      GetStructMapFuzzUnion(fuzz::mojom::FuzzDummyStruct::New());
+  auto union_complex = GetComplexFuzzUnion(std::move(union_bool));
+
+  /* Prepare the nontrivial fields for the struct. */
+  auto fuzz_primitive_array = GetFuzzStructPrimitiveArrayValue();
+  auto fuzz_primitive_map = GetFuzzStructPrimitiveMapValue();
+  auto fuzz_array_map = GetFuzzStructArrayMapValue();
+  auto fuzz_union_map = GetFuzzStructUnionMapValue(std::move(union_struct_map));
+  auto fuzz_union_array =
+      GetFuzzStructUnionArrayValue(std::move(union_complex));
+  auto fuzz_struct_array =
+      GetFuzzStructStructArrayValue(fuzz::mojom::FuzzStruct::New());
+  auto fuzz_nullable_array = GetFuzzStructNullableArrayValue();
+  auto fuzz_complex = GetFuzzStructComplexValue();
+
+  /* Make a populated struct and return it. */
+  return fuzz::mojom::FuzzStruct::New(
+      true,                            /* fuzz_bool */
+      -1,                              /* fuzz_int8 */
+      1,                               /* fuzz_uint8 */
+      -(1 << 8),                       /* fuzz_int16 */
+      1 << 8,                          /* fuzz_uint16 */
+      -(1 << 16),                      /* fuzz_int32 */
+      1 << 16,                         /* fuzz_uint32 */
+      -((int64_t)1 << 32),             /* fuzz_int64 */
+      (uint64_t)1 << 32,               /* fuzz_uint64 */
+      1.0,                             /* fuzz_float */
+      1.0,                             /* fuzz_double */
+      "fuzz",                          /* fuzz_string */
+      std::move(fuzz_primitive_array), /* fuzz_primitive_array */
+      std::move(fuzz_primitive_map),   /* fuzz_primitive_map */
+      std::move(fuzz_array_map),       /* fuzz_array_map */
+      std::move(fuzz_union_map),       /* fuzz_union_map */
+      std::move(fuzz_union_array),     /* fuzz_union_array */
+      std::move(fuzz_struct_array),    /* fuzz_struct_array */
+      std::move(fuzz_nullable_array),  /* fuzz_nullable_array */
+      std::move(fuzz_complex));        /* fuzz_complex */
+}
+
+/* Callback used for messages with responses. Does nothing. */
+void FuzzCallback() {}
+
+/* Invokes each method in the FuzzInterface and dumps the messages to the
+ * supplied directory. */
+void DumpMessages(std::string output_directory) {
+  fuzz::mojom::FuzzInterfacePtr fuzz;
+
+  /* Create the impl and add a MessageDumper to the filter chain. */
+  env->impl = base::MakeUnique<FuzzImpl>(MakeRequest(&fuzz));
+  env->impl->binding_.AddFilter(
+      base::MakeUnique<MessageDumper>(output_directory));
+
+  /* Call methods in various ways to generate interesting messages. */
+  fuzz->FuzzBasic();
+  fuzz->FuzzBasicResp(base::Bind(FuzzCallback));
+  fuzz->FuzzBasicSyncResp();
+  fuzz->FuzzArgs(fuzz::mojom::FuzzStruct::New(),
+                 fuzz::mojom::FuzzStructPtr(nullptr));
+  fuzz->FuzzArgs(fuzz::mojom::FuzzStruct::New(), GetPopulatedFuzzStruct());
+  fuzz->FuzzArgsResp(fuzz::mojom::FuzzStruct::New(), GetPopulatedFuzzStruct(),
+                     base::Bind(FuzzCallback));
+  fuzz->FuzzArgsResp(fuzz::mojom::FuzzStruct::New(), GetPopulatedFuzzStruct(),
+                     base::Bind(FuzzCallback));
+  fuzz->FuzzArgsSyncResp(fuzz::mojom::FuzzStruct::New(),
+                         GetPopulatedFuzzStruct(), base::Bind(FuzzCallback));
+  fuzz->FuzzArgsSyncResp(fuzz::mojom::FuzzStruct::New(),
+                         GetPopulatedFuzzStruct(), base::Bind(FuzzCallback));
+}
+
+int main(int argc, char** argv) {
+  if (argc < 2) {
+    printf("Usage: %s [output_directory]\n", argv[0]);
+    exit(1);
+  }
+  std::string output_directory(argv[1]);
+
+  /* Dump the messages from a MessageLoop, and wait for it to finish. */
+  env->message_loop.task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&DumpMessages, output_directory));
+  base::RunLoop().RunUntilIdle();
+
+  return 0;
+}
diff --git a/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc b/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc
index d4620b4..0c4fb90 100644
--- a/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc
+++ b/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc
@@ -2,52 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <stddef.h>
-#include <stdint.h>
-
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/task_scheduler/task_scheduler.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/tools/fuzzers/fuzz.mojom.h"
-
-/* Dummy implementation of the FuzzInterface. */
-class FuzzImpl : public fuzz::mojom::FuzzInterface {
- public:
-  explicit FuzzImpl(fuzz::mojom::FuzzInterfaceRequest request)
-      : binding_(this, std::move(request)) {}
-
-  void FuzzBasic() override {}
-
-  void FuzzBasicResp(FuzzBasicRespCallback callback) override {
-    std::move(callback).Run();
-  }
-
-  void FuzzBasicSyncResp(FuzzBasicSyncRespCallback callback) override {
-    std::move(callback).Run();
-  }
-
-  void FuzzArgs(fuzz::mojom::FuzzStructPtr a,
-                fuzz::mojom::FuzzStructPtr b) override {}
-
-  void FuzzArgsResp(fuzz::mojom::FuzzStructPtr a,
-                    fuzz::mojom::FuzzStructPtr b,
-                    FuzzArgsRespCallback callback) override {
-    std::move(callback).Run();
-  };
-
-  void FuzzArgsSyncResp(fuzz::mojom::FuzzStructPtr a,
-                        fuzz::mojom::FuzzStructPtr b,
-                        FuzzArgsSyncRespCallback callback) override {
-    std::move(callback).Run();
-  };
-
-  ~FuzzImpl() override {}
-
-  /* Expose the binding to the fuzz harness. */
-  mojo::Binding<FuzzInterface> binding_;
-};
+#include "mojo/public/tools/fuzzers/fuzz_impl.h"
 
 void FuzzMessage(const uint8_t* data, size_t size, base::RunLoop* run) {
   fuzz::mojom::FuzzInterfacePtr fuzz;
diff --git a/net/cert/internal/trust_store_nss_unittest.cc b/net/cert/internal/trust_store_nss_unittest.cc
index 53f4ef1..498a25c6 100644
--- a/net/cert/internal/trust_store_nss_unittest.cc
+++ b/net/cert/internal/trust_store_nss_unittest.cc
@@ -58,15 +58,12 @@
   }
 
   void AddCertToNSS(const ParsedCertificate* cert) {
-    std::string nickname = GetUniqueNickname();
-    ScopedCERTCertificate nss_cert(
-        X509Certificate::CreateOSCertHandleFromBytesWithNickname(
-            cert->der_cert().AsStringPiece().data(), cert->der_cert().Length(),
-            nickname.c_str()));
+    ScopedCERTCertificate nss_cert(X509Certificate::CreateOSCertHandleFromBytes(
+        cert->der_cert().AsStringPiece().data(), cert->der_cert().Length()));
     ASSERT_TRUE(nss_cert);
-    SECStatus srv =
-        PK11_ImportCert(test_nssdb_.slot(), nss_cert.get(), CK_INVALID_HANDLE,
-                        nickname.c_str(), PR_FALSE /* includeTrust (unused) */);
+    SECStatus srv = PK11_ImportCert(
+        test_nssdb_.slot(), nss_cert.get(), CK_INVALID_HANDLE,
+        GetUniqueNickname().c_str(), PR_FALSE /* includeTrust (unused) */);
     ASSERT_EQ(SECSuccess, srv);
   }
 
@@ -246,15 +243,12 @@
 
   void AddCert(scoped_refptr<ParsedCertificate> cert) {
     ASSERT_TRUE(test_nssdb_.is_open());
-    std::string nickname = GetUniqueNickname();
-    ScopedCERTCertificate nss_cert(
-        X509Certificate::CreateOSCertHandleFromBytesWithNickname(
-            cert->der_cert().AsStringPiece().data(), cert->der_cert().Length(),
-            nickname.c_str()));
+    ScopedCERTCertificate nss_cert(X509Certificate::CreateOSCertHandleFromBytes(
+        cert->der_cert().AsStringPiece().data(), cert->der_cert().Length()));
     ASSERT_TRUE(nss_cert);
-    SECStatus srv =
-        PK11_ImportCert(test_nssdb_.slot(), nss_cert.get(), CK_INVALID_HANDLE,
-                        nickname.c_str(), PR_FALSE /* includeTrust (unused) */);
+    SECStatus srv = PK11_ImportCert(
+        test_nssdb_.slot(), nss_cert.get(), CK_INVALID_HANDLE,
+        GetUniqueNickname().c_str(), PR_FALSE /* includeTrust (unused) */);
     ASSERT_EQ(SECSuccess, srv);
   }
 
diff --git a/net/cert/x509_certificate.h b/net/cert/x509_certificate.h
index eef7454..657a391f 100644
--- a/net/cert/x509_certificate.h
+++ b/net/cert/x509_certificate.h
@@ -283,16 +283,6 @@
   static OSCertHandle CreateOSCertHandleFromBytes(const char* data,
                                                   size_t length);
 
-#if defined(USE_NSS_CERTS)
-  // Creates an OS certificate handle from the DER-encoded representation.
-  // Returns NULL on failure.  Sets the default nickname if |nickname| is
-  // non-NULL.
-  static OSCertHandle CreateOSCertHandleFromBytesWithNickname(
-      const char* data,
-      size_t length,
-      const char* nickname);
-#endif
-
   // Creates all possible OS certificate handles from |data| encoded in a
   // specific |format|. Returns an empty collection on failure.
   static OSCertHandles CreateOSCertHandlesFromBytes(const char* data,
diff --git a/net/cert/x509_certificate_nss.cc b/net/cert/x509_certificate_nss.cc
index 19f0f98..cf6de0a 100644
--- a/net/cert/x509_certificate_nss.cc
+++ b/net/cert/x509_certificate_nss.cc
@@ -305,14 +305,6 @@
 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
     const char* data,
     size_t length) {
-  return CreateOSCertHandleFromBytesWithNickname(data, length, NULL);
-}
-
-// static
-X509Certificate::OSCertHandle
-X509Certificate::CreateOSCertHandleFromBytesWithNickname(const char* data,
-                                                         size_t length,
-                                                         const char* nickname) {
   crypto::EnsureNSSInit();
 
   if (!NSS_IsInitialized())
@@ -325,8 +317,8 @@
 
   // Parse into a certificate structure.
   return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert,
-                                 const_cast<char*>(nickname),
-                                 PR_FALSE, PR_TRUE);
+                                 nullptr /* nickname */, PR_FALSE /* is_perm */,
+                                 PR_TRUE /* copyDER */);
 }
 
 // static
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc
index 8d6ee47..67c8e04 100644
--- a/net/cert/x509_certificate_unittest.cc
+++ b/net/cert/x509_certificate_unittest.cc
@@ -17,17 +17,12 @@
 #include "crypto/rsa_private_key.h"
 #include "net/base/net_errors.h"
 #include "net/cert/asn1_util.h"
-#include "net/cert/x509_util_nss.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_certificate_data.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/url_features.h"
 
-#if defined(USE_NSS_CERTS)
-#include <cert.h>
-#endif
-
 using base::HexEncode;
 using base::Time;
 
@@ -585,29 +580,6 @@
   EXPECT_EQ(0u, ip_addresses.size());
 }
 
-#if defined(USE_NSS_CERTS)
-TEST(X509CertificateTest, ParseClientSubjectAltNames) {
-  base::FilePath certs_dir = GetTestCertsDirectory();
-
-  // This cert contains one rfc822Name field, and one Microsoft UPN
-  // otherName field.
-  scoped_refptr<X509Certificate> san_cert =
-      ImportCertFromFile(certs_dir, "client_3.pem");
-  ASSERT_NE(static_cast<X509Certificate*>(NULL), san_cert.get());
-
-  std::vector<std::string> rfc822_names;
-  net::x509_util::GetRFC822SubjectAltNames(san_cert->os_cert_handle(),
-                                           &rfc822_names);
-  ASSERT_EQ(1U, rfc822_names.size());
-  EXPECT_EQ("santest@example.com", rfc822_names[0]);
-
-  std::vector<std::string> upn_names;
-  net::x509_util::GetUPNSubjectAltNames(san_cert->os_cert_handle(), &upn_names);
-  ASSERT_EQ(1U, upn_names.size());
-  EXPECT_EQ("santest@ad.corp.example.com", upn_names[0]);
-}
-#endif  // defined(USE_NSS_CERTS)
-
 TEST(X509CertificateTest, ExtractSPKIFromDERCert) {
   base::FilePath certs_dir = GetTestCertsDirectory();
   scoped_refptr<X509Certificate> cert =
diff --git a/net/cert/x509_util_nss_unittest.cc b/net/cert/x509_util_nss_unittest.cc
index 49c0f57a..8ddcc3b 100644
--- a/net/cert/x509_util_nss_unittest.cc
+++ b/net/cert/x509_util_nss_unittest.cc
@@ -60,4 +60,25 @@
   EXPECT_EQ(test_cert->subject().GetDisplayName(), name);
 }
 
+TEST(X509UtilNSSTest, ParseClientSubjectAltNames) {
+  base::FilePath certs_dir = GetTestCertsDirectory();
+
+  // This cert contains one rfc822Name field, and one Microsoft UPN
+  // otherName field.
+  scoped_refptr<X509Certificate> san_cert =
+      ImportCertFromFile(certs_dir, "client_3.pem");
+  ASSERT_NE(static_cast<X509Certificate*>(NULL), san_cert.get());
+
+  std::vector<std::string> rfc822_names;
+  x509_util::GetRFC822SubjectAltNames(san_cert->os_cert_handle(),
+                                      &rfc822_names);
+  ASSERT_EQ(1U, rfc822_names.size());
+  EXPECT_EQ("santest@example.com", rfc822_names[0]);
+
+  std::vector<std::string> upn_names;
+  x509_util::GetUPNSubjectAltNames(san_cert->os_cert_handle(), &upn_names);
+  ASSERT_EQ(1U, upn_names.size());
+  EXPECT_EQ("santest@ad.corp.example.com", upn_names[0]);
+}
+
 }  // namespace net
diff --git a/net/http/http_stream_factory_impl_job_controller.cc b/net/http/http_stream_factory_impl_job_controller.cc
index a5815ad..5660ab3 100644
--- a/net/http/http_stream_factory_impl_job_controller.cc
+++ b/net/http/http_stream_factory_impl_job_controller.cc
@@ -518,8 +518,8 @@
     }
   }
 
-  // Notify other requests that have the same SpdySessionKey. |request_| and
-  // |bounded_job_| might be deleted already.
+  // Notify other requests that have the same SpdySessionKey.
+  // |request_| and |bound_job_| might be deleted already.
   if (spdy_session && spdy_session->IsAvailable()) {
     spdy_session_pool->OnNewSpdySessionReady(
         spdy_session, direct, used_ssl_config, used_proxy_info,
@@ -845,13 +845,12 @@
   // Alternative Service can only be set for HTTPS requests while Alternative
   // Proxy is set for HTTP requests.
   if (alternative_service_info_.protocol() != kProtoUnknown) {
-    // Never share connection with other jobs for FTP requests.
+    DCHECK(request_info_.url.SchemeIs(url::kHttpsScheme));
     DVLOG(1) << "Selected alternative service (host: "
              << alternative_service_info_.host_port_pair().host()
              << " port: " << alternative_service_info_.host_port_pair().port()
              << " version: " << quic_version << ")";
 
-    DCHECK(!request_info_.url.SchemeIs(url::kFtpScheme));
     HostPortPair alternative_destination(
         alternative_service_info_.host_port_pair());
     ignore_result(
@@ -928,14 +927,17 @@
   if (bound_job_->job_type() == MAIN && alternative_job_) {
     DCHECK(!for_websockets());
     alternative_job_->Orphan();
-  } else if (bound_job_->job_type() == ALTERNATIVE && main_job_) {
+    return;
+  }
+
+  if (bound_job_->job_type() == ALTERNATIVE && main_job_) {
     // Orphan main job.
     // If ResumeMainJob() is not executed, reset |main_job_|. Otherwise,
     // OnOrphanedJobComplete() will clean up |this| when the job completes.
     // Use |main_job_is_blocked_| and |!main_job_wait_time_.is_zero()| instead
     // of |main_job_|->is_waiting() because |main_job_| can be in proxy
     // resolution step.
-    if (main_job_ && (main_job_is_blocked_ || !main_job_wait_time_.is_zero())) {
+    if (main_job_is_blocked_ || !main_job_wait_time_.is_zero()) {
       DCHECK(alternative_job_);
       main_job_.reset();
     } else {
@@ -993,10 +995,10 @@
   alternative_job_net_error_ = net_error;
 
   if (IsJobOrphaned(alternative_job_.get())) {
-    // If |request_| is gone then it must have been successfully served by
+    // If |request_| is gone, then it must have been successfully served by
     // |main_job_|.
     // If |request_| is bound to a different job, then it is being
-    // successfully serverd by the main job.
+    // successfully served by the main job.
     ReportBrokenAlternativeService();
   }
 }
@@ -1007,7 +1009,7 @@
   DCHECK_NE(OK, net_error);
   DCHECK(alternative_job_->alternative_proxy_server().is_valid());
 
-  // Need to mark alt proxy as broken regardless whether the job is bound.
+  // Need to mark alt proxy as broken regardless of whether the job is bound.
   ProxyDelegate* proxy_delegate = session_->context().proxy_delegate;
   if (proxy_delegate) {
     proxy_delegate->OnAlternativeProxyBroken(
diff --git a/net/interfaces/ip_address_struct_traits.h b/net/interfaces/ip_address_struct_traits.h
index e1b8684..7aa3ff6 100644
--- a/net/interfaces/ip_address_struct_traits.h
+++ b/net/interfaces/ip_address_struct_traits.h
@@ -14,8 +14,8 @@
 struct StructTraits<net::interfaces::IPAddressDataView, net::IPAddress> {
   static mojo::ConstCArray<uint8_t> address_bytes(
       const net::IPAddress& ip_address) {
-    return mojo::ConstCArray<uint8_t>(ip_address.bytes().size(),
-                                      ip_address.bytes().data());
+    return mojo::ConstCArray<uint8_t>(ip_address.bytes().data(),
+                                      ip_address.bytes().size());
   }
 
   static bool Read(net::interfaces::IPAddressDataView obj, net::IPAddress* out);
diff --git a/printing/android/java/src/org/chromium/printing/Printable.java b/printing/android/java/src/org/chromium/printing/Printable.java
index 67ac5d3..5948b3b 100644
--- a/printing/android/java/src/org/chromium/printing/Printable.java
+++ b/printing/android/java/src/org/chromium/printing/Printable.java
@@ -15,4 +15,7 @@
 
     /** Get the title of the generated PDF document. */
     String getTitle();
+
+    /** Check if the current Printable can print. */
+    boolean canPrint();
 }
diff --git a/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java b/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java
index a3dc255..386695c 100644
--- a/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java
+++ b/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java
@@ -188,13 +188,22 @@
 
     @Override
     public void startPendingPrint(PrintingContextInterface printingContext) {
-        if (mIsBusy || mPrintManager == null) {
-            if (mIsBusy) Log.d(TAG, "Pending print can't be started. PrintingController is busy.");
-            else Log.d(TAG, "Pending print can't be started. No PrintManager provided.");
+        boolean canStartPrint = false;
+        if (mIsBusy) {
+            Log.d(TAG, "Pending print can't be started. PrintingController is busy.");
+        } else if (mPrintManager == null) {
+            Log.d(TAG, "Pending print can't be started. No PrintManager provided.");
+        } else if (!mPrintable.canPrint()) {
+            Log.d(TAG, "Pending print can't be started. Printable can't perform printing.");
+        } else {
+            canStartPrint = true;
+        }
 
+        if (!canStartPrint) {
             if (printingContext != null) printingContext.showSystemDialogDone();
             return;
         }
+
         mContextFromScriptInitiation = printingContext;
         mIsBusy = true;
         mPrintDocumentAdapterWrapper.print(mPrintManager, mPrintable.getTitle());
diff --git a/remoting/host/installer/mac/BUILD.gn b/remoting/host/installer/mac/BUILD.gn
index 973d20d..8e131a7 100644
--- a/remoting/host/installer/mac/BUILD.gn
+++ b/remoting/host/installer/mac/BUILD.gn
@@ -45,7 +45,6 @@
            "--source-files",
          ] + rebase_path(_installer_mac_files, root_build_dir) + [
            "--generated-files",
-           "remoting_host_prefpane.prefPane",
            "remoting_me2me_host.app",
            "native_messaging_host.app",
            "remote_assistance_host.app",
@@ -53,7 +52,6 @@
            "remoting/com.google.chrome.remote_desktop.json",
            "remoting/com.google.chrome.remote_assistance.json",
            "--generated-files-dst",
-           "PreferencePanes/$prefpane_bundle_name",
            "PrivilegedHelperTools/$host_bundle_name",
            "PrivilegedHelperTools/$host_bundle_name/Contents/MacOS/$native_messaging_host_bundle_name",
            "PrivilegedHelperTools/$host_bundle_name/Contents/MacOS/$remote_assistance_host_bundle_name",
@@ -79,7 +77,6 @@
            "DMG_FILE_NAME=$host_name_nospace-$chrome_version_full",
            "NATIVE_MESSAGING_HOST_BUNDLE_NAME=$native_messaging_host_bundle_name",
            "REMOTE_ASSISTANCE_HOST_BUNDLE_NAME=$remote_assistance_host_bundle_name",
-           "PREFPANE_BUNDLE_NAME=$prefpane_bundle_name",
          ]
 
   deps = [
@@ -88,7 +85,6 @@
     "//remoting/host:remoting_native_messaging_host",
     "//remoting/host:remoting_native_messaging_manifests",
     "//remoting/host/it2me:remote_assistance_host",
-    "//remoting/host/mac:remoting_host_prefpane.prefPane",
   ]
 }
 
diff --git a/remoting/host/installer/mac/ChromotingHostService.pkgproj b/remoting/host/installer/mac/ChromotingHostService.pkgproj
index b5de5cb..8e99b07 100644
--- a/remoting/host/installer/mac/ChromotingHostService.pkgproj
+++ b/remoting/host/installer/mac/ChromotingHostService.pkgproj
@@ -127,7 +127,7 @@
 														<key>GID</key>
 														<integer>0</integer>
 														<key>PATH</key>
-														<string>Config/com.google.chrome.remote_desktop.json</string>
+														<string>Config/com.google.chrome.remote_assistance.json</string>
 														<key>PATH_TYPE</key>
 														<integer>1</integer>
 														<key>PERMISSIONS</key>
@@ -143,7 +143,7 @@
 														<key>GID</key>
 														<integer>0</integer>
 														<key>PATH</key>
-														<string>Config/com.google.chrome.remote_assistance.json</string>
+														<string>Config/com.google.chrome.remote_desktop.json</string>
 														<key>PATH_TYPE</key>
 														<integer>1</integer>
 														<key>PERMISSIONS</key>
@@ -262,26 +262,7 @@
 							</dict>
 							<dict>
 								<key>CHILDREN</key>
-								<array>
-									<dict>
-										<key>BUNDLE_CAN_DOWNGRADE</key>
-										<true/>
-										<key>CHILDREN</key>
-										<array/>
-										<key>GID</key>
-										<integer>0</integer>
-										<key>PATH</key>
-										<string>PreferencePanes/@@PREFPANE_BUNDLE_NAME@@</string>
-										<key>PATH_TYPE</key>
-										<integer>1</integer>
-										<key>PERMISSIONS</key>
-										<integer>493</integer>
-										<key>TYPE</key>
-										<integer>3</integer>
-										<key>UID</key>
-										<integer>0</integer>
-									</dict>
-								</array>
+								<array/>
 								<key>GID</key>
 								<integer>0</integer>
 								<key>PATH</key>
@@ -331,12 +312,14 @@
 								<key>CHILDREN</key>
 								<array>
 									<dict>
+										<key>BUNDLE_CAN_DOWNGRADE</key>
+										<true/>
 										<key>CHILDREN</key>
 										<array/>
 										<key>GID</key>
 										<integer>0</integer>
 										<key>PATH</key>
-										<string>PrivilegedHelperTools/org.chromium.chromoting.me2me.sh</string>
+										<string>PrivilegedHelperTools/@@HOST_BUNDLE_NAME@@</string>
 										<key>PATH_TYPE</key>
 										<integer>1</integer>
 										<key>PERMISSIONS</key>
@@ -347,14 +330,12 @@
 										<integer>0</integer>
 									</dict>
 									<dict>
-										<key>BUNDLE_CAN_DOWNGRADE</key>
-										<true/>
 										<key>CHILDREN</key>
 										<array/>
 										<key>GID</key>
 										<integer>0</integer>
 										<key>PATH</key>
-										<string>PrivilegedHelperTools/@@HOST_BUNDLE_NAME@@</string>
+										<string>PrivilegedHelperTools/org.chromium.chromoting.me2me.sh</string>
 										<key>PATH_TYPE</key>
 										<integer>1</integer>
 										<key>PERMISSIONS</key>
diff --git a/remoting/host/installer/mac/PrivilegedHelperTools/org.chromium.chromoting.me2me.sh b/remoting/host/installer/mac/PrivilegedHelperTools/org.chromium.chromoting.me2me.sh
index b46b7a0..1d66189 100755
--- a/remoting/host/installer/mac/PrivilegedHelperTools/org.chromium.chromoting.me2me.sh
+++ b/remoting/host/installer/mac/PrivilegedHelperTools/org.chromium.chromoting.me2me.sh
@@ -6,13 +6,11 @@
 
 NAME=org.chromium.chromoting
 HOST_BUNDLE_NAME=@@HOST_BUNDLE_NAME@@
-PREFPANE_BUNDLE_NAME=@@PREFPANE_BUNDLE_NAME@@
 CONFIG_DIR=/Library/PrivilegedHelperTools
 ENABLED_FILE=$CONFIG_DIR/$NAME.me2me_enabled
 CONFIG_FILE=$CONFIG_DIR/$NAME.json
 HOST_EXE=$CONFIG_DIR/$HOST_BUNDLE_NAME/Contents/MacOS/remoting_me2me_host
 PLIST_FILE=$CONFIG_DIR/$HOST_BUNDLE_NAME/Contents/Info.plist
-PREF_PANE_BUNDLE=/Library/PreferencePanes/$PREFPANE_BUNDLE_NAME
 
 # The exit code returned by 'wait' when a process is terminated by SIGTERM.
 SIGTERM_EXIT_CODE=143
@@ -148,11 +146,6 @@
   cat > "$CONFIG_FILE"
 elif [[ "$1" = "--host-version" ]]; then
   /usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$PLIST_FILE"
-elif [[ "$1" = "--relaunch-prefpane" ]]; then
-  # Wait for the parent (System Preferences applet) to die, by reading from
-  # stdin until the pipe is broken.
-  cat 2>/dev/null || true
-  open "$PREF_PANE_BUNDLE"
 elif [[ "$1" = "--run-from-launchd" ]]; then
   echo Host started for user $USER at $"$(date)"
   run_host
diff --git a/remoting/host/installer/mac/Scripts/remoting_preflight.sh b/remoting/host/installer/mac/Scripts/remoting_preflight.sh
index e7eb294..372e0541 100755
--- a/remoting/host/installer/mac/Scripts/remoting_preflight.sh
+++ b/remoting/host/installer/mac/Scripts/remoting_preflight.sh
@@ -14,6 +14,7 @@
 PLIST=/Library/LaunchAgents/org.chromium.chromoting.plist
 ENABLED_FILE="$HELPERTOOLS/$SERVICE_NAME.me2me_enabled"
 ENABLED_FILE_BACKUP="$ENABLED_FILE.backup"
+PREF_PANE=/Library/PreferencePanes/ChromeRemoteDesktop.prefPane
 
 # In case of errors, log the fact, but continue to unload launchd jobs as much
 # as possible. When finished, this preflight script should exit successfully in
@@ -103,4 +104,8 @@
   fi
 done
 
+# The installer no longer includes a preference-pane applet, so remove any
+# pref-pane from a previous installation.
+rm -rf "$PREF_PANE"
+
 exit 0
diff --git a/remoting/host/installer/mac/do_signing.props b/remoting/host/installer/mac/do_signing.props
index d5ecce81..0e5b512 100644
--- a/remoting/host/installer/mac/do_signing.props
+++ b/remoting/host/installer/mac/do_signing.props
@@ -4,5 +4,4 @@
 HOST_PKG=@@HOST_PKG@@
 HOST_UNINSTALLER_NAME=@@HOST_UNINSTALLER_NAME@@
 NATIVE_MESSAGING_HOST_BUNDLE_NAME=@@NATIVE_MESSAGING_HOST_BUNDLE_NAME@@
-PREFPANE_BUNDLE_NAME=@@PREFPANE_BUNDLE_NAME@@
 REMOTE_ASSISTANCE_HOST_BUNDLE_NAME=@@REMOTE_ASSISTANCE_HOST_BUNDLE_NAME@@
diff --git a/remoting/host/installer/mac/do_signing.sh b/remoting/host/installer/mac/do_signing.sh
index 5ef98405..a8f5493 100755
--- a/remoting/host/installer/mac/do_signing.sh
+++ b/remoting/host/installer/mac/do_signing.sh
@@ -37,7 +37,6 @@
   HOST_UNINSTALLER_NAME=$(read_property "HOST_UNINSTALLER_NAME")
   NATIVE_MESSAGING_HOST_BUNDLE_NAME=$(read_property\
     "NATIVE_MESSAGING_HOST_BUNDLE_NAME")
-  PREFPANE_BUNDLE_NAME=$(read_property "PREFPANE_BUNDLE_NAME")
   REMOTE_ASSISTANCE_HOST_BUNDLE_NAME=$(read_property\
     "REMOTE_ASSISTANCE_HOST_BUNDLE_NAME")
 
@@ -50,7 +49,6 @@
                 `"${REMOTE_ASSISTANCE_HOST_BUNDLE_NAME}/Contents/MacOS/"`
                 `"remote_assistance_host"
   UNINSTALLER="Applications/${HOST_UNINSTALLER_NAME}.app"
-  PREFPANE="PreferencePanes/${PREFPANE_BUNDLE_NAME}"
 
   # The Chromoting Host installer is a meta-package that consists of 3
   # components:
@@ -145,7 +143,6 @@
   sign "${input_dir}/${IT2ME_NM_HOST}" "${keychain}" "${id}"
   sign "${input_dir}/${ME2ME_HOST}" "${keychain}" "${id}"
   sign "${input_dir}/${UNINSTALLER}" "${keychain}" "${id}"
-  sign "${input_dir}/${PREFPANE}" "${keychain}" "${id}"
 }
 
 sign_installer() {
diff --git a/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm b/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
index 4396df194..012646e8 100644
--- a/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
+++ b/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
@@ -137,7 +137,6 @@
   [self sudoDelete:remoting::kHostBinaryPath usingAuth:authRef];
   [self sudoDelete:remoting::kHostHelperScriptPath usingAuth:authRef];
   [self sudoDelete:remoting::kHostConfigFilePath usingAuth:authRef];
-  [self sudoDelete:remoting::kPrefPaneFilePath usingAuth:authRef];
   [self sudoDelete:remoting::kLogFilePath usingAuth:authRef];
   [self sudoDelete:remoting::kLogFileConfigPath usingAuth:authRef];
   [self sudoDelete:remoting::kNativeMessagingManifestPath usingAuth:authRef];
diff --git a/sandbox/win/src/lpc_policy_test.cc b/sandbox/win/src/lpc_policy_test.cc
index 8b8e745..9ff6c38c 100644
--- a/sandbox/win/src/lpc_policy_test.cc
+++ b/sandbox/win/src/lpc_policy_test.cc
@@ -22,6 +22,20 @@
 
 namespace sandbox {
 
+namespace {
+
+bool CsrssDisconnectSupported() {
+  // This functionality has not been verified on versions before Win10.
+  if (base::win::GetVersion() < base::win::VERSION_WIN10)
+    return false;
+#if !defined(_WIN64)
+  // Does not work on 32-bit. See crbug.com/751809.
+  return false;
+#endif  // !defined(_WIN64)
+  return true;
+}
+
+}  // namespace
 // Converts LCID to std::wstring for passing to sbox tests.
 std::wstring LcidToWString(LCID lcid) {
   wchar_t buff[10] = {0};
@@ -179,7 +193,8 @@
   return SBOX_TEST_SUCCEEDED;
 }
 
-TEST(LpcPolicyTest, TestValidProcessHeaps) {
+// Disabled see crbug.com/751809.
+TEST(LpcPolicyTest, DISABLED_TestValidProcessHeaps) {
   TestRunner runner;
   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Lpc_TestValidProcessHeaps"));
 }
@@ -187,8 +202,7 @@
 // All processes should have a shared heap with csrss.exe. This test ensures
 // that this heap can be found.
 TEST(LpcPolicyTest, TestCanFindCsrPortHeap) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10) {
-    // This functionality has not been verified on versions before Win10.
+  if (!CsrssDisconnectSupported()) {
     return;
   }
   HANDLE csr_port_handle = sandbox::FindCsrPortHeap();
@@ -196,7 +210,7 @@
 }
 
 TEST(LpcPolicyTest, TestHeapFlags) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10) {
+  if (!CsrssDisconnectSupported()) {
     // This functionality has not been verified on versions before Win10.
     return;
   }
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index c0916ea6..b8a6459 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -197,7 +197,7 @@
 
   // Disconnect the target from CSRSS when TargetServices::LowerToken() is
   // called inside the target.
-  virtual void SetDisconnectCsrss() = 0;
+  virtual ResultCode SetDisconnectCsrss() = 0;
 
   // Sets the interceptions to operate in strict mode. By default, interceptions
   // are performed in "relaxed" mode, where if something inside NTDLL.DLL is
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
index 391f559..25423e2 100644
--- a/sandbox/win/src/sandbox_policy_base.cc
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -568,11 +568,15 @@
   return true;
 }
 
-void PolicyBase::SetDisconnectCsrss() {
-  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ResultCode PolicyBase::SetDisconnectCsrss() {
+// Does not work on 32-bit.
+#if defined(_WIN64)
+  if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
     is_csrss_connected_ = false;
-    AddKernelObjectToClose(L"ALPC Port", NULL);
+    return AddKernelObjectToClose(L"ALPC Port", NULL);
   }
+#endif  // !defined(_WIN64)
+  return SBOX_ALL_OK;
 }
 
 EvalResult PolicyBase::EvalPolicy(int service,
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index 5fc3f50..1ec005b 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -58,7 +58,7 @@
   MitigationFlags GetProcessMitigations() override;
   ResultCode SetDelayedProcessMitigations(MitigationFlags flags) override;
   MitigationFlags GetDelayedProcessMitigations() const override;
-  void SetDisconnectCsrss() override;
+  ResultCode SetDisconnectCsrss() override;
   void SetStrictInterceptions() override;
   ResultCode SetStdoutHandle(HANDLE handle) override;
   ResultCode SetStderrHandle(HANDLE handle) override;
diff --git a/services/device/generic_sensor/README.md b/services/device/generic_sensor/README.md
index 1050d91..e64ddae 100644
--- a/services/device/generic_sensor/README.md
+++ b/services/device/generic_sensor/README.md
@@ -23,10 +23,10 @@
 | GYROSCOPE                         | TYPE_GYROSCOPE            | in_anglvel                            |                                       | SENSOR_TYPE_GYROMETER_3D                  |
 | MAGNETOMETER                      | TYPE_MAGNETIC_FIELD       | in_magn                               |                                       | SENSOR_TYPE_COMPASS_3D                    |
 | PRESSURE                          |                           |                                       |                                       |                                           |
-| ABSOLUTE_ORIENTATION_EULER_ANGLES |                           |                                       |                                       | SENSOR_TYPE_INCLINOMETER_3D               |
-| ABSOLUTE_ORIENTATION_QUATERNION   | TYPE_ROTATION_VECTOR      |                                       |                                       | SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION |
-| RELATIVE_ORIENTATION_EULER_ANGLES |                           | ACCELEROMETER (*)                     | ACCELEROMETER (*)                     |                                           |
-| RELATIVE_ORIENTATION_QUATERNION   | TYPE_GAME_ROTATION_VECTOR | RELATIVE_ORIENTATION_EULER_ANGLES (*) | RELATIVE_ORIENTATION_EULER_ANGLES (*) |                                           |
+| ABSOLUTE_ORIENTATION_EULER_ANGLES | See below                 |                                       |                                       | SENSOR_TYPE_INCLINOMETER_3D               |
+| ABSOLUTE_ORIENTATION_QUATERNION   | See below                 |                                       |                                       | SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION |
+| RELATIVE_ORIENTATION_EULER_ANGLES | See below                 | ACCELEROMETER (*)                     | ACCELEROMETER (*)                     |                                           |
+| RELATIVE_ORIENTATION_QUATERNION   | See below                 | RELATIVE_ORIENTATION_EULER_ANGLES (*) | RELATIVE_ORIENTATION_EULER_ANGLES (*) |                                           |
 
 (Note: "*" means the sensor type is provided by sensor fusion.)
 
@@ -34,10 +34,28 @@
 
 Sensors are implemented by passing through values provided by the
 [Sensor](https://developer.android.com/reference/android/hardware/Sensor.html)
-class. The values in the "Android" column of the table above correspond to the
-integer constants from the android.hardware.Sensor used to provide data for a
+class. The TYPE_* values in the below descriptions correspond to the integer
+constants from the android.hardware.Sensor used to provide data for a
 SensorType.
 
+For ABSOLUTE_ORIENTATION_EULER_ANGLES, the following sensor fallback is used:
+1. ABSOLUTE_ORIENTATION_QUATERNION (if it uses TYPE_ROTATION_VECTOR
+     directly)
+2. Combination of ACCELEROMETER and MAGNETOMETER
+
+For ABSOLUTE_ORIENTATION_QUATERNION, the following sensor fallback is used:
+1. Use TYPE_ROTATION_VECTOR directly
+2. ABSOLUTE_ORIENTATION_EULER_ANGLES
+
+For RELATIVE_ORIENTATION_EULER_ANGLES, the following sensor fallback is used:
+1. RELATIVE_ORIENTATION_QUATERNION (if it uses TYPE_GAME_ROTATION_VECTOR
+     directly)
+2. ACCELEROMETER
+
+For RELATIVE_ORIENTATION_QUATERNION, the following sensor fallback is used:
+1. Use TYPE_GAME_ROTATION_VECTOR directly
+2. RELATIVE_ORIENTATION_EULER_ANGLES
+
 ### Linux (and Chrome OS)
 
 Sensors are implemented by reading values from the IIO subsystem. The values in
diff --git a/services/device/generic_sensor/platform_sensor_provider_win.cc b/services/device/generic_sensor/platform_sensor_provider_win.cc
index b450cc8..eb26846 100644
--- a/services/device/generic_sensor/platform_sensor_provider_win.cc
+++ b/services/device/generic_sensor/platform_sensor_provider_win.cc
@@ -23,11 +23,6 @@
       base::LeakySingletonTraits<PlatformSensorProviderWin>>::get();
 }
 
-#if defined(__clang__)
-// Disable optimization to work around a Clang miscompile (crbug.com/749826).
-// TODO(hans): Remove once we roll past the Clang fix in r309343.
-[[clang::optnone]]
-#endif
 void PlatformSensorProviderWin::SetSensorManagerForTesting(
     base::win::ScopedComPtr<ISensorManager> sensor_manager) {
   sensor_manager_ = sensor_manager;
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc
index d137da0e..02b5f3a5 100644
--- a/services/ui/ws/event_dispatcher.cc
+++ b/services/ui/ws/event_dispatcher.cc
@@ -530,7 +530,8 @@
       delegate_->ReleaseNativeCapture();
   }
 
-  if (event.type() == ET_POINTER_DOWN) {
+  if (event.type() == ET_POINTER_DOWN &&
+      found_location_target.deepest_window.window) {
     // Use |found_location_target| as |location_target| has already been
     // adjusted for the modal window.
     ServerWindow* modal_transient = modal_window_controller_.GetModalTransient(
@@ -541,6 +542,12 @@
       DCHECK(toplevel);
       delegate_->SetFocusedWindowFromEventDispatcher(toplevel);
       delegate_->OnEventOccurredOutsideOfModalWindow(modal_transient);
+    } else if (found_location_target.deepest_window.window->IsDrawn() &&
+               modal_window_controller_.IsWindowBlocked(
+                   found_location_target.deepest_window.window) &&
+               modal_window_controller_.GetActiveSystemModalWindow()) {
+      delegate_->OnEventOccurredOutsideOfModalWindow(
+          modal_window_controller_.GetActiveSystemModalWindow());
     }
   }
 }
diff --git a/services/ui/ws/event_dispatcher_unittest.cc b/services/ui/ws/event_dispatcher_unittest.cc
index a86e3d49..f571c0e 100644
--- a/services/ui/ws/event_dispatcher_unittest.cc
+++ b/services/ui/ws/event_dispatcher_unittest.cc
@@ -1733,6 +1733,8 @@
 
   ASSERT_TRUE(test_event_dispatcher_delegate()->last_event_target_not_found());
   ASSERT_FALSE(test_event_dispatcher_delegate()->has_queued_events());
+  EXPECT_EQ(w1.get(),
+            test_event_dispatcher_delegate()->window_that_blocked_event());
 }
 
 // Variant of ModalWindowEventOutsideSystemModal with
diff --git a/services/ui/ws/modal_window_controller.cc b/services/ui/ws/modal_window_controller.cc
index 47fdf03..1cfba19 100644
--- a/services/ui/ws/modal_window_controller.cc
+++ b/services/ui/ws/modal_window_controller.cc
@@ -243,6 +243,16 @@
   return nullptr;
 }
 
+const ServerWindow* ModalWindowController::GetActiveSystemModalWindow() const {
+  for (auto it = system_modal_windows_.rbegin();
+       it != system_modal_windows_.rend(); it++) {
+    ServerWindow* modal = *it;
+    if (modal->IsDrawn() && IsWindowInSystemModalContainer(modal))
+      return modal;
+  }
+  return nullptr;
+}
+
 bool ModalWindowController::IsWindowBlockedBySystemModalOrMinContainer(
     const ServerWindow* window) const {
   const ServerWindow* system_modal_window = GetActiveSystemModalWindow();
@@ -291,16 +301,6 @@
   return nullptr;
 }
 
-const ServerWindow* ModalWindowController::GetActiveSystemModalWindow() const {
-  for (auto it = system_modal_windows_.rbegin();
-       it != system_modal_windows_.rend(); it++) {
-    ServerWindow* modal = *it;
-    if (modal->IsDrawn() && IsWindowInSystemModalContainer(modal))
-      return modal;
-  }
-  return nullptr;
-}
-
 void ModalWindowController::RemoveWindow(ServerWindow* window) {
   window->RemoveObserver(this);
   auto it = std::find(system_modal_windows_.begin(),
diff --git a/services/ui/ws/modal_window_controller.h b/services/ui/ws/modal_window_controller.h
index e752d909..af2b8a20 100644
--- a/services/ui/ws/modal_window_controller.h
+++ b/services/ui/ws/modal_window_controller.h
@@ -65,6 +65,15 @@
   }
   const ServerWindow* GetToplevelWindow(const ServerWindow* window) const;
 
+  // Returns the system modal window that is visible and added/shown most
+  // recently, if any.
+  ServerWindow* GetActiveSystemModalWindow() {
+    return const_cast<ServerWindow*>(
+        const_cast<const ModalWindowController*>(this)
+            ->GetActiveSystemModalWindow());
+  }
+  const ServerWindow* GetActiveSystemModalWindow() const;
+
  private:
   friend class test::ModalWindowControllerTestApi;
   class TrackedBlockingContainers;
@@ -84,10 +93,6 @@
 
   const ServerWindow* GetMinContainer(const ServerWindow* window) const;
 
-  // Returns the system modal window that is visible and added/shown most
-  // recently, if any.
-  const ServerWindow* GetActiveSystemModalWindow() const;
-
   // Removes |window| from the data structures used by this class.
   void RemoveWindow(ServerWindow* window);
 
diff --git a/services/ui/ws/threaded_image_cursors.cc b/services/ui/ws/threaded_image_cursors.cc
index eb7f2daf..2657c8d2 100644
--- a/services/ui/ws/threaded_image_cursors.cc
+++ b/services/ui/ws/threaded_image_cursors.cc
@@ -82,7 +82,7 @@
   ui_service_task_runner_ = base::ThreadTaskRunnerHandle::Get();
 
   // Create and initialize the ImageCursors object here and then set it on
-  // |image_cursors_set_weak_ptr__|. Note that it is essential to initialize
+  // |image_cursors_set_weak_ptr_|. Note that it is essential to initialize
   // the ImageCursors object on the UI Service's thread if we are using Ozone,
   // so that it uses the right (thread-local) CursorFactoryOzone instance.
   std::unique_ptr<ui::ImageCursors> image_cursors =
diff --git a/skia/public/interfaces/bitmap_skbitmap_struct_traits.cc b/skia/public/interfaces/bitmap_skbitmap_struct_traits.cc
index f4220f8..407a0b02 100644
--- a/skia/public/interfaces/bitmap_skbitmap_struct_traits.cc
+++ b/skia/public/interfaces/bitmap_skbitmap_struct_traits.cc
@@ -157,7 +157,7 @@
 // static
 BitmapBuffer StructTraits<skia::mojom::BitmapDataView, SkBitmap>::pixel_data(
     const SkBitmap& b) {
-  return {b.getSize(), b.getSize(), static_cast<uint8_t*>(b.getPixels())};
+  return BitmapBuffer(static_cast<uint8_t*>(b.getPixels()), b.getSize());
 }
 
 // static
@@ -188,9 +188,10 @@
     return false;
   }
 
-  BitmapBuffer bitmap_buffer = {0, b->getSize(),
-                                static_cast<uint8_t*>(b->getPixels())};
-  if (!data.ReadPixelData(&bitmap_buffer) || bitmap_buffer.size != b->getSize())
+  BitmapBuffer bitmap_buffer(static_cast<uint8_t*>(b->getPixels()),
+                             b->getSize());
+  if (!data.ReadPixelData(&bitmap_buffer) ||
+      bitmap_buffer.size() != b->getSize())
     return false;
 
   b->notifyPixelsChanged();
diff --git a/storage/browser/fileapi/sandbox_directory_database.cc b/storage/browser/fileapi/sandbox_directory_database.cc
index 32844fc..4afe5e2 100644
--- a/storage/browser/fileapi/sandbox_directory_database.cc
+++ b/storage/browser/fileapi/sandbox_directory_database.cc
@@ -722,7 +722,7 @@
   const std::string path =
       FilePathToString(filesystem_data_directory_.Append(
           kDirectoryDatabaseName));
-  leveldb::Options options;
+  leveldb_env::Options options;
   if (env_override_)
     options.env = env_override_;
   leveldb::Status status = leveldb::DestroyDB(path, options);
@@ -740,10 +740,9 @@
   std::string path =
       FilePathToString(filesystem_data_directory_.Append(
           kDirectoryDatabaseName));
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = true;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   if (env_override_)
     options.env = env_override_;
   leveldb::Status status = leveldb_env::OpenDB(options, path, &db_);
@@ -789,7 +788,8 @@
 
 bool SandboxDirectoryDatabase::RepairDatabase(const std::string& db_path) {
   DCHECK(!db_.get());
-  leveldb::Options options;
+  leveldb_env::Options options;
+  options.reuse_logs = false;
   options.max_open_files = 0;  // Use minimum.
   if (env_override_)
     options.env = env_override_;
diff --git a/storage/browser/fileapi/sandbox_origin_database.cc b/storage/browser/fileapi/sandbox_origin_database.cc
index e79760f..5735eda 100644
--- a/storage/browser/fileapi/sandbox_origin_database.cc
+++ b/storage/browser/fileapi/sandbox_origin_database.cc
@@ -81,10 +81,9 @@
     return false;
 
   std::string path = FilePathToString(db_path);
-  leveldb::Options options;
+  leveldb_env::Options options;
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = true;
-  options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   if (env_override_)
     options.env = env_override_;
   leveldb::Status status = leveldb_env::OpenDB(options, path, &db_);
@@ -128,7 +127,8 @@
 
 bool SandboxOriginDatabase::RepairDatabase(const std::string& db_path) {
   DCHECK(!db_.get());
-  leveldb::Options options;
+  leveldb_env::Options options;
+  options.reuse_logs = false;
   options.max_open_files = 0;  // Use minimum.
   if (env_override_)
     options.env = env_override_;
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index ffb4d42..6e904f6 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -24,18 +24,16 @@
   "Android Tests with Tracing": {
     "instrumentation_tests": [
       {
-        "args": [
-          "-f",
-          "ContextualSearchTapEventTest#*"
-        ],
         "test": "chrome_public_test_apk",
         "trace_output": true
       },
       {
-        "test": "chrome_sync_shell_test_apk"
+        "test": "chrome_sync_shell_test_apk",
+        "trace_output": true
       },
       {
-        "test": "content_shell_test_apk"
+        "test": "content_shell_test_apk",
+        "trace_output": true
       }
     ]
   },
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 3fc9ae9..1060772 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -2888,67 +2888,6 @@
       },
       {
         "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=android-chromium"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build48-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=reference",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build48-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -8210,67 +8149,6 @@
       },
       {
         "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=android-chromium"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build75-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=reference",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build75-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -12162,37 +12040,6 @@
       },
       {
         "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=android-webview",
-          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
-        ],
-        "isolate_name": "telemetry_perf_webview_tests",
-        "name": "smoothness.key_desktop_move_cases",
-        "override_compile_targets": [
-          "telemetry_perf_webview_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build165-b1--device7",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -16315,67 +16162,6 @@
       },
       {
         "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=android-chromium"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build45-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=reference",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build45-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -20298,37 +20084,6 @@
       },
       {
         "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=android-webview",
-          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
-        ],
-        "isolate_name": "telemetry_perf_webview_tests",
-        "name": "smoothness.key_desktop_move_cases",
-        "override_compile_targets": [
-          "telemetry_perf_webview_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build113-b1--device7",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -24451,67 +24206,6 @@
       },
       {
         "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=android-chromium"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build49-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=reference",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build49-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -29651,67 +29345,6 @@
       },
       {
         "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=android-chromium"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build47-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": false,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
-          "smoothness.key_desktop_move_cases",
-          "-v",
-          "--upload-results",
-          "--output-format=chartjson",
-          "--browser=reference",
-          "--output-trace-tag=_ref"
-        ],
-        "isolate_name": "telemetry_perf_tests",
-        "name": "smoothness.key_desktop_move_cases.reference",
-        "override_compile_targets": [
-          "telemetry_perf_tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "1",
-              "id": "build47-b1--device3",
-              "os": "Android",
-              "pool": "Chrome-perf"
-            }
-          ],
-          "expiration": 72000,
-          "hard_timeout": 10800,
-          "ignore_task_failure": true,
-          "io_timeout": 3600,
-          "upload_test_results": false
-        }
-      },
-      {
-        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
diff --git a/testing/buildbot/filters/fuchsia.base_unittests.filter b/testing/buildbot/filters/fuchsia.base_unittests.filter
index 1a43507..3af890a 100644
--- a/testing/buildbot/filters/fuchsia.base_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.base_unittests.filter
@@ -35,7 +35,6 @@
 -SysInfoTest.AmountOfFreeDiskSpace
 -SysInfoTest.AmountOfMem
 -SysInfoTest.AmountOfTotalDiskSpace
--TrackedObjectsTest.ReuseRetiredThreadData
 
 # CancelableSyncSocket tests fail: https://crbug.com/741783
 -CancelableSyncSocket*
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 1fccfc62..8962dcc6 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1314,21 +1314,6 @@
             ]
         }
     ],
-    "MacV2Sandbox": [
-        {
-            "platforms": [
-                "mac"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "MacV2Sandbox"
-                    ]
-                }
-            ]
-        }
-    ],
     "MaxDelayableRequestsNetworkOverride": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 6cdac92..467f0ea 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -12483,7 +12483,6 @@
 crbug.com/591099 http/tests/security/xssAuditor/cached-frame.html [ Crash Failure ]
 crbug.com/591099 http/tests/security/xssAuditor/chunked-big-script.html [ Failure ]
 crbug.com/591099 http/tests/security/xssAuditor/embed-tag-in-path-unterminated.html [ Failure ]
-crbug.com/591099 http/tests/security/xssAuditor/form-action-token-fragment.html [ Failure ]
 crbug.com/591099 http/tests/security/xssAuditor/full-block-base-href.html [ Failure ]
 crbug.com/591099 http/tests/security/xssAuditor/full-block-iframe-javascript-url.html [ Failure ]
 crbug.com/591099 http/tests/security/xssAuditor/full-block-iframe-no-inherit.php [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 682a13e..cad8794 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -124,10 +124,6 @@
 crbug.com/739559 virtual/gpu-rasterization/images/cross-fade-overflow-position.html [ Failure Pass ]
 crbug.com/739559 virtual/gpu-rasterization/images/cross-fade-tiled.html [ Failure Pass ]
 
-crbug.com/747502 paint/roundedrects/input-with-rounded-rect-and-shadow.html [ NeedsManualRebaseline ]
-crbug.com/747502 fast/borders/border-radius-with-box-shadow.html [ NeedsManualRebaseline ]
-crbug.com/747502 paint/roundedrects/circle-with-shadow.html [ NeedsManualRebaseline ]
-
 crbug.com/749760 compositing/overflow/relpos-under-abspos-border-radius.html [ Failure ]
 crbug.com/749760 virtual/prefer_compositing_to_lcd_text/compositing/overflow/relpos-under-abspos-border-radius.html [ Failure ]
 
@@ -1092,6 +1088,8 @@
 crbug.com/377696 printing/setPrinting.html [ Skip ]
 crbug.com/377696 printing/width-overflow.html [ Skip ]
 
+# Skia roll
+crbug.com/630695 svg/custom/massive-coordinates.svg [ NeedsManualRebaseline ]
 
 crbug.com/658305 css3/filters/buffer-offset.html [ Failure Pass ]
 crbug.com/658305 css3/filters/effect-all-on-background-hw.html [ Failure Pass ]
@@ -3000,6 +2998,9 @@
 # Geolocation tests
 crbug.com/745079 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
 
+# ResizeObserver
+crbug.com/735830 resize-observer/garbage_collection.html [ Failure ]
+
 # Sheriff failures 2017-07-03
 crbug.com/708994 http/tests/security/cross-frame-mouse-source-capabilities.html [ Timeout Pass ]
 crbug.com/708994 virtual/mojo-loading/http/tests/security/cross-frame-mouse-source-capabilities.html [ Timeout Pass ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-with-box-shadow-expected.png
rename to third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-expected.txt
index 6902db5..83e8365a 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-expected.txt
@@ -1,3 +1,3 @@
-CONSOLE ERROR: line 4: The XSS Auditor refused to execute a script in 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?q=%3Cform%20action=http://127.0.0.1:8000/%20method=x%3E%3Cinput%20type=submit%3E%3Cinput%20name=x%20value=%27Please%20type%20your%20PIN.%27%3E&notifyDone=1&showAction=1' because its source code was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior.
+CONSOLE ERROR: line 4: The XSS Auditor refused to execute a script in 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?q=%3Cform%20action=http://127.0.0.1:8000/foo&clutter=bar%20method=x%3E%3Cinput%20type=submit%3E%3Cinput%20name=x%20value=%27Please%20type%20your%20PIN.%27%3E&notifyDone=1&showAction=1' because its source code was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior.
 ALERT: Form action set to data:,
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-token-fragment-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-token-fragment-expected.txt
deleted file mode 100644
index 8ad23ac..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-token-fragment-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This test shows that the XSSAuditor can not be induced to fire against a leading substring of an otherwise unknown attribute. 
-
---------
-Frame: '<!--framePath //<!--frame0-->-->'
---------
-This is an iframe with a injected form
-
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-token-fragment.html b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-token-fragment.html
deleted file mode 100644
index 4521aac..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action-token-fragment.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.dumpChildFramesAsText();
-    testRunner.waitUntilDone();
-    testRunner.setXSSAuditorEnabled(true);
-}
-function done()
-{
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-</script>
-</head>
-<body>
-This test shows that the XSSAuditor can not be induced to fire against a leading
-substring of an otherwise unknown attribute.
-<iframe id="myframe"></iframe>
-<script>
-var pad = '11111111111111111111111111111111111111111111111111111';
-var guess = 'action%3d%22http://localhost:8000/foo%3fpad%3d' + pad + '%26tok%3d1234'
-var src = 'resources/echo-form-action.pl?add-token=1&q=http://localhost:8000/foo%3fpad%3d' + pad + '&guess=' + guess;
-document.getElementById('myframe').src = src;
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action.html b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action.html
index 2717acf..5de834d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/form-action.html
@@ -10,7 +10,7 @@
 </script>
 </head>
 <body>
-<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?q=<form%20action=http://127.0.0.1:8000/%20method=x><input%20type=submit><input%20name=x%20value='Please%20type%20your%20PIN.'>&notifyDone=1&showAction=1">
+<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?q=<form%20action=http://127.0.0.1:8000/foo&clutter=bar%20method=x><input%20type=submit><input%20name=x%20value='Please%20type%20your%20PIN.'>&notifyDone=1&showAction=1">
 </iframe>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
new file mode 100644
index 0000000..7d6bda3f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-with-box-shadow-expected.png
deleted file mode 100644
index 1311c78..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-with-box-shadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/circle-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/circle-with-shadow-expected.png
index b255ce9..5b6153f6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/circle-with-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/circle-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
index aff5d8a..b0dda988 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
index dc856af..e4234cb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/resize-observer/garbage_collection.html b/third_party/WebKit/LayoutTests/resize-observer/garbage_collection.html
new file mode 100644
index 0000000..50fbfe0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/resize-observer/garbage_collection.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<p>ResizeObserver garbage collection tests</p>
+<div id="target1" style="width:100px;height:100px;">t1
+</div>
+<script>
+'use strict';
+
+let result;
+let target = document.querySelector("#target1");
+let test = async_test("ResizeObserver garbage collection");
+
+function initResizeObserver() {
+  // The callback routine will be garbage collected unless it is kept alive
+  // in C++ code.
+  let ro = new ResizeObserver( entries => result = entries );
+  ro.observe(target);
+}
+
+function test1() {
+  initResizeObserver();
+  window.requestAnimationFrame( _ => {
+    test.step( _ => {
+      assert_not_equals(result, null, "initial notification");
+      assert_not_equals(window.gc, null, "window.gc required to run this test");
+      if (window.gc)
+        window.gc();
+      test1part2();
+    });
+  });
+}
+
+function test1part2() {
+  target.style.width = "200px";
+  result = null;
+  window.requestAnimationFrame( _ => {
+    test.step( _ => {
+      assert_not_equals(result, null, "resize notification did not happen because callback was garbage collected");
+      test.done();
+    });
+  });
+}
+
+test1();
+</script>
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 6496a67..3d0bc1b 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1517,10 +1517,6 @@
     "layout/TextAutosizerTest.cpp",
     "layout/VisualRectMappingTest.cpp",
     "layout/api/SelectionStateTest.cpp",
-    "layout/compositing/CompositedLayerMappingTest.cpp",
-    "layout/compositing/CompositingReasonFinderTest.cpp",
-    "layout/compositing/CompositorWorkerTest.cpp",
-    "layout/compositing/PaintLayerCompositorTest.cpp",
     "layout/line/InlineBoxTest.cpp",
     "layout/line/InlineTextBoxTest.cpp",
     "layout/ng/NGInlineLayoutTest.cpp",
@@ -1612,6 +1608,10 @@
     "paint/TextPainterTest.cpp",
     "paint/TextSelectionRepaintTest.cpp",
     "paint/VideoPainterTest.cpp",
+    "paint/compositing/CompositedLayerMappingTest.cpp",
+    "paint/compositing/CompositingReasonFinderTest.cpp",
+    "paint/compositing/CompositorWorkerTest.cpp",
+    "paint/compositing/PaintLayerCompositorTest.cpp",
     "resize_observer/ResizeObserverTest.cpp",
     "scheduler/ActiveConnectionThrottlingTest.cpp",
     "scheduler/FrameThrottlingTest.cpp",
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
index f23e2e6..1ae091f 100644
--- a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
@@ -43,10 +43,10 @@
 #include "core/dom/DOMNodeIds.h"
 #include "core/layout/LayoutBoxModelObject.h"
 #include "core/layout/LayoutObject.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/paint/FilterEffectBuilder.h"
 #include "core/paint/ObjectPaintProperties.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/animation/AnimationTranslationUtil.h"
 #include "platform/animation/CompositorAnimation.h"
 #include "platform/animation/CompositorAnimationPlayer.h"
diff --git a/third_party/WebKit/Source/core/css/MediaValues.cpp b/third_party/WebKit/Source/core/css/MediaValues.cpp
index 1f7d4ee..b1e30d8 100644
--- a/third_party/WebKit/Source/core/css/MediaValues.cpp
+++ b/third_party/WebKit/Source/core/css/MediaValues.cpp
@@ -15,9 +15,9 @@
 #include "core/html/imports/HTMLImportsController.h"
 #include "core/layout/LayoutObject.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/graphics/ColorSpaceGamut.h"
 #include "public/platform/WebScreenInfo.h"
 
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 26ca7f2..8bb8d075 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -189,7 +189,6 @@
 #include "core/layout/TextAutosizer.h"
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/CookieJar.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameFetchContext.h"
@@ -209,6 +208,7 @@
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/page/scrolling/SnapCoordinator.h"
 #include "core/page/scrolling/TopDocumentRootScrollerController.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/probe/CoreProbes.h"
 #include "core/resize_observer/ResizeObserverController.h"
 #include "core/svg/SVGDocumentExtensions.h"
diff --git a/third_party/WebKit/Source/core/editing/RenderedPosition.cpp b/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
index d84876e..1e8b5d1 100644
--- a/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
+++ b/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
@@ -36,8 +36,8 @@
 #include "core/editing/VisibleUnits.h"
 #include "core/html/TextControlElement.h"
 #include "core/layout/api/LineLayoutAPIShim.h"
-#include "core/layout/compositing/CompositedSelectionBound.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedSelectionBound.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
index 7f409d9..8d62d91c 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
@@ -100,4 +100,5 @@
 STATIC_ASSERT_ENUM(kWebAXMarkerTypeTextMatch, DocumentMarker::kTextMatch);
 STATIC_ASSERT_ENUM(kWebAXMarkerTypeActiveSuggestion,
                    DocumentMarker::kActiveSuggestion);
+STATIC_ASSERT_ENUM(kWebAXMarkerTypeSuggestion, DocumentMarker::kSuggestion);
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index 0e18f8f..c72b5e5 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -80,8 +80,6 @@
 #include "core/layout/HitTestResult.h"
 #include "core/layout/LayoutFullScreen.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/DocumentThreadableLoader.h"
 #include "core/loader/DocumentThreadableLoaderClient.h"
@@ -91,6 +89,8 @@
 #include "core/page/Page.h"
 #include "core/page/ScopedPageSuspender.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/testing/NullExecutionContext.h"
 #include "core/testing/sim/SimDisplayItemList.h"
 #include "core/testing/sim/SimRequest.h"
diff --git a/third_party/WebKit/Source/core/exported/WebSelection.cpp b/third_party/WebKit/Source/core/exported/WebSelection.cpp
index 26654fe..a6fcffb 100644
--- a/third_party/WebKit/Source/core/exported/WebSelection.cpp
+++ b/third_party/WebKit/Source/core/exported/WebSelection.cpp
@@ -5,7 +5,7 @@
 #include "public/web/WebSelection.h"
 
 #include "core/editing/SelectionType.h"
-#include "core/layout/compositing/CompositedSelection.h"
+#include "core/paint/compositing/CompositedSelection.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/exported/WebViewImpl.cpp b/third_party/WebKit/Source/core/exported/WebViewImpl.cpp
index e7a9f83..5c52e7a 100644
--- a/third_party/WebKit/Source/core/exported/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebViewImpl.cpp
@@ -84,7 +84,6 @@
 #include "core/layout/LayoutEmbeddedContent.h"
 #include "core/layout/TextAutosizer.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoadRequest.h"
 #include "core/loader/FrameLoader.h"
@@ -105,6 +104,7 @@
 #include "core/paint/FirstMeaningfulPaintDetector.h"
 #include "core/paint/LinkHighlightImpl.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/timing/DOMWindowPerformance.h"
 #include "core/timing/Performance.h"
 #include "platform/ContextMenu.h"
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
index 33cb3ef..c98f0297 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -63,7 +63,6 @@
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoadRequest.h"
 #include "core/loader/NavigationScheduler.h"
@@ -72,6 +71,7 @@
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/paint/ObjectPainter.h"
 #include "core/paint/TransformRecorder.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/plugins/PluginView.h"
 #include "core/probe/CoreProbes.h"
 #include "core/svg/SVGDocumentExtensions.h"
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 89e4b9f..d4bff49 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -76,10 +76,6 @@
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
 #include "core/layout/api/LayoutItem.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/CompositedSelection.h"
-#include "core/layout/compositing/CompositingInputsUpdater.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/layout/svg/LayoutSVGRoot.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoader.h"
@@ -97,6 +93,10 @@
 #include "core/paint/PaintLayer.h"
 #include "core/paint/PaintTiming.h"
 #include "core/paint/PrePaintTreeWalk.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/CompositedSelection.h"
+#include "core/paint/compositing/CompositingInputsUpdater.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/plugins/PluginView.h"
 #include "core/probe/CoreProbes.h"
 #include "core/resize_observer/ResizeObserverController.h"
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.h b/third_party/WebKit/Source/core/frame/LocalFrameView.h
index 9f5981b5..827c27a 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.h
@@ -35,12 +35,12 @@
 #include "core/frame/RootFrameViewport.h"
 #include "core/layout/MapCoordinatesFlags.h"
 #include "core/layout/ScrollAnchor.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/FirstMeaningfulPaintDetector.h"
 #include "core/paint/ObjectPaintProperties.h"
 #include "core/paint/PaintInvalidationCapableScrollableArea.h"
 #include "core/paint/PaintPhase.h"
 #include "core/paint/ScrollbarManager.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/PlatformFrameView.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/animation/CompositorAnimationHost.h"
diff --git a/third_party/WebKit/Source/core/frame/VisualViewport.cpp b/third_party/WebKit/Source/core/frame/VisualViewport.cpp
index 8e59847..be8d27a 100644
--- a/third_party/WebKit/Source/core/frame/VisualViewport.cpp
+++ b/third_party/WebKit/Source/core/frame/VisualViewport.cpp
@@ -42,10 +42,10 @@
 #include "core/frame/Settings.h"
 #include "core/fullscreen/Fullscreen.h"
 #include "core/layout/TextAutosizer.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/probe/CoreProbes.h"
 #include "platform/Histogram.h"
 #include "platform/geometry/DoubleRect.h"
diff --git a/third_party/WebKit/Source/core/frame/VisualViewportTest.cpp b/third_party/WebKit/Source/core/frame/VisualViewportTest.cpp
index 61bc88f..94767daf 100644
--- a/third_party/WebKit/Source/core/frame/VisualViewportTest.cpp
+++ b/third_party/WebKit/Source/core/frame/VisualViewportTest.cpp
@@ -18,11 +18,11 @@
 #include "core/input/EventHandler.h"
 #include "core/layout/LayoutObject.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/page/Page.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/geometry/DoublePoint.h"
 #include "platform/geometry/DoubleRect.h"
 #include "platform/graphics/CompositorElementId.h"
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp
index 9f19c23..88b3c20 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp
@@ -58,13 +58,13 @@
 #include "core/input/EventHandler.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/ContextMenuController.h"
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
 #include "core/page/PagePopup.h"
 #include "core/page/PointerLockController.h"
 #include "core/page/ValidationMessageClient.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/KeyboardCodes.h"
 #include "platform/WebFrameScheduler.h"
 #include "platform/animation/CompositorAnimationHost.h"
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 250aa90..1a62583 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -61,10 +61,10 @@
 #include "core/layout/HitTestCanvasResult.h"
 #include "core/layout/LayoutHTMLCanvas.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/ChromeClient.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/PaintTiming.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/probe/CoreProbes.h"
 #include "platform/Histogram.h"
 #include "platform/RuntimeEnabledFeatures.h"
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index 5021887..08d68c7 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -69,8 +69,8 @@
 #include "core/layout/IntersectionGeometry.h"
 #include "core/layout/LayoutMedia.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/ChromeClient.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/Histogram.h"
 #include "platform/LayoutTestSupport.h"
 #include "platform/RuntimeEnabledFeatures.h"
diff --git a/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp b/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp
index 0861743..71141f97 100644
--- a/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp
+++ b/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp
@@ -668,7 +668,8 @@
   DCHECK_EQ(request.token.GetType(), HTMLToken::kStartTag);
   DCHECK(HasName(request.token, formTag));
 
-  return EraseAttributeIfInjected(request, actionAttr, kURLWithUniqueOrigin);
+  return EraseAttributeIfInjected(request, actionAttr, kURLWithUniqueOrigin,
+                                  kSrcLikeAttributeTruncation);
 }
 
 bool XSSAuditor::FilterInputToken(const FilterTokenRequest& request) {
diff --git a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
index 1833da5..934ae43 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
@@ -41,11 +41,11 @@
 #include "core/inspector/InspectedFrames.h"
 #include "core/layout/LayoutEmbeddedContent.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/graphics/CompositingReasons.h"
 #include "platform/graphics/GraphicsLayer.h"
diff --git a/third_party/WebKit/Source/core/layout/BUILD.gn b/third_party/WebKit/Source/core/layout/BUILD.gn
index 0f360470..87b9faa 100644
--- a/third_party/WebKit/Source/core/layout/BUILD.gn
+++ b/third_party/WebKit/Source/core/layout/BUILD.gn
@@ -275,26 +275,6 @@
     "api/LineLayoutTextCombine.h",
     "api/SelectionState.cpp",
     "api/SelectionState.h",
-    "compositing/CompositedLayerMapping.cpp",
-    "compositing/CompositedLayerMapping.h",
-    "compositing/CompositedSelection.h",
-    "compositing/CompositedSelectionBound.h",
-    "compositing/CompositingInputsUpdater.cpp",
-    "compositing/CompositingInputsUpdater.h",
-    "compositing/CompositingLayerAssigner.cpp",
-    "compositing/CompositingLayerAssigner.h",
-    "compositing/CompositingReasonFinder.cpp",
-    "compositing/CompositingReasonFinder.h",
-    "compositing/CompositingRequirementsUpdater.cpp",
-    "compositing/CompositingRequirementsUpdater.h",
-    "compositing/CompositingState.h",
-    "compositing/CompositingTriggers.h",
-    "compositing/GraphicsLayerTreeBuilder.cpp",
-    "compositing/GraphicsLayerTreeBuilder.h",
-    "compositing/GraphicsLayerUpdater.cpp",
-    "compositing/GraphicsLayerUpdater.h",
-    "compositing/PaintLayerCompositor.cpp",
-    "compositing/PaintLayerCompositor.h",
     "line/AbstractInlineTextBox.cpp",
     "line/AbstractInlineTextBox.h",
     "line/BreakingContext.cpp",
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 78702e3..ca234d0d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -54,7 +54,6 @@
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
 #include "core/layout/api/LineLayoutBlockFlow.h"
 #include "core/layout/api/LineLayoutBox.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/layout/shapes/ShapeOutsideInfo.h"
 #include "core/page/AutoscrollController.h"
 #include "core/page/Page.h"
@@ -66,6 +65,7 @@
 #include "core/paint/BoxPaintInvalidator.h"
 #include "core/paint/BoxPainter.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/style/ShadowList.h"
 #include "platform/LengthFunctions.h"
 #include "platform/geometry/DoubleRect.h"
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
index a471cb1..3afd067 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -33,10 +33,10 @@
 #include "core/layout/LayoutGeometryMap.h"
 #include "core/layout/LayoutInline.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/ObjectPaintInvalidator.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/style/ShadowList.h"
 #include "platform/LengthFunctions.h"
 #include "platform/geometry/TransformState.h"
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 5780261c..1633a00 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -39,11 +39,11 @@
 #include "core/layout/SubtreeLayoutScope.h"
 #include "core/layout/api/HitTestAction.h"
 #include "core/layout/api/SelectionState.h"
-#include "core/layout/compositing/CompositingState.h"
 #include "core/loader/resource/ImageResourceObserver.h"
 #include "core/paint/LayerHitTestRects.h"
 #include "core/paint/PaintPhase.h"
 #include "core/paint/RarePaintData.h"
+#include "core/paint/compositing/CompositingState.h"
 #include "core/style/ComputedStyle.h"
 #include "core/style/StyleDifference.h"
 #include "platform/geometry/FloatQuad.h"
diff --git a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
index fdf9b07a..fc81898 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
@@ -44,7 +44,6 @@
 #include "core/layout/LayoutTableCell.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/layout/line/InlineTextBox.h"
 #include "core/layout/svg/LayoutSVGGradientStop.h"
 #include "core/layout/svg/LayoutSVGImage.h"
@@ -56,6 +55,7 @@
 #include "core/layout/svg/SVGLayoutTreeAsText.h"
 #include "core/page/PrintContext.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/LayoutUnit.h"
 #include "platform/wtf/HexNumber.h"
 #include "platform/wtf/Vector.h"
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.cpp b/third_party/WebKit/Source/core/layout/LayoutView.cpp
index 578d9b9..00d5ee1 100644
--- a/third_party/WebKit/Source/core/layout/LayoutView.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutView.cpp
@@ -36,13 +36,13 @@
 #include "core/layout/api/LayoutAPIShim.h"
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/layout/svg/LayoutSVGRoot.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/ViewPaintInvalidator.h"
 #include "core/paint/ViewPainter.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/svg/SVGDocumentExtensions.h"
 #include "platform/Histogram.h"
 #include "platform/RuntimeEnabledFeatures.h"
diff --git a/third_party/WebKit/Source/core/page/ChromeClientImpl.cpp b/third_party/WebKit/Source/core/page/ChromeClientImpl.cpp
index dfb29b89..13af708 100644
--- a/third_party/WebKit/Source/core/page/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/core/page/ChromeClientImpl.cpp
@@ -66,12 +66,12 @@
 #include "core/inspector/DevToolsEmulator.h"
 #include "core/layout/HitTestResult.h"
 #include "core/layout/LayoutEmbeddedContent.h"
-#include "core/layout/compositing/CompositedSelection.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoadRequest.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "core/page/PopupOpeningObserver.h"
+#include "core/paint/compositing/CompositedSelection.h"
 #include "platform/Cursor.h"
 #include "platform/FileChooser.h"
 #include "platform/Histogram.h"
diff --git a/third_party/WebKit/Source/core/page/PageWidgetDelegate.cpp b/third_party/WebKit/Source/core/page/PageWidgetDelegate.cpp
index c042afa1..813eb22 100644
--- a/third_party/WebKit/Source/core/page/PageWidgetDelegate.cpp
+++ b/third_party/WebKit/Source/core/page/PageWidgetDelegate.cpp
@@ -34,10 +34,10 @@
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/input/EventHandler.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/AutoscrollController.h"
 #include "core/page/Page.h"
 #include "core/paint/TransformRecorder.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/paint/ClipRecorder.h"
 #include "platform/graphics/paint/CullRect.h"
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
index c0685815..ad33c13 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
@@ -12,12 +12,12 @@
 #include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutEmbeddedContent.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/Page.h"
 #include "core/page/scrolling/RootScrollerUtil.h"
 #include "core/page/scrolling/TopDocumentRootScrollerController.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/PaintLayerScrollableArea.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/graphics/GraphicsLayer.h"
 #include "platform/scroll/ScrollableArea.h"
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
index 9f3b6b3c..3fb263f 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
@@ -14,13 +14,13 @@
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/Page.h"
 #include "core/page/scrolling/RootScrollerController.h"
 #include "core/page/scrolling/TopDocumentRootScrollerController.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/PaintLayerScrollableArea.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
 #include "platform/testing/URLTestHelpers.h"
 #include "platform/testing/UnitTestHelpers.h"
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
index 1eba7d48..53fa3e9 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -39,10 +39,10 @@
 #include "core/layout/LayoutGeometryMap.h"
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/plugins/PluginView.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/animation/CompositorAnimationHost.h"
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
index 8142292..8fbc827 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
@@ -35,9 +35,9 @@
 #include "core/html/HTMLIFrameElement.h"
 #include "core/layout/LayoutEmbeddedContent.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/Page.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/geometry/IntPoint.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/graphics/GraphicsLayer.h"
diff --git a/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp b/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp
index ec28025..698d5d6 100644
--- a/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp
@@ -11,13 +11,13 @@
 #include "core/frame/VisualViewport.h"
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "core/page/scrolling/OverscrollController.h"
 #include "core/page/scrolling/RootScrollerUtil.h"
 #include "core/page/scrolling/ViewportScrollCallback.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/scroll/ScrollableArea.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/paint/BUILD.gn b/third_party/WebKit/Source/core/paint/BUILD.gn
index fafd0630..0863dbdf 100644
--- a/third_party/WebKit/Source/core/paint/BUILD.gn
+++ b/third_party/WebKit/Source/core/paint/BUILD.gn
@@ -218,6 +218,26 @@
     "ViewPaintInvalidator.h",
     "ViewPainter.cpp",
     "ViewPainter.h",
+    "compositing/CompositedLayerMapping.cpp",
+    "compositing/CompositedLayerMapping.h",
+    "compositing/CompositedSelection.h",
+    "compositing/CompositedSelectionBound.h",
+    "compositing/CompositingInputsUpdater.cpp",
+    "compositing/CompositingInputsUpdater.h",
+    "compositing/CompositingLayerAssigner.cpp",
+    "compositing/CompositingLayerAssigner.h",
+    "compositing/CompositingReasonFinder.cpp",
+    "compositing/CompositingReasonFinder.h",
+    "compositing/CompositingRequirementsUpdater.cpp",
+    "compositing/CompositingRequirementsUpdater.h",
+    "compositing/CompositingState.h",
+    "compositing/CompositingTriggers.h",
+    "compositing/GraphicsLayerTreeBuilder.cpp",
+    "compositing/GraphicsLayerTreeBuilder.h",
+    "compositing/GraphicsLayerUpdater.cpp",
+    "compositing/GraphicsLayerUpdater.h",
+    "compositing/PaintLayerCompositor.cpp",
+    "compositing/PaintLayerCompositor.h",
   ]
 
   configs += [
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index 043ff16..a2c3c742 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -10,8 +10,8 @@
 #include "core/layout/LayoutTableCell.h"
 #include "core/layout/LayoutTableCol.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/LayoutUnit.h"
 #include "platform/geometry/LayoutRect.h"
 
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
index d6011c0..3307695 100644
--- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
@@ -6,11 +6,11 @@
 
 #include "core/frame/Settings.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/paint/ObjectPaintInvalidator.h"
 #include "core/paint/PaintInvalidator.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/PaintLayerScrollableArea.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/geometry/LayoutRect.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
index fc9509f2..a77dfd4 100644
--- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -9,7 +9,6 @@
 #include "core/layout/LayoutObject.h"
 #include "core/layout/LayoutTable.h"
 #include "core/layout/LayoutTheme.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/paint/BackgroundImageGeometry.h"
 #include "core/paint/BoxDecorationData.h"
 #include "core/paint/BoxModelObjectPainter.h"
@@ -20,6 +19,7 @@
 #include "core/paint/PaintInfo.h"
 #include "core/paint/ScrollRecorder.h"
 #include "core/paint/ThemePainter.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/LengthFunctions.h"
 #include "platform/geometry/LayoutPoint.h"
 #include "platform/graphics/GraphicsContextStateSaver.h"
diff --git a/third_party/WebKit/Source/core/paint/LayerClipRecorderTest.cpp b/third_party/WebKit/Source/core/paint/LayerClipRecorderTest.cpp
index 18c0a91..2558e87e 100644
--- a/third_party/WebKit/Source/core/paint/LayerClipRecorderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/LayerClipRecorderTest.cpp
@@ -5,10 +5,10 @@
 #include "core/paint/LayerClipRecorder.h"
 
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/LayoutObjectDrawingRecorder.h"
 #include "core/paint/PaintControllerPaintTest.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/GraphicsLayer.h"
 #include "platform/graphics/paint/PaintController.h"
diff --git a/third_party/WebKit/Source/core/paint/LinkHighlightImpl.cpp b/third_party/WebKit/Source/core/paint/LinkHighlightImpl.cpp
index ca87f31..eb51271 100644
--- a/third_party/WebKit/Source/core/paint/LinkHighlightImpl.cpp
+++ b/third_party/WebKit/Source/core/paint/LinkHighlightImpl.cpp
@@ -36,8 +36,8 @@
 #include "core/frame/WebLocalFrameImpl.h"
 #include "core/layout/LayoutBoxModelObject.h"
 #include "core/layout/LayoutObject.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/LayoutTestSupport.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/animation/CompositorAnimation.h"
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
index 4a46694f..dfeef48 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
@@ -8,10 +8,10 @@
 #include "core/frame/LocalFrameView.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h"
 #include "core/paint/PaintInvalidator.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/PlatformChromeClient.h"
 #include "platform/graphics/GraphicsLayer.h"
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index fe0ac34..bf9fb304 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -63,8 +63,6 @@
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/layout/svg/LayoutSVGResourceClipper.h"
 #include "core/layout/svg/LayoutSVGRoot.h"
 #include "core/page/Page.h"
@@ -73,6 +71,8 @@
 #include "core/paint/BoxReflectionUtils.h"
 #include "core/paint/FilterEffectBuilder.h"
 #include "core/paint/ObjectPaintInvalidator.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/LengthFunctions.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/bindings/RuntimeCallStats.h"
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index 178d2cb..3e7cc4b 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -6,7 +6,6 @@
 
 #include "core/frame/LocalFrameView.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/paint/ClipPathClipper.h"
 #include "core/paint/FilterPainter.h"
 #include "core/paint/LayerClipRecorder.h"
@@ -17,6 +16,7 @@
 #include "core/paint/ScrollRecorder.h"
 #include "core/paint/ScrollableAreaPainter.h"
 #include "core/paint/Transform3DRecorder.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/geometry/FloatPoint3D.h"
 #include "platform/graphics/GraphicsLayer.h"
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
index 77d48d9..71ee3d5 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
@@ -5,8 +5,8 @@
 #include "core/paint/PaintLayerPainter.h"
 
 #include "core/layout/LayoutBoxModelObject.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/paint/PaintControllerPaintTest.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index b87f49b..6b165b0 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -71,8 +71,6 @@
 #include "core/layout/LayoutTheme.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LayoutBoxItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/FocusController.h"
@@ -82,6 +80,8 @@
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/page/scrolling/TopDocumentRootScrollerController.h"
 #include "core/paint/PaintLayerFragment.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/graphics/CompositorMutableProperties.h"
 #include "platform/graphics/GraphicsLayer.h"
 #include "platform/graphics/paint/DrawingRecorder.h"
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerStackingNode.cpp b/third_party/WebKit/Source/core/paint/PaintLayerStackingNode.cpp
index f1c33dd..64f1788 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerStackingNode.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerStackingNode.cpp
@@ -48,8 +48,8 @@
 #include <memory>
 #include "core/layout/LayoutMultiColumnFlowThread.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/wtf/PtrUtil.h"
 #include "public/platform/Platform.h"
 
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 3923d54ba..4f1754ff 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -11,7 +11,6 @@
 #include "core/frame/Settings.h"
 #include "core/layout/LayoutInline.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/CompositingReasonFinder.h"
 #include "core/layout/svg/LayoutSVGResourceMasker.h"
 #include "core/layout/svg/LayoutSVGRoot.h"
 #include "core/layout/svg/SVGLayoutSupport.h"
@@ -22,6 +21,7 @@
 #include "core/paint/ObjectPaintProperties.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/SVGRootPainter.h"
+#include "core/paint/compositing/CompositingReasonFinder.h"
 #include "platform/transforms/TransformationMatrix.h"
 #include "platform/wtf/PtrUtil.h"
 
diff --git a/third_party/WebKit/Source/core/paint/ReplacedPainter.cpp b/third_party/WebKit/Source/core/paint/ReplacedPainter.cpp
index a6a01ee..0acef3a1 100644
--- a/third_party/WebKit/Source/core/paint/ReplacedPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ReplacedPainter.cpp
@@ -6,7 +6,6 @@
 
 #include "core/layout/LayoutReplaced.h"
 #include "core/layout/api/SelectionState.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/layout/svg/LayoutSVGRoot.h"
 #include "core/paint/BoxPainter.h"
 #include "core/paint/LayoutObjectDrawingRecorder.h"
@@ -14,6 +13,7 @@
 #include "core/paint/PaintInfo.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/RoundedInnerRectClipper.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/wtf/Optional.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/paint/ViewPainter.cpp b/third_party/WebKit/Source/core/paint/ViewPainter.cpp
index d75e422..64f0ffa 100644
--- a/third_party/WebKit/Source/core/paint/ViewPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ViewPainter.cpp
@@ -8,7 +8,6 @@
 #include "core/frame/Settings.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/paint/BackgroundImageGeometry.h"
 #include "core/paint/BlockPainter.h"
 #include "core/paint/BoxModelObjectPainter.h"
@@ -17,6 +16,7 @@
 #include "core/paint/PaintInfo.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/ScrollRecorder.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/RuntimeEnabledFeatures.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
similarity index 99%
rename from third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
rename to third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
index ed7872e..e73215d 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
@@ -23,7 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "core/layout/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 
 #include <memory>
 
@@ -47,7 +47,6 @@
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LayoutAPIShim.h"
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/resource/ImageResourceContent.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
@@ -62,6 +61,7 @@
 #include "core/paint/PaintLayerStackingNodeIterator.h"
 #include "core/paint/ScrollableAreaPainter.h"
 #include "core/paint/TransformRecorder.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/plugins/PluginView.h"
 #include "core/probe/CoreProbes.h"
 #include "platform/LengthFunctions.h"
@@ -749,16 +749,18 @@
     graphics_layer_->SetMaskLayer(nullptr);
     mask_layer_changed = true;
   }
-  if (HasClippingLayer())
+  if (HasClippingLayer()) {
     ClippingLayer()->SetMaskLayer(layer_to_apply_child_clipping_mask ==
                                           ClippingLayer()
                                       ? child_clipping_mask_layer_.get()
                                       : nullptr);
-  if (HasScrollingLayer())
+  }
+  if (HasScrollingLayer()) {
     ScrollingLayer()->SetMaskLayer(layer_to_apply_child_clipping_mask ==
                                            ScrollingLayer()
                                        ? child_clipping_mask_layer_.get()
                                        : nullptr);
+  }
   graphics_layer_->SetContentsClippingMaskLayer(
       should_apply_child_clipping_mask_on_contents
           ? child_clipping_mask_layer_.get()
@@ -853,10 +855,11 @@
   // there is one and only one fragment.
   LayoutPoint offset = layer->VisualOffsetFromAncestor(
       composited_ancestor, local_representative_point_for_fragmentation);
-  if (composited_ancestor)
+  if (composited_ancestor) {
     offset.Move(composited_ancestor->GetCompositedLayerMapping()
                     ->OwningLayer()
                     .SubpixelAccumulation());
+  }
   offset.MoveBy(-local_representative_point_for_fragmentation);
   return offset;
 }
@@ -928,9 +931,10 @@
 
   LayoutPoint compositing_container_offset_from_parent_graphics_layer =
       -graphics_layer_parent_location;
-  if (compositing_container)
+  if (compositing_container) {
     compositing_container_offset_from_parent_graphics_layer +=
         compositing_container->SubpixelAccumulation();
+  }
 
 #if 0 && DCHECK_IS_ON()
   // TODO(trchen): We should enable this for below comment out |DCHECK()| once
@@ -944,9 +948,10 @@
 #endif
   // FIXME: Cache these offsets.
   LayoutPoint compositing_container_offset_from_transformed_ancestor;
-  if (compositing_container && !compositing_container->Transform())
+  if (compositing_container && !compositing_container->Transform()) {
     compositing_container_offset_from_transformed_ancestor =
         compositing_container->ComputeOffsetFromTransformedAncestor();
+  }
 
   LayoutRect total_squash_bounds;
   for (size_t i = 0; i < layers.size(); ++i) {
@@ -1036,9 +1041,10 @@
   offset_from_transformed_ancestor->Move(
       squash_layer_origin_in_compositing_container_space);
 
-  for (size_t i = 0; i < layers.size(); ++i)
+  for (size_t i = 0; i < layers.size(); ++i) {
     layers[i].local_clip_rect_for_squashed_layer =
         LocalClipRectForSquashedLayer(owning_layer_, layers[i], layers);
+  }
 }
 
 void CompositedLayerMapping::UpdateGraphicsLayerGeometry(
@@ -1678,12 +1684,14 @@
   }
   update_bottom_layer(overflow_controls_ancestor_clipping_layer_.get());
   update_bottom_layer(overflow_controls_host_layer_.get());
-  if (layer_for_horizontal_scrollbar_)
+  if (layer_for_horizontal_scrollbar_) {
     overflow_controls_host_layer_->AddChild(
         layer_for_horizontal_scrollbar_.get());
-  if (layer_for_vertical_scrollbar_)
+  }
+  if (layer_for_vertical_scrollbar_) {
     overflow_controls_host_layer_->AddChild(
         layer_for_vertical_scrollbar_.get());
+  }
   if (layer_for_scroll_corner_)
     overflow_controls_host_layer_->AddChild(layer_for_scroll_corner_.get());
 
@@ -1960,12 +1968,13 @@
           owning_layer_.GetScrollableArea()) {
     if (ScrollingCoordinator* scrolling_coordinator =
             owning_layer_.GetScrollingCoordinator()) {
-      if (reason == kCompositingReasonLayerForHorizontalScrollbar)
+      if (reason == kCompositingReasonLayerForHorizontalScrollbar) {
         scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
             scrollable_area, kHorizontalScrollbar);
-      else if (reason == kCompositingReasonLayerForVerticalScrollbar)
+      } else if (reason == kCompositingReasonLayerForVerticalScrollbar) {
         scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
             scrollable_area, kVerticalScrollbar);
+      }
     }
   }
   return true;
@@ -1981,14 +1990,16 @@
     // If the scrollable area is marked as needing a new scrollbar layer,
     // destroy the layer now so that it will be created again below.
     if (layer_for_horizontal_scrollbar_ && needs_horizontal_scrollbar_layer &&
-        scrollable_area->ShouldRebuildHorizontalScrollbarLayer())
+        scrollable_area->ShouldRebuildHorizontalScrollbarLayer()) {
       ToggleScrollbarLayerIfNeeded(
           layer_for_horizontal_scrollbar_, false,
           kCompositingReasonLayerForHorizontalScrollbar);
+    }
     if (layer_for_vertical_scrollbar_ && needs_vertical_scrollbar_layer &&
-        scrollable_area->ShouldRebuildVerticalScrollbarLayer())
+        scrollable_area->ShouldRebuildVerticalScrollbarLayer()) {
       ToggleScrollbarLayerIfNeeded(layer_for_vertical_scrollbar_, false,
                                    kCompositingReasonLayerForVerticalScrollbar);
+    }
     scrollable_area->ResetRebuildScrollbarLayerFlags();
 
     if (scrolling_contents_layer_ &&
@@ -2083,12 +2094,9 @@
   kApplyToDecorationOutlineLayer = (1 << 9),
   kApplyToAllGraphicsLayers =
       (kApplyToSquashingLayer | kApplyToScrollbarLayers |
-       kApplyToBackgroundLayer |
-       kApplyToMaskLayers |
-       kApplyToLayersAffectedByPreserve3D |
-       kApplyToContentLayers |
-       kApplyToScrollingContentLayers |
-       kApplyToDecorationOutlineLayer)
+       kApplyToBackgroundLayer | kApplyToMaskLayers |
+       kApplyToLayersAffectedByPreserve3D | kApplyToContentLayers |
+       kApplyToScrollingContentLayers | kApplyToDecorationOutlineLayer)
 };
 typedef unsigned ApplyToGraphicsLayersMode;
 
@@ -2455,9 +2463,10 @@
       scroll_parent, have_ancestor_clip_layer, have_ancestor_mask_layer);
   if (!have_ancestor_clip_layer) {
     clip_parent = owning_layer_.ClipParent();
-    if (clip_parent)
+    if (clip_parent) {
       clip_parent =
           clip_parent->EnclosingLayerWithCompositedLayerMapping(kIncludeSelf);
+    }
   }
 
   if (ScrollingCoordinator* scrolling_coordinator =
@@ -3065,11 +3074,12 @@
     PaintLayerPainter(*paint_info.paint_layer)
         .PaintLayerContents(context, painting_info, paint_layer_flags);
 
-    if (paint_info.paint_layer->ContainsDirtyOverlayScrollbars())
+    if (paint_info.paint_layer->ContainsDirtyOverlayScrollbars()) {
       PaintLayerPainter(*paint_info.paint_layer)
           .PaintLayerContents(
               context, painting_info,
               paint_layer_flags | kPaintLayerPaintingOverlayScrollbars);
+    }
   } else {
     PaintLayerPaintingInfo painting_info(
         paint_info.paint_layer, LayoutRect(dirty_rect), kGlobalPaintNormalPhase,
@@ -3156,10 +3166,11 @@
   LayoutRect graphics_layer_bounds_in_root_view_space(
       graphics_layer_bounds_in_object_space);
   LayoutView* root_view = anchor_layout_object->View();
-  while (!root_view->GetFrame()->OwnerLayoutItem().IsNull())
+  while (!root_view->GetFrame()->OwnerLayoutItem().IsNull()) {
     root_view = LayoutAPIShim::LayoutObjectFrom(
                     root_view->GetFrame()->OwnerLayoutItem())
                     ->View();
+  }
   anchor_layout_object->MapToVisualRectInAncestorSpace(
       root_view, graphics_layer_bounds_in_root_view_space);
   FloatRect visible_content_rect(graphics_layer_bounds_in_root_view_space);
@@ -3371,9 +3382,10 @@
     DoPaintTask(paint_info, *graphics_layer, paint_layer_flags, context,
                 interest_rect);
   } else if (graphics_layer == squashing_layer_.get()) {
-    for (size_t i = 0; i < squashed_layers_.size(); ++i)
+    for (size_t i = 0; i < squashed_layers_.size(); ++i) {
       DoPaintTask(squashed_layers_[i], *graphics_layer, paint_layer_flags,
                   context, interest_rect);
+    }
   } else if (IsScrollableAreaLayer(graphics_layer)) {
     PaintScrollableArea(graphics_layer, context, interest_rect);
   }
@@ -3571,9 +3583,10 @@
     // entries.
     for (size_t i = next_squashed_layer_index; i < squashed_layers_.size();
          ++i) {
-      if (InvalidateLayerIfNoPrecedingEntry(i))
+      if (InvalidateLayerIfNoPrecedingEntry(i)) {
         squashed_layers_[i].paint_layer->SetGroupedMapping(
             nullptr, PaintLayer::kDoNotInvalidateLayerAndRemoveFromMapping);
+      }
       layers_needing_paint_invalidation.push_back(
           squashed_layers_[i].paint_layer);
     }
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.h
similarity index 99%
rename from third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h
rename to third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.h
index 0c6fda4..4243f90 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.h
@@ -27,9 +27,9 @@
 #define CompositedLayerMapping_h
 
 #include <memory>
-#include "core/layout/compositing/GraphicsLayerUpdater.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/PaintLayerPaintingInfo.h"
+#include "core/paint/compositing/GraphicsLayerUpdater.h"
 #include "platform/geometry/FloatPoint.h"
 #include "platform/geometry/FloatPoint3D.h"
 #include "platform/graphics/GraphicsLayer.h"
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMappingTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
rename to third_party/WebKit/Source/core/paint/compositing/CompositedLayerMappingTest.cpp
index 37da42e..cbac2c8c 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMappingTest.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/layout/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 
 #include "core/frame/FrameTestHelpers.h"
 #include "core/frame/LocalFrameView.h"
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedSelection.h b/third_party/WebKit/Source/core/paint/compositing/CompositedSelection.h
similarity index 97%
rename from third_party/WebKit/Source/core/layout/compositing/CompositedSelection.h
rename to third_party/WebKit/Source/core/paint/compositing/CompositedSelection.h
index b356e95..f789abb8 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedSelection.h
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedSelection.h
@@ -32,7 +32,7 @@
 #define CompositedSelection_h
 
 #include "core/editing/SelectionType.h"
-#include "core/layout/compositing/CompositedSelectionBound.h"
+#include "core/paint/compositing/CompositedSelectionBound.h"
 #include "platform/geometry/FloatPoint.h"
 #include "platform/graphics/GraphicsLayer.h"
 #include "platform/wtf/Allocator.h"
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedSelectionBound.h b/third_party/WebKit/Source/core/paint/compositing/CompositedSelectionBound.h
similarity index 100%
rename from third_party/WebKit/Source/core/layout/compositing/CompositedSelectionBound.h
rename to third_party/WebKit/Source/core/paint/compositing/CompositedSelectionBound.h
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositingInputsUpdater.cpp
similarity index 97%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
rename to third_party/WebKit/Source/core/paint/compositing/CompositingInputsUpdater.cpp
index 520fce8..4729873 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingInputsUpdater.cpp
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/layout/compositing/CompositingInputsUpdater.h"
+#include "core/paint/compositing/CompositingInputsUpdater.h"
 
 #include "core/dom/Document.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/UseCounter.h"
 #include "core/layout/LayoutBlock.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/instrumentation/tracing/TraceEvent.h"
 
 namespace blink {
@@ -148,9 +148,10 @@
     info.enclosing_composited_layer = layer;
 
   if (layer->NeedsCompositingInputsUpdate()) {
-    if (info.enclosing_composited_layer)
+    if (info.enclosing_composited_layer) {
       info.enclosing_composited_layer->GetCompositedLayerMapping()
           ->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
+    }
     update_type = kForceUpdate;
   }
 
@@ -228,9 +229,10 @@
 
         properties.ancestor_scrolling_layer =
             parent_layer_on_containing_block_chain->AncestorScrollingLayer();
-        if (parent_layer_on_containing_block_chain->ScrollsOverflow())
+        if (parent_layer_on_containing_block_chain->ScrollsOverflow()) {
           properties.ancestor_scrolling_layer =
               parent_layer_on_containing_block_chain;
+        }
 
         if (layer->StackingNode()->IsStacked() &&
             properties.ancestor_scrolling_layer &&
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h b/third_party/WebKit/Source/core/paint/compositing/CompositingInputsUpdater.h
similarity index 100%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h
rename to third_party/WebKit/Source/core/paint/compositing/CompositingInputsUpdater.h
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.cpp
similarity index 97%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp
rename to third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.cpp
index c5b44c2a..cb338e7 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.cpp
@@ -24,13 +24,13 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "core/layout/compositing/CompositingLayerAssigner.h"
+#include "core/paint/compositing/CompositingLayerAssigner.h"
 
 #include "core/inspector/InspectorTraceEvents.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/page/Page.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "platform/instrumentation/tracing/TraceEvent.h"
 
 namespace blink {
@@ -53,10 +53,11 @@
   SquashingState squashing_state;
   AssignLayersToBackingsInternal(update_root, squashing_state,
                                  layers_needing_paint_invalidation);
-  if (squashing_state.has_most_recent_mapping)
+  if (squashing_state.has_most_recent_mapping) {
     squashing_state.most_recent_mapping->FinishAccumulatingSquashingLayers(
         squashing_state.next_squashed_layer_index,
         layers_needing_paint_invalidation);
+  }
 }
 
 void CompositingLayerAssigner::SquashingState::
@@ -65,9 +66,10 @@
         bool has_new_composited_layer_mapping,
         Vector<PaintLayer*>& layers_needing_paint_invalidation) {
   // The most recent backing is done accumulating any more squashing layers.
-  if (has_most_recent_mapping)
+  if (has_most_recent_mapping) {
     most_recent_mapping->FinishAccumulatingSquashingLayers(
         next_squashed_layer_index, layers_needing_paint_invalidation);
+  }
 
   next_squashed_layer_index = 0;
   bounding_rect = IntRect();
@@ -322,9 +324,10 @@
   if (layer->StackingNode()->IsStackingContext()) {
     PaintLayerStackingNodeIterator iterator(*layer->StackingNode(),
                                             kNegativeZOrderChildren);
-    while (PaintLayerStackingNode* cur_node = iterator.Next())
+    while (PaintLayerStackingNode* cur_node = iterator.Next()) {
       AssignLayersToBackingsInternal(cur_node->Layer(), squashing_state,
                                      layers_needing_paint_invalidation);
+    }
   }
 
   // At this point, if the layer is to be separately composited, then its
@@ -344,14 +347,16 @@
 
   PaintLayerStackingNodeIterator iterator(
       *layer->StackingNode(), kNormalFlowChildren | kPositiveZOrderChildren);
-  while (PaintLayerStackingNode* cur_node = iterator.Next())
+  while (PaintLayerStackingNode* cur_node = iterator.Next()) {
     AssignLayersToBackingsInternal(cur_node->Layer(), squashing_state,
                                    layers_needing_paint_invalidation);
+  }
 
   if (squashing_state.has_most_recent_mapping &&
-      &squashing_state.most_recent_mapping->OwningLayer() == layer)
+      &squashing_state.most_recent_mapping->OwningLayer() == layer) {
     squashing_state.have_assigned_backings_to_entire_squashing_layer_subtree =
         true;
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.h b/third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.h
similarity index 98%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.h
rename to third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.h
index 63ee050..29e956e 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.h
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.h
@@ -27,7 +27,7 @@
 #ifndef CompositingLayerAssigner_h
 #define CompositingLayerAssigner_h
 
-#include "core/layout/compositing/PaintLayerCompositor.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/geometry/LayoutPoint.h"
 #include "platform/graphics/SquashingDisallowedReasons.h"
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.cpp
similarity index 98%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp
rename to third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.cpp
index 8429127..787991f 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/layout/compositing/CompositingReasonFinder.h"
+#include "core/paint/compositing/CompositingReasonFinder.h"
 
 #include "core/CSSPropertyNames.h"
 #include "core/dom/Document.h"
@@ -236,9 +236,10 @@
   // container, e.g. transformed elements.  They will stay fixed wrt the
   // container rather than the enclosing frame.
   EPosition position = layer->GetLayoutObject().Style()->GetPosition();
-  if (position == EPosition::kFixed)
+  if (position == EPosition::kFixed) {
     return layer->FixedToViewport() &&
            layout_view_.GetFrameView()->IsScrollable();
+  }
   DCHECK_EQ(position, EPosition::kSticky);
 
   // Don't promote sticky position elements that cannot move with scrolls.
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.h b/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.h
similarity index 97%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.h
rename to third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.h
index 1fa18d9d..648bd7ce 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.h
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.h
@@ -6,7 +6,7 @@
 #define CompositingReasonFinder_h
 
 #include "core/CoreExport.h"
-#include "core/layout/compositing/CompositingTriggers.h"
+#include "core/paint/compositing/CompositingTriggers.h"
 #include "platform/graphics/CompositingReasons.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Noncopyable.h"
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinderTest.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinderTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinderTest.cpp
rename to third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinderTest.cpp
index b0fb336..42e2004 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinderTest.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/layout/compositing/CompositingReasonFinder.h"
+#include "core/paint/compositing/CompositingReasonFinder.h"
 
 #include "core/frame/LocalFrameView.h"
 #include "core/layout/LayoutBlock.h"
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositingRequirementsUpdater.cpp
similarity index 98%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp
rename to third_party/WebKit/Source/core/paint/compositing/CompositingRequirementsUpdater.cpp
index 0d9ec45..fb9b50d 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingRequirementsUpdater.cpp
@@ -24,13 +24,13 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "core/layout/compositing/CompositingRequirementsUpdater.h"
+#include "core/paint/compositing/CompositingRequirementsUpdater.h"
 
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/PaintLayerStackingNode.h"
 #include "core/paint/PaintLayerStackingNodeIterator.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/instrumentation/tracing/TraceEvent.h"
 
 namespace blink {
@@ -538,9 +538,10 @@
     }
 
     if (will_be_composited_or_squashed &&
-        layer->GetLayoutObject().Style()->HasBlendMode())
+        layer->GetLayoutObject().Style()->HasBlendMode()) {
       current_recursion_data.has_unisolated_composited_blending_descendant_ =
           true;
+    }
 
     // Tell the parent it has compositing descendants.
     if (will_be_composited_or_squashed)
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.h b/third_party/WebKit/Source/core/paint/compositing/CompositingRequirementsUpdater.h
similarity index 100%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.h
rename to third_party/WebKit/Source/core/paint/compositing/CompositingRequirementsUpdater.h
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingState.h b/third_party/WebKit/Source/core/paint/compositing/CompositingState.h
similarity index 100%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingState.h
rename to third_party/WebKit/Source/core/paint/compositing/CompositingState.h
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingTriggers.h b/third_party/WebKit/Source/core/paint/compositing/CompositingTriggers.h
similarity index 100%
rename from third_party/WebKit/Source/core/layout/compositing/CompositingTriggers.h
rename to third_party/WebKit/Source/core/paint/compositing/CompositingTriggers.h
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositorWorkerTest.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositorWorkerTest.cpp
similarity index 98%
rename from third_party/WebKit/Source/core/layout/compositing/CompositorWorkerTest.cpp
rename to third_party/WebKit/Source/core/paint/compositing/CompositorWorkerTest.cpp
index d2561e4..5f25069 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositorWorkerTest.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositorWorkerTest.cpp
@@ -9,9 +9,9 @@
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/WebLocalFrameImpl.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/page/Page.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/graphics/CompositorMutableProperties.h"
 #include "platform/graphics/CompositorMutation.h"
 #include "platform/graphics/GraphicsLayer.h"
diff --git a/third_party/WebKit/Source/core/layout/compositing/GraphicsLayerTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/compositing/GraphicsLayerTreeBuilder.cpp
similarity index 94%
rename from third_party/WebKit/Source/core/layout/compositing/GraphicsLayerTreeBuilder.cpp
rename to third_party/WebKit/Source/core/paint/compositing/GraphicsLayerTreeBuilder.cpp
index 2a1b1187..8326c83e 100644
--- a/third_party/WebKit/Source/core/layout/compositing/GraphicsLayerTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/GraphicsLayerTreeBuilder.cpp
@@ -24,14 +24,14 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "core/layout/compositing/GraphicsLayerTreeBuilder.h"
+#include "core/paint/compositing/GraphicsLayerTreeBuilder.h"
 
 #include "core/html/HTMLMediaElement.h"
 #include "core/html/HTMLVideoElement.h"
 #include "core/layout/LayoutEmbeddedContent.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 
 namespace blink {
 
@@ -82,9 +82,10 @@
     // If a negative z-order child is compositing, we get a foreground layer
     // which needs to get parented.
     if (has_composited_layer_mapping &&
-        current_composited_layer_mapping->ForegroundLayer())
+        current_composited_layer_mapping->ForegroundLayer()) {
       layer_vector_for_children->push_back(
           current_composited_layer_mapping->ForegroundLayer());
+    }
   }
 
   PaintLayerStackingNodeIterator iterator(
@@ -102,9 +103,10 @@
     if (!parented)
       current_composited_layer_mapping->SetSublayers(this_layer_children);
 
-    if (ShouldAppendLayer(layer))
+    if (ShouldAppendLayer(layer)) {
       child_layers.push_back(
           current_composited_layer_mapping->ChildForSuperlayers());
+    }
   }
 
   if (layer.ScrollParent() &&
diff --git a/third_party/WebKit/Source/core/layout/compositing/GraphicsLayerTreeBuilder.h b/third_party/WebKit/Source/core/paint/compositing/GraphicsLayerTreeBuilder.h
similarity index 100%
rename from third_party/WebKit/Source/core/layout/compositing/GraphicsLayerTreeBuilder.h
rename to third_party/WebKit/Source/core/paint/compositing/GraphicsLayerTreeBuilder.h
diff --git a/third_party/WebKit/Source/core/layout/compositing/GraphicsLayerUpdater.cpp b/third_party/WebKit/Source/core/paint/compositing/GraphicsLayerUpdater.cpp
similarity index 95%
rename from third_party/WebKit/Source/core/layout/compositing/GraphicsLayerUpdater.cpp
rename to third_party/WebKit/Source/core/paint/compositing/GraphicsLayerUpdater.cpp
index 3a40e61..4df8b085 100644
--- a/third_party/WebKit/Source/core/layout/compositing/GraphicsLayerUpdater.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/GraphicsLayerUpdater.cpp
@@ -24,14 +24,14 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "core/layout/compositing/GraphicsLayerUpdater.h"
+#include "core/paint/compositing/GraphicsLayerUpdater.h"
 
 #include "core/html/HTMLMediaElement.h"
 #include "core/inspector/InspectorTraceEvents.h"
 #include "core/layout/LayoutBlock.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/instrumentation/tracing/TraceEvent.h"
 
 namespace blink {
@@ -121,18 +121,20 @@
 
   UpdateContext child_context(context, layer);
   for (PaintLayer* child = layer.FirstChild(); child;
-       child = child->NextSibling())
+       child = child->NextSibling()) {
     UpdateRecursive(*child, update_type, child_context,
                     layers_needing_paint_invalidation);
+  }
 }
 
 #if DCHECK_IS_ON()
 
 void GraphicsLayerUpdater::AssertNeedsToUpdateGraphicsLayerBitsCleared(
     PaintLayer& layer) {
-  if (layer.HasCompositedLayerMapping())
+  if (layer.HasCompositedLayerMapping()) {
     layer.GetCompositedLayerMapping()
         ->AssertNeedsToUpdateGraphicsLayerBitsCleared();
+  }
 
   for (PaintLayer* child = layer.FirstChild(); child;
        child = child->NextSibling())
diff --git a/third_party/WebKit/Source/core/layout/compositing/GraphicsLayerUpdater.h b/third_party/WebKit/Source/core/paint/compositing/GraphicsLayerUpdater.h
similarity index 100%
rename from third_party/WebKit/Source/core/layout/compositing/GraphicsLayerUpdater.h
rename to third_party/WebKit/Source/core/paint/compositing/GraphicsLayerUpdater.h
diff --git a/third_party/WebKit/Source/core/layout/compositing/OWNERS b/third_party/WebKit/Source/core/paint/compositing/OWNERS
similarity index 100%
rename from third_party/WebKit/Source/core/layout/compositing/OWNERS
rename to third_party/WebKit/Source/core/paint/compositing/OWNERS
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp b/third_party/WebKit/Source/core/paint/compositing/PaintLayerCompositor.cpp
similarity index 97%
rename from third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
rename to third_party/WebKit/Source/core/paint/compositing/PaintLayerCompositor.cpp
index e603361..bb56b73b 100644
--- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/PaintLayerCompositor.cpp
@@ -23,7 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "core/layout/compositing/PaintLayerCompositor.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 
 #include "core/animation/DocumentAnimations.h"
 #include "core/animation/DocumentTimeline.h"
@@ -41,12 +41,6 @@
 #include "core/layout/LayoutEmbeddedContent.h"
 #include "core/layout/LayoutVideo.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/CompositingInputsUpdater.h"
-#include "core/layout/compositing/CompositingLayerAssigner.h"
-#include "core/layout/compositing/CompositingRequirementsUpdater.h"
-#include "core/layout/compositing/GraphicsLayerTreeBuilder.h"
-#include "core/layout/compositing/GraphicsLayerUpdater.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
@@ -54,6 +48,12 @@
 #include "core/paint/FramePainter.h"
 #include "core/paint/ObjectPaintInvalidator.h"
 #include "core/paint/TransformRecorder.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/CompositingInputsUpdater.h"
+#include "core/paint/compositing/CompositingLayerAssigner.h"
+#include "core/paint/compositing/CompositingRequirementsUpdater.h"
+#include "core/paint/compositing/GraphicsLayerTreeBuilder.h"
+#include "core/paint/compositing/GraphicsLayerUpdater.h"
 #include "core/probe/CoreProbes.h"
 #include "platform/Histogram.h"
 #include "platform/RuntimeEnabledFeatures.h"
@@ -566,9 +566,10 @@
       // frame.
       if (layer->IsRootLayer() && layout_view_.GetFrame()->IsLocalRoot()) {
         if (ScrollingCoordinator* scrolling_coordinator =
-                this->GetScrollingCoordinator())
+                this->GetScrollingCoordinator()) {
           scrolling_coordinator->FrameViewRootLayerDidChange(
               layout_view_.GetFrameView());
+        }
       }
       break;
     case kRemoveOwnCompositedLayerMapping:
@@ -603,9 +604,10 @@
   // recalculate whether it can do fast scrolling.
   if (composited_layer_mapping_changed) {
     if (ScrollingCoordinator* scrolling_coordinator =
-            this->GetScrollingCoordinator())
+            this->GetScrollingCoordinator()) {
       scrolling_coordinator->FrameViewFixedObjectsDidChange(
           layout_view_.GetFrameView());
+    }
   }
 
   return composited_layer_mapping_changed;
@@ -1015,9 +1017,10 @@
                                           tracks_paint_invalidations);
   }
 
-  if (GraphicsLayer* mask_layer = graphics_layer->MaskLayer())
+  if (GraphicsLayer* mask_layer = graphics_layer->MaskLayer()) {
     SetTracksRasterInvalidationsRecursive(mask_layer,
                                           tracks_paint_invalidations);
+  }
 
   if (GraphicsLayer* clipping_mask_layer =
           graphics_layer->ContentsClippingMaskLayer()) {
@@ -1035,9 +1038,10 @@
 #endif
 
   is_tracking_raster_invalidations_ = tracks_raster_invalidations;
-  if (GraphicsLayer* root_layer = RootGraphicsLayer())
+  if (GraphicsLayer* root_layer = RootGraphicsLayer()) {
     SetTracksRasterInvalidationsRecursive(root_layer,
                                           tracks_raster_invalidations);
+  }
 }
 
 bool PaintLayerCompositor::IsTrackingRasterInvalidations() const {
@@ -1073,18 +1077,20 @@
       controls_parent->AddChild(layer_for_horizontal_scrollbar_.get());
 
       if (ScrollingCoordinator* scrolling_coordinator =
-              this->GetScrollingCoordinator())
+              this->GetScrollingCoordinator()) {
         scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
             layout_view_.GetFrameView(), kHorizontalScrollbar);
+      }
     }
   } else if (layer_for_horizontal_scrollbar_) {
     layer_for_horizontal_scrollbar_->RemoveFromParent();
     layer_for_horizontal_scrollbar_ = nullptr;
 
     if (ScrollingCoordinator* scrolling_coordinator =
-            this->GetScrollingCoordinator())
+            this->GetScrollingCoordinator()) {
       scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
           layout_view_.GetFrameView(), kHorizontalScrollbar);
+    }
   }
 
   if (RequiresVerticalScrollbarLayer()) {
@@ -1096,18 +1102,20 @@
       controls_parent->AddChild(layer_for_vertical_scrollbar_.get());
 
       if (ScrollingCoordinator* scrolling_coordinator =
-              this->GetScrollingCoordinator())
+              this->GetScrollingCoordinator()) {
         scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
             layout_view_.GetFrameView(), kVerticalScrollbar);
+      }
     }
   } else if (layer_for_vertical_scrollbar_) {
     layer_for_vertical_scrollbar_->RemoveFromParent();
     layer_for_vertical_scrollbar_ = nullptr;
 
     if (ScrollingCoordinator* scrolling_coordinator =
-            this->GetScrollingCoordinator())
+            this->GetScrollingCoordinator()) {
       scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
           layout_view_.GetFrameView(), kVerticalScrollbar);
+    }
   }
 
   if (RequiresScrollCornerLayer()) {
@@ -1170,9 +1178,10 @@
     container_layer_ = GraphicsLayer::Create(this);
     scroll_layer_ = GraphicsLayer::Create(this);
     if (ScrollingCoordinator* scrolling_coordinator =
-            this->GetScrollingCoordinator())
+            this->GetScrollingCoordinator()) {
       scrolling_coordinator->SetLayerIsContainerForFixedPositionLayers(
           scroll_layer_.get(), true);
+    }
 
     // In RLS mode, LayoutView scrolling contents layer gets this element ID (in
     // CompositedLayerMapping::updateElementIdAndCompositorMutableProperties).
@@ -1200,9 +1209,10 @@
     layer_for_horizontal_scrollbar_->RemoveFromParent();
     layer_for_horizontal_scrollbar_ = nullptr;
     if (ScrollingCoordinator* scrolling_coordinator =
-            this->GetScrollingCoordinator())
+            this->GetScrollingCoordinator()) {
       scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
           layout_view_.GetFrameView(), kHorizontalScrollbar);
+    }
     layout_view_.GetFrameView()->SetScrollbarNeedsPaintInvalidation(
         kHorizontalScrollbar);
   }
@@ -1211,9 +1221,10 @@
     layer_for_vertical_scrollbar_->RemoveFromParent();
     layer_for_vertical_scrollbar_ = nullptr;
     if (ScrollingCoordinator* scrolling_coordinator =
-            this->GetScrollingCoordinator())
+            this->GetScrollingCoordinator()) {
       scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
           layout_view_.GetFrameView(), kVerticalScrollbar);
+    }
     layout_view_.GetFrameView()->SetScrollbarNeedsPaintInvalidation(
         kVerticalScrollbar);
   }
@@ -1293,9 +1304,10 @@
 
   CompositorAnimationTimeline* compositor_timeline =
       frame.GetDocument()->Timeline().CompositorTimeline();
-  if (compositor_timeline)
+  if (compositor_timeline) {
     page->GetChromeClient().AttachCompositorAnimationTimeline(
         compositor_timeline, &frame);
+  }
 }
 
 void PaintLayerCompositor::DetachCompositorTimeline() {
@@ -1306,9 +1318,10 @@
 
   CompositorAnimationTimeline* compositor_timeline =
       frame.GetDocument()->Timeline().CompositorTimeline();
-  if (compositor_timeline)
+  if (compositor_timeline) {
     page->GetChromeClient().DetachCompositorAnimationTimeline(
         compositor_timeline, &frame);
+  }
 }
 
 ScrollingCoordinator* PaintLayerCompositor::GetScrollingCoordinator() const {
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.h b/third_party/WebKit/Source/core/paint/compositing/PaintLayerCompositor.h
similarity index 99%
rename from third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.h
rename to third_party/WebKit/Source/core/paint/compositing/PaintLayerCompositor.h
index 07ef6f4..bc67cd7 100644
--- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.h
+++ b/third_party/WebKit/Source/core/paint/compositing/PaintLayerCompositor.h
@@ -29,7 +29,7 @@
 #include <memory>
 #include "core/CoreExport.h"
 #include "core/dom/DocumentLifecycle.h"
-#include "core/layout/compositing/CompositingReasonFinder.h"
+#include "core/paint/compositing/CompositingReasonFinder.h"
 #include "platform/graphics/GraphicsLayerClient.h"
 #include "platform/wtf/HashMap.h"
 
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositorTest.cpp b/third_party/WebKit/Source/core/paint/compositing/PaintLayerCompositorTest.cpp
similarity index 96%
rename from third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositorTest.cpp
rename to third_party/WebKit/Source/core/paint/compositing/PaintLayerCompositorTest.cpp
index c483246..9feaed3 100644
--- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositorTest.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/PaintLayerCompositorTest.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/layout/compositing/PaintLayerCompositor.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 
 #include "core/animation/Animation.h"
 #include "core/animation/ElementAnimation.h"
@@ -23,7 +23,7 @@
     EnableCompositing();
   }
 };
-}
+}  // namespace
 
 TEST_F(PaintLayerCompositorTest, AdvancingToCompositingInputsClean) {
   SetBodyInnerHTML("<div id='box' style='position: relative'></div>");
@@ -85,4 +85,4 @@
   EXPECT_EQ(boxAnimations.front()->CompositorGroup(),
             otherBoxAnimations.front()->CompositorGroup());
 }
-}
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/scheduler/FrameThrottlingTest.cpp b/third_party/WebKit/Source/core/scheduler/FrameThrottlingTest.cpp
index 71e04f4..8db9bfb 100644
--- a/third_party/WebKit/Source/core/scheduler/FrameThrottlingTest.cpp
+++ b/third_party/WebKit/Source/core/scheduler/FrameThrottlingTest.cpp
@@ -12,10 +12,10 @@
 #include "core/frame/WebLocalFrameImpl.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "core/testing/sim/SimCompositor.h"
 #include "core/testing/sim/SimDisplayItemList.h"
 #include "core/testing/sim/SimRequest.h"
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index aa68ffc..d36b562 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -102,8 +102,6 @@
 #include "core/layout/LayoutTreeAsText.h"
 #include "core/layout/api/LayoutMenuListItem.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoader.h"
 #include "core/loader/HistoryItem.h"
@@ -113,6 +111,8 @@
 #include "core/page/PrintContext.h"
 #include "core/page/scrolling/ScrollState.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/probe/CoreProbes.h"
 #include "core/svg/SVGImageElement.h"
 #include "core/testing/CallbackFunctionTest.h"
diff --git a/third_party/WebKit/Source/core/testing/sim/SimCompositor.cpp b/third_party/WebKit/Source/core/testing/sim/SimCompositor.cpp
index 828399e..091eb5e6 100644
--- a/third_party/WebKit/Source/core/testing/sim/SimCompositor.cpp
+++ b/third_party/WebKit/Source/core/testing/sim/SimCompositor.cpp
@@ -9,9 +9,9 @@
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/WebLocalFrameImpl.h"
 #include "core/layout/api/LayoutViewItem.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "core/testing/sim/SimDisplayItemList.h"
 #include "platform/graphics/ContentLayerDelegate.h"
 #include "platform/graphics/GraphicsLayer.h"
diff --git a/third_party/WebKit/Source/devtools/scripts/build/generate_devtools_grd.py b/third_party/WebKit/Source/devtools/scripts/build/generate_devtools_grd.py
index 6794459..fa6595cea 100755
--- a/third_party/WebKit/Source/devtools/scripts/build/generate_devtools_grd.py
+++ b/third_party/WebKit/Source/devtools/scripts/build/generate_devtools_grd.py
@@ -155,7 +155,7 @@
         add_file_to_grd(doc, relative_filename)
 
     for dirname in parsed_args.image_dirs:
-        for filename in os.listdir(dirname):
+        for filename in sorted(os.listdir(dirname)):
             if not filename.endswith('.png') and not filename.endswith('.gif') and not filename.endswith('.svg'):
                 continue
             shutil.copy(path.join(dirname, filename), path.join(output_directory, 'Images'))
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
index 7d938e6..b83790b0 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -1521,7 +1521,8 @@
 bool MarkerTypeIsUsedForAccessibility(DocumentMarker::MarkerType type) {
   return DocumentMarker::MarkerTypes(
              DocumentMarker::kSpelling | DocumentMarker::kGrammar |
-             DocumentMarker::kTextMatch | DocumentMarker::kActiveSuggestion)
+             DocumentMarker::kTextMatch | DocumentMarker::kActiveSuggestion |
+             DocumentMarker::kSuggestion)
       .Contains(type);
 }
 
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
index 942bf08a..2db1a00 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
@@ -15,8 +15,8 @@
 #include "core/imagebitmap/ImageBitmap.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/loader/DocumentLoader.h"
+#include "core/paint/compositing/PaintLayerCompositor.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
 #include "modules/EventTargetModules.h"
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
index 991526b..92349db 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
@@ -716,7 +716,9 @@
 
 void BaseAudioContext::NotifySourceNodeFinishedProcessing(
     AudioHandler* handler) {
-  DCHECK(IsAudioThread());
+  // This can be called from either the main thread or the audio thread.  The
+  // mutex below protects access to |finished_source_handlers_| between the two
+  // threads.
   MutexLocker lock(finished_source_handlers_mutex_);
   finished_source_handlers_.push_back(handler);
 }
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 57811c2..c9d207c 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -772,6 +772,7 @@
     "fonts/shaping/HarfBuzzShaper.h",
     "fonts/shaping/RunSegmenter.cpp",
     "fonts/shaping/RunSegmenter.h",
+    "fonts/shaping/ShapeCache.cpp",
     "fonts/shaping/ShapeCache.h",
     "fonts/shaping/ShapeResult.cpp",
     "fonts/shaping/ShapeResult.h",
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedSelection.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.cpp
similarity index 67%
copy from third_party/WebKit/Source/core/layout/compositing/CompositedSelection.h
copy to third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.cpp
index b356e95..9899605 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedSelection.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Google Inc. All rights reserved.
+ * Copyright (c) 2012, 2017 Google Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -28,29 +28,15 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef CompositedSelection_h
-#define CompositedSelection_h
-
-#include "core/editing/SelectionType.h"
-#include "core/layout/compositing/CompositedSelectionBound.h"
-#include "platform/geometry/FloatPoint.h"
-#include "platform/graphics/GraphicsLayer.h"
-#include "platform/wtf/Allocator.h"
+#include "platform/fonts/shaping/ShapeCache.h"
+#include "platform/wtf/StringHasher.h"
 
 namespace blink {
 
-// The active selection region, containing compositing data for the selection
-// end points as well as metadata for the selection region.
-// See |WebSelection|.
-struct CompositedSelection {
-  STACK_ALLOCATED();
-  CompositedSelection() : type(kNoSelection) {}
-
-  SelectionType type;
-  CompositedSelectionBound start;
-  CompositedSelectionBound end;
-};
+void ShapeCache::SmallStringKey::HashString() {
+  // TODO(cavalcantii): replace this for a better hash function,
+  // see crbug.com/735674.
+  hash_ = StringHasher::ComputeHash(characters_, length_);
+}
 
 }  // namespace blink
-
-#endif  // CompositedSelection_h
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
index 37498c9..b4b41d5 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
@@ -33,7 +33,6 @@
 #include "platform/wtf/HashFunctions.h"
 #include "platform/wtf/HashSet.h"
 #include "platform/wtf/HashTableDeletedValueType.h"
-#include "platform/wtf/StringHasher.h"
 #include "platform/wtf/WeakPtr.h"
 
 namespace blink {
@@ -47,13 +46,13 @@
 class ShapeCache {
   USING_FAST_MALLOC(ShapeCache);
   WTF_MAKE_NONCOPYABLE(ShapeCache);
-
- private:
   // Used to optimize small strings as hash table keys. Avoids malloc'ing an
   // out-of-line StringImpl.
   class SmallStringKey {
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
+    void HashString();
+
    public:
     static unsigned Capacity() { return kCapacity; }
 
@@ -65,32 +64,26 @@
         : length_(kDeletedValueLength),
           direction_(static_cast<unsigned>(TextDirection::kLtr)) {}
 
-    template <typename CharacterType>
-    SmallStringKey(CharacterType* characters,
+    SmallStringKey(const LChar* characters,
                    unsigned short length,
                    TextDirection direction)
         : length_(length), direction_(static_cast<unsigned>(direction)) {
       DCHECK(length <= kCapacity);
-
-      StringHasher hasher;
-
-      bool remainder = length & 1;
-      length >>= 1;
-
-      unsigned i = 0;
-      while (length--) {
+      // Up-convert from LChar to UChar.
+      for (unsigned short i = 0; i < length; ++i) {
         characters_[i] = characters[i];
-        characters_[i + 1] = characters[i + 1];
-        hasher.AddCharactersAssumingAligned(characters[i], characters[i + 1]);
-        i += 2;
       }
 
-      if (remainder) {
-        characters_[i] = characters[i];
-        hasher.AddCharacter(characters[i]);
-      }
+      HashString();
+    }
 
-      hash_ = hasher.GetHash();
+    SmallStringKey(const UChar* characters,
+                   unsigned short length,
+                   TextDirection direction)
+        : length_(length), direction_(static_cast<unsigned>(direction)) {
+      DCHECK(length <= kCapacity);
+      memcpy(characters_, characters, length * sizeof(UChar));
+      HashString();
     }
 
     const UChar* Characters() const { return characters_; }
@@ -116,30 +109,11 @@
     UChar characters_[kCapacity];
   };
 
-  struct SmallStringKeyHash {
-    STATIC_ONLY(SmallStringKeyHash);
-    static unsigned GetHash(const SmallStringKey& key) { return key.GetHash(); }
-    static bool Equal(const SmallStringKey& a, const SmallStringKey& b) {
-      return a == b;
-    }
-    // Empty and deleted values have lengths that are not equal to any valid
-    // length.
-    static const bool safe_to_compare_to_empty_or_deleted = true;
-  };
-
-  struct SmallStringKeyHashTraits : WTF::SimpleClassHashTraits<SmallStringKey> {
-    STATIC_ONLY(SmallStringKeyHashTraits);
-    static const bool kHasIsEmptyValueFunction = true;
-    static bool IsEmptyValue(const SmallStringKey& key) {
-      return key.IsHashTableEmptyValue();
-    }
-    static const unsigned kMinimumTableSize = 16;
-  };
-
-  friend bool operator==(const SmallStringKey&, const SmallStringKey&);
-
  public:
-  ShapeCache() : weak_factory_(this), version_(0) {}
+  ShapeCache() : weak_factory_(this), version_(0) {
+    // TODO(cavalcantii): Investigate tradeoffs of reserving space
+    // in short_string_map.
+  }
 
   ShapeCacheEntry* Add(const TextRun& run, ShapeCacheEntry entry) {
     if (run.length() > SmallStringKey::Capacity())
@@ -184,8 +158,8 @@
     ShapeCacheEntry* value;
     if (length == 1) {
       uint32_t key = run[0];
-      // All current codepointsin UTF-32 are bewteen 0x0 and 0x10FFFF,
-      // as such use bit 32 to indicate direction.
+      // All current codepoints in UTF-32 are bewteen 0x0 and 0x10FFFF,
+      // as such use bit 31 (zero-based) to indicate direction.
       if (run.Direction() == TextDirection::kRtl)
         key |= (1u << 31);
       SingleCharMap::AddResult add_result = single_char_map_.insert(key, entry);
@@ -193,12 +167,13 @@
       value = &add_result.stored_value->value;
     } else {
       SmallStringKey small_string_key;
-      if (run.Is8Bit())
+      if (run.Is8Bit()) {
         small_string_key =
             SmallStringKey(run.Characters8(), length, run.Direction());
-      else
+      } else {
         small_string_key =
             SmallStringKey(run.Characters16(), length, run.Direction());
+      }
 
       SmallStringMap::AddResult add_result =
           short_string_map_.insert(small_string_key, entry);
@@ -206,19 +181,39 @@
       value = &add_result.stored_value->value;
     }
 
-    if (!is_new_entry)
+    if ((!is_new_entry) || (size() < kMaxSize)) {
       return value;
-
-    if (size() < kMaxSize)
-      return value;
+    }
 
     // No need to be fancy: we're just trying to avoid pathological growth.
     single_char_map_.clear();
     short_string_map_.clear();
 
-    return 0;
+    return nullptr;
   }
 
+  struct SmallStringKeyHash {
+    STATIC_ONLY(SmallStringKeyHash);
+    static unsigned GetHash(const SmallStringKey& key) { return key.GetHash(); }
+    static bool Equal(const SmallStringKey& a, const SmallStringKey& b) {
+      return a == b;
+    }
+    // Empty and deleted values have lengths that are not equal to any valid
+    // length.
+    static const bool safe_to_compare_to_empty_or_deleted = true;
+  };
+
+  struct SmallStringKeyHashTraits : WTF::SimpleClassHashTraits<SmallStringKey> {
+    STATIC_ONLY(SmallStringKeyHashTraits);
+    static const bool kHasIsEmptyValueFunction = true;
+    static bool IsEmptyValue(const SmallStringKey& key) {
+      return key.IsHashTableEmptyValue();
+    }
+    static const unsigned kMinimumTableSize = 16;
+  };
+
+  friend bool operator==(const SmallStringKey&, const SmallStringKey&);
+
   typedef HashMap<SmallStringKey,
                   ShapeCacheEntry,
                   SmallStringKeyHash,
diff --git a/third_party/WebKit/Source/platform/graphics/CompositorFilterOperations.cpp b/third_party/WebKit/Source/platform/graphics/CompositorFilterOperations.cpp
index 575a2a8..72789a6 100644
--- a/third_party/WebKit/Source/platform/graphics/CompositorFilterOperations.cpp
+++ b/third_party/WebKit/Source/platform/graphics/CompositorFilterOperations.cpp
@@ -64,7 +64,8 @@
       gfx_offset, std_deviation, color.Rgb()));
 }
 
-void CompositorFilterOperations::AppendColorMatrixFilter(SkScalar matrix[20]) {
+void CompositorFilterOperations::AppendColorMatrixFilter(
+    const cc::FilterOperation::Matrix& matrix) {
   filter_operations_.Append(
       cc::FilterOperation::CreateColorMatrixFilter(matrix));
 }
diff --git a/third_party/WebKit/Source/platform/graphics/CompositorFilterOperations.h b/third_party/WebKit/Source/platform/graphics/CompositorFilterOperations.h
index 6c63755b..3af3a32 100644
--- a/third_party/WebKit/Source/platform/graphics/CompositorFilterOperations.h
+++ b/third_party/WebKit/Source/platform/graphics/CompositorFilterOperations.h
@@ -33,7 +33,7 @@
   void AppendOpacityFilter(float amount);
   void AppendBlurFilter(float amount);
   void AppendDropShadowFilter(IntPoint offset, float std_deviation, Color);
-  void AppendColorMatrixFilter(SkScalar matrix[20]);
+  void AppendColorMatrixFilter(const cc::FilterOperation::Matrix&);
   void AppendZoomFilter(float amount, int inset);
   void AppendSaturatingBrightnessFilter(float amount);
 
diff --git a/third_party/WebKit/Source/platform/mojo/CommonCustomTypesStructTraits.cpp b/third_party/WebKit/Source/platform/mojo/CommonCustomTypesStructTraits.cpp
index ee1546b..15f496fc8 100644
--- a/third_party/WebKit/Source/platform/mojo/CommonCustomTypesStructTraits.cpp
+++ b/third_party/WebKit/Source/platform/mojo/CommonCustomTypesStructTraits.cpp
@@ -31,12 +31,12 @@
 
   if (contextObject) {
     return ConstCArray<uint16_t>(
-        contextObject->size(),
-        reinterpret_cast<const uint16_t*>(contextObject->data()));
+        reinterpret_cast<const uint16_t*>(contextObject->data()),
+        contextObject->size());
   }
 
   return ConstCArray<uint16_t>(
-      input.length(), reinterpret_cast<const uint16_t*>(input.Characters16()));
+      reinterpret_cast<const uint16_t*>(input.Characters16()), input.length());
 }
 
 // static
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
deleted file mode 100644
index 5dee02a..0000000
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/ui.gni")
-import("//testing/test.gni")
-import("//third_party/WebKit/Source/bindings/bindings.gni")
-import("//third_party/WebKit/Source/config.gni")
-import("//third_party/WebKit/Source/core/core.gni")
-import("//third_party/WebKit/Source/modules/modules.gni")
diff --git a/third_party/WebKit/Source/web/DEPS b/third_party/WebKit/Source/web/DEPS
deleted file mode 100644
index 0ec881c..0000000
--- a/third_party/WebKit/Source/web/DEPS
+++ /dev/null
@@ -1,17 +0,0 @@
-include_rules = [
-    "+..",
-    "+bindings",
-    "+controller",
-    "+core",
-    "+gin/public",
-    "+modules",
-    "+painting",
-    "+platform",
-    "+public",
-    "+public/platform",
-    "+skia",
-    "+third_party/khronos",
-    "+third_party/skia",
-    "+ui/gfx/geometry",
-    "+web",
-]
diff --git a/third_party/WebKit/Source/web/OWNERS b/third_party/WebKit/Source/web/OWNERS
deleted file mode 100644
index bfa525a..0000000
--- a/third_party/WebKit/Source/web/OWNERS
+++ /dev/null
@@ -1,25 +0,0 @@
-aelias@chromium.org
-bokan@chromium.org
-dcheng@chromium.org
-dglazkov@chromium.org
-dgozman@chromium.org
-haraken@chromium.org
-japhet@chromium.org
-jochen@chromium.org
-kbr@chromium.org
-kinuko@chromium.org
-keishi@chromium.org
-mkwst@chromium.org
-pfeldman@chromium.org
-pdr@chromium.org
-schenney@chromium.org
-tkent@chromium.org
-
-per-file AssertMatchingEnums.cpp=*
-
-# Page load metrics
-per-file WebPerformance.cpp=bmcquade@chromium.org
-per-file WebPerformance.cpp=csharrison@chromium.org
-
-# TEAM: platform-architecture-dev@chromium.org
-# COMPONENT: Blink>Internals>Modularization
diff --git a/third_party/WebKit/public/platform/modules/payments/payment_app.mojom b/third_party/WebKit/public/platform/modules/payments/payment_app.mojom
index 68e38d81..712d2a6 100644
--- a/third_party/WebKit/public/platform/modules/payments/payment_app.mojom
+++ b/third_party/WebKit/public/platform/modules/payments/payment_app.mojom
@@ -82,8 +82,10 @@
 // This interface is provided to pass a payment handler response from payment
 // request event in renderer side to browser side by calling respondWith().
 interface PaymentHandlerResponseCallback {
-  OnResponseForPaymentRequest(PaymentHandlerResponse response,
-                              mojo.common.mojom.Time dispatch_event_time);
+  OnResponseForAbortPayment(bool payment_aborted,
+                            mojo.common.mojom.Time dispatch_event_time);
   OnResponseForCanMakePayment(bool can_make_payment,
                               mojo.common.mojom.Time dispatch_event_time);
+  OnResponseForPaymentRequest(PaymentHandlerResponse response,
+                              mojo.common.mojom.Time dispatch_event_time);
 };
diff --git a/third_party/WebKit/public/web/WebAXEnums.h b/third_party/WebKit/public/web/WebAXEnums.h
index f04eb6b6..630b2b2d 100644
--- a/third_party/WebKit/public/web/WebAXEnums.h
+++ b/third_party/WebKit/public/web/WebAXEnums.h
@@ -291,6 +291,7 @@
   kWebAXMarkerTypeTextMatch = 1 << 2,
   // Skip DocumentMarker::MarkerType::Composition
   kWebAXMarkerTypeActiveSuggestion = 1 << 4,
+  kWebAXMarkerTypeSuggestion = 1 << 5,
 };
 
 // Used for exposing text attributes.
diff --git a/third_party/khronos/EGL/eglplatform.h b/third_party/khronos/EGL/eglplatform.h
index fad491b..161cfa3 100644
--- a/third_party/khronos/EGL/eglplatform.h
+++ b/third_party/khronos/EGL/eglplatform.h
@@ -77,7 +77,7 @@
 typedef HBITMAP EGLNativePixmapType;
 typedef HWND    EGLNativeWindowType;
 
-#elif defined(__WINSCW__) || defined(__SYMBIAN32__) || defined(__Fuchsia__)
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__)
 
 typedef int   EGLNativeDisplayType;
 typedef void *EGLNativeWindowType;
diff --git a/third_party/khronos/README.chromium b/third_party/khronos/README.chromium
index e6b667f8..83eaa5a2 100644
--- a/third_party/khronos/README.chromium
+++ b/third_party/khronos/README.chromium
@@ -31,7 +31,6 @@
 EGL/eglplatform.h
  - Added EGLNative*Type for Mac.
  - Added EGLNative*Type for native linux framebuffers.
- - Added EGLNative*Type for Fuchsia.
 EGL/eglext.h
  - Added support for EGL_EXT_image_flush_external extension
  - Added support for EGL_ANGLE_stream_producer_d3d_texture_nv12
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
index 3ce45e2..ef579f0 100644
--- a/third_party/leveldatabase/env_chromium.cc
+++ b/third_party/leveldatabase/env_chromium.cc
@@ -363,6 +363,24 @@
 
 }  // unnamed namespace
 
+Options::Options() {
+// Note: Ensure that these default values correspond to those in
+// components/leveldb/public/interfaces/leveldb.mojom.
+// TODO(cmumford) Create struct-trait for leveldb.mojom.OpenOptions to force
+// users to pass in a leveldb_env::Options instance (and it's defaults).
+//
+// Currently log reuse is an experimental feature in leveldb. More info at:
+// https://github.com/google/leveldb/commit/251ebf5dc70129ad3
+#if defined(OS_CHROMEOS)
+  // Reusing logs on Chrome OS resulted in an unacceptably high leveldb
+  // corruption rate (at least for Indexed DB). More info at
+  // https://crbug.com/460568
+  reuse_logs = false;
+#else
+  reuse_logs = true;
+#endif
+}
+
 const char* MethodIDToString(MethodID method) {
   switch (method) {
     case kSequentialFileRead:
@@ -551,7 +569,7 @@
 // There is no way to know the size of A, so minimizing the size of B will
 // maximize the likelihood of a successful compaction.
 size_t WriteBufferSize(int64_t disk_size) {
-  const leveldb::Options default_options;
+  const leveldb_env::Options default_options;
   const int64_t kMinBufferSize = 1024 * 1024;
   const int64_t kMaxBufferSize = default_options.write_buffer_size;
   const int64_t kDiskMinBuffSize = 10 * 1024 * 1024;
@@ -1290,7 +1308,7 @@
   database->RemoveFromList();
 }
 
-leveldb::Status OpenDB(const leveldb::Options& options,
+leveldb::Status OpenDB(const leveldb_env::Options& options,
                        const std::string& name,
                        std::unique_ptr<leveldb::DB>* dbptr) {
   DBTracker::TrackedDB* tracked_db = nullptr;
diff --git a/third_party/leveldatabase/env_chromium.h b/third_party/leveldatabase/env_chromium.h
index 02a68c6..c4617ad1 100644
--- a/third_party/leveldatabase/env_chromium.h
+++ b/third_party/leveldatabase/env_chromium.h
@@ -67,16 +67,10 @@
 
 LevelDBStatusValue GetLevelDBStatusUMAValue(const leveldb::Status& s);
 
-// The default value for leveldb::Options::reuse_logs. Currently log reuse is an
-// experimental feature in leveldb. More info at:
-// https://github.com/google/leveldb/commit/251ebf5dc70129ad3
-#if defined(OS_CHROMEOS)
-// Reusing logs on Chrome OS resulted in an unacceptably high leveldb corruption
-// rate (at least for Indexed DB). More info at https://crbug.com/460568
-const bool kDefaultLogReuseOptionValue = false;
-#else
-const bool kDefaultLogReuseOptionValue = true;
-#endif
+// Create the default leveldb options object suitable for leveldb operations.
+struct Options : public leveldb::Options {
+  Options();
+};
 
 const char* MethodIDToString(MethodID method);
 
@@ -297,7 +291,7 @@
 // details). The function guarantees that:
 //   1. |dbptr| is not touched on failure
 //   2. |dbptr| is not NULL on success
-leveldb::Status OpenDB(const leveldb::Options& options,
+leveldb::Status OpenDB(const leveldb_env::Options& options,
                        const std::string& name,
                        std::unique_ptr<leveldb::DB>* dbptr);
 
diff --git a/third_party/leveldatabase/env_chromium_unittest.cc b/third_party/leveldatabase/env_chromium_unittest.cc
index 12bad1e4..a490596 100644
--- a/third_party/leveldatabase/env_chromium_unittest.cc
+++ b/third_party/leveldatabase/env_chromium_unittest.cc
@@ -23,7 +23,6 @@
 
 using leveldb::DB;
 using leveldb::Env;
-using leveldb::Options;
 using leveldb::ReadOptions;
 using leveldb::Slice;
 using leveldb::Status;
@@ -32,6 +31,7 @@
 using leveldb_env::ChromiumEnv;
 using leveldb_env::DBTracker;
 using leveldb_env::MethodID;
+using leveldb_env::Options;
 
 TEST(ErrorEncoding, OnlyAMethod) {
   const MethodID in_method = leveldb_env::kSequentialFileRead;
diff --git a/third_party/libFuzzer/BUILD.gn b/third_party/libFuzzer/BUILD.gn
index fa589511..8d08d1a3 100644
--- a/third_party/libFuzzer/BUILD.gn
+++ b/third_party/libFuzzer/BUILD.gn
@@ -11,6 +11,7 @@
     "src/FuzzerCrossOver.cpp",
     "src/FuzzerDriver.cpp",
     "src/FuzzerExtFunctionsDlsym.cpp",
+    "src/FuzzerExtFunctionsDlsymWin.cpp",
     "src/FuzzerExtFunctionsWeak.cpp",
     "src/FuzzerExtFunctionsWeakAlias.cpp",
     "src/FuzzerExtraCounters.cpp",
@@ -23,8 +24,8 @@
     "src/FuzzerMutate.cpp",
     "src/FuzzerSHA1.cpp",
     "src/FuzzerShmemPosix.cpp",
+    "src/FuzzerShmemWindows.cpp",
     "src/FuzzerTracePC.cpp",
-    "src/FuzzerTraceState.cpp",
     "src/FuzzerUtil.cpp",
     "src/FuzzerUtilDarwin.cpp",
     "src/FuzzerUtilLinux.cpp",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 2e9068b..3d561bc 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -23283,6 +23283,7 @@
   <int value="-88273414" label="ContentSuggestionsShowSummary:enabled"/>
   <int value="-86788587" label="allow-autofill-sync-credential"/>
   <int value="-80353187" label="disable-display-color-calibration"/>
+  <int value="-80222766" label="AutofillUpstreamShowNewUi:disabled"/>
   <int value="-78035185" label="custom_summary"/>
   <int value="-77872983" label="BookmarkAppsMac:disabled"/>
   <int value="-76631048" label="disable-offline-auto-reload-visible-only"/>
@@ -23643,6 +23644,7 @@
   <int value="1126061778" label="CaptureThumbnailOnLoadFinished:enabled"/>
   <int value="1127183523" label="PassiveEventListenersDueToFling:enabled"/>
   <int value="1127427821" label="OmniboxEntitySuggestions:disabled"/>
+  <int value="1127900329" label="AutofillUpstreamShowNewUi:enabled"/>
   <int value="1129888794" label="ash-touch-hud"/>
   <int value="1133635187" label="force-gpu-rasterization"/>
   <int value="1139226452" label="enable-nacl-debug"/>
@@ -33803,6 +33805,7 @@
   <int value="26" label="BACKGROUND_FETCHED"/>
   <int value="27" label="NAVIGATION_HINT"/>
   <int value="28" label="CAN_MAKE_PAYMENT"/>
+  <int value="29" label="ABORT_PAYMENT"/>
 </enum>
 
 <enum name="ServiceWorkerPreparationType">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 8f2bffcc..148e47d9 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -14970,6 +14970,16 @@
   <summary>Time taken to create a single download in the history DB.</summary>
 </histogram>
 
+<histogram name="Download.Database.IsAvailable" enum="BooleanAvailable">
+  <owner>xingliu@chromium.org</owner>
+  <summary>
+    Records whether the download database is available when database startup
+    completes, before starting any pending downloads.  If the database is
+    available, it will provide the next download id. Or no download history will
+    be persisted.
+  </summary>
+</histogram>
+
 <histogram name="Download.Database.QueryDownloadDuration" units="ms">
   <owner>asanka@chromium.org</owner>
   <summary>Time taken to query all downloads from history DB.</summary>
@@ -32789,6 +32799,15 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.Experimental.Browser.EGLShaderCacheSize.Android"
+    units="KB">
+  <owner>ericrk@chromium.org</owner>
+  <summary>
+    The size of the EGL_ANDROID_blob_cache cache file on disk. Recorded once per
+    Chrome launch, after the first page has loaded.
+  </summary>
+</histogram>
+
 <histogram name="Memory.Experimental.Browser.PrivateMemoryFootprint.MacOS"
     units="MB">
   <owner>erikchen@chromium.org</owner>
@@ -70500,6 +70519,15 @@
   </summary>
 </histogram>
 
+<histogram name="ServiceWorker.AbortPaymentEvent.Time" units="ms">
+  <owner>jinho.bang@samsung.com</owner>
+  <summary>
+    The time taken between dispatching an AbortPaymentEvent to a Service Worker
+    and receiving a message that it finished handling the event. Includes the
+    time for the waitUntil() promise to settle.
+  </summary>
+</histogram>
+
 <histogram name="ServiceWorker.ActivatedWorkerPreparationForMainFrame.Time"
     units="ms">
   <owner>horo@chromium.org</owner>
@@ -71799,7 +71827,23 @@
   </summary>
 </histogram>
 
+<histogram name="SessionRestore.FrameUniqueNameFromRequestedNameSize"
+    units="characters">
+  <owner>dcheng@chromium.org</owner>
+  <summary>
+    The size of a unique name derived from the browsing context name. Emitted
+    when generating a unique name for a new subframe or when a subframe's
+    browsing context name is changed before the first real load is committed.
+    Only applies to subframes as main frames always have an empty unique name.
+  </summary>
+</histogram>
+
 <histogram name="SessionRestore.FrameUniqueNameLength" units="bytes">
+  <obsolete>
+    Deprecated 2017-08 due to unique name generation change. Please use
+    SessionRestore.FrameUniqueNameFromRequestedNameSize and
+    SessionRestore.FrameUniqueNameWithFramePathSize instead.
+  </obsolete>
   <owner>dcheng@chromium.org</owner>
   <summary>
     Records the length of unique names for web frames that are saved as part of
@@ -71809,6 +71853,44 @@
   </summary>
 </histogram>
 
+<histogram name="SessionRestore.FrameUniqueNameOriginalRequestedNameSize"
+    units="characters">
+  <owner>dcheng@chromium.org</owner>
+  <summary>
+    The size of the browsing context name (based on the iframe name attribute or
+    window.name) when generating the unique name. Emitted when generating a
+    unique name for a new subframe or when a subframe's browsing context name is
+    changed before the first real load is committed. Only applies to subframes
+    as main frames always have an empty unique name.
+  </summary>
+</histogram>
+
+<histogram name="SessionRestore.FrameUniqueNameWithFramePathSize"
+    units="characters">
+  <owner>dcheng@chromium.org</owner>
+  <summary>
+    The size of a unique name when falling back to the frame path algorithm. The
+    fallback path is used when the browsing context name is empty or non-unique.
+    Emitted when generating a unique name for a new subframe or when a
+    subframe's browsing context name is changed before the first real load is
+    committed. Only applies to subframes as main frames always have an empty
+    unique name.
+  </summary>
+</histogram>
+
+<histogram name="SessionRestore.FrameUniqueNameWithFramePathSizePerComponent"
+    units="characters per depth">
+  <owner>dcheng@chromium.org</owner>
+  <summary>
+    The size of a unique name when falling back to the frame path algorithm,
+    divided by the depth of the frame. Used to normalize sizes for deeper nodes
+    in a frame tree. Emitted when generating a unique name for a new subframe or
+    when a subframe's browsing context name is changed before the first real
+    load is committed. Only applies to subframes as main frames always have an
+    empty unique name.
+  </summary>
+</histogram>
+
 <histogram name="SessionRestore.last_session_file_size" units="KB">
   <obsolete>
     Deprecated 2017-02 as not actionable.
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index 0c7924f..29ca10c 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -196,6 +196,8 @@
   def GetExpectations(self):
     class StoryExpectations(story_module.expectations.StoryExpectations):
       def SetExpectations(self):
+        self.PermanentlyDisableBenchmark(
+            [story_module.expectations.ALL_MOBILE], 'Desktop benchmark.')
         self.DisableStory('https://mail.google.com/mail/',
                           [story_module.expectations.ALL_WIN],
                           'crbug.com/750131')
@@ -686,7 +688,6 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('reference')  # crbug.com/549428
 @benchmark.Owner(emails=['skyostil@chromium.org', 'brianderson@chromium.org'])
 class SmoothnessToughSchedulingCases(_Smoothness):
   """Measures rendering statistics while interacting with pages that have
diff --git a/tools/perf/page_sets/system_health/expectations.py b/tools/perf/page_sets/system_health/expectations.py
index bb4b81b..5a3e172 100644
--- a/tools/perf/page_sets/system_health/expectations.py
+++ b/tools/perf/page_sets/system_health/expectations.py
@@ -130,8 +130,6 @@
     self.DisableStory('browse:news:hackernews',
                       [expectations.ALL_WIN, expectations.ALL_MAC],
                       'crbug.com/676336')
-    self.DisableStory('browse:search:google', [expectations.ALL_WIN],
-                      'crbug.com/673775')
     self.DisableStory('browse:tools:maps', [expectations.ALL],
                       'crbug.com/712694')
     self.DisableStory('browse:tools:earth', [expectations.ALL],
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 35dd5183..4437905 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -573,7 +573,24 @@
     text_match_active_suggestion = 20,
     spelling_text_match_active_suggestion = 21,
     grammar_text_match_active_suggestion = 22,
-    spelling_grammar_text_match_active_suggestion = 23
+    spelling_grammar_text_match_active_suggestion = 23,
+    suggestion = 32,
+    spelling_suggestion = 33,
+    grammar_suggestion = 34,
+    spelling_grammar_suggestion = 35,
+    text_match_suggestion = 36,
+    spelling_text_match_suggestion = 37,
+    grammar_text_match_suggestion = 38,
+    spelling_grammar_text_match_suggestion = 39,
+    // We again skip over DocumentMarker::MarkerType::Composition = 8 here
+    active_suggestion_suggestion = 48,
+    spelling_active_suggestion_suggestion = 49,
+    grammar_active_suggestion_suggestion = 50,
+    spelling_grammar_active_suggestion_suggestion = 51,
+    text_match_active_suggestion_suggestion = 52,
+    spelling_text_match_active_suggestion_suggestion = 53,
+    grammar_text_match_active_suggestion_suggestion = 54,
+    spelling_grammar_text_match_active_suggestion_suggestion = 55
   };
 
   enum AXTextDirection {
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index 63181ae..027cbd75 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -980,6 +980,8 @@
             types_str += "text_match&";
           if (type & AX_MARKER_TYPE_ACTIVE_SUGGESTION)
             types_str += "active_suggestion&";
+          if (type & AX_MARKER_TYPE_SUGGESTION)
+            types_str += "suggestion&";
 
           if (!types_str.empty())
             types_str = types_str.substr(0, types_str.size() - 1);
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index a35775d..c6c9f75 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -545,6 +545,7 @@
 int ContentsView::GetDisplayHeight() const {
   return display::Screen::GetScreen()
       ->GetDisplayNearestView(GetWidget()->GetNativeView())
+      .work_area()
       .size()
       .height();
 }
diff --git a/ui/base/material_design/material_design_controller.cc b/ui/base/material_design/material_design_controller.cc
index ee9a7d6e..530b6896 100644
--- a/ui/base/material_design/material_design_controller.cc
+++ b/ui/base/material_design/material_design_controller.cc
@@ -20,7 +20,7 @@
 
 #include "base/files/file_enumerator.h"
 #include "base/threading/thread_restrictions.h"
-#include "ui/events/ozone/evdev/event_device_info.h"
+#include "ui/events/ozone/evdev/event_device_info.h"  // nogncheck
 #endif  // defined(USE_OZONE)
 
 #endif  // defined(OS_CHROMEOS)
diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h
index fbe0fef..517bd40 100644
--- a/ui/gfx/native_widget_types.h
+++ b/ui/gfx/native_widget_types.h
@@ -133,12 +133,6 @@
 typedef ui::ViewAndroid* NativeView;
 typedef ui::WindowAndroid* NativeWindow;
 typedef jobject NativeEvent;
-#elif defined(OS_FUCHSIA)
-// TODO(fuchsia): Update when we have a plan for UI on Fuchsia.
-typedef void* NativeCursor;
-typedef void* NativeView;
-typedef void* NativeWindow;
-typedef void* NativeEvent;
 #else
 #error Unknown build environment.
 #endif
@@ -203,10 +197,6 @@
 #elif defined(USE_OZONE)
 typedef int32_t AcceleratedWidget;
 constexpr AcceleratedWidget kNullAcceleratedWidget = 0;
-#elif defined(OS_FUCHSIA)
-// TODO(fuchsia): Update when we have a plan for UI on Fuchsia.
-typedef void* AcceleratedWidget;
-constexpr AcceleratedWidget kNullAcceleratedWidget = 0;
 #else
 #error unknown platform
 #endif
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
index 041c9f2..89004b7 100644
--- a/ui/gfx/render_text.cc
+++ b/ui/gfx/render_text.cc
@@ -231,8 +231,16 @@
 void SkiaTextRenderer::DrawPosText(const SkPoint* pos,
                                    const uint16_t* glyphs,
                                    size_t glyph_count) {
-  const size_t byte_length = glyph_count * sizeof(glyphs[0]);
-  canvas_skia_->drawPosText(&glyphs[0], byte_length, &pos[0], flags_);
+  SkTextBlobBuilder builder;
+  const auto& run_buffer = builder.allocRunPos(flags_.ToSkPaint(), glyph_count);
+
+  static_assert(sizeof(*glyphs) == sizeof(*run_buffer.glyphs), "");
+  memcpy(run_buffer.glyphs, glyphs, glyph_count * sizeof(*glyphs));
+
+  static_assert(sizeof(*pos) == 2 * sizeof(*run_buffer.pos), "");
+  memcpy(run_buffer.pos, pos, glyph_count * sizeof(*pos));
+
+  canvas_skia_->drawTextBlob(builder.make(), 0, 0, flags_);
 }
 
 void SkiaTextRenderer::DrawUnderline(int x, int y, int width) {
diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h
index 24ea3d4..024c73e 100644
--- a/ui/gfx/render_text.h
+++ b/ui/gfx/render_text.h
@@ -64,6 +64,7 @@
   void SetForegroundColor(SkColor foreground);
   void SetShader(sk_sp<cc::PaintShader> shader);
   void DrawSelection(const std::vector<Rect>& selection, SkColor color);
+  // TODO(vmpstr): Change this API to mimic SkCanvas::drawTextBlob instead.
   virtual void DrawPosText(const SkPoint* pos,
                            const uint16_t* glyphs,
                            size_t glyph_count);
diff --git a/ui/ozone/common/gl_ozone_osmesa.cc b/ui/ozone/common/gl_ozone_osmesa.cc
index 2ee4dbb..e7ccc73 100644
--- a/ui/ozone/common/gl_ozone_osmesa.cc
+++ b/ui/ozone/common/gl_ozone_osmesa.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/common/gl_ozone_osmesa.h"
 
+#include "build/build_config.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_context_osmesa.h"
@@ -27,7 +28,14 @@
 
 bool GLOzoneOSMesa::InitializeStaticGLBindings(
     gl::GLImplementation implementation) {
+#if defined(OS_FUCHSIA)
+  // TODO(fuchsia): Enable this once there's EGL available, see
+  // https://crbug.com/750943.
+  NOTIMPLEMENTED();
+  return false;
+#else
   return gl::InitializeStaticGLBindingsOSMesaGL();
+#endif
 }
 
 void GLOzoneOSMesa::InitializeDebugGLBindings() {
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index e1658e0..b481f4ae 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -72,6 +72,21 @@
 
 }  // namespace
 
+// A container that changes visibility with its contents.
+class FootnoteContainerView : public View {
+ public:
+  FootnoteContainerView() {}
+
+  // View:
+  void ChildVisibilityChanged(View* child) override {
+    DCHECK_EQ(child_count(), 1);
+    SetVisible(child->visible());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FootnoteContainerView);
+};
+
 // static
 const char BubbleFrameView::kViewClassName[] = "BubbleFrameView";
 
@@ -145,7 +160,9 @@
 gfx::Rect BubbleFrameView::GetBoundsForClientView() const {
   gfx::Rect client_bounds = GetContentsBounds();
   client_bounds.Inset(GetInsets());
-  if (footnote_container_) {
+  // Only account for footnote_container_'s height if it's visible, because
+  // content_margins_ adds extra padding even if all child views are invisible.
+  if (footnote_container_ && footnote_container_->visible()) {
     client_bounds.set_height(client_bounds.height() -
                              footnote_container_->height());
   }
@@ -364,7 +381,9 @@
   title_icon_->SetBounds(bounds.x(), bounds.y(), title_icon_pref_size.width(),
                          title_height);
 
-  if (footnote_container_) {
+  // Only account for footnote_container_'s height if it's visible, because
+  // content_margins_ adds extra padding even if all child views are invisible.
+  if (footnote_container_ && footnote_container_->visible()) {
     const int width = contents_bounds.width();
     const int height = footnote_container_->GetHeightForWidth(width);
     footnote_container_->SetBounds(
@@ -435,7 +454,7 @@
     return;
 
   DCHECK(!footnote_container_);
-  footnote_container_ = new views::View();
+  footnote_container_ = new FootnoteContainerView();
   footnote_container_->SetLayoutManager(
       new BoxLayout(BoxLayout::kVertical, content_margins_, 0));
   footnote_container_->SetBackground(
@@ -443,6 +462,7 @@
   footnote_container_->SetBorder(
       CreateSolidSidedBorder(1, 0, 0, 0, kFootnoteBorderColor));
   footnote_container_->AddChildView(view);
+  footnote_container_->SetVisible(view->visible());
   AddChildView(footnote_container_);
 }
 
@@ -568,7 +588,9 @@
   size.Enlarge(client_insets.width(), client_insets.height());
   size.SetToMax(gfx::Size(title_bar_width, 0));
 
-  if (footnote_container_)
+  // Only account for footnote_container_'s height if it's visible, because
+  // content_margins_ adds extra padding even if all child views are invisible.
+  if (footnote_container_ && footnote_container_->visible())
     size.Enlarge(0, footnote_container_->GetHeightForWidth(size.width()));
 
   DialogDelegate* dialog_delegate =
diff --git a/ui/views/bubble/bubble_frame_view_unittest.cc b/ui/views/bubble/bubble_frame_view_unittest.cc
index dda52ed..61066f0 100644
--- a/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -168,6 +168,20 @@
             frame.GetBoundsForClientView().y());
 }
 
+TEST_F(BubbleFrameViewTest,
+       FootnoteContainerViewShouldMatchVisibilityOfFirstChild) {
+  TestBubbleFrameView frame(this);
+  View* footnote_dummy_view = new StaticSizedView(gfx::Size(200, 200));
+  footnote_dummy_view->SetVisible(false);
+  frame.SetFootnoteView(footnote_dummy_view);
+  View* footnote_container_view = footnote_dummy_view->parent();
+  EXPECT_FALSE(footnote_container_view->visible());
+  footnote_dummy_view->SetVisible(true);
+  EXPECT_TRUE(footnote_container_view->visible());
+  footnote_dummy_view->SetVisible(false);
+  EXPECT_FALSE(footnote_container_view->visible());
+}
+
 // Tests that the arrow is mirrored as needed to better fit the screen.
 TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) {
   TestBubbleFrameView frame(this);
@@ -465,6 +479,7 @@
 }
 
 TEST_F(BubbleFrameViewTest, GetPreferredSize) {
+  // Test border/insets.
   TestBubbleFrameView frame(this);
   gfx::Rect preferred_rect(frame.GetPreferredSize());
   // Expect that a border has been added to the preferred size.
@@ -475,6 +490,29 @@
   EXPECT_EQ(expected_size, preferred_rect.size());
 }
 
+TEST_F(BubbleFrameViewTest, GetPreferredSizeWithFootnote) {
+  // Test footnote view: adding a footnote should increase the preferred size,
+  // but only when the footnote is visible.
+  TestBubbleFrameView frame(this);
+
+  constexpr int kFootnoteHeight = 20;
+  const gfx::Size no_footnote_size = frame.GetPreferredSize();
+  View* footnote = new StaticSizedView(gfx::Size(10, kFootnoteHeight));
+  footnote->SetVisible(false);
+  frame.SetFootnoteView(footnote);
+  EXPECT_EQ(no_footnote_size, frame.GetPreferredSize());  // No change.
+
+  footnote->SetVisible(true);
+  gfx::Size with_footnote_size = no_footnote_size;
+  constexpr int kFootnoteTopBorderThickness = 1;
+  with_footnote_size.Enlarge(0, kFootnoteHeight + kFootnoteTopBorderThickness +
+                                    frame.content_margins().height());
+  EXPECT_EQ(with_footnote_size, frame.GetPreferredSize());
+
+  footnote->SetVisible(false);
+  EXPECT_EQ(no_footnote_size, frame.GetPreferredSize());
+}
+
 TEST_F(BubbleFrameViewTest, GetMinimumSize) {
   TestBubbleFrameView frame(this);
   gfx::Rect minimum_rect(frame.GetMinimumSize());