diff --git a/DEPS b/DEPS
index 1d016ee..1f02de98 100644
--- a/DEPS
+++ b/DEPS
@@ -121,11 +121,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'f6e963ef91c28b94bae45db7d2d30d6a0a307972',
+  'skia_revision': 'acc763e8795c694d0fb7c74a412b1805446754ff',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'cdef3415a2805f926e6da2d5da25da678867c821',
+  'v8_revision': '90efb11e6eb215ccee50b035bd095e747dc57416',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -229,7 +229,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '167f1270a9ee641b17c016a545741e4aadfabe86',
+  'spv_tools_revision': '980ae1d1cd6e9b4fb209ad5097b3ad06eb7877a3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -245,7 +245,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'cb71ba7b3a42849b5e15794426cb9fe55cba8b13',
+  'dawn_revision': '92700bfccd1806971ab47773ebe95576a128a998',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1199,7 +1199,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a2b35635aaef3e9301d69f77f9a0a3fd99291b08',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '7e0978c5e803809e273d6f8b48607917f63ccf05',
+    Var('webrtc_git') + '/src.git' + '@' + '9fe758e78833aa46691b8102bd03b81f77d8660f',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1230,7 +1230,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7234e488b92ea378bb2a86f25da39cb7b5941ec0',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@03fe76f2cf15376da09677808a7801f7ce821015',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/base/containers/adapters.h b/base/containers/adapters.h
index fa671b4..ec33481 100644
--- a/base/containers/adapters.h
+++ b/base/containers/adapters.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <iterator>
+#include <utility>
 
 #include "base/macros.h"
 
@@ -19,15 +20,13 @@
 template <typename T>
 class ReversedAdapter {
  public:
-  using Iterator = decltype(static_cast<T*>(nullptr)->rbegin());
+  using Iterator = decltype(std::rbegin(std::declval<T&>()));
 
   explicit ReversedAdapter(T& t) : t_(t) {}
   ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
 
-  // TODO(mdempsky): Once we can use C++14 library features, use std::rbegin
-  // and std::rend instead, so we can remove the specialization below.
-  Iterator begin() const { return t_.rbegin(); }
-  Iterator end() const { return t_.rend(); }
+  Iterator begin() const { return std::rbegin(t_); }
+  Iterator end() const { return std::rend(t_); }
 
  private:
   T& t_;
@@ -35,23 +34,6 @@
   DISALLOW_ASSIGN(ReversedAdapter);
 };
 
-template <typename T, size_t N>
-class ReversedAdapter<T[N]> {
- public:
-  using Iterator = std::reverse_iterator<T*>;
-
-  explicit ReversedAdapter(T (&t)[N]) : t_(t) {}
-  ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
-
-  Iterator begin() const { return Iterator(&t_[N]); }
-  Iterator end() const { return Iterator(&t_[0]); }
-
- private:
-  T (&t_)[N];
-
-  DISALLOW_ASSIGN(ReversedAdapter);
-};
-
 }  // namespace internal
 
 // Reversed returns a container adapter usable in a range-based "for" statement
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index 799da896..cdb171359b 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -143,7 +143,8 @@
   DCHECK(owning_sequence_checker_.CalledOnValidSequence());
   if (!message_loop_)
     return false;
-  base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
+  // https://crbug.com/918039
+  base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
   start_event_.Wait();
   return true;
 }
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index ee49023..34485b7 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -235,6 +235,7 @@
 }
 
 namespace web {
+class WebMainLoop;
 class WebSubThread;
 }
 
@@ -421,7 +422,6 @@
   friend class base::MessageLoopImpl;
   friend class base::ScopedAllowThreadRecallForStackSamplingProfiler;
   friend class base::StackSamplingProfiler;
-  friend class base::Thread;
   friend class content::DesktopCaptureDevice;
   friend class content::SandboxHostLinux;
   friend class content::ScopedAllowWaitForDebugURL;
@@ -437,6 +437,7 @@
 
   // Usage that should be fixed:
   friend class ::chromeos::BlockingMethodCaller;  // http://crbug.com/125360
+  friend class base::Thread;                      // http://crbug.com/918039
   friend class cc::CompletionEvent;              // http://crbug.com/902653
   friend class cc::SingleThreadTaskGraphRunner;  // http://crbug.com/902823
   friend class content::
@@ -573,6 +574,7 @@
   friend class content::CategorizedWorkerPool;
   friend class remoting::AutoThread;
   friend class ui::WindowResizeHelperMac;
+  friend class web::WebMainLoop;
   friend class MessagePumpDefault;
   friend class SimpleThread;
   friend class Thread;
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index cf06dde..826e194 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-547d327493970d0cdd0f4f289c4b7222f34a24b6
\ No newline at end of file
+4d54ec8046e1222e119eca44d87bd8414ce43e5b
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index eec2fd6..7fdbdb6 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-c49194362b1e6bd2684f7da62bf3d072d6702a91
\ No newline at end of file
+3f82cdd0060d732bdb12f35d65db0497f6b10d37
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 7cbf70e..7304335 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -2507,6 +2507,9 @@
     public void startActivity(Intent intent, Bundle options) {
         if (VrModuleProvider.getDelegate().canLaunch2DIntents()
                 || VrModuleProvider.getIntentDelegate().isVrIntent(intent)) {
+            if (VrModuleProvider.getDelegate().isInVr()) {
+                VrModuleProvider.getIntentDelegate().setupVrIntent(intent);
+            }
             super.startActivity(intent, options);
             return;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusView.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusView.java
index 0fd3bbf..93e1b36 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusView.java
@@ -26,6 +26,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.util.AccessibilityUtil;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -75,6 +76,8 @@
     private StatusViewAnimator mLocationBarNavigationIconShowAnimator;
     private StatusViewAnimator mLocationBarClearAnimator;
 
+    private @StringRes int mSecurityIconAccessibilityDescription;
+
     /**
      * Class animating transition between FrameLayout children.
      * Can take any number of child components; ensures that the
@@ -163,6 +166,7 @@
         assert mNavigationButton != null : "Missing navigation type view.";
 
         configureLocationBarIconAnimations();
+        configureAccessibilityDescriptions();
     }
 
     /**
@@ -194,6 +198,20 @@
     }
 
     /**
+     * Configure accessibility toasts.
+     */
+    void configureAccessibilityDescriptions() {
+        mSecurityButton.setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View view) {
+                Context context = getContext();
+                return AccessibilityUtil.showAccessibilityToast(
+                        context, view, context.getResources().getString(R.string.menu_page_info));
+            }
+        });
+    }
+
+    /**
      * Toggle use of animations.
      */
     void setAnimationsEnabled(boolean enabled) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 29ecef8..6b9247f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -55,6 +55,7 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsStatics;
 import org.chromium.mojo.system.MojoException;
+import org.chromium.payments.mojom.CanMakePaymentQueryResult;
 import org.chromium.payments.mojom.HasEnrolledInstrumentQueryResult;
 import org.chromium.payments.mojom.PaymentComplete;
 import org.chromium.payments.mojom.PaymentCurrencyAmount;
@@ -219,6 +220,7 @@
     private final boolean mIsIncognito;
 
     private PaymentRequestClient mClient;
+    private boolean mIsCanMakePaymentResponsePending;
     private boolean mIsHasEnrolledInstrumentResponsePending;
     private boolean mIsCurrentPaymentRequestShowing;
 
@@ -684,6 +686,10 @@
             }
         }
 
+        if (mIsCanMakePaymentResponsePending) {
+            respondCanMakePaymentQuery(mArePaymentMethodsSupported);
+        }
+
         if (mIsHasEnrolledInstrumentResponsePending && queryApps.isEmpty()) {
             respondHasEnrolledInstrumentQuery(mHasEnrolledInstrument);
         }
@@ -1519,8 +1525,28 @@
      */
     @Override
     public void canMakePayment() {
-        // TODO(https://crbug.com/915907): Implement new canMakePayment.
-        assert false;
+        if (mClient == null) return;
+
+        if (isFinishedQueryingPaymentApps()) {
+            respondCanMakePaymentQuery(mArePaymentMethodsSupported);
+        } else {
+            mIsCanMakePaymentResponsePending = true;
+        }
+    }
+
+    private void respondCanMakePaymentQuery(boolean response) {
+        if (mClient == null) return;
+
+        mIsCanMakePaymentResponsePending = false;
+        mClient.onCanMakePayment(response ? CanMakePaymentQueryResult.CAN_MAKE_PAYMENT
+                                          : CanMakePaymentQueryResult.CANNOT_MAKE_PAYMENT);
+
+        // TODO(https://crbug.com/915907): emit JourneyLogger event once the event names are
+        // updated.
+
+        if (sObserverForTest != null) {
+            sObserverForTest.onPaymentRequestServiceCanMakePaymentQueryResponded();
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
index 464b614..9e0b765 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -57,7 +57,6 @@
     private ImageButton mReloadButton;
     private ImageButton mBookmarkButton;
     private ImageButton mSaveOfflineButton;
-    private ImageButton mSecurityButton;
     private ToggleTabStackButton mAccessibilitySwitcherButton;
 
     private OnClickListener mBookmarkListener;
@@ -109,7 +108,6 @@
         DrawableCompat.setTintList(reloadIcon,
                 AppCompatResources.getColorStateList(getContext(), R.color.dark_mode_tint));
         mReloadButton.setImageDrawable(reloadIcon);
-        mSecurityButton = findViewById(R.id.security_button);
         mShowTabStack = AccessibilityUtil.isAccessibilityEnabled()
                 && isAccessibilityTabSwitcherPreferenceEnabled();
 
@@ -258,8 +256,6 @@
 
         mSaveOfflineButton.setOnClickListener(this);
         mSaveOfflineButton.setOnLongClickListener(this);
-
-        mSecurityButton.setOnLongClickListener(this);
     }
 
     @Override
@@ -333,8 +329,6 @@
             description = resources.getString(R.string.menu_bookmark);
         } else if (v == mSaveOfflineButton) {
             description = resources.getString(R.string.menu_download);
-        } else if (v == mSecurityButton) {
-            description = resources.getString(R.string.menu_page_info);
         }
         return AccessibilityUtil.showAccessibilityToast(context, v, description);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index a31819e3..e082777c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -1441,27 +1441,15 @@
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
     @RetryOnFailure
     public void testNewTabButton() throws InterruptedException {
-        MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
-                mActivityTestRule.getActivity(), R.id.close_all_tabs_menu_id);
-        UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
-
-        CriteriaHelper.pollInstrumentationThread(new Criteria("Should be in overview mode") {
-            @Override
-            public boolean isSatisfied() {
-                return mActivityTestRule.getActivity().isInOverviewMode();
-            }
-        });
-
         int initialTabCount = mActivityTestRule.getActivity().getCurrentTabModel().getCount();
-        Assert.assertEquals(
-                "Tab count is expected to be 0 after closing all the tabs", 0, initialTabCount);
+        showOverviewAndWaitForAnimation();
 
         ChromeTabUtils.clickNewTabButton(
                 InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity());
 
         int newTabCount = mActivityTestRule.getActivity().getCurrentTabModel().getCount();
-        Assert.assertEquals(
-                "Tab count is expected to be 1 after clicking Newtab button", 1, newTabCount);
+        Assert.assertEquals("Tab count is expected to increment by 1 after clicking new tab button",
+                initialTabCount + 1, newTabCount);
         UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
         CriteriaHelper.pollInstrumentationThread(new Criteria("Should not be in overview mode") {
             @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java
index 9b71857..a1027d0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java
@@ -336,8 +336,11 @@
 
         CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(0));
         CriteriaHelper.pollInstrumentationThread(new TabModelCountCountCriteria(false, 0));
-        Assert.assertFalse(
-                mActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button).isEnabled());
+        Assert.assertFalse(mActivityTestRule.getActivity()
+                                   .findViewById(R.id.tab_switcher_mode_tab_switcher_button)
+                                   .isEnabled());
+        Assert.assertTrue(
+                mActivityTestRule.getActivity().findViewById(R.id.new_tab_button).isEnabled());
     }
 
     @Test
@@ -357,16 +360,20 @@
         CriteriaHelper.pollInstrumentationThread(new TabModelCountCountCriteria(true, 0));
 
         CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(4));
-        Assert.assertTrue(
-                mActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button).isEnabled());
+        Assert.assertTrue(mActivityTestRule.getActivity()
+                                  .findViewById(R.id.tab_switcher_mode_tab_switcher_button)
+                                  .isEnabled());
 
         MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
                 mActivityTestRule.getActivity(), R.id.close_all_tabs_menu_id);
 
         CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(0));
         CriteriaHelper.pollInstrumentationThread(new TabModelCountCountCriteria(false, 0));
-        Assert.assertFalse(
-                mActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button).isEnabled());
+        Assert.assertFalse(mActivityTestRule.getActivity()
+                                   .findViewById(R.id.tab_switcher_mode_tab_switcher_button)
+                                   .isEnabled());
+        Assert.assertTrue(
+                mActivityTestRule.getActivity().findViewById(R.id.new_tab_button).isEnabled());
     }
 
     @Test
diff --git a/chrome/app/app_management_strings.grdp b/chrome/app/app_management_strings.grdp
index 699a20e6..27fa67c 100644
--- a/chrome/app/app_management_strings.grdp
+++ b/chrome/app/app_management_strings.grdp
@@ -16,6 +16,9 @@
   <message name="IDS_APP_MANAGEMENT_NOTIFICATIONS" desc="Label for notifications section in app settings page.">
     Notifications
   </message>
+  <message name="IDS_APP_MANAGEMENT_NOTIFICATIONS_SUBLABEL" desc="Sublabel for the Notifications item in the main App Management view">
+    <ph name="NUMBER_OF_MORE_APPS">$1<ex>4</ex></ph> apps
+  </message>
   <message name="IDS_APP_MANAGEMENT_PERMISSIONS" desc="Label for permissions section in app settings page.">
     Permissions
   </message>
diff --git a/chrome/app/md_extensions_strings.grdp b/chrome/app/md_extensions_strings.grdp
index d0ca9a5c..beb02430 100644
--- a/chrome/app/md_extensions_strings.grdp
+++ b/chrome/app/md_extensions_strings.grdp
@@ -7,6 +7,9 @@
   <message name="IDS_EXTENSIONS_ALLOW_ON_ALL_URLS" desc="The checkbox for allowing an extension to run scripts on all websites without explicit permission.">
     Allow on all websites
   </message>
+  <message name="IDS_EXTENSIONS_ALLOW_ON_FOLLOWING_SITES" desc="The label for the option to allow the extension to automatically access all sites listed below.">
+    Automatically allow access on the following sites
+  </message>
   <message name="IDS_EXTENSIONS_VIEW_ACTIVITY_LOG" desc="The label of the button to click to view recent extension activity.">
     View activity log
   </message>
@@ -90,6 +93,9 @@
       =1 {&lt;1 line not shown&gt;}
       other {&lt;<ph name="NUMBER_OF_LINES">$1<ex>4</ex></ph> lines not shown&gt;}}
   </message>
+  <message name="IDS_MD_EXTENSIONS_HOST_PERMISSIONS_DESCRIPTION" desc="The explanatory text for adjusting which websites an extension is allowed to run on.">
+    This extension can read and change your data on sites. You can control which sites the extension can access.
+  </message>
   <!-- TODO(devlin): Unify this with IDS_SETTINGS_EDIT. -->
   <message name="IDS_MD_EXTENSIONS_HOST_PERMISSIONS_EDIT" desc="The label of the button used to edit an extension's access to a given website.">
     Edit
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 8d78a2d..efb03695 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1577,10 +1577,6 @@
      flag_descriptions::kUseMessagesGoogleComDomainName,
      flag_descriptions::kUseMessagesGoogleComDomainDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kUseMessagesGoogleComDomain)},
-    {"enable_android_messages_prod_endpoint",
-     flag_descriptions::kAndroidMessagesProdEndpointName,
-     flag_descriptions::kAndroidMessagesProdEndpointDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(chromeos::features::kAndroidMessagesProdEndpoint)},
     {
         "enable-background-blur",
         flag_descriptions::kEnableBackgroundBlurName,
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 206c10ae..350cb0e 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -707,6 +707,7 @@
       </if>
       <if expr="chromeos">
         <include name="IDR_SMART_DIM_EXAMPLE_PREPROCESSOR_CONFIG_PB" file="chromeos\power\ml\smart_dim\example_preprocessor_config.pb" type="BINDATA" />
+        <include name="IDR_SMART_DIM_LITE_EXAMPLE_PREPROCESSOR_CONFIG_PB" file="chromeos\power\ml\smart_dim\lite_example_preprocessor_config.pb" type="BINDATA" />
       </if>
     </includes>
   </release>
diff --git a/chrome/browser/chromeos/android_sms/android_sms_urls.cc b/chrome/browser/chromeos/android_sms/android_sms_urls.cc
index 981d1eb4..2fcc7ab 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_urls.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_urls.cc
@@ -18,38 +18,31 @@
 
 namespace {
 
-// NOTE: Using internal staging server until changes roll out to prod.
-const char kAndroidMessagesSandboxUrl[] =
-    "https://android-messages.sandbox.google.com/";
+const char kAndroidMessagesUrl[] = "https://messages.android.com/";
+const char kGoogleMessagesUrl[] = "https://messages.google.com/";
 
-const char kAndroidMessagesProdUrl[] = "https://messages.android.com/";
+GURL GetAndroidMessagesURL(bool use_google_url_if_applicable) {
+  // If a custom URL was passed via a command line argument, use it.
+  std::string url_from_command_line_arg =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kAlternateAndroidMessagesUrl);
+  if (!url_from_command_line_arg.empty())
+    return GURL(url_from_command_line_arg);
 
-const char kUrlParams[] = "?DefaultToPersistent=true";
-
-GURL GetURLInternal(bool with_params) {
-  const base::CommandLine* command_line =
-      base::CommandLine::ForCurrentProcess();
-  std::string url_string =
-      command_line->GetSwitchValueASCII(switches::kAlternateAndroidMessagesUrl);
-
-  bool use_prod_url = base::FeatureList::IsEnabled(
-      chromeos::features::kAndroidMessagesProdEndpoint);
-  if (url_string.empty())
-    url_string = std::string(use_prod_url ? kAndroidMessagesProdUrl
-                                          : kAndroidMessagesSandboxUrl);
-  if (with_params)
-    url_string += kUrlParams;
-  return GURL(url_string);
+  return use_google_url_if_applicable ? GURL(kGoogleMessagesUrl)
+                                      : GURL(kAndroidMessagesUrl);
 }
 
 }  // namespace
 
 GURL GetAndroidMessagesURL() {
-  return GetURLInternal(false /* with_params */);
+  return GetAndroidMessagesURL(
+      base::FeatureList::IsEnabled(features::kUseMessagesGoogleComDomain));
 }
 
-GURL GetAndroidMessagesURLWithParams() {
-  return GetURLInternal(true /* with_params */);
+GURL GetAndroidMessagesURLOld() {
+  return GetAndroidMessagesURL(
+      !base::FeatureList::IsEnabled(features::kUseMessagesGoogleComDomain));
 }
 
 }  // namespace android_sms
diff --git a/chrome/browser/chromeos/android_sms/android_sms_urls.h b/chrome/browser/chromeos/android_sms/android_sms_urls.h
index 6a9ed7f..b1292fe6 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_urls.h
+++ b/chrome/browser/chromeos/android_sms/android_sms_urls.h
@@ -14,12 +14,12 @@
 // Returns URL to Android Messages for Web page used by AndroidSmsService.
 GURL GetAndroidMessagesURL();
 
-// Returns URL to Android Messages for Web page used by AndroidSmsService.
-// This includes a URL param indicating that it should default to persist the
-// connection. If still using the sandbox URL, this will also include the
-// experiment URL params for the ChromeOS integrations.  This is temporary for
-// dogfood until these flags are rolled out to prod.
-GURL GetAndroidMessagesURLWithParams();
+// Returns the old URL used for Android Messages. In this context, the "old" URL
+// refers to the URL used before the last change to the
+// kUseMessagesGoogleComDomain flag. See go/awm-cros-domain for details.
+// TODO(https://crbug.com/917855): Remove this function when migration is
+// complete.
+GURL GetAndroidMessagesURLOld();
 
 }  // namespace android_sms
 
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index bf62cfa..560e4a1 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -1119,7 +1119,7 @@
   DisableAttributePromptUpdate();
   LoadConfiguration();
   OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
-  base::RunLoop().RunUntilIdle();
+  ExecutePendingJavaScript();
   EXPECT_TRUE(IsStepDisplayed("success"));
 }
 
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc
index dea3107..2284baff 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc
+++ b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc
@@ -26,6 +26,7 @@
 #include "ui/base/window_open_disposition.h"
 
 namespace {
+
 const char kDefaultToPersistCookieName[] = "default_to_persist";
 const char kDefaultToPersistCookieValue[] = "true";
 
@@ -36,12 +37,33 @@
   return partition->GetCookieManagerForBrowserProcess();
 }
 
+void OnAppUninstallResult(const GURL& app_url, bool succeeded) {
+  if (succeeded)
+    return;
+
+  PA_LOG(ERROR) << "Failed to uninstall messages app; URL: " << app_url;
+  // TODO(khorimoto): Add metrics for failed uninstallations.
+}
+
 }  // namespace
 
 namespace chromeos {
 
 namespace multidevice_setup {
 
+AndroidSmsAppHelperDelegateImpl::PwaFetcherDelegate::PwaFetcherDelegate() =
+    default;
+
+AndroidSmsAppHelperDelegateImpl::PwaFetcherDelegate::~PwaFetcherDelegate() =
+    default;
+
+const extensions::Extension*
+AndroidSmsAppHelperDelegateImpl::PwaFetcherDelegate::GetPwaForUrl(
+    Profile* profile,
+    GURL gurl) {
+  return extensions::util::GetInstalledPwaForUrl(profile, gurl);
+}
+
 AndroidSmsAppHelperDelegateImpl::AndroidSmsAppHelperDelegateImpl(
     Profile* profile)
     : pending_app_manager_(
@@ -50,6 +72,7 @@
       host_content_settings_map_(
           HostContentSettingsMapFactory::GetForProfile(profile)),
       cookie_manager_(GetCookieManager(profile)),
+      pwa_fetcher_delegate_(std::make_unique<PwaFetcherDelegate>()),
       weak_ptr_factory_(this) {}
 
 AndroidSmsAppHelperDelegateImpl::AndroidSmsAppHelperDelegateImpl(
@@ -65,6 +88,28 @@
 
 void AndroidSmsAppHelperDelegateImpl::SetUpAndroidSmsApp(
     bool launch_on_install) {
+  // Before setting up the new app, check to see whether an app exists for the
+  // old URL (i.e., the URL used before the kUseMessagesGoogleComDomain flag
+  // was flipped).
+  const GURL old_messages_url =
+      chromeos::android_sms::GetAndroidMessagesURLOld();
+  const extensions::Extension* old_android_sms_pwa =
+      pwa_fetcher_delegate_->GetPwaForUrl(profile_, old_messages_url);
+  if (old_android_sms_pwa) {
+    PA_LOG(INFO) << "Messages PWA exists for old URL (" << old_messages_url
+                 << "); uninstalling before continuing.";
+    pending_app_manager_->UninstallApps(
+        std::vector<GURL>{old_messages_url},
+        base::BindRepeating(&OnAppUninstallResult));
+    TearDownAndroidSmsAppAtUrl(old_messages_url);
+  }
+
+  // Now that the old app has been uninstalled, continue.
+  SetUpAndroidSmsAppWithNoOldApp(launch_on_install);
+}
+
+void AndroidSmsAppHelperDelegateImpl::SetUpAndroidSmsAppWithNoOldApp(
+    bool launch_on_install) {
   PA_LOG(INFO) << "Setting DefaultToPersist Cookie";
   cookie_manager_->SetCanonicalCookie(
       *net::CanonicalCookie::CreateSanitizedCookie(
@@ -91,7 +136,7 @@
   // TODO(crbug.com/874605): Consider retries and error handling here. This call
   // can easily fail.
   web_app::PendingAppManager::AppInfo info(
-      chromeos::android_sms::GetAndroidMessagesURLWithParams(),
+      chromeos::android_sms::GetAndroidMessagesURL(),
       web_app::LaunchContainer::kWindow, web_app::InstallSource::kInternal);
   info.override_previous_user_uninstall = true;
   // The service worker does not load in time for the installability
@@ -110,8 +155,8 @@
 
 void AndroidSmsAppHelperDelegateImpl::SetUpAndLaunchAndroidSmsApp() {
   const extensions::Extension* android_sms_pwa =
-      extensions::util::GetInstalledPwaForUrl(
-          profile_, chromeos::android_sms::GetAndroidMessagesURL());
+      pwa_fetcher_delegate_->GetPwaForUrl(profile_,
+                                          android_sms::GetAndroidMessagesURL());
   if (!android_sms_pwa) {
     PA_LOG(VERBOSE) << "No Messages app found. Installing it.";
     SetUpAndroidSmsApp(true /* launch_on_install */);
@@ -123,8 +168,8 @@
 
 void AndroidSmsAppHelperDelegateImpl::LaunchAndroidSmsApp() {
   const extensions::Extension* android_sms_pwa =
-      extensions::util::GetInstalledPwaForUrl(
-          profile_, chromeos::android_sms::GetAndroidMessagesURL());
+      pwa_fetcher_delegate_->GetPwaForUrl(profile_,
+                                          android_sms::GetAndroidMessagesURL());
   DCHECK(android_sms_pwa);
 
   PA_LOG(VERBOSE) << "Messages app Launching...";
@@ -160,14 +205,23 @@
 }
 
 void AndroidSmsAppHelperDelegateImpl::TearDownAndroidSmsApp() {
+  TearDownAndroidSmsAppAtUrl(chromeos::android_sms::GetAndroidMessagesURL());
+}
+
+void AndroidSmsAppHelperDelegateImpl::TearDownAndroidSmsAppAtUrl(GURL pwa_url) {
   PA_LOG(INFO) << "Clearing DefaultToPersist Cookie";
   network::mojom::CookieDeletionFilterPtr filter(
       network::mojom::CookieDeletionFilter::New());
-  filter->url = chromeos::android_sms::GetAndroidMessagesURL();
+  filter->url = pwa_url;
   filter->cookie_name = kDefaultToPersistCookieName;
   cookie_manager_->DeleteCookies(std::move(filter), base::DoNothing());
 }
 
+void AndroidSmsAppHelperDelegateImpl::SetPwaFetcherDelegateForTesting(
+    std::unique_ptr<PwaFetcherDelegate> test_pwa_fetcher_delegate) {
+  pwa_fetcher_delegate_ = std::move(test_pwa_fetcher_delegate);
+}
+
 }  // namespace multidevice_setup
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h
index 804ee1c..5868ea4 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h
+++ b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chromeos/services/multidevice_setup/public/cpp/android_sms_app_helper_delegate.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "extensions/common/extension.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "url/gurl.h"
 
@@ -22,6 +23,7 @@
 }  // namespace web_app
 
 namespace chromeos {
+
 namespace multidevice_setup {
 
 class AndroidSmsAppHelperDelegateImpl : public AndroidSmsAppHelperDelegate {
@@ -32,6 +34,18 @@
  private:
   friend class AndroidSmsAppHelperDelegateImplTest;
 
+  // Fetches the Extension* associated with the PWA for |gurl|. This class is
+  // a thin wrapper around extensions::util::GetInstalledPwaForUrl() which is
+  // stubbed out for tests.
+  class PwaFetcherDelegate {
+   public:
+    PwaFetcherDelegate();
+    virtual ~PwaFetcherDelegate();
+
+    virtual const extensions::Extension* GetPwaForUrl(Profile* profile,
+                                                      GURL gurl);
+  };
+
   // Note: This constructor should only be used in testing. Right now, objects
   // built using this constructor will segfault on profile_ if
   // LaunchAndroidSmsApp is called. We'll need to fix this once tests for that
@@ -40,30 +54,38 @@
       web_app::PendingAppManager* pending_app_manager,
       HostContentSettingsMap* host_content_settings_map,
       network::mojom::CookieManager* cookie_manager);
-  void OnAppInstalled(bool launch_on_install,
-                      const GURL& app_url,
-                      web_app::InstallResultCode code);
-  void SetUpAndroidSmsApp(bool launch_on_install);
-  void LaunchAndroidSmsApp();
-  void OnSetDefaultToPersistCookieForInstall(bool launch_on_install,
-                                             bool set_cookie_success);
 
   // AndroidSmsAppHelperDelegate:
   void SetUpAndroidSmsApp() override;
   void SetUpAndLaunchAndroidSmsApp() override;
   void TearDownAndroidSmsApp() override;
 
+  void OnAppInstalled(bool launch_on_install,
+                      const GURL& app_url,
+                      web_app::InstallResultCode code);
+  void SetUpAndroidSmsApp(bool launch_on_install);
+  void SetUpAndroidSmsAppWithNoOldApp(bool launch_on_install);
+  void LaunchAndroidSmsApp();
+  void OnSetDefaultToPersistCookieForInstall(bool launch_on_install,
+                                             bool set_cookie_success);
+  void TearDownAndroidSmsAppAtUrl(GURL pwa_url);
+
+  void SetPwaFetcherDelegateForTesting(
+      std::unique_ptr<PwaFetcherDelegate> test_pwa_fetcher_delegate);
+
   static const char kMessagesWebAppUrl[];
   web_app::PendingAppManager* pending_app_manager_;
   Profile* profile_;
   HostContentSettingsMap* host_content_settings_map_;
   network::mojom::CookieManager* cookie_manager_;
+  std::unique_ptr<PwaFetcherDelegate> pwa_fetcher_delegate_;
   base::WeakPtrFactory<AndroidSmsAppHelperDelegateImpl> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AndroidSmsAppHelperDelegateImpl);
 };
 
 }  // namespace multidevice_setup
+
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_ANDROID_SMS_APP_HELPER_DELEGATE_IMPL_H_
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc
index 09b2289..7189b642 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc
+++ b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc
@@ -8,8 +8,12 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/containers/flat_map.h"
+#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/path_service.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -18,6 +22,8 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/extension_paths.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -82,6 +88,45 @@
 
 class AndroidSmsAppHelperDelegateImplTest : public testing::Test {
  protected:
+  class TestPwaFetcherDelegate
+      : public AndroidSmsAppHelperDelegateImpl::PwaFetcherDelegate {
+   public:
+    TestPwaFetcherDelegate() = default;
+    ~TestPwaFetcherDelegate() override = default;
+
+    void SetHasPwa(GURL gurl, bool has_pwa) {
+      // If no PWA should exist, erase any existing entry and return.
+      if (!has_pwa) {
+        gurl_to_pwa_map_.erase(gurl);
+        return;
+      }
+
+      // If a PWA already exists for this URL, there is nothing to do.
+      if (base::ContainsKey(gurl_to_pwa_map_, gurl))
+        return;
+
+      // Create a test Extension and add it to |gurl_to_pwa_map_|.
+      base::FilePath path;
+      base::PathService::Get(extensions::DIR_TEST_DATA, &path);
+      gurl_to_pwa_map_[gurl] = extensions::ExtensionBuilder(gurl.spec())
+                                   .SetPath(path.AppendASCII(gurl.spec()))
+                                   .Build();
+    }
+
+   private:
+    // AndroidSmsAppHelperDelegateImpl::PwaFetcherDelegate:
+    const extensions::Extension* GetPwaForUrl(Profile* profile,
+                                              GURL gurl) override {
+      if (!base::ContainsKey(gurl_to_pwa_map_, gurl))
+        return nullptr;
+
+      return gurl_to_pwa_map_[gurl].get();
+    }
+
+    base::flat_map<GURL, scoped_refptr<const extensions::Extension>>
+        gurl_to_pwa_map_;
+  };
+
   AndroidSmsAppHelperDelegateImplTest()
       : host_content_settings_map_(
             HostContentSettingsMapFactory::GetForProfile(&profile_)) {}
@@ -99,6 +144,15 @@
         base::WrapUnique(new AndroidSmsAppHelperDelegateImpl(
             test_pending_app_manager_.get(), host_content_settings_map_,
             fake_cookie_manager_.get()));
+
+    auto test_pwa_fetcher_delegate = std::make_unique<TestPwaFetcherDelegate>();
+    test_pwa_fetcher_delegate_ = test_pwa_fetcher_delegate.get();
+    std::unique_ptr<AndroidSmsAppHelperDelegateImpl::PwaFetcherDelegate>
+        base_delegate(test_pwa_fetcher_delegate.release());
+
+    static_cast<AndroidSmsAppHelperDelegateImpl*>(
+        android_sms_app_helper_delegate_.get())
+        ->SetPwaFetcherDelegateForTesting(std::move(base_delegate));
   }
 
   web_app::TestPendingAppManager* test_pending_app_manager() {
@@ -129,56 +183,89 @@
     return static_cast<ContentSetting>(notification_settings_value->GetInt());
   }
 
+  void TestInstallMessagesApp() {
+    base::HistogramTester histogram_tester;
+    EXPECT_NE(ContentSetting::CONTENT_SETTING_ALLOW, GetNotificationSetting());
+    SetUpApp();
+
+    std::vector<web_app::PendingAppManager::AppInfo> expected_apps_to_install;
+
+    web_app::PendingAppManager::AppInfo info(
+        chromeos::android_sms::GetAndroidMessagesURL(),
+        web_app::LaunchContainer::kWindow, web_app::InstallSource::kInternal);
+    info.override_previous_user_uninstall = true;
+    info.bypass_service_worker_check = true;
+    info.require_manifest = true;
+
+    expected_apps_to_install.push_back(std::move(info));
+
+    EXPECT_EQ(expected_apps_to_install,
+              test_pending_app_manager()->install_requests());
+    EXPECT_EQ(ContentSetting::CONTENT_SETTING_ALLOW, GetNotificationSetting());
+    histogram_tester.ExpectBucketCount("AndroidSms.PWAInstallationResult",
+                                       web_app::InstallResultCode::kSuccess, 1);
+
+    // Check if the default_to_persist cookie is set.
+    ASSERT_EQ(1u, fake_cookie_manager()->set_canonical_cookie_calls().size());
+    std::tuple<net::CanonicalCookie, bool, bool> set_cookie_call =
+        fake_cookie_manager()->set_canonical_cookie_calls()[0];
+    EXPECT_EQ("default_to_persist", std::get<0>(set_cookie_call).Name());
+    EXPECT_EQ("true", std::get<0>(set_cookie_call).Value());
+    EXPECT_TRUE(std::get<1>(set_cookie_call));
+    EXPECT_FALSE(std::get<2>(set_cookie_call));
+  }
+
+  void VerifyCookieDeletedForUrl(GURL gurl) {
+    ASSERT_EQ(1u, fake_cookie_manager()->delete_cookies_calls().size());
+    const network::mojom::CookieDeletionFilterPtr& delete_filter =
+        fake_cookie_manager()->delete_cookies_calls()[0];
+    EXPECT_EQ(gurl, delete_filter->url);
+    EXPECT_EQ("default_to_persist", delete_filter->cookie_name);
+  }
+
+  TestPwaFetcherDelegate* test_pwa_fetcher_delegate() {
+    return test_pwa_fetcher_delegate_;
+  }
+
  private:
   content::TestBrowserThreadBundle thread_bundle_;
   TestingProfile profile_;
   HostContentSettingsMap* host_content_settings_map_;
   std::unique_ptr<FakeCookieManager> fake_cookie_manager_;
   std::unique_ptr<web_app::TestPendingAppManager> test_pending_app_manager_;
+  TestPwaFetcherDelegate* test_pwa_fetcher_delegate_;
   std::unique_ptr<AndroidSmsAppHelperDelegate> android_sms_app_helper_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(AndroidSmsAppHelperDelegateImplTest);
 };
 
-TEST_F(AndroidSmsAppHelperDelegateImplTest, TestInstallMessagesApp) {
-  base::HistogramTester histogram_tester;
-  EXPECT_NE(ContentSetting::CONTENT_SETTING_ALLOW, GetNotificationSetting());
-  SetUpApp();
+TEST_F(AndroidSmsAppHelperDelegateImplTest, TestInstallMessagesApp_NoOldApp) {
+  TestInstallMessagesApp();
 
-  std::vector<web_app::PendingAppManager::AppInfo> expected_apps_to_install;
+  // No app should have been uninstalled in this process.
+  EXPECT_EQ(0u, test_pending_app_manager()->uninstall_requests().size());
+}
 
-  web_app::PendingAppManager::AppInfo info(
-      chromeos::android_sms::GetAndroidMessagesURLWithParams(),
-      web_app::LaunchContainer::kWindow, web_app::InstallSource::kInternal);
-  info.override_previous_user_uninstall = true;
-  info.bypass_service_worker_check = true;
-  info.require_manifest = true;
+TEST_F(AndroidSmsAppHelperDelegateImplTest,
+       TestInstallMessagesApp_UninstallsOldApp) {
+  // Simulate a PWA having already been installed at the old URL.
+  test_pwa_fetcher_delegate()->SetHasPwa(
+      android_sms::GetAndroidMessagesURLOld(), true /* has_pwa */);
 
-  expected_apps_to_install.push_back(std::move(info));
+  TestInstallMessagesApp();
 
-  EXPECT_EQ(expected_apps_to_install,
-            test_pending_app_manager()->install_requests());
-  EXPECT_EQ(ContentSetting::CONTENT_SETTING_ALLOW, GetNotificationSetting());
-  histogram_tester.ExpectBucketCount("AndroidSms.PWAInstallationResult",
-                                     web_app::InstallResultCode::kSuccess, 1);
+  // The old app should have been uninstalled.
+  ASSERT_EQ(1u, test_pending_app_manager()->uninstall_requests().size());
+  EXPECT_EQ(android_sms::GetAndroidMessagesURLOld(),
+            test_pending_app_manager()->uninstall_requests()[0]);
 
-  // Check if the default_to_persist cookie is set.
-  ASSERT_EQ(1u, fake_cookie_manager()->set_canonical_cookie_calls().size());
-  std::tuple<net::CanonicalCookie, bool, bool> set_cookie_call =
-      fake_cookie_manager()->set_canonical_cookie_calls()[0];
-  EXPECT_EQ("default_to_persist", std::get<0>(set_cookie_call).Name());
-  EXPECT_EQ("true", std::get<0>(set_cookie_call).Value());
-  EXPECT_TRUE(std::get<1>(set_cookie_call));
-  EXPECT_FALSE(std::get<2>(set_cookie_call));
+  // The old app's cookie should have been deleted.
+  VerifyCookieDeletedForUrl(android_sms::GetAndroidMessagesURLOld());
 }
 
 TEST_F(AndroidSmsAppHelperDelegateImplTest, TestTearDownMessagesApp) {
   TearDownApp();
-  ASSERT_EQ(1u, fake_cookie_manager()->delete_cookies_calls().size());
-  const network::mojom::CookieDeletionFilterPtr& delete_filter =
-      fake_cookie_manager()->delete_cookies_calls()[0];
-  EXPECT_EQ(android_sms::GetAndroidMessagesURL(), delete_filter->url);
-  EXPECT_EQ("default_to_persist", delete_filter->cookie_name);
+  VerifyCookieDeletedForUrl(android_sms::GetAndroidMessagesURL());
 }
 
 TEST_F(AndroidSmsAppHelperDelegateImplTest, TestInstallAndLaunchMessagesApp) {
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn b/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn
index b994829..764e4252 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn
+++ b/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn
@@ -10,6 +10,8 @@
   ]
 
   sources = [
+    "ml_service_client.cc",
+    "ml_service_client.h",
     "model_impl.cc",
     "tf_native_inference.cc",
     "tf_native_inference.h",
@@ -22,6 +24,7 @@
     "//chrome/browser/chromeos/power/ml:user_activity_ukm_logger_helpers",
     "//chrome/common:constants",
     "//chromeos:chromeos",
+    "//chromeos/services/machine_learning/public/cpp:cpp",
     "//components/assist_ranker",
     "//components/assist_ranker/proto",
     "//components/sessions",
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/lite_example_preprocessor_config.pb b/chrome/browser/chromeos/power/ml/smart_dim/lite_example_preprocessor_config.pb
new file mode 100644
index 0000000..a91479e0
--- /dev/null
+++ b/chrome/browser/chromeos/power/ml/smart_dim/lite_example_preprocessor_config.pb
Binary files differ
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.cc b/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.cc
new file mode 100644
index 0000000..7a28fd9
--- /dev/null
+++ b/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.cc
@@ -0,0 +1,138 @@
+// Copyright 2018 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/chromeos/power/ml/smart_dim/ml_service_client.h"
+
+#include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/power/ml/smart_dim/model_impl.h"
+#include "mojo/public/cpp/bindings/map.h"
+
+using ::chromeos::machine_learning::mojom::CreateGraphExecutorResult;
+using ::chromeos::machine_learning::mojom::ExecuteResult;
+using ::chromeos::machine_learning::mojom::FloatList;
+using ::chromeos::machine_learning::mojom::Int64List;
+using ::chromeos::machine_learning::mojom::LoadModelResult;
+using ::chromeos::machine_learning::mojom::ModelId;
+using ::chromeos::machine_learning::mojom::ModelSpec;
+using ::chromeos::machine_learning::mojom::ModelSpecPtr;
+using ::chromeos::machine_learning::mojom::Tensor;
+using ::chromeos::machine_learning::mojom::TensorPtr;
+using ::chromeos::machine_learning::mojom::ValueList;
+
+namespace chromeos {
+namespace power {
+namespace ml {
+
+namespace {
+
+// TODO(crbug.com/893425): This should exist in only one location, so it should
+// be merged with its duplicate in model_impl.cc to a common location.
+void LogPowerMLSmartDimModelResult(SmartDimModelResult result) {
+  UMA_HISTOGRAM_ENUMERATION("PowerML.SmartDimModel.Result", result);
+}
+
+}  // namespace
+
+MlServiceClient::MlServiceClient() : weak_factory_(this) {}
+
+MlServiceClient::~MlServiceClient() {}
+
+void MlServiceClient::LoadModelCallback(LoadModelResult result) {
+  if (result != LoadModelResult::OK) {
+    // TODO(crbug.com/893425): Log to UMA.
+    LOG(ERROR) << "Failed to load Smart Dim model.";
+  }
+}
+
+void MlServiceClient::CreateGraphExecutorCallback(
+    CreateGraphExecutorResult result) {
+  if (result != CreateGraphExecutorResult::OK) {
+    // TODO(crbug.com/893425): Log to UMA.
+    LOG(ERROR) << "Failed to create Smart Dim Graph Executor.";
+  }
+}
+
+void MlServiceClient::ExecuteCallback(
+    base::Callback<UserActivityEvent::ModelPrediction(float)>
+        get_prediction_callback,
+    SmartDimModel::DimDecisionCallback decision_callback,
+    const ExecuteResult result,
+    const base::Optional<std::vector<TensorPtr>> outputs) {
+  UserActivityEvent::ModelPrediction prediction;
+
+  if (result != ExecuteResult::OK) {
+    LOG(ERROR) << "Smart Dim inference execution failed.";
+    prediction.set_response(UserActivityEvent::ModelPrediction::MODEL_ERROR);
+    LogPowerMLSmartDimModelResult(SmartDimModelResult::kOtherError);
+  } else {
+    LogPowerMLSmartDimModelResult(SmartDimModelResult::kSuccess);
+    float inactivity_score =
+        (outputs.value())[0]->data->get_float_list()->value[0];
+    prediction = get_prediction_callback.Run(inactivity_score);
+  }
+
+  std::move(decision_callback).Run(prediction);
+}
+
+void MlServiceClient::InitMlServiceHandlesIfNeeded() {
+  if (!model_) {
+    // Load the model.
+    ModelSpecPtr spec = ModelSpec::New(ModelId::SMART_DIM);
+    chromeos::machine_learning::ServiceConnection::GetInstance()->LoadModel(
+        std::move(spec), mojo::MakeRequest(&model_),
+        base::BindOnce(&MlServiceClient::LoadModelCallback,
+                       weak_factory_.GetWeakPtr()));
+  }
+
+  if (!executor_) {
+    // Get the graph executor.
+    model_->CreateGraphExecutor(
+        mojo::MakeRequest(&executor_),
+        base::BindOnce(&MlServiceClient::CreateGraphExecutorCallback,
+                       weak_factory_.GetWeakPtr()));
+    executor_.set_connection_error_handler(base::BindOnce(
+        &MlServiceClient::OnConnectionError, weak_factory_.GetWeakPtr()));
+  }
+}
+
+void MlServiceClient::OnConnectionError() {
+  // TODO(crbug.com/893425): Log to UMA.
+  LOG(WARNING) << "Mojo connection for ML service closed.";
+  executor_.reset();
+  model_.reset();
+}
+
+void MlServiceClient::DoInference(
+    const std::vector<float>& features,
+    base::Callback<UserActivityEvent::ModelPrediction(float)>
+        get_prediction_callback,
+    SmartDimModel::DimDecisionCallback decision_callback) {
+  InitMlServiceHandlesIfNeeded();
+
+  // Prepare the input tensor.
+  std::map<std::string, TensorPtr> inputs;
+  auto tensor = Tensor::New();
+  tensor->shape = Int64List::New();
+  tensor->shape->value = std::vector<int64_t>({1, features.size()});
+  tensor->data = ValueList::New();
+  tensor->data->set_float_list(FloatList::New());
+  tensor->data->get_float_list()->value =
+      std::vector<double>(std::begin(features), std::end(features));
+  inputs.emplace(std::string("input"), std::move(tensor));
+
+  std::vector<std::string> outputs({std::string("output")});
+
+  executor_->Execute(
+      mojo::MapToFlatMap(std::move(inputs)), std::move(outputs),
+      base::BindOnce(&MlServiceClient::ExecuteCallback,
+                     weak_factory_.GetWeakPtr(), get_prediction_callback,
+                     std::move(decision_callback)));
+}
+
+}  // namespace ml
+}  // namespace power
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.h b/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.h
new file mode 100644
index 0000000..9b76d42
--- /dev/null
+++ b/chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.h
@@ -0,0 +1,82 @@
+// Copyright 2018 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_CHROMEOS_POWER_ML_SMART_DIM_ML_SERVICE_CLIENT_H_
+#define CHROME_BROWSER_CHROMEOS_POWER_ML_SMART_DIM_ML_SERVICE_CLIENT_H_
+
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/power/ml/smart_dim/model.h"
+#include "chromeos/services/machine_learning/public/cpp/service_connection.h"
+
+namespace chromeos {
+namespace power {
+namespace ml {
+
+// ML service Mojo client which loads a Smart Dim model, and then performs
+// inference on inputs provided by the caller.
+class MlServiceClient {
+ public:
+  MlServiceClient();
+  ~MlServiceClient();
+
+  // Sends an input vector to the ML service to run inference on. It also
+  // provides a |decision_callback| to the Mojo service which will be run
+  // by the ExecuteCallback() on a return from the inference call.
+  //
+  // |get_prediction_callback| takes an inactivity score value returned
+  // by the ML model and uses it to return a ModelPrediction which is fed
+  // into the |decision_callback|.
+  //
+  // NOTE: A successful Mojo call *does not* guarantee a successful inference
+  // call. The ExecuteCallback can be run with failure result, in case the
+  // inference call failed.
+  void DoInference(const std::vector<float>& features,
+                   base::Callback<UserActivityEvent::ModelPrediction(float)>
+                       get_prediction_callback,
+                   SmartDimModel::DimDecisionCallback decision_callback);
+
+ private:
+  // Various callbacks that get invoked by the Mojo framework.
+  void LoadModelCallback(
+      ::chromeos::machine_learning::mojom::LoadModelResult result);
+  void CreateGraphExecutorCallback(
+      ::chromeos::machine_learning::mojom::CreateGraphExecutorResult result);
+
+  // Callback executed by ML Service when an Execute call is complete.
+  //
+  // The |get_prediction_callback| and the |decision_callback| are bound
+  // to the ExecuteCallback during while calling the Execute() function
+  // on the Mojo API.
+  void ExecuteCallback(
+      base::Callback<UserActivityEvent::ModelPrediction(float)>
+          get_prediction_callback,
+      SmartDimModel::DimDecisionCallback decision_callback,
+      ::chromeos::machine_learning::mojom::ExecuteResult result,
+      base::Optional<
+          std::vector<::chromeos::machine_learning::mojom::TensorPtr>> outputs);
+  // Initializes the various handles to the ML service if they're not already
+  // available.
+  void InitMlServiceHandlesIfNeeded();
+
+  void OnConnectionError();
+
+  // Pointers used to execute functions in the ML service server end.
+  ::chromeos::machine_learning::mojom::ModelPtr model_;
+  ::chromeos::machine_learning::mojom::GraphExecutorPtr executor_;
+
+  base::WeakPtrFactory<MlServiceClient> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MlServiceClient);
+};
+
+}  // namespace ml
+}  // namespace power
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_POWER_ML_SMART_DIM_ML_SERVICE_CLIENT_H_
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc b/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc
index 7fcf1e3..8a713345 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc
+++ b/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc
@@ -33,16 +33,23 @@
 
 namespace {
 
+constexpr int64_t kLiteModelInputVectorSize = 343;
+
 // Loads the preprocessor config protobuf, which will be used later to convert a
 // RankerExample to a vectorized float for inactivity score calculation. Returns
 // nullptr if cannot load or parse the config.
 std::unique_ptr<assist_ranker::ExamplePreprocessorConfig>
-LoadExamplePreprocessorConfig() {
+LoadExamplePreprocessorConfig(bool use_ml_service) {
   auto config = std::make_unique<assist_ranker::ExamplePreprocessorConfig>();
 
+  // TODO(crbug.com/893425): Remove the TF Native version once we shift to
+  // ML service completely.
+  const int res_id = use_ml_service
+                         ? IDR_SMART_DIM_LITE_EXAMPLE_PREPROCESSOR_CONFIG_PB
+                         : IDR_SMART_DIM_EXAMPLE_PREPROCESSOR_CONFIG_PB;
+
   scoped_refptr<base::RefCountedMemory> raw_config =
-      ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
-          IDR_SMART_DIM_EXAMPLE_PREPROCESSOR_CONFIG_PB);
+      ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(res_id);
   if (!raw_config || !raw_config->front()) {
     LOG(ERROR) << "Failed to load SmartDimModel example preprocessor config.";
     return nullptr;
@@ -240,25 +247,24 @@
 
 SmartDimModelImpl::SmartDimModelImpl()
     : blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
-          {base::MayBlock(), base::TaskPriority::USER_VISIBLE})) {}
+          {base::MayBlock(), base::TaskPriority::USER_VISIBLE})),
+      use_ml_service_(base::FeatureList::IsEnabled(
+          features::kUserActivityPredictionMlService)){};
 
 SmartDimModelImpl::~SmartDimModelImpl() = default;
 
-SmartDimModelResult SmartDimModelImpl::CalculateInactivityScore(
+SmartDimModelResult SmartDimModelImpl::PreprocessInput(
     const UserActivityEvent::Features& features,
-    float* inactivity_score_out) {
-  CHECK(inactivity_score_out);
-
+    std::vector<float>* vectorized_features) {
+  DCHECK(vectorized_features);
   LazyInitialize();
+
   if (!preprocessor_config_) {
-    LogPowerMLSmartDimModelResult(
-        SmartDimModelResult::kPreprocessorInitializationFailed);
     return SmartDimModelResult::kPreprocessorInitializationFailed;
   }
 
   assist_ranker::RankerExample ranker_example;
   if (!PopulateRankerExample(features, &ranker_example)) {
-    LogPowerMLSmartDimModelResult(SmartDimModelResult::kOtherError);
     return SmartDimModelResult::kOtherError;
   }
 
@@ -268,16 +274,40 @@
   if (preprocessor_error &&
       preprocessor_error !=
           assist_ranker::ExamplePreprocessor::kNoFeatureIndexFound) {
-    LogPowerMLSmartDimModelResult(SmartDimModelResult::kPreprocessorOtherError);
     return SmartDimModelResult::kPreprocessorOtherError;
   }
 
-  const auto& vectorized_features =
+  const auto& extracted_features =
       ranker_example.features()
           .at(assist_ranker::ExamplePreprocessor::kVectorizedFeatureDefaultName)
           .float_list()
           .float_value();
-  CHECK_EQ(vectorized_features.size(), tfnative_model::FEATURES_SIZE);
+  vectorized_features->assign(extracted_features.begin(),
+                              extracted_features.end());
+
+  return SmartDimModelResult::kSuccess;
+}
+
+SmartDimModelResult SmartDimModelImpl::CalculateInactivityScoreTfNative(
+    const UserActivityEvent::Features& features,
+    float* inactivity_score_out) {
+  // This is the TF Native codepath.
+  // TODO(crbug.com/893425): Remove this codepath once we shift to ML service
+  // completely.
+  CHECK(inactivity_score_out);
+
+  std::vector<float> vectorized_features;
+  auto preprocess_result = PreprocessInput(features, &vectorized_features);
+  if (preprocess_result != SmartDimModelResult::kSuccess) {
+    LogPowerMLSmartDimModelResult(preprocess_result);
+    return preprocess_result;
+  }
+
+  if (vectorized_features.size() != tfnative_model::FEATURES_SIZE) {
+    LogPowerMLSmartDimModelResult(
+        SmartDimModelResult::kMismatchedFeatureSizeError);
+    return SmartDimModelResult::kMismatchedFeatureSizeError;
+  }
 
   if (!model_alloc_)
     model_alloc_ = std::make_unique<tfnative_model::FixedAllocations>();
@@ -285,28 +315,13 @@
   tfnative_model::Inference(vectorized_features.data(), inactivity_score_out,
                             model_alloc_.get());
 
-  LogPowerMLSmartDimModelResult(SmartDimModelResult::kSuccess);
   return SmartDimModelResult::kSuccess;
 }
 
-UserActivityEvent::ModelPrediction SmartDimModelImpl::ShouldDim(
-    const UserActivityEvent::Features& input_features) {
-  const base::Optional<float> dim_threshold = GetDimThreshold();
-
+UserActivityEvent::ModelPrediction
+SmartDimModelImpl::CreatePredictionFromInactivityScore(float inactivity_score) {
   UserActivityEvent::ModelPrediction prediction;
-  if (!dim_threshold) {
-    prediction.set_response(UserActivityEvent::ModelPrediction::MODEL_ERROR);
-    return prediction;
-  }
-
-  float inactivity_score = 0;
-  const SmartDimModelResult result =
-      CalculateInactivityScore(input_features, &inactivity_score);
-
-  if (result != SmartDimModelResult::kSuccess) {
-    prediction.set_response(UserActivityEvent::ModelPrediction::MODEL_ERROR);
-    return prediction;
-  }
+  const base::Optional<float> dim_threshold = GetDimThreshold();
 
   prediction.set_decision_threshold(ScoreToProbability(dim_threshold.value()));
   prediction.set_inactivity_score(ScoreToProbability(inactivity_score));
@@ -317,20 +332,94 @@
     prediction.set_response(UserActivityEvent::ModelPrediction::NO_DIM);
   }
 
+  LogPowerMLSmartDimModelResult(SmartDimModelResult::kSuccess);
   return prediction;
 }
 
+UserActivityEvent::ModelPrediction SmartDimModelImpl::ShouldDimTfNative(
+    const UserActivityEvent::Features& input_features) {
+  UserActivityEvent::ModelPrediction prediction;
+  prediction.set_response(UserActivityEvent::ModelPrediction::MODEL_ERROR);
+
+  const base::Optional<float> dim_threshold = GetDimThreshold();
+  if (!dim_threshold) {
+    return prediction;
+  }
+
+  float inactivity_score = 0;
+  const SmartDimModelResult result =
+      CalculateInactivityScoreTfNative(input_features, &inactivity_score);
+
+  if (result != SmartDimModelResult::kSuccess) {
+    // No need to log here as all error cases are already logged in
+    // CalculateInactivityScoreTfNative.
+    return prediction;
+  }
+
+  // Logging for the success case will take place in
+  // CreatePredictionFromInactivityScore().
+  return CreatePredictionFromInactivityScore(inactivity_score);
+}
+
+void SmartDimModelImpl::ShouldDimMlService(
+    const UserActivityEvent::Features& input_features,
+    DimDecisionCallback callback) {
+  UserActivityEvent::ModelPrediction prediction;
+  prediction.set_response(UserActivityEvent::ModelPrediction::MODEL_ERROR);
+
+  const base::Optional<float> dim_threshold = GetDimThreshold();
+  if (!dim_threshold) {
+    std::move(callback).Run(prediction);
+    return;
+  }
+
+  std::vector<float> vectorized_features;
+  auto preprocess_result =
+      PreprocessInput(input_features, &vectorized_features);
+  if (preprocess_result != SmartDimModelResult::kSuccess) {
+    LogPowerMLSmartDimModelResult(preprocess_result);
+    std::move(callback).Run(prediction);
+    return;
+  }
+
+  if (vectorized_features.size() != kLiteModelInputVectorSize) {
+    LOG(ERROR) << "Smart Dim vectorized features not of correct size.";
+    LogPowerMLSmartDimModelResult(
+        SmartDimModelResult::kMismatchedFeatureSizeError);
+    std::move(callback).Run(prediction);
+    return;
+  }
+
+  if (!ml_service_client_) {
+    LOG(ERROR) << "ML service Mojo client not initialized correctly";
+    LogPowerMLSmartDimModelResult(
+        SmartDimModelResult::kMlServiceInitializationFailedError);
+    std::move(callback).Run(prediction);
+    return;
+  }
+
+  ml_service_client_->DoInference(
+      vectorized_features,
+      base::Bind(&SmartDimModelImpl::CreatePredictionFromInactivityScore,
+                 base::Unretained(this)),
+      std::move(callback));
+}
+
 void SmartDimModelImpl::RequestDimDecision(
     const UserActivityEvent::Features& input_features,
     DimDecisionCallback dim_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Cancel previously assigned callbacks and set it to the new callback.
   cancelable_callback_.Reset(std::move(dim_callback));
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&SmartDimModelImpl::ShouldDim, base::Unretained(this),
-                     input_features),
-      base::BindOnce(cancelable_callback_.callback()));
+  if (!use_ml_service_) {
+    base::PostTaskAndReplyWithResult(
+        blocking_task_runner_.get(), FROM_HERE,
+        base::BindOnce(&SmartDimModelImpl::ShouldDimTfNative,
+                       base::Unretained(this), input_features),
+        base::BindOnce(cancelable_callback_.callback()));
+  } else {
+    ShouldDimMlService(input_features, cancelable_callback_.callback());
+  }
 }
 
 void SmartDimModelImpl::CancelPreviousRequest() {
@@ -339,10 +428,18 @@
 }
 
 void SmartDimModelImpl::LazyInitialize() {
+  // TODO(crbug.com/893425): Remove the flag check once we shift to ML service
+  // completely.
+  if (use_ml_service_) {
+    if (!ml_service_client_) {
+      ml_service_client_ = std::make_unique<MlServiceClient>();
+    }
+  }
+
   if (preprocessor_config_)
     return;
 
-  preprocessor_config_ = LoadExamplePreprocessorConfig();
+  preprocessor_config_ = LoadExamplePreprocessorConfig(use_ml_service_);
   if (preprocessor_config_) {
     preprocessor_ = std::make_unique<assist_ranker::ExamplePreprocessor>(
         *preprocessor_config_);
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/model_impl.h b/chrome/browser/chromeos/power/ml/smart_dim/model_impl.h
index cd64f60ba..b887091 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/model_impl.h
+++ b/chrome/browser/chromeos/power/ml/smart_dim/model_impl.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/power/ml/smart_dim/ml_service_client.h"
 #include "chrome/browser/chromeos/power/ml/smart_dim/model.h"
 
 namespace assist_ranker {
@@ -33,7 +34,9 @@
   kPreprocessorInitializationFailed = 1,
   kPreprocessorOtherError = 2,
   kOtherError = 3,
-  kMaxValue = kOtherError
+  kMismatchedFeatureSizeError = 4,
+  kMlServiceInitializationFailedError = 5,
+  kMaxValue = kMlServiceInitializationFailedError
 };
 
 // These values are persisted to logs. Entries should not be renumbered and
@@ -59,22 +62,52 @@
 
  private:
   friend class SmartDimModelImplTest;
-  // Loads the preprocessor config if not already loaded.
+  // Loads the preprocessor config if not already loaded. Also initializes the
+  // MlServiceClient object if the ML Service is being used for inference.
   void LazyInitialize();
 
+  // Pre-processes the input features into a vector, placed in
+  // |*vectorized_features|, which is consumable by the ML model.
+  //
+  // Returns SmartDimModelResult::kSuccess on success, and the appropriate
+  // error on failure.
+  SmartDimModelResult PreprocessInput(
+      const UserActivityEvent::Features& features,
+      std::vector<float>* vectorized_features);
+
   // Calculates inactivity score and returns result status. Also logs the status
   // to UMA.
-  SmartDimModelResult CalculateInactivityScore(
+  //
+  // This codepath is used when the inference calls are made to TF-Native.
+  SmartDimModelResult CalculateInactivityScoreTfNative(
       const UserActivityEvent::Features& features,
       float* inactivity_score_out);
 
-  // Asynchronous task which gets posted to the |blocking_task_runner_| and
+  // Takes an |inactivity_score| returned from the ML model and, using that,
+  // returns a ModelPrediction.
+  //
+  // NOTE: This function is only expected to be called after successful
+  // inference executions, and therefore does not have an error path.
+  // As a corollary, it also performs the logging of a successful inference
+  // call to UMA (doing this here allows the logging to take place in a Mojo
+  // callback in case the ML service was used).
+  UserActivityEvent::ModelPrediction CreatePredictionFromInactivityScore(
+      float inactivity_score);
+
+  // Task which gets posted to the |blocking_task_runner_| and
   // performs the ML inference call. Based on the result of the inference call,
   // a prediction is returned, and this return value will be passed to a
   // DimDecisionCallback which will execute after this function.
-  UserActivityEvent::ModelPrediction ShouldDim(
+  UserActivityEvent::ModelPrediction ShouldDimTfNative(
       const UserActivityEvent::Features& input_features);
 
+  // Calls the ML service Mojo API to perform an Smart Dim inference call,
+  // given |input_features|. The |callback| is supplied to the Mojo API,
+  // which in turn will call it to provide the result (a ModelPrediction), once
+  // the inference is complete.
+  void ShouldDimMlService(const UserActivityEvent::Features& input_features,
+                          DimDecisionCallback callback);
+
   std::unique_ptr<assist_ranker::ExamplePreprocessorConfig>
       preprocessor_config_;
   std::unique_ptr<assist_ranker::ExamplePreprocessor> preprocessor_;
@@ -83,11 +116,19 @@
   // initialized once so it isn't reallocated for every inference.
   std::unique_ptr<tfnative_model::FixedAllocations> model_alloc_;
 
-  // A separate task runner is used to perform the inference.
+  // A separate task runner is used to perform the TF Native inference.
   const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+
+  // Cancelable wrapper for the DimDecisionCallback passed by the client to
+  // RequestDimDecision().
   base::CancelableOnceCallback<void(UserActivityEvent::ModelPrediction)>
       cancelable_callback_;
 
+  const bool use_ml_service_;
+  // Pointer to the object that handles the ML service calls. This pointer
+  // is only initialized if features::kSmartDimMLService is set to true.
+  std::unique_ptr<MlServiceClient> ml_service_client_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(SmartDimModelImpl);
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc b/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc
index 8397deb..4bfd455 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc
+++ b/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc
@@ -64,7 +64,8 @@
   float CalculateInactivityScore(const UserActivityEvent::Features& features) {
     float inactivity_score;
     SmartDimModelResult result =
-        smart_dim_model_.CalculateInactivityScore(features, &inactivity_score);
+        smart_dim_model_.CalculateInactivityScoreTfNative(features,
+                                                          &inactivity_score);
     EXPECT_EQ(SmartDimModelResult::kSuccess, result);
     return inactivity_score;
   }
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.cc b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
index 40eb55e..1d3edaf 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
@@ -263,8 +263,8 @@
       smart_dim_model_) {
     waiting_for_model_decision_ = true;
     smart_dim_model_->RequestDimDecision(
-        features_, base::BindOnce(&UserActivityManager::ApplyDimDecision,
-                                  weak_ptr_factory_.GetWeakPtr()));
+        features_, base::Bind(&UserActivityManager::ApplyDimDecision,
+                              weak_ptr_factory_.GetWeakPtr()));
   }
   waiting_for_final_action_ = true;
 }
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index abbfe3b9..f573d150 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -2000,7 +2000,7 @@
     events::HistogramValue histogram_value,
     const std::string& event_name,
     bool include_incognito,
-    const Event::WillDispatchCallback& will_dispatch_callback,
+    Event::WillDispatchCallback will_dispatch_callback,
     std::unique_ptr<base::Value> arg) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!EventRouter::Get(profile_))
@@ -2023,7 +2023,7 @@
   auto event =
       std::make_unique<Event>(histogram_value, event_name, std::move(args),
                               restrict_to_browser_context);
-  event->will_dispatch_callback = will_dispatch_callback;
+  event->will_dispatch_callback = std::move(will_dispatch_callback);
   EventRouter::Get(profile_)->BroadcastEvent(std::move(event));
   DownloadsNotificationSource notification_source;
   notification_source.event_name = event_name;
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.h b/chrome/browser/extensions/api/downloads/downloads_api.h
index 77c38689..6605c2a 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.h
+++ b/chrome/browser/extensions/api/downloads/downloads_api.h
@@ -388,12 +388,11 @@
   void CheckForHistoryFilesRemoval();
 
  private:
-  void DispatchEvent(
-      events::HistogramValue histogram_value,
-      const std::string& event_name,
-      bool include_incognito,
-      const extensions::Event::WillDispatchCallback& will_dispatch_callback,
-      std::unique_ptr<base::Value> json_arg);
+  void DispatchEvent(events::HistogramValue histogram_value,
+                     const std::string& event_name,
+                     bool include_incognito,
+                     Event::WillDispatchCallback will_dispatch_callback,
+                     std::unique_ptr<base::Value> json_arg);
 
   // extensions::ExtensionRegistryObserver.
   void OnExtensionUnloaded(content::BrowserContext* browser_context,
diff --git a/chrome/browser/extensions/api/tabs/tabs_event_router.cc b/chrome/browser/extensions/api/tabs/tabs_event_router.cc
index a2c3f3a..546583c3 100644
--- a/chrome/browser/extensions/api/tabs/tabs_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_event_router.cc
@@ -517,7 +517,7 @@
                                        std::move(args), profile);
   event->user_gesture = EventRouter::USER_GESTURE_NOT_ENABLED;
   event->will_dispatch_callback =
-      base::Bind(&WillDispatchTabCreatedEvent, contents, active);
+      base::BindRepeating(&WillDispatchTabCreatedEvent, contents, active);
   EventRouter::Get(profile)->BroadcastEvent(std::move(event));
 
   RegisterForTabNotifications(contents);
@@ -594,8 +594,8 @@
                                        std::move(args_base), profile);
   event->user_gesture = EventRouter::USER_GESTURE_NOT_ENABLED;
   event->will_dispatch_callback =
-      base::Bind(&WillDispatchTabUpdatedEvent, contents,
-                 std::move(changed_property_names));
+      base::BindRepeating(&WillDispatchTabUpdatedEvent, contents,
+                          std::move(changed_property_names));
   EventRouter::Get(profile)->BroadcastEvent(std::move(event));
 }
 
diff --git a/chrome/browser/extensions/api/tabs/windows_event_router.cc b/chrome/browser/extensions/api/tabs/windows_event_router.cc
index 4190a19..9fa98610 100644
--- a/chrome/browser/extensions/api/tabs/windows_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/windows_event_router.cc
@@ -279,7 +279,7 @@
       events::WINDOWS_ON_FOCUS_CHANGED, windows::OnFocusChanged::kEventName,
       std::make_unique<base::ListValue>());
   event->will_dispatch_callback =
-      base::Bind(&WillDispatchWindowFocusedEvent, window_controller);
+      base::BindRepeating(&WillDispatchWindowFocusedEvent, window_controller);
   EventRouter::Get(profile_)->BroadcastEvent(std::move(event));
 }
 
@@ -291,7 +291,7 @@
       std::make_unique<Event>(histogram_value, event_name, std::move(args),
                               window_controller->profile());
   event->will_dispatch_callback =
-      base::Bind(&WillDispatchWindowEvent, window_controller);
+      base::BindRepeating(&WillDispatchWindowEvent, window_controller);
   EventRouter::Get(profile_)->BroadcastEvent(std::move(event));
 }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index b394162d..ad78faf 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2142,7 +2142,7 @@
   },
   {
     "name": "enable_android_messages_integration",
-    // "owners": [ "your-team" ],
+    "owners": [ "azeemarshad", "jlklein", "khorimoto"],
     "expiry_milestone": 76
   },
   {
@@ -2151,11 +2151,6 @@
     "expiry_milestone": 76
   },
   {
-    "name": "enable_android_messages_prod_endpoint",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "enforce-tls13-downgrade",
     "owners": [ "davidben", "svaldez" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index b2577bb8..92fb0315 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -58,12 +58,6 @@
     "Use the messages.google.com domain as part of the \"Messages\" "
     "feature under \"Connected Devices\" settings.";
 
-const char kAndroidMessagesProdEndpointName[] =
-    "Use Android Messages prod endpoint";
-const char kAndroidMessagesProdEndpointDescription[] =
-    "For Android Messages integration, point to the prod endpoint instead of "
-    "sandbox.";
-
 const char kAndroidSiteSettingsUIRefreshName[] =
     "Android Site Settings UI changes.";
 const char kAndroidSiteSettingsUIRefreshDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 4dbe4ec..5d9838c 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -63,9 +63,6 @@
 extern const char kUseMessagesGoogleComDomainName[];
 extern const char kUseMessagesGoogleComDomainDescription[];
 
-extern const char kAndroidMessagesProdEndpointName[];
-extern const char kAndroidMessagesProdEndpointDescription[];
-
 extern const char kAndroidSiteSettingsUIRefreshName[];
 extern const char kAndroidSiteSettingsUIRefreshDescription[];
 
diff --git a/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h b/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h
index 36a8181a..1a42154 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h
+++ b/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h
@@ -16,7 +16,6 @@
 #include "net/base/completion_once_callback.h"
 #include "storage/browser/fileapi/file_stream_reader.h"
 #include "storage/browser/fileapi/file_system_url.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 class FileSystemContext;
diff --git a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
index 2b2c757..d134814 100644
--- a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
@@ -79,6 +79,11 @@
     LOG(WARNING) << "Set OOM score: " << output;
 }
 
+bool IsNewProcessTypesEnabled() {
+  return base::FeatureList::IsEnabled(features::kNewProcessTypes) &&
+         !base::FeatureList::IsEnabled(features::kTabRanker);
+}
+
 }  // namespace
 
 // static
@@ -134,7 +139,7 @@
     return *app() < *rhs.app();
   if (lifecycle_unit() && rhs.lifecycle_unit())
     return lifecycle_unit_sort_key_ > rhs.lifecycle_unit_sort_key_;
-  // When TabRanker experiment is turned on and using old ProcessType
+  // When NewProcessTypes feature is turned off and using old ProcessType
   // categories, tabs and apps are in separate categories so this is an
   // impossible case. Otherwise, tabs and apps are compared using last active
   // time.
@@ -155,18 +160,18 @@
 }
 
 ProcessType TabManagerDelegate::Candidate::GetProcessTypeInternal() const {
-  bool tab_ranker_active = base::FeatureList::IsEnabled(features::kTabRanker);
+  const bool use_new_proc_types = IsNewProcessTypesEnabled();
   if (app()) {
     if (app()->is_focused())
       return ProcessType::FOCUSED_APP;
-    if (tab_ranker_active && app()->IsImportant())
-      return ProcessType::IMPORTANT_APP;
-    if (!tab_ranker_active && app()->IsBackgroundProtected())
+    if (!use_new_proc_types) {
+      return app()->IsImportant() ? ProcessType::IMPORTANT_APP
+                                  : ProcessType::BACKGROUND_APP;
+    }
+    if (app()->IsBackgroundProtected())
       return ProcessType::PROTECTED_BACKGROUND;
-    if (!tab_ranker_active && app()->IsCached())
+    if (app()->IsCached())
       return ProcessType::CACHED_APP;
-    if (tab_ranker_active)
-      return ProcessType::BACKGROUND_APP;
     return ProcessType::BACKGROUND;
   }
   if (lifecycle_unit()) {
@@ -176,11 +181,11 @@
     if (!lifecycle_unit()->CanDiscard(
             ::mojom::LifecycleUnitDiscardReason::PROACTIVE,
             &decision_details)) {
-      return tab_ranker_active ? ProcessType::PROTECTED_BACKGROUND_TAB
-                               : ProcessType::PROTECTED_BACKGROUND;
+      return use_new_proc_types ? ProcessType::PROTECTED_BACKGROUND
+                                : ProcessType::PROTECTED_BACKGROUND_TAB;
     }
-    return tab_ranker_active ? ProcessType::BACKGROUND_TAB
-                             : ProcessType::BACKGROUND;
+    return use_new_proc_types ? ProcessType::BACKGROUND
+                              : ProcessType::BACKGROUND_TAB;
   }
   return ProcessType::UNKNOWN_TYPE;
 }
@@ -723,9 +728,9 @@
   // Find some pivot point. For now (roughly) apps are in the first half and
   // tabs are in the second half.
   auto lower_priority_part = candidates.end();
-  ProcessType pivot_type = base::FeatureList::IsEnabled(features::kTabRanker)
-                               ? ProcessType::BACKGROUND_TAB
-                               : ProcessType::BACKGROUND;
+  bool use_new_proc_types = IsNewProcessTypesEnabled();
+  ProcessType pivot_type = use_new_proc_types ? ProcessType::BACKGROUND
+                                              : ProcessType::BACKGROUND_TAB;
   for (auto it = candidates.begin(); it != candidates.end(); ++it) {
     if (it->process_type() >= pivot_type) {
       lower_priority_part = it;
diff --git a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h
index 411aec4f..86e3121 100644
--- a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h
@@ -56,6 +56,8 @@
   // and PROTECTED_BACKGROUND_TAB are now in PROTECTED_BACKGROUND, processes
   // previously in either BACKGROUND_APP or BACKGROUND_TAB are now BACKGROUND.
   // CACHED_APP marks Android processes which are cached or empty.
+  // Currently these types are only used on systems where the NewProcessTypes
+  // feature is enabled.
   PROTECTED_BACKGROUND = 7,
   BACKGROUND = 8,
   CACHED_APP = 9,
diff --git a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc
index e063a6df..97d1f6a1 100644
--- a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc
@@ -74,11 +74,11 @@
   // visible app 2, last_activity_time less than visible app 1.
   ASSERT_TRUE(candidates[3].app());
   EXPECT_EQ("visible2", candidates[3].app()->process_name());
-  // protected LifecycleUnit
-  EXPECT_EQ(candidates[4].lifecycle_unit(), &protected_lifecycle_unit);
   // background service.
-  ASSERT_TRUE(candidates[5].app());
-  EXPECT_EQ("service", candidates[5].app()->process_name());
+  ASSERT_TRUE(candidates[4].app());
+  EXPECT_EQ("service", candidates[4].app()->process_name());
+  // protected LifecycleUnit
+  EXPECT_EQ(candidates[5].lifecycle_unit(), &protected_lifecycle_unit);
   // non-focused LifecycleUnits, sorted by last focused time.
   EXPECT_EQ(candidates[6].lifecycle_unit(), &other_non_focused_lifecycle_unit);
   EXPECT_EQ(candidates[7].lifecycle_unit(), &non_focused_lifecycle_unit);
@@ -232,10 +232,10 @@
 
   // Sorted order (by GetSortedCandidates):
   // app "focused"       pid: 10
-  // app "visible1"      pid: 20
-  // app "visible2"      pid: 40
   // app "persistent"    pid: 50
   // app "persistent_ui" pid: 60
+  // app "visible1"      pid: 20
+  // app "visible2"      pid: 40
   // app "service"       pid: 30
   // tab3                pid: 12
   // tab4                pid: 12
@@ -256,13 +256,13 @@
 
   // Higher priority part.
   EXPECT_EQ(300, oom_score_map[10]);
-  EXPECT_EQ(417, oom_score_map[20]);
-  EXPECT_EQ(533, oom_score_map[40]);
+  EXPECT_EQ(388, oom_score_map[20]);
+  EXPECT_EQ(475, oom_score_map[40]);
+  EXPECT_EQ(563, oom_score_map[30]);
 
   // Lower priority part.
-  EXPECT_EQ(650, oom_score_map[30]);
-  EXPECT_EQ(708, oom_score_map[12]);
-  EXPECT_EQ(767, oom_score_map[11]);
+  EXPECT_EQ(650, oom_score_map[12]);
+  EXPECT_EQ(720, oom_score_map[11]);
 }
 
 TEST_F(TabManagerDelegateTest, IsRecentlyKilledArcProcess) {
@@ -390,15 +390,14 @@
   // tab2              pid: 11  id 2
   memory_stat->SetTargetMemoryToFreeKB(250000);
   // Entities to be killed.
-  // TODO(wvk) For now the estimation of freed memory for tabs is 0, but we
-  // probably want to fix it later by properly implementing 
-  // TestLifecycleUnit::GetEstimatedMemoryFreedOnDiscardKB.
-  memory_stat->SetProcessPss(20, 30000);
+  memory_stat->SetProcessPss(11, 50000);
+  memory_stat->SetProcessPss(12, 30000);
   memory_stat->SetProcessPss(30, 10000);
-  memory_stat->SetProcessPss(40, 50000);
   memory_stat->SetProcessPss(50, 60000);
-  // Should not be killed.
+  // Should not be used.
   memory_stat->SetProcessPss(60, 500000);
+  memory_stat->SetProcessPss(40, 50000);
+  memory_stat->SetProcessPss(20, 30000);
   memory_stat->SetProcessPss(10, 100000);
 
   tab_manager_delegate.LowMemoryKillImpl(
@@ -408,13 +407,10 @@
   auto killed_arc_processes = tab_manager_delegate.GetKilledArcProcesses();
   auto killed_tabs = tab_manager_delegate.GetKilledTabs();
 
-  // Killed apps and their nspid. Should be all of the apps except the
-  // the focused app and the app marked as persistent
-  ASSERT_EQ(4U, killed_arc_processes.size());
+  // Killed apps and their nspid.
+  ASSERT_EQ(2U, killed_arc_processes.size());
   EXPECT_EQ(3, killed_arc_processes[0]);
   EXPECT_EQ(5, killed_arc_processes[1]);
-  EXPECT_EQ(4, killed_arc_processes[2]);
-  EXPECT_EQ(2, killed_arc_processes[3]);
   // Killed tabs and their content id.
   // Note that process with pid 11 is counted twice and pid 12 is counted 3
   // times. But so far I don't have a good way to estimate the memory freed
@@ -429,11 +425,9 @@
   // Check that killed apps are in the map.
   const TabManagerDelegate::KilledArcProcessesMap& processes_map =
       tab_manager_delegate.recently_killed_arc_processes_;
-  EXPECT_EQ(4U, processes_map.size());
+  EXPECT_EQ(2U, processes_map.size());
   EXPECT_EQ(1U, processes_map.count("service"));
   EXPECT_EQ(1U, processes_map.count("not-visible"));
-  EXPECT_EQ(1U, processes_map.count("visible1"));
-  EXPECT_EQ(1U, processes_map.count("visible2"));
 }
 
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_manager_features.cc b/chrome/browser/resource_coordinator/tab_manager_features.cc
index ffd7a9b..ccfd1c4 100644
--- a/chrome/browser/resource_coordinator/tab_manager_features.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_features.cc
@@ -53,6 +53,13 @@
 // on last focused time.
 const base::Feature kTabRanker{"TabRanker", base::FEATURE_DISABLED_BY_DEFAULT};
 
+#if defined(OS_CHROMEOS)
+// On ChromeOS, enables using new ProcessType enums that combine apps and tabs
+// in the same categories.
+const base::Feature kNewProcessTypes{
+  "NewProcessTypes", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // defined(OS_CHROMEOS)
+
 }  // namespace features
 
 namespace resource_coordinator {
diff --git a/chrome/browser/resource_coordinator/tab_manager_features.h b/chrome/browser/resource_coordinator/tab_manager_features.h
index 0c2693f..3d9c045 100644
--- a/chrome/browser/resource_coordinator/tab_manager_features.h
+++ b/chrome/browser/resource_coordinator/tab_manager_features.h
@@ -20,6 +20,9 @@
 extern const base::Feature kStaggeredBackgroundTabOpening;
 extern const base::Feature kStaggeredBackgroundTabOpeningExperiment;
 extern const base::Feature kTabRanker;
+#if defined(OS_CHROMEOS)
+extern const base::Feature kNewProcessTypes;
+#endif // defined(OS_CHROMEOS)
 
 }  // namespace features
 
diff --git a/chrome/browser/resources/app_management/main_view.html b/chrome/browser/resources/app_management/main_view.html
index beca642c..5134fd6 100644
--- a/chrome/browser/resources/app_management/main_view.html
+++ b/chrome/browser/resources/app_management/main_view.html
@@ -33,6 +33,11 @@
         padding-inline-end: 8px;
         padding-inline-start: 24px;
       }
+
+      .permission-row-sublabel {
+        display: flex;
+        flex-direction: column;
+      }
     </style>
 
     <div class="card-container">
@@ -57,6 +62,22 @@
         </paper-icon-button-light>
       </div>
     </div>
+
+    <div class="card-container">
+      <div class="permission-row">
+        <div class="permission-row-sublabel">
+          <div class="header-text">
+              $i18n{notifications}
+          </div>
+          <div class="secondary-text">
+              [[getNotificationSublabel_(notificationApps_)]]
+          </div>
+        </div>
+        <paper-icon-button-light class="subpage-arrow" actionable>
+          <button></button>
+        </paper-icon-button-light>
+      </div>
+    </div>
   </template>
   <script src="chrome://apps/main_view.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/app_management/main_view.js b/chrome/browser/resources/app_management/main_view.js
index 38027e346..0e170a67 100644
--- a/chrome/browser/resources/app_management/main_view.js
+++ b/chrome/browser/resources/app_management/main_view.js
@@ -44,7 +44,23 @@
     listExpanded_: {
       type: Boolean,
       value: false,
-    }
+    },
+
+    /**
+     * List of apps with the notification permission.
+     * @private {Array<appManagement.mojom.App>}
+     */
+     notificationApps_: {
+      type: Array,
+      value: function() {
+        const apps = [];
+        for (let i = 0; i < NUMBER_OF_APPS_DISPLAYED_DEFAULT; i++) {
+          apps.push(
+          app_management.FakePageHandler.createApp('Notified' + i));
+        }
+        return apps;
+      },
+    },
   },
 
   attached: function() {
@@ -94,4 +110,14 @@
   getCollapsedIcon_: function(listExpanded) {
     return listExpanded ? 'cr:expand-less' : 'cr:expand-more';
   },
+
+  /**
+   * @param {Array<appManagement.mojom.App>} notificationApps
+   * @return {string}
+   * @private
+   */
+   getNotificationSublabel_: function(notificationApps){
+    return loadTimeData.getStringF(
+        'notificationSublabel', notificationApps.length);
+   }
 });
diff --git a/chrome/browser/resources/app_management/pwa_permission_view.html b/chrome/browser/resources/app_management/pwa_permission_view.html
index 473af257..2fa4145 100644
--- a/chrome/browser/resources/app_management/pwa_permission_view.html
+++ b/chrome/browser/resources/app_management/pwa_permission_view.html
@@ -41,24 +41,6 @@
       flex-direction: column;
     }
 
-    .permission-row {
-      align-items: center;
-      border-top: var(--card-separator);
-      display: inline-flex;
-      height: 62px;
-      justify-content: space-between;
-      padding: 0 24px;
-    }
-
-    .permission-row:first-child {
-      border-style: none;
-    }
-
-    .permission-row-controls {
-      align-items: center;
-      display: inline-flex;
-    }
-
     .control-divider {
       background: var(--control-separator-color);
       height: 24px;
diff --git a/chrome/browser/resources/app_management/shared_style.html b/chrome/browser/resources/app_management/shared_style.html
index 83f45c5..fab54b9 100644
--- a/chrome/browser/resources/app_management/shared_style.html
+++ b/chrome/browser/resources/app_management/shared_style.html
@@ -24,5 +24,28 @@
         color: var(--primary-text-color);
         font-weight: var(--secondary-font-weight);
       }
+
+      .secondary-text {
+        color: var(--secondary-text-color);
+        font-weight: var(--secondary-font-weight);
+      }
+
+      .permission-row {
+        align-items: center;
+        border-top: var(--card-separator);
+        display: flex;
+        height: 62px;
+        justify-content: space-between;
+        padding: 0 24px;
+      }
+
+      .permission-row:first-child {
+        border-style: none;
+      }
+
+      .permission-row-controls {
+        align-items: center;
+        display: inline-flex;
+      }
     </style>
   </template>
diff --git a/chrome/browser/resources/chromeos/certificate_manager_dialog.html b/chrome/browser/resources/chromeos/certificate_manager_dialog.html
index 0879440..97cc276e 100644
--- a/chrome/browser/resources/chromeos/certificate_manager_dialog.html
+++ b/chrome/browser/resources/chromeos/certificate_manager_dialog.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html i18n-values="dir:textdirection;lang:language">
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
 
   <head>
     <meta charset="utf-8">
diff --git a/chrome/browser/resources/discards/discards.html b/chrome/browser/resources/discards/discards.html
index dafda585..75ef478d 100644
--- a/chrome/browser/resources/discards/discards.html
+++ b/chrome/browser/resources/discards/discards.html
@@ -6,7 +6,7 @@
 This is an internal only page meant for debugging. It is not intended for
 general use and is not localized.-->
 <!doctype html>
-<html lang="en">
+<html dir="ltr" lang="en">
   <head>
     <title>Discards</title>
     <meta charset="utf-8">
diff --git a/chrome/browser/resources/md_bookmarks/app.js b/chrome/browser/resources/md_bookmarks/app.js
index c9b5ee2..d158846 100644
--- a/chrome/browser/resources/md_bookmarks/app.js
+++ b/chrome/browser/resources/md_bookmarks/app.js
@@ -35,6 +35,8 @@
 
   /** @override */
   attached: function() {
+    document.documentElement.classList.remove('loading');
+
     this.watch('searchTerm_', function(state) {
       return state.search.term;
     });
@@ -43,6 +45,10 @@
       return state.folderOpenState;
     });
 
+    this.addEventListener('select-toolbar-search', () => {
+      this.$$('bookmarks-toolbar').searchField.showAndFocus();
+    });
+
     chrome.bookmarks.getTree((results) => {
       const nodeMap = bookmarks.util.normalizeNodes(results[0]);
       const initialState = bookmarks.util.createEmptyState();
diff --git a/chrome/browser/resources/md_bookmarks/bookmarks.html b/chrome/browser/resources/md_bookmarks/bookmarks.html
index c4991ad..eee3b239 100644
--- a/chrome/browser/resources/md_bookmarks/bookmarks.html
+++ b/chrome/browser/resources/md_bookmarks/bookmarks.html
@@ -1,12 +1,14 @@
 <!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}" $i18n{dark}>
+<html dir="$i18n{textdirection}" lang="$i18n{language}" class="loading"
+    $i18n{dark}>
 <head>
   <meta charset="utf8">
   <title>$i18n{title}</title>
-  <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
   <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
   <style>
     html {
+      /* Reconcile with cr_toolbar.html and shared_vars_css.html */
+      --toolbar-height: 56px;
       /* Remove 300ms delay for 'click' event, when using touch interface. */
       touch-action: manipulation;
     }
@@ -18,11 +20,21 @@
       margin: 0;
       overflow: hidden;
     }
+
+    html:not([dark]).loading {
+      border-top: var(--toolbar-height) solid var(--md-toolbar-color);
+    }
+
+    html[dark].loading {
+      border-top: 1px solid var(--md-toolbar-border-color);
+      margin-top: var(--toolbar-height);
+    }
   </style>
 </head>
 <body>
   <bookmarks-app></bookmarks-app>
 
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
   <script src="chrome://resources/js/load_time_data.js"></script>
   <script src="strings.js"></script>
   <link rel="import" href="app.html">
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.js b/chrome/browser/resources/md_bookmarks/command_manager.js
index a9e4ede..081c94e 100644
--- a/chrome/browser/resources/md_bookmarks/command_manager.js
+++ b/chrome/browser/resources/md_bookmarks/command_manager.js
@@ -82,6 +82,8 @@
       this.addShortcut_(Command.COPY, 'Ctrl|c', 'Meta|c');
       this.addShortcut_(Command.PASTE, 'Ctrl|v', 'Meta|v');
 
+      this.addShortcut_(Command.FIND, 'Ctrl|f', 'Meta|f');
+
       /** @private {!Map<string, Function>} */
       this.boundListeners_ = new Map();
 
@@ -187,6 +189,7 @@
           return this.globalCanEdit_;
         case Command.SELECT_ALL:
         case Command.DESELECT_ALL:
+        case Command.FIND:
           return true;
         case Command.COPY:
           return itemIds.size > 0;
@@ -410,6 +413,9 @@
         case Command.HELP_CENTER:
           window.open('https://support.google.com/chrome/?p=bookmarks');
           break;
+        case Command.FIND:
+          this.fire('select-toolbar-search');
+          break;
         default:
           assert(false);
       }
diff --git a/chrome/browser/resources/md_bookmarks/constants.js b/chrome/browser/resources/md_bookmarks/constants.js
index 87f3d5e..8b723f87 100644
--- a/chrome/browser/resources/md_bookmarks/constants.js
+++ b/chrome/browser/resources/md_bookmarks/constants.js
@@ -46,8 +46,10 @@
   EXPORT: 19,
   HELP_CENTER: 20,
 
+  FIND: 21,
+
   // Append new values to the end of the enum.
-  MAX_VALUE: 21,
+  MAX_VALUE: 22,
 };
 
 /**
diff --git a/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html b/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html
index 7255fab..142c7dd7 100644
--- a/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html
+++ b/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html
@@ -35,12 +35,12 @@
         margin-inline-start: var(--cr-section-indent-width);
       }
     </style>
-    <div id="section-heading">$i18n{hostPermissionsHeading}</div>
+    <div id="section-heading">$i18n{hostPermissionsDescription}</div>
     <div class="toggle-section">
       <extensions-toggle-row checked="[[allowedOnAllHosts_(permissions.*)]]"
           id="allHostsToggle"
           on-change="onAllHostsToggleChanged_">
-        <span>$i18n{itemAllowOnAllSites}</span>
+        <span>$i18n{itemAllowOnFollowingSites}</span>
       </extensions-toggle-row>
     </div>
     <template is="dom-repeat" items="[[getSortedHosts_(permissions.*)]]">
diff --git a/chrome/browser/resources/md_history/history.html b/chrome/browser/resources/md_history/history.html
index a11ec825..0905748 100644
--- a/chrome/browser/resources/md_history/history.html
+++ b/chrome/browser/resources/md_history/history.html
@@ -4,7 +4,6 @@
   <meta charset="utf8">
   <title>$i18n{title}</title>
 
-  <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
   <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
 
   <style>
@@ -25,7 +24,10 @@
       cursor: default;
     }
 
-    /* Minimal styling required to display app shim. */
+    /* Minimal styling required to display app shim. TODO(dbeam): do we really
+     * need all this HTML/CSS just to show "History"? Other pages just show 56px
+     * of [blue] border on top without text and this seems fine (maybe even
+     * desired when the hamburger menu shifts the text on narrow screens. */
     .loading history-app {
       visibility: hidden;
     }
@@ -59,6 +61,10 @@
       padding-inline-start: 24px;
     }
 
+    html[dark] #loading-toolbar {
+      border-bottom: 1px solid var(--md-toolbar-border-color);
+    }
+
     #loading-message {
       align-items: center;
       color: var(--md-loading-message-color);
@@ -92,6 +98,7 @@
   <command id="select-all-command" shortcut="Ctrl|a">
 </if>
 
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
   <link rel="import" href="chrome://resources/html/util.html">
   <link rel="import" href="chrome://resources/html/load_time_data.html">
   <link rel="import" href="constants.html">
diff --git a/chrome/browser/resources/welcome/dice_welcome/welcome.html b/chrome/browser/resources/welcome/dice_welcome/welcome.html
index f62bf68..03f237ae 100644
--- a/chrome/browser/resources/welcome/dice_welcome/welcome.html
+++ b/chrome/browser/resources/welcome/dice_welcome/welcome.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
   <head>
     <meta charset="utf-8">
     <title>$i18n{headerText}</title>
diff --git a/chrome/browser/resources/welcome/welcome.html b/chrome/browser/resources/welcome/welcome.html
index 21edb26..9840052 100644
--- a/chrome/browser/resources/welcome/welcome.html
+++ b/chrome/browser/resources/welcome/welcome.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
 <head>
   <meta charset="utf-8">
   <title>$i18n{headerText}</title>
diff --git a/chrome/browser/resources/welcome/welcome_win10.html b/chrome/browser/resources/welcome/welcome_win10.html
index f021f1ac..8b7f82a 100644
--- a/chrome/browser/resources/welcome/welcome_win10.html
+++ b/chrome/browser/resources/welcome/welcome_win10.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
 <head>
   <meta charset="utf-8">
   <title>$i18n{headerText}</title>
diff --git a/chrome/browser/secure_origin_whitelist_browsertest.cc b/chrome/browser/secure_origin_whitelist_browsertest.cc
index dcf24e1..8d06a06 100644
--- a/chrome/browser/secure_origin_whitelist_browsertest.cc
+++ b/chrome/browser/secure_origin_whitelist_browsertest.cc
@@ -166,7 +166,7 @@
 }
 
 // Tests that whitelisted insecure origins are correctly set as security level
-// NONE instead of the default level DANGEROUS.
+// NONE instead of the default level HTTPS_SHOW_WARNING.
 IN_PROC_BROWSER_TEST_P(SecureOriginWhitelistBrowsertest, SecurityIndicators) {
   ui_test_utils::NavigateToURL(
       browser(),
@@ -180,7 +180,7 @@
 
   if (GetParam() == TestVariant::kPolicyOldAndNew) {
     // When both policies are set, the new policy overrides the old policy.
-    EXPECT_EQ(security_state::DANGEROUS, security_info.security_level);
+    EXPECT_EQ(security_state::HTTP_SHOW_WARNING, security_info.security_level);
     ui_test_utils::NavigateToURL(
         browser(),
         embedded_test_server()->GetURL(
@@ -189,7 +189,7 @@
     EXPECT_EQ(security_state::NONE, security_info.security_level);
   } else {
     EXPECT_EQ(ExpectSecureContext() ? security_state::NONE
-                                    : security_state::DANGEROUS,
+                                    : security_state::HTTP_SHOW_WARNING,
               security_info.security_level);
   }
 }
diff --git a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
index fdf7a0f..b13d4f9 100644
--- a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
@@ -522,7 +522,7 @@
     ASSERT_TRUE(entry);
 
     EXPECT_EQ(use_secure_inner_origin ? security_state::NONE
-                                      : security_state::DANGEROUS,
+                                      : security_state::HTTP_SHOW_WARNING,
               security_info.security_level);
   }
 
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index bf94fd0..bea1d134b 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -1156,9 +1156,18 @@
   EXPECT_NE(nullptr, GetPaymentsCustomerData(profile_data).get());
 }
 
+#if defined(THREAD_SANITIZER)
+// Web Database thread and history DB thread access sqlite concurrently,
+// https://crbug.com/917380
+#define MAYBE_SwitchesFromAccountToProfileStorageOnSyncOptInWithAdvancedSetup \
+  DISABLED_SwitchesFromAccountToProfileStorageOnSyncOptInWithAdvancedSetup
+#else
+#define MAYBE_SwitchesFromAccountToProfileStorageOnSyncOptInWithAdvancedSetup \
+  SwitchesFromAccountToProfileStorageOnSyncOptInWithAdvancedSetup
+#endif
 IN_PROC_BROWSER_TEST_F(
     SingleClientWalletSecondaryAccountSyncTest,
-    SwitchesFromAccountToProfileStorageOnSyncOptInWithAdvancedSetup) {
+    MAYBE_SwitchesFromAccountToProfileStorageOnSyncOptInWithAdvancedSetup) {
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
   GetPersonalDataManager(0)->OnSyncServiceInitialized(GetSyncService(0));
 
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
index 9927f91..c25d146 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
@@ -552,8 +552,6 @@
       "ExtensionToolbarModel.BrowserActionsPermanentlyHidden", hidden);
   UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsCount",
                            browser_actions_count);
-  UMA_HISTOGRAM_COUNTS_100("Toolbar.ActionsModel.ComponentActionsCount",
-                           component_actions_count);
   UMA_HISTOGRAM_COUNTS_100("Toolbar.ActionsModel.OverallActionsCount",
                            toolbar_items_.size());
 
diff --git a/chrome/browser/ui/webui/app_management/app_management_ui.cc b/chrome/browser/ui/webui/app_management/app_management_ui.cc
index a72a2661..8ee5416 100644
--- a/chrome/browser/ui/webui/app_management/app_management_ui.cc
+++ b/chrome/browser/ui/webui/app_management/app_management_ui.cc
@@ -31,6 +31,8 @@
   source->AddLocalizedString("back", IDS_APP_MANAGEMENT_BACK);
   source->AddLocalizedString("lessApps", IDS_APP_MANAGEMENT_LESS_APPS);
   source->AddLocalizedString("moreApps", IDS_APP_MANAGEMENT_MORE_APPS);
+  source->AddLocalizedString("notificationSublabel",
+                             IDS_APP_MANAGEMENT_NOTIFICATIONS_SUBLABEL);
   source->AddLocalizedString("notifications", IDS_APP_MANAGEMENT_NOTIFICATIONS);
   source->AddLocalizedString("openSiteSettings",
                              IDS_APP_MANAGEMENT_SITE_SETTING);
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index d144d00c..bba349a 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -159,6 +159,8 @@
     {"openChromeWebStore", IDS_MD_EXTENSIONS_SIDEBAR_OPEN_CHROME_WEB_STORE},
     {"keyboardShortcuts", IDS_MD_EXTENSIONS_SIDEBAR_KEYBOARD_SHORTCUTS},
     {"incognitoInfoWarning", IDS_EXTENSIONS_INCOGNITO_WARNING},
+    {"hostPermissionsDescription",
+     IDS_MD_EXTENSIONS_HOST_PERMISSIONS_DESCRIPTION},
     {"hostPermissionsEdit", IDS_MD_EXTENSIONS_HOST_PERMISSIONS_EDIT},
     {"hostPermissionsHeading", IDS_MD_EXTENSIONS_ITEM_HOST_PERMISSIONS_HEADING},
     {"hostAccessOnClick", IDS_MD_EXTENSIONS_HOST_ACCESS_ON_CLICK},
@@ -212,6 +214,7 @@
     {"itemSize", IDS_DIRECTORY_LISTING_SIZE},
     {"itemAllowOnFileUrls", IDS_EXTENSIONS_ALLOW_FILE_ACCESS},
     {"itemAllowOnAllSites", IDS_EXTENSIONS_ALLOW_ON_ALL_URLS},
+    {"itemAllowOnFollowingSites", IDS_EXTENSIONS_ALLOW_ON_FOLLOWING_SITES},
     {"itemCollectErrors", IDS_EXTENSIONS_ENABLE_ERROR_COLLECTION},
     {"itemCorruptInstall", IDS_EXTENSIONS_CORRUPTED_EXTENSION},
     {"itemRepair", IDS_EXTENSIONS_REPAIR_CORRUPTED},
diff --git a/chrome/common/extensions/docs/README b/chrome/common/extensions/docs/README
index 385193c23..66b785b7 100644
--- a/chrome/common/extensions/docs/README
+++ b/chrome/common/extensions/docs/README
@@ -62,12 +62,7 @@
 
   3. Check your work at http://localhost:8000/(apps|extensions)/<doc_name>
 
-  4. Upload patch and offer reviewers a preview link at a URL with your patch
-     number and files, similar to:
-     https://chrome-apps-doc.appspot.com/_patch/12345678/apps/index.html
-     https://chrome-apps-doc.appspot.com/_patch/12345678/extensions/index.html
-
-  5. Commit files as with any other Chrome change. The live server will update
+  4. Commit files as with any other Chrome change. The live server will update
      within 5-10 minutes.
 
 
diff --git a/chrome/common/extensions/docs/templates/articles/content_scripts.html b/chrome/common/extensions/docs/templates/articles/content_scripts.html
index 90418bf..f72968f 100644
--- a/chrome/common/extensions/docs/templates/articles/content_scripts.html
+++ b/chrome/common/extensions/docs/templates/articles/content_scripts.html
@@ -262,6 +262,20 @@
      These are injected in the order they appear in this array.
    </td>
  </tr>
+ <tr id="match_about_blank">
+   <td>
+     <code>match_about_blank</code>
+   </td>
+   <td>
+     boolean
+   </td>
+   <td>
+     <em>Optional.</em>
+     Whether the script should inject into an <code>about:blank</code> frame
+     where the parent or opener frame matches one of the patterns declared in
+     <code>matches</code>. Defaults to false.
+   </td>
+ </tr>
 </table>
 
 <h4 id="matchAndGlob">Exclude Matches and Globs</h4>
diff --git a/chrome/credential_provider/gaiacp/BUILD.gn b/chrome/credential_provider/gaiacp/BUILD.gn
index 085f7af8..5cb651a 100644
--- a/chrome/credential_provider/gaiacp/BUILD.gn
+++ b/chrome/credential_provider/gaiacp/BUILD.gn
@@ -34,6 +34,7 @@
   deps = [
     ":string_resources",
     "//base:base",
+    "//chrome/common:version_header",
     "//components/crash/core/common",
     "//components/version_info",
     "//google_apis:google_apis",
diff --git a/chrome/renderer/autofill/password_generation_agent_browsertest.cc b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
index df9af505..d642bc1 100644
--- a/chrome/renderer/autofill/password_generation_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
@@ -1291,4 +1291,40 @@
   EXPECT_FALSE(input.ShouldRevealPassword());
 }
 
+TEST_F(PasswordGenerationAgentTest, GenerationAvailableByRendererIds) {
+  LoadHTMLWithUserGesture(kMultipleAccountCreationFormHTML);
+
+  constexpr const char* kPasswordElementsIds[] = {"password", "first_password",
+                                                  "second_password"};
+
+  WebDocument document = GetMainFrame()->GetDocument();
+  std::vector<WebInputElement> password_elements;
+  for (const char* id : kPasswordElementsIds) {
+    WebElement element = document.GetElementById(WebString::FromUTF8(id));
+    WebInputElement* input = ToWebInputElement(&element);
+    ASSERT_TRUE(input);
+    password_elements.push_back(*input);
+  }
+
+  // Simulate that the browser informs about eligible for generation form.
+  // Check that generation is available only on new password field of this form.
+  NewPasswordFormGenerationData generation_data = {
+      .new_password_renderer_id =
+          password_elements[0].UniqueRendererFormControlId()};
+
+  password_generation_->FoundFormEligibleForGeneration(generation_data);
+  ExpectAutomaticGenerationAvailable(kPasswordElementsIds[0], true);
+  ExpectAutomaticGenerationAvailable(kPasswordElementsIds[1], false);
+  ExpectAutomaticGenerationAvailable(kPasswordElementsIds[2], false);
+
+  // Simulate that the browser informs about the second eligible for generation
+  // form. Check that generation is available on both forms.
+  generation_data.new_password_renderer_id =
+      password_elements[2].UniqueRendererFormControlId();
+  password_generation_->FoundFormEligibleForGeneration(generation_data);
+  ExpectAutomaticGenerationAvailable(kPasswordElementsIds[0], true);
+  ExpectAutomaticGenerationAvailable(kPasswordElementsIds[1], false);
+  ExpectAutomaticGenerationAvailable(kPasswordElementsIds[2], true);
+}
+
 }  // namespace autofill
diff --git a/chrome/renderer/pepper/pepper_flash_renderer_host.cc b/chrome/renderer/pepper/pepper_flash_renderer_host.cc
index caae499c..05aadc17 100644
--- a/chrome/renderer/pepper/pepper_flash_renderer_host.cc
+++ b/chrome/renderer/pepper/pepper_flash_renderer_host.cc
@@ -34,6 +34,7 @@
 #include "third_party/skia/include/core/SkMatrix.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkPoint.h"
+#include "third_party/skia/include/core/SkTextBlob.h"
 #include "third_party/skia/include/core/SkTypeface.h"
 #include "ui/gfx/geometry/rect.h"
 #include "url/gurl.h"
@@ -256,14 +257,12 @@
 
   SkPaint paint;
   paint.setColor(params.color);
-  paint.setTextEncoding(kGlyphID_SkTextEncoding);
-  paint.setAntiAlias(true);
+
+  SkFont font(std::move(typeface), SkIntToScalar(params.font_desc.size));
   paint.setHinting(SkFontHinting::kFull);
-  paint.setTextSize(SkIntToScalar(params.font_desc.size));
-  paint.setTypeface(std::move(typeface));
   if (params.allow_subpixel_aa) {
-    paint.setSubpixelText(true);
-    paint.setLCDRenderText(true);
+    font.setSubpixel(true);
+    font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
   }
 
   SkScalar x = SkIntToScalar(params.position.x);
@@ -272,15 +271,16 @@
   // Build up the skia advances.
   size_t glyph_count = params.glyph_indices.size();
   if (glyph_count) {
-    std::vector<SkPoint> sk_positions(glyph_count);
+    SkTextBlobBuilder builder;
+    auto rec = builder.allocRunPos(font, glyph_count);
+    memcpy(rec.glyphs, &params.glyph_indices[0], glyph_count * 2);
+    SkPoint* pos = reinterpret_cast<SkPoint*>(rec.pos);
     for (uint32_t i = 0; i < glyph_count; i++) {
-      sk_positions[i].set(x, y);
+      pos[i].set(x, y);
       x += SkFloatToScalar(params.glyph_advances[i].x);
       y += SkFloatToScalar(params.glyph_advances[i].y);
     }
-
-    canvas->drawPosText(
-        &params.glyph_indices[0], glyph_count * 2, &sk_positions[0], paint);
+    canvas->drawTextBlob(builder.make(), 0, 0, paint);
   }
 
   if (needs_unmapping)
diff --git a/chrome/test/chromedriver/server/chromedriver_server.cc b/chrome/test/chromedriver/server/chromedriver_server.cc
index 30f0f72..31e73ff3 100644
--- a/chrome/test/chromedriver/server/chromedriver_server.cc
+++ b/chrome/test/chromedriver/server/chromedriver_server.cc
@@ -34,6 +34,7 @@
 #include "base/threading/thread_local.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "chrome/test/chromedriver/chrome/version.h"
 #include "chrome/test/chromedriver/logging.h"
 #include "chrome/test/chromedriver/server/http_handler.h"
 #include "chrome/test/chromedriver/version.h"
@@ -375,6 +376,8 @@
         "whitelisted-ips",
         "comma-separated whitelist of remote IP addresses "
         "which are allowed to connect to ChromeDriver",
+        "minimum-chrome-version",
+        "minimum supported Chrome version",
     };
     for (size_t i = 0; i < base::size(kOptionAndDescriptions) - 1; i += 2) {
       options += base::StringPrintf(
@@ -462,6 +465,12 @@
     return 1;
   }
 
+  if (cmd_line->HasSwitch("minimum-chrome-version")) {
+    printf("minimum supported Chrome version: %s\n",
+           GetMinimumSupportedChromeVersion().c_str());
+    return 0;
+  }
+
   mojo::core::Init();
 
   base::TaskScheduler::CreateAndStartWithDefaultParams("ChromeDriver");
diff --git a/chrome/test/data/webui/md_bookmarks/app_test.js b/chrome/test/data/webui/md_bookmarks/app_test.js
index 84562f0..4c307cac 100644
--- a/chrome/test/data/webui/md_bookmarks/app_test.js
+++ b/chrome/test/data/webui/md_bookmarks/app_test.js
@@ -89,4 +89,12 @@
     MockInteractions.keyDownOn(item, 40, [], 'ArrowDown');
     assertEquals(null, getFocusAttribute());
   });
+
+  test('when select-toolbar-search is fired, focus on search input', () => {
+    const searchInput =
+        app.$$('bookmarks-toolbar').searchField.getSearchInput();
+    assertNotEquals(searchInput, getDeepActiveElement());
+    app.dispatchEvent(new Event('select-toolbar-search'));
+    assertEquals(searchInput, getDeepActiveElement());
+  });
 });
diff --git a/chrome/test/data/webui/md_bookmarks/command_manager_test.js b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
index b2a1f4c..f4df6a3e 100644
--- a/chrome/test/data/webui/md_bookmarks/command_manager_test.js
+++ b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
@@ -441,6 +441,12 @@
     store.dispatch(bookmarks.actions.createBookmark(item2.id, item2));
     assertTrue(commandManager.canExecute(Command.SORT, new Set()));
   });
+
+  test('find shortcut invokes FIND command', () => {
+    const modifier = cr.isMac ? 'meta' : 'ctrl';
+    MockInteractions.pressAndReleaseKeyOn(document.body, '', modifier, 'f');
+    commandManager.assertLastCommand(Command.FIND, []);
+  });
 });
 
 suite('<bookmarks-item> CommandManager integration', function() {
@@ -672,6 +678,13 @@
     assertEquals(action.anchor, displayedIdsAfter[2]);
   });
 
+  test('FIND fires select-toolbar-search event', () => {
+    const wait =
+        test_util.eventToPromise('select-toolbar-search', commandManager);
+    commandManager.handle(Command.FIND, new Set());
+    return wait;
+  });
+
   suiteTeardown(function(done) {
     chrome.bookmarks.removeTree(testFolderId, () => done());
   });
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
index c6434b7..08b0b97 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
@@ -54,6 +54,7 @@
 
   extraLibraries: MaterialBookmarksBrowserTest.prototype.extraLibraries.concat([
     'app_test.js',
+    ROOT_PATH + 'ui/webui/resources/js/util.js',
   ]),
 };
 
@@ -67,6 +68,7 @@
   __proto__: MaterialBookmarksBrowserTest.prototype,
 
   extraLibraries: MaterialBookmarksBrowserTest.prototype.extraLibraries.concat([
+    '../settings/test_util.js',
     'command_manager_test.js',
   ]),
 };
diff --git a/chromeos/chromeos_features.cc b/chromeos/chromeos_features.cc
index e0b55d74..1ce59965 100644
--- a/chromeos/chromeos_features.cc
+++ b/chromeos/chromeos_features.cc
@@ -12,10 +12,6 @@
 const base::Feature kAndroidMessagesIntegration{
     "AndroidMessagesIntegration", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Point to the production Android Messages URL instead of sandbox.
-const base::Feature kAndroidMessagesProdEndpoint{
-    "AndroidMessagesProdEndpoint", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables or disables auto screen-brightness adjustment when ambient light
 // changes.
 const base::Feature kAutoScreenBrightness{"AutoScreenBrightness",
@@ -88,6 +84,11 @@
 const base::Feature kUserActivityPrediction{"UserActivityPrediction",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables or disables ML service inferencing (instead of TFNative inferencing)
+// for the Smart Dim feature on Chrome OS.
+const base::Feature kUserActivityPredictionMlService{
+    "UserActivityPredictionMlService", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 
 }  // namespace chromeos
diff --git a/chromeos/chromeos_features.h b/chromeos/chromeos_features.h
index 0f8506a..ccede4c 100644
--- a/chromeos/chromeos_features.h
+++ b/chromeos/chromeos_features.h
@@ -16,7 +16,6 @@
 // alongside the definition of their values in the .cc file.
 
 CHROMEOS_EXPORT extern const base::Feature kAndroidMessagesIntegration;
-CHROMEOS_EXPORT extern const base::Feature kAndroidMessagesProdEndpoint;
 CHROMEOS_EXPORT extern const base::Feature kAutoScreenBrightness;
 CHROMEOS_EXPORT extern const base::Feature
     kAutoScreenBrightnessContinuedAdjustment;
@@ -33,6 +32,7 @@
 CHROMEOS_EXPORT extern const base::Feature kVideoPlayerNativeControls;
 CHROMEOS_EXPORT extern const base::Feature kUseMessagesGoogleComDomain;
 CHROMEOS_EXPORT extern const base::Feature kUserActivityPrediction;
+CHROMEOS_EXPORT extern const base::Feature kUserActivityPredictionMlService;
 
 }  // namespace features
 
diff --git a/chromeos/services/machine_learning/public/mojom/model.mojom b/chromeos/services/machine_learning/public/mojom/model.mojom
index 959ace7..4b533227 100644
--- a/chromeos/services/machine_learning/public/mojom/model.mojom
+++ b/chromeos/services/machine_learning/public/mojom/model.mojom
@@ -16,6 +16,7 @@
 enum ModelId {
   UNKNOWN,
   TEST_MODEL,  // Only available in tests.
+  SMART_DIM,
 };
 
 enum CreateGraphExecutorResult {
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 1e2ec97..971072d2 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -2072,6 +2072,23 @@
   return WebFormElement();
 }
 
+WebFormControlElement FindFormControlElementsByUniqueRendererId(
+    WebDocument doc,
+    uint32_t form_control_renderer_id) {
+  WebElementCollection elements = doc.All();
+
+  for (WebElement element = elements.FirstItem(); !element.IsNull();
+       element = elements.NextItem()) {
+    if (!element.IsFormControlElement())
+      continue;
+    WebFormControlElement control = element.To<WebFormControlElement>();
+    if (form_control_renderer_id == control.UniqueRendererFormControlId())
+      return control;
+  }
+
+  return WebFormControlElement();
+}
+
 std::vector<WebFormControlElement> FindFormControlElementsByUniqueRendererId(
     WebDocument doc,
     const std::vector<uint32_t>& form_control_renderer_ids) {
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h
index 1770086..b439c3b 100644
--- a/components/autofill/content/renderer/form_autofill_util.h
+++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -286,6 +286,12 @@
 blink::WebFormElement FindFormByUniqueRendererId(blink::WebDocument doc,
                                                  uint32_t form_renderer_id);
 
+// Returns form control element by unique renderer id. Return null element if
+// there is no element with given renderer id.
+blink::WebFormControlElement FindFormControlElementsByUniqueRendererId(
+    blink::WebDocument doc,
+    uint32_t form_control_renderer_id);
+
 // Note: The vector-based API of the following two functions is a tax for limiting
 // the frequency and duration of retrieving a lot of DOM elements. Alternative
 // solutions have been discussed on https://crrev.com/c/1108201.
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index cb6d671..a05e245 100644
--- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -424,6 +424,23 @@
           .IsNull());
 }
 
+TEST_F(FormAutofillUtilsTest, FindFormControlByUniqueId) {
+  LoadHTML(
+      "<body><form id='form1'><input id='i1'></form><input id='i2'></body>");
+  WebDocument doc = GetMainFrame()->GetDocument();
+  auto input1 = doc.GetElementById("i1").To<WebInputElement>();
+  auto input2 = doc.GetElementById("i2").To<WebInputElement>();
+  uint32_t non_existing_id = input2.UniqueRendererFormControlId() + 1000;
+  using autofill::form_util::FindFormControlElementsByUniqueRendererId;
+
+  EXPECT_EQ(input1, FindFormControlElementsByUniqueRendererId(
+                        doc, input1.UniqueRendererFormControlId()));
+  EXPECT_EQ(input2, FindFormControlElementsByUniqueRendererId(
+                        doc, input2.UniqueRendererFormControlId()));
+  EXPECT_TRUE(
+      FindFormControlElementsByUniqueRendererId(doc, non_existing_id).IsNull());
+}
+
 TEST_F(FormAutofillUtilsTest, FindFormControlElementsByUniqueIdNoForm) {
   LoadHTML("<body><input id='i1'><input id='i2'><input id='i3'></body>");
   WebDocument doc = GetMainFrame()->GetDocument();
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index c36c1e5..2a8faea 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -308,6 +308,7 @@
   automatic_generation_element_.Reset();
   current_generation_item_.reset();
   last_focused_password_element_.Reset();
+  generation_enabled_fields_.clear();
 }
 
 void PasswordGenerationAgent::DidFinishDocumentLoad() {
@@ -488,7 +489,7 @@
 
 void PasswordGenerationAgent::FoundFormEligibleForGeneration(
     const NewPasswordFormGenerationData& form) {
-  // TODO(https://crbug.com/866444): Implement processing |form|.
+  generation_enabled_fields_[form.new_password_renderer_id] = form;
 }
 
 void PasswordGenerationAgent::UserTriggeredGeneratePassword() {
@@ -649,7 +650,12 @@
   if (element && element->IsPasswordFieldForAutofill())
     last_focused_password_element_ = *element;
 
-  if (!element || !current_generation_item_ ||
+  if (!element)
+    return false;
+
+  MaybeCreateCurrentGenerationItem(*element);
+
+  if (!current_generation_item_ ||
       *element != current_generation_item_->generation_element_) {
     return false;
   }
@@ -821,6 +827,42 @@
     GetPasswordManagerClient()->PasswordNoLongerGenerated(*presaved_form);
 }
 
+void PasswordGenerationAgent::MaybeCreateCurrentGenerationItem(
+    const WebInputElement& element) {
+  // Do not create |current_generation_item_| if it already is created for
+  // |element| or the user accepted generated password. So if the user accepted
+  // the generated password, generation is not offered on any other field.
+  if (current_generation_item_ &&
+      (current_generation_item_->generation_element_ == element ||
+       current_generation_item_->password_is_generated_))
+    return;
+
+  auto it =
+      generation_enabled_fields_.find(element.UniqueRendererFormControlId());
+  if (it == generation_enabled_fields_.end())
+    return;
+
+  std::unique_ptr<PasswordForm> password_form =
+      element.Form().IsNull()
+          ? password_agent_->GetPasswordFormFromUnownedInputElements()
+          : password_agent_->GetPasswordFormFromWebForm(element.Form());
+
+  std::vector<blink::WebInputElement> passwords = {element};
+
+  WebFormControlElement confirmation_password =
+      form_util::FindFormControlElementsByUniqueRendererId(
+          element.GetDocument(), it->second.confirmation_password_renderer_id);
+
+  if (!confirmation_password.IsNull()) {
+    WebInputElement* input = ToWebInputElement(&confirmation_password);
+    if (input)
+      passwords.push_back(*input);
+  }
+
+  current_generation_item_.reset(new GenerationItemInfo(
+      element, std::move(*password_form), std::move(passwords)));
+}
+
 const mojom::PasswordManagerDriverAssociatedPtr&
 PasswordGenerationAgent::GetPasswordManagerDriver() {
   DCHECK(password_agent_);
diff --git a/components/autofill/content/renderer/password_generation_agent.h b/components/autofill/content/renderer/password_generation_agent.h
index 201f5de..0f5a17ddd 100644
--- a/components/autofill/content/renderer/password_generation_agent.h
+++ b/components/autofill/content/renderer/password_generation_agent.h
@@ -156,6 +156,11 @@
   // Stops treating a password as generated.
   void PasswordNoLongerGenerated();
 
+  // Creates |current_generation_item_| for |element| if |element| is a
+  // generation enabled element. If |current_generation_item_| is already
+  // created for |element| it is not recreated.
+  void MaybeCreateCurrentGenerationItem(const blink::WebInputElement& element);
+
   // Runs HTML parsing based classifier and saves its outcome to proto.
   // TODO(crbug.com/621442): Remove client-side form classifier when server-side
   // classifier is ready.
@@ -202,6 +207,10 @@
   // the last focused password element.
   blink::WebInputElement last_focused_password_element_;
 
+  // Contains correspondence between generaiton enabled element and data for
+  // generation.
+  std::map<uint32_t, NewPasswordFormGenerationData> generation_enabled_fields_;
+
   // If this feature is enabled. Controlled by Finch.
   bool enabled_;
 
diff --git a/components/autofill/core/common/password_form_generation_data.h b/components/autofill/core/common/password_form_generation_data.h
index 9b221c9..ffbc3ed 100644
--- a/components/autofill/core/common/password_form_generation_data.h
+++ b/components/autofill/core/common/password_form_generation_data.h
@@ -42,8 +42,10 @@
 // TODO(https://crbug.com/866444): Remove old PasswordFormGenerationData and
 // rename to PasswordFormGenerationData when the old parser is gone.
 struct NewPasswordFormGenerationData {
-  uint32_t new_password_renderer_id;
-  uint32_t confirmation_password_renderer_id;
+  uint32_t new_password_renderer_id =
+      FormFieldData::kNotSetFormControlRendererId;
+  uint32_t confirmation_password_renderer_id =
+      FormFieldData::kNotSetFormControlRendererId;
 };
 
 }  // namespace autofill
diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc
index 06768aa2..539fb562 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -74,11 +74,10 @@
 
 void ContentPasswordManagerDriver::AllowPasswordGenerationForForm(
     const autofill::PasswordForm& form) {
-  if (!GetPasswordGenerationManager()->IsGenerationEnabled(
+  if (GetPasswordGenerationManager()->IsGenerationEnabled(
           /*log_debug_data=*/true)) {
-    return;
+    GetPasswordGenerationAgent()->FormNotBlacklisted(form);
   }
-  GetPasswordGenerationAgent()->FormNotBlacklisted(form);
 }
 
 void ContentPasswordManagerDriver::FormsEligibleForGenerationFound(
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc
index ca6cd9f..8448399 100644
--- a/components/password_manager/core/browser/new_password_form_manager.cc
+++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -588,7 +588,7 @@
   if (!driver_)
     return;
 
-  if (!IsBlacklisted() && observed_password_form->is_new_password_reliable) {
+  if (observed_password_form->is_new_password_reliable && !IsBlacklisted()) {
     driver_->FormEligibleForGenerationFound(
         {.new_password_renderer_id =
              observed_password_form->new_password_element_renderer_id,
diff --git a/components/password_manager/core/browser/password_form_filling.cc b/components/password_manager/core/browser/password_form_filling.cc
index 069c08fc..3a1ac5e 100644
--- a/components/password_manager/core/browser/password_form_filling.cc
+++ b/components/password_manager/core/browser/password_form_filling.cc
@@ -115,7 +115,12 @@
   DCHECK(driver);
   DCHECK_EQ(PasswordForm::SCHEME_HTML, observed_form.scheme);
 
-  if (!is_blacklisted)
+  const bool new_parsing_enabled =
+      base::FeatureList::IsEnabled(features::kNewPasswordFormParsing);
+
+  // No need to inform the renderer about form blacklisting.
+  // NewPasswordFormManager sends all needed information to the renderer.
+  if (!new_parsing_enabled && !is_blacklisted)
     driver->AllowPasswordGenerationForForm(observed_form);
 
   if (best_matches.empty()) {
@@ -136,8 +141,7 @@
   // password field ID, then PasswordAutofillAgent has no way to fill the
   // password anywhere.
   const bool form_good_for_filling =
-      base::FeatureList::IsEnabled(features::kNewPasswordFormParsing) ||
-      !observed_form.IsPossibleChangePasswordForm();
+      new_parsing_enabled || !observed_form.IsPossibleChangePasswordForm();
 
   // Wait for the username before filling passwords in case the
   // fill-on-account-select-http feature is active and the main frame is
diff --git a/components/password_manager/core/browser/password_form_filling_unittest.cc b/components/password_manager/core/browser/password_form_filling_unittest.cc
index 72bdf6e..c102e9e5 100644
--- a/components/password_manager/core/browser/password_form_filling_unittest.cc
+++ b/components/password_manager/core/browser/password_form_filling_unittest.cc
@@ -186,7 +186,6 @@
     if (!test_case.current_password_present)
       observed_form.password_element.clear();
 
-    EXPECT_CALL(driver_, AllowPasswordGenerationForForm(observed_form));
     PasswordFormFillData fill_data;
     EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
     EXPECT_CALL(client_, PasswordWasAutofilled(_, _, _));
@@ -198,7 +197,6 @@
     // In all cases, fill on load should not be prevented. If there is no
     // current-password field, the renderer will not fill anyway.
     EXPECT_EQ(LikelyFormFilling::kFillOnPageLoad, likely_form_filling);
-    EXPECT_FALSE(fill_data.wait_for_username);
   }
 }
 
diff --git a/components/password_manager/core/browser/password_generation_manager.cc b/components/password_manager/core/browser/password_generation_manager.cc
index 9cf9f91..78517f1a 100644
--- a/components/password_manager/core/browser/password_generation_manager.cc
+++ b/components/password_manager/core/browser/password_generation_manager.cc
@@ -17,6 +17,7 @@
 #include "components/password_manager/core/browser/password_manager_driver.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/browser/password_requirements_service.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 
 using autofill::AutofillField;
 using autofill::FieldSignature;
@@ -83,6 +84,10 @@
 
 void PasswordGenerationManager::DetectFormsEligibleForGeneration(
     const std::vector<autofill::FormStructure*>& forms) {
+  if (base::FeatureList::IsEnabled(features::kNewPasswordFormParsing)) {
+    // NewPasswordFormManager sends this information to the renderer.
+    return;
+  }
   // IsGenerationEnabled is called multiple times and it is sufficient to
   // log debug data once. This is it!
   if (!IsGenerationEnabled(/*log_debug_data=*/true))
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index 4210ef3e..799564f0 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -555,17 +555,12 @@
 }
 
 void PaymentRequest::CanMakePaymentCallback(bool can_make_payment) {
-  if (!spec_ || CanMakePaymentQueryFactory::GetInstance()
-                    ->GetForContext(web_contents_->GetBrowserContext())
-                    ->CanQuery(top_level_origin_, frame_origin_,
-                               spec_->stringified_method_data())) {
-    RespondToCanMakePaymentQuery(can_make_payment, false);
-  } else if (OriginSecurityChecker::IsOriginLocalhostOrFile(frame_origin_)) {
-    RespondToCanMakePaymentQuery(can_make_payment, true);
-  } else {
-    client_->OnCanMakePayment(
-        mojom::CanMakePaymentQueryResult::QUERY_QUOTA_EXCEEDED);
-  }
+  client_->OnCanMakePayment(
+      can_make_payment ? mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT
+                       : mojom::CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT);
+
+  // TODO(https://crbug.com/915907): emit JourneyLogger event once the event
+  // names are updated.
 
   if (observer_for_testing_)
     observer_for_testing_->OnCanMakePaymentReturned();
@@ -591,21 +586,6 @@
     observer_for_testing_->OnHasEnrolledInstrumentReturned();
 }
 
-void PaymentRequest::RespondToCanMakePaymentQuery(bool can_make_payment,
-                                                  bool warn_localhost_or_file) {
-  mojom::CanMakePaymentQueryResult positive =
-      warn_localhost_or_file
-          ? mojom::CanMakePaymentQueryResult::WARNING_CAN_MAKE_PAYMENT
-          : mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT;
-  mojom::CanMakePaymentQueryResult negative =
-      warn_localhost_or_file
-          ? mojom::CanMakePaymentQueryResult::WARNING_CANNOT_MAKE_PAYMENT
-          : mojom::CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT;
-
-  client_->OnCanMakePayment(can_make_payment ? positive : negative);
-  journey_logger_.SetCanMakePaymentValue(can_make_payment);
-}
-
 void PaymentRequest::RespondToHasEnrolledInstrumentQuery(
     bool has_enrolled_instrument,
     bool warn_localhost_or_file) {
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index 671b0ca..1752553 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -153,18 +153,10 @@
   // The callback for PaymentRequestState::AreRequestedMethodsSupported.
   void AreRequestedMethodsSupportedCallback(bool methods_supported);
 
-  // Sends either CAN_MAKE_PAYMENT or CANNOT_MAKE_PAYMENT to the renderer,
-  // depending on |can_make_payment| value. Never sends QUERY_QUOTA_EXCEEDED.
-  // Does not check query quota, but does check for incognito mode. If
-  // |warn_localhost_or_file| is true, then sends WARNING_CAN_MAKE_PAYMENT or
-  // WARNING_CANNOT_MAKE_PAYMENT version of the values instead.
-  void RespondToCanMakePaymentQuery(bool can_make_payment,
-                                    bool warn_localhost_or_file);
-
   // Sends either HAS_ENROLLED_INSTRUMENT or HAS_NO_ENROLLED_INSTRUMENT to the
-  // renderer, depending on |has_enrolled_instrument| value. Never sends
-  // QUERY_QUOTA_EXCEEDED. Does not check query quota, but does check for
-  // incognito mode. If |warn_localhost_or_file| is true, then sends
+  // renderer, depending on |has_enrolled_instrument| value. Does not check
+  // query quota so never sends QUERY_QUOTA_EXCEEDED. If
+  // |warn_localhost_or_file| is true, then sends
   // WARNING_HAS_ENROLLED_INSTRUMENT or WARNING_HAS_NO_ENROLLED_INSTRUMENT
   // version of the values instead.
   void RespondToHasEnrolledInstrumentQuery(bool has_enrolled_instrument,
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index dcf43b6..1d9f242 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -147,6 +147,10 @@
   are_requested_methods_supported_ |= !available_instruments_.empty();
   NotifyOnGetAllPaymentInstrumentsFinished();
 
+  // Fulfill the pending CanMakePayment call.
+  if (can_make_payment_callback_)
+    CheckCanMakePayment(std::move(can_make_payment_callback_));
+
   // Fulfill the pending HasEnrolledInstrument call.
   if (has_enrolled_instrument_callback_)
     CheckHasEnrolledInstrument(std::move(has_enrolled_instrument_callback_));
@@ -196,17 +200,26 @@
 }
 
 void PaymentRequestState::CanMakePayment(StatusCallback callback) {
-  // TODO(https://crbug.com/915907): Implement new CanMakePayment.
-  NOTREACHED();
+  if (!get_all_instruments_finished_) {
+    DCHECK(!can_make_payment_callback_);
+    can_make_payment_callback_ = std::move(callback);
+    return;
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&PaymentRequestState::CheckCanMakePayment,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void PaymentRequestState::CheckCanMakePayment(StatusCallback callback) {
-  // TODO(https://crbug.com/915907): Implement new CanMakePayment.
-  NOTREACHED();
+  DCHECK(get_all_instruments_finished_);
+  std::move(callback).Run(are_requested_methods_supported_);
 }
 
 void PaymentRequestState::HasEnrolledInstrument(StatusCallback callback) {
   if (!get_all_instruments_finished_) {
+    DCHECK(!has_enrolled_instrument_callback_);
     has_enrolled_instrument_callback_ = std::move(callback);
     return;
   }
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h
index ef77a369..8923798 100644
--- a/components/payments/content/payment_request_state.h
+++ b/components/payments/content/payment_request_state.h
@@ -292,6 +292,7 @@
   autofill::PersonalDataManager* personal_data_manager_;
   JourneyLogger* journey_logger_;
 
+  StatusCallback can_make_payment_callback_;
   StatusCallback has_enrolled_instrument_callback_;
   StatusCallback are_requested_methods_supported_callback_;
   bool are_requested_methods_supported_;
diff --git a/components/payments/content/payment_request_state_unittest.cc b/components/payments/content/payment_request_state_unittest.cc
index e39d0e29..5659ff9 100644
--- a/components/payments/content/payment_request_state_unittest.cc
+++ b/components/payments/content/payment_request_state_unittest.cc
@@ -149,9 +149,13 @@
       base::BindOnce([](bool has_enrolled_instrument) {
         EXPECT_TRUE(has_enrolled_instrument);
       }));
+
+  // CanMakePayment returns true because the requested method is supported.
+  state()->CanMakePayment(base::BindOnce(
+      [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); }));
 }
 
-TEST_F(PaymentRequestStateTest, HasEnrolledInstrument_CannotMakePayment) {
+TEST_F(PaymentRequestStateTest, CanMakePayment_NoEnrolledInstrument) {
   // The method data requires MasterCard.
   std::vector<mojom::PaymentMethodDataPtr> method_data;
   mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
@@ -167,6 +171,33 @@
       base::BindOnce([](bool has_enrolled_instrument) {
         EXPECT_FALSE(has_enrolled_instrument);
       }));
+
+  // CanMakePayment returns true because the requested method is supported, even
+  // though the payment instrument is not ready to pay.
+  state()->CanMakePayment(base::BindOnce(
+      [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); }));
+}
+
+TEST_F(PaymentRequestStateTest, CanMakePayment_UnsupportedPaymentMethod) {
+  std::vector<mojom::PaymentMethodDataPtr> method_data;
+  mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+  entry->supported_method = "unsupported_method";
+  method_data.push_back(std::move(entry));
+  RecreateStateWithOptionsAndDetails(mojom::PaymentOptions::New(),
+                                     mojom::PaymentDetails::New(),
+                                     std::move(method_data));
+
+  // HasEnrolledInstrument returns false because the method data requires
+  // MasterCard, and the user doesn't have such an instrument.
+  state()->HasEnrolledInstrument(
+      base::BindOnce([](bool has_enrolled_instrument) {
+        EXPECT_FALSE(has_enrolled_instrument);
+      }));
+
+  // CanMakePayment returns true because the requested method is supported, even
+  // though the payment instrument is not ready to pay.
+  state()->CanMakePayment(base::BindOnce(
+      [](bool can_make_payment) { EXPECT_FALSE(can_make_payment); }));
 }
 
 TEST_F(PaymentRequestStateTest, HasEnrolledInstrument_OnlyBasicCard) {
@@ -185,6 +216,10 @@
       base::BindOnce([](bool has_enrolled_instrument) {
         EXPECT_TRUE(has_enrolled_instrument);
       }));
+
+  // CanMakePayment returns true because the requested method is supported.
+  state()->CanMakePayment(base::BindOnce(
+      [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); }));
 }
 
 TEST_F(PaymentRequestStateTest,
@@ -205,6 +240,10 @@
       base::BindOnce([](bool has_enrolled_instrument) {
         EXPECT_TRUE(has_enrolled_instrument);
       }));
+
+  // CanMakePayment returns true because the requested method is supported.
+  state()->CanMakePayment(base::BindOnce(
+      [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); }));
 }
 
 TEST_F(PaymentRequestStateTest,
@@ -225,6 +264,11 @@
       base::BindOnce([](bool has_enrolled_instrument) {
         EXPECT_FALSE(has_enrolled_instrument);
       }));
+
+  // CanMakePayment returns true because the requested method is supported, even
+  // though there is no enrolled instrument.
+  state()->CanMakePayment(base::BindOnce(
+      [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); }));
 }
 
 TEST_F(PaymentRequestStateTest,
@@ -245,6 +289,11 @@
       base::BindOnce([](bool has_enrolled_instrument) {
         EXPECT_FALSE(has_enrolled_instrument);
       }));
+
+  // CanMakePayment returns true because the requested method is supported, even
+  // though there is no enrolled instrument.
+  state()->CanMakePayment(base::BindOnce(
+      [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); }));
 }
 
 TEST_F(PaymentRequestStateTest, ReadyToPay_DefaultSelections) {
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc
index 93bd9c02..0282f5e 100644
--- a/content/browser/devtools/devtools_instrumentation.cc
+++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -16,6 +16,7 @@
 #include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/web_package/signed_exchange_envelope.h"
 #include "content/common/navigation_params.mojom.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_request_headers.h"
 #include "net/ssl/ssl_info.h"
@@ -213,6 +214,7 @@
 }
 
 }  // namespace
+
 bool WillCreateURLLoaderFactory(
     RenderFrameHostImpl* rfh,
     bool is_navigation,
@@ -248,6 +250,22 @@
   return had_interceptors;
 }
 
+bool WillCreateURLLoaderFactory(
+    RenderFrameHostImpl* rfh,
+    bool is_navigation,
+    bool is_download,
+    std::unique_ptr<network::mojom::URLLoaderFactory>* factory) {
+  network::mojom::URLLoaderFactoryPtrInfo proxied_factory;
+  network::mojom::URLLoaderFactoryRequest request =
+      mojo::MakeRequest(&proxied_factory);
+  if (!WillCreateURLLoaderFactory(rfh, is_navigation, is_download, &request))
+    return false;
+  mojo::MakeStrongBinding(std::move(*factory), std::move(request));
+  *factory = std::make_unique<DevToolsURLLoaderFactoryAdapter>(
+      mojo::MakeProxy(std::move(proxied_factory)));
+  return true;
+}
+
 void OnNavigationRequestWillBeSent(
     const NavigationRequest& navigation_request) {
   DispatchToAgents(navigation_request.frame_tree_node(),
diff --git a/content/browser/devtools/devtools_instrumentation.h b/content/browser/devtools/devtools_instrumentation.h
index 9730992..ee0e1dc 100644
--- a/content/browser/devtools/devtools_instrumentation.h
+++ b/content/browser/devtools/devtools_instrumentation.h
@@ -54,6 +54,12 @@
     bool is_download,
     network::mojom::URLLoaderFactoryRequest* loader_factory_request);
 
+bool WillCreateURLLoaderFactory(
+    RenderFrameHostImpl* rfh,
+    bool is_navigation,
+    bool is_download,
+    std::unique_ptr<network::mojom::URLLoaderFactory>* factory);
+
 void OnResetNavigationRequest(NavigationRequest* navigation_request);
 void OnNavigationRequestWillBeSent(const NavigationRequest& navigation_request);
 void OnNavigationResponseReceived(const NavigationRequest& nav_request,
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index 572cfaa..442c24e3 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -1453,4 +1453,28 @@
   NotifyClient(std::move(request_info));
 }
 
+DevToolsURLLoaderFactoryAdapter::DevToolsURLLoaderFactoryAdapter(
+    network::mojom::URLLoaderFactoryPtr factory)
+    : factory_(std::move(factory)) {}
+
+DevToolsURLLoaderFactoryAdapter::~DevToolsURLLoaderFactoryAdapter() = default;
+
+void DevToolsURLLoaderFactoryAdapter::CreateLoaderAndStart(
+    network::mojom::URLLoaderRequest loader,
+    int32_t routing_id,
+    int32_t request_id,
+    uint32_t options,
+    const network::ResourceRequest& request,
+    network::mojom::URLLoaderClientPtr client,
+    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+  factory_->CreateLoaderAndStart(std::move(loader), routing_id, request_id,
+                                 options, request, std::move(client),
+                                 traffic_annotation);
+}
+
+void DevToolsURLLoaderFactoryAdapter::Clone(
+    network::mojom::URLLoaderFactoryRequest request) {
+  factory_->Clone(std::move(request));
+}
+
 }  // namespace content
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.h b/content/browser/devtools/devtools_url_loader_interceptor.h
index b751345..4342140 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.h
+++ b/content/browser/devtools/devtools_url_loader_interceptor.h
@@ -64,6 +64,35 @@
   DISALLOW_COPY_AND_ASSIGN(DevToolsURLLoaderInterceptor);
 };
 
+// The purpose of this class is to have a thin wrapper around
+// InterfacePtr<URLLoaderFactory> that is held by the client as
+// unique_ptr<network::mojom::URLLoaderFactory>, since this is the
+// way some clients pass the factory. We prefer wrapping a mojo proxy
+// rather than exposing original DevToolsURLLoaderFactoryProxy because
+// this takes care of thread hopping when necessary.
+class DevToolsURLLoaderFactoryAdapter
+    : public network::mojom::URLLoaderFactory {
+ public:
+  DevToolsURLLoaderFactoryAdapter() = delete;
+  explicit DevToolsURLLoaderFactoryAdapter(
+      network::mojom::URLLoaderFactoryPtr factory);
+  ~DevToolsURLLoaderFactoryAdapter() override;
+
+ private:
+  // network::mojom::URLLoaderFactory implementation
+  void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const network::ResourceRequest& request,
+                            network::mojom::URLLoaderClientPtr client,
+                            const net::MutableNetworkTrafficAnnotationTag&
+                                traffic_annotation) override;
+  void Clone(network::mojom::URLLoaderFactoryRequest request) override;
+
+  network::mojom::URLLoaderFactoryPtr factory_;
+};
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_LOADER_INTERCEPTOR_H_
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 4410db10..bc1aa36 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1676,8 +1676,8 @@
         true /* is_navigation */, navigation_request_initiator,
         &factory_request, &header_client, &bypass_redirect_checks);
     if (devtools_instrumentation::WillCreateURLLoaderFactory(
-            frame_tree_node->current_frame_host(), true, false,
-            &factory_request)) {
+            frame_tree_node->current_frame_host(), true /* is_navigation */,
+            false /* is_download */, &factory_request)) {
       use_proxy = true;
     }
     if (use_proxy) {
@@ -1696,7 +1696,7 @@
   non_network_url_loader_factories_[url::kAboutScheme] =
       std::make_unique<AboutURLLoaderFactory>();
 
-  non_network_url_loader_factories_[url::kFileScheme] =
+  std::unique_ptr<network::mojom::URLLoaderFactory> file_url_loader_factory =
       std::make_unique<FileURLLoaderFactory>(
           partition->browser_context()->GetPath(),
           BrowserContext::GetSharedCorsOriginAccessList(
@@ -1705,6 +1705,15 @@
               {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
                base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
 
+  if (frame_tree_node) {  // May be nullptr in some unit tests.
+    devtools_instrumentation::WillCreateURLLoaderFactory(
+        frame_tree_node->current_frame_host(), true /* is_navigation */,
+        false /* is_download */, &file_url_loader_factory);
+  }
+
+  non_network_url_loader_factories_[url::kFileScheme] =
+      std::move(file_url_loader_factory);
+
 #if defined(OS_ANDROID)
   non_network_url_loader_factories_[url::kContentScheme] =
       std::make_unique<ContentURLLoaderFactory>(
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 980e36c..12c0aea4 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -363,12 +363,9 @@
 
   ResourceRequestInfoImpl* info = GetRequestInfo();
 
-  // With PlzNavigate for frame navigations this check is done in the
+  // For frame navigations this check is done in the
   // NavigationRequest::OnReceivedRedirect() function.
-  bool check_handled_elsewhere = IsBrowserSideNavigationEnabled() &&
-      IsResourceTypeFrame(info->GetResourceType());
-
-  if (!check_handled_elsewhere) {
+  if (!IsResourceTypeFrame(info->GetResourceType())) {
     if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
             info->GetChildID(), redirect_info.new_url)) {
       DVLOG(1) << "Denied unauthorized request for "
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index b5020b3f..9bc87b0 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -214,7 +214,6 @@
   // RenderProcessHost and RenderFrameHost IDs. The FrameTreeNode ID should be
   // used to access the WebContents.
   if (frame_tree_node_id_ != RenderFrameHost::kNoFrameTreeNodeId) {
-    DCHECK(IsBrowserSideNavigationEnabled());
     return base::Bind(WebContents::FromFrameTreeNodeId, frame_tree_node_id_);
   }
 
@@ -234,7 +233,6 @@
 ResourceRequestInfo::FrameTreeNodeIdGetter
 ResourceRequestInfoImpl::GetFrameTreeNodeIdGetterForRequest() const {
   if (frame_tree_node_id_ != -1) {
-    DCHECK(IsBrowserSideNavigationEnabled());
     return base::Bind([](int id) { return id; }, frame_tree_node_id_);
   }
 
@@ -285,11 +283,6 @@
   return resource_type_;
 }
 
-int ResourceRequestInfoImpl::GetProcessType() const {
-  return requester_info_->IsBrowserSideNavigation() ? PROCESS_TYPE_BROWSER
-                                                    : PROCESS_TYPE_RENDERER;
-}
-
 network::mojom::ReferrerPolicy ResourceRequestInfoImpl::GetReferrerPolicy()
     const {
   return referrer_policy_;
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h
index 6d4059d..6658ab8 100644
--- a/content/browser/loader/resource_request_info_impl.h
+++ b/content/browser/loader/resource_request_info_impl.h
@@ -86,7 +86,6 @@
   int GetFrameTreeNodeId() const override;
   bool IsMainFrame() const override;
   ResourceType GetResourceType() const override;
-  int GetProcessType() const override;
   network::mojom::ReferrerPolicy GetReferrerPolicy() const override;
   bool IsPrerendering() const override;
   ui::PageTransition GetPageTransition() const override;
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index 85ee344..5b23582 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -15,6 +15,8 @@
 #include "content/public/browser/web_ui_controller_factory.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/service_manager_connection.h"
+#include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_utils.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
@@ -28,6 +30,8 @@
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/network_service_test.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/application_status_listener.h"
@@ -179,7 +183,7 @@
     std::unique_ptr<network::ResourceRequest> request =
         std::make_unique<network::ResourceRequest>();
     request->url = url;
-    content::SimpleURLLoaderTestHelper simple_loader_helper;
+    SimpleURLLoaderTestHelper simple_loader_helper;
     std::unique_ptr<network::SimpleURLLoader> simple_loader =
         network::SimpleURLLoader::Create(std::move(request),
                                          TRAFFIC_ANNOTATION_FOR_TESTS);
@@ -290,7 +294,7 @@
   base::android::ApplicationStatusListener::NotifyApplicationStateChange(
       base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
   base::RunLoop().RunUntilIdle();
-  content::FlushNetworkServiceInstanceForTesting();
+  FlushNetworkServiceInstanceForTesting();
   disk_cache::FlushCacheThreadForTesting();
 
   EXPECT_GT(base::ComputeDirectorySize(GetCacheIndexDirectory()),
@@ -298,6 +302,35 @@
 }
 #endif
 
+IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest,
+                       MemoryPressureSentToNetworkProcess) {
+  if (IsNetworkServiceRunningInProcess())
+    return;
+
+  network::mojom::NetworkServiceTestPtr network_service_test;
+  ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface(
+      mojom::kNetworkServiceName, &network_service_test);
+  // TODO(crbug.com/901026): Make sure the network process is started to avoid a
+  // deadlock on Android.
+  network_service_test.FlushForTesting();
+
+  mojo::ScopedAllowSyncCallForTesting allow_sync_call;
+  base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level =
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+  network_service_test->GetLatestMemoryPressureLevel(&memory_pressure_level);
+  EXPECT_EQ(memory_pressure_level,
+            base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
+
+  base::MemoryPressureListener::NotifyMemoryPressure(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+  base::RunLoop().RunUntilIdle();
+  FlushNetworkServiceInstanceForTesting();
+
+  network_service_test->GetLatestMemoryPressureLevel(&memory_pressure_level);
+  EXPECT_EQ(memory_pressure_level,
+            base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+}
+
 class NetworkServiceInProcessBrowserTest : public ContentBrowserTest {
  public:
   NetworkServiceInProcessBrowserTest() {
diff --git a/content/browser/network_service_client.cc b/content/browser/network_service_client.cc
index e5837f4..b5cf4548 100644
--- a/content/browser/network_service_client.cc
+++ b/content/browser/network_service_client.cc
@@ -424,8 +424,12 @@
                               base::Unretained(this))))
 #endif
 {
-  if (IsOutOfProcessNetworkService())
+  if (IsOutOfProcessNetworkService()) {
     net::CertDatabase::GetInstance()->AddObserver(this);
+    memory_pressure_listener_ =
+        std::make_unique<base::MemoryPressureListener>(base::BindRepeating(
+            &NetworkServiceClient::OnMemoryPressure, base::Unretained(this)));
+  }
 }
 
 NetworkServiceClient::~NetworkServiceClient() {
@@ -591,6 +595,11 @@
   GetNetworkService()->OnCertDBChanged();
 }
 
+void NetworkServiceClient::OnMemoryPressure(
+    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+  GetNetworkService()->OnMemoryPressure(memory_pressure_level);
+}
+
 #if defined(OS_ANDROID)
 void NetworkServiceClient::OnApplicationStateChange(
     base::android::ApplicationState state) {
diff --git a/content/browser/network_service_client.h b/content/browser/network_service_client.h
index 99a4a525..044aedf 100644
--- a/content/browser/network_service_client.h
+++ b/content/browser/network_service_client.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_NETWORK_SERVICE_IMPL_H_
 
 #include "base/macros.h"
+#include "base/memory/memory_pressure_listener.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -89,6 +90,9 @@
   // net::CertDatabase::Observer implementation:
   void OnCertDBChanged() override;
 
+  void OnMemoryPressure(
+      base::MemoryPressureListener::MemoryPressureLevel memory_presure_level);
+
 #if defined(OS_ANDROID)
   void OnApplicationStateChange(base::android::ApplicationState state);
 #endif
@@ -96,6 +100,8 @@
  private:
   mojo::Binding<network::mojom::NetworkServiceClient> binding_;
 
+  std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
 #if defined(OS_ANDROID)
   std::unique_ptr<base::android::ApplicationStatusListener>
       app_status_listener_;
diff --git a/content/browser/service_worker/service_worker_blob_reader.h b/content/browser/service_worker/service_worker_blob_reader.h
index 4021657a..80d629b 100644
--- a/content/browser/service_worker/service_worker_blob_reader.h
+++ b/content/browser/service_worker/service_worker_blob_reader.h
@@ -11,6 +11,10 @@
 #include "net/base/io_buffer.h"
 #include "net/url_request/url_request.h"
 
+namespace storage {
+class BlobDataHandle;
+}
+
 namespace content {
 
 // Reads a blob response for ServiceWorkerURLRequestJob.
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc
index 4fb9c4d..b97a4f08 100644
--- a/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -15,7 +15,6 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
-#include "base/files/file_util.h"
 #include "base/guid.h"
 #include "base/location.h"
 #include "base/numerics/safe_conversions.h"
@@ -115,110 +114,8 @@
   return n::FAILED;
 }
 
-// Does file IO. Use with base::MayBlock().
-std::vector<int64_t> GetFileSizes(std::vector<base::FilePath> file_paths) {
-  std::vector<int64_t> sizes;
-  sizes.reserve(file_paths.size());
-  for (const base::FilePath& path : file_paths) {
-    base::File::Info file_info;
-    if (!base::GetFileInfo(path, &file_info) || file_info.is_directory)
-      return std::vector<int64_t>();
-    sizes.push_back(file_info.size);
-  }
-  return sizes;
-}
-
 }  // namespace
 
-// Sets the size on each DataElement in the request body that is a file with
-// unknown size. This ensures ServiceWorkerURLRequestJob::CreateRequestBodyBlob
-// can successfuly create a blob from the data elements, as files with unknown
-// sizes are not supported by the blob storage system.
-class ServiceWorkerURLRequestJob::FileSizeResolver {
- public:
-  explicit FileSizeResolver(ServiceWorkerURLRequestJob* owner)
-      : owner_(owner), weak_factory_(this) {
-    TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", "FileSizeResolver", this, "URL",
-                             owner_->request()->url().spec());
-    owner_->request()->net_log().BeginEvent(
-        net::NetLogEventType::SERVICE_WORKER_WAITING_FOR_REQUEST_BODY_FILES);
-  }
-
-  ~FileSizeResolver() {
-    owner_->request()->net_log().EndEvent(
-        net::NetLogEventType::SERVICE_WORKER_WAITING_FOR_REQUEST_BODY_FILES,
-        net::NetLog::BoolCallback("success", phase_ == Phase::SUCCESS));
-    TRACE_EVENT_ASYNC_END1("ServiceWorker", "FileSizeResolver", this, "Success",
-                           phase_ == Phase::SUCCESS);
-  }
-
-  void Resolve(base::OnceCallback<void(bool /* success */)> callback) {
-    DCHECK_EQ(static_cast<int>(Phase::INITIAL), static_cast<int>(phase_));
-    DCHECK(file_elements_.empty());
-    phase_ = Phase::WAITING;
-    body_ = owner_->body_;
-    callback_ = std::move(callback);
-
-    std::vector<base::FilePath> file_paths;
-    for (network::DataElement& element : *body_->elements_mutable()) {
-      if (element.type() == network::DataElement::TYPE_FILE &&
-          element.length() == network::DataElement::kUnknownSize) {
-        file_elements_.push_back(&element);
-        file_paths.push_back(element.path());
-      }
-    }
-    if (file_elements_.empty()) {
-      Complete(true);
-      return;
-    }
-
-    base::PostTaskWithTraitsAndReplyWithResult(
-        FROM_HERE,
-        {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
-        base::BindOnce(&GetFileSizes, std::move(file_paths)),
-        base::BindOnce(
-            &ServiceWorkerURLRequestJob::FileSizeResolver::OnFileSizesResolved,
-            weak_factory_.GetWeakPtr()));
-  }
-
- private:
-  enum class Phase { INITIAL, WAITING, SUCCESS, FAIL };
-
-  void OnFileSizesResolved(std::vector<int64_t> sizes) {
-    bool success = !sizes.empty();
-    if (success) {
-      DCHECK_EQ(sizes.size(), file_elements_.size());
-      size_t num_elements = file_elements_.size();
-      for (size_t i = 0; i < num_elements; i++) {
-        network::DataElement* element = file_elements_[i];
-        element->SetToFilePathRange(element->path(), element->offset(),
-                                    base::checked_cast<uint64_t>(sizes[i]),
-                                    element->expected_modification_time());
-      }
-      file_elements_.clear();
-    }
-    Complete(success);
-  }
-
-  void Complete(bool success) {
-    DCHECK_EQ(static_cast<int>(Phase::WAITING), static_cast<int>(phase_));
-    phase_ = success ? Phase::SUCCESS : Phase::FAIL;
-    // Destroys |this|.
-    std::move(callback_).Run(success);
-  }
-
-  // Owns and must outlive |this|.
-  ServiceWorkerURLRequestJob* owner_;
-
-  scoped_refptr<network::ResourceRequestBody> body_;
-  std::vector<network::DataElement*> file_elements_;
-  base::OnceCallback<void(bool /* success */)> callback_;
-  Phase phase_ = Phase::INITIAL;
-  base::WeakPtrFactory<FileSizeResolver> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(FileSizeResolver);
-};
-
 // A helper for recording navigation preload UMA. The UMA is recorded
 // after both service worker preparation finished and the
 // navigation preload response arrived.
@@ -345,7 +242,6 @@
 
 ServiceWorkerURLRequestJob::~ServiceWorkerURLRequestJob() {
   data_pipe_reader_.reset();
-  file_size_resolver_.reset();
 
   if (!ShouldRecordResult())
     return;
@@ -527,16 +423,7 @@
       return;
 
     case ResponseType::FORWARD_TO_SERVICE_WORKER:
-      if (HasRequestBody()) {
-        DCHECK(!file_size_resolver_);
-        file_size_resolver_.reset(new FileSizeResolver(this));
-        file_size_resolver_->Resolve(base::BindOnce(
-            &ServiceWorkerURLRequestJob::RequestBodyFileSizesResolved,
-            GetWeakPtr()));
-        return;
-      }
-
-      RequestBodyFileSizesResolved(true);
+      ForwardRequestToServiceWorker();
       return;
   }
 
@@ -585,29 +472,6 @@
   return request;
 }
 
-blink::mojom::BlobPtr ServiceWorkerURLRequestJob::CreateRequestBodyBlob(
-    std::string* blob_uuid,
-    uint64_t* blob_size) {
-  DCHECK(HasRequestBody());
-  auto blob_builder =
-      std::make_unique<storage::BlobDataBuilder>(base::GenerateGUID());
-  for (const network::DataElement& element : (*body_->elements())) {
-    blob_builder->AppendIPCDataElement(element,
-                                       blob_storage_context_->registry());
-  }
-
-  *blob_uuid = blob_builder->uuid();
-  request_body_blob_data_handle_ =
-      blob_storage_context_->AddFinishedBlob(std::move(blob_builder));
-  *blob_size = request_body_blob_data_handle_->size();
-
-  blink::mojom::BlobPtr blob_ptr;
-  storage::BlobImpl::Create(std::make_unique<storage::BlobDataHandle>(
-                                *request_body_blob_data_handle_),
-                            MakeRequest(&blob_ptr));
-  return blob_ptr;
-}
-
 bool ServiceWorkerURLRequestJob::ShouldRecordNavigationMetrics(
     const ServiceWorkerVersion* version) const {
   // Don't record navigation metrics in the following situations.
@@ -951,22 +815,10 @@
 bool ServiceWorkerURLRequestJob::HasRequestBody() {
   // URLRequest::has_upload() must be checked since its upload data may have
   // been cleared while handling a redirect.
-  return request_->has_upload() && body_.get() && blob_storage_context_;
+  return request_->has_upload() && body_.get();
 }
 
-void ServiceWorkerURLRequestJob::RequestBodyFileSizesResolved(bool success) {
-  file_size_resolver_.reset();
-  if (!success) {
-    RecordResult(
-        ServiceWorkerMetrics::REQUEST_JOB_ERROR_REQUEST_BODY_BLOB_FAILED);
-    // TODO(falken): This and below should probably be NotifyStartError, not
-    // DeliverErrorResponse. But changing it causes
-    // ServiceWorkerURLRequestJobTest.DeletedProviderHostBeforeFetchEvent to
-    // fail.
-    DeliverErrorResponse();
-    return;
-  }
-
+void ServiceWorkerURLRequestJob::ForwardRequestToServiceWorker() {
   ServiceWorkerMetrics::URLRequestJobResult result =
       ServiceWorkerMetrics::REQUEST_JOB_ERROR_BAD_DELEGATE;
   ServiceWorkerVersion* active_worker =
@@ -989,26 +841,10 @@
 
   std::unique_ptr<network::ResourceRequest> resource_request =
       CreateResourceRequest();
-  std::string blob_uuid;
-  uint64_t blob_size = 0;
-  blink::mojom::BlobPtr blob;
-  if (HasRequestBody()) {
-    // TODO(falken): Could we just set |resource_request->request_body| to
-    // |body_| directly, and not construct a new blob? But I think the
-    // renderer-side might need to know the size of the body.
-    blob = CreateRequestBodyBlob(&blob_uuid, &blob_size);
-  }
-
   auto fetch_api_request =
       blink::mojom::FetchAPIRequest::From(*resource_request);
-  // Use |fetch_api_request->blob| to represent body for non-S13nServiceWorker
-  // case, please see dispatch_fetch_event_params.mojom for details.
-  // TODO(crbug.com/911930): Use |fetch_api_request->body| instead.
-  fetch_api_request->body.reset();
-  DCHECK(!fetch_api_request->blob);
-  if (blob) {
-    fetch_api_request->blob = blink::mojom::SerializedBlob::New(
-        blob_uuid, std::string(), blob_size, blob.PassInterface());
+  if (HasRequestBody()) {
+    fetch_api_request->body = std::move(body_);
   }
   DCHECK(!fetch_dispatcher_);
   fetch_dispatcher_ = std::make_unique<ServiceWorkerFetchDispatcher>(
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h
index a116077..6384c93 100644
--- a/content/browser/service_worker/service_worker_url_request_job.h
+++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -47,7 +47,6 @@
 }
 
 namespace storage {
-class BlobDataHandle;
 class BlobStorageContext;
 }  // namespace storage
 
@@ -150,7 +149,6 @@
  private:
   using ResponseHeaderMap = base::flat_map<std::string, std::string>;
 
-  class FileSizeResolver;
   class NavigationPreloadMetrics;
   friend class service_worker_url_request_job_unittest::DelayHelper;
   friend class ServiceWorkerURLRequestJobTest;
@@ -173,14 +171,6 @@
   // body.
   std::unique_ptr<network::ResourceRequest> CreateResourceRequest();
 
-  // Creates BlobDataHandle of the request body from |body_|. This handle
-  // |request_body_blob_data_handle_| will be deleted when
-  // ServiceWorkerURLRequestJob is deleted.
-  // This must not be called until all files in |body_| with unknown size have
-  // their sizes populated.
-  blink::mojom::BlobPtr CreateRequestBodyBlob(std::string* blob_uuid,
-                                              uint64_t* blob_size);
-
   // Returns true if this job performed a navigation that should be logged to
   // performance-related UMA. It returns false in certain cases that are not
   // relevant to performance analysis, such as if the worker was not already
@@ -242,9 +232,8 @@
 
   bool IsMainResourceLoad() const;
 
-  // For waiting for files sizes of request body files with unknown sizes.
   bool HasRequestBody();
-  void RequestBodyFileSizesResolved(bool success);
+  void ForwardRequestToServiceWorker();
 
   // Called back from
   // ServiceWorkerFetchEventDispatcher::MaybeStartNavigationPreload when the
@@ -323,10 +312,7 @@
   blink::mojom::RequestContextType request_context_type_;
   network::mojom::RequestContextFrameType frame_type_;
   bool fall_back_required_;
-  // ResourceRequestBody has a collection of BlobDataHandles attached to it
-  // using the userdata mechanism. So we have to keep it not to free the blobs.
   scoped_refptr<network::ResourceRequestBody> body_;
-  std::unique_ptr<storage::BlobDataHandle> request_body_blob_data_handle_;
 
   ResponseBodyType response_body_type_ = UNKNOWN;
   bool did_record_result_ = false;
@@ -336,8 +322,6 @@
 
   ServiceWorkerHeaderList cors_exposed_header_names_;
 
-  std::unique_ptr<FileSizeResolver> file_size_resolver_;
-
   base::WeakPtrFactory<ServiceWorkerURLRequestJob> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLRequestJob);
diff --git a/content/public/browser/resource_request_info.h b/content/public/browser/resource_request_info.h
index 4a04aac..7f197a8 100644
--- a/content/public/browser/resource_request_info.h
+++ b/content/public/browser/resource_request_info.h
@@ -136,9 +136,6 @@
   // Returns the associated resource type.
   virtual ResourceType GetResourceType() const = 0;
 
-  // Returns the process type that initiated this request.
-  virtual int GetProcessType() const = 0;
-
   // Returns the associated referrer policy.
   virtual network::mojom::ReferrerPolicy GetReferrerPolicy() const = 0;
 
diff --git a/content/public/test/network_service_test_helper.cc b/content/public/test/network_service_test_helper.cc
index b9b56267..a048c5fd 100644
--- a/content/public/test/network_service_test_helper.cc
+++ b/content/public/test/network_service_test_helper.cc
@@ -67,7 +67,12 @@
     : public network::mojom::NetworkServiceTest,
       public base::MessageLoopCurrent::DestructionObserver {
  public:
-  NetworkServiceTestImpl() {
+  NetworkServiceTestImpl()
+      : memory_pressure_listener_(
+            base::DoNothing(),
+            base::BindRepeating(&NetworkServiceTestHelper::
+                                    NetworkServiceTestImpl::OnMemoryPressure,
+                                base::Unretained(this))) {
     if (base::CommandLine::ForCurrentProcess()->HasSwitch(
             switches::kUseMockCertVerifierForTesting)) {
       mock_cert_verifier_ = std::make_unique<net::MockCertVerifier>();
@@ -177,6 +182,11 @@
         base::BindRepeating(CrashResolveHost, host));
   }
 
+  void GetLatestMemoryPressureLevel(
+      GetLatestMemoryPressureLevelCallback callback) override {
+    std::move(callback).Run(latest_memory_pressure_level_);
+  }
+
   void BindRequest(network::mojom::NetworkServiceTestRequest request) {
     bindings_.AddBinding(this, std::move(request));
     if (!registered_as_destruction_observer_) {
@@ -192,12 +202,21 @@
   }
 
  private:
+  void OnMemoryPressure(
+      base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+    latest_memory_pressure_level_ = memory_pressure_level;
+  }
+
   bool registered_as_destruction_observer_ = false;
   mojo::BindingSet<network::mojom::NetworkServiceTest> bindings_;
   TestHostResolver test_host_resolver_;
   std::unique_ptr<net::MockCertVerifier> mock_cert_verifier_;
   std::unique_ptr<net::ScopedTransportSecurityStateSource>
       transport_security_state_source_;
+  base::MemoryPressureListener memory_pressure_listener_;
+  base::MemoryPressureListener::MemoryPressureLevel
+      latest_memory_pressure_level_ =
+          base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkServiceTestImpl);
 };
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc
index a2d6ae9..6750a68 100644
--- a/content/public/test/test_renderer_host.cc
+++ b/content/public/test/test_renderer_host.cc
@@ -297,15 +297,11 @@
   browser_context_.reset(CreateBrowserContext());
 
   SetContents(CreateTestWebContents());
-
-  if (IsBrowserSideNavigationEnabled())
-    BrowserSideNavigationSetUp();
+  BrowserSideNavigationSetUp();
 }
 
 void RenderViewHostTestHarness::TearDown() {
-  if (IsBrowserSideNavigationEnabled())
-    BrowserSideNavigationTearDown();
-
+  BrowserSideNavigationTearDown();
   DeleteContents();
 #if defined(USE_AURA)
   aura_test_helper_->TearDown();
diff --git a/content/renderer/loader/child_url_loader_factory_bundle.h b/content/renderer/loader/child_url_loader_factory_bundle.h
index 2a26ba3..d0596a2 100644
--- a/content/renderer/loader/child_url_loader_factory_bundle.h
+++ b/content/renderer/loader/child_url_loader_factory_bundle.h
@@ -99,8 +99,8 @@
 
   // Does the same as Clone(), but without cloning the appcache_factory_.
   // This is used for creating a bundle for network fallback loading with
-  // Service Workers (where AppCache must be skipped).
-  // TODO(kinuko): See if this is really needed and remove otherwise.
+  // Service Workers (where AppCache must be skipped), and only when
+  // claim() is called.
   virtual std::unique_ptr<network::SharedURLLoaderFactoryInfo>
   CloneWithoutAppCacheFactory();
 
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 9fe1b34..8a319765 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -332,7 +332,6 @@
   std::unique_ptr<NavigationResponseOverrideParameters> response_override =
       std::move(request_info->navigation_response_override);
   if (response_override) {
-    CHECK(IsBrowserSideNavigationEnabled());
     response_head = response_override->response;
   } else {
     response_head = initial_response_head;
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index ef58637d..98a4da4 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -996,19 +996,6 @@
   // NOTE: We special case MIME types we can render both for performance
   // reasons as well as to support unit tests.
 
-#if defined(OS_ANDROID)
-  // For compatibility reasons on Android we need to expose top-level data://
-  // to the browser. In tests resource_dispatcher_ can be null, and test pages
-  // need to be loaded locally.
-  // For PlzNavigate, navigation requests were already checked in the browser.
-  if (resource_dispatcher_ &&
-      request.GetFrameType() ==
-          network::mojom::RequestContextFrameType::kTopLevel) {
-    if (!IsBrowserSideNavigationEnabled())
-      return false;
-  }
-#endif
-
   if (request.GetFrameType() !=
           network::mojom::RequestContextFrameType::kTopLevel &&
       request.GetFrameType() !=
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index bd533c2..5c3724f 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -1317,16 +1317,10 @@
     }
   }
 
-  // Non-S13nServiceWorker: The body is provided as a blob.
-  if (request->blob) {
-    DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
-    web_request->SetBlob(blink::WebString::FromASCII(request->blob->uuid),
-                         request->blob->size, request->blob->blob.PassHandle());
-  }
-  // S13nServiceWorker: The body is provided in |request->body|.
-  else if (request->body.has_value()) {
+  // The body is provided in |request->body|.
+  DCHECK(!request->blob);
+  if (request->body.has_value()) {
     DCHECK(request->body.value());
-    DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
     std::vector<blink::mojom::BlobPtrInfo> blob_ptrs;
     if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
       // We need this as GetBlobFromUUID is a sync IPC.
diff --git a/content/test/test_navigation_url_loader.cc b/content/test/test_navigation_url_loader.cc
index 22a7ca5..3980d3f 100644
--- a/content/test/test_navigation_url_loader.cc
+++ b/content/test/test_navigation_url_loader.cc
@@ -28,7 +28,6 @@
       delegate_(delegate),
       redirect_count_(0),
       response_proceeded_(false) {
-  DCHECK(IsBrowserSideNavigationEnabled());
 }
 
 void TestNavigationURLLoader::FollowRedirect(
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 8225b9f..44b1c47 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -186,7 +186,7 @@
 void TestRenderFrameHost::SimulateNavigationStop() {
   if (is_loading()) {
     OnDidStopLoading();
-  } else if (IsBrowserSideNavigationEnabled()) {
+  } else {
     // Even if the RenderFrameHost is not loading, there may still be an
     // ongoing navigation in the FrameTreeNode. Cancel this one as well.
     frame_tree_node()->ResetNavigationRequest(false, true);
@@ -482,10 +482,8 @@
 }
 
 void TestRenderFrameHost::PrepareForCommitIfNecessary() {
-  if (!IsBrowserSideNavigationEnabled() ||
-      frame_tree_node()->navigation_request()) {
+  if (frame_tree_node()->navigation_request())
     PrepareForCommit();
-  }
 }
 
 void TestRenderFrameHost::SimulateCommitProcessed(int64_t navigation_id,
diff --git a/extensions/browser/api/audio/audio_api.cc b/extensions/browser/api/audio/audio_api.cc
index 867164a4..c75cde7 100644
--- a/extensions/browser/api/audio/audio_api.cc
+++ b/extensions/browser/api/audio/audio_api.cc
@@ -90,7 +90,8 @@
   std::unique_ptr<Event> event(new Event(
       events::AUDIO_ON_DEVICE_CHANGED, audio::OnDeviceChanged::kEventName,
       std::unique_ptr<base::ListValue>(new base::ListValue())));
-  event->will_dispatch_callback = base::Bind(&CanReceiveDeprecatedAudioEvent);
+  event->will_dispatch_callback =
+      base::BindRepeating(&CanReceiveDeprecatedAudioEvent);
   event_router->BroadcastEvent(std::move(event));
 }
 
diff --git a/extensions/browser/api/hid/hid_device_manager.cc b/extensions/browser/api/hid/hid_device_manager.cc
index 51baa7c..0fc62e41 100644
--- a/extensions/browser/api/hid/hid_device_manager.cc
+++ b/extensions/browser/api/hid/hid_device_manager.cc
@@ -358,8 +358,8 @@
   // The |event->will_dispatch_callback| will be called synchronously, it is
   // safe to pass |device_info| by reference.
   event->will_dispatch_callback =
-      base::Bind(&WillDispatchDeviceEvent, weak_factory_.GetWeakPtr(),
-                 base::ConstRef(device_info));
+      base::BindRepeating(&WillDispatchDeviceEvent, weak_factory_.GetWeakPtr(),
+                          base::ConstRef(device_info));
   event_router_->BroadcastEvent(std::move(event));
 }
 
diff --git a/extensions/browser/api/printer_provider/printer_provider_api.cc b/extensions/browser/api/printer_provider/printer_provider_api.cc
index 01bdbe1..e9e9b18 100644
--- a/extensions/browser/api/printer_provider/printer_provider_api.cc
+++ b/extensions/browser/api/printer_provider/printer_provider_api.cc
@@ -542,8 +542,8 @@
   // This callback is called synchronously during |BroadcastEvent|, so
   // Unretained is safe.
   event->will_dispatch_callback =
-      base::Bind(&PrinterProviderAPIImpl::WillRequestPrinters,
-                 base::Unretained(this), request_id);
+      base::BindRepeating(&PrinterProviderAPIImpl::WillRequestPrinters,
+                          base::Unretained(this), request_id);
 
   event_router->BroadcastEvent(std::move(event));
 }
diff --git a/extensions/browser/api/usb/usb_event_router.cc b/extensions/browser/api/usb/usb_event_router.cc
index 855732d..ede59f7 100644
--- a/extensions/browser/api/usb/usb_event_router.cc
+++ b/extensions/browser/api/usb/usb_event_router.cc
@@ -119,7 +119,7 @@
     }
 
     event->will_dispatch_callback =
-        base::Bind(&WillDispatchDeviceEvent, device);
+        base::BindRepeating(&WillDispatchDeviceEvent, device);
     event_router->BroadcastEvent(std::move(event));
   }
 }
diff --git a/extensions/browser/event_listener_map_unittest.cc b/extensions/browser/event_listener_map_unittest.cc
index f8cd2065..a07f86b 100644
--- a/extensions/browser/event_listener_map_unittest.cc
+++ b/extensions/browser/event_listener_map_unittest.cc
@@ -29,10 +29,11 @@
 const char kEvent2Name[] = "event2";
 const char kURL[] = "https://google.com/some/url";
 
-using EventListenerConstructor = base::Callback<std::unique_ptr<EventListener>(
-    const std::string& /* event_name */,
-    content::RenderProcessHost* /* process */,
-    std::unique_ptr<base::DictionaryValue> /* filter */)>;
+using EventListenerConstructor =
+    base::RepeatingCallback<std::unique_ptr<EventListener>(
+        const std::string& /* event_name */,
+        content::RenderProcessHost* /* process */,
+        std::unique_ptr<base::DictionaryValue> /* filter */)>;
 
 class EmptyDelegate : public EventListenerMap::Delegate {
   void OnListenerAdded(const EventListener* listener) override {}
@@ -121,12 +122,12 @@
 
 TEST_F(EventListenerMapTest, UnfilteredEventsGoToAllListenersForExtensions) {
   TestUnfilteredEventsGoToAllListeners(
-      base::Bind(&CreateEventListenerForExtension, kExt1Id));
+      base::BindRepeating(&CreateEventListenerForExtension, kExt1Id));
 }
 
 TEST_F(EventListenerMapTest, UnfilteredEventsGoToAllListenersForURLs) {
   TestUnfilteredEventsGoToAllListeners(
-      base::Bind(&CreateEventListenerForURL, GURL(kURL)));
+      base::BindRepeating(&CreateEventListenerForURL, GURL(kURL)));
 }
 
 TEST_F(EventListenerMapTest, FilteredEventsGoToAllMatchingListeners) {
@@ -182,11 +183,13 @@
 }
 
 TEST_F(EventListenerMapTest, TestRemovingByProcessForExtension) {
-  TestRemovingByProcess(base::Bind(&CreateEventListenerForExtension, kExt1Id));
+  TestRemovingByProcess(
+      base::BindRepeating(&CreateEventListenerForExtension, kExt1Id));
 }
 
 TEST_F(EventListenerMapTest, TestRemovingByProcessForURL) {
-  TestRemovingByProcess(base::Bind(&CreateEventListenerForURL, GURL(kURL)));
+  TestRemovingByProcess(
+      base::BindRepeating(&CreateEventListenerForURL, GURL(kURL)));
 }
 
 void EventListenerMapTest::TestRemovingByListener(
@@ -207,11 +210,13 @@
 }
 
 TEST_F(EventListenerMapTest, TestRemovingByListenerForExtension) {
-  TestRemovingByListener(base::Bind(&CreateEventListenerForExtension, kExt1Id));
+  TestRemovingByListener(
+      base::BindRepeating(&CreateEventListenerForExtension, kExt1Id));
 }
 
 TEST_F(EventListenerMapTest, TestRemovingByListenerForURL) {
-  TestRemovingByListener(base::Bind(&CreateEventListenerForURL, GURL(kURL)));
+  TestRemovingByListener(
+      base::BindRepeating(&CreateEventListenerForURL, GURL(kURL)));
 }
 
 TEST_F(EventListenerMapTest, TestLazyDoubleAddIsUndoneByRemove) {
@@ -288,12 +293,12 @@
 
 TEST_F(EventListenerMapTest, AddExistingUnfilteredListenerForExtensions) {
   TestAddExistingUnfilteredListener(
-      base::Bind(&CreateEventListenerForExtension, kExt1Id));
+      base::BindRepeating(&CreateEventListenerForExtension, kExt1Id));
 }
 
 TEST_F(EventListenerMapTest, AddExistingUnfilteredListenerForURLs) {
   TestAddExistingUnfilteredListener(
-      base::Bind(&CreateEventListenerForURL, GURL(kURL)));
+      base::BindRepeating(&CreateEventListenerForURL, GURL(kURL)));
 }
 
 TEST_F(EventListenerMapTest, RemovingRouters) {
@@ -320,11 +325,12 @@
 
 TEST_F(EventListenerMapTest, HasListenerForEventForExtension) {
   TestHasListenerForEvent(
-      base::Bind(&CreateEventListenerForExtension, kExt1Id));
+      base::BindRepeating(&CreateEventListenerForExtension, kExt1Id));
 }
 
 TEST_F(EventListenerMapTest, HasListenerForEventForURL) {
-  TestHasListenerForEvent(base::Bind(&CreateEventListenerForURL, GURL(kURL)));
+  TestHasListenerForEvent(
+      base::BindRepeating(&CreateEventListenerForURL, GURL(kURL)));
 }
 
 TEST_F(EventListenerMapTest, HasListenerForExtension) {
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc
index cce7e2b5..f29668a 100644
--- a/extensions/browser/event_router.cc
+++ b/extensions/browser/event_router.cc
@@ -135,9 +135,9 @@
     // TODO(lazyboy): Skip this entirely: http://crbug.com/488747.
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::UI},
-        base::Bind(&EventRouter::DoDispatchEventToSenderBookkeepingOnUI,
-                   browser_context_id, extension_id, event_id, histogram_value,
-                   event_name));
+        base::BindOnce(&EventRouter::DoDispatchEventToSenderBookkeepingOnUI,
+                       browser_context_id, extension_id, event_id,
+                       histogram_value, event_name));
   }
 
   DispatchExtensionMessage(ipc_sender,
diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h
index 3e2cd3e..1de4c1a 100644
--- a/extensions/browser/event_router.h
+++ b/extensions/browser/event_router.h
@@ -396,10 +396,10 @@
   // This callback should return true if the event should be dispatched to the
   // given context and extension, and false otherwise.
   using WillDispatchCallback =
-      base::Callback<bool(content::BrowserContext*,
-                          const Extension*,
-                          Event*,
-                          const base::DictionaryValue*)>;
+      base::RepeatingCallback<bool(content::BrowserContext*,
+                                   const Extension*,
+                                   Event*,
+                                   const base::DictionaryValue*)>;
 
   // The identifier for the event, for histograms. In most cases this
   // correlates 1:1 with |event_name|, in some cases events will generate
diff --git a/extensions/browser/event_router_unittest.cc b/extensions/browser/event_router_unittest.cc
index 6342f2c..e0fd1fe 100644
--- a/extensions/browser/event_router_unittest.cc
+++ b/extensions/browser/event_router_unittest.cc
@@ -67,10 +67,11 @@
   DISALLOW_COPY_AND_ASSIGN(MockEventRouterObserver);
 };
 
-using EventListenerConstructor = base::Callback<std::unique_ptr<EventListener>(
-    const std::string& /* event_name */,
-    content::RenderProcessHost* /* process */,
-    std::unique_ptr<base::DictionaryValue> /* filter */)>;
+using EventListenerConstructor =
+    base::RepeatingCallback<std::unique_ptr<EventListener>(
+        const std::string& /* event_name */,
+        content::RenderProcessHost* /* process */,
+        std::unique_ptr<base::DictionaryValue> /* filter */)>;
 
 std::unique_ptr<EventListener> CreateEventListenerForExtension(
     const std::string& extension_id,
@@ -311,12 +312,12 @@
 
 TEST_F(EventRouterTest, EventRouterObserverForExtensions) {
   RunEventRouterObserverTest(
-      base::Bind(&CreateEventListenerForExtension, "extension_id"));
+      base::BindRepeating(&CreateEventListenerForExtension, "extension_id"));
 }
 
 TEST_F(EventRouterTest, EventRouterObserverForURLs) {
-  RunEventRouterObserverTest(
-      base::Bind(&CreateEventListenerForURL, GURL("http://google.com/path")));
+  RunEventRouterObserverTest(base::BindRepeating(
+      &CreateEventListenerForURL, GURL("http://google.com/path")));
 }
 
 TEST_F(EventRouterTest, TestReportEvent) {
diff --git a/extensions/browser/events/lazy_event_dispatcher.cc b/extensions/browser/events/lazy_event_dispatcher.cc
index 06edb87..63bcd8b 100644
--- a/extensions/browser/events/lazy_event_dispatcher.cc
+++ b/extensions/browser/events/lazy_event_dispatcher.cc
@@ -17,11 +17,10 @@
 
 namespace extensions {
 
-LazyEventDispatcher::LazyEventDispatcher(
-    BrowserContext* browser_context,
-    const DispatchFunction& dispatch_function)
+LazyEventDispatcher::LazyEventDispatcher(BrowserContext* browser_context,
+                                         DispatchFunction dispatch_function)
     : browser_context_(browser_context),
-      dispatch_function_(dispatch_function) {}
+      dispatch_function_(std::move(dispatch_function)) {}
 
 LazyEventDispatcher::~LazyEventDispatcher() {}
 
diff --git a/extensions/browser/events/lazy_event_dispatcher.h b/extensions/browser/events/lazy_event_dispatcher.h
index 9ef74be..e09ee60 100644
--- a/extensions/browser/events/lazy_event_dispatcher.h
+++ b/extensions/browser/events/lazy_event_dispatcher.h
@@ -36,7 +36,7 @@
       std::unique_ptr<LazyContextTaskQueue::ContextInfo>)>;
 
   LazyEventDispatcher(content::BrowserContext* browser_context,
-                      const DispatchFunction& dispatch_function);
+                      DispatchFunction dispatch_function);
   ~LazyEventDispatcher();
 
   // Dispatches the lazy |event| to |extension_id|.
diff --git a/extensions/browser/lazy_background_task_queue_unittest.cc b/extensions/browser/lazy_background_task_queue_unittest.cc
index 926a3fc..f7c4cee8 100644
--- a/extensions/browser/lazy_background_task_queue_unittest.cc
+++ b/extensions/browser/lazy_background_task_queue_unittest.cc
@@ -151,17 +151,19 @@
   // doesn't run the task.
   const LazyContextId no_background_context_id(browser_context(),
                                                no_background->id());
-  queue.AddPendingTask(no_background_context_id,
-                       base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
-                                  base::Unretained(this)));
+  queue.AddPendingTask(
+      no_background_context_id,
+      base::BindOnce(&LazyBackgroundTaskQueueTest::RunPendingTask,
+                     base::Unretained(this)));
   EXPECT_EQ(1u, queue.pending_tasks_.size());
   EXPECT_EQ(0, task_run_count());
 
   // Another task on the same extension doesn't increase the number of
   // extensions that have tasks and doesn't run any tasks.
-  queue.AddPendingTask(no_background_context_id,
-                       base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
-                                  base::Unretained(this)));
+  queue.AddPendingTask(
+      no_background_context_id,
+      base::BindOnce(&LazyBackgroundTaskQueueTest::RunPendingTask,
+                     base::Unretained(this)));
   EXPECT_EQ(1u, queue.pending_tasks_.size());
   EXPECT_EQ(0, task_run_count());
 
@@ -171,9 +173,10 @@
       CreateLazyBackgroundExtension();
   const LazyContextId lazy_background_context_id(browser_context(),
                                                  lazy_background->id());
-  queue.AddPendingTask(lazy_background_context_id,
-                       base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
-                                  base::Unretained(this)));
+  queue.AddPendingTask(
+      lazy_background_context_id,
+      base::BindOnce(&LazyBackgroundTaskQueueTest::RunPendingTask,
+                     base::Unretained(this)));
   EXPECT_EQ(1u, queue.pending_tasks_.size());
   // The process manager tried to create a background host.
   EXPECT_EQ(1, process_manager()->create_count());
@@ -191,9 +194,10 @@
   EXPECT_EQ(0, task_run_count());
 
   // Schedule a task to run.
-  queue.AddPendingTask(LazyContextId(browser_context(), extension->id()),
-                       base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
-                                  base::Unretained(this)));
+  queue.AddPendingTask(
+      LazyContextId(browser_context(), extension->id()),
+      base::BindOnce(&LazyBackgroundTaskQueueTest::RunPendingTask,
+                     base::Unretained(this)));
   EXPECT_EQ(0, task_run_count());
   EXPECT_EQ(1u, queue.pending_tasks_.size());
 
@@ -226,9 +230,10 @@
   // Did not try to create a background host because there are no queued tasks.
   EXPECT_EQ(0, process_manager()->create_count());
 
-  queue.AddPendingTask(LazyContextId(browser_context(), lazy_background->id()),
-                       base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask,
-                                  base::Unretained(this)));
+  queue.AddPendingTask(
+      LazyContextId(browser_context(), lazy_background->id()),
+      base::BindOnce(&LazyBackgroundTaskQueueTest::RunPendingTask,
+                     base::Unretained(this)));
   EXPECT_EQ(1u, queue.pending_tasks_.size());
   // Did not try to create a background host because extension is not yet
   // loaded.
diff --git a/extensions/common/api/_manifest_features.json b/extensions/common/api/_manifest_features.json
index 159cbb5..8563424 100644
--- a/extensions/common/api/_manifest_features.json
+++ b/extensions/common/api/_manifest_features.json
@@ -113,12 +113,6 @@
     // app.content_security_policy whitelist).
     "extension_types": ["extension", "legacy_packaged_app"]
   },
-  "content_security_policy.extension_pages": {
-    // TODO(crbug.com/914224): Keep the channel in sync with the check in
-    // csp_info.cc.
-    "channel": "trunk",
-    "extension_types": ["extension"]
-  },
   "current_locale": {
     "channel": "stable",
     "extension_types": "all"
diff --git a/extensions/common/manifest_handlers/csp_info.cc b/extensions/common/manifest_handlers/csp_info.cc
index 1c33a84..7e5148b 100644
--- a/extensions/common/manifest_handlers/csp_info.cc
+++ b/extensions/common/manifest_handlers/csp_info.cc
@@ -119,68 +119,60 @@
 
 bool CSPHandler::Parse(Extension* extension, base::string16* error) {
   const std::string key = Keys()[0];
-  if (!extension->manifest()->HasPath(key))
-    return SetDefaultExtensionPagesCSP(extension);
-
   // The "content_security_policy" manifest key can either be a string or a
   // dictionary of the format
   // "content_security_policy" : {
   //     "extension_pages" : ""
   //  }
-  const base::DictionaryValue* csp_dict = nullptr;
-  std::string content_security_policy;
+  const base::Value* csp = nullptr;
+  bool result = extension->manifest()->Get(key, &csp);
+  DCHECK_EQ(result, !!csp);
 
   // TODO(crbug.com/914224): Remove the channel check once the support for the
   // dictionary key is launched to other channels.
   bool csp_dictionary_supported =
       !is_platform_app_ &&
       GetCurrentChannel() == version_info::Channel::UNKNOWN;
-  if (csp_dictionary_supported &&
-      extension->manifest()->GetDictionary(key, &csp_dict))
-    return ParseCSPDictionary(extension, error, *csp_dict);
+  if (csp_dictionary_supported && csp && csp->is_dict())
+    return ParseCSPDictionary(extension, error, *csp);
 
-  if (extension->manifest()->GetString(key, &content_security_policy)) {
-    return ParseExtensionPagesCSP(extension, error, key,
-                                  content_security_policy);
-  }
-
-  *error = GetInvalidManifestKeyError(key);
-  return false;
+  return ParseExtensionPagesCSP(extension, error, key, csp);
 }
 
 bool CSPHandler::ParseCSPDictionary(Extension* extension,
                                     base::string16* error,
                                     const base::Value& csp_dict) {
   DCHECK(csp_dict.is_dict());
-
-  auto* extension_pages_csp = csp_dict.FindKey(kExtensionPagesKey);
-  if (!extension_pages_csp)
-    return SetDefaultExtensionPagesCSP(extension);
-
-  if (!extension_pages_csp->is_string()) {
-    *error = GetInvalidManifestKeyError(kExtensionPagesPath);
-    return false;
-  }
-
   return ParseExtensionPagesCSP(extension, error, kExtensionPagesPath,
-                                extension_pages_csp->GetString());
+                                csp_dict.FindKey(kExtensionPagesKey));
 }
 
 bool CSPHandler::ParseExtensionPagesCSP(
     Extension* extension,
     base::string16* error,
     const std::string& manifest_key,
-    const std::string& content_security_policy) {
-  if (!ContentSecurityPolicyIsLegal(content_security_policy)) {
+    const base::Value* content_security_policy) {
+  if (!content_security_policy)
+    return SetDefaultExtensionPagesCSP(extension);
+
+  if (!content_security_policy->is_string()) {
     *error = GetInvalidManifestKeyError(manifest_key);
     return false;
   }
+
+  const std::string& content_security_policy_str =
+      content_security_policy->GetString();
+  if (!ContentSecurityPolicyIsLegal(content_security_policy_str)) {
+    *error = GetInvalidManifestKeyError(manifest_key);
+    return false;
+  }
+
   std::vector<InstallWarning> warnings;
   // TODO(crbug.com/914224): For manifest V3, instead of sanitizing the
   // extension provided csp value and raising install warnings, see if we want
   // to raise errors and prevent the extension from loading.
   std::string sanitized_content_security_policy = SanitizeContentSecurityPolicy(
-      content_security_policy, GetValidatorOptions(extension), &warnings);
+      content_security_policy_str, GetValidatorOptions(extension), &warnings);
   extension->AddInstallWarnings(std::move(warnings));
 
   extension->SetManifestData(
diff --git a/extensions/common/manifest_handlers/csp_info.h b/extensions/common/manifest_handlers/csp_info.h
index 2aea0af..5f5d0b0 100644
--- a/extensions/common/manifest_handlers/csp_info.h
+++ b/extensions/common/manifest_handlers/csp_info.h
@@ -53,7 +53,7 @@
   bool ParseExtensionPagesCSP(Extension* extension,
                               base::string16* error,
                               const std::string& manifest_key,
-                              const std::string& content_security_policy);
+                              const base::Value* content_security_policy);
 
   // Sets the default CSP value for the extension.
   bool SetDefaultExtensionPagesCSP(Extension* extension);
diff --git a/extensions/renderer/bindings/api_binding.cc b/extensions/renderer/bindings/api_binding.cc
index fee80bc..4d5eb7c 100644
--- a/extensions/renderer/bindings/api_binding.cc
+++ b/extensions/renderer/bindings/api_binding.cc
@@ -203,8 +203,8 @@
                        const base::ListValue* type_definitions,
                        const base::ListValue* event_definitions,
                        const base::DictionaryValue* property_definitions,
-                       const CreateCustomType& create_custom_type,
-                       const OnSilentRequest& on_silent_request,
+                       CreateCustomType create_custom_type,
+                       OnSilentRequest on_silent_request,
                        std::unique_ptr<APIBindingHooks> binding_hooks,
                        APITypeReferenceMap* type_refs,
                        APIRequestHandler* request_handler,
@@ -212,8 +212,8 @@
                        BindingAccessChecker* access_checker)
     : api_name_(api_name),
       property_definitions_(property_definitions),
-      create_custom_type_(create_custom_type),
-      on_silent_request_(on_silent_request),
+      create_custom_type_(std::move(create_custom_type)),
+      on_silent_request_(std::move(on_silent_request)),
       binding_hooks_(std::move(binding_hooks)),
       type_refs_(type_refs),
       request_handler_(request_handler),
@@ -417,8 +417,8 @@
     MethodData& method = *key_value.second;
     DCHECK(method.callback.is_null());
     method.callback =
-        base::Bind(&APIBinding::HandleCall, weak_factory_.GetWeakPtr(),
-                   method.full_name, method.signature, method.thread);
+        base::BindRepeating(&APIBinding::HandleCall, weak_factory_.GetWeakPtr(),
+                            method.full_name, method.signature, method.thread);
 
     object_template->Set(
         gin::StringToSymbol(isolate, key_value.first),
diff --git a/extensions/renderer/bindings/api_binding.h b/extensions/renderer/bindings/api_binding.h
index 8f896ec..c41ffe9 100644
--- a/extensions/renderer/bindings/api_binding.h
+++ b/extensions/renderer/bindings/api_binding.h
@@ -46,20 +46,20 @@
 // contexts.
 class APIBinding {
  public:
-  using CreateCustomType = base::Callback<v8::Local<v8::Object>(
+  using CreateCustomType = base::RepeatingCallback<v8::Local<v8::Object>(
       v8::Isolate* isolate,
       const std::string& type_name,
       const std::string& property_name,
       const base::ListValue* property_values)>;
 
   // Called when a request is handled without notifying the browser.
-  using OnSilentRequest =
-      base::Callback<void(v8::Local<v8::Context>,
-                          const std::string& name,
-                          const std::vector<v8::Local<v8::Value>>& arguments)>;
+  using OnSilentRequest = base::RepeatingCallback<void(
+      v8::Local<v8::Context>,
+      const std::string& name,
+      const std::vector<v8::Local<v8::Value>>& arguments)>;
 
   // The callback type for handling an API call.
-  using HandlerCallback = base::Callback<void(gin::Arguments*)>;
+  using HandlerCallback = base::RepeatingCallback<void(gin::Arguments*)>;
 
   // The APITypeReferenceMap is required to outlive this object.
   // |function_definitions|, |type_definitions| and |event_definitions|
@@ -69,8 +69,8 @@
              const base::ListValue* type_definitions,
              const base::ListValue* event_definitions,
              const base::DictionaryValue* property_definitions,
-             const CreateCustomType& create_custom_type,
-             const OnSilentRequest& on_silent_request,
+             CreateCustomType create_custom_type,
+             OnSilentRequest on_silent_request,
              std::unique_ptr<APIBindingHooks> binding_hooks,
              APITypeReferenceMap* type_refs,
              APIRequestHandler* request_handler,
diff --git a/extensions/renderer/bindings/api_binding_hooks_test_delegate.cc b/extensions/renderer/bindings/api_binding_hooks_test_delegate.cc
index d153e81..a175c70 100644
--- a/extensions/renderer/bindings/api_binding_hooks_test_delegate.cc
+++ b/extensions/renderer/bindings/api_binding_hooks_test_delegate.cc
@@ -21,23 +21,23 @@
 }
 
 void APIBindingHooksTestDelegate::AddHandler(base::StringPiece name,
-                                             const RequestHandler& handler) {
-  request_handlers_[name.as_string()] = handler;
+                                             RequestHandler handler) {
+  request_handlers_[name.as_string()] = std::move(handler);
 }
 
 void APIBindingHooksTestDelegate::SetCustomEvent(
-    const CustomEventFactory& custom_event) {
-  custom_event_ = custom_event;
+    CustomEventFactory custom_event) {
+  custom_event_ = std::move(custom_event);
 }
 
 void APIBindingHooksTestDelegate::SetTemplateInitializer(
-    const TemplateInitializer& initializer) {
-  template_initializer_ = initializer;
+    TemplateInitializer initializer) {
+  template_initializer_ = std::move(initializer);
 }
 
 void APIBindingHooksTestDelegate::SetInstanceInitializer(
-    const InstanceInitializer& initializer) {
-  instance_initializer_ = initializer;
+    InstanceInitializer initializer) {
+  instance_initializer_ = std::move(initializer);
 }
 
 APIBindingHooks::RequestResult APIBindingHooksTestDelegate::HandleRequest(
diff --git a/extensions/renderer/bindings/api_binding_hooks_test_delegate.h b/extensions/renderer/bindings/api_binding_hooks_test_delegate.h
index c1b7391..281cbe7 100644
--- a/extensions/renderer/bindings/api_binding_hooks_test_delegate.h
+++ b/extensions/renderer/bindings/api_binding_hooks_test_delegate.h
@@ -22,32 +22,34 @@
   APIBindingHooksTestDelegate();
   ~APIBindingHooksTestDelegate() override;
 
-  using CustomEventFactory = base::Callback<v8::Local<v8::Value>(
+  using CustomEventFactory = base::RepeatingCallback<v8::Local<v8::Value>(
       v8::Local<v8::Context>,
       const std::string& event_name)>;
 
-  using RequestHandler = base::Callback<APIBindingHooks::RequestResult(
+  using RequestHandler = base::RepeatingCallback<APIBindingHooks::RequestResult(
       const APISignature*,
       v8::Local<v8::Context> context,
       std::vector<v8::Local<v8::Value>>*,
       const APITypeReferenceMap&)>;
 
-  using TemplateInitializer = base::Callback<void(v8::Isolate*,
-                                                  v8::Local<v8::ObjectTemplate>,
-                                                  const APITypeReferenceMap&)>;
+  using TemplateInitializer =
+      base::RepeatingCallback<void(v8::Isolate*,
+                                   v8::Local<v8::ObjectTemplate>,
+                                   const APITypeReferenceMap&)>;
 
   using InstanceInitializer =
-      base::Callback<void(v8::Local<v8::Context>, v8::Local<v8::Object>)>;
+      base::RepeatingCallback<void(v8::Local<v8::Context>,
+                                   v8::Local<v8::Object>)>;
 
   // Adds a custom |handler| for the method with the given |name|.
-  void AddHandler(base::StringPiece name, const RequestHandler& handler);
+  void AddHandler(base::StringPiece name, RequestHandler handler);
 
   // Creates events with the given factory.
-  void SetCustomEvent(const CustomEventFactory& custom_event);
+  void SetCustomEvent(CustomEventFactory custom_event);
 
-  void SetTemplateInitializer(const TemplateInitializer& initializer);
+  void SetTemplateInitializer(TemplateInitializer initializer);
 
-  void SetInstanceInitializer(const InstanceInitializer& initializer);
+  void SetInstanceInitializer(InstanceInitializer initializer);
 
   // APIBindingHooksDelegate:
   bool CreateCustomEvent(v8::Local<v8::Context> context,
diff --git a/extensions/renderer/bindings/api_binding_types.h b/extensions/renderer/bindings/api_binding_types.h
index 63041f2c..18ead725 100644
--- a/extensions/renderer/bindings/api_binding_types.h
+++ b/extensions/renderer/bindings/api_binding_types.h
@@ -51,8 +51,8 @@
 };
 
 // Adds an error message to the context's console.
-using AddConsoleError =
-    base::Callback<void(v8::Local<v8::Context>, const std::string& error)>;
+using AddConsoleError = base::RepeatingCallback<void(v8::Local<v8::Context>,
+                                                     const std::string& error)>;
 
 }  // namespace binding
 }  // namespace extensions
diff --git a/extensions/renderer/bindings/api_binding_unittest.cc b/extensions/renderer/bindings/api_binding_unittest.cc
index fb377da..4565825 100644
--- a/extensions/renderer/bindings/api_binding_unittest.cc
+++ b/extensions/renderer/bindings/api_binding_unittest.cc
@@ -198,12 +198,12 @@
     if (!on_silent_request_)
       on_silent_request_ = base::DoNothing();
     if (!availability_callback_)
-      availability_callback_ = base::Bind(&AllowAllFeatures);
+      availability_callback_ = base::BindRepeating(&AllowAllFeatures);
     auto get_context_owner = [](v8::Local<v8::Context>) {
       return std::string("context");
     };
     event_handler_ = std::make_unique<APIEventHandler>(
-        base::Bind(&OnEventListenersChanged),
+        base::BindRepeating(&OnEventListenersChanged),
         base::BindRepeating(get_context_owner), nullptr);
     access_checker_ =
         std::make_unique<BindingAccessChecker>(availability_callback_);
@@ -551,7 +551,7 @@
     EXPECT_TRUE(allowed.count(name) || restricted.count(name)) << name;
     return allowed.count(name) != 0;
   };
-  SetAvailabilityCallback(base::Bind(is_available));
+  SetAvailabilityCallback(base::BindRepeating(is_available));
 
   InitializeBinding();
 
@@ -712,7 +712,7 @@
     return result;
   };
 
-  SetCreateCustomType(base::Bind(create_custom_type));
+  SetCreateCustomType(base::BindRepeating(create_custom_type));
 
   InitializeBinding();
 
@@ -811,7 +811,7 @@
     EXPECT_EQ("foo", gin::V8ToString(context->GetIsolate(), arguments->at(0)));
     return result;
   };
-  hooks->AddHandler("test.oneString", base::Bind(hook, &did_call));
+  hooks->AddHandler("test.oneString", base::BindRepeating(hook, &did_call));
   SetHooksDelegate(std::move(hooks));
 
   InitializeBinding();
@@ -1082,7 +1082,7 @@
         gin::StringToV8(context->GetIsolate(), arg_value + " pong");
     return result;
   };
-  hooks->AddHandler("test.oneString", base::Bind(hook, &did_call));
+  hooks->AddHandler("test.oneString", base::BindRepeating(hook, &did_call));
 
   SetHooksDelegate(std::move(hooks));
   SetFunctions(kFunctions);
@@ -1301,7 +1301,7 @@
     object_template->Set(gin::StringToSymbol(isolate, "hookedProperty"),
                          gin::ConvertToV8(isolate, 42));
   };
-  hooks->SetTemplateInitializer(base::Bind(hook));
+  hooks->SetTemplateInitializer(base::BindRepeating(hook));
   SetHooksDelegate(std::move(hooks));
 
   InitializeBinding();
@@ -1338,7 +1338,7 @@
     }
   };
 
-  hooks->SetInstanceInitializer(base::Bind(hook, &count));
+  hooks->SetInstanceInitializer(base::BindRepeating(hook, &count));
   SetHooksDelegate(std::move(hooks));
 
   InitializeBinding();
@@ -1413,28 +1413,31 @@
   auto hooks = std::make_unique<APIBindingHooksTestDelegate>();
   hooks->AddHandler(
       "test.modifyArgs",
-      base::Bind(basic_handler, RequestResult::ARGUMENTS_UPDATED));
+      base::BindRepeating(basic_handler, RequestResult::ARGUMENTS_UPDATED));
   hooks->AddHandler(
       "test.invalidInvocation",
-      base::Bind(basic_handler, RequestResult::INVALID_INVOCATION));
-  hooks->AddHandler("test.dontHandle",
-                    base::Bind(basic_handler, RequestResult::NOT_HANDLED));
+      base::BindRepeating(basic_handler, RequestResult::INVALID_INVOCATION));
+  hooks->AddHandler(
+      "test.dontHandle",
+      base::BindRepeating(basic_handler, RequestResult::NOT_HANDLED));
   hooks->AddHandler("test.handle",
-                    base::Bind(basic_handler, RequestResult::HANDLED));
+                    base::BindRepeating(basic_handler, RequestResult::HANDLED));
   hooks->AddHandler(
       "test.throwException",
-      base::Bind([](const APISignature*, v8::Local<v8::Context> context,
-                    std::vector<v8::Local<v8::Value>>* arguments,
-                    const APITypeReferenceMap& map) {
+      base::BindRepeating([](const APISignature*,
+                             v8::Local<v8::Context> context,
+                             std::vector<v8::Local<v8::Value>>* arguments,
+                             const APITypeReferenceMap& map) {
         context->GetIsolate()->ThrowException(
             gin::StringToV8(context->GetIsolate(), "some error"));
         return RequestResult(RequestResult::THROWN);
       }));
   hooks->AddHandler(
       "test.handleWithArgs",
-      base::Bind([](const APISignature*, v8::Local<v8::Context> context,
-                    std::vector<v8::Local<v8::Value>>* arguments,
-                    const APITypeReferenceMap& map) {
+      base::BindRepeating([](const APISignature*,
+                             v8::Local<v8::Context> context,
+                             std::vector<v8::Local<v8::Value>>* arguments,
+                             const APITypeReferenceMap& map) {
         arguments->push_back(v8::Integer::New(context->GetIsolate(), 42));
         return RequestResult(RequestResult::HANDLED);
       }));
@@ -1450,8 +1453,9 @@
             v8::Local<v8::Function>(), binding::RequestThread::UI);
         return RequestResult(RequestResult::HANDLED);
       };
-  hooks->AddHandler("test.handleAndSendRequest",
-                    base::Bind(handle_and_send_request, request_handler()));
+  hooks->AddHandler(
+      "test.handleAndSendRequest",
+      base::BindRepeating(handle_and_send_request, request_handler()));
 
   SetHooksDelegate(std::move(hooks));
 
@@ -1468,8 +1472,8 @@
       };
   base::Optional<std::string> silent_request;
   base::Optional<std::vector<std::string>> request_arguments;
-  SetOnSilentRequest(
-      base::Bind(on_silent_request, &silent_request, &request_arguments));
+  SetOnSilentRequest(base::BindRepeating(on_silent_request, &silent_request,
+                                         &request_arguments));
 
   InitializeBinding();
 
@@ -1571,7 +1575,8 @@
             APIBindingHooks::RequestResult::NOT_HANDLED, custom_callback);
         return result;
       };
-  hooks->AddHandler("test.oneString", base::Bind(hook_with_custom_callback));
+  hooks->AddHandler("test.oneString",
+                    base::BindRepeating(hook_with_custom_callback));
   SetHooksDelegate(std::move(hooks));
 
   InitializeBinding();
diff --git a/extensions/renderer/bindings/api_bindings_system.cc b/extensions/renderer/bindings/api_bindings_system.cc
index 9743c0c..64061ff 100644
--- a/extensions/renderer/bindings/api_bindings_system.cc
+++ b/extensions/renderer/bindings/api_bindings_system.cc
@@ -13,29 +13,30 @@
 namespace extensions {
 
 APIBindingsSystem::APIBindingsSystem(
-    const GetAPISchemaMethod& get_api_schema,
-    const BindingAccessChecker::AvailabilityCallback& is_available,
-    const APIRequestHandler::SendRequestMethod& send_request,
-    const APIRequestHandler::GetUserActivationState&
+    GetAPISchemaMethod get_api_schema,
+    BindingAccessChecker::AvailabilityCallback is_available,
+    APIRequestHandler::SendRequestMethod send_request,
+    APIRequestHandler::GetUserActivationState
         get_user_activation_state_callback,
-    const APIEventListeners::ListenersUpdated& event_listeners_changed,
-    const APIEventHandler::ContextOwnerIdGetter& context_owner_getter,
-    const APIBinding::OnSilentRequest& on_silent_request,
-    const binding::AddConsoleError& add_console_error,
+    APIEventListeners::ListenersUpdated event_listeners_changed,
+    APIEventHandler::ContextOwnerIdGetter context_owner_getter,
+    APIBinding::OnSilentRequest on_silent_request,
+    binding::AddConsoleError add_console_error,
     APILastError last_error)
-    : type_reference_map_(base::Bind(&APIBindingsSystem::InitializeType,
-                                     base::Unretained(this))),
-      exception_handler_(add_console_error),
-      request_handler_(send_request,
+    : type_reference_map_(
+          base::BindRepeating(&APIBindingsSystem::InitializeType,
+                              base::Unretained(this))),
+      exception_handler_(std::move(add_console_error)),
+      request_handler_(std::move(send_request),
                        std::move(last_error),
                        &exception_handler_,
-                       get_user_activation_state_callback),
-      event_handler_(event_listeners_changed,
-                     context_owner_getter,
+                       std::move(get_user_activation_state_callback)),
+      event_handler_(std::move(event_listeners_changed),
+                     std::move(context_owner_getter),
                      &exception_handler_),
-      access_checker_(is_available),
-      get_api_schema_(get_api_schema),
-      on_silent_request_(on_silent_request) {
+      access_checker_(std::move(is_available)),
+      get_api_schema_(std::move(get_api_schema)),
+      on_silent_request_(std::move(on_silent_request)) {
   if (binding::IsResponseValidationEnabled()) {
     request_handler_.SetResponseValidator(
         std::make_unique<APIResponseValidator>(&type_reference_map_));
@@ -85,7 +86,8 @@
   return std::make_unique<APIBinding>(
       api_name, function_definitions, type_definitions, event_definitions,
       property_definitions,
-      base::Bind(&APIBindingsSystem::CreateCustomType, base::Unretained(this)),
+      base::BindRepeating(&APIBindingsSystem::CreateCustomType,
+                          base::Unretained(this)),
       on_silent_request_, std::move(hooks), &type_reference_map_,
       &request_handler_, &event_handler_, &access_checker_);
 }
@@ -133,10 +135,10 @@
 }
 
 void APIBindingsSystem::RegisterCustomType(const std::string& type_name,
-                                           const CustomTypeHandler& function) {
+                                           CustomTypeHandler function) {
   DCHECK(custom_types_.find(type_name) == custom_types_.end())
       << "Custom type already registered: " << type_name;
-  custom_types_[type_name] = function;
+  custom_types_[type_name] = std::move(function);
 }
 
 void APIBindingsSystem::WillReleaseContext(v8::Local<v8::Context> context) {
diff --git a/extensions/renderer/bindings/api_bindings_system.h b/extensions/renderer/bindings/api_bindings_system.h
index b70a0ef1..833f1a5b 100644
--- a/extensions/renderer/bindings/api_bindings_system.h
+++ b/extensions/renderer/bindings/api_bindings_system.h
@@ -34,8 +34,8 @@
 class APIBindingsSystem {
  public:
   using GetAPISchemaMethod =
-      base::Callback<const base::DictionaryValue&(const std::string&)>;
-  using CustomTypeHandler = base::Callback<v8::Local<v8::Object>(
+      base::RepeatingCallback<const base::DictionaryValue&(const std::string&)>;
+  using CustomTypeHandler = base::RepeatingCallback<v8::Local<v8::Object>(
       v8::Isolate* isolate,
       const std::string& property_name,
       const base::ListValue* property_values,
@@ -44,17 +44,16 @@
       APITypeReferenceMap* type_refs,
       const BindingAccessChecker* access_checker)>;
 
-  APIBindingsSystem(
-      const GetAPISchemaMethod& get_api_schema,
-      const BindingAccessChecker::AvailabilityCallback& is_available,
-      const APIRequestHandler::SendRequestMethod& send_request,
-      const APIRequestHandler::GetUserActivationState&
-          get_user_activation_state_callback,
-      const APIEventListeners::ListenersUpdated& event_listeners_changed,
-      const APIEventHandler::ContextOwnerIdGetter& context_owner_getter,
-      const APIBinding::OnSilentRequest& on_silent_request,
-      const binding::AddConsoleError& add_console_error,
-      APILastError last_error);
+  APIBindingsSystem(GetAPISchemaMethod get_api_schema,
+                    BindingAccessChecker::AvailabilityCallback is_available,
+                    APIRequestHandler::SendRequestMethod send_request,
+                    APIRequestHandler::GetUserActivationState
+                        get_user_activation_state_callback,
+                    APIEventListeners::ListenersUpdated event_listeners_changed,
+                    APIEventHandler::ContextOwnerIdGetter context_owner_getter,
+                    APIBinding::OnSilentRequest on_silent_request,
+                    binding::AddConsoleError add_console_error,
+                    APILastError last_error);
   ~APIBindingsSystem();
 
   // Returns a new v8::Object representing the api specified by |api_name|.
@@ -89,7 +88,7 @@
   // |type_name|, where |type_name| is the fully-qualified type (e.g.
   // storage.StorageArea).
   void RegisterCustomType(const std::string& type_name,
-                          const CustomTypeHandler& function);
+                          CustomTypeHandler function);
 
   // Handles any cleanup necessary before releasing the given |context|.
   void WillReleaseContext(v8::Local<v8::Context> context);
diff --git a/extensions/renderer/bindings/api_bindings_system_unittest.cc b/extensions/renderer/bindings/api_bindings_system_unittest.cc
index d5b27f4..0df93d7 100644
--- a/extensions/renderer/bindings/api_bindings_system_unittest.cc
+++ b/extensions/renderer/bindings/api_bindings_system_unittest.cc
@@ -109,7 +109,7 @@
     api_schemas_[api.name] = std::move(api_schema);
   }
 
-  binding::AddConsoleError add_console_error(base::Bind(
+  binding::AddConsoleError add_console_error(base::BindRepeating(
       &APIBindingsSystemTest::AddConsoleError, base::Unretained(this)));
   auto get_context_owner = [](v8::Local<v8::Context>) {
     return std::string("context");
@@ -125,9 +125,10 @@
                           base::Unretained(this)),
       base::BindRepeating(get_context_owner), base::DoNothing(),
       add_console_error,
-      APILastError(base::Bind(&APIBindingsSystemTest::GetLastErrorParent,
+      APILastError(
+          base::BindRepeating(&APIBindingsSystemTest::GetLastErrorParent,
                               base::Unretained(this)),
-                   add_console_error));
+          add_console_error));
 }
 
 void APIBindingsSystemTest::TearDown() {
@@ -341,7 +342,7 @@
 
   auto test_hooks = std::make_unique<APIBindingHooksTestDelegate>();
   test_hooks->AddHandler("alpha.functionWithCallback",
-                         base::Bind(hook, &did_call));
+                         base::BindRepeating(hook, &did_call));
   APIBindingHooks* binding_hooks =
       bindings_system()->GetHooksForAPI(kAlphaAPIName);
   binding_hooks->SetDelegate(std::move(test_hooks));
@@ -455,7 +456,7 @@
   };
 
   auto test_hooks = std::make_unique<APIBindingHooksTestDelegate>();
-  test_hooks->SetCustomEvent(base::Bind(create_custom_event));
+  test_hooks->SetCustomEvent(base::BindRepeating(create_custom_event));
   APIBindingHooks* binding_hooks =
       bindings_system()->GetHooksForAPI(kAlphaAPIName);
   binding_hooks->SetDelegate(std::move(test_hooks));
diff --git a/extensions/renderer/bindings/api_event_handler_unittest.cc b/extensions/renderer/bindings/api_event_handler_unittest.cc
index b16d93e..92b06ad 100644
--- a/extensions/renderer/bindings/api_event_handler_unittest.cc
+++ b/extensions/renderer/bindings/api_event_handler_unittest.cc
@@ -551,7 +551,8 @@
          const std::string& error) { errors_out->push_back(error); };
 
   std::vector<std::string> logged_errors;
-  ExceptionHandler exception_handler(base::Bind(log_error, &logged_errors));
+  ExceptionHandler exception_handler(
+      base::BindRepeating(log_error, &logged_errors));
   SetHandler(std::make_unique<APIEventHandler>(
       base::DoNothing(), base::BindRepeating(&GetContextOwner),
       &exception_handler));
@@ -1018,7 +1019,7 @@
          const base::DictionaryValue* filter, bool was_manual,
          v8::Local<v8::Context> context) { ADD_FAILURE(); };
 
-  APIEventHandler handler(base::Bind(fail_on_notified),
+  APIEventHandler handler(base::BindRepeating(fail_on_notified),
                           base::BindRepeating(&GetContextOwner), nullptr);
 
   const char kEventName[] = "alpha";
diff --git a/extensions/renderer/bindings/api_event_listeners.cc b/extensions/renderer/bindings/api_event_listeners.cc
index e714cac..6f41e0b96 100644
--- a/extensions/renderer/bindings/api_event_listeners.cc
+++ b/extensions/renderer/bindings/api_event_listeners.cc
@@ -77,15 +77,15 @@
 }  // namespace
 
 UnfilteredEventListeners::UnfilteredEventListeners(
-    const ListenersUpdated& listeners_updated,
+    ListenersUpdated listeners_updated,
     const std::string& event_name,
-    const ContextOwnerIdGetter& context_owner_id_getter,
+    ContextOwnerIdGetter context_owner_id_getter,
     int max_listeners,
     bool supports_lazy_listeners,
     ListenerTracker* listener_tracker)
-    : listeners_updated_(listeners_updated),
+    : listeners_updated_(std::move(listeners_updated)),
       event_name_(event_name),
-      context_owner_id_getter_(context_owner_id_getter),
+      context_owner_id_getter_(std::move(context_owner_id_getter)),
       max_listeners_(max_listeners),
       supports_lazy_listeners_(supports_lazy_listeners),
       listener_tracker_(listener_tracker) {
@@ -227,15 +227,15 @@
 };
 
 FilteredEventListeners::FilteredEventListeners(
-    const ListenersUpdated& listeners_updated,
+    ListenersUpdated listeners_updated,
     const std::string& event_name,
-    const ContextOwnerIdGetter& context_owner_id_getter,
+    ContextOwnerIdGetter context_owner_id_getter,
     int max_listeners,
     bool supports_lazy_listeners,
     ListenerTracker* listener_tracker)
-    : listeners_updated_(listeners_updated),
+    : listeners_updated_(std::move(listeners_updated)),
       event_name_(event_name),
-      context_owner_id_getter_(context_owner_id_getter),
+      context_owner_id_getter_(std::move(context_owner_id_getter)),
       max_listeners_(max_listeners),
       supports_lazy_listeners_(supports_lazy_listeners),
       listener_tracker_(listener_tracker) {
diff --git a/extensions/renderer/bindings/api_event_listeners.h b/extensions/renderer/bindings/api_event_listeners.h
index 63d6932..c4db441 100644
--- a/extensions/renderer/bindings/api_event_listeners.h
+++ b/extensions/renderer/bindings/api_event_listeners.h
@@ -32,11 +32,11 @@
   // change was "manual" (i.e., triggered by a direct call from the extension
   // rather than something like the context being destroyed).
   using ListenersUpdated =
-      base::Callback<void(const std::string& event_name,
-                          binding::EventListenersChanged,
-                          const base::DictionaryValue* filter,
-                          bool update_lazy_listeners,
-                          v8::Local<v8::Context> context)>;
+      base::RepeatingCallback<void(const std::string& event_name,
+                                   binding::EventListenersChanged,
+                                   const base::DictionaryValue* filter,
+                                   bool update_lazy_listeners,
+                                   v8::Local<v8::Context> context)>;
 
   // A callback to retrieve the identity of the context's owner. This allows us
   // to associate multiple listeners from different v8::Contexts with the same
@@ -90,9 +90,9 @@
 // dispatched is dispatched to all the associated listeners.
 class UnfilteredEventListeners final : public APIEventListeners {
  public:
-  UnfilteredEventListeners(const ListenersUpdated& listeners_updated,
+  UnfilteredEventListeners(ListenersUpdated listeners_updated,
                            const std::string& event_name,
-                           const ContextOwnerIdGetter& context_owner_id_getter,
+                           ContextOwnerIdGetter context_owner_id_getter,
                            int max_listeners,
                            bool supports_lazy_listeners,
                            ListenerTracker* listener_tracker);
@@ -163,9 +163,9 @@
 // added, or the last listener with a given filter is removed.
 class FilteredEventListeners final : public APIEventListeners {
  public:
-  FilteredEventListeners(const ListenersUpdated& listeners_updated,
+  FilteredEventListeners(ListenersUpdated listeners_updated,
                          const std::string& event_name,
-                         const ContextOwnerIdGetter& context_owner_id_getter,
+                         ContextOwnerIdGetter context_owner_id_getter,
                          int max_listeners,
                          bool supports_lazy_listeners,
                          ListenerTracker* listener_tracker);
diff --git a/extensions/renderer/bindings/api_last_error.cc b/extensions/renderer/bindings/api_last_error.cc
index c347361..3a71c69 100644
--- a/extensions/renderer/bindings/api_last_error.cc
+++ b/extensions/renderer/bindings/api_last_error.cc
@@ -113,9 +113,10 @@
 
 }  // namespace
 
-APILastError::APILastError(const GetParent& get_parent,
-                           const binding::AddConsoleError& add_console_error)
-    : get_parent_(get_parent), add_console_error_(add_console_error) {}
+APILastError::APILastError(GetParent get_parent,
+                           binding::AddConsoleError add_console_error)
+    : get_parent_(std::move(get_parent)),
+      add_console_error_(std::move(add_console_error)) {}
 APILastError::APILastError(APILastError&& other) = default;
 APILastError::~APILastError() = default;
 
diff --git a/extensions/renderer/bindings/api_last_error.h b/extensions/renderer/bindings/api_last_error.h
index 3eb72df5..ba24cf6 100644
--- a/extensions/renderer/bindings/api_last_error.h
+++ b/extensions/renderer/bindings/api_last_error.h
@@ -24,12 +24,12 @@
   // a simple object without getters/setters. This is to accommodate the
   // legacy chrome.extension.lastError property.
   // Note: |secondary_parent| may be null.
-  using GetParent = base::Callback<v8::Local<v8::Object>(
+  using GetParent = base::RepeatingCallback<v8::Local<v8::Object>(
       v8::Local<v8::Context>,
       v8::Local<v8::Object>* secondary_parent)>;
 
-  APILastError(const GetParent& get_parent,
-               const binding::AddConsoleError& add_console_error);
+  APILastError(GetParent get_parent,
+               binding::AddConsoleError add_console_error);
   APILastError(APILastError&& other);
   ~APILastError();
 
diff --git a/extensions/renderer/bindings/api_last_error_unittest.cc b/extensions/renderer/bindings/api_last_error_unittest.cc
index 3d15cdca..a47cd83 100644
--- a/extensions/renderer/bindings/api_last_error_unittest.cc
+++ b/extensions/renderer/bindings/api_last_error_unittest.cc
@@ -61,7 +61,8 @@
   v8::Local<v8::Object> parent_object = v8::Object::New(isolate());
 
   ParentList parents = {{context, parent_object}};
-  APILastError last_error(base::Bind(&GetParent, parents), base::DoNothing());
+  APILastError last_error(base::BindRepeating(&GetParent, parents),
+                          base::DoNothing());
 
   EXPECT_FALSE(last_error.HasError(context));
   EXPECT_EQ("undefined", GetLastErrorMessage(parent_object, context));
@@ -95,8 +96,8 @@
                       const std::string& error) { *console_error = error; };
 
   ParentList parents = {{context, parent_object}};
-  APILastError last_error(base::Bind(&GetParent, parents),
-                          base::Bind(log_error, &console_error));
+  APILastError last_error(base::BindRepeating(&GetParent, parents),
+                          base::BindRepeating(log_error, &console_error));
 
   {
     v8::TryCatch try_catch(isolate());
@@ -195,7 +196,8 @@
   v8::Local<v8::Object> parent_object = v8::Object::New(isolate());
 
   ParentList parents = {{context, parent_object}};
-  APILastError last_error(base::Bind(&GetParent, parents), base::DoNothing());
+  APILastError last_error(base::BindRepeating(&GetParent, parents),
+                          base::DoNothing());
 
   auto checked_set = [context](v8::Local<v8::Object> object,
                                base::StringPiece key,
@@ -238,7 +240,8 @@
   v8::Local<v8::Object> parent_a = v8::Object::New(isolate());
   v8::Local<v8::Object> parent_b = v8::Object::New(isolate());
   ParentList parents = {{context_a, parent_a}, {context_b, parent_b}};
-  APILastError last_error(base::Bind(&GetParent, parents), base::DoNothing());
+  APILastError last_error(base::BindRepeating(&GetParent, parents),
+                          base::DoNothing());
 
   last_error.SetError(context_a, "Last error a");
   EXPECT_EQ("\"Last error a\"", GetLastErrorMessage(parent_a, context_a));
@@ -278,8 +281,8 @@
   v8::Local<v8::Object> secondary_parent = v8::Object::New(isolate());
 
   APILastError last_error(
-      base::Bind(get_parents, primary_parent, secondary_parent),
-      base::Bind(log_error, &console_error));
+      base::BindRepeating(get_parents, primary_parent, secondary_parent),
+      base::BindRepeating(log_error, &console_error));
 
   last_error.SetError(context, "error");
   EXPECT_TRUE(last_error.HasError(context));
diff --git a/extensions/renderer/bindings/api_request_handler.cc b/extensions/renderer/bindings/api_request_handler.cc
index abe07b3..f98de6e2 100644
--- a/extensions/renderer/bindings/api_request_handler.cc
+++ b/extensions/renderer/bindings/api_request_handler.cc
@@ -98,14 +98,15 @@
     PendingRequest&&) = default;
 
 APIRequestHandler::APIRequestHandler(
-    const SendRequestMethod& send_request,
+    SendRequestMethod send_request,
     APILastError last_error,
     ExceptionHandler* exception_handler,
-    const GetUserActivationState& get_user_activation_state_callback)
-    : send_request_(send_request),
+    GetUserActivationState get_user_activation_state_callback)
+    : send_request_(std::move(send_request)),
       last_error_(std::move(last_error)),
       exception_handler_(exception_handler),
-      get_user_activation_state_callback_(get_user_activation_state_callback) {}
+      get_user_activation_state_callback_(
+          std::move(get_user_activation_state_callback)) {}
 
 APIRequestHandler::~APIRequestHandler() {}
 
diff --git a/extensions/renderer/bindings/api_request_handler.h b/extensions/renderer/bindings/api_request_handler.h
index 74e3cc4d..a273a4bec 100644
--- a/extensions/renderer/bindings/api_request_handler.h
+++ b/extensions/renderer/bindings/api_request_handler.h
@@ -48,16 +48,16 @@
   };
 
   using SendRequestMethod =
-      base::Callback<void(std::unique_ptr<Request>, v8::Local<v8::Context>)>;
+      base::RepeatingCallback<void(std::unique_ptr<Request>,
+                                   v8::Local<v8::Context>)>;
 
   using GetUserActivationState =
       base::RepeatingCallback<bool(v8::Local<v8::Context>)>;
 
-  APIRequestHandler(
-      const SendRequestMethod& send_request,
-      APILastError last_error,
-      ExceptionHandler* exception_handler,
-      const GetUserActivationState& get_user_activation_state_callback);
+  APIRequestHandler(SendRequestMethod send_request,
+                    APILastError last_error,
+                    ExceptionHandler* exception_handler,
+                    GetUserActivationState get_user_activation_state_callback);
   ~APIRequestHandler();
 
   // Begins the process of processing the request. Returns the identifier of the
diff --git a/extensions/renderer/bindings/api_type_reference_map.cc b/extensions/renderer/bindings/api_type_reference_map.cc
index 94bb4e80..62430e7 100644
--- a/extensions/renderer/bindings/api_type_reference_map.cc
+++ b/extensions/renderer/bindings/api_type_reference_map.cc
@@ -9,9 +9,8 @@
 
 namespace extensions {
 
-APITypeReferenceMap::APITypeReferenceMap(
-    const InitializeTypeCallback& initialize_type)
-    : initialize_type_(initialize_type) {}
+APITypeReferenceMap::APITypeReferenceMap(InitializeTypeCallback initialize_type)
+    : initialize_type_(std::move(initialize_type)) {}
 APITypeReferenceMap::~APITypeReferenceMap() = default;
 
 void APITypeReferenceMap::AddSpec(const std::string& name,
diff --git a/extensions/renderer/bindings/api_type_reference_map.h b/extensions/renderer/bindings/api_type_reference_map.h
index 9575edca..98944c0 100644
--- a/extensions/renderer/bindings/api_type_reference_map.h
+++ b/extensions/renderer/bindings/api_type_reference_map.h
@@ -21,9 +21,10 @@
  public:
   // A callback used to initialize an unknown type, so that these can be
   // created lazily.
-  using InitializeTypeCallback = base::Callback<void(const std::string& name)>;
+  using InitializeTypeCallback =
+      base::RepeatingCallback<void(const std::string& name)>;
 
-  explicit APITypeReferenceMap(const InitializeTypeCallback& initialize_type);
+  explicit APITypeReferenceMap(InitializeTypeCallback initialize_type);
   ~APITypeReferenceMap();
 
   // Adds the |spec| to the map under the given |name|.
diff --git a/extensions/renderer/bindings/binding_access_checker.cc b/extensions/renderer/bindings/binding_access_checker.cc
index 8f0fd55..9707645a 100644
--- a/extensions/renderer/bindings/binding_access_checker.cc
+++ b/extensions/renderer/bindings/binding_access_checker.cc
@@ -9,9 +9,8 @@
 
 namespace extensions {
 
-BindingAccessChecker::BindingAccessChecker(
-    const AvailabilityCallback& is_available)
-    : is_available_(is_available) {}
+BindingAccessChecker::BindingAccessChecker(AvailabilityCallback is_available)
+    : is_available_(std::move(is_available)) {}
 BindingAccessChecker::~BindingAccessChecker() {}
 
 bool BindingAccessChecker::HasAccess(v8::Local<v8::Context> context,
diff --git a/extensions/renderer/bindings/binding_access_checker.h b/extensions/renderer/bindings/binding_access_checker.h
index 7f9ccc25..e8e0685 100644
--- a/extensions/renderer/bindings/binding_access_checker.h
+++ b/extensions/renderer/bindings/binding_access_checker.h
@@ -19,9 +19,10 @@
   // The callback for determining if a given API feature (specified by |name|)
   // is available in the given context.
   using AvailabilityCallback =
-      base::Callback<bool(v8::Local<v8::Context>, const std::string& name)>;
+      base::RepeatingCallback<bool(v8::Local<v8::Context>,
+                                   const std::string& name)>;
 
-  BindingAccessChecker(const AvailabilityCallback& is_available);
+  BindingAccessChecker(AvailabilityCallback is_available);
   ~BindingAccessChecker();
 
   // Returns true if the feature specified by |full_name| is available to the
diff --git a/extensions/renderer/bindings/binding_access_checker_unittest.cc b/extensions/renderer/bindings/binding_access_checker_unittest.cc
index 4d40fe1..836c4503 100644
--- a/extensions/renderer/bindings/binding_access_checker_unittest.cc
+++ b/extensions/renderer/bindings/binding_access_checker_unittest.cc
@@ -25,7 +25,7 @@
 TEST_F(BindingAccessCheckerTest, TestHasAccess) {
   v8::HandleScope handle_scope(isolate());
 
-  BindingAccessChecker checker(base::Bind(&IsAvailable));
+  BindingAccessChecker checker(base::BindRepeating(&IsAvailable));
 
   v8::Local<v8::Context> context = MainContext();
   EXPECT_TRUE(checker.HasAccess(context, "available"));
@@ -35,7 +35,7 @@
 TEST_F(BindingAccessCheckerTest, TestHasAccessOrThrowError) {
   v8::HandleScope handle_scope(isolate());
 
-  BindingAccessChecker checker(base::Bind(&IsAvailable));
+  BindingAccessChecker checker(base::BindRepeating(&IsAvailable));
 
   v8::Local<v8::Context> context = MainContext();
   {
diff --git a/extensions/renderer/bindings/declarative_event_unittest.cc b/extensions/renderer/bindings/declarative_event_unittest.cc
index 97aa9675..48920a11 100644
--- a/extensions/renderer/bindings/declarative_event_unittest.cc
+++ b/extensions/renderer/bindings/declarative_event_unittest.cc
@@ -93,7 +93,8 @@
     }
 
     request_handler_ = std::make_unique<APIRequestHandler>(
-        base::Bind(&DeclarativeEventTest::OnRequest, base::Unretained(this)),
+        base::BindRepeating(&DeclarativeEventTest::OnRequest,
+                            base::Unretained(this)),
         APILastError(APILastError::GetParent(), binding::AddConsoleError()),
         nullptr, base::BindRepeating(&GetTestUserActivationState));
   }
diff --git a/extensions/renderer/bindings/event_emitter_unittest.cc b/extensions/renderer/bindings/event_emitter_unittest.cc
index f7cc5525..e86c12f2 100644
--- a/extensions/renderer/bindings/event_emitter_unittest.cc
+++ b/extensions/renderer/bindings/event_emitter_unittest.cc
@@ -60,7 +60,8 @@
                       const std::string& error) { errors->push_back(error); };
 
   std::vector<std::string> logged_errors;
-  ExceptionHandler exception_handler(base::Bind(log_error, &logged_errors));
+  ExceptionHandler exception_handler(
+      base::BindRepeating(log_error, &logged_errors));
 
   gin::Handle<EventEmitter> event = gin::CreateHandle(
       isolate(),
diff --git a/extensions/renderer/bindings/exception_handler_unittest.cc b/extensions/renderer/bindings/exception_handler_unittest.cc
index dfc3d7b..42a41100 100644
--- a/extensions/renderer/bindings/exception_handler_unittest.cc
+++ b/extensions/renderer/bindings/exception_handler_unittest.cc
@@ -46,7 +46,7 @@
   v8::Local<v8::Context> context = MainContext();
 
   base::Optional<std::string> logged_error;
-  ExceptionHandler handler(base::Bind(&PopulateError, &logged_error));
+  ExceptionHandler handler(base::BindRepeating(&PopulateError, &logged_error));
 
   ThrowException(context, "new Error('some error')", &handler);
 
@@ -60,7 +60,7 @@
   v8::Local<v8::Context> context_b = AddContext();
 
   base::Optional<std::string> logged_error;
-  ExceptionHandler handler(base::Bind(&PopulateError, &logged_error));
+  ExceptionHandler handler(base::BindRepeating(&PopulateError, &logged_error));
 
   v8::Local<v8::Function> custom_handler = FunctionFromString(
       context_a,
@@ -107,7 +107,7 @@
   v8::Local<v8::Context> context = MainContext();
 
   base::Optional<std::string> logged_error;
-  ExceptionHandler handler(base::Bind(&PopulateError, &logged_error));
+  ExceptionHandler handler(base::BindRepeating(&PopulateError, &logged_error));
 
   ThrowException(context, "'hello'", &handler);
   ASSERT_TRUE(logged_error);
@@ -145,7 +145,7 @@
   v8::Local<v8::Context> context = MainContext();
 
   base::Optional<std::string> logged_error;
-  ExceptionHandler handler(base::Bind(&PopulateError, &logged_error));
+  ExceptionHandler handler(base::BindRepeating(&PopulateError, &logged_error));
 
   {
     v8::TryCatch try_catch(isolate());
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 9e631dc..0fefd66 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -464,8 +464,6 @@
 // Completes the process of dismissing the tab switcher, removing it from the
 // screen and showing the appropriate BVC.
 - (void)finishDismissingTabSwitcher;
-// Sets up self.currentBVC for testing by closing existing tabs.
-- (void)setUpCurrentBVCForTesting;
 // Opens an url from a link in the settings UI.
 - (void)openUrlFromSettings:(OpenNewTabCommand*)command;
 // Switches to show either regular or incognito tabs, and then opens
@@ -1490,7 +1488,8 @@
       // because the currentTab will change after the switch.
       Tab* currentTab = self.currentTabModel.currentTab;
       if (currentTab) {
-        SnapshotTabHelper::FromWebState(currentTab.webState)->UpdateSnapshot();
+        SnapshotTabHelper::FromWebState(currentTab.webState)
+            ->UpdateSnapshotWithCallback(nil);
       }
       // Not for this browser state, send it on its way.
       [self switchModesAndOpenNewTab:command];
@@ -2552,13 +2551,6 @@
   return username.empty() ? nil : base::SysUTF8ToNSString(username);
 }
 
-#pragma mark - UI Automation Testing
-
-- (void)setUpCurrentBVCForTesting {
-  [self.otrTabModel closeAllTabs];
-  [self.mainTabModel closeAllTabs];
-}
-
 #pragma mark - GoogleServicesNavigationCoordinatorDelegate
 
 - (void)googleServicesNavigationCoordinatorDidClose:
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
index 4d1d2896..752b7a4 100644
--- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
+++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -34,6 +34,70 @@
 			<key>Type</key>
 			<string>PSMultiValueSpecifier</string>
 			<key>Title</key>
+			<string>Force What&apos;s New Promo</string>
+			<key>Key</key>
+			<string>WhatsNewPromoStatus</string>
+			<key>DefaultValue</key>
+			<integer>0</integer>
+			<key>Values</key>
+			<array>
+				<integer>0</integer>
+				<integer>1</integer>
+				<integer>2</integer>
+			</array>
+			<key>Titles</key>
+			<array>
+				<string>Default</string>
+				<string>Tip Command Test</string>
+				<string>Tip Move to Dock Promo</string>
+			</array>
+		</dict>
+		<dict>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+			<key>Title</key>
+			<string>Debug Settings</string>
+		</dict>
+		<dict>
+			<key>Type</key>
+			<string>PSToggleSwitchSpecifier</string>
+			<key>Title</key>
+			<string>Enable Startup Crash</string>
+			<key>Key</key>
+			<string>EnableStartupCrash</string>
+			<key>DefaultValue</key>
+			<false/>
+		</dict>
+		<dict>
+			<key>Type</key>
+			<string>PSToggleSwitchSpecifier</string>
+			<key>Title</key>
+			<string>Enable Memory Debugging</string>
+			<key>Key</key>
+			<string>EnableMemoryDebugging</string>
+			<key>DefaultValue</key>
+			<false/>
+		</dict>
+		<dict>
+			<key>Type</key>
+			<string>PSToggleSwitchSpecifier</string>
+			<key>Title</key>
+			<string>Use Mobile Safari UA</string>
+			<key>Key</key>
+			<string>UseMobileSafariUA</string>
+			<key>DefaultValue</key>
+			<false/>
+		</dict>
+		<dict>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+			<key>Title</key>
+			<string>Google App Ecosystem</string>
+		</dict>
+		<dict>
+			<key>Type</key>
+			<string>PSMultiValueSpecifier</string>
+			<key>Title</key>
 			<string>Gaia Environment</string>
 			<key>Key</key>
 			<string>GAIAEnvironment</string>
@@ -56,76 +120,6 @@
 			<key>Type</key>
 			<string>PSToggleSwitchSpecifier</string>
 			<key>Title</key>
-			<string>Enable Startup Crash</string>
-			<key>Key</key>
-			<string>EnableStartupCrash</string>
-			<key>DefaultValue</key>
-			<false/>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSMultiValueSpecifier</string>
-			<key>Title</key>
-			<string>Force What&apos;s New Promo</string>
-			<key>Key</key>
-			<string>WhatsNewPromoStatus</string>
-			<key>DefaultValue</key>
-			<integer>0</integer>
-			<key>Values</key>
-			<array>
-				<integer>0</integer>
-				<integer>1</integer>
-				<integer>2</integer>
-			</array>
-			<key>Titles</key>
-			<array>
-				<string>Default</string>
-				<string>Tip Command Test</string>
-				<string>Tip Move to Dock Promo</string>
-			</array>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSMultiValueSpecifier</string>
-			<key>Title</key>
-			<string>Enable View/Copy passwords</string>
-			<key>Key</key>
-			<string>EnableViewCopyPasswords</string>
-			<key>DefaultValue</key>
-			<string></string>
-			<key>Values</key>
-			<array>
-				<string></string>
-				<string>Disabled</string>
-				<string>Enabled</string>
-			</array>
-			<key>Titles</key>
-			<array>
-				<string>Default</string>
-				<string>Disabled</string>
-				<string>Enabled</string>
-			</array>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSToggleSwitchSpecifier</string>
-			<key>Title</key>
-			<string>Disable Update Password UI</string>
-			<key>Key</key>
-			<string>UpdatePasswordUIDisabled</string>
-			<key>DefaultValue</key>
-			<false/>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSGroupSpecifier</string>
-			<key>Title</key>
-			<string>Application Group</string>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSToggleSwitchSpecifier</string>
-			<key>Title</key>
 			<string>Clear Application Group sandbox</string>
 			<key>Key</key>
 			<string>ClearApplicationGroup</string>
@@ -134,44 +128,6 @@
 		</dict>
 		<dict>
 			<key>Type</key>
-			<string>PSGroupSpecifier</string>
-			<key>Title</key>
-			<string>Memory</string>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSToggleSwitchSpecifier</string>
-			<key>Title</key>
-			<string>Enable Memory Debugging</string>
-			<key>Key</key>
-			<string>EnableMemoryDebugging</string>
-			<key>DefaultValue</key>
-			<false/>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSGroupSpecifier</string>
-			<key>Title</key>
-			<string>User Agent</string>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSToggleSwitchSpecifier</string>
-			<key>Title</key>
-			<string>Use Mobile Safari UA</string>
-			<key>Key</key>
-			<string>UseMobileSafariUA</string>
-			<key>DefaultValue</key>
-			<false/>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSGroupSpecifier</string>
-			<key>Title</key>
-			<string>Google App Ecosystem</string>
-		</dict>
-		<dict>
-			<key>Type</key>
 			<string>PSTextFieldSpecifier</string>
 			<key>Title</key>
 			<string>Origin Server Host</string>
diff --git a/ios/chrome/browser/snapshots/snapshot_tab_helper.h b/ios/chrome/browser/snapshots/snapshot_tab_helper.h
index 21eacd62..8e250c9 100644
--- a/ios/chrome/browser/snapshots/snapshot_tab_helper.h
+++ b/ios/chrome/browser/snapshots/snapshot_tab_helper.h
@@ -57,6 +57,8 @@
   // runs |callback| with the new snapshot image.
   void UpdateSnapshotWithCallback(void (^callback)(UIImage*));
 
+  // DEPRECATED(crbug.com/917929): Use the asynchronous function
+  // |UpdateSnapshotWithCallback()| for all new callsites.
   // Generates a new snapshot, updates the snapshot cache, and returns the new
   // snapshot image.
   UIImage* UpdateSnapshot();
diff --git a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
index 4202425..bf38387e 100644
--- a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
+++ b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
@@ -113,16 +113,11 @@
     web::PageLoadCompletionStatus load_completion_status) {
   if (!ignore_next_load_ &&
       load_completion_status == web::PageLoadCompletionStatus::SUCCESS) {
-    if (web_state->ContentIsHTML()) {
       base::PostDelayedTaskWithTraits(
           FROM_HERE, {web::WebThread::UI},
           base::BindOnce(&SnapshotTabHelper::UpdateSnapshotWithCallback,
                          weak_ptr_factory_.GetWeakPtr(), /*callback=*/nil),
           base::TimeDelta::FromSeconds(1));
-      return;
-    }
-    // Native content cannot utilize the WKWebView snapshotting API.
-    UpdateSnapshot();
   }
   ignore_next_load_ = false;
 }
diff --git a/ios/chrome/browser/test/perf_test_with_bvc_ios.mm b/ios/chrome/browser/test/perf_test_with_bvc_ios.mm
index d5f5594..91a3848c 100644
--- a/ios/chrome/browser/test/perf_test_with_bvc_ios.mm
+++ b/ios/chrome/browser/test/perf_test_with_bvc_ios.mm
@@ -138,7 +138,6 @@
   // Documented example of how to clear out the browser view controller
   // and its associated data.
   window_ = nil;
-  [bvc_ browserStateDestroyed];
   [bvc_ shutdown];
   bvc_ = nil;
   bvc_factory_ = nil;
diff --git a/ios/chrome/browser/ui/browser_view_controller+private.h b/ios/chrome/browser/ui/browser_view_controller+private.h
index 881c18d..47fe60e 100644
--- a/ios/chrome/browser/ui/browser_view_controller+private.h
+++ b/ios/chrome/browser/ui/browser_view_controller+private.h
@@ -24,11 +24,6 @@
 - (void)clearPresentedStateWithCompletion:(ProceduralBlock)completion
                            dismissOmnibox:(BOOL)dismissOmnibox;
 
-// Called when the browser state provided to this instance is being destroyed.
-// At this point the browser will no longer ever be active, and will likely be
-// deallocated soon.
-- (void)browserStateDestroyed;
-
 // Called before the instance is deallocated.
 - (void)shutdown;
 
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 5adefbf..f441562 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -1180,7 +1180,8 @@
   // opened from an incognito tab. A different BVC is displayed, which may not
   // have enough time to finish appearing before a snapshot is requested.
   if (self.currentWebState && self.viewVisible) {
-    SnapshotTabHelper::FromWebState(self.currentWebState)->UpdateSnapshot();
+    SnapshotTabHelper::FromWebState(self.currentWebState)
+        ->UpdateSnapshotWithCallback(nil);
   }
 
   [self.tabModel
@@ -1364,19 +1365,27 @@
   }
 }
 
-- (void)browserStateDestroyed {
+- (void)shutdown {
+  DCHECK(!_isShutdown);
+  _isShutdown = YES;
+
   [self setActive:NO];
   [_paymentRequestManager close];
   _paymentRequestManager = nil;
-  [self.tabModel browserStateDestroyed];
 
-  TextToSpeechPlaybackControllerFactory::GetInstance()
-      ->GetForBrowserState(_browserState)
-      ->SetWebStateList(nullptr);
+  if (_browserState) {
+    TextToSpeechPlaybackController* controller =
+        TextToSpeechPlaybackControllerFactory::GetInstance()
+            ->GetForBrowserState(_browserState);
+    if (controller)
+      controller->SetWebStateList(nullptr);
 
-  WebStateListWebUsageEnablerFactory::GetInstance()
-      ->GetForBrowserState(_browserState)
-      ->SetWebStateList(nullptr);
+    WebStateListWebUsageEnabler* webUsageEnabler =
+        WebStateListWebUsageEnablerFactory::GetInstance()->GetForBrowserState(
+            _browserState);
+    if (webUsageEnabler)
+      webUsageEnabler->SetWebStateList(nullptr);
+  }
 
   // Disconnect child coordinators.
   [_activityServiceCoordinator disconnect];
@@ -1388,11 +1397,7 @@
   _browserState = nullptr;
   [self.commandDispatcher stopDispatchingToTarget:self];
   self.commandDispatcher = nil;
-}
 
-- (void)shutdown {
-  DCHECK(!_isShutdown);
-  _isShutdown = YES;
   [self.tabStripCoordinator stop];
   self.tabStripCoordinator = nil;
   [self.primaryToolbarCoordinator stop];
@@ -1413,7 +1418,6 @@
   [self.tabModel removeObserver:self];
   if (_voiceSearchController)
     _voiceSearchController->SetDispatcher(nil);
-  [self.tabModel closeAllTabs];
   [_paymentRequestManager setActiveWebState:nullptr];
   [[NSNotificationCenter defaultCenter] removeObserver:self];
   DCHECK(_ntpCoordinatorsForWebStates.empty());
@@ -2476,6 +2480,10 @@
 }
 
 - (void)dismissPopups {
+  // The dispatcher may not be fully connected during shutdown, so selectors may
+  // be unrecognized.
+  if (_isShutdown)
+    return;
   [self.dispatcher hidePageInfo];
   [self.dispatcher dismissPopupMenuAnimated:NO];
   [self.bubblePresenter dismissBubbles];
@@ -3068,7 +3076,8 @@
 
   // Requested web state should not be blocked from opening.
   Tab* currentTab = LegacyTabHelper::GetTabForWebState(webState);
-  SnapshotTabHelper::FromWebState(currentTab.webState)->UpdateSnapshot();
+  SnapshotTabHelper::FromWebState(currentTab.webState)
+      ->UpdateSnapshotWithCallback(nil);
 
   Tab* childTab = [[self tabModel] insertOpenByDOMTabWithOpener:currentTab];
 
@@ -4037,7 +4046,8 @@
         // If the page has finished loading, take a snapshot.  If the page is
         // still loading, do nothing, as the tab helper will automatically take
         // a snapshot once the load completes.
-        SnapshotTabHelper::FromWebState(newTab.webState)->UpdateSnapshot();
+        SnapshotTabHelper::FromWebState(newTab.webState)
+            ->UpdateSnapshotWithCallback(nil);
       }
 
       if (typed_or_generated_transition) {
@@ -4184,7 +4194,7 @@
   bool oldTabIsNTPWithoutHistory =
       IsNTPWithoutHistory(webStateList->GetActiveWebState());
 
-  if (!webStateList->ContainsIndex(newWebStateIndex)) {
+  if (newWebStateIndex == WebStateList::kInvalidIndex) {
     // If the tab containing the URL has been closed.
     if (oldTabIsNTPWithoutHistory) {
       // It is NTP, just load the URL.
@@ -4311,7 +4321,7 @@
     _locationBarEditCancelledLoad = NO;
 
     web::WebState* webState = self.currentWebState;
-    if (webState && ![self.helper isToolbarLoading:webState])
+    if (!_isShutdown && webState && ![self.helper isToolbarLoading:webState])
       webState->GetNavigationManager()->Reload(web::ReloadType::NORMAL,
                                                false /* check_for_repost */);
   }
@@ -4502,6 +4512,7 @@
   // TODO(crbug.com/688003): Evaluate if a screenshot of the tab is needed on
   // iPad.
   UIImageView* exitingPage = [self pageOpenCloseAnimationView];
+  // TODO(crbug.com/917929): Refactor to remove usage of UpdateSnapshot().
   exitingPage.image =
       SnapshotTabHelper::FromWebState(self.currentWebState)->UpdateSnapshot();
 
@@ -4761,6 +4772,7 @@
       newPage.userInteractionEnabled = NO;
     } else {
       UIImageView* pageScreenshot = [self pageOpenCloseAnimationView];
+      // TODO(crbug.com/917929): Refactor to remove usage of UpdateSnapshot().
       pageScreenshot.image =
           SnapshotTabHelper::FromWebState(tab.webState)->UpdateSnapshot();
       newPage = pageScreenshot;
diff --git a/ios/chrome/browser/ui/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
index 9e704ff..ee4cedc 100644
--- a/ios/chrome/browser/ui/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
@@ -254,7 +254,6 @@
 
   void TearDown() override {
     [[bvc_ view] removeFromSuperview];
-    [bvc_ browserStateDestroyed];
     [bvc_ shutdown];
 
     BlockCleanupTest::TearDown();
diff --git a/ios/chrome/browser/ui/main/browser_coordinator.mm b/ios/chrome/browser/ui/main/browser_coordinator.mm
index db45080..61dee506 100644
--- a/ios/chrome/browser/ui/main/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/main/browser_coordinator.mm
@@ -196,7 +196,6 @@
 
 // Shuts down the BrowserViewController.
 - (void)destroyViewController {
-  [self.viewController browserStateDestroyed];
   [self.viewController shutdown];
   _viewController = nil;
 }
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler.mm b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
index a155e56..a65ed4c 100644
--- a/ios/chrome/browser/ui/main/browser_view_wrangler.mm
+++ b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
@@ -349,30 +349,9 @@
   DCHECK(!_isShutdown);
   _isShutdown = YES;
 
-  if (_tabModelObserver) {
-    [_mainTabModel removeObserver:_tabModelObserver];
-    [_otrTabModel removeObserver:_tabModelObserver];
-    _tabModelObserver = nil;
-  }
-
-  [_mainTabModel removeObserver:self];
-  [_otrTabModel removeObserver:self];
-
   // Disconnect the DeviceSharingManager.
   [self cleanDeviceSharingManager];
 
-  // Stop URL monitoring of the main tab model.
-  breakpad::StopMonitoringURLsForTabModel(_mainTabModel);
-
-  // Stop Breakpad state monitoring of both tab models (if necessary).
-  breakpad::StopMonitoringTabStateForTabModel(_mainTabModel);
-  breakpad::StopMonitoringTabStateForTabModel(_otrTabModel);
-
-  // Normally other objects will take care of unhooking the tab models from
-  // the browser state, but this code should ensure that it happens regardless.
-  [_mainTabModel browserStateDestroyed];
-  [_otrTabModel browserStateDestroyed];
-
   // At this stage, new BrowserCoordinators shouldn't be lazily constructed by
   // calling their property getters.
   [_mainBrowserCoordinator stop];
@@ -380,6 +359,12 @@
   [_incognitoBrowserCoordinator stop];
   _incognitoBrowserCoordinator = nil;
 
+  [_mainTabModel closeAllTabs];
+  [_otrTabModel closeAllTabs];
+  // Handles removing observers and stopping breakpad monitoring.
+  [self setMainTabModel:nil];
+  [self setOtrTabModel:nil];
+
   _browserState = nullptr;
 }
 
diff --git a/ios/chrome/browser/ui/settings/cells/BUILD.gn b/ios/chrome/browser/ui/settings/cells/BUILD.gn
index c30184c..98b0d91 100644
--- a/ios/chrome/browser/ui/settings/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/cells/BUILD.gn
@@ -28,8 +28,6 @@
     "settings_cells_constants.mm",
     "settings_detail_item.h",
     "settings_detail_item.mm",
-    "settings_image_detail_text_item.h",
-    "settings_image_detail_text_item.mm",
     "settings_multiline_detail_item.h",
     "settings_multiline_detail_item.mm",
     "settings_search_item.h",
diff --git a/ios/chrome/browser/ui/settings/cells/legacy/BUILD.gn b/ios/chrome/browser/ui/settings/cells/legacy/BUILD.gn
index d0d7b1d..acbb77b 100644
--- a/ios/chrome/browser/ui/settings/cells/legacy/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/cells/legacy/BUILD.gn
@@ -8,6 +8,8 @@
     "legacy_autofill_data_item.mm",
     "legacy_settings_detail_item.h",
     "legacy_settings_detail_item.mm",
+    "legacy_settings_image_detail_text_item.h",
+    "legacy_settings_image_detail_text_item.mm",
     "legacy_settings_switch_item.h",
     "legacy_settings_switch_item.mm",
     "legacy_sync_switch_item.h",
diff --git a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h b/ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.h
similarity index 68%
rename from ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h
rename to ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.h
index 1eb62be..d2fb74e 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h
+++ b/ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_LEGACY_LEGACY_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_LEGACY_LEGACY_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
 
 #import <Foundation/Foundation.h>
 
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
 #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
 
-// SettingsImageDetailTextItem is an item that displays an image, a title and
-// a detail text (optional). This item uses multi-lines text field. It also
+// LegacySettingsImageDetailTextItem is an item that displays an image, a title
+// and a detail text (optional). This item uses multi-lines text field. It also
 // contains acommand id.
 // This class is intended to be used with Google services settings view.
-@interface SettingsImageDetailTextItem : CollectionViewItem
+@interface LegacySettingsImageDetailTextItem : CollectionViewItem
 
 // The image to display.
 @property(nonatomic, strong) UIImage* image;
@@ -30,14 +30,14 @@
 
 @end
 
-// Cell representation for SettingsImageDetailTextItem.
+// Cell representation for LegacySettingsImageDetailTextItem.
 //  +--------------------------------------------------+
 //  |  +-------+                                       |
 //  |  | image |   Multiline title                     |
 //  |  |       |   Optional multiline detail text      |
 //  |  +-------+                                       |
 //  +--------------------------------------------------+
-@interface SettingsImageDetailTextCell : MDCCollectionViewCell
+@interface LegacySettingsImageDetailTextCell : MDCCollectionViewCell
 
 // Cell image.
 @property(nonatomic, readonly, strong) UIImageView* imageView;
@@ -50,4 +50,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_LEGACY_LEGACY_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
diff --git a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm b/ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.mm
similarity index 91%
rename from ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm
rename to ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.mm
index c5c5341..7bd20b3c 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
+#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.h"
 
 #include "ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
@@ -27,16 +27,16 @@
 
 }  // namespace
 
-@interface SettingsImageDetailTextCell ()
+@interface LegacySettingsImageDetailTextCell ()
 
 // Container view which contains |self.textLabel| and |self.detailTextLabel|.
 @property(nonatomic, strong) UIStackView* textStackView;
 
 @end
 
-#pragma mark - SettingsImageDetailTextItem
+#pragma mark - LegacySettingsImageDetailTextItem
 
-@implementation SettingsImageDetailTextItem
+@implementation LegacySettingsImageDetailTextItem
 
 @synthesize image = _image;
 @synthesize text = _text;
@@ -46,12 +46,12 @@
 - (instancetype)initWithType:(NSInteger)type {
   self = [super initWithType:type];
   if (self) {
-    self.cellClass = [SettingsImageDetailTextCell class];
+    self.cellClass = [LegacySettingsImageDetailTextCell class];
   }
   return self;
 }
 
-- (void)configureCell:(SettingsImageDetailTextCell*)cell {
+- (void)configureCell:(LegacySettingsImageDetailTextCell*)cell {
   [super configureCell:cell];
   cell.isAccessibilityElement = YES;
   cell.textLabel.text = self.text;
@@ -61,9 +61,9 @@
 
 @end
 
-#pragma mark - SettingsImageDetailTextCell
+#pragma mark - LegacySettingsImageDetailTextCell
 
-@implementation SettingsImageDetailTextCell
+@implementation LegacySettingsImageDetailTextCell
 
 @synthesize imageView = _imageView;
 @synthesize textLabel = _textLabel;
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
index adc3dd6..216ddde6 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
@@ -13,8 +13,8 @@
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
+#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/settings/cells/legacy/legacy_sync_switch_item.h"
-#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/settings/sync_utils/sync_util.h"
 #import "ios/chrome/browser/ui/settings/utils/observable_boolean.h"
 #import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h"
@@ -91,7 +91,7 @@
 // from one state to another.
 @property(nonatomic, assign) BOOL personalizedSectionBeingAnimated;
 // Item to display the sync error.
-@property(nonatomic, strong) SettingsImageDetailTextItem* syncErrorItem;
+@property(nonatomic, strong) LegacySettingsImageDetailTextItem* syncErrorItem;
 // All the items for the personalized section.
 @property(nonatomic, strong, readonly) ItemArray personalizedItems;
 // Item for the autocomplete wallet feature.
@@ -170,10 +170,10 @@
   return self.authService->IsAuthenticated();
 }
 
-- (SettingsImageDetailTextItem*)syncErrorItem {
+- (LegacySettingsImageDetailTextItem*)syncErrorItem {
   if (!_syncErrorItem) {
-    _syncErrorItem =
-        [[SettingsImageDetailTextItem alloc] initWithType:SyncErrorItemType];
+    _syncErrorItem = [[LegacySettingsImageDetailTextItem alloc]
+        initWithType:SyncErrorItemType];
     {
       // TODO(crbug.com/889470): Needs asset for the sync error.
       CGSize size = CGSizeMake(40, 40);
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
index 5199d83..e6907053 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
@@ -6,8 +6,8 @@
 
 #include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
+#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/settings/cells/legacy/legacy_sync_switch_item.h"
-#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_local_commands.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_service_delegate.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller_model_delegate.h"
@@ -180,7 +180,7 @@
       [self.collectionViewModel itemAtIndexPath:indexPath];
   if ([item isKindOfClass:[LegacySyncSwitchItem class]]) {
     return NO;
-  } else if ([item isKindOfClass:[SettingsImageDetailTextItem class]]) {
+  } else if ([item isKindOfClass:[LegacySettingsImageDetailTextItem class]]) {
     return YES;
   }
   // The highlight of an item should be explicitly defined. If the item can be
@@ -198,9 +198,9 @@
       [self.collectionViewModel itemAtIndexPath:indexPath];
   GoogleServicesSettingsCommandID commandID =
       GoogleServicesSettingsCommandIDNoOp;
-  if ([item isKindOfClass:[SettingsImageDetailTextItem class]]) {
-    SettingsImageDetailTextItem* imageDetailTextItem =
-        base::mac::ObjCCast<SettingsImageDetailTextItem>(item);
+  if ([item isKindOfClass:[LegacySettingsImageDetailTextItem class]]) {
+    LegacySettingsImageDetailTextItem* imageDetailTextItem =
+        base::mac::ObjCCast<LegacySettingsImageDetailTextItem>(item);
     commandID = static_cast<GoogleServicesSettingsCommandID>(
         imageDetailTextItem.commandID);
   } else {
diff --git a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
index 09567da..c1fdcf8 100644
--- a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
@@ -35,11 +35,11 @@
 #import "ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.h"
 #import "ios/chrome/browser/ui/settings/cells/legacy/legacy_autofill_data_item.h"
 #import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_detail_item.h"
+#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_switch_item.h"
 #import "ios/chrome/browser/ui/settings/cells/legacy/legacy_sync_switch_item.h"
 #import "ios/chrome/browser/ui/settings/cells/passphrase_error_item.h"
 #import "ios/chrome/browser/ui/settings/cells/password_details_item.h"
-#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_search_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_text_item.h"
@@ -245,7 +245,7 @@
       toSectionWithIdentifier:SectionIdentifierMultilineCell];
   [model addItem:[self settingsImageDetailTextItem]
       toSectionWithIdentifier:SectionIdentifierMultilineCell];
-  SettingsImageDetailTextItem* settingsImageDetailTextItem =
+  LegacySettingsImageDetailTextItem* settingsImageDetailTextItem =
       [self settingsImageDetailTextItem];
   settingsImageDetailTextItem.text = @"Short title";
   [model addItem:settingsImageDetailTextItem
@@ -798,9 +798,9 @@
   return articleItem;
 }
 
-- (SettingsImageDetailTextItem*)settingsImageDetailTextItem {
-  SettingsImageDetailTextItem* settingsImageDetailTextItem =
-      [[SettingsImageDetailTextItem alloc]
+- (LegacySettingsImageDetailTextItem*)settingsImageDetailTextItem {
+  LegacySettingsImageDetailTextItem* settingsImageDetailTextItem =
+      [[LegacySettingsImageDetailTextItem alloc]
           initWithType:ItemTypeImageDetailTextItem];
   settingsImageDetailTextItem.image =
       [UIImage imageNamed:@"ios_default_avatar"];
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
index aaf1522..d7e2b842 100644
--- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
+++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
@@ -335,7 +335,7 @@
         FullscreenControllerFactory::GetInstance()->GetForBrowserState(
             browserState_));
     SnapshotTabHelper::FromWebState([model_ currentTab].webState)
-        ->UpdateSnapshot();
+        ->UpdateSnapshotWithCallback(nil);
     [[NSNotificationCenter defaultCenter]
         postNotificationName:kSideSwipeWillStartNotification
                       object:nil];
@@ -527,7 +527,8 @@
     }
 
     // Ensure that there's an up-to-date snapshot of the current tab.
-    SnapshotTabHelper::FromWebState(currentTab.webState)->UpdateSnapshot();
+    SnapshotTabHelper::FromWebState(currentTab.webState)
+        ->UpdateSnapshotWithCallback(nil);
 
     // Hide the infobar after snapshot has been updated (see the previous line)
     // to avoid it obscuring the cards in the side swipe view.
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
index a681f904..b8acfb0 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -1671,7 +1671,8 @@
   Tab* tappedTab = [_tabModel tabAtIndex:index];
   Tab* currentTab = [_tabModel currentTab];
   if (IsIPadIdiom() && (currentTab != tappedTab)) {
-    SnapshotTabHelper::FromWebState(currentTab.webState)->UpdateSnapshot();
+    SnapshotTabHelper::FromWebState(currentTab.webState)
+        ->UpdateSnapshotWithCallback(nil);
   }
   [_tabModel setCurrentTab:tappedTab];
   [self updateContentOffsetForTabIndex:index isNewTab:NO];
diff --git a/ios/chrome/browser/web_state_list/web_state_list_unittest.mm b/ios/chrome/browser/web_state_list/web_state_list_unittest.mm
index d0ec2e76..c7fb005 100644
--- a/ios/chrome/browser/web_state_list/web_state_list_unittest.mm
+++ b/ios/chrome/browser/web_state_list/web_state_list_unittest.mm
@@ -180,6 +180,7 @@
   DISALLOW_COPY_AND_ASSIGN(WebStateListTest);
 };
 
+// Test that empty() matches count() != 0.
 TEST_F(WebStateListTest, IsEmpty) {
   EXPECT_EQ(0, web_state_list_.count());
   EXPECT_TRUE(web_state_list_.empty());
@@ -191,6 +192,7 @@
   EXPECT_FALSE(web_state_list_.empty());
 }
 
+// Test that inserting a single webstate works.
 TEST_F(WebStateListTest, InsertUrlSingle) {
   AppendNewWebState(kURL0);
 
@@ -199,6 +201,7 @@
   EXPECT_EQ(kURL0, web_state_list_.GetWebStateAt(0)->GetVisibleURL().spec());
 }
 
+// Test that inserting multiple webstates puts them in the expected places.
 TEST_F(WebStateListTest, InsertUrlMultiple) {
   web_state_list_.InsertWebState(0, CreateWebState(kURL0),
                                  WebStateList::INSERT_FORCE_INDEX,
@@ -217,6 +220,7 @@
   EXPECT_EQ(kURL0, web_state_list_.GetWebStateAt(2)->GetVisibleURL().spec());
 }
 
+// Test webstate activation.
 TEST_F(WebStateListTest, ActivateWebState) {
   AppendNewWebState(kURL0);
   EXPECT_EQ(nullptr, web_state_list_.GetActiveWebState());
@@ -229,6 +233,7 @@
             web_state_list_.GetActiveWebState());
 }
 
+// Test activating a webstate as it is inserted.
 TEST_F(WebStateListTest, InsertActivate) {
   web_state_list_.InsertWebState(
       0, CreateWebState(kURL0),
@@ -241,6 +246,7 @@
             web_state_list_.GetActiveWebState());
 }
 
+// Test finding a known webstate.
 TEST_F(WebStateListTest, GetIndexOfWebState) {
   std::unique_ptr<web::TestWebState> web_state_0 = CreateWebState(kURL0);
   web::WebState* target_web_state = web_state_0.get();
@@ -268,6 +274,7 @@
   EXPECT_EQ(2, web_state_list_.GetIndexOfWebState(target_web_state));
 }
 
+// Test finding a webstate by URL.
 TEST_F(WebStateListTest, GetIndexOfWebStateWithURL) {
   // Empty list.
   EXPECT_EQ(WebStateList::kInvalidIndex,
@@ -288,6 +295,7 @@
   EXPECT_EQ(1, web_state_list_.GetIndexOfWebStateWithURL(GURL(kURL0)));
 }
 
+// Test finding a non-active webstate by URL.
 TEST_F(WebStateListTest, GetIndexOfInactiveWebStateWithURL) {
   // Empty list.
   EXPECT_EQ(WebStateList::kInvalidIndex,
@@ -327,6 +335,7 @@
   EXPECT_EQ(2, web_state_list_.GetIndexOfInactiveWebStateWithURL(GURL(kURL0)));
 }
 
+// Test that inserted webstates correctly inherit openers.
 TEST_F(WebStateListTest, InsertInheritOpener) {
   AppendNewWebState(kURL0);
   web_state_list_.ActivateWebStateAt(0);
@@ -344,12 +353,13 @@
             web_state_list_.GetOpenerOfWebStateAt(1).opener);
 }
 
+// Test moving webstates one place to the "right" (to a higher index).
 TEST_F(WebStateListTest, MoveWebStateAtRightByOne) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
   AppendNewWebState(kURL2);
 
-  // Sanity check before closing WebState.
+  // Coherence check before closing WebState.
   EXPECT_EQ(3, web_state_list_.count());
   EXPECT_EQ(kURL0, web_state_list_.GetWebStateAt(0)->GetVisibleURL().spec());
   EXPECT_EQ(kURL1, web_state_list_.GetWebStateAt(1)->GetVisibleURL().spec());
@@ -365,6 +375,7 @@
   EXPECT_EQ(kURL2, web_state_list_.GetWebStateAt(2)->GetVisibleURL().spec());
 }
 
+// Test moving webstates more than one place to the "right" (to a higher index).
 TEST_F(WebStateListTest, MoveWebStateAtRightByMoreThanOne) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
@@ -386,6 +397,7 @@
   EXPECT_EQ(kURL0, web_state_list_.GetWebStateAt(2)->GetVisibleURL().spec());
 }
 
+// Test moving webstates one place to the "left" (to a lower index).
 TEST_F(WebStateListTest, MoveWebStateAtLeftByOne) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
@@ -407,6 +419,7 @@
   EXPECT_EQ(kURL1, web_state_list_.GetWebStateAt(2)->GetVisibleURL().spec());
 }
 
+// Test moving webstates more than one place to the "left" (to a lower index).
 TEST_F(WebStateListTest, MoveWebStateAtLeftByMoreThanOne) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
@@ -428,6 +441,8 @@
   EXPECT_EQ(kURL1, web_state_list_.GetWebStateAt(2)->GetVisibleURL().spec());
 }
 
+// Test "moving" webstates (calling MoveWebStateAt with the same source and
+// destination indexes.
 TEST_F(WebStateListTest, MoveWebStateAtSameIndex) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
@@ -449,6 +464,7 @@
   EXPECT_EQ(kURL2, web_state_list_.GetWebStateAt(2)->GetVisibleURL().spec());
 }
 
+// Test replacing webstates.
 TEST_F(WebStateListTest, ReplaceWebStateAt) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
@@ -470,6 +486,7 @@
   EXPECT_EQ(kURL1, old_web_state->GetVisibleURL().spec());
 }
 
+// Test detaching webstates at index 0.
 TEST_F(WebStateListTest, DetachWebStateAtIndexBegining) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
@@ -490,6 +507,7 @@
   EXPECT_EQ(kURL2, web_state_list_.GetWebStateAt(1)->GetVisibleURL().spec());
 }
 
+// Test detaching webstates at an index that isn't 0 or the last index.
 TEST_F(WebStateListTest, DetachWebStateAtIndexMiddle) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
@@ -510,6 +528,7 @@
   EXPECT_EQ(kURL2, web_state_list_.GetWebStateAt(1)->GetVisibleURL().spec());
 }
 
+// Test detaching webstates at the last index.
 TEST_F(WebStateListTest, DetachWebStateAtIndexLast) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
@@ -530,6 +549,7 @@
   EXPECT_EQ(kURL1, web_state_list_.GetWebStateAt(1)->GetVisibleURL().spec());
 }
 
+// Test finding opended-by indexes on an empty list.
 TEST_F(WebStateListTest, OpenersEmptyList) {
   EXPECT_TRUE(web_state_list_.empty());
 
@@ -548,6 +568,7 @@
                 nullptr, WebStateList::kInvalidIndex, true));
 }
 
+// Test finding opended-by indexes when no webstates have been opened.
 TEST_F(WebStateListTest, OpenersNothingOpened) {
   AppendNewWebState(kURL0);
   AppendNewWebState(kURL1);
@@ -571,6 +592,8 @@
   }
 }
 
+// Test finding opended-by indexes when the opened child is at an index after
+// the parent.
 TEST_F(WebStateListTest, OpenersChildsAfterOpener) {
   AppendNewWebState(kURL0);
   web::WebState* opener = web_state_list_.GetWebStateAt(0);
@@ -623,6 +646,8 @@
                    opener, start_index, true));
 }
 
+// Test finding opended-by indexes when the opened child is at an index before
+// the parent.
 TEST_F(WebStateListTest, OpenersChildsBeforeOpener) {
   AppendNewWebState(kURL0);
   web::WebState* opener = web_state_list_.GetWebStateAt(0);
diff --git a/ios/web/app/web_main_loop.mm b/ios/web/app/web_main_loop.mm
index 083fc5d1..87d630cf 100644
--- a/ios/web/app/web_main_loop.mm
+++ b/ios/web/app/web_main_loop.mm
@@ -167,6 +167,17 @@
       base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
                  true));
 
+  // Also allow waiting to join threads.
+  // TODO(crbug.com/800808): Ideally this (and the above SetIOAllowed()
+  // would be scoped allowances). That would be one of the first step to ensure
+  // no persistent work is being done after TaskScheduler::Shutdown() in order
+  // to move towards atomic shutdown.
+  base::ThreadRestrictions::SetWaitAllowed(true);
+  base::PostTaskWithTraits(
+      FROM_HERE, {WebThread::IO},
+      base::BindOnce(
+          base::IgnoreResult(&base::ThreadRestrictions::SetWaitAllowed), true));
+
   if (parts_) {
     parts_->PostMainMessageLoopRun();
   }
diff --git a/media/filters/ivf_parser.cc b/media/filters/ivf_parser.cc
index b6160fb5..8361088 100644
--- a/media/filters/ivf_parser.cc
+++ b/media/filters/ivf_parser.cc
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/logging.h"
-#include "base/sys_byteorder.h"
 #include "media/filters/ivf_parser.h"
 
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/sys_byteorder.h"
+
 namespace media {
 
 void IvfFileHeader::ByteSwap() {
@@ -34,6 +36,7 @@
   DCHECK(file_header);
   ptr_ = stream;
   end_ = stream + size;
+  CHECK_GE(end_, ptr_);
 
   if (size < sizeof(IvfFileHeader)) {
     DLOG(ERROR) << "EOF before file header";
@@ -65,8 +68,9 @@
                                const uint8_t** payload) {
   DCHECK(ptr_);
   DCHECK(payload);
+  CHECK_GE(end_, ptr_);
 
-  if (end_ < ptr_ + sizeof(IvfFrameHeader)) {
+  if (base::checked_cast<size_t>(end_ - ptr_) < sizeof(IvfFrameHeader)) {
     DLOG_IF(ERROR, ptr_ != end_) << "Incomplete frame header";
     return false;
   }
@@ -75,7 +79,7 @@
   frame_header->ByteSwap();
   ptr_ += sizeof(IvfFrameHeader);
 
-  if (end_ < ptr_ + frame_header->frame_size) {
+  if (base::checked_cast<uint32_t>(end_ - ptr_) < frame_header->frame_size) {
     DLOG(ERROR) << "Not enough frame data";
     return false;
   }
diff --git a/media/gpu/image_processor.cc b/media/gpu/image_processor.cc
index 1f5c409..ec95e43 100644
--- a/media/gpu/image_processor.cc
+++ b/media/gpu/image_processor.cc
@@ -16,4 +16,15 @@
 
 ImageProcessor::PortConfig::~PortConfig() {}
 
+ImageProcessor::ImageProcessor(const VideoFrameLayout& input_layout,
+                               VideoFrame::StorageType input_storage_type,
+                               const VideoFrameLayout& output_layout,
+                               VideoFrame::StorageType output_storage_type,
+                               OutputMode output_mode)
+    : input_layout_(input_layout),
+      input_storage_type_(input_storage_type),
+      output_layout_(output_layout),
+      output_storage_type_(output_storage_type),
+      output_mode_(output_mode) {}
+
 }  // namespace media
diff --git a/media/gpu/image_processor.h b/media/gpu/image_processor.h
index feefd75..894fd3de 100644
--- a/media/gpu/image_processor.h
+++ b/media/gpu/image_processor.h
@@ -9,10 +9,12 @@
 
 #include "base/callback_forward.h"
 #include "base/files/scoped_file.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_frame_layout.h"
+#include "media/gpu/media_gpu_export.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace media {
@@ -26,7 +28,7 @@
 // The threading model of ImageProcessor:
 // Process(), Reset(), and callbacks: FrameReadyCB, ErrorCB, should be run in
 // the same thread that creates ImageProcessor.
-class ImageProcessor {
+class MEDIA_GPU_EXPORT ImageProcessor {
  public:
   // OutputMode is used as intermediate stage. The ultimate goal is to make
   // ImageProcessor's clients all use IMPORT output mode.
@@ -38,7 +40,7 @@
   };
 
   // Encapsulates ImageProcessor input / output configurations.
-  struct PortConfig {
+  struct MEDIA_GPU_EXPORT PortConfig {
     PortConfig() = delete;
     PortConfig(
         const VideoFrameLayout& layout,
@@ -68,20 +70,28 @@
   // lifetime of or outlive ImageProcessor.
   using ErrorCB = base::RepeatingClosure;
 
-  // Returns input allocated size required by the processor to be fed with.
-  virtual gfx::Size input_allocated_size() const = 0;
+  virtual ~ImageProcessor() = default;
 
-  // Returns output allocated size required by the processor.
-  virtual gfx::Size output_allocated_size() const = 0;
+  // Returns input layout of the processor.
+  const VideoFrameLayout& input_layout() const { return input_layout_; }
+
+  // Returns output layout of the processor.
+  const VideoFrameLayout& output_layout() const { return output_layout_; }
 
   // Returns input storage type.
-  virtual VideoFrame::StorageType input_storage_type() const = 0;
+  VideoFrame::StorageType input_storage_type() const {
+    return input_storage_type_;
+  }
 
   // Returns output storage type.
-  virtual VideoFrame::StorageType output_storage_type() const = 0;
+  VideoFrame::StorageType output_storage_type() const {
+    return output_storage_type_;
+  }
 
   // Returns output mode.
-  virtual OutputMode output_mode() const = 0;
+  // TODO(crbug.com/907767): Remove it once ImageProcessor always works as
+  // IMPORT mode for output.
+  OutputMode output_mode() const { return output_mode_; }
 
 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
   // Called by client to process |frame|. The resulting processed frame will be
@@ -118,7 +128,25 @@
   // Reset() must be called on the same thread that creates ImageProcessor.
   virtual bool Reset() = 0;
 
-  virtual ~ImageProcessor() = default;
+ protected:
+  ImageProcessor(const VideoFrameLayout& input_layout,
+                 VideoFrame::StorageType input_storage_type,
+                 const VideoFrameLayout& output_layout,
+                 VideoFrame::StorageType output_storage_type,
+                 OutputMode output_mode);
+
+  // Stores input frame's layout and storage type.
+  const VideoFrameLayout input_layout_;
+  const VideoFrame::StorageType input_storage_type_;
+
+  // Stores output frame's layout, storage type and output mode.
+  // TODO(crbug.com/907767): Remove |output_mode_| once ImageProcessor always
+  // works as IMPORT mode for output.
+  const VideoFrameLayout output_layout_;
+  const VideoFrame::StorageType output_storage_type_;
+  const OutputMode output_mode_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ImageProcessor);
 };
 
 }  // namespace media
diff --git a/media/gpu/libyuv_image_processor.cc b/media/gpu/libyuv_image_processor.cc
index d4470dfba..aeb487e 100644
--- a/media/gpu/libyuv_image_processor.cc
+++ b/media/gpu/libyuv_image_processor.cc
@@ -21,13 +21,15 @@
     const VideoFrameLayout& output_layout,
     const gfx::Size& output_visible_size,
     VideoFrame::StorageType output_storage_type,
+    OutputMode output_mode,
     ErrorCB error_cb)
-    : input_layout_(input_layout),
+    : ImageProcessor(input_layout,
+                     input_storage_type,
+                     output_layout,
+                     output_storage_type,
+                     output_mode),
       input_visible_rect_(input_visible_size),
-      input_storage_type_(input_storage_type),
-      output_layout_(output_layout),
       output_visible_rect_(output_visible_size),
-      output_storage_type_(output_storage_type),
       error_cb_(error_cb),
       client_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       process_thread_("LibYUVImageProcessorThread"),
@@ -91,7 +93,7 @@
   auto processor = base::WrapUnique(new LibYUVImageProcessor(
       input_config.layout, input_config.visible_size, input_storage_type,
       output_config.layout, output_config.visible_size, output_storage_type,
-      std::move(error_cb)));
+      output_mode, std::move(error_cb)));
   if (!processor->process_thread_.Start()) {
     VLOGF(1) << "Failed to start processing thread";
     return nullptr;
@@ -178,26 +180,6 @@
   return true;
 }
 
-gfx::Size LibYUVImageProcessor::input_allocated_size() const {
-  return input_layout_.coded_size();
-}
-
-gfx::Size LibYUVImageProcessor::output_allocated_size() const {
-  return output_layout_.coded_size();
-}
-
-VideoFrame::StorageType LibYUVImageProcessor::input_storage_type() const {
-  return input_storage_type_;
-}
-
-VideoFrame::StorageType LibYUVImageProcessor::output_storage_type() const {
-  return output_storage_type_;
-}
-
-ImageProcessor::OutputMode LibYUVImageProcessor::output_mode() const {
-  return OutputMode::IMPORT;
-}
-
 void LibYUVImageProcessor::NotifyError() {
   VLOGF(1);
   DCHECK(!client_task_runner_->BelongsToCurrentThread());
diff --git a/media/gpu/libyuv_image_processor.h b/media/gpu/libyuv_image_processor.h
index a51be70..b034dd9 100644
--- a/media/gpu/libyuv_image_processor.h
+++ b/media/gpu/libyuv_image_processor.h
@@ -36,11 +36,6 @@
  public:
   // ImageProcessor override
   ~LibYUVImageProcessor() override;
-  gfx::Size input_allocated_size() const override;
-  gfx::Size output_allocated_size() const override;
-  VideoFrame::StorageType input_storage_type() const override;
-  VideoFrame::StorageType output_storage_type() const override;
-  OutputMode output_mode() const override;
 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
   bool Process(scoped_refptr<VideoFrame> frame,
                int output_buffer_index,
@@ -70,6 +65,7 @@
                        const VideoFrameLayout& output_layout,
                        const gfx::Size& output_visible_size,
                        VideoFrame::StorageType output_storage_type,
+                       OutputMode output_mode,
                        ErrorCB error_cb);
 
   void ProcessTask(scoped_refptr<VideoFrame> input_frame,
@@ -88,12 +84,8 @@
   static bool IsFormatSupported(VideoPixelFormat input_format,
                                 VideoPixelFormat output_format);
 
-  const VideoFrameLayout input_layout_;
   const gfx::Rect input_visible_rect_;
-  VideoFrame::StorageType input_storage_type_;
-  const VideoFrameLayout output_layout_;
   const gfx::Rect output_visible_rect_;
-  VideoFrame::StorageType output_storage_type_;
 
   // Error callback to the client.
   ErrorCB error_cb_;
diff --git a/media/gpu/v4l2/v4l2_image_processor.cc b/media/gpu/v4l2/v4l2_image_processor.cc
index 27cea3d..7d33c70 100644
--- a/media/gpu/v4l2/v4l2_image_processor.cc
+++ b/media/gpu/v4l2/v4l2_image_processor.cc
@@ -74,15 +74,15 @@
     gfx::Size output_visible_size,
     size_t num_buffers,
     ErrorCB error_cb)
-    : input_layout_(input_layout),
+    : ImageProcessor(input_layout,
+                     input_storage_type,
+                     output_layout,
+                     output_storage_type,
+                     output_mode),
       input_visible_size_(input_visible_size),
       input_memory_type_(input_memory_type),
-      input_storage_type_(input_storage_type),
-      output_layout_(output_layout),
       output_visible_size_(output_visible_size),
       output_memory_type_(output_memory_type),
-      output_storage_type_(output_storage_type),
-      output_mode_(output_mode),
       client_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       device_(device),
       device_thread_("V4L2ImageProcessorThread"),
@@ -387,26 +387,6 @@
   return true;
 }
 
-gfx::Size V4L2ImageProcessor::input_allocated_size() const {
-  return input_layout_.coded_size();
-}
-
-gfx::Size V4L2ImageProcessor::output_allocated_size() const {
-  return output_layout_.coded_size();
-}
-
-VideoFrame::StorageType V4L2ImageProcessor::input_storage_type() const {
-  return input_storage_type_;
-}
-
-VideoFrame::StorageType V4L2ImageProcessor::output_storage_type() const {
-  return output_storage_type_;
-}
-
-ImageProcessor::OutputMode V4L2ImageProcessor::output_mode() const {
-  return output_mode_;
-}
-
 bool V4L2ImageProcessor::Process(scoped_refptr<VideoFrame> frame,
                                  int output_buffer_index,
                                  std::vector<base::ScopedFD> output_dmabuf_fds,
@@ -875,7 +855,7 @@
   for (size_t i = 0; i < input_layout_.num_buffers(); ++i) {
     qbuf.m.planes[i].bytesused =
         VideoFrame::PlaneSize(input_record.frame->format(), i,
-                              input_allocated_size())
+                              input_layout_.coded_size())
             .GetArea();
     qbuf.m.planes[i].length = qbuf.m.planes[i].bytesused;
     switch (input_memory_type_) {
diff --git a/media/gpu/v4l2/v4l2_image_processor.h b/media/gpu/v4l2/v4l2_image_processor.h
index 4b6d09e..394c06ae 100644
--- a/media/gpu/v4l2/v4l2_image_processor.h
+++ b/media/gpu/v4l2/v4l2_image_processor.h
@@ -36,11 +36,6 @@
  public:
   // ImageProcessor implementation.
   ~V4L2ImageProcessor() override;
-  gfx::Size input_allocated_size() const override;
-  gfx::Size output_allocated_size() const override;
-  VideoFrame::StorageType input_storage_type() const override;
-  VideoFrame::StorageType output_storage_type() const override;
-  OutputMode output_mode() const override;
   bool Process(scoped_refptr<VideoFrame> frame,
                int output_buffer_index,
                std::vector<base::ScopedFD> output_dmabuf_fds,
@@ -169,18 +164,13 @@
   // callbacks will be invoked.
   void Destroy();
 
-  // Stores input frame's format, coded_size, buffer and plane layout.
-  const VideoFrameLayout input_layout_;
+  // Stores input frame's visible size and v4l2_memory type.
   const gfx::Size input_visible_size_;
   const v4l2_memory input_memory_type_;
-  const VideoFrame::StorageType input_storage_type_;
 
-  // Stores input frame's format, coded_size, buffer and plane layout.
-  const VideoFrameLayout output_layout_;
+  // Stores output frame's visible size and v4l2_memory type.
   const gfx::Size output_visible_size_;
   const v4l2_memory output_memory_type_;
-  const VideoFrame::StorageType output_storage_type_;
-  const OutputMode output_mode_;
 
   // A task runner belongs to a thread where V4L2ImageProcessor is created.
   const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner_;
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
index 719f495..2394b3e2 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
@@ -2414,14 +2414,14 @@
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
-  VLOGF(2) << "image_processor_->output_allocated_size()="
-           << image_processor_->output_allocated_size().ToString();
-  DCHECK(image_processor_->output_allocated_size() == egl_image_size_);
-  if (image_processor_->input_allocated_size() != coded_size_) {
+  VLOGF(2) << "image_processor_->output_layout().coded_size()="
+           << image_processor_->output_layout().coded_size().ToString();
+  DCHECK(image_processor_->output_layout().coded_size() == egl_image_size_);
+  if (image_processor_->input_layout().coded_size() != coded_size_) {
     VLOGF(1) << "Image processor should be able to take the output coded "
              << "size of decoder " << coded_size_.ToString()
              << " without adjusting to "
-             << image_processor_->input_allocated_size().ToString();
+             << image_processor_->input_layout().coded_size().ToString();
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index 281fd9c9..d55b686 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -249,12 +249,12 @@
     // Output coded height of processor can be larger but not smaller than the
     // input coded height of encoder. For example, suppose input size of encoder
     // is 320x193. It is OK if the output of processor is 320x208.
-    if (image_processor_->output_allocated_size().width() !=
+    if (image_processor_->output_layout().coded_size().width() !=
             device_input_layout_->coded_size().width() ||
-        image_processor_->output_allocated_size().height() <
+        image_processor_->output_layout().coded_size().height() <
             device_input_layout_->coded_size().height()) {
       VLOGF(1) << "Invalid image processor output coded size "
-               << image_processor_->output_allocated_size().ToString()
+               << image_processor_->output_layout().coded_size().ToString()
                << ", encode input coded size is "
                << device_input_layout_->coded_size().ToString();
       return false;
@@ -293,7 +293,7 @@
       FROM_HERE,
       base::Bind(&Client::RequireBitstreamBuffers, client_, kInputBufferCount,
                  image_processor_.get()
-                     ? image_processor_->input_allocated_size()
+                     ? image_processor_->input_layout().coded_size()
                      : device_input_layout_->coded_size(),
                  output_buffer_byte_size_));
   return true;
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc
index c66e389..9abf1aa 100644
--- a/media/gpu/windows/d3d11_video_decoder.cc
+++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -694,33 +694,33 @@
   create_device_func_ = std::move(callback);
 }
 
-void D3D11VideoDecoder::SetWasSupportedReason(
-    D3D11VideoNotSupportedReason enum_value) {
+void D3D11VideoDecoder::ReportNotSupportedReason(
+    NotSupportedReason enum_value) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   UMA_HISTOGRAM_ENUMERATION("Media.D3D11.WasVideoSupported", enum_value);
 
   const char* reason = nullptr;
   switch (enum_value) {
-    case D3D11VideoNotSupportedReason::kVideoIsSupported:
+    case NotSupportedReason::kVideoIsSupported:
       reason = "Playback is supported by D3D11VideoDecoder";
       break;
-    case D3D11VideoNotSupportedReason::kInsufficientD3D11FeatureLevel:
+    case NotSupportedReason::kInsufficientD3D11FeatureLevel:
       reason = "Insufficient D3D11 feature level";
       break;
-    case D3D11VideoNotSupportedReason::kProfileNotSupported:
+    case NotSupportedReason::kProfileNotSupported:
       reason = "Video profile is not supported by D3D11VideoDecoder";
       break;
-    case D3D11VideoNotSupportedReason::kCodecNotSupported:
+    case NotSupportedReason::kCodecNotSupported:
       reason = "H264 is required for D3D11VideoDecoder";
       break;
-    case D3D11VideoNotSupportedReason::kZeroCopyNv12Required:
+    case NotSupportedReason::kZeroCopyNv12Required:
       reason = "Must allow zero-copy NV12 for D3D11VideoDecoder";
       break;
-    case D3D11VideoNotSupportedReason::kZeroCopyVideoRequired:
+    case NotSupportedReason::kZeroCopyVideoRequired:
       reason = "Must allow zero-copy video for D3D11VideoDecoder";
       break;
-    case D3D11VideoNotSupportedReason::kEncryptedMedia:
+    case NotSupportedReason::kEncryptedMedia:
       reason = "Encrypted media is not enabled for D3D11VideoDecoder";
       break;
   }
@@ -738,30 +738,30 @@
 
   // Must allow zero-copy of nv12 textures.
   if (!gpu_preferences_.enable_zero_copy_dxgi_video) {
-    SetWasSupportedReason(D3D11VideoNotSupportedReason::kZeroCopyNv12Required);
+    ReportNotSupportedReason(NotSupportedReason::kZeroCopyNv12Required);
     return false;
   }
 
   if (gpu_workarounds_.disable_dxgi_zero_copy_video) {
-    SetWasSupportedReason(D3D11VideoNotSupportedReason::kZeroCopyVideoRequired);
+    ReportNotSupportedReason(NotSupportedReason::kZeroCopyVideoRequired);
     return false;
   }
 
   if (config.profile() == H264PROFILE_HIGH10PROFILE) {
     // H264 HIGH10 is never supported.
-    SetWasSupportedReason(D3D11VideoNotSupportedReason::kProfileNotSupported);
+    ReportNotSupportedReason(NotSupportedReason::kProfileNotSupported);
     return false;
   }
 
   if (IsUnsupportedVP9Profile(config)) {
-    SetWasSupportedReason(D3D11VideoNotSupportedReason::kProfileNotSupported);
+    ReportNotSupportedReason(NotSupportedReason::kProfileNotSupported);
     return false;
   }
 
   bool encrypted_stream = config.is_encrypted();
 
   if (encrypted_stream && !base::FeatureList::IsEnabled(kD3D11EncryptedMedia)) {
-    SetWasSupportedReason(D3D11VideoNotSupportedReason::kEncryptedMedia);
+    ReportNotSupportedReason(NotSupportedReason::kEncryptedMedia);
     return false;
   }
 
@@ -772,7 +772,7 @@
   // If we got the empty guid, fail.
   GUID empty_guid = {};
   if (decoder_GUID == empty_guid) {
-    SetWasSupportedReason(D3D11VideoNotSupportedReason::kCodecNotSupported);
+    ReportNotSupportedReason(NotSupportedReason::kCodecNotSupported);
     return false;
   }
 
@@ -789,21 +789,21 @@
       D3D11_SDK_VERSION, nullptr, &usable_feature_level_, nullptr);
 
   if (FAILED(hr)) {
-    SetWasSupportedReason(
-        D3D11VideoNotSupportedReason::kInsufficientD3D11FeatureLevel);
+    ReportNotSupportedReason(
+        NotSupportedReason::kInsufficientD3D11FeatureLevel);
     return false;
   }
 
   if (encrypted_stream && usable_feature_level_ == D3D_FEATURE_LEVEL_11_0) {
-    SetWasSupportedReason(
-        D3D11VideoNotSupportedReason::kInsufficientD3D11FeatureLevel);
+    ReportNotSupportedReason(
+        NotSupportedReason::kInsufficientD3D11FeatureLevel);
     return false;
   }
 
   // TODO(liberato): dxva checks IsHDR() in the target colorspace, but we don't
   // have the target colorspace.  It's commented as being for vpx, though, so
   // we skip it here for now.
-  SetWasSupportedReason(D3D11VideoNotSupportedReason::kVideoIsSupported);
+  ReportNotSupportedReason(NotSupportedReason::kVideoIsSupported);
   return true;
 }
 
diff --git a/media/gpu/windows/d3d11_video_decoder.h b/media/gpu/windows/d3d11_video_decoder.h
index 80a461e0..9ae3024 100644
--- a/media/gpu/windows/d3d11_video_decoder.h
+++ b/media/gpu/windows/d3d11_video_decoder.h
@@ -120,7 +120,7 @@
   // main thread.
   void CreatePictureBuffers();
 
-  enum class D3D11VideoNotSupportedReason {
+  enum class NotSupportedReason {
     kVideoIsSupported = 0,
 
     // D3D11 version 11.1 required.
@@ -165,9 +165,9 @@
     kError,
   };
 
-  // Record a UMA about why IsPotentiallySupported returned false, or that it
-  // returned true.  Also will add a MediaLog entry, etc.
-  void SetWasSupportedReason(D3D11VideoNotSupportedReason enum_value);
+  // Reports why IsPotentiallySupported() returned false, or that it returned
+  // true. It is reported to UMA and MediaLog, etc.
+  void ReportNotSupportedReason(NotSupportedReason enum_value);
 
   // Callback to notify that new CdmContext event is available.
   void OnCdmContextEvent(CdmContext::Event event);
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc
index 9cc6152e..707f416 100644
--- a/remoting/protocol/webrtc_transport.cc
+++ b/remoting/protocol/webrtc_transport.cc
@@ -108,6 +108,53 @@
   }
 }
 
+// Returns true if the RTC stats report indicates a relay connection. If the
+// connection type cannot be determined (which should never happen with a valid
+// RTCStatsReport), this returns false.
+bool IsConnectionRelayed(
+    const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) {
+  auto transport_stats_list =
+      report->GetStatsOfType<webrtc::RTCTransportStats>();
+  if (transport_stats_list.size() != 1) {
+    LOG(ERROR) << "Unexpected number of transport stats: "
+               << transport_stats_list.size();
+    return false;
+  }
+  std::string selected_candidate_pair_id =
+      *(transport_stats_list[0]->selected_candidate_pair_id);
+  const webrtc::RTCStats* selected_candidate_pair =
+      report->Get(selected_candidate_pair_id);
+  if (!selected_candidate_pair) {
+    LOG(ERROR) << "Expected to find RTC stats for id: "
+               << selected_candidate_pair;
+    return false;
+  }
+  std::string local_candidate_id =
+      *(selected_candidate_pair->cast_to<webrtc::RTCIceCandidatePairStats>()
+            .local_candidate_id);
+  const webrtc::RTCStats* local_candidate = report->Get(local_candidate_id);
+  if (!local_candidate) {
+    LOG(ERROR) << "Expected to find RTC stats for id: " << local_candidate_id;
+    return false;
+  }
+  std::string local_candidate_type =
+      *(local_candidate->cast_to<webrtc::RTCLocalIceCandidateStats>()
+            .candidate_type);
+  std::string remote_candidate_id =
+      *(selected_candidate_pair->cast_to<webrtc::RTCIceCandidatePairStats>()
+            .remote_candidate_id);
+  const webrtc::RTCStats* remote_candidate = report->Get(remote_candidate_id);
+  if (!remote_candidate) {
+    LOG(ERROR) << "Expected to find RTC stats for id: " << remote_candidate_id;
+    return false;
+  }
+  std::string remote_candidate_type =
+      *(remote_candidate->cast_to<webrtc::RTCRemoteIceCandidateStats>()
+            .candidate_type);
+
+  return local_candidate_type == "relay" || remote_candidate_type == "relay";
+}
+
 // A webrtc::CreateSessionDescriptionObserver implementation used to receive the
 // results of creating descriptions for this end of the PeerConnection.
 class CreateSessionDescriptionObserver
@@ -506,6 +553,29 @@
   return true;
 }
 
+void WebrtcTransport::Close(ErrorCode error) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (!peer_connection_wrapper_)
+    return;
+
+  weak_factory_.InvalidateWeakPtrs();
+
+  // Close and delete PeerConnection asynchronously. PeerConnection may be on
+  // the stack and so it must be destroyed later.
+  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
+      FROM_HERE, peer_connection_wrapper_.release());
+
+  if (error != OK)
+    event_handler_->OnWebrtcTransportError(error);
+}
+
+void WebrtcTransport::ApplySessionOptions(const SessionOptions& options) {
+  base::Optional<std::string> video_codec = options.Get("Video-Codec");
+  if (video_codec) {
+    preferred_video_codec_ = *video_codec;
+  }
+}
+
 void WebrtcTransport::OnLocalSessionDescriptionCreated(
     std::unique_ptr<webrtc::SessionDescriptionInterface> description,
     const std::string& error) {
@@ -651,17 +721,6 @@
   }
 }
 
-void WebrtcTransport::RequestNegotiation() {
-  DCHECK(transport_context_->role() == TransportRole::SERVER);
-
-  if (!negotiation_pending_) {
-    negotiation_pending_ = true;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&WebrtcTransport::SendOffer, weak_factory_.GetWeakPtr()));
-  }
-}
-
 void WebrtcTransport::OnIceConnectionChange(
     webrtc::PeerConnectionInterface::IceConnectionState new_state) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -715,47 +774,7 @@
 
 void WebrtcTransport::OnStatsDelivered(
     const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) {
-  auto transport_stats_list =
-      report->GetStatsOfType<webrtc::RTCTransportStats>();
-  if (transport_stats_list.size() != 1) {
-    LOG(ERROR) << "Unexpected number of transport stats: "
-               << transport_stats_list.size();
-    return;
-  }
-  std::string selected_candidate_pair_id =
-      *(transport_stats_list[0]->selected_candidate_pair_id);
-  const webrtc::RTCStats* selected_candidate_pair =
-      report->Get(selected_candidate_pair_id);
-  if (!selected_candidate_pair) {
-    LOG(ERROR) << "Expected to find RTC stats for id: "
-               << selected_candidate_pair;
-    return;
-  }
-  std::string local_candidate_id =
-      *(selected_candidate_pair->cast_to<webrtc::RTCIceCandidatePairStats>()
-            .local_candidate_id);
-  const webrtc::RTCStats* local_candidate = report->Get(local_candidate_id);
-  if (!local_candidate) {
-    LOG(ERROR) << "Expected to find RTC stats for id: " << local_candidate_id;
-    return;
-  }
-  std::string local_candidate_type =
-      *(local_candidate->cast_to<webrtc::RTCLocalIceCandidateStats>()
-            .candidate_type);
-  std::string remote_candidate_id =
-      *(selected_candidate_pair->cast_to<webrtc::RTCIceCandidatePairStats>()
-            .remote_candidate_id);
-  const webrtc::RTCStats* remote_candidate = report->Get(remote_candidate_id);
-  if (!remote_candidate) {
-    LOG(ERROR) << "Expected to find RTC stats for id: " << remote_candidate_id;
-    return;
-  }
-  std::string remote_candidate_type =
-      *(remote_candidate->cast_to<webrtc::RTCRemoteIceCandidateStats>()
-            .candidate_type);
-
-  bool is_relay =
-      local_candidate_type == "relay" || remote_candidate_type == "relay";
+  bool is_relay = IsConnectionRelayed(report);
   VLOG(0) << "Relay connection: " << (is_relay ? "true" : "false");
 
   if (is_relay) {
@@ -769,32 +788,59 @@
     // Apply the suggested bitrate cap to prevent large amounts of packet loss.
     // The Google TURN/relay server limits the connection speed by dropping
     // packets, which may interact badly with WebRTC's bandwidth-estimation.
-    auto senders = peer_connection()->GetSenders();
-    for (rtc::scoped_refptr<webrtc::RtpSenderInterface> sender : senders) {
-      // x-google-max-bitrate is only set for video codecs in the SDP exchange.
-      // So avoid setting a very large bitrate cap on the audio sender.
-      if (sender->media_type() != cricket::MediaType::MEDIA_TYPE_VIDEO) {
-        continue;
-      }
-
-      webrtc::RtpParameters parameters = sender->GetParameters();
-      if (parameters.encodings.empty()) {
-        LOG(ERROR) << "No encodings found for sender " << sender->id();
-        continue;
-      }
-
-      if (parameters.encodings.size() != 1) {
-        LOG(ERROR) << "Unexpected number of encodings ("
-                   << parameters.encodings.size() << ") for sender "
-                   << sender->id();
-      }
-
-      parameters.encodings[0].max_bitrate_bps = max_bitrate_kbps * 1000;
-      sender->SetParameters(parameters);
+    // Only set the cap on the VideoSender, because the AudioSender (via the
+    // Opus codec) is already configured with a lower bitrate.
+    rtc::scoped_refptr<webrtc::RtpSenderInterface> sender = GetVideoSender();
+    if (!sender) {
+      LOG(ERROR) << "Video sender not found.";
+      return;
     }
+
+    webrtc::RtpParameters parameters = sender->GetParameters();
+    if (parameters.encodings.empty()) {
+      LOG(ERROR) << "No encodings found for sender " << sender->id();
+      return;
+    }
+
+    if (parameters.encodings.size() != 1) {
+      LOG(ERROR) << "Unexpected number of encodings ("
+                 << parameters.encodings.size() << ") for sender "
+                 << sender->id();
+    }
+
+    parameters.encodings[0].max_bitrate_bps = max_bitrate_kbps * 1000;
+    sender->SetParameters(parameters);
   }
 }
 
+void WebrtcTransport::RequestNegotiation() {
+  DCHECK(transport_context_->role() == TransportRole::SERVER);
+
+  if (!negotiation_pending_) {
+    negotiation_pending_ = true;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&WebrtcTransport::SendOffer,
+                                  weak_factory_.GetWeakPtr()));
+  }
+}
+
+void WebrtcTransport::SendOffer() {
+  DCHECK(transport_context_->role() == TransportRole::SERVER);
+
+  DCHECK(negotiation_pending_);
+  negotiation_pending_ = false;
+
+  webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
+  options.offer_to_receive_video = true;
+  options.offer_to_receive_audio = false;
+  options.ice_restart = want_ice_restart_;
+  peer_connection()->CreateOffer(
+      CreateSessionDescriptionObserver::Create(base::BindRepeating(
+          &WebrtcTransport::OnLocalSessionDescriptionCreated,
+          weak_factory_.GetWeakPtr())),
+      options);
+}
+
 void WebrtcTransport::EnsurePendingTransportInfoMessage() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -815,23 +861,6 @@
   }
 }
 
-void WebrtcTransport::SendOffer() {
-  DCHECK(transport_context_->role() == TransportRole::SERVER);
-
-  DCHECK(negotiation_pending_);
-  negotiation_pending_ = false;
-
-  webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
-  options.offer_to_receive_video = true;
-  options.offer_to_receive_audio = false;
-  options.ice_restart = want_ice_restart_;
-  peer_connection()->CreateOffer(
-      CreateSessionDescriptionObserver::Create(
-          base::Bind(&WebrtcTransport::OnLocalSessionDescriptionCreated,
-                     weak_factory_.GetWeakPtr())),
-      options);
-}
-
 void WebrtcTransport::SendTransportInfo() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(pending_transport_info_message_);
@@ -855,27 +884,15 @@
   }
 }
 
-void WebrtcTransport::Close(ErrorCode error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (!peer_connection_wrapper_)
-    return;
-
-  weak_factory_.InvalidateWeakPtrs();
-
-  // Close and delete PeerConnection asynchronously. PeerConnection may be on
-  // the stack and so it must be destroyed later.
-  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
-      FROM_HERE, peer_connection_wrapper_.release());
-
-  if (error != OK)
-    event_handler_->OnWebrtcTransportError(error);
-}
-
-void WebrtcTransport::ApplySessionOptions(const SessionOptions& options) {
-  base::Optional<std::string> video_codec = options.Get("Video-Codec");
-  if (video_codec) {
-    preferred_video_codec_ = *video_codec;
+rtc::scoped_refptr<webrtc::RtpSenderInterface>
+WebrtcTransport::GetVideoSender() {
+  auto senders = peer_connection()->GetSenders();
+  for (rtc::scoped_refptr<webrtc::RtpSenderInterface> sender : senders) {
+    if (sender->media_type() == cricket::MediaType::MEDIA_TYPE_VIDEO) {
+      return sender;
+    }
   }
+  return nullptr;
 }
 
 }  // namespace protocol
diff --git a/remoting/protocol/webrtc_transport.h b/remoting/protocol/webrtc_transport.h
index 63133f2a..e9086c2 100644
--- a/remoting/protocol/webrtc_transport.h
+++ b/remoting/protocol/webrtc_transport.h
@@ -127,6 +127,10 @@
   void SendTransportInfo();
   void AddPendingCandidatesIfPossible();
 
+  // Returns the VideoSender for this connection, or nullptr if it hasn't
+  // been created yet.
+  rtc::scoped_refptr<webrtc::RtpSenderInterface> GetVideoSender();
+
   base::ThreadChecker thread_checker_;
 
   scoped_refptr<TransportContext> transport_context_;
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
index 15bd782..e4cf802 100644
--- a/services/network/network_service.cc
+++ b/services/network/network_service.cc
@@ -523,6 +523,11 @@
   CrossOriginReadBlocking::RemoveExceptionForPlugin(process_id);
 }
 
+void NetworkService::OnMemoryPressure(
+    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+  base::MemoryPressureListener::NotifyMemoryPressure(memory_pressure_level);
+}
+
 #if defined(OS_ANDROID)
 void NetworkService::OnApplicationStateChange(
     base::android::ApplicationState state) {
diff --git a/services/network/network_service.h b/services/network/network_service.h
index 5f440de..1ce00fa 100644
--- a/services/network/network_service.h
+++ b/services/network/network_service.h
@@ -183,6 +183,8 @@
 #endif
   void AddCorbExceptionForPlugin(uint32_t process_id) override;
   void RemoveCorbExceptionForPlugin(uint32_t process_id) override;
+  void OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel
+                            memory_pressure_level) override;
 #if defined(OS_ANDROID)
   void OnApplicationStateChange(base::android::ApplicationState state) override;
 #endif
diff --git a/services/network/public/cpp/network_param.typemap b/services/network/public/cpp/network_param.typemap
index e8a71b2..32dc46c7 100644
--- a/services/network/public/cpp/network_param.typemap
+++ b/services/network/public/cpp/network_param.typemap
@@ -4,6 +4,7 @@
 
 mojom = "//services/network/public/mojom/network_param.mojom"
 public_headers = [
+  "//base/memory/memory_pressure_listener.h",
   "//net/base/auth.h",
   "//net/base/host_port_pair.h",
   "//net/cert/cert_verify_result.h",
@@ -40,6 +41,7 @@
   "network.mojom.HostPortPair=net::HostPortPair",
   "network.mojom.HttpResponseHeaders=scoped_refptr<net::HttpResponseHeaders>[nullable_is_same_type]",
   "network.mojom.HttpVersion=net::HttpVersion",
+  "network.mojom.MemoryPressureLevel=base::MemoryPressureListener::MemoryPressureLevel",
   "network.mojom.SSLCertRequestInfo=scoped_refptr<net::SSLCertRequestInfo>[nullable_is_same_type]",
   "network.mojom.SSLInfo=net::SSLInfo",
   "network.mojom.X509Certificate=scoped_refptr<net::X509Certificate>[nullable_is_same_type]",
diff --git a/services/network/public/cpp/network_param_mojom_traits.cc b/services/network/public/cpp/network_param_mojom_traits.cc
index 7b51f55..47ea7922 100644
--- a/services/network/public/cpp/network_param_mojom_traits.cc
+++ b/services/network/public/cpp/network_param_mojom_traits.cc
@@ -62,4 +62,41 @@
 }
 #endif
 
+network::mojom::MemoryPressureLevel
+EnumTraits<network::mojom::MemoryPressureLevel,
+           base::MemoryPressureListener::MemoryPressureLevel>::
+    ToMojom(base::MemoryPressureListener::MemoryPressureLevel input) {
+  switch (input) {
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+      return network::mojom::MemoryPressureLevel::NONE;
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      return network::mojom::MemoryPressureLevel::MODERATE;
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      return network::mojom::MemoryPressureLevel::CRITICAL;
+  }
+  NOTREACHED();
+  return static_cast<network::mojom::MemoryPressureLevel>(input);
+}
+
+bool EnumTraits<network::mojom::MemoryPressureLevel,
+                base::MemoryPressureListener::MemoryPressureLevel>::
+    FromMojom(network::mojom::MemoryPressureLevel input,
+              base::MemoryPressureListener::MemoryPressureLevel* output) {
+  switch (input) {
+    case network::mojom::MemoryPressureLevel::NONE:
+      *output = base::MemoryPressureListener::MemoryPressureLevel::
+          MEMORY_PRESSURE_LEVEL_NONE;
+      return true;
+    case network::mojom::MemoryPressureLevel::MODERATE:
+      *output = base::MemoryPressureListener::MemoryPressureLevel::
+          MEMORY_PRESSURE_LEVEL_MODERATE;
+      return true;
+    case network::mojom::MemoryPressureLevel::CRITICAL:
+      *output = base::MemoryPressureListener::MemoryPressureLevel::
+          MEMORY_PRESSURE_LEVEL_CRITICAL;
+      return true;
+  }
+  return false;
+}
+
 }  // namespace mojo
diff --git a/services/network/public/cpp/network_param_mojom_traits.h b/services/network/public/cpp/network_param_mojom_traits.h
index 2840fe9..dbf9dab4 100644
--- a/services/network/public/cpp/network_param_mojom_traits.h
+++ b/services/network/public/cpp/network_param_mojom_traits.h
@@ -5,6 +5,7 @@
 #ifndef SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_
 #define SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_
 
+#include "base/memory/memory_pressure_listener.h"
 #include "build/build_config.h"
 #include "mojo/public/cpp/bindings/struct_traits.h"
 #include "net/http/http_version.h"
@@ -41,6 +42,16 @@
 };
 #endif
 
+template <>
+struct EnumTraits<network::mojom::MemoryPressureLevel,
+                  base::MemoryPressureListener::MemoryPressureLevel> {
+  static network::mojom::MemoryPressureLevel ToMojom(
+      base::MemoryPressureListener::MemoryPressureLevel input);
+  static bool FromMojom(
+      network::mojom::MemoryPressureLevel input,
+      base::MemoryPressureListener::MemoryPressureLevel* output);
+};
+
 }  // namespace mojo
 
 #endif  // SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_
diff --git a/services/network/public/mojom/network_param.mojom b/services/network/public/mojom/network_param.mojom
index e8b54d7..57dec30f 100644
--- a/services/network/public/mojom/network_param.mojom
+++ b/services/network/public/mojom/network_param.mojom
@@ -14,6 +14,13 @@
   HAS_DESTROYED_ACTIVITIES,
 };
 
+// Mirror of base::MemoryPressureListener::MemoryPressureLevel.
+enum MemoryPressureLevel {
+  NONE,
+  MODERATE,
+  CRITICAL,
+};
+
 [Native]
 struct AuthChallengeInfo;
 
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index 11c4762..49fbe92 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -352,6 +352,9 @@
   // Reverts AddCorbExceptionForPlugin.
   RemoveCorbExceptionForPlugin(uint32 process_id);
 
+  // Called when the system is low on memory.
+  OnMemoryPressure(MemoryPressureLevel memory_pressure_level);
+
   // Called on state changes of the Android application.
   [EnableIf=is_android]
   OnApplicationStateChange(ApplicationState state);
diff --git a/services/network/public/mojom/network_service_test.mojom b/services/network/public/mojom/network_service_test.mojom
index fda35294..9925ae0 100644
--- a/services/network/public/mojom/network_service_test.mojom
+++ b/services/network/public/mojom/network_service_test.mojom
@@ -73,4 +73,9 @@
 
   // Causes the next host resolve to the given hostname to crash the process.
   CrashOnResolveHost(string host);
+
+  // Gets the latest memory pressure level reported by the
+  // MemoryPressureListener.
+  [Sync]
+  GetLatestMemoryPressureLevel() => (MemoryPressureLevel memory_pressure_level);
 };
diff --git a/services/service_manager/sandbox/mac/sandbox_mac.mm b/services/service_manager/sandbox/mac/sandbox_mac.mm
index f83bcee..d3b9305 100644
--- a/services/service_manager/sandbox/mac/sandbox_mac.mm
+++ b/services/service_manager/sandbox/mac/sandbox_mac.mm
@@ -27,9 +27,9 @@
 #include "base/mac/scoped_cftyperef.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
 #include "base/metrics/field_trial_memory_mac.h"
 #include "base/rand_util.h"
+#include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
@@ -108,8 +108,8 @@
   {  // CGImageSourceGetStatus() - 10.6
      // Create a png with just enough data to get everything warmed up...
     char png_header[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
-    NSData* data =
-        [NSData dataWithBytes:png_header length:arraysize(png_header)];
+    NSData* data = [NSData dataWithBytes:png_header
+                                  length:base::size(png_header)];
     base::ScopedCFTypeRef<CGImageSourceRef> img(
         CGImageSourceCreateWithData((CFDataRef)data, NULL));
     CGImageSourceGetStatus(img);
diff --git a/services/service_manager/sandbox/win/sandbox_win.cc b/services/service_manager/sandbox/win/sandbox_win.cc
index 8d7453d..f4c3eed 100644
--- a/services/service_manager/sandbox/win/sandbox_win.cc
+++ b/services/service_manager/sandbox/win/sandbox_win.cc
@@ -17,7 +17,6 @@
 #include "base/files/file_util.h"
 #include "base/hash.h"
 #include "base/logging.h"
-#include "base/macros.h"
 #include "base/memory/shared_memory.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_functions.h"
@@ -25,6 +24,7 @@
 #include "base/path_service.h"
 #include "base/process/launch.h"
 #include "base/sha1.h"
+#include "base/stl_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
@@ -185,12 +185,12 @@
 // Compares the loaded |module| file name matches |module_name|.
 bool IsExpandedModuleName(HMODULE module, const wchar_t* module_name) {
   wchar_t path[MAX_PATH];
-  DWORD sz = ::GetModuleFileNameW(module, path, arraysize(path));
-  if ((sz == arraysize(path)) || (sz == 0)) {
+  DWORD sz = ::GetModuleFileNameW(module, path, base::size(path));
+  if ((sz == base::size(path)) || (sz == 0)) {
     // XP does not set the last error properly, so we bail out anyway.
     return false;
   }
-  if (!::GetLongPathName(path, path, arraysize(path)))
+  if (!::GetLongPathName(path, path, base::size(path)))
     return false;
   base::FilePath fname(path);
   return (fname.BaseName().value() == module_name);
@@ -239,7 +239,7 @@
 // Eviction of injected DLLs is done by the sandbox so that the injected module
 // does not get a chance to execute any code.
 void AddGenericDllEvictionPolicy(sandbox::TargetPolicy* policy) {
-  for (int ix = 0; ix != arraysize(kTroublesomeDlls); ++ix)
+  for (int ix = 0; ix != base::size(kTroublesomeDlls); ++ix)
     BlacklistAddOneDll(kTroublesomeDlls[ix], true, policy);
 }
 
diff --git a/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc b/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc
index 247bcb3e..25fa17e 100644
--- a/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc
+++ b/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "mojo/public/cpp/base/string16_mojom_traits.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
@@ -138,7 +139,7 @@
   };
 
   mojom::IMEStructTraitsTestPtr proxy = GetTraitsTestProxy();
-  for (size_t i = 0; i < arraysize(kTextInputModes); i++) {
+  for (size_t i = 0; i < base::size(kTextInputModes); i++) {
     ui::TextInputMode mode_out;
     ASSERT_TRUE(proxy->EchoTextInputMode(kTextInputModes[i], &mode_out));
     EXPECT_EQ(kTextInputModes[i], mode_out);
@@ -167,7 +168,7 @@
   };
 
   mojom::IMEStructTraitsTestPtr proxy = GetTraitsTestProxy();
-  for (size_t i = 0; i < arraysize(kTextInputTypes); i++) {
+  for (size_t i = 0; i < base::size(kTextInputTypes); i++) {
     ui::TextInputType type_out;
     ASSERT_TRUE(proxy->EchoTextInputType(kTextInputTypes[i], &type_out));
     EXPECT_EQ(kTextInputTypes[i], type_out);
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index a1b1ef5..b2b0d5b 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -157,9 +157,7 @@
     defines += [ "SK_FREETYPE_MINIMUM_RUNTIME_VERSION=(((FREETYPE_MAJOR) * 0x01000000) | ((FREETYPE_MINOR) * 0x00010000) | ((FREETYPE_PATCH) * 0x00000100))" ]
   }
 
-  if (is_component_build) {
-    defines += [ "SKIA_IMPLEMENTATION=1" ]
-  }
+  defines += [ "SKIA_IMPLEMENTATION=1" ]
 
   if (current_cpu == "arm") {
     if (arm_use_neon) {
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn
index 75fa738..c0f1005 100644
--- a/storage/browser/BUILD.gn
+++ b/storage/browser/BUILD.gn
@@ -197,10 +197,9 @@
     "quota/storage_observer.h",
     "quota/usage_tracker.cc",
     "quota/usage_tracker.h",
-    "storage_browser_export.h",
   ]
 
-  defines = [ "STORAGE_BROWSER_IMPLEMENTATION" ]
+  defines = [ "IS_STORAGE_BROWSER_IMPL" ]
   configs += [
     "//build/config:precompiled_headers",
 
diff --git a/storage/browser/blob/blob_builder_from_stream.h b/storage/browser/blob/blob_builder_from_stream.h
index d97752ee..7ee4d518 100644
--- a/storage/browser/blob/blob_builder_from_stream.h
+++ b/storage/browser/blob/blob_builder_from_stream.h
@@ -5,12 +5,12 @@
 #ifndef STORAGE_BROWSER_BLOB_BLOB_BUILDER_FROM_STREAM_H
 #define STORAGE_BROWSER_BLOB_BLOB_BUILDER_FROM_STREAM_H
 
+#include "base/component_export.h"
 #include "base/containers/queue.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/blob/shareable_blob_data_item.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h"
 
 namespace storage {
@@ -44,7 +44,7 @@
 // TODO(mek): Actually deal with length_hint.
 //
 // If destroyed before building has finished this will not create a blob.
-class STORAGE_EXPORT BlobBuilderFromStream {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobBuilderFromStream {
  public:
   using ResultCallback =
       base::OnceCallback<void(BlobBuilderFromStream*,
diff --git a/storage/browser/blob/blob_data_builder.h b/storage/browser/blob/blob_data_builder.h
index 35ce853..af3efee5 100644
--- a/storage/browser/blob/blob_data_builder.h
+++ b/storage/browser/blob/blob_data_builder.h
@@ -11,6 +11,7 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -21,7 +22,6 @@
 #include "storage/browser/blob/shareable_blob_data_item.h"
 #include "storage/browser/blob/shareable_file_reference.h"
 #include "storage/browser/fileapi/file_system_context.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace disk_cache {
 class Entry;
@@ -41,7 +41,7 @@
 // bytes item, but we don't have the memory or file yet. See AppendFuture* and
 // PopulateFuture* methods for more description. Use
 // BlobDataHandle::GetBlobStatus to check for an error after creating the blob.
-class STORAGE_EXPORT BlobDataBuilder {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataBuilder {
  public:
   using DataHandle = BlobDataItem::DataHandle;
   using ItemCopyEntry = BlobEntry::ItemCopyEntry;
@@ -69,7 +69,7 @@
   void AppendData(const char* data, size_t length);
 
   // Represents a piece of unpopulated data.
-  class STORAGE_EXPORT FutureData {
+  class COMPONENT_EXPORT(STORAGE_BROWSER) FutureData {
    public:
     FutureData(FutureData&&);
     FutureData& operator=(FutureData&&);
@@ -104,7 +104,7 @@
   FutureData AppendFutureData(size_t length);
 
   // Represents an unpopulated file.
-  class STORAGE_EXPORT FutureFile {
+  class COMPONENT_EXPORT(STORAGE_BROWSER) FutureFile {
    public:
     FutureFile(FutureFile&&);
     FutureFile& operator=(FutureFile&&);
@@ -232,8 +232,9 @@
 
  private:
   friend class BlobStorageContext;
-  friend STORAGE_EXPORT void PrintTo(const BlobDataBuilder& x,
-                                     ::std::ostream* os);
+  friend COMPONENT_EXPORT(STORAGE_BROWSER) void PrintTo(
+      const BlobDataBuilder& x,
+      ::std::ostream* os);
   friend class BlobSliceTest;
 
   void SliceBlob(const BlobEntry* entry,
diff --git a/storage/browser/blob/blob_data_handle.h b/storage/browser/blob/blob_data_handle.h
index 5290b904..9324afd 100644
--- a/storage/browser/blob/blob_data_handle.h
+++ b/storage/browser/blob/blob_data_handle.h
@@ -10,12 +10,12 @@
 #include <string>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner_helpers.h"
 #include "base/supports_user_data.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/blob_storage/blob_storage_constants.h"
 
 namespace base {
@@ -37,7 +37,7 @@
 // resources remain around for the duration of reading the blob.  This snapshot
 // can be read on any thread, but it must be destructed on the IO thread.
 // This object has delete semantics and may be deleted on any thread.
-class STORAGE_EXPORT BlobDataHandle
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataHandle
     : public base::SupportsUserData::Data {
  public:
   static constexpr uint64_t kUnknownSize = std::numeric_limits<uint64_t>::max();
diff --git a/storage/browser/blob/blob_data_item.h b/storage/browser/blob/blob_data_item.h
index b955d5a..91d5d53 100644
--- a/storage/browser/blob/blob_data_item.h
+++ b/storage/browser/blob/blob_data_item.h
@@ -11,10 +11,10 @@
 #include <ostream>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/containers/span.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
-#include "storage/browser/storage_browser_export.h"
 #include "url/gurl.h"
 
 namespace disk_cache {
@@ -31,7 +31,8 @@
 // this class is to allow the resource to stick around in the snapshot even
 // after the resource was swapped in the blob (either to disk or to memory) by
 // the BlobStorageContext.
-class STORAGE_EXPORT BlobDataItem : public base::RefCounted<BlobDataItem> {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataItem
+    : public base::RefCounted<BlobDataItem> {
  public:
   enum class Type {
     kBytes,
@@ -46,7 +47,8 @@
   // pending. If all blobs with this item are deleted or the item is swapped for
   // a different backend version (mem-to-disk or the reverse), then the item
   // will be destructed after all pending reads are complete.
-  class STORAGE_EXPORT DataHandle : public base::RefCounted<DataHandle> {
+  class COMPONENT_EXPORT(STORAGE_BROWSER) DataHandle
+      : public base::RefCounted<DataHandle> {
    public:
     virtual bool IsValid();
 
@@ -148,7 +150,8 @@
   friend class BlobDataBuilder;
   friend class BlobStorageContext;
   friend class base::RefCounted<BlobDataItem>;
-  friend STORAGE_EXPORT void PrintTo(const BlobDataItem& x, ::std::ostream* os);
+  friend COMPONENT_EXPORT(STORAGE_BROWSER) void PrintTo(const BlobDataItem& x,
+                                                        ::std::ostream* os);
 
   BlobDataItem(Type type, uint64_t offset, uint64_t length);
   virtual ~BlobDataItem();
@@ -198,8 +201,10 @@
       file_system_context_;  // For Type::kFileFilesystem.
 };
 
-STORAGE_EXPORT bool operator==(const BlobDataItem& a, const BlobDataItem& b);
-STORAGE_EXPORT bool operator!=(const BlobDataItem& a, const BlobDataItem& b);
+COMPONENT_EXPORT(STORAGE_BROWSER)
+bool operator==(const BlobDataItem& a, const BlobDataItem& b);
+COMPONENT_EXPORT(STORAGE_BROWSER)
+bool operator!=(const BlobDataItem& a, const BlobDataItem& b);
 
 }  // namespace storage
 
diff --git a/storage/browser/blob/blob_data_snapshot.h b/storage/browser/blob/blob_data_snapshot.h
index 3db666e..19c44d2 100644
--- a/storage/browser/blob/blob_data_snapshot.h
+++ b/storage/browser/blob/blob_data_snapshot.h
@@ -10,10 +10,10 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/memory/ref_counted.h"
 #include "base/supports_user_data.h"
 #include "storage/browser/blob/blob_data_item.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 class BlobDataBuilder;
@@ -25,7 +25,8 @@
 // guarantees that the resources stay alive, but it does not guarentee that
 // the blob stays alive.  Use the BlobDataHandle to keep a blob alive.
 // This class must be deleted on the IO thread.
-class STORAGE_EXPORT BlobDataSnapshot : public base::SupportsUserData::Data {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataSnapshot
+    : public base::SupportsUserData::Data {
  public:
   BlobDataSnapshot(const BlobDataSnapshot& other);
   ~BlobDataSnapshot() override;
@@ -44,8 +45,9 @@
  private:
   friend class BlobDataBuilder;
   friend class BlobStorageContext;
-  friend STORAGE_EXPORT void PrintTo(const BlobDataSnapshot& x,
-                                     ::std::ostream* os);
+  friend COMPONENT_EXPORT(STORAGE_BROWSER) void PrintTo(
+      const BlobDataSnapshot& x,
+      ::std::ostream* os);
   BlobDataSnapshot(const std::string& uuid,
                    const std::string& content_type,
                    const std::string& content_disposition);
diff --git a/storage/browser/blob/blob_entry.h b/storage/browser/blob/blob_entry.h
index 9611b425..e159e65 100644
--- a/storage/browser/blob/blob_entry.h
+++ b/storage/browser/blob/blob_entry.h
@@ -12,19 +12,19 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "storage/browser/blob/blob_memory_controller.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 class BlobDataHandle;
 class ShareableBlobDataItem;
 
 // Represents a blob in BlobStorageRegistry. Exported only for unit tests.
-class STORAGE_EXPORT BlobEntry {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobEntry {
  public:
   using TransportAllowedCallback = base::OnceCallback<
       void(BlobStatus, std::vector<BlobMemoryController::FileCreationInfo>)>;
@@ -32,7 +32,7 @@
 
   // Records a copy from a referenced blob. Copies happen after referenced blobs
   // are complete & quota for the copies is granted.
-  struct STORAGE_EXPORT ItemCopyEntry {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) ItemCopyEntry {
     ItemCopyEntry(scoped_refptr<ShareableBlobDataItem> source_item,
                   size_t source_item_offset,
                   scoped_refptr<ShareableBlobDataItem> dest_item);
@@ -53,7 +53,7 @@
   // 2. Waiting for user population of data after quota (PENDING_TRANSPORT)
   // 3. Waiting for blobs we reference to complete & quota granted for possible
   //    copies. (PENDING_INTERNALS)
-  struct STORAGE_EXPORT BuildingState {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) BuildingState {
     // |transport_allowed_callback| is not null when data needs population. See
     // BlobStorageContext::BuildBlob for when the callback is called.
     BuildingState(bool transport_items_present,
diff --git a/storage/browser/blob/blob_impl.h b/storage/browser/blob/blob_impl.h
index 70b2d41..5397e48 100644
--- a/storage/browser/blob/blob_impl.h
+++ b/storage/browser/blob/blob_impl.h
@@ -5,9 +5,9 @@
 #ifndef STORAGE_BROWSER_BLOB_BLOB_IMPL_H_
 #define STORAGE_BROWSER_BLOB_BLOB_IMPL_H_
 
+#include "base/component_export.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/network/public/mojom/data_pipe_getter.mojom.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 
 namespace storage {
@@ -15,8 +15,9 @@
 class BlobDataHandle;
 
 // Self destroys when no more bindings exist.
-class STORAGE_EXPORT BlobImpl : public blink::mojom::Blob,
-                                public network::mojom::DataPipeGetter {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobImpl
+    : public blink::mojom::Blob,
+      public network::mojom::DataPipeGetter {
  public:
   static base::WeakPtr<BlobImpl> Create(std::unique_ptr<BlobDataHandle> handle,
                                         blink::mojom::BlobRequest request);
diff --git a/storage/browser/blob/blob_memory_controller.h b/storage/browser/blob/blob_memory_controller.h
index c60d193..6824d436 100644
--- a/storage/browser/blob/blob_memory_controller.h
+++ b/storage/browser/blob/blob_memory_controller.h
@@ -18,6 +18,7 @@
 
 #include "base/callback_forward.h"
 #include "base/callback_helpers.h"
+#include "base/component_export.h"
 #include "base/containers/mru_cache.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
@@ -28,7 +29,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/time/time.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/blob_storage/blob_storage_constants.h"
 
 namespace base {
@@ -52,7 +52,7 @@
 // * Maintaining an LRU of memory items to choose candidates to page to disk
 //   (NotifyMemoryItemsUsed).
 // This class can only be interacted with on the IO thread.
-class STORAGE_EXPORT BlobMemoryController {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobMemoryController {
  public:
   enum class Strategy {
     // We don't have enough memory for this blob.
@@ -65,7 +65,7 @@
     FILE
   };
 
-  struct STORAGE_EXPORT FileCreationInfo {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) FileCreationInfo {
     FileCreationInfo();
     ~FileCreationInfo();
     FileCreationInfo(FileCreationInfo&& other);
diff --git a/storage/browser/blob/blob_reader.h b/storage/browser/blob/blob_reader.h
index 4614fd6d..b63b6e5 100644
--- a/storage/browser/blob/blob_reader.h
+++ b/storage/browser/blob/blob_reader.h
@@ -12,12 +12,12 @@
 #include <memory>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "net/base/completion_once_callback.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/blob_storage/blob_storage_constants.h"
 
 class GURL;
@@ -49,9 +49,9 @@
 //
 // For more information on how to read Blobs in your specific situation, see:
 // https://chromium.googlesource.com/chromium/src/+/HEAD/storage/browser/blob/README.md#accessing-reading
-class STORAGE_EXPORT BlobReader {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobReader {
  public:
-  class STORAGE_EXPORT FileStreamReaderProvider {
+  class COMPONENT_EXPORT(STORAGE_BROWSER) FileStreamReaderProvider {
    public:
     virtual ~FileStreamReaderProvider();
 
diff --git a/storage/browser/blob/blob_registry_impl.h b/storage/browser/blob/blob_registry_impl.h
index 16a6e19c..213fb2a 100644
--- a/storage/browser/blob/blob_registry_impl.h
+++ b/storage/browser/blob/blob_registry_impl.h
@@ -6,12 +6,12 @@
 #define STORAGE_BROWSER_BLOB_BLOB_REGISTRY_IMPL_H_
 
 #include <memory>
+#include "base/component_export.h"
 #include "base/containers/flat_set.h"
 #include "base/containers/unique_ptr_adapters.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "storage/browser/fileapi/file_system_context.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h"
 
 namespace storage {
@@ -21,7 +21,8 @@
 class BlobStorageContext;
 class FileSystemURL;
 
-class STORAGE_EXPORT BlobRegistryImpl : public blink::mojom::BlobRegistry {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobRegistryImpl
+    : public blink::mojom::BlobRegistry {
  public:
   // Per binding delegate, used for security checks for requests coming in on
   // specific bindings/from specific processes.
diff --git a/storage/browser/blob/blob_storage_context.h b/storage/browser/blob/blob_storage_context.h
index e0bb90a..a323049 100644
--- a/storage/browser/blob/blob_storage_context.h
+++ b/storage/browser/blob/blob_storage_context.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -23,7 +24,6 @@
 #include "storage/browser/blob/blob_entry.h"
 #include "storage/browser/blob/blob_memory_controller.h"
 #include "storage/browser/blob/blob_storage_registry.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/blob_storage/blob_storage_constants.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 
@@ -45,7 +45,7 @@
 // This class handles the logistics of blob storage within the browser process.
 // This class is not threadsafe, access on IO thread. In Chromium there is one
 // instance per profile.
-class STORAGE_EXPORT BlobStorageContext
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobStorageContext
     : public base::trace_event::MemoryDumpProvider {
  public:
   using TransportAllowedCallback = BlobEntry::TransportAllowedCallback;
diff --git a/storage/browser/blob/blob_storage_registry.h b/storage/browser/blob/blob_storage_registry.h
index f1cadc1..86e6bffb 100644
--- a/storage/browser/blob/blob_storage_registry.h
+++ b/storage/browser/blob/blob_storage_registry.h
@@ -14,9 +14,9 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/unguessable_token.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/blob_storage/blob_storage_constants.h"
 
 class GURL;
@@ -29,7 +29,7 @@
 // Implementation notes:
 // * When removing a uuid registration, we do not check for URL mappings to that
 //   uuid. The user must keep track of these.
-class STORAGE_EXPORT BlobStorageRegistry {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobStorageRegistry {
  public:
   BlobStorageRegistry();
   ~BlobStorageRegistry();
diff --git a/storage/browser/blob/blob_transport_strategy.h b/storage/browser/blob/blob_transport_strategy.h
index 6ddeadb..24be11f 100644
--- a/storage/browser/blob/blob_transport_strategy.h
+++ b/storage/browser/blob/blob_transport_strategy.h
@@ -6,8 +6,8 @@
 #define STORAGE_BROWSER_BLOB_BLOB_TRANSPORT_STRATEGY_H_
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "storage/browser/blob/blob_memory_controller.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h"
 
 namespace storage {
@@ -17,7 +17,7 @@
 // This class is responsible for transporting bytes for an under-construction
 // blob, using a specified transport strategy. This is used by BlobRegistryImpl
 // for the actual transportation of bytes.
-class STORAGE_EXPORT BlobTransportStrategy {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobTransportStrategy {
  public:
   using ResultCallback = base::OnceCallback<void(BlobStatus)>;
 
diff --git a/storage/browser/blob/blob_url_loader.h b/storage/browser/blob/blob_url_loader.h
index 2e1782d..907fa124 100644
--- a/storage/browser/blob/blob_url_loader.h
+++ b/storage/browser/blob/blob_url_loader.h
@@ -5,13 +5,13 @@
 #ifndef STORAGE_BROWSER_BLOB_BLOB_URL_LOADER_H_
 #define STORAGE_BROWSER_BLOB_BLOB_URL_LOADER_H_
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "storage/browser/blob/mojo_blob_reader.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 class BlobDataHandle;
@@ -20,8 +20,9 @@
 // or after passing ownership to MojoBlobReader at the end of the Start
 // method) when it has finished responding.
 // Note: some of this code is duplicated from BlobURLRequestJob.
-class STORAGE_EXPORT BlobURLLoader : public storage::MojoBlobReader::Delegate,
-                                     public network::mojom::URLLoader {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobURLLoader
+    : public storage::MojoBlobReader::Delegate,
+      public network::mojom::URLLoader {
  public:
   static void CreateAndStart(
       network::mojom::URLLoaderRequest url_loader_request,
diff --git a/storage/browser/blob/blob_url_loader_factory.h b/storage/browser/blob/blob_url_loader_factory.h
index aa8a9af..53c597e 100644
--- a/storage/browser/blob/blob_url_loader_factory.h
+++ b/storage/browser/blob/blob_url_loader_factory.h
@@ -5,9 +5,9 @@
 #ifndef STORAGE_BROWSER_BLOB_BLOB_URL_LOADER_FACTORY_H_
 #define STORAGE_BROWSER_BLOB_BLOB_URL_LOADER_FACTORY_H_
 
+#include "base/component_export.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
 
 namespace storage {
@@ -18,7 +18,7 @@
 // URLLoaderFactory that can create loaders for exactly one url, loading the
 // blob that was passed to its constructor. This factory keeps the blob alive.
 // Self destroys when no more bindings exist.
-class STORAGE_EXPORT BlobURLLoaderFactory
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobURLLoaderFactory
     : public network::mojom::URLLoaderFactory {
  public:
   static void Create(std::unique_ptr<BlobDataHandle> handle,
diff --git a/storage/browser/blob/blob_url_request_job.h b/storage/browser/blob/blob_url_request_job.h
index 7379360..5305044 100644
--- a/storage/browser/blob/blob_url_request_job.h
+++ b/storage/browser/blob/blob_url_request_job.h
@@ -11,13 +11,13 @@
 #include <memory>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "net/http/http_byte_range.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/url_request_job.h"
 #include "storage/browser/blob/blob_reader.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace net {
 class HttpResponseHeaders;
@@ -29,7 +29,7 @@
 class BlobDataHandle;
 
 // A request job that handles reading blob URLs.
-class STORAGE_EXPORT BlobURLRequestJob
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobURLRequestJob
     : public net::URLRequestJob {
  public:
   BlobURLRequestJob(net::URLRequest* request,
diff --git a/storage/browser/blob/blob_url_request_job_factory.h b/storage/browser/blob/blob_url_request_job_factory.h
index d2d189d..38c8cc5 100644
--- a/storage/browser/blob/blob_url_request_job_factory.h
+++ b/storage/browser/blob/blob_url_request_job_factory.h
@@ -8,11 +8,11 @@
 #include <memory>
 
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_job_factory.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace net {
 class URLRequestContext;
@@ -23,7 +23,7 @@
 class BlobDataHandle;
 class BlobStorageContext;
 
-class STORAGE_EXPORT BlobProtocolHandler
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobProtocolHandler
     : public net::URLRequestJobFactory::ProtocolHandler {
  public:
   // A helper to manufacture an URLRequest to retrieve the given blob.
diff --git a/storage/browser/blob/blob_url_store_impl.h b/storage/browser/blob/blob_url_store_impl.h
index 3db2a3d..959ed1e 100644
--- a/storage/browser/blob/blob_url_store_impl.h
+++ b/storage/browser/blob/blob_url_store_impl.h
@@ -6,15 +6,17 @@
 #define STORAGE_BROWSER_BLOB_BLOB_URL_STORE_IMPL_H_
 
 #include <memory>
+
+#include "base/component_export.h"
 #include "storage/browser/blob/blob_registry_impl.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
 
 namespace storage {
 
 class BlobStorageContext;
 
-class STORAGE_EXPORT BlobURLStoreImpl : public blink::mojom::BlobURLStore {
+class COMPONENT_EXPORT(STORAGE_BROWSER) BlobURLStoreImpl
+    : public blink::mojom::BlobURLStore {
  public:
   BlobURLStoreImpl(base::WeakPtr<BlobStorageContext> context,
                    BlobRegistryImpl::Delegate* delegate);
diff --git a/storage/browser/blob/mojo_blob_reader.h b/storage/browser/blob/mojo_blob_reader.h
index 518d7a5f..42796fd0 100644
--- a/storage/browser/blob/mojo_blob_reader.h
+++ b/storage/browser/blob/mojo_blob_reader.h
@@ -6,6 +6,8 @@
 #define STORAGE_BROWSER_BLOB_MOJO_BLOB_READER_H_
 
 #include <memory>
+
+#include "base/component_export.h"
 #include "base/memory/ref_counted.h"
 #include "base/sequence_checker.h"
 #include "mojo/public/cpp/system/data_pipe.h"
@@ -13,7 +15,6 @@
 #include "net/base/net_errors.h"
 #include "net/http/http_byte_range.h"
 #include "storage/browser/blob/blob_reader.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace net {
 class IOBufferWithSize;
@@ -28,7 +29,7 @@
 
 // Reads a blob into a data pipe. Owns itself, and owns its delegate. Self
 // destructs when reading is complete.
-class STORAGE_EXPORT MojoBlobReader {
+class COMPONENT_EXPORT(STORAGE_BROWSER) MojoBlobReader {
  public:
   // Methods on this delegate are called in the order they are defined here.
   // With the exception of DidRead, each method is called at most once.
diff --git a/storage/browser/blob/scoped_file.h b/storage/browser/blob/scoped_file.h
index 7f50bb4..73f06ec 100644
--- a/storage/browser/blob/scoped_file.h
+++ b/storage/browser/blob/scoped_file.h
@@ -8,10 +8,10 @@
 #include <map>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class TaskRunner;
@@ -25,7 +25,7 @@
 //
 // TODO(kinuko): Probably this can be moved under base or somewhere more
 // common place.
-class STORAGE_EXPORT ScopedFile {
+class COMPONENT_EXPORT(STORAGE_BROWSER) ScopedFile {
  public:
   using ScopeOutCallback = base::OnceCallback<void(const base::FilePath&)>;
   enum ScopeOutPolicy {
diff --git a/storage/browser/blob/shareable_blob_data_item.h b/storage/browser/blob/shareable_blob_data_item.h
index b6a6442..b4d877e7 100644
--- a/storage/browser/blob/shareable_blob_data_item.h
+++ b/storage/browser/blob/shareable_blob_data_item.h
@@ -8,12 +8,12 @@
 #include <string>
 
 #include "base/callback_helpers.h"
+#include "base/component_export.h"
 #include "base/containers/hash_tables.h"
 #include "base/hash.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "storage/browser/blob/blob_memory_controller.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 class BlobDataItem;
@@ -25,7 +25,7 @@
 // RAM vs file backed).
 // We also allow the storage of a memory quota allocation object which is used
 // for memory quota reclamation.
-class STORAGE_EXPORT ShareableBlobDataItem
+class COMPONENT_EXPORT(STORAGE_BROWSER) ShareableBlobDataItem
     : public base::RefCounted<ShareableBlobDataItem> {
  public:
   enum State {
@@ -69,8 +69,9 @@
   friend class BlobMemoryControllerTest;
   friend class BlobStorageContext;
   friend class base::RefCounted<ShareableBlobDataItem>;
-  friend STORAGE_EXPORT void PrintTo(const ShareableBlobDataItem& x,
-                                     ::std::ostream* os);
+  friend COMPONENT_EXPORT(STORAGE_BROWSER) void PrintTo(
+      const ShareableBlobDataItem& x,
+      ::std::ostream* os);
 
   ~ShareableBlobDataItem();
 
@@ -90,10 +91,10 @@
   DISALLOW_COPY_AND_ASSIGN(ShareableBlobDataItem);
 };
 
-STORAGE_EXPORT bool operator==(const ShareableBlobDataItem& a,
-                               const ShareableBlobDataItem& b);
-STORAGE_EXPORT bool operator!=(const ShareableBlobDataItem& a,
-                               const ShareableBlobDataItem& b);
+COMPONENT_EXPORT(STORAGE_BROWSER)
+bool operator==(const ShareableBlobDataItem& a, const ShareableBlobDataItem& b);
+COMPONENT_EXPORT(STORAGE_BROWSER)
+bool operator!=(const ShareableBlobDataItem& a, const ShareableBlobDataItem& b);
 
 }  // namespace storage
 #endif  // STORAGE_BROWSER_BLOB_SHAREABLE_BLOB_DATA_ITEM_H_
diff --git a/storage/browser/blob/shareable_file_reference.h b/storage/browser/blob/shareable_file_reference.h
index 295a9e9..c009c70 100644
--- a/storage/browser/blob/shareable_file_reference.h
+++ b/storage/browser/blob/shareable_file_reference.h
@@ -5,10 +5,10 @@
 #ifndef STORAGE_BROWSER_BLOB_SHAREABLE_FILE_REFERENCE_H_
 #define STORAGE_BROWSER_BLOB_SHAREABLE_FILE_REFERENCE_H_
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "storage/browser/blob/blob_data_item.h"
 #include "storage/browser/blob/scoped_file.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
@@ -16,7 +16,8 @@
 // same path if it already exists in its internal map.
 // This class is non-thread-safe and all methods must be called on a single
 // thread.
-class STORAGE_EXPORT ShareableFileReference : public BlobDataItem::DataHandle {
+class COMPONENT_EXPORT(STORAGE_BROWSER) ShareableFileReference
+    : public BlobDataItem::DataHandle {
  public:
   using FinalReleaseCallback = ScopedFile::ScopeOutCallback;
 
diff --git a/storage/browser/blob/upload_blob_element_reader.h b/storage/browser/blob/upload_blob_element_reader.h
index 7b08f12..11ca8198 100644
--- a/storage/browser/blob/upload_blob_element_reader.h
+++ b/storage/browser/blob/upload_blob_element_reader.h
@@ -9,11 +9,11 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/upload_element_reader.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace net {
 class IOBuffer;
@@ -26,7 +26,8 @@
 // This class is a wrapper around the BlobReader to make it conform
 // to the net::UploadElementReader interface, and it also holds around the
 // handle to the blob so it stays in memory while we read it.
-class STORAGE_EXPORT UploadBlobElementReader : public net::UploadElementReader {
+class COMPONENT_EXPORT(STORAGE_BROWSER) UploadBlobElementReader
+    : public net::UploadElementReader {
  public:
   explicit UploadBlobElementReader(std::unique_ptr<BlobDataHandle> handle);
   ~UploadBlobElementReader() override;
diff --git a/storage/browser/blob/view_blob_internals_job.h b/storage/browser/blob/view_blob_internals_job.h
index 4ad9a2b5..8a01c77 100644
--- a/storage/browser/blob/view_blob_internals_job.h
+++ b/storage/browser/blob/view_blob_internals_job.h
@@ -7,11 +7,11 @@
 
 #include <string>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "net/base/completion_once_callback.h"
 #include "net/url_request/url_request_simple_job.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace net {
 class URLRequest;
@@ -24,7 +24,7 @@
 
 // A job subclass that implements a protocol to inspect the internal
 // state of blob registry.
-class STORAGE_EXPORT ViewBlobInternalsJob
+class COMPONENT_EXPORT(STORAGE_BROWSER) ViewBlobInternalsJob
     : public net::URLRequestSimpleJob {
  public:
   ViewBlobInternalsJob(net::URLRequest* request,
diff --git a/storage/browser/database/database_quota_client.h b/storage/browser/database/database_quota_client.h
index b0de8e4..fa991a5 100644
--- a/storage/browser/database/database_quota_client.h
+++ b/storage/browser/database/database_quota_client.h
@@ -8,11 +8,11 @@
 #include <set>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "storage/browser/quota/quota_client.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/origin.h"
 
@@ -23,7 +23,8 @@
 // A QuotaClient implementation to integrate WebSQLDatabases
 // with the quota  management system. This interface is used
 // on the IO thread by the quota manager.
-class STORAGE_EXPORT DatabaseQuotaClient : public storage::QuotaClient {
+class COMPONENT_EXPORT(STORAGE_BROWSER) DatabaseQuotaClient
+    : public storage::QuotaClient {
  public:
   DatabaseQuotaClient(scoped_refptr<DatabaseTracker> tracker);
   ~DatabaseQuotaClient() override;
diff --git a/storage/browser/database/database_tracker.h b/storage/browser/database/database_tracker.h
index 6c7798ed..07e0630c 100644
--- a/storage/browser/database/database_tracker.h
+++ b/storage/browser/database/database_tracker.h
@@ -12,6 +12,7 @@
 #include <set>
 #include <utility>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
@@ -22,7 +23,6 @@
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "net/base/completion_once_callback.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/database/database_connections.h"
 
 namespace content {
@@ -42,15 +42,15 @@
 
 namespace storage {
 
-STORAGE_EXPORT extern const base::FilePath::CharType
-    kDatabaseDirectoryName[];
-STORAGE_EXPORT extern const base::FilePath::CharType
-    kTrackerDatabaseFileName[];
+COMPONENT_EXPORT(STORAGE_BROWSER)
+extern const base::FilePath::CharType kDatabaseDirectoryName[];
+COMPONENT_EXPORT(STORAGE_BROWSER)
+extern const base::FilePath::CharType kTrackerDatabaseFileName[];
 
 class DatabasesTable;
 
 // This class is used to store information about all databases in an origin.
-class STORAGE_EXPORT OriginInfo {
+class COMPONENT_EXPORT(STORAGE_BROWSER) OriginInfo {
  public:
   OriginInfo();
   OriginInfo(const OriginInfo& origin_info);
@@ -77,7 +77,7 @@
 // should be called on the task runner returned by |task_runner()|. The only
 // exceptions are the ctor(), the dtor() and the database_directory() and
 // quota_manager_proxy() getters.
-class STORAGE_EXPORT DatabaseTracker
+class COMPONENT_EXPORT(STORAGE_BROWSER) DatabaseTracker
     : public base::RefCountedThreadSafe<DatabaseTracker> {
  public:
   class Observer {
diff --git a/storage/browser/database/database_util.h b/storage/browser/database/database_util.h
index cf10659..a78e380 100644
--- a/storage/browser/database/database_util.h
+++ b/storage/browser/database/database_util.h
@@ -6,8 +6,9 @@
 #define STORAGE_BROWSER_DATABASE_DATABASE_UTIL_H_
 
 #include <string>
+
+#include "base/component_export.h"
 #include "base/strings/string16.h"
-#include "storage/browser/storage_browser_export.h"
 #include "url/gurl.h"
 
 namespace base {
@@ -18,7 +19,7 @@
 
 class DatabaseTracker;
 
-class STORAGE_EXPORT DatabaseUtil {
+class COMPONENT_EXPORT(STORAGE_BROWSER) DatabaseUtil {
  public:
   static const char kJournalFileSuffix[];
 
diff --git a/storage/browser/database/databases_table.h b/storage/browser/database/databases_table.h
index c622b807..6057346 100644
--- a/storage/browser/database/databases_table.h
+++ b/storage/browser/database/databases_table.h
@@ -9,8 +9,8 @@
 
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/strings/string16.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace sql {
 class Database;
@@ -18,7 +18,7 @@
 
 namespace storage {
 
-struct STORAGE_EXPORT DatabaseDetails {
+struct COMPONENT_EXPORT(STORAGE_BROWSER) DatabaseDetails {
   DatabaseDetails();
   DatabaseDetails(const DatabaseDetails& other);
   ~DatabaseDetails();
@@ -29,7 +29,7 @@
   int64_t estimated_size;
 };
 
-class STORAGE_EXPORT DatabasesTable {
+class COMPONENT_EXPORT(STORAGE_BROWSER) DatabasesTable {
  public:
   explicit DatabasesTable(sql::Database* db) : db_(db) {}
 
diff --git a/storage/browser/database/vfs_backend.h b/storage/browser/database/vfs_backend.h
index 9fcb08b..e53b471c 100644
--- a/storage/browser/database/vfs_backend.h
+++ b/storage/browser/database/vfs_backend.h
@@ -7,10 +7,10 @@
 
 #include <stdint.h>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/process/process.h"
 #include "base/strings/string16.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class FilePath;
@@ -18,7 +18,7 @@
 
 namespace storage {
 
-class STORAGE_EXPORT VfsBackend {
+class COMPONENT_EXPORT(STORAGE_BROWSER) VfsBackend {
  public:
    static base::File OpenFile(const base::FilePath& file_path,
                               int desired_flags);
diff --git a/storage/browser/fileapi/async_file_util.h b/storage/browser/fileapi/async_file_util.h
index c933738..3a5f45e1 100644
--- a/storage/browser/fileapi/async_file_util.h
+++ b/storage/browser/fileapi/async_file_util.h
@@ -11,11 +11,11 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/macros.h"
 #include "components/services/filesystem/public/interfaces/types.mojom.h"
 #include "storage/browser/fileapi/file_system_operation.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class Time;
@@ -82,8 +82,8 @@
   // Creates an AsyncFileUtil instance which performs file operations on
   // local native file system. The created instance assumes
   // FileSystemURL::path() has the target platform path.
-  STORAGE_EXPORT static AsyncFileUtil*
-      CreateForLocalFileSystem();
+  COMPONENT_EXPORT(STORAGE_BROWSER)
+  static AsyncFileUtil* CreateForLocalFileSystem();
 
   AsyncFileUtil() {}
   virtual ~AsyncFileUtil() {}
diff --git a/storage/browser/fileapi/async_file_util_adapter.h b/storage/browser/fileapi/async_file_util_adapter.h
index 76231644a..7a6add4 100644
--- a/storage/browser/fileapi/async_file_util_adapter.h
+++ b/storage/browser/fileapi/async_file_util_adapter.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "storage/browser/fileapi/async_file_util.h"
@@ -27,7 +28,8 @@
 //
 // This instance (as thus this->sync_file_util_) is guaranteed to be alive
 // as far as FileSystemOperationContext given to each operation is kept alive.
-class STORAGE_EXPORT AsyncFileUtilAdapter : public AsyncFileUtil {
+class COMPONENT_EXPORT(STORAGE_BROWSER) AsyncFileUtilAdapter
+    : public AsyncFileUtil {
  public:
   // Creates a new AsyncFileUtil for |sync_file_util|. This takes the
   // ownership of |sync_file_util|. (This doesn't take std::unique_ptr<> just
diff --git a/storage/browser/fileapi/copy_or_move_file_validator.h b/storage/browser/fileapi/copy_or_move_file_validator.h
index e2c05cc2..80fe801 100644
--- a/storage/browser/fileapi/copy_or_move_file_validator.h
+++ b/storage/browser/fileapi/copy_or_move_file_validator.h
@@ -6,8 +6,8 @@
 #define STORAGE_BROWSER_FILEAPI_COPY_OR_MOVE_FILE_VALIDATOR_H_
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class FilePath;
@@ -17,7 +17,7 @@
 
 class FileSystemURL;
 
-class STORAGE_EXPORT CopyOrMoveFileValidator {
+class COMPONENT_EXPORT(STORAGE_BROWSER) CopyOrMoveFileValidator {
  public:
   // Callback that is invoked when validation completes. A result of
   // base::File::FILE_OK means the file validated.
diff --git a/storage/browser/fileapi/copy_or_move_operation_delegate.h b/storage/browser/fileapi/copy_or_move_operation_delegate.h
index 47d92b7..8a08a12 100644
--- a/storage/browser/fileapi/copy_or_move_operation_delegate.h
+++ b/storage/browser/fileapi/copy_or_move_operation_delegate.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
@@ -45,7 +46,7 @@
 
   // Helper to copy a file by reader and writer streams.
   // Export for testing.
-  class STORAGE_EXPORT StreamCopyHelper {
+  class COMPONENT_EXPORT(STORAGE_BROWSER) StreamCopyHelper {
    public:
     StreamCopyHelper(
         std::unique_ptr<storage::FileStreamReader> reader,
diff --git a/storage/browser/fileapi/dragged_file_util.h b/storage/browser/fileapi/dragged_file_util.h
index c170910c..cbd33b30c 100644
--- a/storage/browser/fileapi/dragged_file_util.h
+++ b/storage/browser/fileapi/dragged_file_util.h
@@ -7,9 +7,9 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "storage/browser/fileapi/local_file_util.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
@@ -18,7 +18,7 @@
 // Dragged file system is a specialized LocalFileUtil where read access to
 // the virtual root directory (i.e. empty cracked path case) is allowed
 // and single isolated context may be associated with multiple file paths.
-class STORAGE_EXPORT DraggedFileUtil : public LocalFileUtil {
+class COMPONENT_EXPORT(STORAGE_BROWSER) DraggedFileUtil : public LocalFileUtil {
  public:
   DraggedFileUtil();
   ~DraggedFileUtil() override {}
diff --git a/storage/browser/fileapi/external_mount_points.h b/storage/browser/fileapi/external_mount_points.h
index 965766e..c339725c4 100644
--- a/storage/browser/fileapi/external_mount_points.h
+++ b/storage/browser/fileapi/external_mount_points.h
@@ -10,11 +10,11 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
 #include "storage/browser/fileapi/mount_points.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_mount_option.h"
 #include "storage/common/fileapi/file_system_types.h"
 
@@ -32,7 +32,7 @@
 //
 //   filesystem:<origin>/external/<mount_name>/relative/path
 //
-class STORAGE_EXPORT ExternalMountPoints
+class COMPONENT_EXPORT(STORAGE_BROWSER) ExternalMountPoints
     : public base::RefCountedThreadSafe<ExternalMountPoints>,
       public MountPoints {
  public:
diff --git a/storage/browser/fileapi/file_observers.h b/storage/browser/fileapi/file_observers.h
index f45c6337..901e2a19 100644
--- a/storage/browser/fileapi/file_observers.h
+++ b/storage/browser/fileapi/file_observers.h
@@ -7,8 +7,8 @@
 
 #include <stdint.h>
 
+#include "base/component_export.h"
 #include "base/macros.h"
-#include "storage/browser/storage_browser_export.h"
 
 // TODO(kinuko): Split this file into per-observer multiple files.
 
@@ -29,7 +29,7 @@
 //
 // OnUpdate() is called each time the |url| is updated but works only for
 // sandboxed files (where usage is tracked).
-class STORAGE_EXPORT FileUpdateObserver {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileUpdateObserver {
  public:
   FileUpdateObserver() {}
   virtual ~FileUpdateObserver() {}
@@ -46,7 +46,7 @@
 // OnAccess is called whenever an operation reads file contents or metadata.
 // (It is called only once per operation regardless of whether the operation
 // is recursive or not)
-class STORAGE_EXPORT FileAccessObserver {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileAccessObserver {
  public:
   FileAccessObserver() {}
   virtual ~FileAccessObserver() {}
@@ -62,7 +62,7 @@
 // removed or modified.  For recursive operations each method is called for
 // each subdirectory/subfile.  Currently ChangeObserver is only supported
 // by the local sandbox file system.
-class STORAGE_EXPORT FileChangeObserver {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileChangeObserver {
  public:
   FileChangeObserver() {}
   virtual ~FileChangeObserver() {}
diff --git a/storage/browser/fileapi/file_permission_policy.h b/storage/browser/fileapi/file_permission_policy.h
index 8580954..88c2ee84 100644
--- a/storage/browser/fileapi/file_permission_policy.h
+++ b/storage/browser/fileapi/file_permission_policy.h
@@ -5,8 +5,6 @@
 #ifndef STORAGE_BROWSER_FILEAPI_FILE_PERMISSION_POLICY_H_
 #define STORAGE_BROWSER_FILEAPI_FILE_PERMISSION_POLICY_H_
 
-#include "storage/browser/storage_browser_export.h"
-
 namespace storage {
 
 enum FilePermissionPolicy {
diff --git a/storage/browser/fileapi/file_stream_reader.h b/storage/browser/fileapi/file_stream_reader.h
index 99fba8c..1aeaf0e 100644
--- a/storage/browser/fileapi/file_stream_reader.h
+++ b/storage/browser/fileapi/file_stream_reader.h
@@ -8,9 +8,9 @@
 #include <stdint.h>
 
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "net/base/completion_once_callback.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class FilePath;
@@ -41,7 +41,8 @@
   // actual modification time to see if the file has been modified, and if
   // it does any succeeding read operations should fail with
   // ERR_UPLOAD_FILE_CHANGED error.
-  STORAGE_EXPORT static FileStreamReader* CreateForLocalFile(
+  COMPONENT_EXPORT(STORAGE_BROWSER)
+  static FileStreamReader* CreateForLocalFile(
       base::TaskRunner* task_runner,
       const base::FilePath& file_path,
       int64_t initial_offset,
@@ -52,16 +53,17 @@
   // the value is non-null, the reader will check the underlying file's actual
   // modification time to see if the file has been modified, and if it does any
   // succeeding read operations should fail with ERR_UPLOAD_FILE_CHANGED error.
-  STORAGE_EXPORT static FileStreamReader* CreateForFileSystemFile(
+  COMPONENT_EXPORT(STORAGE_BROWSER)
+  static FileStreamReader* CreateForFileSystemFile(
       storage::FileSystemContext* context,
       const storage::FileSystemURL& url,
       int64_t initial_offset,
       const base::Time& expected_modification_time);
 
   // Verify if the underlying file has not been modified.
-  STORAGE_EXPORT static bool VerifySnapshotTime(
-      const base::Time& expected_modification_time,
-      const base::File::Info& file_info);
+  COMPONENT_EXPORT(STORAGE_BROWSER)
+  static bool VerifySnapshotTime(const base::Time& expected_modification_time,
+                                 const base::File::Info& file_info);
 
   // It is valid to delete the reader at any time.  If the stream is deleted
   // while it has a pending read, its callback will not be called.
diff --git a/storage/browser/fileapi/file_stream_writer.h b/storage/browser/fileapi/file_stream_writer.h
index 83fc071..0d899c0 100644
--- a/storage/browser/fileapi/file_stream_writer.h
+++ b/storage/browser/fileapi/file_stream_writer.h
@@ -7,8 +7,8 @@
 
 #include <stdint.h>
 
+#include "base/component_export.h"
 #include "net/base/completion_once_callback.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class FilePath;
@@ -28,11 +28,11 @@
 
   // Creates a writer for the existing file in the path |file_path| starting
   // from |initial_offset|. Uses |task_runner| for async file operations.
-  STORAGE_EXPORT static FileStreamWriter* CreateForLocalFile(
-      base::TaskRunner* task_runner,
-      const base::FilePath& file_path,
-      int64_t initial_offset,
-      OpenOrCreate open_or_create);
+  COMPONENT_EXPORT(STORAGE_BROWSER)
+  static FileStreamWriter* CreateForLocalFile(base::TaskRunner* task_runner,
+                                              const base::FilePath& file_path,
+                                              int64_t initial_offset,
+                                              OpenOrCreate open_or_create);
 
   // Closes the file. If there's an in-flight operation, it is canceled (i.e.,
   // the callback function associated with the operation is not called).
diff --git a/storage/browser/fileapi/file_system_backend.h b/storage/browser/fileapi/file_system_backend.h
index 79825434..e811f95 100644
--- a/storage/browser/fileapi/file_system_backend.h
+++ b/storage/browser/fileapi/file_system_backend.h
@@ -13,12 +13,12 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "storage/browser/fileapi/file_permission_policy.h"
 #include "storage/browser/fileapi/open_file_system_mode.h"
 #include "storage/browser/fileapi/task_runner_bound_observer_list.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 
 class GURL;
@@ -48,7 +48,7 @@
 // NOTE: when you implement a new FileSystemBackend for your own
 // FileSystem module, please contact to kinuko@chromium.org.
 //
-class STORAGE_EXPORT FileSystemBackend {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemBackend {
  public:
   // Callback for InitializeFileSystem.
   using OpenFileSystemCallback =
diff --git a/storage/browser/fileapi/file_system_context.h b/storage/browser/fileapi/file_system_context.h
index f3ede98..9e4c99f 100644
--- a/storage/browser/fileapi/file_system_context.h
+++ b/storage/browser/fileapi/file_system_context.h
@@ -13,6 +13,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -23,7 +24,6 @@
 #include "storage/browser/fileapi/plugin_private_file_system_backend.h"
 #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
 #include "storage/browser/fileapi/task_runner_bound_observer_list.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 
 namespace base {
@@ -87,7 +87,7 @@
 
 // This class keeps and provides a file system context for FileSystem API.
 // An instance of this class is created and owned by profile.
-class STORAGE_EXPORT FileSystemContext
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
     : public base::RefCountedThreadSafe<FileSystemContext,
                                         DefaultContextDeleter> {
  public:
diff --git a/storage/browser/fileapi/file_system_dir_url_request_job.h b/storage/browser/fileapi/file_system_dir_url_request_job.h
index 9876c566..918b10b5 100644
--- a/storage/browser/fileapi/file_system_dir_url_request_job.h
+++ b/storage/browser/fileapi/file_system_dir_url_request_job.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
@@ -17,14 +18,14 @@
 #include "components/services/filesystem/public/interfaces/types.mojom.h"
 #include "net/url_request/url_request_job.h"
 #include "storage/browser/fileapi/file_system_url.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
 class FileSystemContext;
 
 // A request job that handles reading filesystem: URLs for directories.
-class STORAGE_EXPORT FileSystemDirURLRequestJob : public net::URLRequestJob {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemDirURLRequestJob
+    : public net::URLRequestJob {
  public:
   FileSystemDirURLRequestJob(
       net::URLRequest* request,
diff --git a/storage/browser/fileapi/file_system_file_stream_reader.h b/storage/browser/fileapi/file_system_file_stream_reader.h
index 78ff4e9..7bba41a 100644
--- a/storage/browser/fileapi/file_system_file_stream_reader.h
+++ b/storage/browser/fileapi/file_system_file_stream_reader.h
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -18,7 +19,6 @@
 #include "storage/browser/blob/shareable_file_reference.h"
 #include "storage/browser/fileapi/file_stream_reader.h"
 #include "storage/browser/fileapi/file_system_url.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class FilePath;
@@ -37,7 +37,7 @@
 // remote filesystem should implement its own reader rather than relying
 // on FileSystemOperation::GetSnapshotFile() which may force downloading
 // the entire contents for remote files.
-class STORAGE_EXPORT FileSystemFileStreamReader
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemFileStreamReader
     : public storage::FileStreamReader {
  public:
   ~FileSystemFileStreamReader() override;
diff --git a/storage/browser/fileapi/file_system_file_util.h b/storage/browser/fileapi/file_system_file_util.h
index af6bef6..d2448436 100644
--- a/storage/browser/fileapi/file_system_file_util.h
+++ b/storage/browser/fileapi/file_system_file_util.h
@@ -9,12 +9,12 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "storage/browser/blob/scoped_file.h"
 #include "storage/browser/fileapi/file_system_operation.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class Time;
@@ -30,12 +30,12 @@
 //
 // Layering structure of the FileSystemFileUtil was split out.
 // See http://crbug.com/128136 if you need it.
-class STORAGE_EXPORT FileSystemFileUtil {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemFileUtil {
  public:
   using CopyOrMoveOption = FileSystemOperation::CopyOrMoveOption;
 
   // It will be implemented by each subclass such as FileSystemFileEnumerator.
-  class STORAGE_EXPORT AbstractFileEnumerator {
+  class COMPONENT_EXPORT(STORAGE_BROWSER) AbstractFileEnumerator {
    public:
     virtual ~AbstractFileEnumerator() = default;
 
@@ -51,7 +51,7 @@
     virtual bool IsDirectory() = 0;
   };
 
-  class STORAGE_EXPORT EmptyFileEnumerator
+  class COMPONENT_EXPORT(STORAGE_BROWSER) EmptyFileEnumerator
       : public AbstractFileEnumerator {
     base::FilePath Next() override;
     int64_t Size() override;
diff --git a/storage/browser/fileapi/file_system_operation.h b/storage/browser/fileapi/file_system_operation.h
index a966684..5b02db07 100644
--- a/storage/browser/fileapi/file_system_operation.h
+++ b/storage/browser/fileapi/file_system_operation.h
@@ -11,13 +11,13 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/process/process.h"
 #include "components/services/filesystem/public/interfaces/types.mojom.h"
 #include "storage/browser/blob/blob_reader.h"
 #include "storage/browser/fileapi/file_system_operation_context.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class Time;
@@ -56,7 +56,8 @@
 // it gets called.
 class FileSystemOperation {
  public:
-  STORAGE_EXPORT static FileSystemOperation* Create(
+  COMPONENT_EXPORT(STORAGE_BROWSER)
+  static FileSystemOperation* Create(
       const FileSystemURL& url,
       FileSystemContext* file_system_context,
       std::unique_ptr<FileSystemOperationContext> operation_context);
diff --git a/storage/browser/fileapi/file_system_operation_context.h b/storage/browser/fileapi/file_system_operation_context.h
index 5e8b111..a291115 100644
--- a/storage/browser/fileapi/file_system_operation_context.h
+++ b/storage/browser/fileapi/file_system_operation_context.h
@@ -7,12 +7,12 @@
 
 #include <stdint.h>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/supports_user_data.h"
 #include "base/threading/thread_checker.h"
 #include "storage/browser/fileapi/task_runner_bound_observer_list.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/quota/quota_limit_type.h"
 
 namespace base {
@@ -29,7 +29,7 @@
 // the same context (e.g. use the same task runner, share the quota etc).
 // Note that the remaining quota bytes (allowed_bytes_growth) may be
 // updated during the execution of write operations.
-class STORAGE_EXPORT FileSystemOperationContext
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemOperationContext
     : public base::SupportsUserData {
  public:
   explicit FileSystemOperationContext(FileSystemContext* context);
diff --git a/storage/browser/fileapi/file_system_operation_impl.h b/storage/browser/fileapi/file_system_operation_impl.h
index d7a6047d..2f117fb7 100644
--- a/storage/browser/fileapi/file_system_operation_impl.h
+++ b/storage/browser/fileapi/file_system_operation_impl.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -18,7 +19,6 @@
 #include "storage/browser/fileapi/file_system_operation_context.h"
 #include "storage/browser/fileapi/file_system_url.h"
 #include "storage/browser/fileapi/file_writer_delegate.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 
 namespace storage {
@@ -28,7 +28,8 @@
 class RecursiveOperationDelegate;
 
 // The default implementation of FileSystemOperation for file systems.
-class STORAGE_EXPORT FileSystemOperationImpl : public FileSystemOperation {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemOperationImpl
+    : public FileSystemOperation {
  public:
   ~FileSystemOperationImpl() override;
 
diff --git a/storage/browser/fileapi/file_system_operation_runner.h b/storage/browser/fileapi/file_system_operation_runner.h
index 8617556..8be86ab 100644
--- a/storage/browser/fileapi/file_system_operation_runner.h
+++ b/storage/browser/fileapi/file_system_operation_runner.h
@@ -12,6 +12,7 @@
 #include <set>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/containers/id_map.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -19,7 +20,6 @@
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/fileapi/file_system_operation.h"
 #include "storage/browser/fileapi/file_system_url.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
@@ -33,7 +33,7 @@
 // operation fails, in addition to dispatching the callback with an error
 // code (therefore in most cases the caller does not need to check the
 // returned operation ID).
-class STORAGE_EXPORT FileSystemOperationRunner {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemOperationRunner {
  public:
   using GetMetadataCallback = FileSystemOperation::GetMetadataCallback;
   using ReadDirectoryCallback = FileSystemOperation::ReadDirectoryCallback;
diff --git a/storage/browser/fileapi/file_system_options.h b/storage/browser/fileapi/file_system_options.h
index c0228a3..a1d52d20 100644
--- a/storage/browser/fileapi/file_system_options.h
+++ b/storage/browser/fileapi/file_system_options.h
@@ -8,13 +8,13 @@
 #include <string>
 #include <vector>
 
-#include "storage/browser/storage_browser_export.h"
+#include "base/component_export.h"
 
 namespace storage {
 
 // Provides runtime options that may change FileSystem API behavior.
 // This object is copyable.
-class STORAGE_EXPORT FileSystemOptions {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemOptions {
  public:
   enum ProfileMode {
     PROFILE_MODE_NORMAL = 0,
diff --git a/storage/browser/fileapi/file_system_quota_client.h b/storage/browser/fileapi/file_system_quota_client.h
index 6705995..5e6d459 100644
--- a/storage/browser/fileapi/file_system_quota_client.h
+++ b/storage/browser/fileapi/file_system_quota_client.h
@@ -10,12 +10,12 @@
 #include <utility>
 
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "storage/browser/fileapi/file_system_quota_util.h"
 #include "storage/browser/quota/quota_client.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/origin.h"
@@ -33,7 +33,8 @@
 // is called.
 // All of the public methods of this class are called by the quota manager
 // (except for the constructor/destructor).
-class STORAGE_EXPORT FileSystemQuotaClient : public storage::QuotaClient {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemQuotaClient
+    : public storage::QuotaClient {
  public:
   FileSystemQuotaClient(
       FileSystemContext* file_system_context,
diff --git a/storage/browser/fileapi/file_system_quota_util.h b/storage/browser/fileapi/file_system_quota_util.h
index 1e54ded..938b4af 100644
--- a/storage/browser/fileapi/file_system_quota_util.h
+++ b/storage/browser/fileapi/file_system_quota_util.h
@@ -10,9 +10,9 @@
 #include <set>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/memory/scoped_refptr.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 #include "url/gurl.h"
 
@@ -29,7 +29,7 @@
 // for file_system_quota_client.
 // All the methods of this class are synchronous and need to be called on
 // the thread that the method name implies.
-class STORAGE_EXPORT FileSystemQuotaUtil {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemQuotaUtil {
  public:
   virtual ~FileSystemQuotaUtil() {}
 
diff --git a/storage/browser/fileapi/file_system_url.h b/storage/browser/fileapi/file_system_url.h
index 1661b334..8f1111c 100644
--- a/storage/browser/fileapi/file_system_url.h
+++ b/storage/browser/fileapi/file_system_url.h
@@ -8,8 +8,8 @@
 #include <set>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_mount_option.h"
 #include "storage/common/fileapi/file_system_types.h"
 #include "url/gurl.h"
@@ -75,7 +75,7 @@
 // illegal on the current platform.
 // To avoid problems, use VirtualPath::BaseName and
 // VirtualPath::GetComponents instead of the base::FilePath methods.
-class STORAGE_EXPORT FileSystemURL {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemURL {
  public:
   FileSystemURL();
   FileSystemURL(const FileSystemURL& other);
@@ -149,7 +149,7 @@
     return !(*this == that);
   }
 
-  struct STORAGE_EXPORT Comparator {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) Comparator {
     bool operator() (const FileSystemURL& lhs, const FileSystemURL& rhs) const;
   };
 
diff --git a/storage/browser/fileapi/file_system_url_request_job.h b/storage/browser/fileapi/file_system_url_request_job.h
index 162cc0e1..97929c3 100644
--- a/storage/browser/fileapi/file_system_url_request_job.h
+++ b/storage/browser/fileapi/file_system_url_request_job.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -18,7 +19,6 @@
 #include "net/http/http_byte_range.h"
 #include "net/url_request/url_request_job.h"
 #include "storage/browser/fileapi/file_system_url.h"
-#include "storage/browser/storage_browser_export.h"
 
 class GURL;
 
@@ -30,7 +30,8 @@
 class FileSystemContext;
 
 // A request job that handles reading filesystem: URLs
-class STORAGE_EXPORT FileSystemURLRequestJob : public net::URLRequestJob {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemURLRequestJob
+    : public net::URLRequestJob {
  public:
   FileSystemURLRequestJob(
       net::URLRequest* request,
diff --git a/storage/browser/fileapi/file_system_url_request_job_factory.h b/storage/browser/fileapi/file_system_url_request_job_factory.h
index 289d2105..61e1448 100644
--- a/storage/browser/fileapi/file_system_url_request_job_factory.h
+++ b/storage/browser/fileapi/file_system_url_request_job_factory.h
@@ -10,7 +10,7 @@
 
 #include "net/url_request/url_request_job_factory.h"
 
-#include "storage/browser/storage_browser_export.h"
+#include "base/component_export.h"
 
 namespace storage {
 
@@ -19,7 +19,8 @@
 // |context|'s lifetime should exceed the lifetime of the ProtocolHandler.
 // Currently, this is only used by ProfileIOData which owns |context| and the
 // ProtocolHandler.
-STORAGE_EXPORT std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>
+COMPONENT_EXPORT(STORAGE_BROWSER)
+std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>
 CreateFileSystemProtocolHandler(const std::string& storage_domain,
                                 FileSystemContext* context);
 
diff --git a/storage/browser/fileapi/file_system_usage_cache.h b/storage/browser/fileapi/file_system_usage_cache.h
index 613eb5f7..e2e03e1 100644
--- a/storage/browser/fileapi/file_system_usage_cache.h
+++ b/storage/browser/fileapi/file_system_usage_cache.h
@@ -10,17 +10,17 @@
 #include <map>
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/timer/timer.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
-class STORAGE_EXPORT FileSystemUsageCache {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemUsageCache {
  public:
   FileSystemUsageCache();
   ~FileSystemUsageCache();
diff --git a/storage/browser/fileapi/file_writer_delegate.h b/storage/browser/fileapi/file_writer_delegate.h
index 77dc1e9..c60db4be 100644
--- a/storage/browser/fileapi/file_writer_delegate.h
+++ b/storage/browser/fileapi/file_writer_delegate.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
@@ -19,14 +20,13 @@
 #include "net/base/file_stream.h"
 #include "net/base/io_buffer.h"
 #include "storage/browser/blob/blob_reader.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
 class FileStreamWriter;
 enum class FlushPolicy;
 
-class STORAGE_EXPORT FileWriterDelegate {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileWriterDelegate {
  public:
   enum WriteProgressStatus {
     SUCCESS_IO_PENDING,
diff --git a/storage/browser/fileapi/file_writer_impl.h b/storage/browser/fileapi/file_writer_impl.h
index 3abdf1bae..c5917ca 100644
--- a/storage/browser/fileapi/file_writer_impl.h
+++ b/storage/browser/fileapi/file_writer_impl.h
@@ -5,9 +5,9 @@
 #ifndef STORAGE_BROWSER_FILEAPI_FILE_WRITER_IMPL_H_
 #define STORAGE_BROWSER_FILEAPI_FILE_WRITER_IMPL_H_
 
+#include "base/component_export.h"
 #include "storage/browser/fileapi/file_system_operation_runner.h"
 #include "storage/browser/fileapi/file_system_url.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/filesystem/file_writer.mojom.h"
 
 namespace storage {
@@ -16,7 +16,8 @@
 // FileSystemOperationRunner and BlobStorageContext so all methods should be
 // called on the sequence those instances live on. In chromium that means all
 // usage has to be on the IO thread.
-class STORAGE_EXPORT FileWriterImpl : public blink::mojom::FileWriter {
+class COMPONENT_EXPORT(STORAGE_BROWSER) FileWriterImpl
+    : public blink::mojom::FileWriter {
  public:
   FileWriterImpl(FileSystemURL url,
                  std::unique_ptr<FileSystemOperationRunner> operation_runner,
diff --git a/storage/browser/fileapi/isolated_context.h b/storage/browser/fileapi/isolated_context.h
index 713b105..f5477a16 100644
--- a/storage/browser/fileapi/isolated_context.h
+++ b/storage/browser/fileapi/isolated_context.h
@@ -10,13 +10,13 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/synchronization/lock.h"
 #include "storage/browser/fileapi/mount_points.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 
 namespace storage {
@@ -37,9 +37,9 @@
 //
 // Some methods of this class are virtual just for mocking.
 //
-class STORAGE_EXPORT IsolatedContext : public MountPoints {
+class COMPONENT_EXPORT(STORAGE_BROWSER) IsolatedContext : public MountPoints {
  public:
-  class STORAGE_EXPORT FileInfoSet {
+  class COMPONENT_EXPORT(STORAGE_BROWSER) FileInfoSet {
    public:
     FileInfoSet();
     ~FileInfoSet();
diff --git a/storage/browser/fileapi/local_file_stream_reader.h b/storage/browser/fileapi/local_file_stream_reader.h
index 7705d12..7b0b269 100644
--- a/storage/browser/fileapi/local_file_stream_reader.h
+++ b/storage/browser/fileapi/local_file_stream_reader.h
@@ -10,13 +10,13 @@
 #include <memory>
 
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "net/base/completion_once_callback.h"
 #include "storage/browser/fileapi/file_stream_reader.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class TaskRunner;
@@ -34,7 +34,8 @@
 
 // A thin wrapper of net::FileStream with range support for sliced file
 // handling.
-class STORAGE_EXPORT LocalFileStreamReader : public FileStreamReader {
+class COMPONENT_EXPORT(STORAGE_BROWSER) LocalFileStreamReader
+    : public FileStreamReader {
  public:
   ~LocalFileStreamReader() override;
 
diff --git a/storage/browser/fileapi/local_file_stream_writer.h b/storage/browser/fileapi/local_file_stream_writer.h
index 38e8b47..466b36c8 100644
--- a/storage/browser/fileapi/local_file_stream_writer.h
+++ b/storage/browser/fileapi/local_file_stream_writer.h
@@ -12,12 +12,12 @@
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task_runner.h"
 #include "storage/browser/fileapi/file_stream_writer.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace content {
 class LocalFileStreamWriterTest;
@@ -30,7 +30,8 @@
 namespace storage {
 
 // This class is a thin wrapper around net::FileStream for writing local files.
-class STORAGE_EXPORT LocalFileStreamWriter : public FileStreamWriter {
+class COMPONENT_EXPORT(STORAGE_BROWSER) LocalFileStreamWriter
+    : public FileStreamWriter {
  public:
   ~LocalFileStreamWriter() override;
 
diff --git a/storage/browser/fileapi/local_file_util.h b/storage/browser/fileapi/local_file_util.h
index a886014..6406a30 100644
--- a/storage/browser/fileapi/local_file_util.h
+++ b/storage/browser/fileapi/local_file_util.h
@@ -10,10 +10,10 @@
 #include <memory>
 
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "storage/browser/fileapi/file_system_file_util.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class Time;
@@ -25,7 +25,7 @@
 class FileSystemURL;
 
 // An instance of this class is created and owned by *FileSystemBackend.
-class STORAGE_EXPORT LocalFileUtil
+class COMPONENT_EXPORT(STORAGE_BROWSER) LocalFileUtil
     : public FileSystemFileUtil {
  public:
   LocalFileUtil();
diff --git a/storage/browser/fileapi/mount_points.h b/storage/browser/fileapi/mount_points.h
index 10cf47d..8ca7ef6 100644
--- a/storage/browser/fileapi/mount_points.h
+++ b/storage/browser/fileapi/mount_points.h
@@ -8,9 +8,9 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_util.h"
 
 class GURL;
@@ -23,9 +23,9 @@
 namespace storage {
 
 // Represents a set of mount points for File API.
-class STORAGE_EXPORT MountPoints {
+class COMPONENT_EXPORT(STORAGE_BROWSER) MountPoints {
  public:
-  struct STORAGE_EXPORT MountPointInfo {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) MountPointInfo {
     MountPointInfo();
     MountPointInfo(const std::string& name, const base::FilePath& path);
 
diff --git a/storage/browser/fileapi/native_file_util.h b/storage/browser/fileapi/native_file_util.h
index e85eadb0..5dc9e1d4 100644
--- a/storage/browser/fileapi/native_file_util.h
+++ b/storage/browser/fileapi/native_file_util.h
@@ -9,11 +9,11 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "storage/browser/fileapi/file_system_file_util.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class Time;
@@ -31,7 +31,7 @@
 //
 // Note that all the methods of this class are static and this does NOT
 // inherit from FileSystemFileUtil.
-class STORAGE_EXPORT NativeFileUtil {
+class COMPONENT_EXPORT(STORAGE_BROWSER) NativeFileUtil {
  public:
   enum CopyOrMoveMode {
     COPY_NOSYNC,
diff --git a/storage/browser/fileapi/obfuscated_file_util.h b/storage/browser/fileapi/obfuscated_file_util.h
index f68671e8..742ffbd 100644
--- a/storage/browser/fileapi/obfuscated_file_util.h
+++ b/storage/browser/fileapi/obfuscated_file_util.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
@@ -24,7 +25,6 @@
 #include "storage/browser/fileapi/file_system_url.h"
 #include "storage/browser/fileapi/sandbox_directory_database.h"
 #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 
 namespace content {
@@ -66,7 +66,8 @@
 //
 // This class must be deleted on the FILE thread, because that's where
 // DropDatabases needs to be called.
-class STORAGE_EXPORT ObfuscatedFileUtil : public FileSystemFileUtil {
+class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtil
+    : public FileSystemFileUtil {
  public:
   // Origin enumerator interface.
   // An instance of this interface is assumed to be called on the file thread.
diff --git a/storage/browser/fileapi/plugin_private_file_system_backend.h b/storage/browser/fileapi/plugin_private_file_system_backend.h
index 9fc44127..f312846f 100644
--- a/storage/browser/fileapi/plugin_private_file_system_backend.h
+++ b/storage/browser/fileapi/plugin_private_file_system_backend.h
@@ -11,6 +11,7 @@
 #include <set>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -37,7 +38,7 @@
 class SpecialStoragePolicy;
 class WatcherManager;
 
-class STORAGE_EXPORT PluginPrivateFileSystemBackend
+class COMPONENT_EXPORT(STORAGE_BROWSER) PluginPrivateFileSystemBackend
     : public FileSystemBackend,
       public FileSystemQuotaUtil {
  public:
diff --git a/storage/browser/fileapi/quota/open_file_handle.h b/storage/browser/fileapi/quota/open_file_handle.h
index a48d29b..d142e3c 100644
--- a/storage/browser/fileapi/quota/open_file_handle.h
+++ b/storage/browser/fileapi/quota/open_file_handle.h
@@ -7,10 +7,10 @@
 
 #include <stdint.h>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class FilePath;
@@ -25,7 +25,7 @@
 // Represents an open file like a file descriptor.
 // This should be alive while a consumer keeps a file opened and should be
 // deleted when the plugin closes the file.
-class STORAGE_EXPORT OpenFileHandle {
+class COMPONENT_EXPORT(STORAGE_BROWSER) OpenFileHandle {
  public:
   ~OpenFileHandle();
 
diff --git a/storage/browser/fileapi/quota/open_file_handle_context.h b/storage/browser/fileapi/quota/open_file_handle_context.h
index ca1570c..9729137a 100644
--- a/storage/browser/fileapi/quota/open_file_handle_context.h
+++ b/storage/browser/fileapi/quota/open_file_handle_context.h
@@ -13,7 +13,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 #include "url/gurl.h"
 
diff --git a/storage/browser/fileapi/quota/quota_backend_impl.h b/storage/browser/fileapi/quota/quota_backend_impl.h
index 2a8e915..496a470a 100644
--- a/storage/browser/fileapi/quota/quota_backend_impl.h
+++ b/storage/browser/fileapi/quota/quota_backend_impl.h
@@ -7,12 +7,12 @@
 
 #include <stdint.h>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "storage/browser/fileapi/quota/quota_reservation_manager.h"
 #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/origin.h"
 
@@ -31,7 +31,7 @@
 class QuotaManagerProxy;
 
 // An instance of this class is owned by QuotaReservationManager.
-class STORAGE_EXPORT QuotaBackendImpl
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaBackendImpl
     : public QuotaReservationManager::QuotaBackend {
  public:
   using ReserveQuotaCallback = QuotaReservationManager::ReserveQuotaCallback;
diff --git a/storage/browser/fileapi/quota/quota_reservation.h b/storage/browser/fileapi/quota/quota_reservation.h
index 9f7fb7b..c93b04d 100644
--- a/storage/browser/fileapi/quota/quota_reservation.h
+++ b/storage/browser/fileapi/quota/quota_reservation.h
@@ -9,13 +9,13 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "storage/browser/fileapi/quota/quota_reservation_manager.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 
 namespace url {
@@ -28,7 +28,7 @@
 class OpenFileHandle;
 
 // Represents a unit of quota reservation.
-class STORAGE_EXPORT QuotaReservation
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaReservation
     : public base::RefCounted<QuotaReservation> {
  public:
   using StatusCallback = base::OnceCallback<void(base::File::Error error)>;
diff --git a/storage/browser/fileapi/quota/quota_reservation_buffer.h b/storage/browser/fileapi/quota/quota_reservation_buffer.h
index 5943a30..d18bd36 100644
--- a/storage/browser/fileapi/quota/quota_reservation_buffer.h
+++ b/storage/browser/fileapi/quota/quota_reservation_buffer.h
@@ -15,7 +15,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 #include "url/origin.h"
 
diff --git a/storage/browser/fileapi/quota/quota_reservation_manager.h b/storage/browser/fileapi/quota/quota_reservation_manager.h
index 603ed83..3a16ac1 100644
--- a/storage/browser/fileapi/quota/quota_reservation_manager.h
+++ b/storage/browser/fileapi/quota/quota_reservation_manager.h
@@ -12,11 +12,11 @@
 #include <utility>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 
 namespace content {
@@ -32,7 +32,7 @@
 class QuotaReservation;
 class QuotaReservationBuffer;
 
-class STORAGE_EXPORT QuotaReservationManager {
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaReservationManager {
  public:
   // Callback for ReserveQuota. When this callback returns false, ReserveQuota
   // operation should be reverted.
@@ -40,7 +40,7 @@
       base::OnceCallback<bool(base::File::Error error, int64_t delta)>;
 
   // An abstraction of backing quota system.
-  class STORAGE_EXPORT QuotaBackend {
+  class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaBackend {
    public:
     QuotaBackend() = default;
     virtual ~QuotaBackend() = default;
diff --git a/storage/browser/fileapi/recursive_operation_delegate.h b/storage/browser/fileapi/recursive_operation_delegate.h
index 3fb79f7..177c37f 100644
--- a/storage/browser/fileapi/recursive_operation_delegate.h
+++ b/storage/browser/fileapi/recursive_operation_delegate.h
@@ -6,6 +6,7 @@
 #define STORAGE_BROWSER_FILEAPI_RECURSIVE_OPERATION_DELEGATE_H_
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/containers/queue.h"
 #include "base/containers/stack.h"
 #include "base/macros.h"
@@ -23,7 +24,7 @@
 // In short, each subclass should override ProcessFile and ProcessDirectory
 // to process a directory or a file. To start the recursive operation it
 // should also call StartRecursiveOperation.
-class STORAGE_EXPORT RecursiveOperationDelegate
+class COMPONENT_EXPORT(STORAGE_BROWSER) RecursiveOperationDelegate
     : public base::SupportsWeakPtr<RecursiveOperationDelegate> {
  public:
   using StatusCallback = FileSystemOperation::StatusCallback;
diff --git a/storage/browser/fileapi/sandbox_directory_database.h b/storage/browser/fileapi/sandbox_directory_database.h
index 84bb1c7..e8b74bf 100644
--- a/storage/browser/fileapi/sandbox_directory_database.h
+++ b/storage/browser/fileapi/sandbox_directory_database.h
@@ -11,11 +11,11 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/time/time.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace content {
 class SandboxDirectoryDatabaseTest;
@@ -43,11 +43,11 @@
 // TODO(ericu): Safe mode, which does more checks such as the above on debug
 // builds.
 // TODO(ericu): Add a method that will give a unique filename for a data file.
-class STORAGE_EXPORT SandboxDirectoryDatabase {
+class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxDirectoryDatabase {
  public:
   using FileId = int64_t;
 
-  struct STORAGE_EXPORT FileInfo {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) FileInfo {
     FileInfo();
     ~FileInfo();
 
diff --git a/storage/browser/fileapi/sandbox_file_stream_writer.h b/storage/browser/fileapi/sandbox_file_stream_writer.h
index 785571e6c..308f370 100644
--- a/storage/browser/fileapi/sandbox_file_stream_writer.h
+++ b/storage/browser/fileapi/sandbox_file_stream_writer.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
@@ -16,7 +17,6 @@
 #include "storage/browser/fileapi/file_stream_writer.h"
 #include "storage/browser/fileapi/file_system_url.h"
 #include "storage/browser/fileapi/task_runner_bound_observer_list.h"
-#include "storage/browser/storage_browser_export.h"
 #include "storage/common/fileapi/file_system_types.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/gurl.h"
@@ -26,7 +26,8 @@
 class FileSystemContext;
 class FileStreamWriter;
 
-class STORAGE_EXPORT SandboxFileStreamWriter : public FileStreamWriter {
+class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileStreamWriter
+    : public FileStreamWriter {
  public:
   SandboxFileStreamWriter(FileSystemContext* file_system_context,
                           const FileSystemURL& url,
diff --git a/storage/browser/fileapi/sandbox_file_system_backend.h b/storage/browser/fileapi/sandbox_file_system_backend.h
index 98a106a2..921ccfe 100644
--- a/storage/browser/fileapi/sandbox_file_system_backend.h
+++ b/storage/browser/fileapi/sandbox_file_system_backend.h
@@ -12,6 +12,7 @@
 #include <string>
 
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -20,7 +21,6 @@
 #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
 #include "storage/browser/fileapi/task_runner_bound_observer_list.h"
 #include "storage/browser/quota/special_storage_policy.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
@@ -28,7 +28,7 @@
 // profile directory in a sandboxed way.
 // This interface also lets one enumerate and remove storage for the origins
 // that use the filesystem.
-class STORAGE_EXPORT SandboxFileSystemBackend
+class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackend
     : public FileSystemBackend {
  public:
   explicit SandboxFileSystemBackend(SandboxFileSystemBackendDelegate* delegate);
diff --git a/storage/browser/fileapi/sandbox_file_system_backend_delegate.h b/storage/browser/fileapi/sandbox_file_system_backend_delegate.h
index 46c68d1..e2fc892 100644
--- a/storage/browser/fileapi/sandbox_file_system_backend_delegate.h
+++ b/storage/browser/fileapi/sandbox_file_system_backend_delegate.h
@@ -13,6 +13,7 @@
 #include <string>
 #include <utility>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -23,7 +24,6 @@
 #include "storage/browser/fileapi/file_system_options.h"
 #include "storage/browser/fileapi/file_system_quota_util.h"
 #include "storage/browser/fileapi/task_runner_bound_observer_list.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -61,7 +61,7 @@
 
 // Delegate implementation of the some methods in Sandbox/SyncFileSystemBackend.
 // An instance of this class is created and owned by FileSystemContext.
-class STORAGE_EXPORT SandboxFileSystemBackendDelegate
+class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackendDelegate
     : public FileSystemQuotaUtil {
  public:
   using OpenFileSystemCallback = FileSystemBackend::OpenFileSystemCallback;
diff --git a/storage/browser/fileapi/sandbox_isolated_origin_database.h b/storage/browser/fileapi/sandbox_isolated_origin_database.h
index 4dbcaace..690675aa 100644
--- a/storage/browser/fileapi/sandbox_isolated_origin_database.h
+++ b/storage/browser/fileapi/sandbox_isolated_origin_database.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "storage/browser/fileapi/sandbox_origin_database_interface.h"
 
@@ -17,7 +18,7 @@
 
 // This origin database implementation supports only one origin
 // (therefore is expected to run very fast).
-class STORAGE_EXPORT SandboxIsolatedOriginDatabase
+class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxIsolatedOriginDatabase
     : public SandboxOriginDatabaseInterface {
  public:
   static const base::FilePath::CharType kObsoleteOriginDirectory[];
diff --git a/storage/browser/fileapi/sandbox_origin_database.h b/storage/browser/fileapi/sandbox_origin_database.h
index a06a6be..33ce99e0 100644
--- a/storage/browser/fileapi/sandbox_origin_database.h
+++ b/storage/browser/fileapi/sandbox_origin_database.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "storage/browser/fileapi/sandbox_origin_database_interface.h"
@@ -27,7 +28,7 @@
 
 // All methods of this class other than the constructor may be used only from
 // the browser's FILE thread.  The constructor may be used on any thread.
-class STORAGE_EXPORT SandboxOriginDatabase
+class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxOriginDatabase
     : public SandboxOriginDatabaseInterface {
  public:
   // Only one instance of SandboxOriginDatabase should exist for a given path
diff --git a/storage/browser/fileapi/sandbox_origin_database_interface.h b/storage/browser/fileapi/sandbox_origin_database_interface.h
index a2498c6..49b6ea9c 100644
--- a/storage/browser/fileapi/sandbox_origin_database_interface.h
+++ b/storage/browser/fileapi/sandbox_origin_database_interface.h
@@ -8,14 +8,14 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
-class STORAGE_EXPORT SandboxOriginDatabaseInterface {
+class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxOriginDatabaseInterface {
  public:
-  struct STORAGE_EXPORT OriginRecord {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) OriginRecord {
     std::string origin;
     base::FilePath path;
 
diff --git a/storage/browser/fileapi/sandbox_prioritized_origin_database.h b/storage/browser/fileapi/sandbox_prioritized_origin_database.h
index d4e4998..40979c5 100644
--- a/storage/browser/fileapi/sandbox_prioritized_origin_database.h
+++ b/storage/browser/fileapi/sandbox_prioritized_origin_database.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "storage/browser/fileapi/sandbox_origin_database_interface.h"
@@ -23,7 +24,7 @@
 class SandboxIsolatedOriginDatabase;
 class SandboxOriginDatabase;
 
-class STORAGE_EXPORT SandboxPrioritizedOriginDatabase
+class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxPrioritizedOriginDatabase
     : public SandboxOriginDatabaseInterface {
  public:
   static const base::FilePath::CharType* const kPrimaryDirectory;
diff --git a/storage/browser/fileapi/transient_file_util.h b/storage/browser/fileapi/transient_file_util.h
index 68440e0..a24b8d70 100644
--- a/storage/browser/fileapi/transient_file_util.h
+++ b/storage/browser/fileapi/transient_file_util.h
@@ -7,15 +7,16 @@
 
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "storage/browser/fileapi/local_file_util.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
 class FileSystemOperationContext;
 
-class STORAGE_EXPORT TransientFileUtil : public LocalFileUtil {
+class COMPONENT_EXPORT(STORAGE_BROWSER) TransientFileUtil
+    : public LocalFileUtil {
  public:
   TransientFileUtil() {}
   ~TransientFileUtil() override {}
diff --git a/storage/browser/quota/client_usage_tracker.h b/storage/browser/quota/client_usage_tracker.h
index b688228..7d358d0 100644
--- a/storage/browser/quota/client_usage_tracker.h
+++ b/storage/browser/quota/client_usage_tracker.h
@@ -20,7 +20,6 @@
 #include "storage/browser/quota/quota_client.h"
 #include "storage/browser/quota/quota_task.h"
 #include "storage/browser/quota/special_storage_policy.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/gurl.h"
 #include "url/origin.h"
diff --git a/storage/browser/quota/quota_client.h b/storage/browser/quota/quota_client.h
index 268a79f..efa788c7 100644
--- a/storage/browser/quota/quota_client.h
+++ b/storage/browser/quota/quota_client.h
@@ -11,7 +11,7 @@
 #include <string>
 
 #include "base/callback.h"
-#include "storage/browser/storage_browser_export.h"
+#include "base/component_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/origin.h"
 
@@ -23,7 +23,7 @@
 // the quota manager, by calling QuotaManager::RegisterClient().
 //
 // All the methods will be called on the IO thread in the browser.
-class STORAGE_EXPORT QuotaClient {
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaClient {
  public:
   using GetUsageCallback = base::OnceCallback<void(int64_t usage)>;
   using GetOriginsCallback =
diff --git a/storage/browser/quota/quota_database.h b/storage/browser/quota/quota_database.h
index 2c7471e..eb080d3 100644
--- a/storage/browser/quota/quota_database.h
+++ b/storage/browser/quota/quota_database.h
@@ -13,11 +13,11 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/origin.h"
 
@@ -35,9 +35,9 @@
 class SpecialStoragePolicy;
 
 // All the methods of this class must run on the DB thread.
-class STORAGE_EXPORT QuotaDatabase {
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaDatabase {
  public:
-  struct STORAGE_EXPORT OriginInfoTableEntry {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) OriginInfoTableEntry {
     OriginInfoTableEntry();
     OriginInfoTableEntry(const url::Origin& origin,
                          blink::mojom::StorageType type,
@@ -134,7 +134,7 @@
   bool SetOriginDatabaseBootstrapped(bool bootstrap_flag);
 
  private:
-  struct STORAGE_EXPORT QuotaTableEntry {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) QuotaTableEntry {
     QuotaTableEntry();
     QuotaTableEntry(const std::string& host,
                     blink::mojom::StorageType type,
@@ -143,10 +143,12 @@
     blink::mojom::StorageType type;
     int64_t quota;
   };
-  friend STORAGE_EXPORT bool operator <(
-      const QuotaTableEntry& lhs, const QuotaTableEntry& rhs);
-  friend STORAGE_EXPORT bool operator <(
-      const OriginInfoTableEntry& lhs, const OriginInfoTableEntry& rhs);
+  friend COMPONENT_EXPORT(STORAGE_BROWSER) bool operator<(
+      const QuotaTableEntry& lhs,
+      const QuotaTableEntry& rhs);
+  friend COMPONENT_EXPORT(STORAGE_BROWSER) bool operator<(
+      const OriginInfoTableEntry& lhs,
+      const OriginInfoTableEntry& rhs);
 
   // Structures used for CreateSchema.
   struct TableSchema {
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h
index 83e39d2..9f680d8 100644
--- a/storage/browser/quota/quota_manager.h
+++ b/storage/browser/quota/quota_manager.h
@@ -17,6 +17,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -30,7 +31,6 @@
 #include "storage/browser/quota/quota_task.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "storage/browser/quota/storage_observer.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 
 namespace base {
@@ -61,7 +61,7 @@
 struct QuotaManagerDeleter;
 
 // An interface called by QuotaTemporaryStorageEvictor.
-class STORAGE_EXPORT QuotaEvictionHandler {
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaEvictionHandler {
  public:
   using EvictionRoundInfoCallback =
       base::OnceCallback<void(blink::mojom::QuotaStatusCode status,
@@ -103,7 +103,7 @@
 //
 // Methods must be called on the IO thread, except for the constructor and
 // proxy().
-class STORAGE_EXPORT QuotaManager
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManager
     : public QuotaTaskObserver,
       public QuotaEvictionHandler,
       public base::RefCountedThreadSafe<QuotaManager, QuotaManagerDeleter> {
diff --git a/storage/browser/quota/quota_manager_proxy.h b/storage/browser/quota/quota_manager_proxy.h
index 91ebbf4..b9593915 100644
--- a/storage/browser/quota/quota_manager_proxy.h
+++ b/storage/browser/quota/quota_manager_proxy.h
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -21,7 +22,6 @@
 #include "storage/browser/quota/quota_manager.h"
 #include "storage/browser/quota/quota_task.h"
 #include "storage/browser/quota/special_storage_policy.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/origin.h"
 
@@ -33,7 +33,7 @@
 namespace storage {
 
 // The proxy may be called and finally released on any thread.
-class STORAGE_EXPORT QuotaManagerProxy
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerProxy
     : public base::RefCountedThreadSafe<QuotaManagerProxy> {
  public:
   using UsageAndQuotaCallback = QuotaManager::UsageAndQuotaCallback;
diff --git a/storage/browser/quota/quota_settings.h b/storage/browser/quota/quota_settings.h
index 04e5f11..aafa93e1 100644
--- a/storage/browser/quota/quota_settings.h
+++ b/storage/browser/quota/quota_settings.h
@@ -8,10 +8,10 @@
 #include <stdint.h>
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "base/optional.h"
 #include "base/time/time.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace storage {
 
@@ -74,7 +74,7 @@
 // interval is 60 seconds to accomodate changes to the size of the volume.
 // Except, in the case of incognito, the poolize and quota values are based
 // on the amount of physical memory and the rerfresh interval is max'd out.
-STORAGE_EXPORT
+COMPONENT_EXPORT(STORAGE_BROWSER)
 void GetNominalDynamicSettings(const base::FilePath& partition_path,
                                bool is_incognito,
                                OptionalQuotaSettingsCallback callback);
diff --git a/storage/browser/quota/quota_task.h b/storage/browser/quota/quota_task.h
index 3fd9255c..11dcafd 100644
--- a/storage/browser/quota/quota_task.h
+++ b/storage/browser/quota/quota_task.h
@@ -8,9 +8,9 @@
 #include <set>
 
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner_helpers.h"
-#include "storage/browser/storage_browser_export.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -59,7 +59,7 @@
   bool delete_scheduled_;
 };
 
-class STORAGE_EXPORT QuotaTaskObserver {
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaTaskObserver {
  protected:
   friend class QuotaTask;
 
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.h b/storage/browser/quota/quota_temporary_storage_evictor.h
index 9761c02b..fd817a2b 100644
--- a/storage/browser/quota/quota_temporary_storage_evictor.h
+++ b/storage/browser/quota/quota_temporary_storage_evictor.h
@@ -11,12 +11,12 @@
 #include <set>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "base/timer/timer.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 
 namespace content {
@@ -32,7 +32,7 @@
 class QuotaEvictionHandler;
 struct QuotaSettings;
 
-class STORAGE_EXPORT QuotaTemporaryStorageEvictor {
+class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaTemporaryStorageEvictor {
  public:
   struct Statistics {
     Statistics()
diff --git a/storage/browser/quota/special_storage_policy.h b/storage/browser/quota/special_storage_policy.h
index 25000d5f..9ff79ed 100644
--- a/storage/browser/quota/special_storage_policy.h
+++ b/storage/browser/quota/special_storage_policy.h
@@ -8,10 +8,10 @@
 #include <string>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
 #include "services/network/session_cleanup_cookie_store.h"
-#include "storage/browser/storage_browser_export.h"
 
 class GURL;
 
@@ -23,7 +23,7 @@
 // is currently installed in the extensions system.
 // The IsSomething() methods must be thread-safe, however Observers should
 // only be notified, added, and removed on the IO thead.
-class STORAGE_EXPORT SpecialStoragePolicy
+class COMPONENT_EXPORT(STORAGE_BROWSER) SpecialStoragePolicy
     : public base::RefCountedThreadSafe<SpecialStoragePolicy> {
  public:
   using StoragePolicy = int;
@@ -32,7 +32,7 @@
     STORAGE_UNLIMITED = 1 << 1,
   };
 
-  class STORAGE_EXPORT Observer {
+  class COMPONENT_EXPORT(STORAGE_BROWSER) Observer {
    public:
     virtual void OnGranted(const GURL& origin, int change_flags) = 0;
     virtual void OnRevoked(const GURL& origin, int change_flags) = 0;
diff --git a/storage/browser/quota/storage_monitor.h b/storage/browser/quota/storage_monitor.h
index db75face..6797d3a 100644
--- a/storage/browser/quota/storage_monitor.h
+++ b/storage/browser/quota/storage_monitor.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <memory>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
@@ -28,7 +29,7 @@
 
 // This class dispatches storage events to observers of a common
 // StorageObserver::Filter.
-class STORAGE_EXPORT StorageObserverList {
+class COMPONENT_EXPORT(STORAGE_BROWSER) StorageObserverList {
  public:
   StorageObserverList();
   virtual ~StorageObserverList();
@@ -53,7 +54,7 @@
   void ScheduleUpdateForObserver(StorageObserver* observer);
 
  private:
-  struct STORAGE_EXPORT ObserverState {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) ObserverState {
     url::Origin origin;
     base::TimeTicks last_notification_time;
     base::TimeDelta rate;
@@ -73,10 +74,9 @@
   DISALLOW_COPY_AND_ASSIGN(StorageObserverList);
 };
 
-
 // Manages the storage observers of a common host. Caches the usage and quota of
 // the host to avoid accumulating for every change.
-class STORAGE_EXPORT HostStorageObservers {
+class COMPONENT_EXPORT(STORAGE_BROWSER) HostStorageObservers {
  public:
   explicit HostStorageObservers(QuotaManager* quota_manager);
   virtual ~HostStorageObservers();
@@ -121,9 +121,8 @@
   DISALLOW_COPY_AND_ASSIGN(HostStorageObservers);
 };
 
-
 // Manages the observers of a common storage type.
-class STORAGE_EXPORT StorageTypeObservers {
+class COMPONENT_EXPORT(STORAGE_BROWSER) StorageTypeObservers {
  public:
   explicit StorageTypeObservers(QuotaManager* quota_manager);
   virtual ~StorageTypeObservers();
@@ -147,9 +146,8 @@
   DISALLOW_COPY_AND_ASSIGN(StorageTypeObservers);
 };
 
-
 // Storage monitor manages observers and dispatches storage events to them.
-class STORAGE_EXPORT StorageMonitor {
+class COMPONENT_EXPORT(STORAGE_BROWSER) StorageMonitor {
  public:
   explicit StorageMonitor(QuotaManager* quota_manager);
   virtual ~StorageMonitor();
diff --git a/storage/browser/quota/storage_observer.h b/storage/browser/quota/storage_observer.h
index 68292e2..942ca9ef 100644
--- a/storage/browser/quota/storage_observer.h
+++ b/storage/browser/quota/storage_observer.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include "base/component_export.h"
 #include "base/time/time.h"
 #include "storage/browser/quota/quota_client.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
@@ -16,9 +17,9 @@
 
 // This interface is implemented by observers that wish to monitor storage
 // events, such as changes in quota or usage.
-class STORAGE_EXPORT StorageObserver {
+class COMPONENT_EXPORT(STORAGE_BROWSER) StorageObserver {
  public:
-  struct STORAGE_EXPORT Filter {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) Filter {
     // The storage type to monitor. This must not be kUnknown or
     // kQuotaNotManaged.
     blink::mojom::StorageType storage_type;
@@ -31,7 +32,7 @@
     bool operator==(const Filter& other) const;
   };
 
-  struct STORAGE_EXPORT MonitorParams {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) MonitorParams {
     // Storage type and origin to monitor.
     Filter filter;
 
@@ -53,7 +54,7 @@
                   bool get_initial_state);
   };
 
-  struct STORAGE_EXPORT Event {
+  struct COMPONENT_EXPORT(STORAGE_BROWSER) Event {
     // The storage type and origin monitored.
     Filter filter;
 
diff --git a/storage/browser/quota/usage_tracker.h b/storage/browser/quota/usage_tracker.h
index 9bbd6c69..1fbcf48 100644
--- a/storage/browser/quota/usage_tracker.h
+++ b/storage/browser/quota/usage_tracker.h
@@ -14,12 +14,12 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "storage/browser/quota/quota_callbacks.h"
 #include "storage/browser/quota/quota_client.h"
 #include "storage/browser/quota/quota_task.h"
 #include "storage/browser/quota/special_storage_policy.h"
-#include "storage/browser/storage_browser_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/origin.h"
 
@@ -31,7 +31,8 @@
 // A helper class that gathers and tracks the amount of data stored in
 // all quota clients.
 // An instance of this class is created per storage type.
-class STORAGE_EXPORT UsageTracker : public QuotaTaskObserver {
+class COMPONENT_EXPORT(STORAGE_BROWSER) UsageTracker
+    : public QuotaTaskObserver {
  public:
   UsageTracker(const std::vector<QuotaClient*>& clients,
                blink::mojom::StorageType type,
diff --git a/storage/browser/storage_browser_export.h b/storage/browser/storage_browser_export.h
deleted file mode 100644
index bad5e41..0000000
--- a/storage/browser/storage_browser_export.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2013 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 STORAGE_BROWSER_STORAGE_BROWSER_EXPORT_H__
-#define STORAGE_BROWSER_STORAGE_BROWSER_EXPORT_H__
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(STORAGE_BROWSER_IMPLEMENTATION)
-#define STORAGE_EXPORT __declspec(dllexport)
-#else
-#define STORAGE_EXPORT __declspec(dllimport)
-#endif  // defined(STORAGE_BROWSER_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(STORAGE_BROWSER_IMPLEMENTATION)
-#define STORAGE_EXPORT __attribute__((visibility("default")))
-#else
-#define STORAGE_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define STORAGE_EXPORT
-#endif
-
-#endif  // STORAGE_BROWSER_STORAGE_BROWSER_EXPORT_H__
diff --git a/storage/common/BUILD.gn b/storage/common/BUILD.gn
index a7f41a35..6c7d280 100644
--- a/storage/common/BUILD.gn
+++ b/storage/common/BUILD.gn
@@ -23,7 +23,6 @@
     "fileapi/file_system_util.cc",
     "fileapi/file_system_util.h",
     "quota/quota_limit_type.h",
-    "storage_common_export.h",
     "storage_histograms.cc",
     "storage_histograms.h",
   ]
@@ -34,7 +33,7 @@
     "//build/config/compiler:wexit_time_destructors",
   ]
 
-  defines = [ "STORAGE_COMMON_IMPLEMENTATION" ]
+  defines = [ "IS_STORAGE_COMMON_IMPL" ]
 
   public_deps = [
     "//components/services/filesystem/public/interfaces",
diff --git a/storage/common/blob_storage/blob_handle.h b/storage/common/blob_storage/blob_handle.h
index 72c3cf1..8ba9e9b 100644
--- a/storage/common/blob_storage/blob_handle.h
+++ b/storage/common/blob_storage/blob_handle.h
@@ -5,14 +5,15 @@
 #ifndef STORAGE_COMMON_BLOB_STORAGE_BLOB_HANDLE_H_
 #define STORAGE_COMMON_BLOB_STORAGE_BLOB_HANDLE_H_
 
+#include "base/component_export.h"
 #include "base/memory/ref_counted.h"
-#include "storage/common/storage_common_export.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 
 namespace storage {
 
 // Refcounted wrapper around a mojom::BlobPtr.
-class STORAGE_COMMON_EXPORT BlobHandle : public base::RefCounted<BlobHandle> {
+class COMPONENT_EXPORT(STORAGE_COMMON) BlobHandle
+    : public base::RefCounted<BlobHandle> {
  public:
   explicit BlobHandle(blink::mojom::BlobPtr blob);
 
diff --git a/storage/common/blob_storage/blob_storage_constants.h b/storage/common/blob_storage/blob_storage_constants.h
index 17a0812..077b5e4 100644
--- a/storage/common/blob_storage/blob_storage_constants.h
+++ b/storage/common/blob_storage/blob_storage_constants.h
@@ -9,8 +9,8 @@
 #include <stdint.h>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "build/build_config.h"
-#include "storage/common/storage_common_export.h"
 
 namespace storage {
 
@@ -35,7 +35,7 @@
     "blob-transport-by-file-trigger";
 
 // All sizes are in bytes.
-struct STORAGE_COMMON_EXPORT BlobStorageLimits {
+struct COMPONENT_EXPORT(STORAGE_COMMON) BlobStorageLimits {
   BlobStorageLimits();
   ~BlobStorageLimits();
   BlobStorageLimits(const BlobStorageLimits&);
@@ -151,13 +151,13 @@
 using BlobStatusCallback = base::OnceCallback<void(BlobStatus)>;
 
 // Returns if the status is an error code.
-STORAGE_COMMON_EXPORT bool BlobStatusIsError(BlobStatus status);
+COMPONENT_EXPORT(STORAGE_COMMON) bool BlobStatusIsError(BlobStatus status);
 
-STORAGE_COMMON_EXPORT bool BlobStatusIsPending(BlobStatus status);
+COMPONENT_EXPORT(STORAGE_COMMON) bool BlobStatusIsPending(BlobStatus status);
 
 // Returns if the status is a bad enough error to flag the IPC as bad. This is
 // only INVALID_CONSTRUCTION_ARGUMENTS.
-STORAGE_COMMON_EXPORT bool BlobStatusIsBadIPC(BlobStatus status);
+COMPONENT_EXPORT(STORAGE_COMMON) bool BlobStatusIsBadIPC(BlobStatus status);
 
 }  // namespace storage
 
diff --git a/storage/common/database/database_connections.h b/storage/common/database/database_connections.h
index a6adc5a..6636f6d 100644
--- a/storage/common/database/database_connections.h
+++ b/storage/common/database/database_connections.h
@@ -11,12 +11,12 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/strings/string16.h"
-#include "storage/common/storage_common_export.h"
 
 namespace storage {
 
-class STORAGE_COMMON_EXPORT DatabaseConnections {
+class COMPONENT_EXPORT(STORAGE_COMMON) DatabaseConnections {
  public:
   DatabaseConnections();
   ~DatabaseConnections();
diff --git a/storage/common/database/database_identifier.h b/storage/common/database/database_identifier.h
index ea03ffd8..45144c4f 100644
--- a/storage/common/database/database_identifier.h
+++ b/storage/common/database/database_identifier.h
@@ -7,27 +7,28 @@
 
 #include <string>
 
+#include "base/component_export.h"
 #include "base/strings/string_piece.h"
-#include "storage/common/storage_common_export.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
 namespace storage {
 
-STORAGE_COMMON_EXPORT std::string GetIdentifierFromOrigin(
-    const url::Origin& origin);
-STORAGE_COMMON_EXPORT url::Origin GetOriginFromIdentifier(
-    const std::string& identifier);
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::string GetIdentifierFromOrigin(const url::Origin& origin);
+COMPONENT_EXPORT(STORAGE_COMMON)
+url::Origin GetOriginFromIdentifier(const std::string& identifier);
 
 // TODO(jsbell): Remove use of the GURL variants.
-STORAGE_COMMON_EXPORT std::string GetIdentifierFromOrigin(const GURL& origin);
-STORAGE_COMMON_EXPORT GURL
-GetOriginURLFromIdentifier(const std::string& identifier);
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::string GetIdentifierFromOrigin(const GURL& origin);
+COMPONENT_EXPORT(STORAGE_COMMON)
+GURL GetOriginURLFromIdentifier(const std::string& identifier);
 
-STORAGE_COMMON_EXPORT bool IsValidOriginIdentifier(
-    const std::string& identifier);
+COMPONENT_EXPORT(STORAGE_COMMON)
+bool IsValidOriginIdentifier(const std::string& identifier);
 
-class STORAGE_COMMON_EXPORT DatabaseIdentifier {
+class COMPONENT_EXPORT(STORAGE_COMMON) DatabaseIdentifier {
  public:
   static const DatabaseIdentifier UniqueFileIdentifier();
   static DatabaseIdentifier CreateFromOrigin(const GURL& origin);
diff --git a/storage/common/fileapi/file_system_info.h b/storage/common/fileapi/file_system_info.h
index bb2fea93..9dec2b7e 100644
--- a/storage/common/fileapi/file_system_info.h
+++ b/storage/common/fileapi/file_system_info.h
@@ -7,8 +7,8 @@
 
 #include <string>
 
+#include "base/component_export.h"
 #include "storage/common/fileapi/file_system_types.h"
-#include "storage/common/storage_common_export.h"
 #include "url/gurl.h"
 
 namespace storage {
@@ -16,7 +16,7 @@
 // This struct is used to send the necessary information for Blink to create a
 // DOMFileSystem.  Since Blink side only uses mount_type (rather than
 // detailed/cracked filesystem type) this only contains mount_type but not type.
-struct STORAGE_COMMON_EXPORT FileSystemInfo {
+struct COMPONENT_EXPORT(STORAGE_COMMON) FileSystemInfo {
   FileSystemInfo();
   FileSystemInfo(const std::string& filesystem_name,
                  const GURL& root_url,
diff --git a/storage/common/fileapi/file_system_util.h b/storage/common/fileapi/file_system_util.h
index 9664178..06d8f29 100644
--- a/storage/common/fileapi/file_system_util.h
+++ b/storage/common/fileapi/file_system_util.h
@@ -8,11 +8,11 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "storage/common/fileapi/file_system_info.h"
 #include "storage/common/fileapi/file_system_types.h"
-#include "storage/common/storage_common_export.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "third_party/blink/public/platform/web_file_system_type.h"
 
@@ -20,13 +20,13 @@
 
 namespace storage {
 
-STORAGE_COMMON_EXPORT extern const char kPersistentDir[];
-STORAGE_COMMON_EXPORT extern const char kTemporaryDir[];
-STORAGE_COMMON_EXPORT extern const char kExternalDir[];
-STORAGE_COMMON_EXPORT extern const char kIsolatedDir[];
-STORAGE_COMMON_EXPORT extern const char kTestDir[];
+COMPONENT_EXPORT(STORAGE_COMMON) extern const char kPersistentDir[];
+COMPONENT_EXPORT(STORAGE_COMMON) extern const char kTemporaryDir[];
+COMPONENT_EXPORT(STORAGE_COMMON) extern const char kExternalDir[];
+COMPONENT_EXPORT(STORAGE_COMMON) extern const char kIsolatedDir[];
+COMPONENT_EXPORT(STORAGE_COMMON) extern const char kTestDir[];
 
-class STORAGE_COMMON_EXPORT VirtualPath {
+class COMPONENT_EXPORT(STORAGE_COMMON) VirtualPath {
  public:
   static const base::FilePath::CharType kRoot[];
   static const base::FilePath::CharType kSeparator;
@@ -67,11 +67,11 @@
 // Example: For a URL 'filesystem:http://foo.com/temporary/foo/bar',
 // |origin_url| is set to 'http://foo.com', |type| is set to
 // kFileSystemTypeTemporary, and |virtual_path| is set to 'foo/bar'.
-STORAGE_COMMON_EXPORT bool ParseFileSystemSchemeURL(
-    const GURL& url,
-    GURL* origin_url,
-    FileSystemType* type,
-    base::FilePath* virtual_path);
+COMPONENT_EXPORT(STORAGE_COMMON)
+bool ParseFileSystemSchemeURL(const GURL& url,
+                              GURL* origin_url,
+                              FileSystemType* type,
+                              base::FilePath* virtual_path);
 
 // Returns the root URI of the filesystem that can be specified by a pair of
 // |origin_url| and |type|.  The returned URI can be used as a root path
@@ -82,8 +82,8 @@
 // returns URL without the filesystem ID.
 //
 // |type| needs to be public type as the returned URI is given to the renderer.
-STORAGE_COMMON_EXPORT GURL GetFileSystemRootURI(const GURL& origin_url,
-                                                       FileSystemType type);
+COMPONENT_EXPORT(STORAGE_COMMON)
+GURL GetFileSystemRootURI(const GURL& origin_url, FileSystemType type);
 
 // Returns the name for the filesystem that is specified by a pair of
 // |origin_url| and |type|.
@@ -96,77 +96,79 @@
 // Example:
 //   The name for a TEMPORARY filesystem of "http://www.example.com:80/"
 //   should look like: "http_www.example.host_80:temporary"
-STORAGE_COMMON_EXPORT std::string
-GetFileSystemName(const GURL& origin_url, FileSystemType type);
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::string GetFileSystemName(const GURL& origin_url, FileSystemType type);
 
 // Converts FileSystemType |type| to/from the StorageType |storage_type| that
 // is used for the unified quota system.
 // (Basically this naively maps TEMPORARY storage type to TEMPORARY filesystem
 // type, PERSISTENT storage type to PERSISTENT filesystem type and vice versa.)
-STORAGE_COMMON_EXPORT FileSystemType
-QuotaStorageTypeToFileSystemType(blink::mojom::StorageType storage_type);
+COMPONENT_EXPORT(STORAGE_COMMON)
+FileSystemType QuotaStorageTypeToFileSystemType(
+    blink::mojom::StorageType storage_type);
 
-STORAGE_COMMON_EXPORT blink::mojom::StorageType
-FileSystemTypeToQuotaStorageType(FileSystemType type);
+COMPONENT_EXPORT(STORAGE_COMMON)
+blink::mojom::StorageType FileSystemTypeToQuotaStorageType(FileSystemType type);
 
 // Returns the string representation of the given filesystem |type|.
 // Returns an empty string if the |type| is invalid.
-STORAGE_COMMON_EXPORT std::string
-GetFileSystemTypeString(FileSystemType type);
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::string GetFileSystemTypeString(FileSystemType type);
 
 // Sets type to FileSystemType enum that corresponds to the string name.
 // Returns false if the |type_string| is invalid.
-STORAGE_COMMON_EXPORT bool GetFileSystemPublicType(
-    std::string type_string,
-    blink::WebFileSystemType* type);
+COMPONENT_EXPORT(STORAGE_COMMON)
+bool GetFileSystemPublicType(std::string type_string,
+                             blink::WebFileSystemType* type);
 
 // Encodes |file_path| to a string.
 // Following conditions should be held:
 //  - StringToFilePath(FilePathToString(path)) == path
 //  - StringToFilePath(FilePathToString(path) + "/" + "SubDirectory") ==
 //    path.AppendASCII("SubDirectory");
-STORAGE_COMMON_EXPORT std::string FilePathToString(
-    const base::FilePath& file_path);
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::string FilePathToString(const base::FilePath& file_path);
 
 // Decode a file path from |file_path_string|.
-STORAGE_COMMON_EXPORT base::FilePath StringToFilePath(
-    const std::string& file_path_string);
+COMPONENT_EXPORT(STORAGE_COMMON)
+base::FilePath StringToFilePath(const std::string& file_path_string);
 
 // Generate a file system name for the given arguments. Should only be used by
 // platform apps.
-STORAGE_COMMON_EXPORT std::string GetIsolatedFileSystemName(
-    const GURL& origin_url,
-    const std::string& filesystem_id);
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::string GetIsolatedFileSystemName(const GURL& origin_url,
+                                      const std::string& filesystem_id);
 
 // Find the file system id from |filesystem_name|. Should only be used by
 // platform apps. This function will return false if the file system name is
 // not of the form {origin}:Isolated_{id}, and will also check that there is an
 // origin and id present. It will not check that the origin or id are valid.
-STORAGE_COMMON_EXPORT bool CrackIsolatedFileSystemName(
-    const std::string& filesystem_name,
-    std::string* filesystem_id);
+COMPONENT_EXPORT(STORAGE_COMMON)
+bool CrackIsolatedFileSystemName(const std::string& filesystem_name,
+                                 std::string* filesystem_id);
 
 // Validates the given isolated file system id.
-STORAGE_COMMON_EXPORT bool ValidateIsolatedFileSystemId(
-    const std::string& filesystem_id);
+COMPONENT_EXPORT(STORAGE_COMMON)
+bool ValidateIsolatedFileSystemId(const std::string& filesystem_id);
 
 // Returns the root URI for an isolated filesystem for origin |origin_url|
 // and |filesystem_id|. If the |optional_root_name| is given the resulting
 // root URI will point to the subfolder within the isolated filesystem.
-STORAGE_COMMON_EXPORT std::string GetIsolatedFileSystemRootURIString(
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::string GetIsolatedFileSystemRootURIString(
     const GURL& origin_url,
     const std::string& filesystem_id,
     const std::string& optional_root_name);
 
 // Returns the root URI for an external filesystem for origin |origin_url|
 // and |mount_name|.
-STORAGE_COMMON_EXPORT std::string GetExternalFileSystemRootURIString(
-    const GURL& origin_url,
-    const std::string& mount_name);
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::string GetExternalFileSystemRootURIString(const GURL& origin_url,
+                                               const std::string& mount_name);
 
 // Translates the net::Error to base::File::Error.
-STORAGE_COMMON_EXPORT base::File::Error
-NetErrorToFileError(int error);
+COMPONENT_EXPORT(STORAGE_COMMON)
+base::File::Error NetErrorToFileError(int error);
 
 }  // namespace storage
 
diff --git a/storage/common/storage_common_export.h b/storage/common/storage_common_export.h
deleted file mode 100644
index 3c97109..0000000
--- a/storage/common/storage_common_export.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2013 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 STORAGE_COMMON_STORAGE_COMMON_EXPORT_H_
-#define STORAGE_COMMON_STORAGE_COMMON_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(STORAGE_COMMON_IMPLEMENTATION)
-#define STORAGE_COMMON_EXPORT __declspec(dllexport)
-#else
-#define STORAGE_COMMON_EXPORT __declspec(dllimport)
-#endif  // defined(STORAGE_COMMON_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(STORAGE_COMMON_IMPLEMENTATION)
-#define STORAGE_COMMON_EXPORT __attribute__((visibility("default")))
-#else
-#define STORAGE_COMMON_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define STORAGE_COMMON_EXPORT
-#endif
-
-#endif  // STORAGE_COMMON_STORAGE_COMMON_EXPORT_H_
diff --git a/storage/common/storage_histograms.h b/storage/common/storage_histograms.h
index 8cde5c2c..155ec6a 100644
--- a/storage/common/storage_histograms.h
+++ b/storage/common/storage_histograms.h
@@ -2,17 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef STORAGE_COMMON_HISTOGRAMS_H
-#define STORAGE_COMMON_HISTOGRAMS_H
+#ifndef STORAGE_COMMON_STORAGE_HISTOGRAMS_H_
+#define STORAGE_COMMON_STORAGE_HISTOGRAMS_H_
 
 #include <string>
-#include "storage/common/storage_common_export.h"
+
+#include "base/component_export.h"
 
 namespace storage {
 
-STORAGE_COMMON_EXPORT void RecordBytesWritten(const char* label, int bytes);
-STORAGE_COMMON_EXPORT void RecordBytesRead(const char* label, int bytes);
+COMPONENT_EXPORT(STORAGE_COMMON)
+void RecordBytesWritten(const char* label, int bytes);
+COMPONENT_EXPORT(STORAGE_COMMON)
+void RecordBytesRead(const char* label, int bytes);
 
 }  // namespace storage
 
-#endif  // STORAGE_COMMON_HISTOGRAMS_H
+#endif  // STORAGE_COMMON_STORAGE_HISTOGRAMS_H_
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 607dc7e..33c43dab 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2122,7 +2122,7 @@
             ]
         }
     ],
-    "HTTPReallyBadFinal": [
+    "HTTPBadPhase3": [
         {
             "platforms": [
                 "android",
@@ -2134,9 +2134,9 @@
             ],
             "experiments": [
                 {
-                    "name": "enabled",
+                    "name": "NotSecureWarning",
                     "params": {
-                        "treatment": "dangerous"
+                        "treatment": "warning"
                     },
                     "enable_features": [
                         "MarkHttpAs"
diff --git a/third_party/blink/public/mojom/fetch/fetch_api_request.mojom b/third_party/blink/public/mojom/fetch/fetch_api_request.mojom
index a7d2f5d3..31cd8d6 100644
--- a/third_party/blink/public/mojom/fetch/fetch_api_request.mojom
+++ b/third_party/blink/public/mojom/fetch/fetch_api_request.mojom
@@ -128,11 +128,9 @@
   FetchAPIRequestHeaders headers;
 
   // Note: |blob| and |body| are mutually exclusive.
-  // |blob| is used in implementing Background Fetch APIs, also used to
-  // represent the FetchEvent#request#body dispatched to service workers for
-  // non-S13nServiceWorker case.
-  // |body| is used only to represent the FetchEvent#request#body dispatched to
-  // service workers for S13nServiceWorker case.
+  // |blob| is used in implementing Background Fetch APIs.
+  // |body| is used to represent the FetchEvent#request#body dispatched to
+  // service workers.
   // TODO(crbug.com/911930): Remove |blob| and use |body| instead everywhere.
   SerializedBlob? blob;
   network.mojom.URLRequestBody? body;
diff --git a/third_party/blink/public/mojom/payments/payment_request.mojom b/third_party/blink/public/mojom/payments/payment_request.mojom
index 46e0d56..fc315100 100644
--- a/third_party/blink/public/mojom/payments/payment_request.mojom
+++ b/third_party/blink/public/mojom/payments/payment_request.mojom
@@ -41,12 +41,6 @@
 enum CanMakePaymentQueryResult {
   CAN_MAKE_PAYMENT,
   CANNOT_MAKE_PAYMENT,
-  QUERY_QUOTA_EXCEEDED,
-
-  // Used only on localhost and file:// schemes to warn web developer that the
-  // query quota has been exceeded, but Chrome is returning an answer anyway.
-  WARNING_CAN_MAKE_PAYMENT,
-  WARNING_CANNOT_MAKE_PAYMENT,
 };
 
 enum HasEnrolledInstrumentQueryResult {
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h
index e9723b4..1c8588a 100644
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h
+++ b/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h
@@ -17,7 +17,6 @@
 
 #if INSIDE_BLINK
 #include <utility>
-#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"  // nogncheck
 #include "third_party/blink/renderer/platform/network/http_header_map.h"  // nogncheck
 #include "third_party/blink/renderer/platform/weborigin/referrer.h"  // nogncheck
 #include "third_party/blink/renderer/platform/wtf/forward.h"  // nogncheck
@@ -29,7 +28,6 @@
 }
 namespace blink {
 
-class BlobDataHandle;
 class WebHTTPHeaderVisitor;
 class WebServiceWorkerRequestPrivate;
 
@@ -69,13 +67,8 @@
 
   void VisitHTTPHeaderFields(WebHTTPHeaderVisitor*) const;
 
-  // There are two ways of representing body: WebHTTPBody or Blob.  Only one
-  // should be used.
   void SetBody(const WebHTTPBody&);
   WebHTTPBody Body() const;
-  void SetBlob(const WebString& uuid,
-               long long size,
-               mojo::ScopedMessagePipeHandle);
 
   void SetReferrer(const WebString&, network::mojom::ReferrerPolicy);
   WebURL ReferrerUrl() const;
@@ -125,12 +118,7 @@
 
 #if INSIDE_BLINK
   const HTTPHeaderMap& Headers() const;
-  void SetBlobDataHandle(scoped_refptr<BlobDataHandle>);
-  scoped_refptr<BlobDataHandle> GetBlobDataHandle() const;
   const Referrer& GetReferrer() const;
-  void SetBlob(const WebString& uuid,
-               long long size,
-               mojom::blink::BlobPtrInfo);
 #endif
 
  private:
diff --git a/third_party/blink/renderer/core/fetch/fetch_request_data.cc b/third_party/blink/renderer/core/fetch/fetch_request_data.cc
index 5e4eb3d5..8eca9b7 100644
--- a/third_party/blink/renderer/core/fetch/fetch_request_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_request_data.cc
@@ -40,13 +40,6 @@
         MakeGarbageCollected<FormDataBytesConsumer>(
             ExecutionContext::From(script_state), std::move(body)),
         nullptr /* AbortSignal */));
-  } else if (web_request.GetBlobDataHandle()) {
-    request->SetBuffer(MakeGarbageCollected<BodyStreamBuffer>(
-        script_state,
-        MakeGarbageCollected<BlobBytesConsumer>(
-            ExecutionContext::From(script_state),
-            web_request.GetBlobDataHandle()),
-        nullptr /* AbortSignal */));
   }
   request->SetContext(web_request.GetRequestContext());
   request->SetReferrerString(web_request.ReferrerUrl().GetString());
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 7224e37f..e905b58 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -628,10 +628,7 @@
 
 void LocalFrameView::LayoutFromRootObject(LayoutObject& root) {
   LayoutState layout_state(root);
-  if (!root.IsBoxModelObject())
-    root.UpdateLayout();
-  else
-    ToLayoutBoxModelObject(root).UpdateLayout();
+  root.UpdateLayout();
 }
 
 void LocalFrameView::PrepareLayoutAnalyzer() {
diff --git a/third_party/blink/renderer/core/frame/use_counter.cc b/third_party/blink/renderer/core/frame/use_counter.cc
index 3bf1d23d..ec72ff3 100644
--- a/third_party/blink/renderer/core/frame/use_counter.cc
+++ b/third_party/blink/renderer/core/frame/use_counter.cc
@@ -1345,6 +1345,8 @@
   const KURL url = frame->GetDocument()->Url();
   if (url.ProtocolIs("chrome-extension"))
     context_ = kExtensionContext;
+  if (url.ProtocolIs("file"))
+    context_ = kFileContext;
 
   DCHECK_EQ(kPreCommit, commit_state_);
   commit_state_ = kCommited;
@@ -1366,8 +1368,10 @@
 
     // TODO(loonybear): remove or move SVG histogram and extension histogram
     // to the browser side.
-    if ((context_ == kSVGImageContext || context_ == kExtensionContext))
+    if ((context_ == kSVGImageContext || context_ == kExtensionContext ||
+         context_ == kFileContext)) {
       FeaturesHistogram().Count(static_cast<int>(WebFeature::kPageVisits));
+    }
   }
 }
 
@@ -1528,9 +1532,6 @@
 }
 
 EnumerationHistogram& UseCounter::FeaturesHistogram() const {
-  DCHECK_NE(kDisabledContext, context_);
-  // The default features histogram is being recorded on the browser side.
-  DCHECK_NE(kDefaultContext, context_);
   // Every SVGImage has it's own Page instance, and multiple web pages can
   // share the usage of a single SVGImage.  Ideally perhaps we'd delegate
   // metrics from an SVGImage to one of the Page's it's displayed in, but
@@ -1543,9 +1544,29 @@
   DEFINE_STATIC_LOCAL(blink::EnumerationHistogram, extension_histogram,
                       ("Blink.UseCounter.Extensions.Features",
                        static_cast<int32_t>(WebFeature::kNumberOfFeatures)));
+  DEFINE_STATIC_LOCAL(blink::EnumerationHistogram, file_histogram,
+                      ("Blink.UseCounter.File.Features",
+                       static_cast<int32_t>(WebFeature::kNumberOfFeatures)));
   // Track what features/properties have been reported to the browser side
   // histogram.
-  return context_ == kSVGImageContext ? svg_histogram : extension_histogram;
+  switch (context_) {
+    case kDefaultContext:
+      // The default features histogram is being recorded on the browser side.
+      NOTREACHED();
+      break;
+    case kSVGImageContext:
+      return svg_histogram;
+    case kExtensionContext:
+      return extension_histogram;
+    case kFileContext:
+      return file_histogram;
+    case kDisabledContext:
+      NOTREACHED();
+      break;
+  }
+  NOTREACHED();
+  blink::EnumerationHistogram* null = nullptr;
+  return *null;
 }
 
 EnumerationHistogram& UseCounter::CssHistogram() const {
diff --git a/third_party/blink/renderer/core/frame/use_counter.h b/third_party/blink/renderer/core/frame/use_counter.h
index 22481b4..c3708c5c 100644
--- a/third_party/blink/renderer/core/frame/use_counter.h
+++ b/third_party/blink/renderer/core/frame/use_counter.h
@@ -75,6 +75,8 @@
     kSVGImageContext,
     // Counters for extensions.
     kExtensionContext,
+    // Context for file:// URLs.
+    kFileContext,
     // Context when counters should be disabled (eg, internal pages such as
     // about, chrome-devtools, etc).
     kDisabledContext
diff --git a/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc b/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
index d67642b52..0b25873 100644
--- a/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
@@ -520,9 +520,19 @@
   rgm.PushMappingsToAncestor(container->Layer(), nullptr);
   rgm.PushMappingsToAncestor(span->Layer(), container->Layer());
   rgm.PushMappingsToAncestor(layer_under_float->Layer(), span->Layer());
-  EXPECT_EQ(rect, RectFromQuad(rgm.MapToAncestor(rect, container)));
-  EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f),
-            RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    // LayoutNG inline-level floats are children of their inline-level
+    // containers. As such they are positioned relative to their inline-level
+    // container, (and shifted by an additional 200,100 in this case).
+    EXPECT_EQ(FloatRect(203.0f, 104.0f, 10.0f, 8.0f),
+              RectFromQuad(rgm.MapToAncestor(rect, container)));
+    EXPECT_EQ(FloatRect(263.0f, 154.0f, 10.0f, 8.0f),
+              RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+  } else {
+    EXPECT_EQ(rect, RectFromQuad(rgm.MapToAncestor(rect, container)));
+    EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f),
+              RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+  }
 
   rgm.PopMappingsToAncestor(span->Layer());
   EXPECT_EQ(FloatRect(203.0f, 104.0f, 10.0f, 8.0f),
@@ -531,9 +541,16 @@
             RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
 
   rgm.PushMappingsToAncestor(floating, span);
-  EXPECT_EQ(rect, RectFromQuad(rgm.MapToAncestor(rect, container)));
-  EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f),
-            RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(FloatRect(203.0f, 104.0f, 10.0f, 8.0f),
+              RectFromQuad(rgm.MapToAncestor(rect, container)));
+    EXPECT_EQ(FloatRect(263.0f, 154.0f, 10.0f, 8.0f),
+              RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+  } else {
+    EXPECT_EQ(rect, RectFromQuad(rgm.MapToAncestor(rect, container)));
+    EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f),
+              RectFromQuad(rgm.MapToAncestor(rect, nullptr)));
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 6cc8df6..230413a 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -691,8 +691,12 @@
        // Use containingBlock instead of parentCrossingFrames for floating
        // objects to omit any self-painting layers of inline objects that don't
        // paint the floating object.
-       current = current->IsFloating() ? current->ContainingBlock()
-                                       : current->ParentCrossingFrames()) {
+       // This is only needed for inline-level floats not managed by LayoutNG.
+       // LayoutNG floats are painted by the correct painting layer.
+       current = (current->IsFloating() &&
+                  !current->IsInLayoutNGInlineFormattingContext())
+                     ? current->ContainingBlock()
+                     : current->ParentCrossingFrames()) {
     if (current->HasLayer() &&
         ToLayoutBoxModelObject(current)->Layer()->IsSelfPaintingLayer()) {
       return ToLayoutBoxModelObject(current)->Layer();
@@ -2332,12 +2336,6 @@
     if (NeedsLayout() && old_style->GetPosition() != style_->GetPosition())
       MarkContainerChainForLayout();
 
-    // Ditto.
-    // TODO(chrishtr): review this. Why are we checking Needs* at all?
-    if ((NeedsLayoutOverflowRecalc() || NeedsVisualOverflowRecalc()) &&
-        old_style->GetPosition() != style_->GetPosition())
-      MarkContainerChainForOverflowRecalcIfNeeded();
-
     SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange);
   } else if (diff.NeedsPositionedMovementLayout()) {
     SetNeedsPositionedMovementLayout();
@@ -3097,7 +3095,7 @@
     return multicol_container;
   }
 
-  if (IsFloating())
+  if (IsFloating() && !IsInLayoutNGInlineFormattingContext())
     return ContainingBlock(skip_info);
 
   return Parent();
diff --git a/third_party/blink/renderer/core/layout/layout_object_test.cc b/third_party/blink/renderer/core/layout/layout_object_test.cc
index d74784b..47450ba5 100644
--- a/third_party/blink/renderer/core/layout/layout_object_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_test.cc
@@ -278,8 +278,13 @@
       ToLayoutBoxModelObject(GetLayoutObjectByElementId("float_obj"));
   LayoutObject* span =
       ToLayoutBoxModelObject(GetLayoutObjectByElementId("span"));
-  // 10px for margin, -40px because float is to the left of the span.
-  EXPECT_EQ(LayoutSize(-30, 0), float_obj->OffsetFromAncestor(span));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    // 10px for margin.
+    EXPECT_EQ(LayoutSize(10, 0), float_obj->OffsetFromAncestor(span));
+  } else {
+    // 10px for margin, -40px because float is to the left of the span.
+    EXPECT_EQ(LayoutSize(-30, 0), float_obj->OffsetFromAncestor(span));
+  }
 }
 
 TEST_F(LayoutObjectTest, FloatUnderInline) {
@@ -303,17 +308,30 @@
 
   EXPECT_EQ(layered_div->Layer(), layered_div->PaintingLayer());
   EXPECT_EQ(layered_span->Layer(), layered_span->PaintingLayer());
-  EXPECT_EQ(layered_div->Layer(), floating->PaintingLayer());
-  EXPECT_EQ(container, floating->Container());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    // LayoutNG inline-level floats are children of their inline-level
+    // containers. As such LayoutNG paints these within the correct
+    // inline-level layer.
+    EXPECT_EQ(layered_span->Layer(), floating->PaintingLayer());
+    EXPECT_EQ(layered_span, floating->Container());
+  } else {
+    EXPECT_EQ(layered_div->Layer(), floating->PaintingLayer());
+    EXPECT_EQ(container, floating->Container());
+  }
   EXPECT_EQ(container, floating->ContainingBlock());
 
   LayoutObject::AncestorSkipInfo skip_info(layered_span);
-  EXPECT_EQ(container, floating->Container(&skip_info));
-  EXPECT_TRUE(skip_info.AncestorSkipped());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(layered_span, floating->Container(&skip_info));
+    EXPECT_FALSE(skip_info.AncestorSkipped());
+  } else {
+    EXPECT_EQ(container, floating->Container(&skip_info));
+    EXPECT_TRUE(skip_info.AncestorSkipped());
 
-  skip_info = LayoutObject::AncestorSkipInfo(container);
-  EXPECT_EQ(container, floating->Container(&skip_info));
-  EXPECT_FALSE(skip_info.AncestorSkipped());
+    skip_info = LayoutObject::AncestorSkipInfo(container);
+    EXPECT_EQ(container, floating->Container(&skip_info));
+    EXPECT_FALSE(skip_info.AncestorSkipped());
+  }
 }
 
 TEST_F(LayoutObjectTest, MutableForPaintingClearPaintFlags) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc
index 0025d7f..a0130dee4 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc
@@ -18,13 +18,15 @@
                                        unsigned start,
                                        unsigned end,
                                        bool break_anywhere_if_overflow,
-                                       bool should_create_line_box)
+                                       bool should_create_line_box,
+                                       bool has_unpositioned_floats)
     : item(item),
       item_index(index),
       start_offset(start),
       end_offset(end),
       break_anywhere_if_overflow(break_anywhere_if_overflow),
-      should_create_line_box(should_create_line_box) {}
+      should_create_line_box(should_create_line_box),
+      has_unpositioned_floats(has_unpositioned_floats) {}
 
 void NGLineInfo::SetLineStyle(const NGInlineNode& node,
                               const NGInlineItemsData& items_data,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
index db73f1b..4b19e6c5 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -49,6 +50,11 @@
   // NGLayoutResult for atomic inline items.
   scoped_refptr<NGLayoutResult> layout_result;
 
+  // NGPositionedFloat for floating inline items. Should only be present for
+  // positioned floats (not unpositioned). It indicates where it was placed
+  // within the BFC.
+  base::Optional<NGPositionedFloat> positioned_float;
+
   // Margins, borders, and padding for open tags.
   // Margins are set for atomic inlines too.
   NGLineBoxStrut margins;
@@ -96,6 +102,11 @@
   // correctly determine that we don't need a line box.
   bool should_create_line_box = false;
 
+  // The field should be initialized and maintained like
+  // |should_create_line_box|. It indicates if there are (at the current
+  // position) any unpositioned floats.
+  bool has_unpositioned_floats = false;
+
   // End effects for text items.
   // The effects are included in |shape_result|, but not in text content.
   NGTextEndEffect text_end_effect = NGTextEndEffect::kNone;
@@ -106,7 +117,8 @@
                      unsigned start,
                      unsigned end,
                      bool break_anywhere_if_overflow,
-                     bool should_create_line_box);
+                     bool should_create_line_box,
+                     bool has_unpositioned_floats);
 
 #if DCHECK_IS_ON()
   void CheckConsistency(bool during_line_break = false) const;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 82e8a8dd..9f3ccbb 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -161,8 +161,10 @@
 }
 #endif
 
-void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
-                                         NGExclusionSpace* exclusion_space) {
+void NGInlineLayoutAlgorithm::CreateLine(
+    const NGLineLayoutOpportunity& opportunity,
+    NGLineInfo* line_info,
+    NGExclusionSpace* exclusion_space) {
   // Needs MutableResults to move ShapeResult out of the NGLineInfo.
   NGInlineItemResults* line_items = line_info->MutableResults();
   line_box_.resize(0);
@@ -190,6 +192,7 @@
 #endif
 
   bool has_out_of_flow_positioned_items = false;
+  bool has_floating_items = false;
 
   // List items trigger strict line height, i.e. we make room for the line box
   // strut, for *every* line. This matches other browsers. The intention may
@@ -248,6 +251,15 @@
 
       line_box_.AddChild(item.GetLayoutObject(), item.BidiLevel(), direction);
       has_out_of_flow_positioned_items = true;
+    } else if (item.Type() == NGInlineItem::kFloating) {
+      if (item_result.positioned_float) {
+        line_box_.AddChild(
+            std::move(item_result.positioned_float->layout_result),
+            item_result.positioned_float->bfc_offset, item.BidiLevel());
+      } else {
+        line_box_.AddChild(item.GetLayoutObject(), item.BidiLevel());
+      }
+      has_floating_items = true;
     } else if (item.Type() == NGInlineItem::kBidiControl) {
       line_box_.AddChild(item.BidiLevel());
     }
@@ -299,6 +311,16 @@
   if (has_out_of_flow_positioned_items)
     PlaceOutOfFlowObjects(*line_info, line_box_metrics);
 
+  // Place floating objects.
+  // This adjusts the  NGLineBoxFragmentBuilder::Child::offset member to
+  // contain the position of the float relative to the linebox.
+  // Additionally it will perform layout on any unpositioned floats which
+  // needed the line height to correctly determine their final position.
+  if (has_floating_items) {
+    PlaceFloatingObjects(*line_info, line_box_metrics, opportunity,
+                         exclusion_space);
+  }
+
   // Create box fragments if needed. After this point forward, |line_box_| is a
   // tree structure.
   // The individual children don't move position within the |line_box_|, rather
@@ -453,14 +475,14 @@
   DCHECK(line_info.IsEmptyLine() || !line_box_metrics.IsEmpty())
       << "Non-empty lines must have a valid set of linebox metrics.";
 
-  LayoutUnit line_height =
-      line_info.IsEmptyLine() ? LayoutUnit() : line_box_metrics.LineHeight();
-
   // All children within the linebox are positioned relative to the baseline,
   // then shifted later using NGLineBoxFragmentBuilder::MoveInBlockDirection.
   LayoutUnit baseline_adjustment =
       line_info.IsEmptyLine() ? LayoutUnit() : -line_box_metrics.ascent;
 
+  LayoutUnit line_height =
+      line_info.IsEmptyLine() ? LayoutUnit() : line_box_metrics.LineHeight();
+
   // The location of the "next" line.
   //
   // This uses NGConstraintSpace::Direction rather than
@@ -509,6 +531,71 @@
   }
 }
 
+void NGInlineLayoutAlgorithm::PlaceFloatingObjects(
+    const NGLineInfo& line_info,
+    const NGLineHeightMetrics& line_box_metrics,
+    const NGLineLayoutOpportunity& opportunity,
+    NGExclusionSpace* exclusion_space) {
+  DCHECK(line_info.IsEmptyLine() || !line_box_metrics.IsEmpty())
+      << "Non-empty lines must have a valid set of linebox metrics.";
+
+  // All children within the linebox are positioned relative to the baseline,
+  // then shifted later using NGLineBoxFragmentBuilder::MoveInBlockDirection.
+  LayoutUnit baseline_adjustment =
+      line_info.IsEmptyLine() ? LayoutUnit() : -line_box_metrics.ascent;
+
+  LayoutUnit line_height =
+      line_info.IsEmptyLine() ? LayoutUnit() : line_box_metrics.LineHeight();
+
+  // Any unpositioned floats we encounter need to be placed on the "next" line.
+  // This BFC block-offset represents the start of the "next" line.
+  LayoutUnit origin_bfc_block_offset =
+      opportunity.bfc_block_offset + line_height;
+
+  bool is_empty_inline = Node().IsEmptyInline();
+
+  LayoutUnit bfc_block_offset = line_info.BfcOffset().block_offset;
+  if (is_empty_inline && ConstraintSpace().FloatsBfcBlockOffset()) {
+    bfc_block_offset = *ConstraintSpace().FloatsBfcBlockOffset();
+  }
+
+  LayoutUnit bfc_line_offset = container_builder_.BfcLineOffset();
+
+  for (NGLineBoxFragmentBuilder::Child& child : line_box_) {
+    // We need to position any floats which should be on the "next" line now.
+    // If this is an empty inline, all floats are positioned during the
+    // PositionLeadingFloats step.
+    if (child.unpositioned_float && !is_empty_inline) {
+      NGPositionedFloat positioned_float = PositionFloat(
+          origin_bfc_block_offset, child.unpositioned_float, exclusion_space);
+
+      child.layout_result = std::move(positioned_float.layout_result);
+      child.bfc_offset = positioned_float.bfc_offset;
+      child.unpositioned_float = nullptr;
+    }
+
+    // Skip any children which aren't positioned floats.
+    if (!child.layout_result ||
+        !child.layout_result->PhysicalFragment()->IsFloating())
+      continue;
+
+    LayoutUnit block_offset =
+        child.bfc_offset.block_offset - bfc_block_offset + baseline_adjustment;
+
+    // We need to manually account for the flipped-lines writing mode here :(.
+    if (IsFlippedLinesWritingMode(ConstraintSpace().GetWritingMode())) {
+      NGFragment fragment(
+          ConstraintSpace().GetWritingMode(),
+          ToNGPhysicalBoxFragment(*child.layout_result->PhysicalFragment()));
+
+      block_offset = -fragment.BlockSize() - block_offset;
+    }
+
+    child.offset = {child.bfc_offset.line_offset - bfc_line_offset,
+                    block_offset};
+  }
+}
+
 // Place a list marker.
 void NGInlineLayoutAlgorithm::PlaceListMarker(const NGInlineItem& item,
                                               NGInlineItemResult* item_result,
@@ -671,19 +758,16 @@
   } else {
     DCHECK(ConstraintSpace().MarginStrut().IsEmpty());
 
-    // We need to pre-emptively set the BFC block offset in order for leading
-    // floats to be positioned correctly.
-    container_builder_.SetBfcBlockOffset(
-        ConstraintSpace().BfcOffset().block_offset);
-
     // The BFC block offset was determined before entering this algorithm. This
     // means that there should be no adjoining floats.
     DCHECK(!ConstraintSpace().AdjoiningFloatTypes());
   }
 
   // In order to get the correct list of layout opportunities, we need to
-  // position any "leading" items (floats) within the exclusion space first.
-  unsigned handled_item_index = PositionLeadingFloats(&initial_exclusion_space);
+  // position any "leading" floats within the exclusion space first.
+  NGPositionedFloatVector leading_floats;
+  unsigned handled_leading_floats_index =
+      PositionLeadingFloats(&initial_exclusion_space, &leading_floats);
 
   // We query all the layout opportunities on the initial exclusion space up
   // front, as if the line breaker may add floats and change the opportunities.
@@ -692,10 +776,6 @@
           ConstraintSpace().BfcOffset(),
           ConstraintSpace().AvailableSize().inline_size);
 
-  Vector<NGPositionedFloat> positioned_floats;
-  // We shouldn't have any unpositioned floats if we aren't empty.
-  DCHECK(unpositioned_floats_.IsEmpty() || is_empty_inline);
-
   NGExclusionSpace exclusion_space;
   const NGInlineBreakToken* break_token = BreakToken();
 
@@ -724,8 +804,6 @@
 #endif
 
     // Reset any state that may have been modified in a previous pass.
-    positioned_floats.Shrink(0);
-    unpositioned_floats_.Shrink(0);
     container_builder_.Reset();
     exclusion_space = initial_exclusion_space;
 
@@ -734,10 +812,10 @@
                                                  line_block_size, block_delta);
 
     NGLineInfo line_info;
-    NGLineBreaker line_breaker(
-        Node(), NGLineBreakerMode::kContent, constraint_space_,
-        &positioned_floats, &unpositioned_floats_, &container_builder_,
-        &exclusion_space, handled_item_index, line_opportunity, break_token);
+    NGLineBreaker line_breaker(Node(), NGLineBreakerMode::kContent,
+                               constraint_space_, line_opportunity,
+                               leading_floats, handled_leading_floats_index,
+                               break_token, &exclusion_space);
     line_breaker.NextLine(&line_info);
 
     // If this fragment will be larger than the inline-size of the opportunity,
@@ -765,7 +843,7 @@
     }
 
     PrepareBoxStates(line_info, break_token);
-    CreateLine(&line_info, &exclusion_space);
+    CreateLine(line_opportunity, &line_info, &exclusion_space);
 
     // We now can check the block-size of the fragment, and it fits within the
     // opportunity.
@@ -809,15 +887,11 @@
       container_builder_.SetIsPushedByFloats();
 
     // Success!
-    positioned_floats_.AppendVector(positioned_floats);
     container_builder_.SetBreakToken(line_breaker.CreateBreakToken(line_info));
 
     if (is_empty_inline) {
       DCHECK_EQ(container_builder_.BlockSize(), 0);
     } else {
-      // Place any remaining floats which couldn't fit on the line.
-      PositionPendingFloats(line_height, &exclusion_space);
-
       // A <br clear=both> will strech the line-box height, such that the
       // block-end edge will clear any floats.
       // TODO(ikilpatrick): Move this into ng_block_layout_algorithm.
@@ -827,9 +901,6 @@
     break;
   }
 
-  // We shouldn't have any unpositioned floats if we aren't empty.
-  DCHECK(unpositioned_floats_.IsEmpty() || is_empty_inline);
-  container_builder_.SwapPositionedFloats(&positioned_floats_);
   container_builder_.SetExclusionSpace(std::move(exclusion_space));
   container_builder_.MoveOutOfFlowDescendantCandidatesToDescendants();
   return container_builder_.ToLineBoxFragment();
@@ -838,64 +909,64 @@
 // This positions any "leading" floats within the given exclusion space.
 // If we are also an empty inline, it will add any out-of-flow descendants.
 unsigned NGInlineLayoutAlgorithm::PositionLeadingFloats(
-    NGExclusionSpace* exclusion_space) {
-  const Vector<NGInlineItem>& items = Node().ItemsData(false).items;
+    NGExclusionSpace* exclusion_space,
+    NGPositionedFloatVector* positioned_floats) {
+  bool is_empty_inline = Node().IsEmptyInline();
+  bool should_ignore_floats = BreakToken() && BreakToken()->IgnoreFloats();
+
+  const Vector<NGInlineItem>& items =
+      Node().ItemsData(/* is_first_line */ false).items;
 
   unsigned index = BreakToken() ? BreakToken()->ItemIndex() : 0;
   for (; index < items.size(); ++index) {
     const NGInlineItem& item = items[index];
 
-    if (item.Type() == NGInlineItem::kFloating) {
-      NGBlockNode node(ToLayoutBox(item.GetLayoutObject()));
-
-      AddUnpositionedFloat(&unpositioned_floats_, &container_builder_,
-                           NGUnpositionedFloat(node, /* break_token */ nullptr),
-                           ConstraintSpace());
-    }
-
     // Abort if we've found something that makes this a non-empty inline.
     if (!item.IsEmptyItem()) {
-      DCHECK(!Node().IsEmptyInline());
+      DCHECK(!is_empty_inline);
       break;
     }
-  }
 
-  if (container_builder_.BfcBlockOffset() ||
-      ConstraintSpace().FloatsBfcBlockOffset())
-    PositionPendingFloats(/* content_size */ LayoutUnit(), exclusion_space);
+    if (item.Type() != NGInlineItem::kFloating || should_ignore_floats)
+      continue;
+
+    container_builder_.AddAdjoiningFloatTypes(
+        ResolvedFloating(item.GetLayoutObject()->StyleRef().Floating(),
+                         ConstraintSpace().Direction()) == EFloat::kLeft
+            ? kFloatTypeLeft
+            : kFloatTypeRight);
+
+    // If we are an empty inline, and don't have the special floats BFC
+    // block-offset yet, there is no way to position any floats.
+    if (is_empty_inline && !ConstraintSpace().FloatsBfcBlockOffset())
+      continue;
+
+    LayoutUnit origin_bfc_block_offset =
+        is_empty_inline ? ConstraintSpace().FloatsBfcBlockOffset().value()
+                        : ConstraintSpace().BfcOffset().block_offset;
+
+    NGPositionedFloat positioned_float = PositionFloat(
+        origin_bfc_block_offset, item.GetLayoutObject(), exclusion_space);
+    positioned_floats->push_back(std::move(positioned_float));
+  }
 
   return index;
 }
 
-void NGInlineLayoutAlgorithm::PositionPendingFloats(
-    LayoutUnit content_size,
-    NGExclusionSpace* exclusion_space) {
-  DCHECK(container_builder_.BfcBlockOffset() ||
-         ConstraintSpace().FloatsBfcBlockOffset())
-      << "The floats BFC block offset should be known here";
-
-  if (BreakToken() && BreakToken()->IgnoreFloats()) {
-    unpositioned_floats_.Shrink(0);
-    return;
-  }
-
-  LayoutUnit bfc_block_offset =
-      container_builder_.BfcBlockOffset()
-          ? container_builder_.BfcBlockOffset().value()
-          : ConstraintSpace().FloatsBfcBlockOffset().value();
+NGPositionedFloat NGInlineLayoutAlgorithm::PositionFloat(
+    LayoutUnit origin_bfc_block_offset,
+    LayoutObject* floating_object,
+    NGExclusionSpace* exclusion_space) const {
+  NGUnpositionedFloat unpositioned_float(
+      NGBlockNode(ToLayoutBox(floating_object)), /* break_token */ nullptr);
 
   NGBfcOffset origin_bfc_offset = {ConstraintSpace().BfcOffset().line_offset,
-                                   bfc_block_offset + content_size};
-
-  NGPositionedFloatVector positioned_floats;
-  PositionFloats(ConstraintSpace().AvailableSize(),
-                 ConstraintSpace().PercentageResolutionSize(),
-                 ConstraintSpace().ReplacedPercentageResolutionSize(),
-                 origin_bfc_offset, unpositioned_floats_, ConstraintSpace(),
-                 Style(), exclusion_space, &positioned_floats);
-
-  positioned_floats_.AppendVector(positioned_floats);
-  unpositioned_floats_.Shrink(0);
+                                   origin_bfc_block_offset};
+  return ::blink::PositionFloat(
+      ConstraintSpace().AvailableSize(),
+      ConstraintSpace().PercentageResolutionSize(),
+      ConstraintSpace().ReplacedPercentageResolutionSize(), origin_bfc_offset,
+      &unpositioned_float, ConstraintSpace(), Style(), exclusion_space);
 }
 
 void NGInlineLayoutAlgorithm::BidiReorder() {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
index 5d8049b2..e23cd43 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -28,7 +28,6 @@
 class NGLineInfo;
 struct NGInlineBoxState;
 struct NGInlineItemResult;
-struct NGPositionedFloat;
 
 // A class for laying out an inline formatting context, i.e. a block with inline
 // children.
@@ -47,14 +46,17 @@
                           NGInlineChildLayoutContext* context);
   ~NGInlineLayoutAlgorithm() override;
 
-  void CreateLine(NGLineInfo*, NGExclusionSpace*);
+  void CreateLine(const NGLineLayoutOpportunity&,
+                  NGLineInfo*,
+                  NGExclusionSpace*);
 
   scoped_refptr<NGLayoutResult> Layout() override;
 
  private:
-  unsigned PositionLeadingFloats(NGExclusionSpace*);
-
-  void PositionPendingFloats(LayoutUnit content_size, NGExclusionSpace*);
+  unsigned PositionLeadingFloats(NGExclusionSpace*, NGPositionedFloatVector*);
+  NGPositionedFloat PositionFloat(LayoutUnit origin_block_bfc_offset,
+                                  LayoutObject* floating_object,
+                                  NGExclusionSpace*) const;
 
   bool IsHorizontalWritingMode() const { return is_horizontal_writing_mode_; }
 
@@ -89,6 +91,10 @@
                          NGInlineBoxState*,
                          LayoutUnit inline_offset = LayoutUnit());
   void PlaceOutOfFlowObjects(const NGLineInfo&, const NGLineHeightMetrics&);
+  void PlaceFloatingObjects(const NGLineInfo&,
+                            const NGLineHeightMetrics&,
+                            const NGLineLayoutOpportunity&,
+                            NGExclusionSpace*);
   void PlaceListMarker(const NGInlineItem&,
                        NGInlineItemResult*,
                        const NGLineInfo&);
@@ -109,9 +115,6 @@
   unsigned is_horizontal_writing_mode_ : 1;
   unsigned quirks_mode_ : 1;
 
-  Vector<NGPositionedFloat> positioned_floats_;
-  NGUnpositionedFloatVector unpositioned_floats_;
-
 #if DCHECK_IS_ON()
   // True if |box_states_| is taken from |context_|, to check the |box_states_|
   // is the same as when it is rebuilt.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
index 4585f67..49193ed 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
@@ -361,8 +361,8 @@
   const NGPhysicalBoxFragment* block_box = block_flow->CurrentFragment();
   ASSERT_TRUE(block_box);
 
-  // float plus two lines.
-  EXPECT_EQ(3u, block_box->Children().size());
+  // Two lines.
+  EXPECT_EQ(2u, block_box->Children().size());
   NGPhysicalOffset first_line_offset = block_box->Children()[1].Offset();
 
   // 30 == narrow-float's width.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index 55d2c3ca..5e3a355 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -240,6 +240,9 @@
       if (builder->ShouldAbort())
         return;
 
+      if (update_layout)
+        ClearInlineFragment(node);
+
     } else if (node->IsOutOfFlowPositioned()) {
       builder->AppendOutOfFlowPositioned(node);
       if (builder->ShouldAbort())
@@ -877,8 +880,7 @@
   for (unsigned i = break_token ? break_token->ItemIndex() : 0;
        i < items.size(); i++) {
     const NGInlineItem& item = items[i];
-    if (item.Type() == NGInlineItem::kFloating ||
-        item.Type() == NGInlineItem::kOutOfFlowPositioned ||
+    if (item.Type() == NGInlineItem::kOutOfFlowPositioned ||
         item.Type() == NGInlineItem::kListMarker)
       continue;
     LayoutObject* object = item.GetLayoutObject();
@@ -965,21 +967,20 @@
           .SetIsIntermediateLayout(true)
           .ToConstraintSpace();
 
-  Vector<NGPositionedFloat> positioned_floats;
-  NGUnpositionedFloatVector unpositioned_floats;
-
   NGExclusionSpace empty_exclusion_space;
+  NGPositionedFloatVector empty_leading_floats;
+  Vector<LayoutObject*> floats_for_min_max;
   NGLineLayoutOpportunity line_opportunity(available_inline_size);
   LayoutUnit result;
   LayoutUnit previous_floats_inline_size =
       input.float_left_inline_size + input.float_right_inline_size;
   DCHECK_GE(previous_floats_inline_size, 0);
   NGLineBreaker line_breaker(
-      node, mode, space, &positioned_floats, &unpositioned_floats,
-      nullptr /* container_builder */, &empty_exclusion_space, 0u,
-      line_opportunity, nullptr /* break_token */);
+      node, mode, space, line_opportunity, empty_leading_floats,
+      /* handled_leading_floats_index */ 0u,
+      /* break_token */ nullptr, &empty_exclusion_space, &floats_for_min_max);
   do {
-    unpositioned_floats.Shrink(0);
+    floats_for_min_max.Shrink(0);
 
     NGLineInfo line_info;
     line_breaker.NextLine(&line_info);
@@ -989,9 +990,6 @@
     LayoutUnit inline_size = line_info.Width();
     DCHECK_EQ(inline_size, line_info.ComputeWidth().ClampNegativeToZero());
 
-    // There should be no positioned floats while determining the min/max sizes.
-    DCHECK_EQ(positioned_floats.size(), 0u);
-
     // These variables are only used for the max-content calculation.
     LayoutUnit floats_inline_size = mode == NGLineBreakerMode::kMaxContent
                                         ? previous_floats_inline_size
@@ -1002,8 +1000,10 @@
     // them now.
     previous_floats_inline_size = LayoutUnit();
 
-    for (const auto& unpositioned_float : unpositioned_floats) {
-      NGBlockNode float_node = unpositioned_float.node;
+    for (auto* floating_object : floats_for_min_max) {
+      DCHECK(floating_object->IsFloating());
+
+      NGBlockNode float_node(ToLayoutBox(floating_object));
       const ComputedStyle& float_style = float_node.Style();
 
       MinMaxSizeInput zero_input;  // Floats don't intrude into floats.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
index e1e5e6f5..6b1f5357 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -20,7 +20,6 @@
 class ComputedStyle;
 class NGInlineBreakToken;
 class NGPhysicalFragment;
-struct NGPositionedFloat;
 
 class CORE_EXPORT NGLineBoxFragmentBuilder final
     : public NGContainerFragmentBuilder {
@@ -52,10 +51,6 @@
     base_direction_ = direction;
   }
 
-  void SwapPositionedFloats(Vector<NGPositionedFloat>* positioned_floats) {
-    positioned_floats_.swap(*positioned_floats);
-  }
-
   // Set the break token for the fragment to build.
   // A finished break token will be attached if not set.
   void SetBreakToken(scoped_refptr<NGInlineBreakToken> break_token) {
@@ -70,9 +65,13 @@
     scoped_refptr<NGLayoutResult> layout_result;
     scoped_refptr<const NGPhysicalFragment> fragment;
     LayoutObject* out_of_flow_positioned_box = nullptr;
+    LayoutObject* unpositioned_float = nullptr;
     // The offset of the border box, initially in this child coordinate system.
     // |ComputeInlinePositions()| converts it to the offset within the line box.
     NGLogicalOffset offset;
+    // The offset of a positioned float wrt. the root BFC. This should only be
+    // set for positioned floats.
+    NGBfcOffset bfc_offset;
     // The inline size of the margin box.
     LayoutUnit inline_size;
     LayoutUnit margin_line_left;
@@ -124,8 +123,26 @@
         : out_of_flow_positioned_box(out_of_flow_positioned_box),
           bidi_level(bidi_level),
           container_direction(container_direction) {}
+    // Create an unpositioned float.
+    Child(LayoutObject* unpositioned_float, UBiDiLevel bidi_level)
+        : unpositioned_float(unpositioned_float), bidi_level(bidi_level) {}
+    // Create a positioned float.
+    Child(scoped_refptr<NGLayoutResult> layout_result,
+          NGBfcOffset bfc_offset,
+          UBiDiLevel bidi_level)
+        : layout_result(std::move(layout_result)),
+          bfc_offset(bfc_offset),
+          bidi_level(bidi_level) {}
 
-    bool HasInFlowFragment() const { return layout_result || fragment; }
+    bool HasInFlowFragment() const {
+      if (fragment)
+        return true;
+
+      if (layout_result && !layout_result->PhysicalFragment()->IsFloating())
+        return true;
+
+      return false;
+    }
     bool HasOutOfFlowFragment() const { return out_of_flow_positioned_box; }
     bool HasFragment() const {
       return HasInFlowFragment() || HasOutOfFlowFragment();
@@ -208,8 +225,6 @@
   NGInlineNode node_;
 
   NGLineHeightMetrics metrics_;
-  Vector<NGPositionedFloat> positioned_floats_;
-
   NGPhysicalLineBoxFragment::NGLineBoxType line_box_type_;
   TextDirection base_direction_;
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index d8ff7ee..38c8831 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -41,18 +41,21 @@
   return !item_results.IsEmpty() && item_results.back().should_create_line_box;
 }
 
+inline bool HasUnpositionedFloats(const NGInlineItemResults& item_results) {
+  return !item_results.IsEmpty() && item_results.back().has_unpositioned_floats;
+}
+
 }  // namespace
 
 NGLineBreaker::NGLineBreaker(NGInlineNode node,
                              NGLineBreakerMode mode,
                              const NGConstraintSpace& space,
-                             Vector<NGPositionedFloat>* positioned_floats,
-                             NGUnpositionedFloatVector* unpositioned_floats,
-                             NGContainerFragmentBuilder* container_builder,
-                             NGExclusionSpace* exclusion_space,
-                             unsigned handled_float_index,
                              const NGLineLayoutOpportunity& line_opportunity,
-                             const NGInlineBreakToken* break_token)
+                             const NGPositionedFloatVector& leading_floats,
+                             unsigned handled_leading_floats_index,
+                             const NGInlineBreakToken* break_token,
+                             NGExclusionSpace* exclusion_space,
+                             Vector<LayoutObject*>* out_floats_for_min_max)
     : line_opportunity_(line_opportunity),
       node_(node),
       is_first_formatted_line_((!break_token || (!break_token->ItemIndex() &&
@@ -67,14 +70,13 @@
       items_data_(node.ItemsData(use_first_line_style_)),
       mode_(mode),
       constraint_space_(space),
-      positioned_floats_(positioned_floats),
-      unpositioned_floats_(unpositioned_floats),
-      container_builder_(container_builder),
       exclusion_space_(exclusion_space),
       break_iterator_(items_data_.text_content),
       shaper_(items_data_.text_content),
       spacing_(items_data_.text_content),
-      handled_floats_end_item_index_(handled_float_index),
+      leading_floats_(leading_floats),
+      handled_leading_floats_index_(handled_leading_floats_index),
+      out_floats_for_min_max_(out_floats_for_min_max),
       base_direction_(node_.BaseDirection()) {
   break_iterator_.SetBreakSpace(BreakSpaceType::kBeforeSpaceRun);
 
@@ -98,7 +100,8 @@
   DCHECK_LE(end_offset, item.EndOffset());
   return &item_results_->emplace_back(&item, item_index_, offset_, end_offset,
                                       break_anywhere_if_overflow_,
-                                      ShouldCreateLineBox(*item_results_));
+                                      ShouldCreateLineBox(*item_results_),
+                                      HasUnpositionedFloats(*item_results_));
 }
 
 inline NGInlineItemResult* NGLineBreaker::AddItem(const NGInlineItem& item) {
@@ -908,24 +911,31 @@
   NGInlineItemResult* item_result = AddItem(item);
   ComputeCanBreakAfter(item_result);
   MoveToNextOf(item);
-  if (item_index_ <= handled_floats_end_item_index_ || ignore_floats_)
+
+  // If we are currently computing our min/max-content size simply append to
+  // the unpositioned floats list and abort.
+  if (mode_ != NGLineBreakerMode::kContent) {
+    DCHECK(out_floats_for_min_max_);
+    out_floats_for_min_max_->push_back(item.GetLayoutObject());
+    return;
+  }
+
+  if (ignore_floats_)
     return;
 
-  NGBlockNode node(ToLayoutBox(item.GetLayoutObject()));
-
-  const ComputedStyle& float_style = node.Style();
+  // Make sure we populate the positioned_float inside the |item_result|.
+  if (item_index_ <= handled_leading_floats_index_ &&
+      !leading_floats_.IsEmpty()) {
+    DCHECK_LT(leading_floats_index_, leading_floats_.size());
+    item_result->positioned_float = leading_floats_[leading_floats_index_++];
+    return;
+  }
 
   // TODO(ikilpatrick): Add support for float break tokens inside an inline
   // layout context.
-  NGUnpositionedFloat unpositioned_float(node, /* break_token */ nullptr);
-
-  // If we are currently computing our min/max-content size simply append
-  // to the unpositioned floats list and abort.
-  if (mode_ != NGLineBreakerMode::kContent) {
-    AddUnpositionedFloat(unpositioned_floats_, container_builder_,
-                         std::move(unpositioned_float), constraint_space_);
-    return;
-  }
+  NGUnpositionedFloat unpositioned_float(
+      NGBlockNode(ToLayoutBox(item.GetLayoutObject())),
+      /* break_token */ nullptr);
 
   LayoutUnit inline_margin_size =
       ComputeMarginBoxInlineSizeForUnpositionedFloat(
@@ -955,15 +965,13 @@
   bool float_after_line =
       !can_fit_float ||
       exclusion_space_->LastFloatBlockStart() > bfc_block_offset ||
-      exclusion_space_->ClearanceOffset(
-          ResolvedClear(float_style.Clear(), constraint_space_.Direction())) >
-          bfc_block_offset;
+      exclusion_space_->ClearanceOffset(unpositioned_float.ClearType(
+          constraint_space_.Direction())) > bfc_block_offset;
 
   // Check if we already have a pending float. That's because a float cannot be
   // higher than any block or floated box generated before.
-  if (!unpositioned_floats_->IsEmpty() || float_after_line) {
-    AddUnpositionedFloat(unpositioned_floats_, container_builder_,
-                         std::move(unpositioned_float), constraint_space_);
+  if (HasUnpositionedFloats(*item_results_) || float_after_line) {
+    item_result->has_unpositioned_floats = true;
   } else {
     NGPositionedFloat positioned_float = PositionFloat(
         constraint_space_.AvailableSize(),
@@ -972,7 +980,8 @@
         {constraint_space_.BfcOffset().line_offset, bfc_block_offset},
         &unpositioned_float, constraint_space_, node_.Style(),
         exclusion_space_);
-    positioned_floats_->push_back(positioned_float);
+
+    item_result->positioned_float = positioned_float;
 
     NGLayoutOpportunity opportunity = exclusion_space_->FindLayoutOpportunity(
         {constraint_space_.BfcOffset().line_offset, bfc_block_offset},
@@ -1217,20 +1226,17 @@
   // rewinding them needs to remove from these lists too.
   for (unsigned i = item_results.size(); i > new_end;) {
     NGInlineItemResult& rewind = item_results[--i];
-    if (rewind.item->Type() == NGInlineItem::kFloating) {
-      NGBlockNode float_node(ToLayoutBox(rewind.item->GetLayoutObject()));
-      if (!RemoveUnpositionedFloat(unpositioned_floats_, float_node)) {
-        // TODO(kojii): We do not have mechanism to remove once positioned
-        // floats yet, and that rewinding them may lay it out twice. For now,
-        // prohibit rewinding positioned floats. This may results in incorrect
-        // layout, but still better than rewinding them.
-        new_end = i + 1;
-        if (new_end == item_results.size()) {
-          UpdatePosition();
-          return;
-        }
-        break;
+    if (rewind.positioned_float) {
+      // TODO(kojii): We do not have mechanism to remove once positioned floats
+      // yet, and that rewinding them may lay it out twice. For now, prohibit
+      // rewinding positioned floats. This may results in incorrect layout, but
+      // still better than rewinding them.
+      new_end = i + 1;
+      if (new_end == item_results.size()) {
+        UpdatePosition();
+        return;
       }
+      break;
     }
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
index 1052fb0..04ed7efb 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -18,10 +18,8 @@
 namespace blink {
 
 class Hyphenation;
-class NGContainerFragmentBuilder;
 class NGInlineBreakToken;
 class NGInlineItem;
-struct NGPositionedFloat;
 
 // The line breaker needs to know which mode its in to properly handle floats.
 enum class NGLineBreakerMode { kContent, kMinContent, kMaxContent };
@@ -37,13 +35,12 @@
   NGLineBreaker(NGInlineNode,
                 NGLineBreakerMode,
                 const NGConstraintSpace&,
-                Vector<NGPositionedFloat>*,
-                NGUnpositionedFloatVector*,
-                NGContainerFragmentBuilder* container_builder,
-                NGExclusionSpace*,
-                unsigned handled_float_index,
                 const NGLineLayoutOpportunity&,
-                const NGInlineBreakToken* = nullptr);
+                const NGPositionedFloatVector& leading_floats,
+                unsigned handled_leading_floats_index,
+                const NGInlineBreakToken*,
+                NGExclusionSpace*,
+                Vector<LayoutObject*>* out_floats_for_min_max = nullptr);
   ~NGLineBreaker();
 
   // Compute the next line break point and produces NGInlineItemResults for
@@ -209,9 +206,6 @@
 
   NGLineBreakerMode mode_;
   const NGConstraintSpace& constraint_space_;
-  Vector<NGPositionedFloat>* positioned_floats_;
-  NGUnpositionedFloatVector* unpositioned_floats_;
-  NGContainerFragmentBuilder* container_builder_; /* May be nullptr */
   NGExclusionSpace* exclusion_space_;
   scoped_refptr<const ComputedStyle> current_style_;
 
@@ -230,7 +224,11 @@
   base::Optional<TrailingCollapsibleSpace> trailing_collapsible_space_;
 
   // Keep track of handled float items. See HandleFloat().
-  unsigned handled_floats_end_item_index_;
+  const NGPositionedFloatVector& leading_floats_;
+  unsigned leading_floats_index_ = 0u;
+  unsigned handled_leading_floats_index_;
+
+  Vector<LayoutObject*>* out_floats_for_min_max_;
 
   // The current base direction for the bidi algorithm.
   // This is copied from NGInlineNode, then updated after each forced line break
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
index b4f9af9..49d3006 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
@@ -41,22 +41,18 @@
             .SetAvailableSize({available_width, NGSizeIndefinite})
             .ToConstraintSpace();
 
-    Vector<NGPositionedFloat> positioned_floats;
-    NGUnpositionedFloatVector unpositioned_floats;
-
     scoped_refptr<NGInlineBreakToken> break_token;
 
     Vector<NGLineInfo> line_infos;
     trailing_whitespaces_.resize(0);
     NGExclusionSpace exclusion_space;
+    NGPositionedFloatVector leading_floats;
     NGLineLayoutOpportunity line_opportunity(available_width);
     while (!break_token || !break_token->IsFinished()) {
       NGLineInfo& line_info = line_infos.emplace_back();
       NGLineBreaker line_breaker(node, NGLineBreakerMode::kContent, space,
-                                 &positioned_floats, &unpositioned_floats,
-                                 /* container_builder */ nullptr,
-                                 &exclusion_space, 0u, line_opportunity,
-                                 break_token.get());
+                                 line_opportunity, leading_floats, 0u,
+                                 break_token.get(), &exclusion_space);
       line_breaker.NextLine(&line_info);
       trailing_whitespaces_.push_back(
           line_breaker.TrailingWhitespaceForTesting());
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 75a9129..7759f35 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -344,6 +344,11 @@
   if (constraint_space.HasFloats() || cached_constraint_space.HasFloats())
     return false;
 
+  // Any floats might need to move, causing lines to wrap differently, needing
+  // re-layout.
+  if (!cached_result_->ExclusionSpace().IsEmpty())
+    return false;
+
   // Propagating OOF needs re-layout.
   if (!cached_result_->OutOfFlowPositionedDescendants().IsEmpty())
     return false;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index c5e7153..8522444 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -1391,12 +1391,6 @@
       container_builder_.SetIsPushedByFloats();
   }
 
-  // A line-box may have a list of floats which we add as children.
-  if (child.IsInline() && (container_builder_.BfcBlockOffset() ||
-                           ConstraintSpace().FloatsBfcBlockOffset())) {
-    AddPositionedFloats(layout_result->PositionedFloats());
-  }
-
   // We must have an actual fragment at this stage.
   DCHECK(layout_result->PhysicalFragment());
   const auto& physical_fragment = *layout_result->PhysicalFragment();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
index 20dda17..2f382133 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -1077,18 +1077,18 @@
   // 35 = empty1's padding(20) + empty2's padding(15)
   EXPECT_THAT(offset.left, LayoutUnit(35));
 
-  iterator.SetParent(empty2_fragment);
-  iterator.NextChild(&offset);
-  // inline 25 = empty2's padding(15) + left float's margin(10)
-  // block 10 = left float's margin
-  EXPECT_THAT(offset, NGPhysicalOffset(LayoutUnit(25), LayoutUnit(10)));
+  const auto* linebox_fragment = empty2_fragment->Children()[0].fragment;
 
-  iterator.NextChild(&offset);
-  // inline offset 150 = empty2's padding(15) + right float's margin(10) + right
-  // float offset(125)
+  offset = ToNGPhysicalLineBoxFragment(linebox_fragment)->Children()[0].offset;
+  // inline 10 = left float's margin(10)
+  // block 10 = left float's margin
+  EXPECT_THAT(offset, NGPhysicalOffset(LayoutUnit(10), LayoutUnit(10)));
+
+  offset = ToNGPhysicalLineBoxFragment(linebox_fragment)->Children()[1].offset;
+  // inline offset 135 = right float's margin(10) + right float offset(125)
   // block offset 15 = right float's margin
   LayoutUnit right_float_offset = LayoutUnit(125);
-  EXPECT_THAT(offset, NGPhysicalOffset(LayoutUnit(25) + right_float_offset,
+  EXPECT_THAT(offset, NGPhysicalOffset(LayoutUnit(10) + right_float_offset,
                                        LayoutUnit(15)));
 
   // ** Verify layout tree **
@@ -1914,7 +1914,7 @@
 }
 
 // Tests that float children fragment correctly inside a parallel flow.
-TEST_F(NGBlockLayoutAlgorithmTest, FloatFragmentationParallelFlows) {
+TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_FloatFragmentationParallelFlows) {
   SetBodyInnerHTML(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -2035,18 +2035,18 @@
   EXPECT_EQ(NGPhysicalSize(LayoutUnit(150), LayoutUnit(60)), fragment->Size());
   ASSERT_TRUE(!fragment->BreakToken() || fragment->BreakToken()->IsFinished());
 
+  const auto* linebox =
+      ToNGPhysicalBoxFragment(fragment.get())->Children()[0].fragment;
+  const auto* float2 =
+      ToNGPhysicalLineBoxFragment(linebox)->Children()[1].fragment;
+
   // float2 should only have one fragment.
-  FragmentChildIterator iterator(ToNGPhysicalBoxFragment(fragment.get()));
-  NGPhysicalOffset offset;
-  const auto* child = iterator.NextChild(&offset);
-  child = iterator.NextChild(&offset);
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(60), LayoutUnit(200)), child->Size());
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(90), LayoutUnit(50)), offset);
-  ASSERT_TRUE(!child->BreakToken() || child->BreakToken()->IsFinished());
+  EXPECT_EQ(NGPhysicalSize(LayoutUnit(60), LayoutUnit(200)), float2->Size());
+  ASSERT_TRUE(!float2->BreakToken() || float2->BreakToken()->IsFinished());
 }
 
 // Tests that a float child inside a zero height block fragments correctly.
-TEST_F(NGBlockLayoutAlgorithmTest, FloatFragmentationZeroHeight) {
+TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_FloatFragmentationZeroHeight) {
   SetBodyInnerHTML(R"HTML(
     <!DOCTYPE html>
     <style>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 6467db21..1e28906a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -85,6 +85,38 @@
   return layout_object && layout_object->IsFloating() && fragment.IsBox();
 }
 
+// Creates a blink::FloatingObject (if needed), and populates it with the
+// position information needed by the existing layout tree.
+void CopyFloatChildFragmentPosition(LayoutBox* floating_box,
+                                    const NGPhysicalOffset offset,
+                                    bool has_flipped_x_axis) {
+  DCHECK(floating_box->IsFloating());
+
+  LayoutBlock* containing_block = floating_box->ContainingBlock();
+  DCHECK(containing_block);
+
+  // Floats need an associated FloatingObject for painting.
+  FloatingObject* floating_object =
+      ToLayoutBlockFlow(containing_block)->InsertFloatingObject(*floating_box);
+  floating_object->SetShouldPaint(!floating_box->HasSelfPaintingLayer());
+  LayoutUnit horizontal_margin_edge_offset = offset.left;
+  if (has_flipped_x_axis)
+    horizontal_margin_edge_offset -= floating_box->MarginRight();
+  else
+    horizontal_margin_edge_offset -= floating_box->MarginLeft();
+  floating_object->SetX(horizontal_margin_edge_offset);
+  floating_object->SetY(offset.top - floating_box->MarginTop());
+#if DCHECK_IS_ON()
+  // Being "placed" is a legacy thing. Make sure the flags remain unset in NG.
+  DCHECK(!floating_object->IsPlaced());
+  DCHECK(!floating_object->IsInPlacedTree());
+
+  // Set this flag to tell the float machinery that it's safe to read out
+  // position data.
+  floating_object->SetHasGeometry();
+#endif
+}
+
 void UpdateLegacyMultiColumnFlowThread(
     NGBlockNode node,
     LayoutMultiColumnFlowThread* flow_thread,
@@ -707,28 +739,9 @@
   layout_box->SetLocation(LayoutPoint(
       horizontal_offset, fragment_offset.top + additional_offset.top));
 
-  // Floats need an associated FloatingObject for painting.
-  if (IsFloatFragment(fragment) && containing_block->IsLayoutBlockFlow()) {
-    FloatingObject* floating_object =
-        ToLayoutBlockFlow(containing_block)->InsertFloatingObject(*layout_box);
-    floating_object->SetShouldPaint(!layout_box->HasSelfPaintingLayer());
-    LayoutUnit horizontal_margin_edge_offset = horizontal_offset;
-    if (has_flipped_x_axis)
-      horizontal_margin_edge_offset -= layout_box->MarginRight();
-    else
-      horizontal_margin_edge_offset -= layout_box->MarginLeft();
-    floating_object->SetX(horizontal_margin_edge_offset);
-    floating_object->SetY(fragment_offset.top + additional_offset.top -
-                          layout_box->MarginTop());
-#if DCHECK_IS_ON()
-    // Being "placed" is a legacy thing. Make sure the flags remain unset in NG.
-    DCHECK(!floating_object->IsPlaced());
-    DCHECK(!floating_object->IsInPlacedTree());
-
-    // Set this flag to tell the float machinery that it's safe to read out
-    // position data.
-    floating_object->SetHasGeometry();
-#endif
+  if (IsFloatFragment(fragment)) {
+    CopyFloatChildFragmentPosition(
+        layout_box, fragment_offset + additional_offset, has_flipped_x_axis);
   }
 }
 
@@ -756,6 +769,11 @@
                                       maybe_flipped_offset.left;
         }
         layout_box.SetLocation(maybe_flipped_offset.ToLayoutPoint());
+
+        if (IsFloatFragment(*child)) {
+          CopyFloatChildFragmentPosition(&layout_box, maybe_flipped_offset,
+                                         initial_container_is_flipped);
+        }
       }
 
       // Legacy compatibility. This flag is used in paint layer for
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
index 9c2e939..37f15d7 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -461,7 +461,8 @@
   EXPECT_EQ(expectation, dump);
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, FloatInOneColumn) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatInOneColumn) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
@@ -490,7 +491,8 @@
   EXPECT_EQ(expectation, dump);
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInOneColumn) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_TwoFloatsInOneColumn) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
@@ -521,7 +523,8 @@
   EXPECT_EQ(expectation, dump);
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInTwoColumns) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_TwoFloatsInTwoColumns) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
@@ -1333,7 +1336,8 @@
   EXPECT_EQ(expectation, dump);
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, LinesAndFloatsMulticol) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_LinesAndFloatsMulticol) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
@@ -1386,7 +1390,8 @@
   EXPECT_EQ(expectation, dump);
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, FloatBelowLastLineInColumn) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatBelowLastLineInColumn) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
@@ -1738,7 +1743,8 @@
   EXPECT_EQ(expectation, dump);
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, FloatInBlockMovedByOrphans) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatInBlockMovedByOrphans) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
@@ -1781,7 +1787,8 @@
   EXPECT_EQ(expectation, dump);
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, FloatMovedWithWidows) {
+// TODO(crbug.com/915929): Fix inline-level float fragmentation.
+TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatMovedWithWidows) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
index 1172302..a2b06d56 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
@@ -273,9 +273,9 @@
   offset:unplaced size:1000x323
     offset:0,0 size:126x323
       offset:13,0 size:50x200
-        offset:0,0 size:25x200
-        offset:25,0 size:25x200
         offset:50,0 size:0x0
+          offset:-50,0 size:25x200
+          offset:-25,0 size:25x200
       offset:3,200 size:120x120
         offset:10,10 size:100x100
 )DUMP";
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
index c17b1a9..28385668 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -70,7 +70,6 @@
       status_(kSuccess) {
   root_fragment_.fragment_ = std::move(physical_fragment);
   oof_positioned_descendants_ = std::move(builder->oof_positioned_descendants_);
-  positioned_floats_ = std::move(builder->positioned_floats_);
 }
 
 // We can't use =default here because RefCounted can't be copied.
@@ -78,7 +77,6 @@
                                base::Optional<LayoutUnit> bfc_block_offset)
     : root_fragment_(other.root_fragment_),
       oof_positioned_descendants_(other.oof_positioned_descendants_),
-      positioned_floats_(other.positioned_floats_),
       unpositioned_list_marker_(other.unpositioned_list_marker_),
       exclusion_space_(other.exclusion_space_),
       bfc_line_offset_(other.bfc_line_offset_),
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
index 1ed7835..accd3aa 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -23,7 +23,6 @@
 class NGBoxFragmentBuilder;
 class NGExclusionSpace;
 class NGLineBoxFragmentBuilder;
-struct NGPositionedFloat;
 
 // The NGLayoutResult stores the resulting data from layout. This includes
 // geometry information in form of a NGPhysicalFragment, which is kept around
@@ -58,14 +57,6 @@
     return oof_positioned_descendants_;
   }
 
-  // A line-box can have a list of positioned floats. These should be added to
-  // the line-box's parent fragment (as floats which occur within a line-box do
-  // not appear a children).
-  const Vector<NGPositionedFloat>& PositionedFloats() const {
-    DCHECK(root_fragment_->Type() == NGPhysicalFragment::kFragmentLineBox);
-    return positioned_floats_;
-  }
-
   const NGUnpositionedListMarker& UnpositionedListMarker() const {
     return unpositioned_list_marker_;
   }
@@ -138,8 +129,6 @@
   NGLink root_fragment_;
   Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
 
-  Vector<NGPositionedFloat> positioned_floats_;
-
   NGUnpositionedListMarker unpositioned_list_marker_;
 
   const NGExclusionSpace exclusion_space_;
diff --git a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
index 1155978..5eaf546 100644
--- a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
+++ b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
@@ -765,12 +765,23 @@
 
   LayoutRect rect = target_visual_rect;
   EXPECT_TRUE(target->MapToVisualRectInAncestorSpace(&GetLayoutView(), rect));
-  EXPECT_EQ(LayoutRect(66, 55, 33, 44), rect);
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    // LayoutNG inline-level floats are children of their inline-level
+    // containers. As such they are positioned relative to their inline-level
+    // container, (and shifted by an additional 200,100 in this case).
+    EXPECT_EQ(LayoutRect(266, 155, 33, 44), rect);
+  } else {
+    EXPECT_EQ(LayoutRect(66, 55, 33, 44), rect);
+  }
   EXPECT_EQ(rect, target->FirstFragment().VisualRect());
 
   rect = target_visual_rect;
 
-  CheckVisualRect(*target, *span, rect, LayoutRect(-200, -100, 33, 44));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    CheckVisualRect(*target, *span, rect, LayoutRect(0, 0, 33, 44));
+  } else {
+    CheckVisualRect(*target, *span, rect, LayoutRect(-200, -100, 33, 44));
+  }
 }
 
 TEST_P(VisualRectMappingTest, ShouldAccountForPreserve3d) {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index d58c79e..a21157b 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -265,15 +265,15 @@
 
   if (paint_phase != PaintPhase::kSelfOutlineOnly) {
     if (PhysicalFragment().ChildrenInline()) {
-      if (PhysicalFragment().IsBlockFlow()) {
+      if (PhysicalFragment().IsBlockFlow())
         PaintBlockFlowContents(paint_info, paint_offset);
-        if (paint_phase == PaintPhase::kFloat ||
-            paint_phase == PaintPhase::kSelection ||
-            paint_phase == PaintPhase::kTextClip)
-          PaintFloats(paint_info);
-      } else {
+      else
         PaintInlineChildren(box_fragment_.Children(), paint_info, paint_offset);
-      }
+
+      if (paint_phase == PaintPhase::kFloat ||
+          paint_phase == PaintPhase::kSelection ||
+          paint_phase == PaintPhase::kTextClip)
+        PaintFloats(paint_info);
     } else {
       PaintBlockChildren(paint_info);
     }
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index daa0a1b0..52d4398e7 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -459,8 +459,7 @@
                       std::move(previous_child), &populate_children);
 
     if (children_are_inline) {
-      if (!child_fragment->IsFloating() &&
-          !child_fragment->IsOutOfFlowPositioned() &&
+      if (!child_fragment->IsOutOfFlowPositioned() &&
           !child_fragment->IsListMarker()) {
         if (LayoutObject* layout_object = child_fragment->GetLayoutObject())
           child->AssociateWithLayoutObject(layout_object, last_fragment_map);
@@ -487,7 +486,7 @@
     HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map) {
   DCHECK(layout_object);
   DCHECK(!next_for_same_layout_object_);
-  DCHECK(layout_object->IsInline());
+  DCHECK(layout_object->IsInline() || layout_object->IsFloating());
 
   auto add_result = last_fragment_map->insert(layout_object, this);
   if (add_result.is_new_entry) {
@@ -806,6 +805,9 @@
   LayoutUnit closest_child_after_inline_offset = LayoutUnit::Max();
 
   for (const NGPaintFragment* child : Children()) {
+    if (child->PhysicalFragment().IsFloating())
+      continue;
+
     const LayoutUnit child_inline_min =
         ChildLogicalOffsetInParent(*child).inline_offset;
     const LayoutUnit child_inline_max =
diff --git a/third_party/blink/renderer/core/paint/paint_invalidator.cc b/third_party/blink/renderer/core/paint/paint_invalidator.cc
index 43da82b..8731e344 100644
--- a/third_party/blink/renderer/core/paint/paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/paint_invalidator.cc
@@ -14,6 +14,7 @@
 #include "third_party/blink/renderer/core/layout/layout_table_section.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
+#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
 #include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
 #include "third_party/blink/renderer/core/paint/find_paint_offset_and_visual_rect_needing_update.h"
@@ -192,12 +193,20 @@
     context.painting_layer = ToLayoutBoxModelObject(object).Layer();
   } else if (object.IsColumnSpanAll() ||
              object.IsFloatingWithNonContainingBlockParent()) {
-    // See LayoutObject::paintingLayer() for the special-cases of floating under
+    // See |LayoutObject::PaintingLayer| for the special-cases of floating under
     // inline and multicolumn.
+    // Post LayoutNG the |LayoutObject::IsFloatingWithNonContainingBlockParent|
+    // check can be removed as floats will be painted by the correct layer.
     context.painting_layer = object.PaintingLayer();
   }
 
-  if (object.IsLayoutBlockFlow() && ToLayoutBlockFlow(object).ContainsFloats())
+  if (object.IsLayoutBlockFlow() && !object.IsLayoutNGBlockFlow() &&
+      ToLayoutBlockFlow(object).ContainsFloats())
+    context.painting_layer->SetNeedsPaintPhaseFloat();
+
+  if (object.IsFloating() &&
+      (object.IsInLayoutNGInlineFormattingContext() ||
+       IsLayoutNGContainingBlock(object.ContainingBlock())))
     context.painting_layer->SetNeedsPaintPhaseFloat();
 
   // Table collapsed borders are painted in PaintPhaseDescendantBlockBackgrounds
@@ -246,10 +255,12 @@
     // this frame's paintInvalidationContainer.
     context.paint_invalidation_container_for_stacked_contents =
         context.paint_invalidation_container;
-  } else if (object.IsFloatingWithNonContainingBlockParent() ||
-             object.IsColumnSpanAll()) {
+  } else if (object.IsColumnSpanAll() ||
+             object.IsFloatingWithNonContainingBlockParent()) {
     // In these cases, the object may belong to an ancestor of the current
     // paint invalidation container, in paint order.
+    // Post LayoutNG the |LayoutObject::IsFloatingWithNonContainingBlockParent|
+    // check can be removed as floats will be painted by the correct layer.
     context.paint_invalidation_container =
         &object.ContainerForPaintInvalidation();
   } else if (object.StyleRef().IsStacked() &&
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc b/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
index dea2f31..9fcb305 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
@@ -590,7 +590,11 @@
       GetDocument().getElementById("span")->GetLayoutObject());
   PaintLayer& span_layer = *span.Layer();
   ASSERT_TRUE(&span_layer == float_div.EnclosingLayer());
-  ASSERT_FALSE(span_layer.NeedsPaintPhaseFloat());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    ASSERT_TRUE(span_layer.NeedsPaintPhaseFloat());
+  } else {
+    ASSERT_FALSE(span_layer.NeedsPaintPhaseFloat());
+  }
   LayoutBoxModelObject& self_painting_layer_object = *ToLayoutBoxModelObject(
       GetDocument().getElementById("self-painting-layer")->GetLayoutObject());
   PaintLayer& self_painting_layer = *self_painting_layer_object.Layer();
@@ -602,9 +606,14 @@
            ->Layer();
   ASSERT_FALSE(non_self_painting_layer.IsSelfPaintingLayer());
 
-  EXPECT_TRUE(self_painting_layer.NeedsPaintPhaseFloat());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_FALSE(self_painting_layer.NeedsPaintPhaseFloat());
+    EXPECT_TRUE(span_layer.NeedsPaintPhaseFloat());
+  } else {
+    EXPECT_TRUE(self_painting_layer.NeedsPaintPhaseFloat());
+    EXPECT_FALSE(span_layer.NeedsPaintPhaseFloat());
+  }
   EXPECT_FALSE(non_self_painting_layer.NeedsPaintPhaseFloat());
-  EXPECT_FALSE(span_layer.NeedsPaintPhaseFloat());
   EXPECT_TRUE(DisplayItemListContains(
       RootPaintController().GetDisplayItemList(), float_div,
       DisplayItem::kBoxDecorationBackground));
diff --git a/third_party/blink/renderer/core/paint/paint_layer_test.cc b/third_party/blink/renderer/core/paint/paint_layer_test.cc
index 3e6ebbd..cdb169b1 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -882,8 +882,12 @@
   )HTML");
 
   PaintLayer* target = GetPaintLayerByElementId("target");
-  EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
-            target->CompositingContainer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+  } else {
+    EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+              target->CompositingContainer());
+  }
 
   // enclosingLayerWithCompositedLayerMapping is not needed or applicable to
   // CAP.
@@ -907,14 +911,23 @@
   )HTML");
 
   PaintLayer* target = GetPaintLayerByElementId("target");
-  EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
-            target->CompositingContainer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+  } else {
+    EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+              target->CompositingContainer());
+  }
 
   // enclosingLayerWithCompositedLayerMapping is not needed or applicable to
   // CAP.
   if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
-              target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+    if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+      EXPECT_EQ(GetPaintLayerByElementId("span"),
+                target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+    } else {
+      EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
+                target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+    }
   }
 }
 
@@ -987,8 +1000,12 @@
   )HTML");
 
   PaintLayer* target = GetPaintLayerByElementId("target");
-  EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
-            target->CompositingContainer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+  } else {
+    EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+              target->CompositingContainer());
+  }
 
   // enclosingLayerWithCompositedLayerMapping is not needed or applicable to
   // CAP.
@@ -1014,14 +1031,23 @@
   )HTML");
 
   PaintLayer* target = GetPaintLayerByElementId("target");
-  EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
-            target->CompositingContainer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+  } else {
+    EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+              target->CompositingContainer());
+  }
 
   // enclosingLayerWithCompositedLayerMapping is not needed or applicable to
   // CAP.
   if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
-              target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+    if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+      EXPECT_EQ(GetPaintLayerByElementId("span"),
+                target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+    } else {
+      EXPECT_EQ(GetPaintLayerByElementId("compositedContainer"),
+                target->EnclosingLayerWithCompositedLayerMapping(kExcludeSelf));
+    }
   }
 }
 
@@ -1047,20 +1073,35 @@
   PaintLayer* container = GetPaintLayerByElementId("container");
 
   EXPECT_EQ(span, floating->Parent());
-  EXPECT_EQ(container, floating->ContainingLayer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(span, floating->ContainingLayer());
+  } else {
+    EXPECT_EQ(container, floating->ContainingLayer());
+  }
   EXPECT_EQ(span, absolute->Parent());
   EXPECT_EQ(span, absolute->ContainingLayer());
   EXPECT_EQ(container, span->Parent());
   EXPECT_EQ(container, span->ContainingLayer());
 
-  EXPECT_EQ(LayoutPoint(83, 83), floating->Location());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(LayoutPoint(50, 50), floating->Location());
+  } else {
+    EXPECT_EQ(LayoutPoint(83, 83), floating->Location());
+  }
   EXPECT_EQ(LayoutPoint(50, 50), absolute->Location());
   EXPECT_EQ(LayoutPoint(133, 133), span->Location());
   EXPECT_EQ(LayoutPoint(20, 20), container->Location());
 
-  EXPECT_EQ(LayoutPoint(-50, -50), floating->VisualOffsetFromAncestor(span));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(LayoutPoint(50, 50), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(183, 183),
+              floating->VisualOffsetFromAncestor(container));
+  } else {
+    EXPECT_EQ(LayoutPoint(-50, -50), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(83, 83),
+              floating->VisualOffsetFromAncestor(container));
+  }
   EXPECT_EQ(LayoutPoint(50, 50), absolute->VisualOffsetFromAncestor(span));
-  EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(container));
   EXPECT_EQ(LayoutPoint(183, 183),
             absolute->VisualOffsetFromAncestor(container));
 }
@@ -1084,16 +1125,26 @@
                                                   kProgrammaticScroll);
 
   EXPECT_EQ(span, floating->Parent());
-  EXPECT_EQ(container, floating->ContainingLayer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(span, floating->ContainingLayer());
+  } else {
+    EXPECT_EQ(container, floating->ContainingLayer());
+  }
   EXPECT_EQ(container, span->Parent());
   EXPECT_EQ(container, span->ContainingLayer());
 
-  EXPECT_EQ(LayoutPoint(50, -350), floating->Location());
   EXPECT_EQ(LayoutPoint(100, -300), span->Location());
-
-  EXPECT_EQ(LayoutPoint(-50, -50), floating->VisualOffsetFromAncestor(span));
-  EXPECT_EQ(LayoutPoint(50, -350),
-            floating->VisualOffsetFromAncestor(container));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(LayoutPoint(50, 50), floating->Location());
+    EXPECT_EQ(LayoutPoint(50, 50), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(150, -250),
+              floating->VisualOffsetFromAncestor(container));
+  } else {
+    EXPECT_EQ(LayoutPoint(50, -350), floating->Location());
+    EXPECT_EQ(LayoutPoint(-50, -50), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(50, -350),
+              floating->VisualOffsetFromAncestor(container));
+  }
 }
 
 TEST_P(PaintLayerTest, FloatLayerUnderBlockUnderInlineLayer) {
@@ -1137,13 +1188,24 @@
   PaintLayer* span = GetPaintLayerByElementId("span");
 
   EXPECT_EQ(span, floating->Parent());
-  EXPECT_EQ(span->Parent(), floating->ContainingLayer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(span, floating->ContainingLayer());
+  } else {
+    EXPECT_EQ(span->Parent(), floating->ContainingLayer());
+  }
 
   EXPECT_EQ(LayoutPoint(83, 83), floating->Location());
   EXPECT_EQ(LayoutPoint(100, 100), span->Location());
-  EXPECT_EQ(LayoutPoint(-17, -17), floating->VisualOffsetFromAncestor(span));
-  EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(
-                                     GetDocument().GetLayoutView()->Layer()));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(183, 183),
+              floating->VisualOffsetFromAncestor(
+                  GetDocument().GetLayoutView()->Layer()));
+  } else {
+    EXPECT_EQ(LayoutPoint(-17, -17), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(
+                                       GetDocument().GetLayoutView()->Layer()));
+  }
 }
 
 TEST_P(PaintLayerTest, FloatLayerUnderFloatLayerUnderInlineLayer) {
@@ -1166,16 +1228,29 @@
   EXPECT_EQ(floating_parent, floating->Parent());
   EXPECT_EQ(floating_parent, floating->ContainingLayer());
   EXPECT_EQ(span, floating_parent->Parent());
-  EXPECT_EQ(span->Parent(), floating_parent->ContainingLayer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(span, floating_parent->ContainingLayer());
+  } else {
+    EXPECT_EQ(span->Parent(), floating_parent->ContainingLayer());
+  }
 
   EXPECT_EQ(LayoutPoint(50, 50), floating->Location());
   EXPECT_EQ(LayoutPoint(33, 33), floating_parent->Location());
   EXPECT_EQ(LayoutPoint(100, 100), span->Location());
-  EXPECT_EQ(LayoutPoint(-17, -17), floating->VisualOffsetFromAncestor(span));
-  EXPECT_EQ(LayoutPoint(-67, -67),
-            floating_parent->VisualOffsetFromAncestor(span));
-  EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(
-                                     GetDocument().GetLayoutView()->Layer()));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(33, 33),
+              floating_parent->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(183, 183),
+              floating->VisualOffsetFromAncestor(
+                  GetDocument().GetLayoutView()->Layer()));
+  } else {
+    EXPECT_EQ(LayoutPoint(-17, -17), floating->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(-67, -67),
+              floating_parent->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(83, 83), floating->VisualOffsetFromAncestor(
+                                       GetDocument().GetLayoutView()->Layer()));
+  }
 }
 
 TEST_P(PaintLayerTest, LayerUnderFloatUnderInlineLayer) {
@@ -1195,13 +1270,25 @@
   PaintLayer* span = GetPaintLayerByElementId("span");
 
   EXPECT_EQ(span, child->Parent());
-  EXPECT_EQ(span->Parent(), child->ContainingLayer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(span, child->ContainingLayer());
+  } else {
+    EXPECT_EQ(span->Parent(), child->ContainingLayer());
+  }
 
   EXPECT_EQ(LayoutPoint(83, 83), child->Location());
   EXPECT_EQ(LayoutPoint(100, 100), span->Location());
-  EXPECT_EQ(LayoutPoint(-17, -17), child->VisualOffsetFromAncestor(span));
-  EXPECT_EQ(LayoutPoint(83, 83), child->VisualOffsetFromAncestor(
-                                     GetDocument().GetLayoutView()->Layer()));
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(LayoutPoint(83, 83), child->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(183, 183),
+              child->VisualOffsetFromAncestor(
+                  GetDocument().GetLayoutView()->Layer()));
+
+  } else {
+    EXPECT_EQ(LayoutPoint(-17, -17), child->VisualOffsetFromAncestor(span));
+    EXPECT_EQ(LayoutPoint(83, 83), child->VisualOffsetFromAncestor(
+                                       GetDocument().GetLayoutView()->Layer()));
+  }
 }
 
 TEST_P(PaintLayerTest, CompositingContainerFloatingIframe) {
@@ -1223,8 +1310,12 @@
   // A non-positioned iframe still gets a PaintLayer because PaintLayers are
   // forced for all LayoutEmbeddedContent objects. However, such PaintLayers are
   // not stacked.
-  PaintLayer* containing_block = GetPaintLayerByElementId("containingBlock");
-  EXPECT_EQ(containing_block, target->CompositingContainer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(GetPaintLayerByElementId("span"), target->CompositingContainer());
+  } else {
+    EXPECT_EQ(GetPaintLayerByElementId("containingBlock"),
+              target->CompositingContainer());
+  }
   PaintLayer* composited_container =
       GetPaintLayerByElementId("compositedContainer");
 
@@ -1252,7 +1343,11 @@
 
   PaintLayer* container = GetPaintLayerByElementId("container");
   PaintLayer* span = GetPaintLayerByElementId("span");
-  EXPECT_EQ(container, target->ContainingLayer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(span, target->ContainingLayer());
+  } else {
+    EXPECT_EQ(container, target->ContainingLayer());
+  }
   EXPECT_EQ(span, target->CompositingContainer());
 }
 
@@ -1335,7 +1430,11 @@
                                "overflow: hidden; float: left");
   GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
   EXPECT_FALSE(target_layer->IsSelfPaintingLayer());
-  EXPECT_EQ(span_layer->Parent(), target_layer->CompositingContainer());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(span_layer, target_layer->CompositingContainer());
+  } else {
+    EXPECT_EQ(span_layer->Parent(), target_layer->CompositingContainer());
+  }
   EXPECT_TRUE(target_layer->NeedsRepaint());
   EXPECT_TRUE(target_layer->CompositingContainer()->NeedsRepaint());
   EXPECT_TRUE(span_layer->NeedsRepaint());
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 56f0fbf..20709f1 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -2052,7 +2052,7 @@
     return;
   }
 
-  if (object_.IsFloating())
+  if (object_.IsFloating() && !object_.IsInLayoutNGInlineFormattingContext())
     context_.current.paint_offset = context_.paint_offset_for_float;
 
   // Multicolumn spanners are painted starting at the multicolumn container (but
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 04a94c8..c09566bd 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -4923,7 +4923,11 @@
   EXPECT_EQ(0.5f, effect->Opacity());
 
   LayoutObject* target = GetLayoutObjectByElementId("target");
-  EXPECT_EQ(LayoutPoint(66, 55), target->FirstFragment().PaintOffset());
+  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    EXPECT_EQ(LayoutPoint(266, 155), target->FirstFragment().PaintOffset());
+  } else {
+    EXPECT_EQ(LayoutPoint(66, 55), target->FirstFragment().PaintOffset());
+  }
   EXPECT_EQ(effect,
             target->FirstFragment().LocalBorderBoxProperties().Effect());
 }
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index b91df7ab7..de2bfac 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -189,10 +189,6 @@
     "accessibility/testing/internals_accessibility.h",
     "mediastream/testing/internals_media_stream.cc",
     "mediastream/testing/internals_media_stream.h",
-    "navigatorcontentutils/testing/internals_navigator_content_utils.cc",
-    "navigatorcontentutils/testing/internals_navigator_content_utils.h",
-    "navigatorcontentutils/testing/navigator_content_utils_client_mock.cc",
-    "navigatorcontentutils/testing/navigator_content_utils_client_mock.h",
     "peerconnection/adapters/test/mock_ice_transport_adapter.h",
     "peerconnection/adapters/test/mock_ice_transport_adapter_cross_thread_factory.h",
     "peerconnection/adapters/test/mock_p2p_quic_packet_transport.h",
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 6ac635e..e88b2985 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -859,7 +859,6 @@
         [
           "accessibility/testing/internals_accessibility.idl",
           "mediastream/testing/internals_media_stream.idl",
-          "navigatorcontentutils/testing/internals_navigator_content_utils.idl",
           "peerconnection/testing/internals_rtc_certificate.idl",
           "peerconnection/testing/internals_rtc_peer_connection.idl",
           "service_worker/testing/internals_service_worker.idl",
diff --git a/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.cc b/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.cc
deleted file mode 100644
index 7c76008..0000000
--- a/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.cc
+++ /dev/null
@@ -1,26 +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.
-
-#include "third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.h"
-
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/testing/internals.h"
-#include "third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h"
-#include "third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h"
-
-namespace blink {
-
-void InternalsNavigatorContentUtils::setNavigatorContentUtilsClientMock(
-    Internals&,
-    Document* document) {
-  DCHECK(document);
-  DCHECK(document->GetPage());
-  NavigatorContentUtils* navigator_content_utils =
-      NavigatorContentUtils::From(*document->domWindow()->navigator());
-  navigator_content_utils->SetClientForTest(
-      NavigatorContentUtilsClientMock::Create());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.h b/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.h
deleted file mode 100644
index 598fb461..0000000
--- a/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.h
+++ /dev/null
@@ -1,24 +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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_INTERNALS_NAVIGATOR_CONTENT_UTILS_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_INTERNALS_NAVIGATOR_CONTENT_UTILS_H_
-
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-
-namespace blink {
-
-class Document;
-class Internals;
-
-class InternalsNavigatorContentUtils {
-  STATIC_ONLY(InternalsNavigatorContentUtils);
-
- public:
-  static void setNavigatorContentUtilsClientMock(Internals&, Document*);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_INTERNALS_NAVIGATOR_CONTENT_UTILS_H_
diff --git a/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.idl b/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.idl
deleted file mode 100644
index a8430ed..0000000
--- a/third_party/blink/renderer/modules/navigatorcontentutils/testing/internals_navigator_content_utils.idl
+++ /dev/null
@@ -1,9 +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.
-
-[
-    ImplementedAs=InternalsNavigatorContentUtils
-] partial interface Internals {
-    void setNavigatorContentUtilsClientMock(Document document);
-};
diff --git a/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.cc b/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.cc
deleted file mode 100644
index aaa7e14..0000000
--- a/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.cc
+++ /dev/null
@@ -1,30 +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.
-
-#include "third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h"
-
-#include "third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
-
-namespace blink {
-
-void NavigatorContentUtilsClientMock::RegisterProtocolHandler(
-    const String& scheme,
-    const KURL& url,
-    const String& title) {
-  ProtocolInfo info;
-  info.scheme = scheme;
-  info.url = url;
-  info.title = title;
-
-  protocol_map_.Set(scheme, info);
-}
-
-void NavigatorContentUtilsClientMock::UnregisterProtocolHandler(
-    const String& scheme,
-    const KURL& url) {
-  protocol_map_.erase(scheme);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h b/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h
deleted file mode 100644
index bbdb43d..0000000
--- a/third_party/blink/renderer/modules/navigatorcontentutils/testing/navigator_content_utils_client_mock.h
+++ /dev/null
@@ -1,48 +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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_NAVIGATOR_CONTENT_UTILS_CLIENT_MOCK_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_NAVIGATOR_CONTENT_UTILS_CLIENT_MOCK_H_
-
-#include "third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-// Provides a mock object for the navigatorcontentutils client.
-class NavigatorContentUtilsClientMock final
-    : public NavigatorContentUtilsClient {
- public:
-  static NavigatorContentUtilsClientMock* Create() {
-    return MakeGarbageCollected<NavigatorContentUtilsClientMock>();
-  }
-
-  // TODO(sashab): Make NavigatorContentUtilsClientMock non-virtual and test it
-  // using a WebLocalFrameClient mock.
-  NavigatorContentUtilsClientMock() : NavigatorContentUtilsClient(nullptr) {}
-  ~NavigatorContentUtilsClientMock() override = default;
-
-  void RegisterProtocolHandler(const String& scheme,
-                               const KURL&,
-                               const String& title) override;
-
-  void UnregisterProtocolHandler(const String& scheme, const KURL&) override;
-
- private:
-  typedef struct {
-    String scheme;
-    KURL url;
-    String title;
-  } ProtocolInfo;
-
-  typedef HashMap<String, ProtocolInfo> RegisteredProtocolMap;
-  RegisteredProtocolMap protocol_map_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_NAVIGATORCONTENTUTILS_TESTING_NAVIGATOR_CONTENT_UTILS_CLIENT_MOCK_H_
diff --git a/third_party/blink/renderer/modules/payments/can_make_payment_test.cc b/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
index 9663144a..19e383286 100644
--- a/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
+++ b/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
@@ -12,11 +12,166 @@
 namespace blink {
 namespace {
 
+using payments::mojom::blink::CanMakePaymentQueryResult;
 using payments::mojom::blink::HasEnrolledInstrumentQueryResult;
 using payments::mojom::blink::PaymentErrorReason;
 using payments::mojom::blink::PaymentRequestClient;
 
-TEST(CanMakePaymentTest, RejectPromiseOnUserCancel) {
+// HasEnrolledInstrumentTest is parameterized on this enum to test that
+// canMakePayment when PaymentRequestHasEnrolledInstrumentEnabled is false
+// behaves identically to hasEnrolledInstrument.
+enum class HasEnrolledInstrumentEnabled { YES, NO };
+
+class HasEnrolledInstrumentTest
+    : public testing::Test,
+      public testing::WithParamInterface<HasEnrolledInstrumentEnabled> {
+  void SetUp() override {
+    testing::Test::SetUp();
+    RuntimeEnabledFeatures::SetPaymentRequestHasEnrolledInstrumentEnabled(
+        GetParam() == HasEnrolledInstrumentEnabled::YES);
+  }
+};
+
+TEST_P(HasEnrolledInstrumentTest, RejectPromiseOnUserCancel) {
+  V8TestingScope scope;
+  PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+  MakePaymentRequestOriginSecure(scope.GetDocument());
+  PaymentRequest* request = PaymentRequest::Create(
+      scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+      BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+
+  if (GetParam() == HasEnrolledInstrumentEnabled::YES) {
+    request->hasEnrolledInstrument(scope.GetScriptState())
+        .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+  } else {
+    request->canMakePayment(scope.GetScriptState())
+        .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+  }
+
+  static_cast<PaymentRequestClient*>(request)->OnError(
+      PaymentErrorReason::USER_CANCEL);
+}
+
+TEST_P(HasEnrolledInstrumentTest, RejectPromiseOnUnknownError) {
+  V8TestingScope scope;
+  PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+  MakePaymentRequestOriginSecure(scope.GetDocument());
+  PaymentRequest* request = PaymentRequest::Create(
+      scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+      BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+
+  if (GetParam() == HasEnrolledInstrumentEnabled::YES) {
+    request->hasEnrolledInstrument(scope.GetScriptState())
+        .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+  } else {
+    request->canMakePayment(scope.GetScriptState())
+        .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+  }
+
+  static_cast<PaymentRequestClient*>(request)->OnError(
+      PaymentErrorReason::UNKNOWN);
+}
+
+TEST_P(HasEnrolledInstrumentTest, RejectDuplicateRequest) {
+  V8TestingScope scope;
+  PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+  MakePaymentRequestOriginSecure(scope.GetDocument());
+  PaymentRequest* request = PaymentRequest::Create(
+      scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+      BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+  if (GetParam() == HasEnrolledInstrumentEnabled::YES) {
+    request->hasEnrolledInstrument(scope.GetScriptState());
+    request->hasEnrolledInstrument(scope.GetScriptState())
+        .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+  } else {
+    request->canMakePayment(scope.GetScriptState());
+    request->canMakePayment(scope.GetScriptState())
+        .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+  }
+}
+
+TEST_P(HasEnrolledInstrumentTest, RejectQueryQuotaExceeded) {
+  RuntimeEnabledFeatures::SetPaymentRequestHasEnrolledInstrumentEnabled(false);
+  V8TestingScope scope;
+  PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+  MakePaymentRequestOriginSecure(scope.GetDocument());
+  PaymentRequest* request = PaymentRequest::Create(
+      scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+      BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+
+  if (GetParam() == HasEnrolledInstrumentEnabled::YES) {
+    request->hasEnrolledInstrument(scope.GetScriptState())
+        .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+  } else {
+    request->canMakePayment(scope.GetScriptState())
+        .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
+  }
+
+  static_cast<PaymentRequestClient*>(request)->OnHasEnrolledInstrument(
+      HasEnrolledInstrumentQueryResult::QUERY_QUOTA_EXCEEDED);
+}
+
+TEST_P(HasEnrolledInstrumentTest, ReturnHasNoEnrolledInstrument) {
+  V8TestingScope scope;
+  PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+  MakePaymentRequestOriginSecure(scope.GetDocument());
+  PaymentRequest* request = PaymentRequest::Create(
+      scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+      BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+  String captor;
+  if (GetParam() == HasEnrolledInstrumentEnabled::YES) {
+    request->hasEnrolledInstrument(scope.GetScriptState())
+        .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
+  } else {
+    request->canMakePayment(scope.GetScriptState())
+        .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
+  }
+
+  static_cast<PaymentRequestClient*>(request)->OnHasEnrolledInstrument(
+      HasEnrolledInstrumentQueryResult::HAS_NO_ENROLLED_INSTRUMENT);
+
+  v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
+  EXPECT_EQ("false", captor);
+}
+
+TEST_P(HasEnrolledInstrumentTest, ReturnHasEnrolledInstrument) {
+  V8TestingScope scope;
+  PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
+  MakePaymentRequestOriginSecure(scope.GetDocument());
+  PaymentRequest* request = PaymentRequest::Create(
+      scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
+      BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
+  String captor;
+  if (GetParam() == HasEnrolledInstrumentEnabled::YES) {
+    request->hasEnrolledInstrument(scope.GetScriptState())
+        .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
+  } else {
+    request->canMakePayment(scope.GetScriptState())
+        .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
+  }
+
+  static_cast<PaymentRequestClient*>(request)->OnHasEnrolledInstrument(
+      HasEnrolledInstrumentQueryResult::HAS_ENROLLED_INSTRUMENT);
+
+  v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
+  EXPECT_EQ("true", captor);
+}
+
+INSTANTIATE_TEST_CASE_P(ProgrammaticHasEnrolledInstrumentTest,
+                        HasEnrolledInstrumentTest,
+                        ::testing::Values(HasEnrolledInstrumentEnabled::YES,
+                                          HasEnrolledInstrumentEnabled::NO));
+
+// Test fixture for canMakePayment when
+// PaymentRequestHasEnrolledInstrumentEnabled is true.
+class CanMakePaymentTest : public testing::Test {
+  void SetUp() override {
+    testing::Test::SetUp();
+    RuntimeEnabledFeatures::SetPaymentRequestHasEnrolledInstrumentEnabled(true);
+  }
+};
+
+TEST_F(CanMakePaymentTest, RejectPromiseOnUserCancel) {
   V8TestingScope scope;
   PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
   MakePaymentRequestOriginSecure(scope.GetDocument());
@@ -31,7 +186,7 @@
       PaymentErrorReason::USER_CANCEL);
 }
 
-TEST(CanMakePaymentTest, RejectPromiseOnUnknownError) {
+TEST_F(CanMakePaymentTest, RejectPromiseOnUnknownError) {
   V8TestingScope scope;
   PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
   MakePaymentRequestOriginSecure(scope.GetDocument());
@@ -46,7 +201,7 @@
       PaymentErrorReason::UNKNOWN);
 }
 
-TEST(CanMakePaymentTest, RejectDuplicateRequest) {
+TEST_F(CanMakePaymentTest, RejectDuplicateRequest) {
   V8TestingScope scope;
   PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
   MakePaymentRequestOriginSecure(scope.GetDocument());
@@ -59,22 +214,7 @@
       .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
 }
 
-TEST(CanMakePaymentTest, RejectQueryQuotaExceeded) {
-  V8TestingScope scope;
-  PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
-  MakePaymentRequestOriginSecure(scope.GetDocument());
-  PaymentRequest* request = PaymentRequest::Create(
-      scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
-      BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
-
-  request->canMakePayment(scope.GetScriptState())
-      .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
-
-  static_cast<PaymentRequestClient*>(request)->OnHasEnrolledInstrument(
-      HasEnrolledInstrumentQueryResult::QUERY_QUOTA_EXCEEDED);
-}
-
-TEST(CanMakePaymentTest, ReturnCannotMakeCanMakePayment) {
+TEST_F(CanMakePaymentTest, ReturnCannotMakePayment) {
   V8TestingScope scope;
   PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
   MakePaymentRequestOriginSecure(scope.GetDocument());
@@ -85,14 +225,14 @@
   request->canMakePayment(scope.GetScriptState())
       .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
 
-  static_cast<PaymentRequestClient*>(request)->OnHasEnrolledInstrument(
-      HasEnrolledInstrumentQueryResult::HAS_NO_ENROLLED_INSTRUMENT);
+  static_cast<PaymentRequestClient*>(request)->OnCanMakePayment(
+      CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT);
 
   v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
   EXPECT_EQ("false", captor);
 }
 
-TEST(CanMakePaymentTest, ReturnCanMakePayment) {
+TEST_F(CanMakePaymentTest, ReturnCanMakePayment) {
   V8TestingScope scope;
   PaymentRequestMockFunctionScope funcs(scope.GetScriptState());
   MakePaymentRequestOriginSecure(scope.GetDocument());
@@ -103,8 +243,8 @@
   request->canMakePayment(scope.GetScriptState())
       .Then(funcs.ExpectCall(&captor), funcs.ExpectNoCall());
 
-  static_cast<PaymentRequestClient*>(request)->OnHasEnrolledInstrument(
-      HasEnrolledInstrumentQueryResult::HAS_ENROLLED_INSTRUMENT);
+  static_cast<PaymentRequestClient*>(request)->OnCanMakePayment(
+      CanMakePaymentQueryResult::CAN_MAKE_PAYMENT);
 
   v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
   EXPECT_EQ("true", captor);
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 0e962ce6..14256df 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -863,6 +863,12 @@
 }
 
 ScriptPromise PaymentRequest::canMakePayment(ScriptState* script_state) {
+  if (!RuntimeEnabledFeatures::PaymentRequestHasEnrolledInstrumentEnabled()) {
+    // Fallback to backward-compatible definition of canMakePayment, which is
+    // now implemented as hasEnrolledInstrument.
+    return hasEnrolledInstrument(script_state);
+  }
+
   if (!payment_provider_.is_bound() || GetPendingAcceptPromiseResolver() ||
       can_make_payment_resolver_ || !script_state->ContextIsValid()) {
     return ScriptPromise::RejectWithDOMException(
@@ -870,12 +876,27 @@
                                            "Cannot query payment request"));
   }
 
-  payment_provider_->HasEnrolledInstrument();
+  payment_provider_->CanMakePayment();
 
   can_make_payment_resolver_ = ScriptPromiseResolver::Create(script_state);
   return can_make_payment_resolver_->Promise();
 }
 
+ScriptPromise PaymentRequest::hasEnrolledInstrument(ScriptState* script_state) {
+  if (!payment_provider_.is_bound() || GetPendingAcceptPromiseResolver() ||
+      has_enrolled_instrument_resolver_ || !script_state->ContextIsValid()) {
+    return ScriptPromise::RejectWithDOMException(
+        script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
+                                           "Cannot query payment request"));
+  }
+
+  payment_provider_->HasEnrolledInstrument();
+
+  has_enrolled_instrument_resolver_ =
+      ScriptPromiseResolver::Create(script_state);
+  return has_enrolled_instrument_resolver_->Promise();
+}
+
 bool PaymentRequest::HasPendingActivity() const {
   return GetPendingAcceptPromiseResolver() || complete_resolver_;
 }
@@ -1096,6 +1117,7 @@
   visitor->Trace(complete_resolver_);
   visitor->Trace(abort_resolver_);
   visitor->Trace(can_make_payment_resolver_);
+  visitor->Trace(has_enrolled_instrument_resolver_);
   EventTargetWithInlineData::Trace(visitor);
   ContextLifecycleObserver::Trace(visitor);
 }
@@ -1381,6 +1403,11 @@
         DOMException::Create(exception_code, message));
   }
 
+  if (has_enrolled_instrument_resolver_) {
+    has_enrolled_instrument_resolver_->Reject(
+        DOMException::Create(exception_code, message));
+  }
+
   ClearResolversAndCloseMojoConnection();
 }
 
@@ -1409,15 +1436,26 @@
 }
 
 void PaymentRequest::OnCanMakePayment(CanMakePaymentQueryResult result) {
-  // TODO(https://crbug.com/915907): implement new CanMakePayment behavior.
-  NOTREACHED();
+  if (!can_make_payment_resolver_)
+    return;
+
+  switch (result) {
+    case CanMakePaymentQueryResult::CAN_MAKE_PAYMENT:
+      can_make_payment_resolver_->Resolve(true);
+      break;
+    case CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT:
+      can_make_payment_resolver_->Resolve(false);
+      break;
+  }
+
+  can_make_payment_resolver_.Clear();
 }
 
 void PaymentRequest::OnHasEnrolledInstrument(
     HasEnrolledInstrumentQueryResult result) {
   // TODO(https://crbug.com/891371): Understand how the resolver could be null
   // here and prevent it.
-  if (!can_make_payment_resolver_)
+  if (!has_enrolled_instrument_resolver_)
     return;
 
   switch (result) {
@@ -1425,22 +1463,22 @@
       WarnIgnoringQueryQuotaForCanMakePayment(*GetExecutionContext());
       FALLTHROUGH;
     case HasEnrolledInstrumentQueryResult::HAS_ENROLLED_INSTRUMENT:
-      can_make_payment_resolver_->Resolve(true);
+      has_enrolled_instrument_resolver_->Resolve(true);
       break;
     case HasEnrolledInstrumentQueryResult::WARNING_HAS_NO_ENROLLED_INSTRUMENT:
       WarnIgnoringQueryQuotaForCanMakePayment(*GetExecutionContext());
       FALLTHROUGH;
     case HasEnrolledInstrumentQueryResult::HAS_NO_ENROLLED_INSTRUMENT:
-      can_make_payment_resolver_->Resolve(false);
+      has_enrolled_instrument_resolver_->Resolve(false);
       break;
     case HasEnrolledInstrumentQueryResult::QUERY_QUOTA_EXCEEDED:
-      can_make_payment_resolver_->Reject(DOMException::Create(
+      has_enrolled_instrument_resolver_->Reject(DOMException::Create(
           DOMExceptionCode::kNotAllowedError,
           "Not allowed to check whether can make payment"));
       break;
   }
 
-  can_make_payment_resolver_.Clear();
+  has_enrolled_instrument_resolver_.Clear();
 }
 
 void PaymentRequest::WarnNoFavicon() {
@@ -1465,6 +1503,7 @@
   retry_resolver_.Clear();
   abort_resolver_.Clear();
   can_make_payment_resolver_.Clear();
+  has_enrolled_instrument_resolver_.Clear();
   if (client_binding_.is_bound())
     client_binding_.Close();
   payment_provider_.reset();
diff --git a/third_party/blink/renderer/modules/payments/payment_request.h b/third_party/blink/renderer/modules/payments/payment_request.h
index afa9049..089fd8b1 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.h
+++ b/third_party/blink/renderer/modules/payments/payment_request.h
@@ -80,6 +80,7 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(paymentmethodchange, kPaymentmethodchange);
 
   ScriptPromise canMakePayment(ScriptState*);
+  ScriptPromise hasEnrolledInstrument(ScriptState*);
 
   // ScriptWrappable:
   bool HasPendingActivity() const override;
@@ -152,6 +153,7 @@
   Member<ScriptPromiseResolver> retry_resolver_;
   Member<ScriptPromiseResolver> abort_resolver_;
   Member<ScriptPromiseResolver> can_make_payment_resolver_;
+  Member<ScriptPromiseResolver> has_enrolled_instrument_resolver_;
   payments::mojom::blink::PaymentRequestPtr payment_provider_;
   mojo::Binding<payments::mojom::blink::PaymentRequestClient> client_binding_;
   TaskRunnerTimer<PaymentRequest> complete_timer_;
diff --git a/third_party/blink/renderer/modules/payments/payment_request.idl b/third_party/blink/renderer/modules/payments/payment_request.idl
index 2cfcb5e..db1d392 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.idl
+++ b/third_party/blink/renderer/modules/payments/payment_request.idl
@@ -17,6 +17,7 @@
     [CallWith=ScriptState, NewObject] Promise<PaymentResponse> show();
     [CallWith=ScriptState, NewObject] Promise<void> abort();
     [CallWith=ScriptState, HighEntropy, Measure, NewObject] Promise<boolean> canMakePayment();
+    [CallWith=ScriptState, NewObject, RuntimeEnabled=PaymentRequestHasEnrolledInstrument] Promise<boolean> hasEnrolledInstrument();
 
     readonly attribute DOMString id;
     [ImplementedAs=getShippingAddress] readonly attribute PaymentAddress? shippingAddress;
diff --git a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
index 20b1740..473f8b1 100644
--- a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
+++ b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
@@ -161,17 +161,11 @@
   }
 
   IncrementPendingPromiseCount();
-
-  // Call Then() separately for fulfilled and rejected cases. This ensures
-  // throwing an exception in |on_promise_fulfilled| doesn't invoke
-  // |on_promise_rejected|.
   script_promise.Then(
       ThenFunction::CreateFunction(script_state, this, ThenFunction::kFulfilled,
                                    std::move(on_promise_fulfilled)),
-      {});
-  script_promise.Then({}, ThenFunction::CreateFunction(
-                              script_state, this, ThenFunction::kRejected,
-                              std::move(on_promise_rejected)));
+      ThenFunction::CreateFunction(script_state, this, ThenFunction::kRejected,
+                                   std::move(on_promise_rejected)));
 }
 
 bool WaitUntilObserver::IsEventActive(ScriptState* script_state) const {
diff --git a/third_party/blink/renderer/platform/exported/web_service_worker_request.cc b/third_party/blink/renderer/platform/exported/web_service_worker_request.cc
index 1a4b4ae..c1f8a8b 100644
--- a/third_party/blink/renderer/platform/exported/web_service_worker_request.cc
+++ b/third_party/blink/renderer/platform/exported/web_service_worker_request.cc
@@ -9,7 +9,6 @@
 #include "third_party/blink/public/platform/web_http_header_visitor.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url_request.h"
-#include "third_party/blink/renderer/platform/blob/blob_data.h"
 #include "third_party/blink/renderer/platform/network/encoded_form_data.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
@@ -23,7 +22,6 @@
   WebString method_;
   HTTPHeaderMap headers_;
   scoped_refptr<EncodedFormData> http_body;
-  scoped_refptr<BlobDataHandle> blob_data_handle;
   Referrer referrer_;
   network::mojom::FetchRequestMode mode_ =
       network::mojom::FetchRequestMode::kNoCors;
@@ -122,31 +120,6 @@
   return private_->http_body;
 }
 
-void WebServiceWorkerRequest::SetBlob(const WebString& uuid,
-                                      long long size,
-                                      mojo::ScopedMessagePipeHandle blob_pipe) {
-  SetBlob(uuid, size,
-          mojom::blink::BlobPtrInfo(std::move(blob_pipe),
-                                    mojom::blink::Blob::Version_));
-}
-
-void WebServiceWorkerRequest::SetBlob(const WebString& uuid,
-                                      long long size,
-                                      mojom::blink::BlobPtrInfo blob_info) {
-  private_->blob_data_handle =
-      BlobDataHandle::Create(uuid, String(), size, std::move(blob_info));
-}
-
-void WebServiceWorkerRequest::SetBlobDataHandle(
-    scoped_refptr<BlobDataHandle> blob_data_handle) {
-  private_->blob_data_handle = std::move(blob_data_handle);
-}
-
-scoped_refptr<BlobDataHandle> WebServiceWorkerRequest::GetBlobDataHandle()
-    const {
-  return private_->blob_data_handle;
-}
-
 void WebServiceWorkerRequest::SetReferrer(
     const WebString& web_referrer,
     network::mojom::ReferrerPolicy referrer_policy) {
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index b7cde05..676eb95 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -28,6 +28,7 @@
 
 #include <memory>
 
+#include "base/optional.h"
 #include "build/build_config.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
@@ -58,6 +59,34 @@
 
 namespace blink {
 
+class GraphicsContext::HighContrastFlags final {
+  STACK_ALLOCATED();
+
+ public:
+  // This helper's lifetime should never exceed |flags|'.
+  HighContrastFlags(const GraphicsContext* gc, const PaintFlags& flags) {
+    if (!gc->high_contrast_filter_) {
+      flags_ = &flags;
+    } else {
+      high_contrast_flags_ = flags;
+      if (flags.HasShader()) {
+        high_contrast_flags_->setColorFilter(gc->high_contrast_filter_);
+      } else {
+        high_contrast_flags_->setColor(
+            gc->high_contrast_filter_->filterColor(flags.getColor()));
+      }
+
+      flags_ = &high_contrast_flags_.value();
+    }
+  }
+
+  operator const PaintFlags&() const { return *flags_; }
+
+ private:
+  const PaintFlags* flags_;
+  base::Optional<PaintFlags> high_contrast_flags_;
+};
+
 GraphicsContext::GraphicsContext(PaintController& paint_controller,
                                  DisabledMode disable_context_or_painting,
                                  SkMetaData* meta_data)
@@ -637,7 +666,7 @@
   // probably worth the speed up of no square root, which also won't be exact.
   FloatSize disp = p2 - p1;
   int length = SkScalarRoundToInt(disp.Width() + disp.Height());
-  PaintFlags flags(ImmutableState()->StrokeFlags(length));
+  const HighContrastFlags flags(this, ImmutableState()->StrokeFlags(length));
 
   if (pen_style == kDottedStroke) {
     if (StrokeData::StrokeIsDashed(width, pen_style)) {
@@ -664,8 +693,7 @@
   }
 
   AdjustLineToPixelBoundaries(p1, p2, width);
-  canvas_->drawLine(p1.X(), p1.Y(), p2.X(), p2.Y(),
-                    ApplyHighContrastFilter(flags));
+  canvas_->drawLine(p1.X(), p1.Y(), p2.X(), p2.Y(), flags);
 }
 
 void GraphicsContext::DrawLineForText(const FloatPoint& pt, float width) {
@@ -743,7 +771,7 @@
     return;
 
   font.DrawText(canvas_, text_info, point, device_scale_factor_,
-                ApplyHighContrastFilter(flags));
+                HighContrastFlags(this, flags));
 }
 
 void GraphicsContext::DrawText(const Font& font,
@@ -788,7 +816,7 @@
 
   DrawTextPasses([&font, &text_info, &point, this](const PaintFlags& flags) {
     font.DrawText(canvas_, text_info, point, device_scale_factor_,
-                  ApplyHighContrastFilter(flags));
+                  HighContrastFlags(this, flags));
   });
 }
 
@@ -816,7 +844,7 @@
       [&font, &text_info, &mark, &point, this](const PaintFlags& flags) {
         font.DrawEmphasisMarks(canvas_, text_info, mark, point,
                                device_scale_factor_,
-                               ApplyHighContrastFilter(flags));
+                               HighContrastFlags(this, flags));
       });
 }
 
@@ -847,7 +875,7 @@
                   this](const PaintFlags& flags) {
     if (font.DrawBidiText(canvas_, run_info, point,
                           custom_font_not_ready_action, device_scale_factor_,
-                          ApplyHighContrastFilter(flags)))
+                          HighContrastFlags(this, flags)))
       paint_controller_.SetTextPainted();
   });
 }
@@ -1011,7 +1039,7 @@
     return;
   DCHECK(canvas_);
 
-  canvas_->drawOval(oval, ApplyHighContrastFilter(flags));
+  canvas_->drawOval(oval, HighContrastFlags(this, flags));
 }
 
 void GraphicsContext::DrawPath(const SkPath& path, const PaintFlags& flags) {
@@ -1019,7 +1047,7 @@
     return;
   DCHECK(canvas_);
 
-  canvas_->drawPath(path, ApplyHighContrastFilter(flags));
+  canvas_->drawPath(path, HighContrastFlags(this, flags));
 }
 
 void GraphicsContext::DrawRect(const SkRect& rect, const PaintFlags& flags) {
@@ -1027,7 +1055,7 @@
     return;
   DCHECK(canvas_);
 
-  canvas_->drawRect(rect, ApplyHighContrastFilter(flags));
+  canvas_->drawRect(rect, HighContrastFlags(this, flags));
 }
 
 void GraphicsContext::DrawRRect(const SkRRect& rrect, const PaintFlags& flags) {
@@ -1035,7 +1063,7 @@
     return;
   DCHECK(canvas_);
 
-  canvas_->drawRRect(rrect, ApplyHighContrastFilter(flags));
+  canvas_->drawRRect(rrect, HighContrastFlags(this, flags));
 }
 
 void GraphicsContext::FillPath(const Path& path_to_fill) {
@@ -1426,17 +1454,4 @@
   return Color(high_contrast_filter_->filterColor(input.Rgb()));
 }
 
-PaintFlags GraphicsContext::ApplyHighContrastFilter(
-    const PaintFlags& input) const {
-  PaintFlags output(input);
-  if (!high_contrast_filter_)
-    return output;
-  if (output.HasShader()) {
-    output.setColorFilter(high_contrast_filter_);
-  } else {
-    output.setColor(high_contrast_filter_->filterColor(output.getColor()));
-  }
-  return output;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h
index 617d1b0..f46176a4 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -88,7 +88,7 @@
 
   bool ContextDisabled() const { return disabled_state_; }
 
-  const HighContrastSettings& high_contrast_settings() {
+  const HighContrastSettings& high_contrast_settings() const {
     return high_contrast_settings_;
   }
 
@@ -466,9 +466,9 @@
 
   const SkMetaData& MetaData() const { return meta_data_; }
 
+  class HighContrastFlags;
   bool ShouldApplyHighContrastFilterToImage(Image&);
   Color ApplyHighContrastFilter(const Color& input) const;
-  PaintFlags ApplyHighContrastFilter(const PaintFlags& input) const;
 
   // null indicates painting is contextDisabled. Never delete this object.
   cc::PaintCanvas* canvas_;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 2448fe2..880f5e4 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -989,6 +989,9 @@
       status: "experimental",
     },
     {
+      name: "PaymentRequestHasEnrolledInstrument",
+    },
+    {
       name: "PaymentRetry",
       status: "experimental",
     },
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-features=NetworkService b/third_party/blink/web_tests/FlagExpectations/enable-features=NetworkService
index 49790d1..f2cd391 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/blink/web_tests/FlagExpectations/enable-features=NetworkService
@@ -12,6 +12,7 @@
 crbug.com/896924 http/tests/inspector-protocol/network/interception-multiclient.js [ Pass ]
 crbug.com/899303 http/tests/inspector-protocol/fetch/fetch-basic.js [ Pass ]
 crbug.com/899303 http/tests/inspector-protocol/fetch/fetch-renderer.js [ Pass ]
+crbug.com/917284 external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html [ Pass ]
 
 # This passes in content_shell but not in chrome with network service disabled,
 # because content_shell does not add the about: handler. With network service
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 749d13b..7db6a9f6 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -283,8 +283,6 @@
 crbug.com/774873 [ Linux ] virtual/exotic-color-space/images/color-profile-border-fade.html [ Pass Failure ]
 crbug.com/774873 [ Win ] virtual/exotic-color-space/images/color-profile-border-fade.html [ Pass Failure ]
 
-crbug.com/915417 http/tests/webmidi/midi-default-feature-policy.https.sub.html [ Pass Timeout Failure ]
-
 # Flakily timing out or failing.
 # TODO(ccameron): Investigate this.
 crbug.com/730267 virtual/gpu-rasterization/images/color-profile-group.html [ Pass Timeout Failure ]
@@ -669,6 +667,7 @@
 crbug.com/591099 external/wpt/css/cssom-view/elementsFromPoint-inline-vrl-rtl.html [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/offsetTopLeftInline.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/inline-box-border-vlr-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/filter-effects/filtered-inline-applies-to-float.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug14159-1.html [ Failure ]
 
 ### virtual/layout_ng/external/wpt/css/CSS2/abspos
@@ -1017,6 +1016,7 @@
 crbug.com/714962 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-width-large-001.xht [ Failure ]
 crbug.com/714962 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-width-large-002.xht [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-width-small-001.xht [ Failure ]
+crbug.com/829028 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-zero-height-001.xht [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/abspos-after-break-after.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/abspos-new-width-rebalance.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/balance-float-after-forced-break.html [ Failure ]
@@ -1100,6 +1100,7 @@
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/remove-spanner-in-content.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/spanner-after-content-becomes-regular-block.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/spanner-ancestor-becomes-spanner.html [ Failure ]
+crbug.com/829028 virtual/layout_ng_experimental/fast/multicol/dynamic/spanner-becomes-float.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/spanner-before-content-becomes-regular-block.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/spanner-in-content-becomes-regular-block.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/dynamic/static-becomes-relpos-has-abspos.html [ Failure ]
@@ -1401,6 +1402,7 @@
 crbug.com/591099 virtual/layout_ng_experimental/fragmentation/float-margin-top.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fragmentation/float-pushed-to-next-fragmentainer-by-floats.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fragmentation/forced-break-clearance-unsplittable-content.html [ Failure ]
+crbug.com/829028 virtual/layout_ng_experimental/fragmentation/forced-break-inside-float.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fragmentation/fragmented-rowspan-alignment.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fragmentation/fragmented-rowspan.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fragmentation/fragmented-table-cell.html [ Failure ]
@@ -5278,8 +5280,7 @@
 crbug.com/831685 [ Linux ] external/wpt/2dcontext/compositing/2d.composite.canvas.lighter.html [ Pass Timeout ]
 crbug.com/831673 http/tests/devtools/reveal-objects.js [ Pass Timeout ]
 crbug.com/831496 virtual/gpu/fast/canvas/fillrect_gradient.html [ Pass Timeout ]
-# TODO (michaelludwig): Restore after skia roll, crbug.com/917379
-#crbug.com/831482 [ Linux ] virtual/gpu-rasterization/images/cross-fade-background-size.html [ Pass Timeout ]
+crbug.com/831482 [ Linux ] virtual/gpu-rasterization/images/cross-fade-background-size.html [ Pass Timeout ]
 crbug.com/831249 [ Linux ] virtual/gpu/fast/canvas/canvas-filter-svg-inline.html [ Pass Timeout ]
 crbug.com/829952 fast/webgl/texImage-imageBitmap-from-image-resize.html [ Pass Timeout ]
 crbug.com/829938 [ Linux ] css3/filters/blur-filter-page-scroll.html [ Pass Timeout ]
@@ -5948,21 +5949,6 @@
 crbug.com/v8/8381 http/tests/devtools/coverage/multiple-instances-merge.js [ Pass Failure ]
 crbug.com/v8/8381 http/tests/devtools/coverage/coverage-export.js [ Pass Failure ]
 
-# TODO (michaelludwig): Todo after Skia roll and rebaseline
-crbug.com/917379 media/video-layer-crash.html [ Pass Failure ]
-crbug.com/917379 virtual/gpu-rasterization/images/color-profile-background-image-cover.html [ Pass Failure ]
-crbug.com/917379 virtual/gpu-rasterization/images/color-profile-background-image-space.html [ Pass Failure ]
-crbug.com/917379 virtual/gpu-rasterization/images/cross-fade-background-size.html [ Pass Failure ]
-crbug.com/917379 virtual/gpu-rasterization/images/feature-policy-oversized-images-styles.html [ Pass Failure ]
-crbug.com/917379 virtual/gpu-rasterization/images/image-map-anchor-children.html [ Pass Failure ]
-crbug.com/917379 virtual/gpu-rasterization/images/sprite-no-bleed.html [ Pass Failure ]
-crbug.com/917379 virtual/gpu/fast/canvas/canvas-drawImage-antiAlias.html [ Pass Failure ]
-crbug.com/917379 virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns.html [ Pass Failure ]
-crbug.com/917379 [ Android ] virtual/gpu/fast/canvas/image-object-in-canvas.html [ Pass Failure ]
-crbug.com/917379 [ Linux ] virtual/gpu/fast/canvas/image-object-in-canvas.html [ Pass Failure ]
-crbug.com/917379 [ Mac ] virtual/gpu/fast/canvas/image-object-in-canvas.html [ Pass Failure ]
-crbug.com/917379 virtual/video-surface-layer/media/video-layer-crash.html [ Pass Failure ]
-
 # ssauleau 2018-12-20
 crbug.com/v8/8319 external/wpt/wasm/jsapi/global/constructor.any.html [ Pass Failure ]
 crbug.com/v8/8319 external/wpt/wasm/jsapi/global/constructor.any.worker.html [ Pass Failure ]
@@ -5974,3 +5960,12 @@
 crbug.com/v8/8319 external/wpt/wasm/jsapi/table/get-set.any.worker.html [ Pass Failure ]
 crbug.com/v8/8319 external/wpt/wasm/jsapi/table/grow.any.html [ Pass Failure ]
 crbug.com/v8/8319 external/wpt/wasm/jsapi/table/grow.any.worker.html [ Pass Failure ]
+
+# Failing when NetworkService is not enabled.
+crbug.com/917284 external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html [ Failure ]
+crbug.com/917284 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html [ Failure ]
+crbug.com/917284 virtual/outofblink-cors/external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html [ Failure ]
+
+# Sheriff 2018-12-27
+crbug.com/917944 [ Mac10.10 Mac10.11 ] paint/invalidation/forms/textarea-caret.html [ Failure ]
+crbug.com/917970 [ Mac10.13 ] virtual/mouseevent_fractional/fast/events/popup-blocking-timers5.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/abspos-float-with-inline-container-ref.html b/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/abspos-float-with-inline-container-ref.html
new file mode 100644
index 0000000..3bf67ed4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/abspos-float-with-inline-container-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<style>
+div {
+  width: 100px;
+  height: 100px;
+  background: green;
+}
+</style>
+<p>Test passes if there is green square.</p>
+<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/abspos-float-with-inline-container.html b/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/abspos-float-with-inline-container.html
new file mode 100644
index 0000000..9918bcc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/abspos-float-with-inline-container.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html" />
+<link rel="match" href="abspos-float-with-inline-container-ref.html" />
+<meta name="assert" content="A inline-level element can contain a absolute-positioned child within a float." />
+<style>
+#abs {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 100px;
+  background: green;
+}
+#float { float: left; }
+span {
+  position: relative;
+  padding-left: 100px;
+}
+</style>
+<p>Test passes if there is green square.</p>
+<div>
+  <span>
+    <div id="float">
+      <div id="abs"></div>
+    </div>
+  </span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/filtered-inline-applies-to-float-ref.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/filtered-inline-applies-to-float-ref.html
new file mode 100644
index 0000000..439d7c4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/filtered-inline-applies-to-float-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<style>
+#float {
+    float: left;
+    width: 100px;
+    height: 100px;
+    background: green;
+    filter: blur(2px);
+}
+</style>
+<p>There should be a blurred green square.</p>
+<div id="float"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/filtered-inline-applies-to-float.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/filtered-inline-applies-to-float.html
new file mode 100644
index 0000000..2d368de
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/filtered-inline-applies-to-float.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty" />
+<link rel="match" href="filtered-inline-applies-to-float-ref.html" />
+<meta name="assert" content="A filter on an inline element applies to floats." />
+<style>
+span { filter: blur(2px); }
+#float {
+    float: left;
+    width: 100px;
+    height: 100px;
+    background: green;
+}
+</style>
+<p>There should be a blurred green square.</p>
+<div>
+  <span><div id="float"></div></span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/appcache-ordering-main.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/appcache-ordering-main.https.html
index 921dae01..a86671c1 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/appcache-ordering-main.https.html
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/appcache-ordering-main.https.html
@@ -5,7 +5,6 @@
 <body>
 <script>
 
-var INSTALL_APPCACHE_URL = "resources/appcache-ordering.install.html";
 var IS_APPCACHED_URL = "resources/appcache-ordering.is-appcached.html";
 var SERVICE_WORKER_SCOPE = "resources/appcache-ordering";
 var SERVICE_WORKER_SCRIPT = "resources/empty-worker.js";
@@ -15,31 +14,6 @@
 
 var frames = [];
 
-// Called by the INSTALL_APPCACHE_URL child frame.
-function notify_appcache_installed(success) {
-  if (success)
-    resolve_install_appcache();
-  else
-    reject_install_appcache();
-}
-
-function install_appcache() {
-  return new Promise(function(resolve, reject) {
-      var frame = document.createElement('iframe');
-      frames.push(frame);
-      frame.src = INSTALL_APPCACHE_URL;
-      document.body.appendChild(frame);
-      resolve_install_appcache = function() {
-          document.body.removeChild(frame);
-          resolve();
-        };
-      reject_install_appcache = function() {
-          document.body.removeChild(frame);
-          reject();
-        };
-  });
-}
-
 var resolve_is_appcached = undefined;
 
 // Called by the IS_APPCACHED_URL child frame.
@@ -63,7 +37,7 @@
 promise_test(function(t) {
     return service_worker_unregister(t, SERVICE_WORKER_SCOPE)
       .then(function() {
-          return install_appcache();
+          return install_appcache_ordering_manifest();
         })
       .then(function() {
           return is_appcached();
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html
new file mode 100644
index 0000000..4890a84b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html
@@ -0,0 +1,81 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<body>
+<script>
+
+// This test makes a frame controlled by AppCache, then registers a service
+// worker that calls claim() to control the frame. AppCache should be completely
+// bypassed once the service worker claims the frame.
+
+const fetch_text = async frame => {
+  const response = await
+    frame.contentWindow.fetch('appcache-ordering.is-appcached.js');
+  return await response.text();
+};
+
+const check_is_appcached = async frame => {
+  // This should FALLBACK to ordering.is_appcached.js as in the manifest
+  // if the appcache is effective.
+  const response = await
+    frame.contentWindow.fetch('appcache-ordering.is-appcached404.js');
+  return await response.ok;
+};
+
+promise_test(async t => {
+  const scope = 'resources/';
+  const script = 'resources/claim-worker.js';
+
+  await install_appcache_ordering_manifest();
+
+  // Create the test iframe.
+  const frame = await with_iframe('resources/blank.html');
+  t.add_cleanup(async () => {
+    if (frame) frame.remove();
+    return service_worker_unregister(t, scope);
+  });
+
+  // Check that the appcache controls the frame.
+  assert_equals(await check_is_appcached(frame), true,
+                'AppCache should be present');
+
+  // Check the controller and test with fetch.
+  assert_equals(frame.contentWindow.navigator.controller, undefined,
+                'Should have no controller.');
+  assert_equals(await fetch_text(frame), 'var is_appcached = true;\n',
+                'fetch() should not be intercepted.');
+
+  // Register a service worker.
+  let registration = await service_worker_unregister_and_register(t, script, scope);
+  const worker = registration.installing;
+  await wait_for_state(t, worker, 'activated');
+
+  // Let the service worker claim the iframe.
+  const channel = new MessageChannel();
+  const check_message = new Promise(resolve => {
+    channel.port1.onmessage = async e => {
+      assert_equals(e.data, 'PASS', 'Worker call to claim() should fulfill.');
+      resolve();
+    };
+  });
+  worker.postMessage({port: channel.port2}, [channel.port2]);
+  await check_message;
+
+  // Check that the appcache does NOT control the frame.
+  assert_equals(await check_is_appcached(frame), false,
+                'AppCache should not be present');
+
+  // Check the controller and test with fetch.
+  registration = await
+    frame.contentWindow.navigator.serviceWorker.getRegistration(scope);
+  assert_equals(frame.contentWindow.navigator.serviceWorker.controller,
+                registration.active, 'iframe should be claimed.');
+  assert_equals(await fetch_text(frame), 'Intercepted!',
+                'fetch() should be intercepted.');
+}, 'fetch() should be intercepted after the client is claimed.')
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/appcache-ordering.manifest b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/appcache-ordering.manifest
index 0deed0e..e6597cc 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/appcache-ordering.manifest
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/appcache-ordering.manifest
@@ -1,6 +1,7 @@
 CACHE MANIFEST
 
 appcache-ordering.is-appcached.html
+blank.html
 
 FALLBACK:
 appcache-ordering.is-appcached404.js appcache-ordering.is-appcached.js
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/claim-worker.js b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/claim-worker.js
index 53f210c..18004079 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/claim-worker.js
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/claim-worker.js
@@ -14,5 +14,6 @@
   });
 
 self.addEventListener('fetch', function(event) {
-    event.respondWith(new Response('Intercepted!'));
-});
+    if (!/404/.test(event.request.url))
+      event.respondWith(new Response('Intercepted!'));
+  });
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/test-helpers.sub.js b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/test-helpers.sub.js
index 7efde35..14101319 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/test-helpers.sub.js
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/test-helpers.sub.js
@@ -276,3 +276,33 @@
   await wait_for_state(t, registration.installing, 'activated');
   await registration.unregister();
 }
+
+// This installs resources/appcache-ordering.manifest.
+function install_appcache_ordering_manifest() {
+  let resolve_install_appcache;
+  let reject_install_appcache;
+
+  // This is notified by the child iframe, i.e. appcache-ordering.install.html,
+  // that's to be created below.
+  window.notify_appcache_installed = success => {
+    if (success)
+      resolve_install_appcache();
+    else
+      reject_install_appcache();
+  };
+
+  return new Promise((resolve, reject) => {
+      const frame = document.createElement('iframe');
+      frame.src = 'resources/appcache-ordering.install.html';
+      document.body.appendChild(frame);
+      resolve_install_appcache = function() {
+          document.body.removeChild(frame);
+          resolve();
+        };
+      reject_install_appcache = function() {
+          document.body.removeChild(frame);
+          reject();
+        };
+  });
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-expected.html b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-expected.html
new file mode 100644
index 0000000..c523ba1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-expected.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<div style="position: relative; top: 150px; left: 150px; width: 100px; height: 100px; background-color: green"></div>
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
new file mode 100644
index 0000000..b35e050
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
@@ -0,0 +1,40 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutInline (relative positioned) SPAN",
+      "position": [108, 108]
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
+      "position": [158, 158],
+      "bounds": [100, 100],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "paintInvalidations": [
+        {
+          "object": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
+          "rect": [0, 0, 100, 100],
+          "reason": "background"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.html b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.html
new file mode 100644
index 0000000..c523ba1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<div style="position: relative; top: 150px; left: 150px; width: 100px; height: 100px; background-color: green"></div>
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
new file mode 100644
index 0000000..b35e050
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
@@ -0,0 +1,40 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutInline (relative positioned) SPAN",
+      "position": [108, 108]
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
+      "position": [158, 158],
+      "bounds": [100, 100],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "paintInvalidations": [
+        {
+          "object": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
+          "rect": [0, 0, 100, 100],
+          "reason": "background"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/float-under-composited-inline-expected.html b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/float-under-composited-inline-expected.html
new file mode 100644
index 0000000..58a15aee
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/float-under-composited-inline-expected.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<div style="position: relative; top: 100px; left: 100px; width: 100px; height: 100px; background-color: green"></div>
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/float-under-composited-inline-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/float-under-composited-inline-expected.txt
new file mode 100644
index 0000000..d3490256
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/float-under-composited-inline-expected.txt
@@ -0,0 +1,34 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutInline (relative positioned) SPAN",
+      "position": [108, 108],
+      "bounds": [100, 100],
+      "paintInvalidations": [
+        {
+          "object": "LayoutNGBlockFlow (floating) DIV id='float'",
+          "rect": [0, 0, 100, 100],
+          "reason": "background"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.html b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.html
new file mode 100644
index 0000000..c523ba1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<div style="position: relative; top: 150px; left: 150px; width: 100px; height: 100px; background-color: green"></div>
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
new file mode 100644
index 0000000..6f005dd5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
@@ -0,0 +1,35 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutInline (relative positioned) SPAN",
+      "position": [158, 158],
+      "bounds": [100, 100],
+      "contentsOpaque": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
+          "rect": [0, 0, 100, 100],
+          "reason": "background"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
index c48e005..ca4b54d 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -28,16 +28,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'here; the great wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [14, 580, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
           "rect": [14, 560, 406, 19],
           "reason": "geometry"
@@ -48,18 +38,8 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
           "rect": [14, 520, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 520, 406, 19],
           "reason": "geometry"
         },
         {
@@ -98,11 +78,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'minute.'",
-          "rect": [14, 480, 355, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'with his head!\u2019 or \u2018Off with her head!\u2019 about once in a'",
           "rect": [14, 480, 355, 19],
           "reason": "geometry"
@@ -110,17 +85,12 @@
         {
           "object": "NGPhysicalTextFragment 'passion, and went stamping about, and shouting \u2018Off'",
           "rect": [14, 460, 355, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'with his head!\u2019 or \u2018Off with her head!\u2019 about once in a'",
-          "rect": [14, 460, 355, 19],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'quarrelling all the while, and fighting for the hedgehogs;'",
           "rect": [14, 420, 355, 19],
-          "reason": "appeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
@@ -150,32 +120,27 @@
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
           "rect": [14, 360, 317, 19],
-          "reason": "appeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
           "rect": [65, 360, 306, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'and in a very short time '",
-          "rect": [65, 420, 304, 19],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'The players all played at once without waiting'",
+          "object": "NGPhysicalTextFragment 'The players all played at once without waiting '",
           "rect": [65, 400, 304, 19],
-          "reason": "disappeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'The players all played at once without waiting '",
           "rect": [14, 400, 298, 19],
-          "reason": "appeared"
+          "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
+          "object": "NGPhysicalTextFragment 'and in a very short time '",
           "rect": [14, 440, 289, 19],
-          "reason": "disappeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'head down, and was going to '",
@@ -193,14 +158,9 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'and in a very short time '",
-          "rect": [14, 440, 171, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'about once in a minute.'",
+          "object": "NGPhysicalTextFragment 'minute.'",
           "rect": [14, 500, 147, 19],
-          "reason": "disappeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment ' twist itself round and'",
@@ -218,19 +178,19 @@
           "reason": "appeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "object": "NGPhysicalTextFragment 'indeed.'",
           "rect": [65, 380, 85, 19],
-          "reason": "disappeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [184, 440, 70, 19],
-          "reason": "appeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [302, 440, 68, 19],
-          "reason": "disappeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'for turns,'",
@@ -253,14 +213,9 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'minute.'",
-          "rect": [14, 500, 47, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'indeed.'",
           "rect": [14, 380, 46, 19],
-          "reason": "appeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'would'",
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-9-expected.txt
index 2e4cbc83..570c09b 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -29,25 +29,10 @@
         },
         {
           "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 580, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
           "rect": [14, 560, 406, 19],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
           "rect": [14, 540, 406, 19],
           "reason": "geometry"
@@ -58,28 +43,13 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'ground, Alice soon came to the conclusion that it was a very'",
           "rect": [14, 360, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'wanted to send the hedgehog to, and, as the doubled-up soldiers'",
-          "rect": [14, 340, 406, 19],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'were always getting up and walking off to other parts of the'",
           "rect": [14, 340, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'there was generally a ridge or furrow in the way wherever she'",
-          "rect": [14, 320, 406, 19],
           "reason": "geometry"
         },
         {
@@ -88,24 +58,19 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'and was in the act of crawling away: besides all this,'",
-          "rect": [14, 300, 406, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'there was generally a ridge or furrow in the way wherever she'",
           "rect": [14, 300, 406, 19],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself,'",
+          "object": "NGPhysicalTextFragment 'and was in the act of crawling away: besides all this,'",
           "rect": [14, 280, 406, 19],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
+          "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself,'",
           "rect": [14, 260, 406, 19],
-          "reason": "disappeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
@@ -123,26 +88,11 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
-          "rect": [14, 480, 355, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
           "rect": [14, 460, 355, 19],
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'and was in the act of crawling away: besides all this,'",
-          "rect": [14, 280, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself,'",
-          "rect": [14, 260, 355, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
           "rect": [14, 160, 354, 19],
           "reason": "geometry"
@@ -173,44 +123,29 @@
           "reason": "appeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 360, 306, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
           "rect": [65, 420, 304, 19],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'The players all played at once without waiting'",
           "rect": [65, 400, 304, 19],
-          "reason": "appeared"
+          "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
+          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
           "rect": [14, 440, 289, 19],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
           "rect": [65, 440, 285, 19],
-          "reason": "appeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'head down, and was going to '",
           "rect": [14, 240, 230, 19],
-          "reason": "disappeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
@@ -220,12 +155,7 @@
         {
           "object": "NGPhysicalTextFragment 'her head!\u2019 about once in a minute.'",
           "rect": [14, 500, 214, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 199, 19],
-          "reason": "appeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'begin again, it was very'",
@@ -238,11 +168,6 @@
           "reason": "appeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
-          "rect": [14, 500, 147, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment ' twist itself round and'",
           "rect": [277, 180, 144, 19],
           "reason": "geometry"
@@ -250,17 +175,12 @@
         {
           "object": "NGPhysicalTextFragment 'difficult game indeed.'",
           "rect": [65, 380, 138, 19],
-          "reason": "appeared"
+          "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'the Queen'",
+          "object": "NGPhysicalTextFragment 'the'",
           "rect": [302, 440, 68, 19],
-          "reason": "disappeared"
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'difficult'",
@@ -296,11 +216,6 @@
           "object": "NGPhysicalTextFragment 'would'",
           "rect": [238, 180, 41, 19],
           "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'the'",
-          "rect": [349, 440, 20, 19],
-          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/blink/web_tests/inspector-protocol/network/interception-file-url-expected.txt b/third_party/blink/web_tests/inspector-protocol/network/interception-file-url-expected.txt
index de2ed11..8e9f658d 100644
--- a/third_party/blink/web_tests/inspector-protocol/network/interception-file-url-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/network/interception-file-url-expected.txt
@@ -1,4 +1,6 @@
-Verify that request interception doesn't mess mime types
+Verify that interception works for file URLs
+Intercepted: .../network/resources/simple.html
 <h1>simple!</h1>
 
+Intercepted: .../network/resources/simple.js
 
diff --git a/third_party/blink/web_tests/inspector-protocol/network/interception-file-url.js b/third_party/blink/web_tests/inspector-protocol/network/interception-file-url.js
index 7dc44c7..0eed808 100644
--- a/third_party/blink/web_tests/inspector-protocol/network/interception-file-url.js
+++ b/third_party/blink/web_tests/inspector-protocol/network/interception-file-url.js
@@ -1,18 +1,30 @@
 (async function(testRunner) {
-  var {page, session, dp} = await testRunner.startBlank(`Verify that request interception doesn't mess mime types`);
+  var {page, session, dp} = await testRunner.startBlank(`Verify that interception works for file URLs`);
 
   await dp.Network.enable();
   await dp.Network.setRequestInterception({
     patterns: [{ urlPattern: '*' }]
   });
-  dp.Network.onRequestIntercepted(event => {
-    dp.Network.continueInterceptedRequest({
-      interceptionId: event.params.interceptionId
-    });
-  });
   await dp.Runtime.enable();
-  await session.navigate('./resources/simple.html');
+  const navigationPromise = session.navigate('./resources/simple.html');
+  const mainResource = (await dp.Network.onceRequestIntercepted()).params;
+  testRunner.log(`Intercepted: ${testRunner.trimURL(mainResource.request.url)}`);
+  dp.Network.continueInterceptedRequest({
+    interceptionId: mainResource.interceptionId
+  });
+  await navigationPromise;
   // If resource is interpreted as text/plain instead of text/html, the HTML will be escaped.
   testRunner.log(await session.evaluate(() => document.body.innerHTML));
+  session.evaluate(`(() => {
+    let script = document.createElement('script');
+    script.src = 'simple.js';
+    document.body.appendChild(script);
+  })()`);
+  const subresource = (await dp.Network.onceRequestIntercepted()).params;
+  testRunner.log(`Intercepted: ${testRunner.trimURL(subresource.request.url)}`);
+  dp.Network.continueInterceptedRequest({
+    interceptionId: subresource.interceptionId
+  });
+
   testRunner.completeTest();
 })
diff --git a/third_party/blink/web_tests/inspector-protocol/network/resources/simple.js b/third_party/blink/web_tests/inspector-protocol/network/resources/simple.js
new file mode 100644
index 0000000..eccb9bb
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/network/resources/simple.js
@@ -0,0 +1,2 @@
+function() {
+}
diff --git a/third_party/blink/web_tests/platform/linux/media/video-layer-crash-expected.png b/third_party/blink/web_tests/platform/linux/media/video-layer-crash-expected.png
index 0f66feb..25098b6 100644
--- a/third_party/blink/web_tests/platform/linux/media/video-layer-crash-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/video-layer-crash-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
index 3c9114bf..1d114a199 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
index 40c0749..624fbe2 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/video-surface-layer/media/video-layer-crash-expected.png b/third_party/blink/web_tests/platform/linux/virtual/video-surface-layer/media/video-layer-crash-expected.png
index 0f66feb..25098b6 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/video-surface-layer/media/video-layer-crash-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/video-surface-layer/media/video-layer-crash-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/video-layer-crash-expected.png b/third_party/blink/web_tests/platform/mac/media/video-layer-crash-expected.png
index 178d2b2..dac906f 100644
--- a/third_party/blink/web_tests/platform/mac/media/video-layer-crash-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/video-layer-crash-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
index 4b95f41..17f1093 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/feature-policy-oversized-images-styles-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/feature-policy-oversized-images-styles-expected.png
index dc44b74..59de00a0 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/feature-policy-oversized-images-styles-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/feature-policy-oversized-images-styles-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/image-map-anchor-children-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/image-map-anchor-children-expected.png
index eb8fe49..b78a734 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/image-map-anchor-children-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/image-map-anchor-children-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png
index cc3854a2..67b341279 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
index eab1194..b8f1cce 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
index 79c62c4..72e7768 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/video-layer-crash-expected.png b/third_party/blink/web_tests/platform/win/media/video-layer-crash-expected.png
index 11b98a7..a991cf96 100644
--- a/third_party/blink/web_tests/platform/win/media/video-layer-crash-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/video-layer-crash-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
index 3c9114bf..1d114a199 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png
index 68808cf..d00cd39b 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
index 7e42a6d..687af03 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
index 5b61662..015149c 100644
--- a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
index 17a2692..4af1e46 100644
--- a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/canvas-drawImage-antiAlias-expected.png b/third_party/blink/web_tests/virtual/gpu/fast/canvas/canvas-drawImage-antiAlias-expected.png
index 6e945b8..ef8933d 100644
--- a/third_party/blink/web_tests/virtual/gpu/fast/canvas/canvas-drawImage-antiAlias-expected.png
+++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/canvas-drawImage-antiAlias-expected.png
Binary files differ
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ead567c..0c18789 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -116161,8 +116161,10 @@
   <summary>Number of retries until the final response was recorded.</summary>
 </histogram>
 
-<histogram name="Toolbar.ActionsModel.ComponentActionsCount"
-    expires_after="2018-08-30">
+<histogram name="Toolbar.ActionsModel.ComponentActionsCount">
+  <obsolete>
+    Expired
+  </obsolete>
   <owner>rdevlin.cronin@chromium.org</owner>
   <summary>
     The number of component action icons the Browser Actions Container knows
diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc
index fc96c61b..c57c8b57 100644
--- a/ui/base/ime/input_method_base.cc
+++ b/ui/base/ime/input_method_base.cc
@@ -262,6 +262,10 @@
       !client->GetEditableSelectionRange(&info.selection_range)) {
     return SurroundingTextInfo();
   }
+  // Makes the |selection_range| be relative to the |surrounding_text|.
+  info.selection_range.set_start(info.selection_range.start() -
+                                 text_range.start());
+  info.selection_range.set_end(info.selection_range.end() - text_range.start());
   return info;
 }
 
diff --git a/ui/webui/resources/css/md_colors.css b/ui/webui/resources/css/md_colors.css
index 7c6a46c..5606926 100644
--- a/ui/webui/resources/css/md_colors.css
+++ b/ui/webui/resources/css/md_colors.css
@@ -11,3 +11,13 @@
    */
   --md-toolbar-color: rgb(51, 103, 214);
 }
+
+html[dark],
+:host-context(html[dark]) {
+  --md-background-color: rgb(32, 33, 36);  /* --google-grey-900 */
+  --md-toolbar-border-color: rgb(95, 99, 104);  /* --google-grey-refresh-700 */
+  /* Dark mode doesn't currently have a different toolbar background color.
+   * Instead, it uses a 1px grey border at the bottom. We set it just in case
+   * opaqueness is required for some reason. */
+  --md-toolbar-color: var(--md-background-color);
+}
diff --git a/ui/webui/resources/css/text_defaults.css b/ui/webui/resources/css/text_defaults.css
index ac98968..33942fb 100644
--- a/ui/webui/resources/css/text_defaults.css
+++ b/ui/webui/resources/css/text_defaults.css
@@ -16,6 +16,7 @@
  * Otherwise its placeholders won't be expanded. */
 
 html {
+  /* TODO(dbeam): remove this soon. Prefer dir= in HTML. */
   direction: $i18n{textDirection};
 }
 
diff --git a/ui/webui/resources/css/text_defaults_md.css b/ui/webui/resources/css/text_defaults_md.css
index 56892a04..a862419 100644
--- a/ui/webui/resources/css/text_defaults_md.css
+++ b/ui/webui/resources/css/text_defaults_md.css
@@ -18,6 +18,7 @@
 @import url(chrome://resources/css/roboto.css);
 
 html {
+  /* TODO(dbeam): remove this soon. Prefer dir= in HTML. */
   direction: $i18n{textDirection};
 }