diff --git a/DEPS b/DEPS
index ff0bc0e..d1428f2 100644
--- a/DEPS
+++ b/DEPS
@@ -144,11 +144,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': '8c31f2bf7f154e00952da9bdfbe3accc7691aecf',
+  'skia_revision': 'd7639aff1001736bc6072da539b31f911bb3788a',
   # 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': '3ec321d4ceec28228248d2b530719ac180847d3f',
+  'v8_revision': '483d4365d323f0344da5c69055c3664908966352',
   # 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.
@@ -156,11 +156,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'b243a2a4f27b7ab93b34dd247088afa7c2a10038',
+  'angle_revision': '0efe516eeaeff1ea7d9c79d577e73573509f814c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '64f2cec30c96dad0ac67cdffe42feda7611fe4ae',
+  'swiftshader_revision': '0662a4afb5d1374752063337335089878acc462e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -808,7 +808,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '66c4e85a160b6b01b49a1cafb6776f6012f31e39',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '97028a5397fdfd14ffbad8614edf0c4c1dd6fe73',
       'condition': 'checkout_linux',
   },
 
@@ -1362,7 +1362,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6453c2f5604ec8bca15e9e1edc64e979da8f1083',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '0be40bf53fc4aa6707636a385e5eaaf01da7c7e4',
+    Var('webrtc_git') + '/src.git' + '@' + 'b04e2561be34029bc06867946a706d268500212d',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1403,7 +1403,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@223c459965a8777dbe34a456508808b65496ad34',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@49b659419343e79e56fc4054b2179959caebe313',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 14f7bc2..d543207 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -1937,7 +1937,9 @@
            'OWNERS']
   try:
     if files:
-      input_api.subprocess.check_output(args + files)
+      warnings = input_api.subprocess.check_output(args + files).splitlines()
+      if warnings:
+        return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
     return []
   except input_api.subprocess.CalledProcessError as error:
     return [output_api.PresubmitError(
@@ -4265,7 +4267,7 @@
     """
     doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
         stop_after=None, first_ids_file=None,
-        debug=False, defines=None,
+        debug=False, defines={'_chromium': 1},
         tags_to_ignore=set([PART_FILE_TAG]))
     return {
       msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
diff --git a/PRESUBMIT_test_mocks.py b/PRESUBMIT_test_mocks.py
index ed6a750..7fc3b2abc 100644
--- a/PRESUBMIT_test_mocks.py
+++ b/PRESUBMIT_test_mocks.py
@@ -111,7 +111,7 @@
     return found_in_white_list
 
   def LocalPaths(self):
-    return self.files
+    return [file.LocalPath() for file in self.files]
 
   def PresubmitLocalPath(self):
     return self.presubmit_local_path
@@ -220,6 +220,10 @@
     """os.path.basename is called on MockFile so we need a len method."""
     return len(self._local_path)
 
+  def replace(self, altsep, sep):
+    """os.path.basename is called on MockFile so we need a replace method."""
+    return self._local_path.replace(altsep, sep)
+
 
 class MockAffectedFile(MockFile):
   def AbsoluteLocalPath(self):
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 8b65d01..f1bdf68 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -479,14 +479,22 @@
   return rb.GetImageNamed(IDR_DEFAULT_FAVICON).AsImageSkia();
 }
 
-bool AwContentBrowserClient::AllowAppCache(const GURL& manifest_url,
-                           const GURL& first_party,
-                           content::ResourceContext* context) {
+bool AwContentBrowserClient::AllowAppCacheOnIO(
+    const GURL& manifest_url,
+    const GURL& first_party,
+    content::ResourceContext* context) {
   // WebView doesn't have a per-site policy for locally stored data,
   // instead AppCache can be disabled for individual WebViews.
   return true;
 }
 
+bool AwContentBrowserClient::AllowAppCache(const GURL& manifest_url,
+                                           const GURL& first_party,
+                                           content::BrowserContext* context) {
+  // WebView doesn't have a per-site policy for locally stored data,
+  // instead AppCache can be disabled for individual WebViews.
+  return true;
+}
 
 bool AwContentBrowserClient::AllowGetCookie(const GURL& url,
                                             const GURL& first_party,
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 9b34344..3aeeffa5a 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -75,9 +75,12 @@
   std::string GetApplicationLocale() override;
   std::string GetAcceptLangs(content::BrowserContext* context) override;
   gfx::ImageSkia GetDefaultFavicon() override;
+  bool AllowAppCacheOnIO(const GURL& manifest_url,
+                         const GURL& first_party,
+                         content::ResourceContext* context) override;
   bool AllowAppCache(const GURL& manifest_url,
                      const GURL& first_party,
-                     content::ResourceContext* context) override;
+                     content::BrowserContext* context) override;
   bool AllowGetCookie(const GURL& url,
                       const GURL& first_party,
                       const net::CookieList& cookie_list,
diff --git a/android_webview/browser/gfx/surfaces_instance.cc b/android_webview/browser/gfx/surfaces_instance.cc
index 636d902..6fac701 100644
--- a/android_webview/browser/gfx/surfaces_instance.cc
+++ b/android_webview/browser/gfx/surfaces_instance.cc
@@ -207,7 +207,6 @@
   settings.should_clear_root_render_pass = false;
 
   settings.use_skia_renderer = features::IsUsingSkiaRenderer();
-  settings.use_skia_renderer_non_ddl = features::IsUsingSkiaRendererNonDDL();
 
   // The SharedBitmapManager is null as we do not support or use software
   // compositing on Android.
@@ -222,8 +221,6 @@
       this, frame_sink_manager_.get(), frame_sink_id_, is_root,
       needs_sync_points);
 
-  const bool use_skia_renderer =
-      settings.use_skia_renderer || settings.use_skia_renderer_non_ddl;
   auto* command_line = base::CommandLine::ForCurrentProcess();
   const bool enable_vulkan =
       command_line->HasSwitch(switches::kWebViewEnableVulkan);
@@ -232,7 +229,7 @@
   LOG_IF(FATAL, enable_vulkan && !enable_shared_image)
       << "--webview-enable-vulkan only works with shared image "
          "(--webview-enable-shared-image).";
-  LOG_IF(FATAL, enable_vulkan && !use_skia_renderer)
+  LOG_IF(FATAL, enable_vulkan && !settings.use_skia_renderer)
       << "--webview-enable-vulkan only works with skia renderer "
          "(--enable-features=UseSkiaRenderer or UseSkiaRendererNonDDL).";
 
@@ -240,7 +237,7 @@
       enable_vulkan ? AwVulkanContextProvider::GetOrCreateInstance() : nullptr;
   std::unique_ptr<viz::OutputSurface> output_surface;
   gl_surface_ = base::MakeRefCounted<AwGLSurface>();
-  if (settings.use_skia_renderer || settings.use_skia_renderer_non_ddl) {
+  if (settings.use_skia_renderer) {
     auto* task_executor = DeferredGpuCommandService::GetInstance();
     gpu::GpuDriverBugWorkarounds workarounds(
         task_executor->gpu_feature_info().enabled_gpu_driver_bug_workarounds);
@@ -256,14 +253,10 @@
       shared_context_state_->InitializeGrContext(workarounds,
                                                  nullptr /* gr_shader_cache */);
     }
-    if (settings.use_skia_renderer_non_ddl) {
-      NOTIMPLEMENTED();
-    } else {
-      output_surface = std::make_unique<viz::SkiaOutputSurfaceImpl>(
-          std::make_unique<SkiaOutputSurfaceDependencyWebView>(
-              task_executor, workarounds, shared_context_state_, gl_surface_),
-          settings);
-    }
+    output_surface = std::make_unique<viz::SkiaOutputSurfaceImpl>(
+        std::make_unique<SkiaOutputSurfaceDependencyWebView>(
+            task_executor, workarounds, shared_context_state_, gl_surface_),
+        settings);
   } else {
     auto context_provider = AwRenderThreadContextProvider::Create(
         gl_surface_, DeferredGpuCommandService::GetInstance());
diff --git a/android_webview/common/crash_reporter/aw_crash_reporter_client.cc b/android_webview/common/crash_reporter/aw_crash_reporter_client.cc
index cd0db55..87450c1f 100644
--- a/android_webview/common/crash_reporter/aw_crash_reporter_client.cc
+++ b/android_webview/common/crash_reporter/aw_crash_reporter_client.cc
@@ -74,7 +74,8 @@
 
   unsigned int GetCrashDumpPercentage() override {
     if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kEnableCrashReporterForTesting)) {
+            switches::kEnableCrashReporterForTesting) ||
+        base::android::BuildInfo::GetInstance()->is_debug_android()) {
       return 100;
     }
 
diff --git a/android_webview/tools/record_netlog.py b/android_webview/tools/record_netlog.py
index be1d5d5..8308120d 100755
--- a/android_webview/tools/record_netlog.py
+++ b/android_webview/tools/record_netlog.py
@@ -79,8 +79,7 @@
 
   args = parser.parse_args()
   logging_common.InitializeLogging(args)
-  devil_chromium.Initialize()
-  script_common.InitializeEnvironment(args)
+  devil_chromium.Initialize(adb_path=args.adb_path)
 
   # Only use a single device, for the sake of simplicity (of implementation and
   # user experience).
diff --git a/android_webview/tools/remove_preinstalled_webview.py b/android_webview/tools/remove_preinstalled_webview.py
index 2e96fd20..5eaff7f 100755
--- a/android_webview/tools/remove_preinstalled_webview.py
+++ b/android_webview/tools/remove_preinstalled_webview.py
@@ -112,8 +112,7 @@
 
   args = parser.parse_args()
   logging_common.InitializeLogging(args)
-  devil_chromium.Initialize()
-  script_common.InitializeEnvironment(args)
+  devil_chromium.Initialize(adb_path=args.adb_path)
 
   devices = device_utils.DeviceUtils.HealthyDevices(device_arg=args.devices)
   device_utils.DeviceUtils.parallel(devices).pMap(RemovePreinstalledWebViews)
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 0a0c0db..113ac26 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -506,8 +506,12 @@
     "multi_user/user_switch_animator.h",
     "policy/policy_recommendation_restorer.cc",
     "policy/policy_recommendation_restorer.h",
+    "power/fake_gatt_battery_percentage_fetcher.cc",
+    "power/fake_gatt_battery_percentage_fetcher.h",
     "power/gatt_battery_percentage_fetcher.cc",
     "power/gatt_battery_percentage_fetcher.h",
+    "power/gatt_battery_poller.cc",
+    "power/gatt_battery_poller.h",
     "root_window_controller.cc",
     "root_window_settings.cc",
     "root_window_settings.h",
@@ -1712,6 +1716,7 @@
     "multi_device_setup/multi_device_notification_presenter_unittest.cc",
     "policy/policy_recommendation_restorer_unittest.cc",
     "power/gatt_battery_percentage_fetcher_unittest.cc",
+    "power/gatt_battery_poller_unittest.cc",
     "root_window_controller_unittest.cc",
     "rotator/screen_rotation_animation_unittest.cc",
     "rotator/screen_rotation_animator_unittest.cc",
diff --git a/ash/dbus/gesture_properties_service_provider.cc b/ash/dbus/gesture_properties_service_provider.cc
index 0b4d622a..2b40d1d 100644
--- a/ash/dbus/gesture_properties_service_provider.cc
+++ b/ash/dbus/gesture_properties_service_provider.cc
@@ -33,6 +33,18 @@
       base::BindRepeating(&GesturePropertiesServiceProvider::ListDevices,
                           weak_ptr_factory_.GetWeakPtr()),
       on_exported);
+  exported_object->ExportMethod(
+      chromeos::kGesturePropertiesServiceInterface,
+      chromeos::kGesturePropertiesServiceListPropertiesMethod,
+      base::BindRepeating(&GesturePropertiesServiceProvider::ListProperties,
+                          weak_ptr_factory_.GetWeakPtr()),
+      on_exported);
+  exported_object->ExportMethod(
+      chromeos::kGesturePropertiesServiceInterface,
+      chromeos::kGesturePropertiesServiceGetPropertyMethod,
+      base::BindRepeating(&GesturePropertiesServiceProvider::GetProperty,
+                          weak_ptr_factory_.GetWeakPtr()),
+      on_exported);
 }
 
 void GesturePropertiesServiceProvider::OnExported(
@@ -45,6 +57,78 @@
 
 namespace {
 
+void GetPropertyCallback(
+    dbus::MethodCall* method_call,
+    std::unique_ptr<dbus::Response> response,
+    const dbus::ExportedObject::ResponseSender& response_sender,
+    bool is_read_only,
+    ui::ozone::mojom::GesturePropValuePtr values) {
+  if (values.is_null()) {
+    response_sender.Run(dbus::ErrorResponse::FromMethodCall(
+        method_call, DBUS_ERROR_INVALID_ARGS,
+        "The device ID or property name specified was not found."));
+    return;
+  }
+
+  dbus::MessageWriter writer(response.get());
+  dbus::MessageWriter variant_writer(nullptr);
+  dbus::MessageWriter array_writer(nullptr);
+  writer.AppendBool(is_read_only);
+  switch (values->which()) {
+    case ui::ozone::mojom::GesturePropValue::Tag::INTS: {
+      writer.AppendUint32(values->get_ints().size());
+      writer.OpenVariant("ai", &variant_writer);
+      variant_writer.AppendArrayOfInt32s(values->get_ints().data(),
+                                         values->get_ints().size());
+      writer.CloseContainer(&variant_writer);
+      break;
+    }
+    case ui::ozone::mojom::GesturePropValue::Tag::SHORTS: {
+      writer.AppendUint32(values->get_shorts().size());
+      writer.OpenVariant("an", &variant_writer);
+      variant_writer.OpenArray("n", &array_writer);
+      for (int16_t value : values->get_shorts()) {
+        array_writer.AppendInt16(value);
+      }
+      variant_writer.CloseContainer(&array_writer);
+      writer.CloseContainer(&variant_writer);
+      break;
+    }
+    case ui::ozone::mojom::GesturePropValue::Tag::BOOLS: {
+      writer.AppendUint32(values->get_bools().size());
+      writer.OpenVariant("ab", &variant_writer);
+      variant_writer.OpenArray("b", &array_writer);
+      for (bool value : values->get_bools()) {
+        array_writer.AppendBool(value);
+      }
+      variant_writer.CloseContainer(&array_writer);
+      writer.CloseContainer(&variant_writer);
+      break;
+    }
+    case ui::ozone::mojom::GesturePropValue::Tag::STR: {
+      writer.AppendUint32(1);
+      writer.AppendVariantOfString(values->get_str());
+      break;
+    }
+    case ui::ozone::mojom::GesturePropValue::Tag::REALS: {
+      writer.AppendUint32(values->get_reals().size());
+      writer.OpenVariant("ad", &variant_writer);
+      variant_writer.AppendArrayOfDoubles(values->get_reals().data(),
+                                          values->get_reals().size());
+      writer.CloseContainer(&variant_writer);
+      break;
+    }
+    default: {
+      // This should never happen.
+      LOG(WARNING) << "No value set on GesturePropValue union; not returning "
+                      "values to GetProperty call.";
+      writer.AppendUint32(0);
+      break;
+    }
+  }
+  response_sender.Run(std::move(response));
+}
+
 void ListDevicesCallback(
     std::unique_ptr<dbus::Response> response,
     const dbus::ExportedObject::ResponseSender& response_sender,
@@ -64,6 +148,16 @@
   response_sender.Run(std::move(response));
 }
 
+void ListPropertiesCallback(
+    std::unique_ptr<dbus::Response> response,
+    const dbus::ExportedObject::ResponseSender& response_sender,
+    const std::vector<std::string>& result) {
+  dbus::MessageWriter writer(response.get());
+  writer.AppendUint32(result.size());
+  writer.AppendArrayOfStrings(result);
+  response_sender.Run(std::move(response));
+}
+
 }  // namespace
 
 void GesturePropertiesServiceProvider::ListDevices(
@@ -76,6 +170,50 @@
       &ListDevicesCallback, std::move(response), response_sender));
 }
 
+void GesturePropertiesServiceProvider::ListProperties(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  dbus::MessageReader reader(method_call);
+  int32_t device_id;
+  if (!reader.PopInt32(&device_id)) {
+    response_sender.Run(dbus::ErrorResponse::FromMethodCall(
+        method_call, DBUS_ERROR_INVALID_ARGS,
+        "The device ID (int32) is missing."));
+    return;
+  }
+
+  std::unique_ptr<dbus::Response> response =
+      dbus::Response::FromMethodCall(method_call);
+
+  GetService()->ListProperties(
+      device_id, base::BindOnce(&ListPropertiesCallback, std::move(response),
+                                response_sender));
+}
+
+void GesturePropertiesServiceProvider::GetProperty(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  dbus::MessageReader reader(method_call);
+
+  int32_t device_id;
+  std::string property_name;
+
+  if (!reader.PopInt32(&device_id) || !reader.PopString(&property_name)) {
+    response_sender.Run(dbus::ErrorResponse::FromMethodCall(
+        method_call, DBUS_ERROR_INVALID_ARGS,
+        "The device ID (int32) and/or property name (string) is missing."));
+    return;
+  }
+
+  std::unique_ptr<dbus::Response> response =
+      dbus::Response::FromMethodCall(method_call);
+
+  GetService()->GetProperty(
+      device_id, property_name,
+      base::BindOnce(&GetPropertyCallback, method_call, std::move(response),
+                     response_sender));
+}
+
 ui::ozone::mojom::GesturePropertiesService*
 GesturePropertiesServiceProvider::GetService() {
   if (service_for_test_ != nullptr)
diff --git a/ash/dbus/gesture_properties_service_provider.h b/ash/dbus/gesture_properties_service_provider.h
index cb1b4171..7c8aa6c 100644
--- a/ash/dbus/gesture_properties_service_provider.h
+++ b/ash/dbus/gesture_properties_service_provider.h
@@ -51,6 +51,14 @@
   void ListDevices(dbus::MethodCall* method_call,
                    dbus::ExportedObject::ResponseSender response_sender);
 
+  // Called on UI thread in response to a D-Bus request.
+  void ListProperties(dbus::MethodCall* method_call,
+                      dbus::ExportedObject::ResponseSender response_sender);
+
+  // Called on UI thread in response to a D-Bus request.
+  void GetProperty(dbus::MethodCall* method_call,
+                   dbus::ExportedObject::ResponseSender response_sender);
+
   ui::ozone::mojom::GesturePropertiesService* GetService();
 
   ui::ozone::mojom::GesturePropertiesServicePtr service_;
diff --git a/ash/dbus/gesture_properties_service_provider_unittest.cc b/ash/dbus/gesture_properties_service_provider_unittest.cc
index e23bd42f..ee1fbdc7 100644
--- a/ash/dbus/gesture_properties_service_provider_unittest.cc
+++ b/ash/dbus/gesture_properties_service_provider_unittest.cc
@@ -21,6 +21,18 @@
 
 namespace {
 
+bool expect_bool(dbus::MessageReader* reader) {
+  bool result;
+  EXPECT_TRUE(reader->PopBool(&result));
+  return result;
+}
+
+int16_t expect_int16(dbus::MessageReader* reader) {
+  int16_t result;
+  EXPECT_TRUE(reader->PopInt16(&result));
+  return result;
+}
+
 uint32_t expect_uint32(dbus::MessageReader* reader) {
   uint32_t result;
   EXPECT_TRUE(reader->PopUint32(&result));
@@ -39,6 +51,12 @@
   return result;
 }
 
+double expect_double(dbus::MessageReader* reader) {
+  double result;
+  EXPECT_TRUE(reader->PopDouble(&result));
+  return result;
+}
+
 }  // namespace
 
 class GesturePropertiesServiceProviderTest : public testing::Test {
@@ -52,7 +70,9 @@
     ON_CALL(*mock_service_, ListProperties(_, _))
         .WillByDefault(Invoke(
             this, &GesturePropertiesServiceProviderTest::FakeListProperties));
-
+    ON_CALL(*mock_service_, GetProperty(_, _, _))
+        .WillByDefault(Invoke(
+            this, &GesturePropertiesServiceProviderTest::FakeGetProperty));
     service_provider_ = std::make_unique<GesturePropertiesServiceProvider>();
     service_provider_->set_service_for_test(mock_service_.get());
   }
@@ -72,6 +92,15 @@
     std::move(callback).Run(list_properties_response_);
   }
 
+  void FakeGetProperty(
+      Unused,
+      Unused,
+      ui::ozone::mojom::GesturePropertiesService::GetPropertyCallback
+          callback) {
+    std::move(callback).Run(get_property_read_only_,
+                            std::move(get_property_response_));
+  }
+
  protected:
   void CallDBusMethod(std::string name,
                       dbus::MethodCall* method_call,
@@ -92,6 +121,19 @@
     CallDBusMethod(name, std::move(method_call), response);
   }
 
+  void CallGetProperty(int32_t device_id,
+                       std::string name,
+                       std::unique_ptr<dbus::Response>& response) {
+    dbus::MethodCall* method_call = new dbus::MethodCall(
+        chromeos::kGesturePropertiesServiceInterface,
+        chromeos::kGesturePropertiesServiceGetPropertyMethod);
+    dbus::MessageWriter writer(method_call);
+    writer.AppendInt32(device_id);
+    writer.AppendString(name);
+    CallDBusMethod(chromeos::kGesturePropertiesServiceGetPropertyMethod,
+                   std::move(method_call), response);
+  }
+
   void CheckMethodErrorsWithNoParameters(std::string name) {
     std::unique_ptr<dbus::Response> response = nullptr;
     CallWithoutParameters(name, response);
@@ -100,6 +142,8 @@
 
   base::flat_map<int, std::string> list_devices_response_ = {};
   std::vector<std::string> list_properties_response_ = {};
+  bool get_property_read_only_ = true;
+  ui::ozone::mojom::GesturePropValuePtr get_property_response_ = nullptr;
 
   std::unique_ptr<MockGesturePropertiesService> mock_service_;
 
@@ -154,4 +198,175 @@
   EXPECT_FALSE(reader.HasMoreData());
 }
 
+TEST_F(GesturePropertiesServiceProviderTest, ListPropertiesEmpty) {
+  list_properties_response_ = {};
+  EXPECT_CALL(*mock_service_, ListProperties(4, _));
+
+  std::unique_ptr<dbus::Response> response = nullptr;
+  dbus::MethodCall* method_call = new dbus::MethodCall(
+      chromeos::kGesturePropertiesServiceInterface,
+      chromeos::kGesturePropertiesServiceListPropertiesMethod);
+  dbus::MessageWriter writer(method_call);
+  writer.AppendInt32(4);
+  CallDBusMethod(chromeos::kGesturePropertiesServiceListPropertiesMethod,
+                 std::move(method_call), response);
+
+  dbus::MessageReader reader(response.get());
+  EXPECT_EQ(0u, expect_uint32(&reader));
+  dbus::MessageReader array_reader(nullptr);
+  ASSERT_TRUE(reader.PopArray(&array_reader));
+  EXPECT_FALSE(array_reader.HasMoreData());
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(GesturePropertiesServiceProviderTest, ListPropertiesSuccess) {
+  list_properties_response_ = {"prop 1", "prop 2"};
+  EXPECT_CALL(*mock_service_, ListProperties(4, _));
+
+  std::unique_ptr<dbus::Response> response = nullptr;
+  dbus::MethodCall* method_call = new dbus::MethodCall(
+      chromeos::kGesturePropertiesServiceInterface,
+      chromeos::kGesturePropertiesServiceListPropertiesMethod);
+  dbus::MessageWriter writer(method_call);
+  writer.AppendInt32(4);
+  CallDBusMethod(chromeos::kGesturePropertiesServiceListPropertiesMethod,
+                 std::move(method_call), response);
+
+  dbus::MessageReader reader(response.get());
+  EXPECT_EQ(2u, expect_uint32(&reader));
+  dbus::MessageReader array_reader(nullptr);
+  ASSERT_TRUE(reader.PopArray(&array_reader));
+  EXPECT_EQ("prop 1", expect_string(&array_reader));
+  EXPECT_EQ("prop 2", expect_string(&array_reader));
+  EXPECT_FALSE(array_reader.HasMoreData());
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(GesturePropertiesServiceProviderTest, ListPropertiesMissingParameter) {
+  CheckMethodErrorsWithNoParameters(
+      chromeos::kGesturePropertiesServiceListPropertiesMethod);
+}
+
+TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessInts) {
+  get_property_read_only_ = false;
+  get_property_response_ =
+      ui::ozone::mojom::GesturePropValue::NewInts({1, 2, 4});
+  EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
+
+  std::unique_ptr<dbus::Response> response = nullptr;
+  CallGetProperty(4, "prop 1", response);
+
+  dbus::MessageReader reader(response.get());
+  EXPECT_EQ(false, expect_bool(&reader));
+  EXPECT_EQ(3u, expect_uint32(&reader));
+  dbus::MessageReader variant_reader(nullptr);
+  ASSERT_TRUE(reader.PopVariant(&variant_reader));
+  dbus::MessageReader array_reader(nullptr);
+  ASSERT_TRUE(variant_reader.PopArray(&array_reader));
+  EXPECT_EQ(1, expect_int32(&array_reader));
+  EXPECT_EQ(2, expect_int32(&array_reader));
+  EXPECT_EQ(4, expect_int32(&array_reader));
+  EXPECT_FALSE(array_reader.HasMoreData());
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessShorts) {
+  get_property_read_only_ = false;
+  get_property_response_ =
+      ui::ozone::mojom::GesturePropValue::NewShorts({1, 2, 4});
+  EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
+
+  std::unique_ptr<dbus::Response> response = nullptr;
+  CallGetProperty(4, "prop 1", response);
+
+  dbus::MessageReader reader(response.get());
+  EXPECT_EQ(false, expect_bool(&reader));
+  EXPECT_EQ(3u, expect_uint32(&reader));
+  dbus::MessageReader variant_reader(nullptr);
+  ASSERT_TRUE(reader.PopVariant(&variant_reader));
+  dbus::MessageReader array_reader(nullptr);
+  ASSERT_TRUE(variant_reader.PopArray(&array_reader));
+  EXPECT_EQ(1, expect_int16(&array_reader));
+  EXPECT_EQ(2, expect_int16(&array_reader));
+  EXPECT_EQ(4, expect_int16(&array_reader));
+  EXPECT_FALSE(array_reader.HasMoreData());
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessBools) {
+  get_property_read_only_ = false;
+  get_property_response_ =
+      ui::ozone::mojom::GesturePropValue::NewBools({true, false});
+  EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
+
+  std::unique_ptr<dbus::Response> response = nullptr;
+  CallGetProperty(4, "prop 1", response);
+
+  dbus::MessageReader reader(response.get());
+  EXPECT_EQ(false, expect_bool(&reader));
+  EXPECT_EQ(2u, expect_uint32(&reader));
+  dbus::MessageReader variant_reader(nullptr);
+  ASSERT_TRUE(reader.PopVariant(&variant_reader));
+  dbus::MessageReader array_reader(nullptr);
+  ASSERT_TRUE(variant_reader.PopArray(&array_reader));
+  EXPECT_EQ(true, expect_bool(&array_reader));
+  EXPECT_EQ(false, expect_bool(&array_reader));
+  EXPECT_FALSE(array_reader.HasMoreData());
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessStr) {
+  get_property_read_only_ = false;
+  get_property_response_ = ui::ozone::mojom::GesturePropValue::NewStr("llama");
+  EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
+
+  std::unique_ptr<dbus::Response> response = nullptr;
+  CallGetProperty(4, "prop 1", response);
+
+  dbus::MessageReader reader(response.get());
+  EXPECT_EQ(false, expect_bool(&reader));
+  EXPECT_EQ(1u, expect_uint32(&reader));
+  dbus::MessageReader variant_reader(nullptr);
+  ASSERT_TRUE(reader.PopVariant(&variant_reader));
+  EXPECT_EQ("llama", expect_string(&variant_reader));
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessReals) {
+  get_property_read_only_ = false;
+  get_property_response_ =
+      ui::ozone::mojom::GesturePropValue::NewReals({3.14, 6.28});
+  EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
+
+  std::unique_ptr<dbus::Response> response = nullptr;
+  CallGetProperty(4, "prop 1", response);
+
+  dbus::MessageReader reader(response.get());
+  EXPECT_EQ(false, expect_bool(&reader));
+  EXPECT_EQ(2u, expect_uint32(&reader));
+  dbus::MessageReader variant_reader(nullptr);
+  ASSERT_TRUE(reader.PopVariant(&variant_reader));
+  dbus::MessageReader array_reader(nullptr);
+  ASSERT_TRUE(variant_reader.PopArray(&array_reader));
+  EXPECT_EQ(3.14, expect_double(&array_reader));
+  EXPECT_EQ(6.28, expect_double(&array_reader));
+  EXPECT_FALSE(array_reader.HasMoreData());
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(GesturePropertiesServiceProviderTest, GetPropertyPropertyDoesntExist) {
+  get_property_read_only_ = true;
+  get_property_response_ = nullptr;
+  EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
+
+  std::unique_ptr<dbus::Response> response = nullptr;
+  CallGetProperty(4, "prop 1", response);
+  EXPECT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+}
+
+TEST_F(GesturePropertiesServiceProviderTest, GetPropertyMissingParameters) {
+  CheckMethodErrorsWithNoParameters(
+      chromeos::kGesturePropertiesServiceGetPropertyMethod);
+}
+
 }  // namespace ash
diff --git a/ash/power/fake_gatt_battery_percentage_fetcher.cc b/ash/power/fake_gatt_battery_percentage_fetcher.cc
new file mode 100644
index 0000000..03674e1
--- /dev/null
+++ b/ash/power/fake_gatt_battery_percentage_fetcher.cc
@@ -0,0 +1,16 @@
+// Copyright 2019 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 "ash/power/fake_gatt_battery_percentage_fetcher.h"
+
+namespace ash {
+
+FakeGattBatteryPercentageFetcher::FakeGattBatteryPercentageFetcher(
+    const std::string& device_address,
+    BatteryPercentageCallback callback)
+    : GattBatteryPercentageFetcher(device_address, std::move(callback)) {}
+
+FakeGattBatteryPercentageFetcher::~FakeGattBatteryPercentageFetcher() = default;
+
+}  // namespace ash
diff --git a/ash/power/fake_gatt_battery_percentage_fetcher.h b/ash/power/fake_gatt_battery_percentage_fetcher.h
new file mode 100644
index 0000000..ae0dc49
--- /dev/null
+++ b/ash/power/fake_gatt_battery_percentage_fetcher.h
@@ -0,0 +1,34 @@
+// Copyright 2019 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 ASH_POWER_FAKE_GATT_BATTERY_PERCENTAGE_FETCHER_H_
+#define ASH_POWER_FAKE_GATT_BATTERY_PERCENTAGE_FETCHER_H_
+
+#include <string>
+
+#include "ash/ash_export.h"
+#include "ash/power/gatt_battery_percentage_fetcher.h"
+#include "base/macros.h"
+
+namespace ash {
+
+// Fake implementation of GattBatteryPercentageFetcher to use in tests.
+class ASH_EXPORT FakeGattBatteryPercentageFetcher
+    : public GattBatteryPercentageFetcher {
+ public:
+  FakeGattBatteryPercentageFetcher(const std::string& device_address,
+                                   BatteryPercentageCallback callback);
+
+  ~FakeGattBatteryPercentageFetcher() override;
+
+  using GattBatteryPercentageFetcher::InvokeCallbackWithFailedFetch;
+  using GattBatteryPercentageFetcher::InvokeCallbackWithSuccessfulFetch;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeGattBatteryPercentageFetcher);
+};
+
+}  // namespace ash
+
+#endif  // ASH_POWER_FAKE_GATT_BATTERY_PERCENTAGE_FETCHER_H_
diff --git a/ash/power/gatt_battery_poller.cc b/ash/power/gatt_battery_poller.cc
new file mode 100644
index 0000000..caa613af
--- /dev/null
+++ b/ash/power/gatt_battery_poller.cc
@@ -0,0 +1,113 @@
+// Copyright 2019 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 "ash/power/gatt_battery_poller.h"
+
+#include "ash/power/gatt_battery_percentage_fetcher.h"
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+
+namespace ash {
+
+namespace {
+
+// Maximum number of consecutive attempts to try reading the battery status.
+// The class stops polling if |current_retry_count_| exceeds this value.
+const int kMaxRetryCount = 3;
+
+// Default interval for polling the device battery value.
+constexpr base::TimeDelta kDefaultPollInterval =
+    base::TimeDelta::FromMinutes(10);
+
+GattBatteryPoller::Factory* g_test_factory_instance = nullptr;
+
+}  // namespace
+
+// static
+void GattBatteryPoller::Factory::SetFactoryForTesting(Factory* factory) {
+  g_test_factory_instance = factory;
+}
+
+// static
+std::unique_ptr<GattBatteryPoller> GattBatteryPoller::Factory::NewInstance(
+    scoped_refptr<device::BluetoothAdapter> adapter,
+    const std::string& device_address,
+    std::unique_ptr<base::OneShotTimer> poll_timer) {
+  if (g_test_factory_instance) {
+    return g_test_factory_instance->BuildInstance(adapter, device_address,
+                                                  std::move(poll_timer));
+  }
+  auto instance = base::WrapUnique(new GattBatteryPoller(device_address));
+  instance->StartFetching(adapter, std::move(poll_timer));
+  return instance;
+}
+
+GattBatteryPoller::GattBatteryPoller(const std::string& device_address)
+    : device_address_(device_address) {}
+
+GattBatteryPoller::~GattBatteryPoller() = default;
+
+void GattBatteryPoller::StartFetching(
+    scoped_refptr<device::BluetoothAdapter> adapter,
+    std::unique_ptr<base::OneShotTimer> poll_timer) {
+  adapter_ = adapter;
+  poll_timer_ = std::move(poll_timer);
+  CreateBatteryFetcher();
+}
+
+void GattBatteryPoller::CreateBatteryFetcher() {
+  DCHECK(!fetcher_);
+  // Creating the fetcher implicitly begins the process of fetching the battery
+  // status.
+  fetcher_ = GattBatteryPercentageFetcher::Factory::NewInstance(
+      adapter_, device_address_,
+      base::BindOnce(&GattBatteryPoller::OnBatteryPercentageFetched,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void GattBatteryPoller::OnBatteryPercentageFetched(
+    base::Optional<uint8_t> battery_percentage) {
+  fetcher_.reset();
+
+  if (battery_percentage) {
+    device::BluetoothDevice* device = adapter_->GetDevice(device_address_);
+    if (device)
+      device->set_battery_percentage(*battery_percentage);
+  }
+
+  ScheduleNextAttempt(battery_percentage.has_value());
+}
+
+void GattBatteryPoller::ScheduleNextAttempt(bool was_last_attempt_successful) {
+  device::BluetoothDevice* device = adapter_->GetDevice(device_address_);
+  // If the device is not present now, it won't be present in the future. Give
+  // up retrying.
+  if (!device)
+    return;
+
+  if (was_last_attempt_successful) {
+    current_retry_count_ = 0;
+    StartNextAttemptTimer();
+    return;
+  }
+
+  ++current_retry_count_;
+  if (current_retry_count_ <= kMaxRetryCount) {
+    StartNextAttemptTimer();
+  } else {
+    // Reset battery field after exceeding the retry count.
+    device->set_battery_percentage(base::nullopt);
+  }
+}
+
+void GattBatteryPoller::StartNextAttemptTimer() {
+  poll_timer_->Start(FROM_HERE, kDefaultPollInterval,
+                     base::BindOnce(&GattBatteryPoller::CreateBatteryFetcher,
+                                    weak_ptr_factory_.GetWeakPtr()));
+}
+
+}  // namespace ash
diff --git a/ash/power/gatt_battery_poller.h b/ash/power/gatt_battery_poller.h
new file mode 100644
index 0000000..e9a33147
--- /dev/null
+++ b/ash/power/gatt_battery_poller.h
@@ -0,0 +1,95 @@
+// Copyright 2019 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 ASH_POWER_GATT_BATTERY_POLLER_H_
+#define ASH_POWER_GATT_BATTERY_POLLER_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "ash/ash_export.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+
+namespace base {
+class OneShotTimer;
+}  // namespace base
+
+namespace device {
+class BluetoothAdapter;
+}  // namespace device
+
+namespace ash {
+
+class GattBatteryPercentageFetcher;
+
+// Gets the battery level of a connected Bluetooth device through the
+// standardized GATT Battery Service. Polling is done periodically and updates
+// the device::BluetoothDevice with the specified |device_address_|.
+class ASH_EXPORT GattBatteryPoller {
+ public:
+  class Factory {
+   public:
+    virtual ~Factory() = default;
+
+    static void SetFactoryForTesting(Factory* factory);
+    static std::unique_ptr<GattBatteryPoller> NewInstance(
+        scoped_refptr<device::BluetoothAdapter> adapter,
+        const std::string& device_address,
+        std::unique_ptr<base::OneShotTimer> poll_timer);
+
+    virtual std::unique_ptr<GattBatteryPoller> BuildInstance(
+        scoped_refptr<device::BluetoothAdapter> adapter,
+        const std::string& device_address,
+        std::unique_ptr<base::OneShotTimer> poll_timer) = 0;
+  };
+
+  virtual ~GattBatteryPoller();
+
+ protected:
+  GattBatteryPoller(const std::string& device_address);
+
+  // Calling this function starts the fetching process. This allows tests to
+  // to create instances of this class without running the whole mechanism.
+  void StartFetching(scoped_refptr<device::BluetoothAdapter> adapter,
+                     std::unique_ptr<base::OneShotTimer> poll_timer);
+
+ private:
+  friend class GattBatteryPollerTest;
+
+  // A GattBatteryPercentageFetcher object is created every time it is needed to
+  // read the battery level.
+  void CreateBatteryFetcher();
+
+  // Callback function to run after the fetcher completes getting the battery.
+  void OnBatteryPercentageFetched(base::Optional<uint8_t> battery_percentage);
+
+  // Schedules the next attempt for reading the battery level. Will stop
+  // scheduling after several consecutive unsuccessful attempts or if the device
+  // is no longer found in the adapter.
+  void ScheduleNextAttempt(bool was_last_attempt_successful);
+
+  // Starts a timer. When time's up, tries to fetch the battery level again.
+  void StartNextAttemptTimer();
+
+  scoped_refptr<device::BluetoothAdapter> adapter_;
+  const std::string device_address_;
+  std::unique_ptr<base::OneShotTimer> poll_timer_;
+  std::unique_ptr<GattBatteryPercentageFetcher> fetcher_;
+
+  // The number of consecutive attempts we have tried to read the battery status
+  // and failed. Resets when the battery is read successfully.
+  int current_retry_count_ = 0;
+
+  base::WeakPtrFactory<GattBatteryPoller> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(GattBatteryPoller);
+};
+
+}  // namespace ash
+
+#endif  // ASH_POWER_GATT_BATTERY_POLLER_H_
diff --git a/ash/power/gatt_battery_poller_unittest.cc b/ash/power/gatt_battery_poller_unittest.cc
new file mode 100644
index 0000000..54dcd81b
--- /dev/null
+++ b/ash/power/gatt_battery_poller_unittest.cc
@@ -0,0 +1,205 @@
+// Copyright 2019 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 "ash/power/gatt_battery_poller.h"
+
+#include "ash/power/fake_gatt_battery_percentage_fetcher.h"
+#include "ash/power/gatt_battery_percentage_fetcher.h"
+#include "base/macros.h"
+#include "base/timer/mock_timer.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/bluetooth/test/mock_bluetooth_device.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using device::BluetoothDevice;
+using testing::NiceMock;
+using testing::Return;
+
+namespace ash {
+namespace {
+
+constexpr char kDeviceAddress[] = "AA:BB:CC:DD:EE:FF";
+const uint8_t kBatteryPercentage = 100;
+
+class FakeGattBatteryFetcherFactory
+    : public GattBatteryPercentageFetcher::Factory {
+ public:
+  FakeGattBatteryFetcherFactory() = default;
+  ~FakeGattBatteryFetcherFactory() override = default;
+
+  FakeGattBatteryPercentageFetcher* last_fake_fetcher() {
+    return last_fake_fetcher_;
+  }
+
+  int fetchers_created_count() { return fetchers_created_count_; }
+
+ private:
+  std::unique_ptr<GattBatteryPercentageFetcher> BuildInstance(
+      scoped_refptr<device::BluetoothAdapter> adapter,
+      const std::string& device_address,
+      GattBatteryPercentageFetcher::BatteryPercentageCallback callback)
+      override {
+    ++fetchers_created_count_;
+    auto instance = std::make_unique<FakeGattBatteryPercentageFetcher>(
+        device_address, std::move(callback));
+    last_fake_fetcher_ = instance.get();
+    return std::move(instance);
+  }
+
+  FakeGattBatteryPercentageFetcher* last_fake_fetcher_ = nullptr;
+
+  int fetchers_created_count_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeGattBatteryFetcherFactory);
+};
+
+}  // namespace
+
+class GattBatteryPollerTest : public testing::Test {
+ public:
+  GattBatteryPollerTest() = default;
+
+  ~GattBatteryPollerTest() override = default;
+
+  void SetUp() override {
+    mock_device_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>(
+        mock_adapter_.get(), 0 /* bluetooth_class */, "device_name",
+        kDeviceAddress, true /* paired */, true /* connected */);
+    ASSERT_FALSE(mock_device_->battery_percentage());
+
+    mock_adapter_ =
+        base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>();
+    ON_CALL(*mock_adapter_, GetDevice(kDeviceAddress))
+        .WillByDefault(Return(mock_device_.get()));
+    device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);
+
+    fake_gatt_battery_fetcher_factory_ =
+        std::make_unique<FakeGattBatteryFetcherFactory>();
+    GattBatteryPercentageFetcher::Factory::SetFactoryForTesting(
+        fake_gatt_battery_fetcher_factory_.get());
+  }
+
+  void TearDown() override {
+    GattBatteryPercentageFetcher::Factory::SetFactoryForTesting(nullptr);
+  }
+
+  void CreateGattBatteryPoller() {
+    auto mock_timer = std::make_unique<base::MockOneShotTimer>();
+    mock_timer_ = mock_timer.get();
+    poller_ = GattBatteryPoller::Factory::NewInstance(
+        mock_adapter_, kDeviceAddress, std::move(mock_timer));
+  }
+
+  FakeGattBatteryPercentageFetcher* last_fake_fetcher() {
+    return fake_gatt_battery_fetcher_factory_->last_fake_fetcher();
+  }
+
+  int fetchers_created_count() {
+    return fake_gatt_battery_fetcher_factory_->fetchers_created_count();
+  }
+
+ protected:
+  scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_;
+  std::unique_ptr<device::MockBluetoothDevice> mock_device_;
+  base::MockOneShotTimer* mock_timer_ = nullptr;
+  std::unique_ptr<FakeGattBatteryFetcherFactory>
+      fake_gatt_battery_fetcher_factory_;
+  std::unique_ptr<GattBatteryPoller> poller_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GattBatteryPollerTest);
+};
+
+TEST_F(GattBatteryPollerTest, PollsTheBatteryAndUpdatesTheBluetoothDevice) {
+  CreateGattBatteryPoller();
+
+  // The poller should have created a fetcher.
+  EXPECT_EQ(1, fetchers_created_count());
+  last_fake_fetcher()->InvokeCallbackWithSuccessfulFetch(kBatteryPercentage);
+
+  // Expect the returned battery value is set in the device.
+  EXPECT_EQ(kBatteryPercentage, mock_device_->battery_percentage());
+}
+
+TEST_F(GattBatteryPollerTest, PollsBatteryAgainAfterSuccess) {
+  CreateGattBatteryPoller();
+  EXPECT_EQ(1, fetchers_created_count());
+  last_fake_fetcher()->InvokeCallbackWithSuccessfulFetch(kBatteryPercentage);
+
+  // Expect the returned battery value is set in the device.
+  EXPECT_EQ(kBatteryPercentage, mock_device_->battery_percentage());
+
+  // The poller should be waiting for the timer timeout.
+  ASSERT_TRUE(mock_timer_->IsRunning());
+  mock_timer_->Fire();
+
+  // A new fetcher should have been created.
+  EXPECT_EQ(2, fetchers_created_count());
+
+  const uint8_t kNewBatteryPercentage = 0;
+  last_fake_fetcher()->InvokeCallbackWithSuccessfulFetch(kNewBatteryPercentage);
+
+  EXPECT_EQ(kNewBatteryPercentage, mock_device_->battery_percentage());
+  EXPECT_TRUE(mock_timer_->IsRunning());
+}
+
+TEST_F(GattBatteryPollerTest, RetryPollingAfterAnError) {
+  CreateGattBatteryPoller();
+  EXPECT_EQ(1, fetchers_created_count());
+  // Simulate the battery level was not fetched.
+  last_fake_fetcher()->InvokeCallbackWithFailedFetch();
+
+  // Battery should not have been set.
+  EXPECT_FALSE(mock_device_->battery_percentage());
+  // Retry logic should schedule a new attempt to read the battery level.
+  ASSERT_TRUE(mock_timer_->IsRunning());
+  mock_timer_->Fire();
+
+  // A new fetcher should have been created.
+  EXPECT_EQ(2, fetchers_created_count());
+  // Battery should not have been set.
+  EXPECT_FALSE(mock_device_->battery_percentage());
+}
+
+TEST_F(GattBatteryPollerTest, DoesNotModifyBatteryValueAfterAnError) {
+  mock_device_->set_battery_percentage(kBatteryPercentage);
+
+  CreateGattBatteryPoller();
+  EXPECT_EQ(1, fetchers_created_count());
+  last_fake_fetcher()->InvokeCallbackWithFailedFetch();
+
+  // Check retry logic is running.
+  EXPECT_TRUE(mock_timer_->IsRunning());
+  // Battery should not have changed.
+  EXPECT_EQ(kBatteryPercentage, mock_device_->battery_percentage());
+}
+
+TEST_F(GattBatteryPollerTest, StopsRetryingAfterMaxRetryCount) {
+  // Set a battery level to the device. Expect it resets after maximum retry
+  // count is exceeded.
+  mock_device_->set_battery_percentage(kBatteryPercentage);
+  CreateGattBatteryPoller();
+
+  const int kMaxRetryCount = 3;
+  for (int i = 1; i <= kMaxRetryCount; ++i) {
+    EXPECT_EQ(i, fetchers_created_count());
+    last_fake_fetcher()->InvokeCallbackWithFailedFetch();
+
+    // Battery should not change.
+    EXPECT_EQ(kBatteryPercentage, mock_device_->battery_percentage());
+    ASSERT_TRUE(mock_timer_->IsRunning());
+    mock_timer_->Fire();
+  }
+
+  EXPECT_EQ(4, fetchers_created_count());
+  last_fake_fetcher()->InvokeCallbackWithFailedFetch();
+
+  // Check retry logic is not running.
+  EXPECT_FALSE(mock_timer_->IsRunning());
+  // Battery should reset.
+  EXPECT_FALSE(mock_device_->battery_percentage());
+}
+
+}  // namespace ash
diff --git a/ash/public/cpp/app_list/app_list_config.cc b/ash/public/cpp/app_list/app_list_config.cc
index 610bf4e3..3882eb6 100644
--- a/ash/public/cpp/app_list/app_list_config.cc
+++ b/ash/public/cpp/app_list/app_list_config.cc
@@ -7,6 +7,7 @@
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/macros.h"
 #include "base/no_destructor.h"
+#include "chromeos/constants/chromeos_switches.h"
 #include "ui/gfx/color_palette.h"
 
 namespace app_list {
@@ -59,7 +60,8 @@
       grid_tile_spacing_in_folder_(8),
       // TODO(manucornet): Share the value with ShelfConstants and use
       // 48 when the new shelf UI is turned off.
-      shelf_height_(56),
+      shelf_height_(chromeos::switches::ShouldShowShelfDenseClamshell() ? 48
+                                                                        : 56),
       background_radius_(shelf_height_ / 2),
       blur_radius_(30),
       contents_background_color_(SkColorSetRGB(0xF2, 0xF2, 0xF2)),
diff --git a/ash/shelf/home_button_unittest.cc b/ash/shelf/home_button_unittest.cc
index ac2a066..7755e82b 100644
--- a/ash/shelf/home_button_unittest.cc
+++ b/ash/shelf/home_button_unittest.cc
@@ -152,7 +152,8 @@
 
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   test_api.RunMessageLoopUntilAnimationsDone();
-  EXPECT_EQ(ShelfConstants::button_spacing(), home_button()->bounds().x());
+  EXPECT_EQ(ShelfConstants::home_button_edge_spacing(),
+            home_button()->bounds().x());
 }
 
 TEST_F(HomeButtonTest, LongPressGesture) {
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index e899682f..87e1d7b 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -90,18 +90,22 @@
 
 // The margins of the button contents.
 constexpr int kButtonMarginTopDp = 18;
+constexpr int kButtonMarginTopDpDense = 16;
 constexpr int kButtonMarginLeftDp = 18;
 constexpr int kButtonMarginBottomDp = 18;
+constexpr int kButtonMarginBottomDpDense = 16;
 constexpr int kButtonMarginRightDp = 16;
 
 // The margins of the button background.
 constexpr gfx::Insets kButtonBackgroundMargin(8, 8, 8, 0);
+constexpr gfx::Insets kButtonBackgroundMarginDense(6, 8, 6, 0);
 
 // Spacing between the button image and label.
 constexpr int kImageLabelSpacingDp = 10;
 
 // The border radius of the button background.
 constexpr int kButtonRoundedBorderRadiusDp = 20;
+constexpr int kButtonRoundedBorderRadiusDpDense = 18;
 
 // The color of the button background.
 constexpr SkColor kButtonBackgroundColor =
@@ -117,10 +121,14 @@
   auto path = std::make_unique<SkPath>();
 
   gfx::Rect rect(view->GetLocalBounds());
-  rect.Inset(kButtonBackgroundMargin);
+  rect.Inset(chromeos::switches::ShouldShowShelfDenseClamshell()
+                 ? kButtonBackgroundMarginDense
+                 : kButtonBackgroundMargin);
 
-  path->addRoundRect(gfx::RectToSkRect(rect), kButtonRoundedBorderRadiusDp,
-                     kButtonRoundedBorderRadiusDp);
+  int border_radius = chromeos::switches::ShouldShowShelfDenseClamshell()
+                          ? kButtonRoundedBorderRadiusDpDense
+                          : kButtonRoundedBorderRadiusDp;
+  path->addRoundRect(gfx::RectToSkRect(rect), border_radius, border_radius);
   return path;
 }
 
@@ -175,8 +183,14 @@
 
   // views::LabelButton:
   gfx::Insets GetInsets() const override {
-    return gfx::Insets(kButtonMarginTopDp, kButtonMarginLeftDp,
-                       kButtonMarginBottomDp, kButtonMarginRightDp);
+    int top_margin = chromeos::switches::ShouldShowShelfDenseClamshell()
+                         ? kButtonMarginTopDpDense
+                         : kButtonMarginTopDp;
+    int bottom_margin = chromeos::switches::ShouldShowShelfDenseClamshell()
+                            ? kButtonMarginBottomDpDense
+                            : kButtonMarginBottomDp;
+    return gfx::Insets(top_margin, kButtonMarginLeftDp, bottom_margin,
+                       kButtonMarginRightDp);
   }
 
   const char* GetClassName() const override {
diff --git a/ash/shelf/shelf_constants.h b/ash/shelf/shelf_constants.h
index f023a4e..18fd6dc 100644
--- a/ash/shelf/shelf_constants.h
+++ b/ash/shelf/shelf_constants.h
@@ -17,12 +17,15 @@
 // Size of the shelf when visible (height when the shelf is horizontal and
 // width when the shelf is vertical).
 constexpr int kShelfSize = 56;
+constexpr int kShelfSizeDense = 48;
 
 // Size of the icons within shelf buttons.
 constexpr int kShelfButtonIconSize = 44;
+constexpr int kShelfButtonIconSizeDense = 36;
 
 // Size for controls like the home button, back button, etc.
 constexpr int kShelfControlSize = 40;
+constexpr int kShelfControlSizeDense = 36;
 
 ASH_EXPORT constexpr SkColor kShelfControlPermanentHighlightBackground =
     SkColorSetA(SK_ColorWHITE, 26);  // 10%
@@ -51,13 +54,20 @@
 
 // Size allocated for each app button on the shelf.
 ASH_EXPORT constexpr int kShelfButtonSize = kShelfSize;
+ASH_EXPORT constexpr int kShelfButtonSizeDense = kShelfSizeDense;
 
 // Size of the space between buttons on the shelf.
 ASH_EXPORT constexpr int kShelfButtonSpacing = 8;
 
+// Size of the space between edge of screen and home button.
+ASH_EXPORT constexpr int kShelfHomeButtonEdgeSpacing = 8;
+ASH_EXPORT constexpr int kShelfHomeButtonEdgeSpacingDense = 6;
+
 // The margin around the overflow button on the shelf.
 constexpr int kShelfOverflowButtonMargin =
     (kShelfButtonSize - kShelfControlSize) / 2;
+constexpr int kShelfOverflowButtonMarginDense =
+    (kShelfButtonSizeDense - kShelfControlSizeDense) / 2;
 
 // Ink drop color for shelf items.
 constexpr SkColor kShelfInkDropBaseColor = SK_ColorWHITE;
@@ -97,30 +107,55 @@
  public:
   // Size of the shelf when visible (height when the shelf is horizontal and
   // width when the shelf is vertical).
-  static int shelf_size() { return kShelfSize; }
+  static int shelf_size() {
+    return UseNewDenseShelfUi() ? kShelfSizeDense : kShelfSize;
+  }
 
   // Size allocated for each app button on the shelf.
-  static int button_size() { return kShelfButtonSize; }
+  static int button_size() {
+    return UseNewDenseShelfUi() ? kShelfButtonSizeDense : kShelfButtonSize;
+  }
 
   // Size of the space between buttons on the shelf.
   static int button_spacing() { return kShelfButtonSpacing; }
 
   // Size of the icons within shelf buttons.
-  static int button_icon_size() { return kShelfButtonIconSize; }
+  static int button_icon_size() {
+    return UseNewDenseShelfUi() ? kShelfButtonIconSizeDense
+                                : kShelfButtonIconSize;
+  }
 
   // Size for controls like the home button, back button, etc.
-  static int control_size() { return kShelfControlSize; }
+  static int control_size() {
+    return UseNewDenseShelfUi() ? kShelfControlSizeDense : kShelfControlSize;
+  }
 
   // The radius of shelf control buttons.
-  static int control_border_radius() { return kShelfControlSize / 2; }
+  static int control_border_radius() { return control_size() / 2; }
 
-  static int overflow_button_margin() { return kShelfOverflowButtonMargin; }
+  static int overflow_button_margin() {
+    return UseNewDenseShelfUi() ? kShelfOverflowButtonMarginDense
+                                : kShelfOverflowButtonMargin;
+  }
 
   // The distance between the edge of the shelf and the status indicators.
   static int status_indicator_offset_from_edge() {
     return kStatusIndicatorOffsetFromShelfEdge;
   }
 
+  // The distance between the edge of the shelf and the home and back button.
+  static int home_button_edge_spacing() {
+    return UseNewDenseShelfUi() ? kShelfHomeButtonEdgeSpacingDense
+                                : kShelfHomeButtonEdgeSpacing;
+  }
+
+ private:
+  static bool UseNewDenseShelfUi() {
+    static bool use_new_dense_shelf_ui =
+        chromeos::switches::ShouldShowShelfDenseClamshell();
+    return use_new_dense_shelf_ui;
+  }
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(ShelfConstants);
 };
 
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index c8f9b9b..4265f3d 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -644,14 +644,6 @@
   gfx::Point new_point(edge_to_show);
   gfx::Vector2d diff = edge_to_hide - edge_to_show;
   new_point.Offset(diff.x() * 3 / 10, diff.y() * 3 / 10);
-  /*
-  if (shelf->IsHorizontalAlignment())
-    end.set_y(start.y() + shelf_shown.height() * 3 / 10);
-  else if (SHELF_ALIGNMENT_LEFT == shelf->alignment())
-    end.set_x(start.x() - shelf_shown.width() * 3 / 10);
-  else if (SHELF_ALIGNMENT_RIGHT == shelf->alignment())
-    end.set_x(start.x() + shelf_shown.width() * 3 / 10);
-  */
   generator->GestureScrollSequence(edge_to_show, new_point, kTimeDelta, 5);
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 2e9f451..0d27eb7 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -1009,7 +1009,7 @@
       padding_for_centering = (screen_size - icons_size) / 2;
     } else {
       padding_for_centering =
-          button_spacing +
+          ShelfConstants::home_button_edge_spacing() +
           (IsTabletModeEnabled() ? 2 : 1) * ShelfConstants::control_size() +
           (IsTabletModeEnabled() ? button_spacing : 0) + kAppIconGroupMargin +
           (available_size_for_app_icons - icons_size) / 2;
@@ -1115,17 +1115,18 @@
     back_and_app_list_background_->SetVisible(false);
     return;
   }
-  const int button_spacing = ShelfConstants::button_spacing();
+  const int edge_spacing = ShelfConstants::home_button_edge_spacing();
   // "Secondary" as in "orthogonal to the shelf primary axis".
   const int control_secondary_padding =
       (ShelfConstants::shelf_size() - ShelfConstants::control_size()) / 2;
   const int back_and_app_list_background_size =
       ShelfConstants::control_size() +
-      (IsTabletModeEnabled() ? ShelfConstants::control_size() + button_spacing
-                             : 0);
+      (IsTabletModeEnabled()
+           ? ShelfConstants::control_size() + ShelfConstants::button_spacing()
+           : 0);
   back_and_app_list_background_->SetBounds(
-      shelf()->PrimaryAxisValue(button_spacing, control_secondary_padding),
-      shelf()->PrimaryAxisValue(control_secondary_padding, button_spacing),
+      shelf()->PrimaryAxisValue(edge_spacing, control_secondary_padding),
+      shelf()->PrimaryAxisValue(control_secondary_padding, edge_spacing),
       shelf()->PrimaryAxisValue(back_and_app_list_background_size,
                                 ShelfConstants::control_size()),
       shelf()->PrimaryAxisValue(ShelfConstants::control_size(),
@@ -1144,7 +1145,8 @@
 int ShelfView::GetAvailableSpaceForAppIcons() const {
   // Subtract space already allocated to the home button, and the back
   // button if applicable.
-  return shelf()->PrimaryAxisValue(width(), height()) - kShelfButtonSpacing -
+  return shelf()->PrimaryAxisValue(width(), height()) -
+         ShelfConstants::home_button_edge_spacing() -
          (IsTabletModeEnabled() ? 2 : 1) * ShelfConstants::control_size() -
          (IsTabletModeEnabled() ? ShelfConstants::button_spacing() : 0) -
          2 * kAppIconGroupMargin;
@@ -1167,9 +1169,10 @@
   const int control_size = ShelfConstants::control_size();
   const int button_size = ShelfConstants::button_size();
   const int button_spacing = ShelfConstants::button_spacing();
+  const int edge_spacing = ShelfConstants::home_button_edge_spacing();
 
-  int x = shelf()->PrimaryAxisValue(button_spacing, 0);
-  int y = shelf()->PrimaryAxisValue(0, button_spacing);
+  int x = shelf()->PrimaryAxisValue(edge_spacing, 0);
+  int y = shelf()->PrimaryAxisValue(0, edge_spacing);
 
   GetBackButton()->set_ideal_bounds(
       gfx::Rect(x, y, shelf()->PrimaryAxisValue(control_size, button_size),
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 68c4308..9b193f5e 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -43,7 +43,6 @@
 namespace ash {
 namespace {
 
-constexpr int kShelfRoundedCornerRadius = 28;
 constexpr int kShelfBlurRadius = 30;
 // The maximum size of the opaque layer during an "overshoot" (drag away from
 // the screen edge).
@@ -225,7 +224,7 @@
   // when dragged away.
   // To achieve this, we extend the layer in the same direction where the shelf
   // is aligned (downwards for a bottom shelf, etc.).
-  const int radius = kShelfRoundedCornerRadius;
+  const int radius = ShelfConstants::shelf_size() / 2;
   // We can easily round only 2 corners out of 4 which means we don't need as
   // much extra shelf height.
   const int safety_margin = kShelfMaxOvershootHeight;
diff --git a/ash/system/status_area_widget_delegate.cc b/ash/system/status_area_widget_delegate.cc
index 73070d4..4db09b37 100644
--- a/ash/system/status_area_widget_delegate.cc
+++ b/ash/system/status_area_widget_delegate.cc
@@ -25,6 +25,8 @@
 
 constexpr int kPaddingBetweenWidgetsNewUi = 8;
 
+constexpr int kPaddingBetweenWidgetAndRightScreenEdge = 6;
+
 class StatusAreaWidgetDelegateAnimationSettings
     : public ui::ScopedLayerAnimationSettings {
  public:
@@ -125,13 +127,15 @@
   views::GridLayout* layout =
       SetLayoutManager(std::make_unique<views::GridLayout>());
 
-  // Update tray border based on layout.
-  bool is_child_on_edge = true;
+  const auto it = std::find_if(children().crbegin(), children().crend(),
+                               [](const View* v) { return v->GetVisible(); });
+  const View* last_visible_child = it == children().crend() ? nullptr : *it;
+
+  // Set the border for each child, with a different border for the edge child.
   for (auto* child : children()) {
     if (!child->GetVisible())
       continue;
-    SetBorderOnChild(child, is_child_on_edge);
-    is_child_on_edge = false;
+    SetBorderOnChild(child, last_visible_child == child);
   }
 
   views::ColumnSet* columns = layout->AddColumnSet(0);
@@ -184,7 +188,7 @@
 }
 
 void StatusAreaWidgetDelegate::SetBorderOnChild(views::View* child,
-                                                bool extend_border_to_edge) {
+                                                bool is_child_on_edge) {
   const int vertical_padding =
       (ShelfConstants::shelf_size() - kTrayItemSize) / 2;
 
@@ -195,6 +199,8 @@
   // Add some extra space so that borders don't overlap. This padding between
   // items also takes care of padding at the edge of the shelf.
   int right_edge = kPaddingBetweenWidgetsNewUi;
+  if (is_child_on_edge && chromeos::switches::ShouldShowShelfDenseClamshell())
+    right_edge = kPaddingBetweenWidgetAndRightScreenEdge;
 
   // Swap edges if alignment is not horizontal (bottom-to-top).
   if (!shelf_->IsHorizontalAlignment()) {
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index cee0639..da70b157 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -72,7 +72,7 @@
   gfx::Insets insets;
   // "Primary" is the same direction as the shelf, "secondary" is orthogonal.
   const int primary_padding = 0;
-  const int secondary_padding = -ash::kHitRegionPadding;
+  const int secondary_padding = -ash::TrayConstants::hit_region_padding();
 
   if (is_shelf_horizontal) {
     insets.Set(secondary_padding, primary_padding, secondary_padding,
diff --git a/ash/system/tray/tray_constants.cc b/ash/system/tray/tray_constants.cc
index 36fadb71..687f461d 100644
--- a/ash/system/tray/tray_constants.cc
+++ b/ash/system/tray/tray_constants.cc
@@ -66,6 +66,7 @@
     kMenuExtraMarginFromLeftEdge + (kMenuButtonSize - kMenuIconSize) / 2;
 
 const int kHitRegionPadding = 4;
+const int kHitRegionPaddingDense = 2;
 
 const SkColor kMenuSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F);
 
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index ad5e228..d1807bb 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -82,6 +82,7 @@
 
 // Extra padding used to adjust hitting region around tray items.
 extern const int kHitRegionPadding;
+extern const int kHitRegionPaddingDense;
 
 // Width of lines used to separate menu items (e.g. input method menu).
 constexpr int kMenuSeparatorWidth = 1;
@@ -186,7 +187,7 @@
 constexpr int kUnifiedTraySpacingBetweenIcons = 6;
 constexpr int kUnifiedTrayBatteryWidth = 10;
 constexpr int kUnifiedTrayCornerRadius = 20;
-constexpr int kUnifiedTrayContentPadding = 8;
+constexpr int kUnifiedTrayContentPadding = 12;
 constexpr int kUnifiedTopShortcutSpacing = 16;
 constexpr int kUnifiedNotificationHiddenLineHeight = 20;
 constexpr int kUnifiedTopShortcutContainerTopPadding = 12;
@@ -274,6 +275,22 @@
 constexpr gfx::Insets kUnifiedDetailedViewTitlePadding(0, 0, 0, 16);
 constexpr int kUnifiedDetailedViewTitleRowHeight = 64;
 
+class TrayConstants {
+ public:
+  static int hit_region_padding() {
+    return UseNewDenseShelfUi() ? kHitRegionPaddingDense : kHitRegionPadding;
+  }
+
+ private:
+  static bool UseNewDenseShelfUi() {
+    static bool use_new_dense_shelf_ui =
+        chromeos::switches::ShouldShowShelfDenseClamshell();
+    return use_new_dense_shelf_ui;
+  }
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(TrayConstants);
+};
+
 }  // namespace ash
 
 #endif  // ASH_SYSTEM_TRAY_TRAY_CONSTANTS_H_
diff --git a/ash/system/tray/tray_container.cc b/ash/system/tray/tray_container.cc
index 8168df5..23c9f35 100644
--- a/ash/system/tray/tray_container.cc
+++ b/ash/system/tray/tray_container.cc
@@ -73,8 +73,9 @@
       is_horizontal ? views::BoxLayout::Orientation::kHorizontal
                     : views::BoxLayout::Orientation::kVertical;
 
-  gfx::Insets insets(is_horizontal ? gfx::Insets(0, kHitRegionPadding)
-                                   : gfx::Insets(kHitRegionPadding, 0));
+  gfx::Insets insets(is_horizontal
+                         ? gfx::Insets(0, TrayConstants::hit_region_padding())
+                         : gfx::Insets(TrayConstants::hit_region_padding(), 0));
   SetBorder(views::CreateEmptyBorder(insets));
 
   int horizontal_margin = main_axis_margin_;
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc
index 90673a3..e9d9ae3 100644
--- a/ash/system/unified/unified_system_tray.cc
+++ b/ash/system/unified/unified_system_tray.cc
@@ -133,7 +133,8 @@
       notification_counter_item_(new NotificationCounterView(shelf)),
       quiet_mode_view_(new QuietModeView(shelf)),
       time_view_(new tray::TimeTrayItemView(shelf)) {
-  tray_container()->SetMargin(kUnifiedTrayContentPadding, 0);
+  tray_container()->SetMargin(
+      kUnifiedTrayContentPadding - TrayConstants::hit_region_padding(), 0);
   tray_container()->AddChildView(current_locale_view_);
   tray_container()->AddChildView(ime_mode_view_);
   tray_container()->AddChildView(managed_device_view_);
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 6d185db..94a3b28 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -308,8 +308,6 @@
     "guid.h",
     "hash/hash.cc",
     "hash/hash.h",
-    "hash/sha1.cc",
-    "hash/sha1.h",
     "immediate_crash.h",
     "ios/block_types.h",
     "ios/crb_protocol_observers.h",
@@ -1593,16 +1591,19 @@
     "hash/md5.h",
     "hash/md5_constexpr.h",
     "hash/md5_constexpr_internal.h",
+    "hash/sha1.h",
   ]
   if (is_nacl) {
     sources += [
       "hash/md5_nacl.cc",
       "hash/md5_nacl.h",
+      "hash/sha1.cc",
     ]
   } else {
     sources += [
       "hash/md5_boringssl.cc",
       "hash/md5_boringssl.h",
+      "hash/sha1_boringssl.cc",
     ]
     public_deps += [ "//third_party/boringssl" ]
   }
@@ -2222,6 +2223,7 @@
 
 test("base_perftests") {
   sources = [
+    "hash/sha1_perftest.cc",
     "message_loop/message_pump_perftest.cc",
     "observer_list_perftest.cc",
     "strings/string_util_perftest.cc",
diff --git a/base/android/build_info.cc b/base/android/build_info.cc
index 38777a2..82bc16a 100644
--- a/base/android/build_info.cc
+++ b/base/android/build_info.cc
@@ -76,7 +76,8 @@
       custom_themes_(StrDupParam(params, 19)),
       resources_version_(StrDupParam(params, 20)),
       extracted_file_suffix_(params[21]),
-      is_at_least_q_(GetIntParam(params, 22)) {}
+      is_at_least_q_(GetIntParam(params, 22)),
+      is_debug_android_(GetIntParam(params, 23)) {}
 
 // static
 BuildInfo* BuildInfo::GetInstance() {
diff --git a/base/android/build_info.h b/base/android/build_info.h
index 96be7ee..3904b6c0 100644
--- a/base/android/build_info.h
+++ b/base/android/build_info.h
@@ -124,6 +124,8 @@
 
   bool is_at_least_q() const { return is_at_least_q_; }
 
+  bool is_debug_android() const { return is_debug_android_; }
+
  private:
   friend struct BuildInfoSingletonTraits;
 
@@ -157,6 +159,7 @@
   // Not needed by breakpad.
   const std::string extracted_file_suffix_;
   const bool is_at_least_q_;
+  const bool is_debug_android_;
 
   DISALLOW_COPY_AND_ASSIGN(BuildInfo);
 };
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index c625211..e21b2477 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -335,6 +335,12 @@
             }
         }
         ImageViewCompat.setImageTintList(view, tintList);
+
+        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
+            // Work around that the tint list is not cleared when setting tint list to null on L in
+            // some cases. See https://crbug.com/983686.
+            if (tintList == null) view.refreshDrawableState();
+        }
     }
 
     /**
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
index 969d2410e..ccee0f5b 100644
--- a/base/android/java/src/org/chromium/base/BuildInfo.java
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -83,6 +83,7 @@
                 buildInfo.resourcesVersion,
                 buildInfo.extractedFileSuffix,
                 isAtLeastQ() ? "1" : "0",
+                isDebugAndroid() ? "1" : "0",
         };
     }
 
diff --git a/base/hash/sha1_boringssl.cc b/base/hash/sha1_boringssl.cc
new file mode 100644
index 0000000..53eafbc
--- /dev/null
+++ b/base/hash/sha1_boringssl.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2019 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 "base/hash/sha1.h"
+
+#include <stdint.h>
+
+#include "base/strings/string_util.h"
+#include "third_party/boringssl/src/include/openssl/crypto.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
+
+namespace base {
+
+void SHA1HashBytes(const unsigned char* data, size_t len, unsigned char* hash) {
+  CRYPTO_library_init();
+  SHA1(data, len, hash);
+}
+
+std::string SHA1HashString(const std::string& str) {
+  CRYPTO_library_init();
+  std::string digest;
+  SHA1(reinterpret_cast<const uint8_t*>(str.data()), str.size(),
+       reinterpret_cast<uint8_t*>(base::WriteInto(&digest, kSHA1Length + 1)));
+  return digest;
+}
+
+}  // namespace base
diff --git a/base/hash/sha1_perftest.cc b/base/hash/sha1_perftest.cc
new file mode 100644
index 0000000..fe75d158
--- /dev/null
+++ b/base/hash/sha1_perftest.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2019 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 "base/hash/sha1.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+static void Timing(const size_t len) {
+  std::vector<uint8_t> buf(len);
+  base::RandBytes(buf.data(), len);
+
+  const int runs = 111;
+  std::vector<base::TimeDelta> utime(runs);
+  unsigned char digest[base::kSHA1Length];
+  memset(digest, 0, base::kSHA1Length);
+
+  double total_test_time = 0.0;
+  for (int i = 0; i < runs; ++i) {
+    auto start = base::TimeTicks::Now();
+    base::SHA1HashBytes(buf.data(), len, digest);
+    auto end = base::TimeTicks::Now();
+    utime[i] = end - start;
+    total_test_time += utime[i].InMicroseconds();
+  }
+
+  std::sort(utime.begin(), utime.end());
+  const int med = runs / 2;
+  const int min = 0;
+
+  // No need for conversions as length is in bytes and time in usecs:
+  // MB/s = (len / (bytes/megabytes)) / (usecs / usecs/sec)
+  // MB/s = (len / 1,000,000)/(usecs / 1,000,000)
+  // MB/s = (len * 1,000,000)/(usecs * 1,000,000)
+  // MB/s = len/utime
+  double median_rate = len / utime[med].InMicroseconds();
+  double max_rate = len / utime[min].InMicroseconds();
+
+  perf_test::PrintResult("len=", base::NumberToString(len), "median",
+                         median_rate, "MB/s", true);
+  perf_test::PrintResult("usecs=", base::NumberToString(total_test_time), "max",
+                         max_rate, "MB/s", true);
+}
+
+TEST(SHA1PerfTest, Speed) {
+  Timing(1024 * 1024U >> 1);
+  Timing(1024 * 1024U >> 5);
+  Timing(1024 * 1024U >> 6);
+  Timing(1024 * 1024U >> 7);
+}
diff --git a/build/android/list_class_verification_failures.py b/build/android/list_class_verification_failures.py
index e540465..5ff5adc 100755
--- a/build/android/list_class_verification_failures.py
+++ b/build/android/list_class_verification_failures.py
@@ -219,7 +219,6 @@
 
 
 def main():
-  devil_chromium.Initialize()
   parser = argparse.ArgumentParser(description="""
 List Java classes in an APK which fail ART class verification.
 """)
@@ -262,7 +261,7 @@
   logging_common.AddLoggingArguments(parser)
 
   args = parser.parse_args()
-  script_common.InitializeEnvironment(args)
+  devil_chromium.Initialize(adb_path=args.adb_path)
   logging_common.InitializeLogging(args)
 
   if args.workdir:
diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py
index 2a277e1..38c28832 100755
--- a/build/mac/find_sdk.py
+++ b/build/mac/find_sdk.py
@@ -84,11 +84,7 @@
   sdk_dir = os.path.join(
       dev_dir, 'Platforms/MacOSX.platform/Developer/SDKs')
 
-  # Xcode must be installed, its license agreement must be accepted, and its
-  # command-line tools must be installed. Stand-alone installations (in
-  # /Library/Developer/CommandLineTools) are not supported.
-  # https://bugs.chromium.org/p/chromium/issues/detail?id=729990#c1
-  if not os.path.isdir(sdk_dir) or not '.app/Contents/Developer' in sdk_dir:
+  if not os.path.isdir(sdk_dir):
     raise SdkError('Install Xcode, launch it, accept the license ' +
       'agreement, and run `sudo xcode-select -s /path/to/Xcode.app` ' +
       'to continue.')
diff --git a/build/mac_toolchain.py b/build/mac_toolchain.py
index ea264a2f..aed58896 100755
--- a/build/mac_toolchain.py
+++ b/build/mac_toolchain.py
@@ -11,6 +11,7 @@
   * Accepts the license.
     * If xcode-select and xcodebuild are not passwordless in sudoers, requires
       user interaction.
+  * Downloads standalone binaries from [a possibly different version of Xcode].
 
 The toolchain version can be overridden by setting MAC_TOOLCHAIN_REVISION with
 the full revision, e.g. 9A235.
@@ -19,7 +20,9 @@
 from __future__ import print_function
 
 import os
+import pkg_resources
 import platform
+import plistlib
 import shutil
 import subprocess
 import sys
@@ -27,8 +30,19 @@
 
 # This can be changed after running:
 #    mac_toolchain upload -xcode-path path/to/Xcode.app
+# The hermetic install of Xcode is used:
+#  1) For sizes support
+#  2) To build clang
+#  3) For code-coverage support.
+# These should eventually be phased out to use the new deployment of
+# xcode_binaries, see InstallXcodeBinaries. https://crbug.com/984746
 MAC_TOOLCHAIN_VERSION = '9E501'
 
+# This contains binaries from Xcode 9.3.1, along with the 10.13 SDK.
+# To build this package, see comments in build/xcode_binaries.yaml
+MAC_BINARIES_LABEL = 'infra_internal/ios/xcode/xcode_binaries/mac-amd64'
+MAC_BINARIES_TAG = 'oXeIQqw4E0pXIStoixHwKg_1TJZTJGhfhmn2fq8LPOAC'
+
 # The toolchain will not be downloaded if the minimum OS version is not met.
 # 17 is the major version number for macOS 10.13.
 # 9E145 (Xcode 9.3) only runs on 10.13.2 and newer.
@@ -129,6 +143,69 @@
   return True
 
 
+def InstallXcodeBinaries():
+  """Installs the Xcode binaries needed to build Chrome and accepts the license.
+
+  This is the replacement for InstallXcode that installs a trimmed down version
+  of Xcode that is OS-version agnostic.
+  """
+  # First make sure the directory exists. It will serve as the cipd root. This
+  # also ensures that there will be no conflicts of cipd root.
+  binaries_root = os.path.join(TOOLCHAIN_ROOT, 'xcode_binaries')
+  if not os.path.exists(binaries_root):
+    os.mkdir(binaries_root)
+
+  # 'cipd ensure' is idempotent.
+  args = [
+      'cipd', 'ensure', '-root', binaries_root, '-ensure-file', '-'
+  ]
+  p = subprocess.Popen(args, stdin=subprocess.PIPE)
+  p.communicate(input=MAC_BINARIES_LABEL + ' ' + MAC_BINARIES_TAG)
+
+  # Accept the license for this version of Xcode if it's newer than the
+  # currently accepted version.
+  cipd_xcode_version_plist_path = os.path.join(
+      binaries_root, 'Contents/version.plist')
+  cipd_xcode_version_plist = plistlib.readPlist(cipd_xcode_version_plist_path)
+  cipd_xcode_version = cipd_xcode_version_plist['CFBundleShortVersionString']
+
+  cipd_license_path = os.path.join(
+      binaries_root, 'Contents/Resources/LicenseInfo.plist')
+  cipd_license_plist = plistlib.readPlist(cipd_license_path)
+  cipd_license_version = cipd_license_plist['licenseID']
+
+  should_overwrite_license = True
+  current_license_path = '/Library/Preferences/com.apple.dt.Xcode.plist'
+  if os.path.exists(current_license_path):
+    current_license_plist = plistlib.readPlist(current_license_path)
+    xcode_version = current_license_plist['IDEXcodeVersionForAgreedToGMLicense']
+    if (pkg_resources.parse_version(xcode_version) >=
+        pkg_resources.parse_version(cipd_xcode_version)):
+      should_overwrite_license = False
+
+  if not should_overwrite_license:
+    return
+
+  # Use puppet's sudoers script to accept the license if its available.
+  license_accept_script = '/usr/local/bin/xcode_accept_license.py'
+  if os.path.exists(license_accept_script):
+    args = ['sudo', license_accept_script, '--xcode_version',
+            cipd_xcode_version, '--license-version', cipd_license_version]
+    subprocess.call(args)
+    return
+
+  # Otherwise manually accept the license. This will prompt for sudo.
+  print('Accepting new Xcode license.')
+  args = ['sudo', 'defaults', 'write', current_license_path,
+          'IDEXcodeVersionForAgreedToGMLicense', cipd_xcode_version]
+  subprocess.call(args)
+  args = ['sudo', 'defaults', 'write', current_license_path,
+          'IDELastGMLicenseAgreedTo', cipd_license_version]
+  subprocess.call(args)
+  args = ['sudo', 'plutil', '-convert', 'xml1', current_license_path]
+  subprocess.call(args)
+
+
 def main():
   if sys.platform != 'darwin':
     return 0
@@ -166,6 +243,8 @@
   if not success:
     return 1
 
+  InstallXcodeBinaries()
+
   return 0
 
 
diff --git a/build/toolchain/toolchain.gni b/build/toolchain/toolchain.gni
index 5101f6e..ede0b024 100644
--- a/build/toolchain/toolchain.gni
+++ b/build/toolchain/toolchain.gni
@@ -36,8 +36,14 @@
 
 # The path to the hermetic install of Xcode. Only relevant when
 # use_system_xcode = false.
-hermetic_xcode_path =
-    rebase_path("//build/${target_os}_files/Xcode.app", "", root_build_dir)
+if (is_ios) {
+  hermetic_xcode_path =
+      rebase_path("//build/${target_os}_files/Xcode.app", "", root_build_dir)
+} else {
+  hermetic_xcode_path = rebase_path("//build/${target_os}_files/xcode_binaries",
+                                    "",
+                                    root_build_dir)
+}
 
 declare_args() {
   if (is_clang) {
diff --git a/build/xcode_binaries.yaml b/build/xcode_binaries.yaml
new file mode 100644
index 0000000..3f7854a
--- /dev/null
+++ b/build/xcode_binaries.yaml
@@ -0,0 +1,36 @@
+# This yaml file is used to package binaries from Xcode.app.
+# To use this:
+#   1) Move Xcode.app to the same directory as this file.
+#   2) Rename Xcode.app to xcode_binaries
+#   3) Call `cipd create --pkg-def xcode_binaries.yaml`
+# To deploy the newly created cipd package across the fleet, modify
+# mac_toolchain.py to point to the new cipd hash.
+#
+# The ACLs for this package are determined by the directory structure. The
+# nomenclature mirrors that of the hermetic toolchain to avoid ACL duplication.
+package: infra_internal/ios/xcode/xcode_binaries/mac-amd64
+description: A hermetic deployment of all Xcode binaries used to build Chromium.
+root: "xcode_binaries"
+data:
+  - dir: Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
+  - dir: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/share/bison
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/bison
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/gm4
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/gperf
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/llvm-nm
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/llvm-objdump
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/llvm-otool
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/mig
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/nm
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/otool
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/size
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libtapi.dylib
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libswiftDemangle.dylib
+  - file: Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/libexec/migcom
+  - file: Contents/Resources/English.lproj/License.rtf
+  - file: Contents/Resources/LicenseInfo.plist
+  - file: Contents/version.plist
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 3870fa2..c7fa5fa 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -134,7 +134,7 @@
   ImageInvalidationResult InvalidateRegionForImages(
       const PaintImageIdFlatSet& images_to_invalidate);
 
-  bool RasterSourceUsesLCDTextForTesting() const { return can_use_lcd_text_; }
+  bool can_use_lcd_text() const { return can_use_lcd_text_; }
 
   const Region& InvalidationForTesting() const { return invalidation_; }
 
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 698fa42..60862954 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -4934,7 +4934,7 @@
       FakeRasterSource::CreateFilledLCD(layer_bounds);
   SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region());
 
-  EXPECT_TRUE(pending_layer()->RasterSourceUsesLCDTextForTesting());
+  EXPECT_TRUE(pending_layer()->can_use_lcd_text());
   EXPECT_TRUE(pending_layer()->HighResTiling()->has_tiles());
   std::vector<Tile*> tiles =
       pending_layer()->HighResTiling()->AllTilesForTesting();
@@ -4942,7 +4942,7 @@
   pending_layer()->SetContentsOpaque(false);
   pending_layer()->UpdateCanUseLCDTextAfterCommit();
 
-  EXPECT_FALSE(pending_layer()->RasterSourceUsesLCDTextForTesting());
+  EXPECT_FALSE(pending_layer()->can_use_lcd_text());
   EXPECT_TRUE(pending_layer()->HighResTiling()->has_tiles());
   std::vector<Tile*> new_tiles =
       pending_layer()->HighResTiling()->AllTilesForTesting();
diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h
index d11f49a..533cade 100644
--- a/cc/paint/display_item_list.h
+++ b/cc/paint/display_item_list.h
@@ -165,6 +165,7 @@
 
   int NumSlowPaths() const { return paint_op_buffer_.numSlowPaths(); }
   bool HasNonAAPaint() const { return paint_op_buffer_.HasNonAAPaint(); }
+  bool HasText() const { return paint_op_buffer_.HasText(); }
 
   // This gives the total number of PaintOps.
   size_t TotalOpCount() const { return paint_op_buffer_.total_op_count(); }
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index 1359b636..d0c02ee71 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -2203,6 +2203,10 @@
   return record->HasDiscardableImages();
 }
 
+bool DrawRecordOp::HasText() const {
+  return record->HasText();
+}
+
 DrawTextBlobOp::DrawTextBlobOp() : PaintOpWithFlags(kType) {}
 
 DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
@@ -2240,7 +2244,9 @@
     default;
 
 PaintOpBuffer::PaintOpBuffer()
-    : has_non_aa_paint_(false), has_discardable_images_(false) {}
+    : has_non_aa_paint_(false),
+      has_discardable_images_(false),
+      has_text_(false) {}
 
 PaintOpBuffer::PaintOpBuffer(PaintOpBuffer&& other) {
   *this = std::move(other);
@@ -2260,6 +2266,7 @@
   subrecord_op_count_ = other.subrecord_op_count_;
   has_non_aa_paint_ = other.has_non_aa_paint_;
   has_discardable_images_ = other.has_discardable_images_;
+  has_text_ = other.has_text_;
 
   // Make sure the other pob can destruct safely.
   other.used_ = 0;
@@ -2281,6 +2288,7 @@
   subrecord_bytes_used_ = 0;
   subrecord_op_count_ = 0;
   has_discardable_images_ = false;
+  has_text_ = false;
 }
 
 // When |op| is a nested PaintOpBuffer, this returns the PaintOp inside
@@ -2543,6 +2551,8 @@
     return false;
   if (has_discardable_images_ != other.has_discardable_images_)
     return false;
+  if (has_text_ != other.has_text_)
+    return false;
 
   auto left_iter = Iterator(this);
   auto right_iter = Iterator(&other);
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h
index 943fe9c..6d0e0928 100644
--- a/cc/paint/paint_op_buffer.h
+++ b/cc/paint/paint_op_buffer.h
@@ -246,6 +246,8 @@
   bool HasDiscardableImages() const { return false; }
   bool HasDiscardableImagesFromFlags() const { return false; }
 
+  bool HasText() const { return false; }
+
   // Returns the number of bytes used by this op in referenced sub records
   // and display lists.  This doesn't count other objects like paths or blobs.
   size_t AdditionalBytesUsed() const { return 0; }
@@ -662,6 +664,7 @@
   bool HasDiscardableImages() const;
   int CountSlowPaths() const;
   bool HasNonAAPaint() const;
+  bool HasText() const;
   HAS_SERIALIZATION_FUNCTIONS();
 
   sk_sp<const PaintRecord> record;
@@ -750,6 +753,7 @@
                               const PlaybackParams& params);
   bool IsValid() const { return flags.IsValid(); }
   static bool AreEqual(const PaintOp* left, const PaintOp* right);
+  bool HasText() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 
   sk_sp<SkTextBlob> blob;
@@ -952,6 +956,7 @@
   int numSlowPaths() const { return num_slow_paths_; }
   bool HasNonAAPaint() const { return has_non_aa_paint_; }
   bool HasDiscardableImages() const { return has_discardable_images_; }
+  bool HasText() const { return has_text_; }
 
   bool operator==(const PaintOpBuffer& other) const;
   bool operator!=(const PaintOpBuffer& other) const {
@@ -1012,6 +1017,8 @@
     has_discardable_images_ |= op->HasDiscardableImages();
     has_discardable_images_ |= op->HasDiscardableImagesFromFlags();
 
+    has_text_ |= (op->HasText());
+
     subrecord_bytes_used_ += op->AdditionalBytesUsed();
     subrecord_op_count_ += op->AdditionalOpCount();
   }
@@ -1239,6 +1246,7 @@
 
   bool has_non_aa_paint_ : 1;
   bool has_discardable_images_ : 1;
+  bool has_text_ : 1;
 };
 
 }  // namespace cc
diff --git a/cc/raster/raster_source.cc b/cc/raster/raster_source.cc
index 76c8859..95235b98 100644
--- a/cc/raster/raster_source.cc
+++ b/cc/raster/raster_source.cc
@@ -245,6 +245,10 @@
   return recorded_viewport_;
 }
 
+bool RasterSource::HasText() const {
+  return display_list_ && display_list_->HasText();
+}
+
 void RasterSource::AsValueInto(base::trace_event::TracedValue* array) const {
   if (display_list_.get())
     viz::TracedValue::AppendIDRef(display_list_.get(), array);
diff --git a/cc/raster/raster_source.h b/cc/raster/raster_source.h
index 25bd76b..e2af9af 100644
--- a/cc/raster/raster_source.h
+++ b/cc/raster/raster_source.h
@@ -103,6 +103,9 @@
   // Valid rectangle in which everything is recorded and can be rastered from.
   virtual gfx::Rect RecordedViewport() const;
 
+  // Returns true if this raster source may try and draw text.
+  bool HasText() const;
+
   // Tracing functionality.
   virtual void DidBeginTracing();
   virtual void AsValueInto(base::trace_event::TracedValue* array) const;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index f7e03765..778220d 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1453,10 +1453,19 @@
   if (client_name) {
     size_t total_memory_in_bytes = 0;
     size_t total_gpu_memory_for_tilings_in_bytes = 0;
+    int layers_with_text_count = 0;
+    int layers_with_text_no_lcd_text_count = 0;
     for (const PictureLayerImpl* layer : active_tree()->picture_layers()) {
       total_memory_in_bytes += layer->GetRasterSource()->GetMemoryUsage();
       total_gpu_memory_for_tilings_in_bytes += layer->GPUMemoryUsageInBytes();
+      if (layer->GetRasterSource()->HasText()) {
+        layers_with_text_count++;
+        if (!layer->can_use_lcd_text()) {
+          layers_with_text_no_lcd_text_count++;
+        }
+      }
     }
+
     if (total_memory_in_bytes != 0) {
       UMA_HISTOGRAM_COUNTS_1M(
           base::StringPrintf("Compositing.%s.PictureMemoryUsageKb",
@@ -1474,6 +1483,34 @@
         base::saturated_cast<int>(active_tree_->picture_layers().size()), 1,
         400, 20);
 
+    if (layers_with_text_count > 0) {
+      int percent =
+          100.0 * layers_with_text_no_lcd_text_count / layers_with_text_count;
+
+      if (layers_with_text_count < 10) {
+        UMA_HISTOGRAM_PERCENTAGE(
+            base::StringPrintf(
+                "Compositing.%s.PercentPictureLayersWithTextButLCDTextDisabled."
+                "LessThan10",
+                client_name),
+            percent);
+      } else if (layers_with_text_count <= 30) {
+        UMA_HISTOGRAM_PERCENTAGE(
+            base::StringPrintf(
+                "Compositing.%s.PercentPictureLayersWithTextButLCDTextDisabled."
+                "10To30",
+                client_name),
+            percent);
+      } else {
+        UMA_HISTOGRAM_PERCENTAGE(
+            base::StringPrintf(
+                "Compositing.%s."
+                "PercentPictureLayersWithTextButLCDTextDisabled.MoreThan30",
+                client_name),
+            percent);
+      }
+    }
+
     // TODO(yigu): Maybe we should use the same check above. Need to figure out
     // why exactly we skip 0.
     if (!active_tree()->picture_layers().empty()) {
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index c252091..1def5050 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -4006,25 +4006,25 @@
         // The first draw.
         EXPECT_EQ(1, num_tiles_rastered_);
         EXPECT_TRUE(can_use_lcd_text);
-        EXPECT_TRUE(root_layer->RasterSourceUsesLCDTextForTesting());
+        EXPECT_TRUE(root_layer->can_use_lcd_text());
         break;
       case 1:
         // Nothing changed on the layer.
         EXPECT_EQ(1, num_tiles_rastered_);
         EXPECT_TRUE(can_use_lcd_text);
-        EXPECT_TRUE(root_layer->RasterSourceUsesLCDTextForTesting());
+        EXPECT_TRUE(root_layer->can_use_lcd_text());
         break;
       case 2:
         // LCD text was disabled; it should be re-rastered with LCD text off.
         EXPECT_EQ(2, num_tiles_rastered_);
         EXPECT_FALSE(can_use_lcd_text);
-        EXPECT_FALSE(root_layer->RasterSourceUsesLCDTextForTesting());
+        EXPECT_FALSE(root_layer->can_use_lcd_text());
         break;
       case 3:
         // LCD text was enabled, but it's sticky and stays off.
         EXPECT_EQ(2, num_tiles_rastered_);
         EXPECT_TRUE(can_use_lcd_text);
-        EXPECT_FALSE(root_layer->RasterSourceUsesLCDTextForTesting());
+        EXPECT_FALSE(root_layer->can_use_lcd_text());
         break;
     }
   }
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 4f2641cd..e5b48fd 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1636,6 +1636,7 @@
     "//chrome/browser/resources:net_internals_resources",
     "//chrome/browser/resources:quota_internals_resources",
     "//chrome/browser/resources:webapks_ui_resources",
+    "//components/autofill/core/browser:autofill_address_rewriter_resources",
   ]
 
   if (!is_android) {
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java
index 30924b5..59a47aa 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java
@@ -54,8 +54,7 @@
     private static final String TAG = "SSLayout";
 
     // Duration of the transition animation
-    @VisibleForTesting
-    static final long ZOOMING_DURATION = 300;
+    public static final long ZOOMING_DURATION = 300;
     private static final int BACKGROUND_FADING_DURATION_MS = 150;
 
     // Field trial parameter for whether skipping slow zooming animation.
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
index 8182504b..2409be1 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
@@ -147,6 +147,14 @@
 
     @Test
     @EnormousTest
+    @CommandLineFlags.Add({BASE_PARAMS + "/max-duty-cycle/1"})
+    public void testTabToGridFromLiveTabWith10TabsNoRateLimit() throws InterruptedException {
+        prepareTabs(10, NTP_URL);
+        reportTabToGridPerf(mUrl, "Tab-to-Grid from live tab with 10 tabs (no rate-limit)");
+    }
+
+    @Test
+    @EnormousTest
     @CommandLineFlags.Add({BASE_PARAMS})
     public void testTabToGridFromLiveTabWith10TabsWithoutThumbnail() throws InterruptedException {
         // Note that most of the tabs won't have thumbnails.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
index b8430a83..5a23185 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.tasks.tab_management;
 
+import static org.chromium.chrome.features.start_surface.StartSurfaceLayout.ZOOMING_DURATION;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -11,6 +13,7 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.os.SystemClock;
 import android.support.annotation.Nullable;
@@ -23,6 +26,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import org.chromium.base.Log;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
@@ -33,6 +37,11 @@
  * A custom RecyclerView implementation for the tab grid, to handle show/hide logic in class.
  */
 class TabListRecyclerView extends RecyclerView {
+    private static final String TAG = "TabListRecyclerView";
+
+    private static final String MAX_DUTY_CYCLE_PARAM = "max-duty-cycle";
+    private static final float DEFAULT_MAX_DUTY_CYCLE = 0.2f;
+
     public static final long BASE_ANIMATION_DURATION_MS = 218;
     public static final long FINAL_FADE_IN_DURATION_MS = 50;
 
@@ -214,18 +223,58 @@
      */
     void createDynamicView(DynamicResourceLoader loader) {
         mDynamicView = new ViewResourceAdapter(this) {
+            private long mSuppressedUntil;
+
             @Override
             public boolean isDirty() {
                 boolean dirty = super.isDirty();
-                if (dirty) mLastDirtyTime = SystemClock.elapsedRealtime();
+                if (dirty) {
+                    mLastDirtyTime = SystemClock.elapsedRealtime();
+                }
+                if (SystemClock.elapsedRealtime() < mSuppressedUntil) {
+                    if (dirty) {
+                        Log.d(TAG, "Dynamic View is dirty but suppressed");
+                    }
+                    return false;
+                }
                 return dirty;
             }
+
+            @Override
+            public Bitmap getBitmap() {
+                long startTime = SystemClock.elapsedRealtime();
+                Bitmap bitmap = super.getBitmap();
+                long elapsed = SystemClock.elapsedRealtime() - startTime;
+                if (elapsed == 0) elapsed = 1;
+
+                float maxDutyCycle = getMaxDutyCycle();
+                Log.d(TAG, "MaxDutyCycle = " + getMaxDutyCycle());
+                assert maxDutyCycle > 0;
+                assert maxDutyCycle <= 1;
+                long suppressedFor = Math.min(
+                        (long) (elapsed * (1 - maxDutyCycle) / maxDutyCycle), ZOOMING_DURATION);
+
+                mSuppressedUntil = SystemClock.elapsedRealtime() + suppressedFor;
+                Log.d(TAG, "DynamicView: spent %dms on getBitmap, suppress updating for %dms.",
+                        elapsed, suppressedFor);
+                return bitmap;
+            }
         };
         mDynamicView.setDownsamplingScale(getDownsamplingScale());
         assert mLoader == null : "createDynamicView should only be called once";
         mLoader = loader;
     }
 
+    private float getMaxDutyCycle() {
+        String maxDutyCycle = ChromeFeatureList.getFieldTrialParamByFeature(
+                ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, MAX_DUTY_CYCLE_PARAM);
+        try {
+            return Float.valueOf(maxDutyCycle);
+        } catch (NumberFormatException e) {
+            return DEFAULT_MAX_DUTY_CYCLE;
+        }
+    }
+
     private void registerDynamicView() {
         if (mIsDynamicViewRegistered) return;
         if (mLoader == null) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
index ece51a8d..4a5ac7df 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
@@ -194,7 +194,9 @@
                     }
                 }
 
-                DownloadStartupUtils.ensureDownloadSystemInitialized(browserStarted);
+                DownloadStartupUtils.ensureDownloadSystemInitialized(
+                        BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                                .isFullBrowserStarted());
                 propagateInteraction(intent);
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadDirectoryProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadDirectoryProvider.java
index f93a455..17a48fe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadDirectoryProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadDirectoryProvider.java
@@ -267,6 +267,7 @@
                 Environment.DIRECTORY_DOWNLOADS);
         if (dirs.length <= 1 || TextUtils.isEmpty(filePath)) return false;
         for (int i = 1; i < dirs.length; ++i) {
+            if (dirs[i] == null) continue;
             if (filePath.startsWith(dirs[i].getAbsolutePath())) return true;
         }
         return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
index d70083a..86f344b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
@@ -233,7 +233,7 @@
             // TODO(dfalcantara): Get thumbnails for audio and video files when possible.
         }
 
-        if (mThumbnailBitmap == null) updateView();
+        if (mThumbnailBitmap == null) updateView(false);
 
         Context context = mDescriptionCompletedView.getContext();
         mFilenameCompletedView.setText(item.getDisplayFileName());
@@ -302,7 +302,7 @@
 
     private void setThumbnailBitmap(Bitmap thumbnail) {
         mThumbnailBitmap = thumbnail;
-        updateView();
+        updateView(false);
     }
 
     @Override
@@ -325,14 +325,14 @@
     }
 
     @Override
-    protected void updateView() {
+    protected void updateView(boolean animate) {
         if (isChecked()) {
             mIconView.setBackgroundResource(mIconBackgroundResId);
             mIconView.getBackground().setLevel(
                     getResources().getInteger(R.integer.list_item_level_selected));
             mIconView.setImageDrawable(mCheckDrawable);
             ApiCompatibilityUtils.setImageTintList(mIconView, mCheckedIconForegroundColorList);
-            mCheckDrawable.start();
+            if (animate) mCheckDrawable.start();
         } else if (mThumbnailBitmap != null) {
             assert !mThumbnailBitmap.isRecycled();
             mIconView.setBackground(null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java
index 14b77b4..e2c18bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java
@@ -67,13 +67,6 @@
     }
 
     @Override
-    public void setChecked(boolean checked) {
-        if (checked == isChecked()) return;
-        super.setChecked(checked);
-        updateCheckIcon(checked);
-    }
-
-    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         if (mSelectionDelegate != null) {
@@ -98,7 +91,6 @@
         mDescriptionTextView.setText(description);
         updateExpandIcon(header.isExpanded());
         setChecked(mSelectionDelegate.isHeaderSelected(header));
-        updateCheckIcon(isChecked());
     }
 
     private void updateExpandIcon(boolean expanded) {
@@ -109,15 +101,16 @@
                                                   : R.string.accessibility_expand_section_header));
     }
 
-    private void updateCheckIcon(boolean checked) {
-        if (checked) {
+    @Override
+    protected void updateView(boolean animate) {
+        if (isChecked()) {
             mIconImageView.setBackgroundResource(mIconBackgroundResId);
             mIconImageView.getBackground().setLevel(
                     getResources().getInteger(R.integer.list_item_level_selected));
 
             mIconImageView.setImageDrawable(mCheckDrawable);
             ApiCompatibilityUtils.setImageTintList(mIconImageView, mCheckedIconForegroundColorList);
-            mCheckDrawable.start();
+            if (animate) mCheckDrawable.start();
         } else {
             mIconImageView.setBackgroundResource(mIconBackgroundResId);
             mIconImageView.getBackground().setLevel(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
index e953dc03..62e5baa8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -179,13 +179,14 @@
     @CalledByNative
     private static SnippetArticle addSuggestion(List<SnippetArticle> suggestions, int category,
             String id, String title, String publisher, String url, long timestamp, float score,
-            long fetchTime, boolean isVideoSuggestion, int thumbnailDominantColor) {
+            long fetchTime, boolean isVideoSuggestion, int thumbnailDominantColor,
+            boolean hasThumbnail) {
         int position = suggestions.size();
         // thumbnailDominantColor equal to 0 encodes absence of the value. 0 is not a valid color,
         // because the passed color cannot be fully transparent.
-        suggestions.add(new SnippetArticle(category, id, title, publisher, url, timestamp, score,
-                fetchTime, isVideoSuggestion,
-                thumbnailDominantColor == 0 ? null : thumbnailDominantColor));
+        suggestions.add(new SnippetArticle(category, id, title, /*snippet=*/"", publisher, url,
+                timestamp, score, fetchTime, isVideoSuggestion,
+                thumbnailDominantColor == 0 ? null : thumbnailDominantColor, hasThumbnail));
         return suggestions.get(position);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
index a86bc754..dced6ff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
@@ -69,7 +69,7 @@
      */
     protected void setIconDrawable(Drawable iconDrawable) {
         mIconDrawable = iconDrawable;
-        updateView();
+        updateView(false);
     }
 
     /**
@@ -83,7 +83,7 @@
      * Update icon image and background based on whether this item is selected.
      */
     @Override
-    protected void updateView() {
+    protected void updateView(boolean animate) {
         // TODO(huayinz): Refactor this method so that mIconView is not exposed to subclass.
         if (mIconView == null) return;
 
@@ -91,7 +91,7 @@
             mIconView.getBackground().setLevel(mSelectedLevel);
             mIconView.setImageDrawable(mCheckDrawable);
             ApiCompatibilityUtils.setImageTintList(mIconView, mIconColorList);
-            mCheckDrawable.start();
+            if (animate) mCheckDrawable.start();
         } else {
             mIconView.getBackground().setLevel(mDefaultLevel);
             mIconView.setImageDrawable(mIconDrawable);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemViewBase.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemViewBase.java
index efc69ccb..81b5db61 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemViewBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemViewBase.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.widget.selection;
 
 import android.content.Context;
+import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -37,7 +38,7 @@
 
     private SelectionDelegate<E> mSelectionDelegate;
     private E mItem;
-    private boolean mIsChecked;
+    private @Nullable Boolean mIsChecked;
 
     // Controls whether selection should happen during onLongClick.
     private boolean mSelectOnLongClick = true;
@@ -121,7 +122,7 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        setChecked(false);
+        resetCheckedState();
     }
 
     // OnTouchListener implementation.
@@ -187,7 +188,7 @@
     // Checkable implementations.
     @Override
     public boolean isChecked() {
-        return mIsChecked;
+        return mIsChecked != null && mIsChecked;
     }
 
     @Override
@@ -195,11 +196,28 @@
         setChecked(!isChecked());
     }
 
+    /**
+     * Sets whether the item is checked. Note that if the views to be updated run animations, you
+     * should override {@link #updateView(boolean)} to get the correct animation state instead of
+     * overriding this method to update the views.
+     * @param checked Whether the item is checked.
+     */
     @Override
     public void setChecked(boolean checked) {
-        if (checked == mIsChecked) return;
+        if (mIsChecked != null && checked == mIsChecked) return;
+
+        // We shouldn't run the animation when mIsChecked is first initialized to the correct state.
+        final boolean animate = mIsChecked != null;
         mIsChecked = checked;
-        updateView();
+        updateView(animate);
+    }
+
+    /**
+     * Resets the checked state to be uninitialized.
+     */
+    private void resetCheckedState() {
+        setChecked(false);
+        mIsChecked = null;
     }
 
     // SelectionObserver implementation.
@@ -210,8 +228,9 @@
 
     /**
      * Update the view based on whether this item is selected.
+     * @param animate Whether to animate the selection state changing if applicable.
      */
-    protected void updateView() {}
+    protected void updateView(boolean animate) {}
 
     /**
      * Same as {@link OnClickListener#onClick(View)} on this.
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f90d9881..fcf8ba9 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1060,6 +1060,12 @@
     "performance_manager/graph/system_node.cc",
     "performance_manager/graph/system_node_impl.cc",
     "performance_manager/graph/system_node_impl.h",
+    "performance_manager/mechanisms/working_set_trimmer.cc",
+    "performance_manager/mechanisms/working_set_trimmer.h",
+    "performance_manager/mechanisms/working_set_trimmer_chromeos.cc",
+    "performance_manager/mechanisms/working_set_trimmer_chromeos.h",
+    "performance_manager/mechanisms/working_set_trimmer_win.cc",
+    "performance_manager/mechanisms/working_set_trimmer_win.h",
     "performance_manager/observers/background_metrics_reporter.h",
     "performance_manager/observers/graph_observer.cc",
     "performance_manager/observers/graph_observer.h",
@@ -1067,8 +1073,8 @@
     "performance_manager/observers/isolation_context_metrics.h",
     "performance_manager/observers/metrics_collector.cc",
     "performance_manager/observers/metrics_collector.h",
-    "performance_manager/observers/working_set_trimmer_win.cc",
-    "performance_manager/observers/working_set_trimmer_win.h",
+    "performance_manager/observers/working_set_trimmer_observer_win.cc",
+    "performance_manager/observers/working_set_trimmer_observer_win.h",
     "performance_manager/performance_manager.cc",
     "performance_manager/performance_manager.h",
     "performance_manager/performance_manager_clock.cc",
@@ -3101,6 +3107,8 @@
       "memory/swap_thrashing_monitor_delegate.h",
       "memory/swap_thrashing_monitor_delegate_win.cc",
       "memory/swap_thrashing_monitor_delegate_win.h",
+      "metrics/browser_activity_watcher.cc",
+      "metrics/browser_activity_watcher.h",
       "metrics/desktop_platform_features_metrics_provider.cc",
       "metrics/desktop_platform_features_metrics_provider.h",
       "metrics/desktop_session_duration/audible_contents_tracker.cc",
diff --git a/chrome/browser/accessibility/accessibility_extension_api.cc b/chrome/browser/accessibility/accessibility_extension_api.cc
index d3deac9..55e9b36 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api.cc
@@ -20,8 +20,11 @@
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/common/extensions/api/accessibility_private.h"
 #include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/webui_url_constants.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "components/infobars/core/infobar.h"
 #include "content/public/browser/browser_accessibility_state.h"
@@ -79,6 +82,27 @@
 }
 
 ExtensionFunction::ResponseAction
+AccessibilityPrivateOpenSettingsSubpageFunction::Run() {
+  using extensions::api::accessibility_private::OpenSettingsSubpage::Params;
+  const std::unique_ptr<Params> params(Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+#if defined(OS_CHROMEOS)
+  Profile* profile = chromeos::AccessibilityManager::Get()->profile();
+  if (chrome::IsOSSettingsSubPage(params->subpage)) {
+    chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
+        profile, params->subpage);
+  } else {
+    chrome::ShowSettingsSubPageForProfile(profile, params->subpage);
+  }
+#else
+  // This function should only be available on ChromeOS.
+  EXTENSION_FUNCTION_VALIDATE(false);
+#endif  // OS_CHROMEOS
+  return RespondNow(NoArguments());
+}
+
+ExtensionFunction::ResponseAction
 AccessibilityPrivateSetFocusRingsFunction::Run() {
 #if defined(OS_CHROMEOS)
   std::unique_ptr<accessibility_private::SetFocusRings::Params> params(
diff --git a/chrome/browser/accessibility/accessibility_extension_api.h b/chrome/browser/accessibility/accessibility_extension_api.h
index 2733a147..0d21dd3 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.h
+++ b/chrome/browser/accessibility/accessibility_extension_api.h
@@ -58,8 +58,17 @@
                              ACCESSIBILITY_PRIVATE_DARKENSCREEN)
 };
 
-// API function that sets the keys to be captured by Switch Access.
+// Opens a specified subpage in Chrome settings.
+class AccessibilityPrivateOpenSettingsSubpageFunction
+    : public UIThreadExtensionFunction {
+  ~AccessibilityPrivateOpenSettingsSubpageFunction() override {}
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.openSettingsSubpage",
+                             ACCESSIBILITY_PRIVATE_OPENSETTINGSSUBPAGE)
+};
+
 #if defined(OS_CHROMEOS)
+// API function that sets the keys to be captured by Switch Access.
 class AccessibilityPrivateSetSwitchAccessKeysFunction
     : public UIThreadExtensionFunction {
   ~AccessibilityPrivateSetSwitchAccessKeysFunction() override {}
diff --git a/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc b/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc
index 05cd646..6877107 100644
--- a/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc
@@ -2,8 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/common/webui_url_constants.h"
 #include "ui/base/ui_base_features.h"
 
 namespace extensions {
@@ -22,4 +28,58 @@
       << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(AccessibilityPrivateApiTest, OpenSettingsSubpage) {
+  Profile* profile = chromeos::AccessibilityManager::Get()->profile();
+
+  // Install the Settings App.
+  web_app::WebAppProvider::Get(profile)
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
+
+  ASSERT_TRUE(RunExtensionSubtest("accessibility_private/",
+                                  "open_settings_subpage.html"))
+      << message_;
+
+  chrome::SettingsWindowManager* settings_manager =
+      chrome::SettingsWindowManager::GetInstance();
+
+  Browser* settings_browser = settings_manager->FindBrowserForProfile(profile);
+  EXPECT_NE(nullptr, settings_browser);
+
+  content::WebContents* web_contents =
+      settings_browser->tab_strip_model()->GetWebContentsAt(0);
+
+  WaitForLoadStop(web_contents);
+
+  EXPECT_EQ(GURL("chrome://settings/manageAccessibility/tts"),
+            web_contents->GetLastCommittedURL());
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityPrivateApiTest,
+                       OpenSettingsSubpage_InvalidSubpage) {
+  Profile* profile = chromeos::AccessibilityManager::Get()->profile();
+
+  // Install the Settings App.
+  web_app::WebAppProvider::Get(profile)
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
+
+  ASSERT_TRUE(RunExtensionSubtest("accessibility_private/",
+                                  "open_settings_subpage_invalid_subpage.html"))
+      << message_;
+
+  chrome::SettingsWindowManager* settings_manager =
+      chrome::SettingsWindowManager::GetInstance();
+
+  Browser* settings_browser = settings_manager->FindBrowserForProfile(profile);
+  EXPECT_NE(nullptr, settings_browser);
+
+  content::WebContents* web_contents =
+      settings_browser->tab_strip_model()->GetWebContentsAt(0);
+
+  WaitForLoadStop(web_contents);
+
+  EXPECT_EQ(GURL("chrome://settings"), web_contents->GetLastCommittedURL());
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
index e0538d1..45f53c2 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -73,7 +73,8 @@
             suggestion.publish_date().ToJavaTime(), suggestion.score(),
             suggestion.fetch_date().ToJavaTime(),
             suggestion.is_video_suggestion(),
-            suggestion.optional_image_dominant_color().value_or(0));
+            suggestion.optional_image_dominant_color().value_or(0),
+            !suggestion.salient_image_url().is_empty());
   }
 
   return result;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index de37af59..62db14f 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2382,16 +2382,27 @@
       out_prefs, Profile::FromBrowserContext(browser_context));
 }
 
-bool ChromeContentBrowserClient::AllowAppCache(
+bool ChromeContentBrowserClient::AllowAppCacheOnIO(
     const GURL& manifest_url,
     const GURL& first_party,
     content::ResourceContext* context) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(!base::FeatureList::IsEnabled(features::kNavigationLoaderOnUI));
   ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
   return io_data->GetCookieSettings()->IsCookieAccessAllowed(manifest_url,
                                                              first_party);
 }
 
+bool ChromeContentBrowserClient::AllowAppCache(
+    const GURL& manifest_url,
+    const GURL& first_party,
+    content::BrowserContext* context) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  return CookieSettingsFactory::GetForProfile(
+             Profile::FromBrowserContext(context))
+      ->IsCookieAccessAllowed(manifest_url, first_party);
+}
+
 bool ChromeContentBrowserClient::AllowServiceWorker(
     const GURL& scope,
     const GURL& first_party_url,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index af05161b..1e6cbffb 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -216,9 +216,12 @@
   void UpdateRendererPreferencesForWorker(
       content::BrowserContext* browser_context,
       blink::mojom::RendererPreferences* out_prefs) override;
+  bool AllowAppCacheOnIO(const GURL& manifest_url,
+                         const GURL& first_party,
+                         content::ResourceContext* context) override;
   bool AllowAppCache(const GURL& manifest_url,
                      const GURL& first_party,
-                     content::ResourceContext* context) override;
+                     content::BrowserContext* context) override;
   bool AllowServiceWorker(
       const GURL& scope,
       const GURL& first_party,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 80d099a..18bd3c9 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -592,6 +592,10 @@
     "arc/screen_capture/arc_screen_capture_bridge.h",
     "arc/screen_capture/arc_screen_capture_session.cc",
     "arc/screen_capture/arc_screen_capture_session.h",
+    "arc/tracing/arc_app_performance_tracing.cc",
+    "arc/tracing/arc_app_performance_tracing.h",
+    "arc/tracing/arc_app_performance_tracing_session.cc",
+    "arc/tracing/arc_app_performance_tracing_session.h",
     "arc/tracing/arc_cpu_event.cc",
     "arc/tracing/arc_cpu_event.h",
     "arc/tracing/arc_graphics_jank_detector.cc",
@@ -2357,6 +2361,7 @@
     "arc/pip/arc_pip_bridge_unittest.cc",
     "arc/policy/arc_policy_bridge_unittest.cc",
     "arc/process/arc_process_unittest.cc",
+    "arc/tracing/arc_app_performance_tracing_unittest.cc",
     "arc/tracing/arc_cpu_event_unittest.cc",
     "arc/tracing/arc_graphics_jank_detector_unittest.cc",
     "arc/tracing/arc_system_model_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc
index 3c0a67d..0c4fc87 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/chromeos/arc/print_spooler/arc_print_spooler_bridge.h"
 #include "chrome/browser/chromeos/arc/process/arc_process_service.h"
 #include "chrome/browser/chromeos/arc/screen_capture/arc_screen_capture_bridge.h"
+#include "chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h"
 #include "chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.h"
 #include "chrome/browser/chromeos/arc/tts/arc_tts_service.h"
 #include "chrome/browser/chromeos/arc/user_session/arc_user_session_service.h"
@@ -204,6 +205,7 @@
   ArcSettingsService::GetForBrowserContext(profile);
   ArcTimerBridge::GetForBrowserContext(profile);
   ArcTracingBridge::GetForBrowserContext(profile);
+  ArcAppPerformanceTracing::GetForBrowserContext(profile);
   ArcTtsService::GetForBrowserContext(profile);
   ArcUsbHostBridge::GetForBrowserContext(profile);
   ArcUsbHostPermissionManager::GetForBrowserContext(profile);
diff --git a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.cc b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.cc
new file mode 100644
index 0000000..aa300a9
--- /dev/null
+++ b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.cc
@@ -0,0 +1,234 @@
+// Copyright 2019 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/arc/tracing/arc_app_performance_tracing.h"
+
+#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_session.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
+#include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "components/arc/arc_features.h"
+#include "components/arc/arc_util.h"
+#include "components/exo/wm_helper.h"
+#include "ui/aura/window.h"
+
+namespace arc {
+
+namespace {
+
+// Singleton factory for ArcAppPerformanceTracing.
+class ArcAppPerformanceTracingFactory
+    : public internal::ArcBrowserContextKeyedServiceFactoryBase<
+          ArcAppPerformanceTracing,
+          ArcAppPerformanceTracingFactory> {
+ public:
+  // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
+  static constexpr const char* kName = "ArcAppPerformanceTracingFactory";
+
+  static ArcAppPerformanceTracingFactory* GetInstance() {
+    return base::Singleton<ArcAppPerformanceTracingFactory>::get();
+  }
+
+ private:
+  friend base::DefaultSingletonTraits<ArcAppPerformanceTracingFactory>;
+  ArcAppPerformanceTracingFactory() {
+    DependsOn(ArcAppListPrefsFactory::GetInstance());
+  }
+  ~ArcAppPerformanceTracingFactory() override = default;
+};
+
+// Singleton for app id to category mapping.
+class AppToCategoryMapper {
+ public:
+  AppToCategoryMapper() {
+    // Please refer to
+    // https://goto.google.com/arc++app-runtime-performance-metrics.
+    Add("iicceeckdelepgbcpojbgahbhnklpane", "OnlineGame");
+    Add("kmglgjicdcmjphkoojighlhjejkiefih", "CasualGame");
+    Add("niajncocfieigpbiamllekeadpgbhkke", "ShooterGame");
+    Add("icloenboalgjkknjdficgpgpcedmmojn", "Video");
+  }
+
+  static AppToCategoryMapper& GetInstance() {
+    static base::NoDestructor<AppToCategoryMapper> instance;
+    return *instance.get();
+  }
+
+  // Returns empty string if category is not set for app |app_id|.
+  const std::string& GetCategory(const std::string& app_id) const {
+    const auto& it = app_id_to_category_.find(app_id);
+    if (it == app_id_to_category_.end())
+      return base::EmptyString();
+    return it->second;
+  }
+
+  void Add(const std::string& app_id, const std::string& category) {
+    app_id_to_category_[app_id] = category;
+  }
+
+ private:
+  ~AppToCategoryMapper() = default;
+
+  std::map<std::string, std::string> app_id_to_category_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppToCategoryMapper);
+};
+
+}  // namespace
+
+ArcAppPerformanceTracing::ArcAppPerformanceTracing(
+    content::BrowserContext* context,
+    ArcBridgeService* bridge)
+    : context_(context) {
+  // Not related tests may indirectly create this instance and helper might
+  // not be set.
+  if (exo::WMHelper::HasInstance())
+    exo::WMHelper::GetInstance()->AddActivationObserver(this);
+  ArcAppListPrefs::Get(context_)->AddObserver(this);
+}
+
+// Releasing resources in DTOR is not safe, see |Shutdown|.
+ArcAppPerformanceTracing::~ArcAppPerformanceTracing() = default;
+
+// static
+ArcAppPerformanceTracing* ArcAppPerformanceTracing::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return ArcAppPerformanceTracingFactory::GetForBrowserContext(context);
+}
+
+// static
+void ArcAppPerformanceTracing::SetFocusAppForTesting(
+    const std::string& package_name,
+    const std::string& activity,
+    const std::string& category) {
+  AppToCategoryMapper::GetInstance().Add(
+      ArcAppListPrefs::GetAppId(package_name, activity), category);
+}
+
+void ArcAppPerformanceTracing::Shutdown() {
+  MaybeStopTracing();
+
+  // |session_|. Make sure that |arc_active_window_| is detached.
+  DetachActiveWindow();
+
+  ArcAppListPrefs::Get(context_)->RemoveObserver(this);
+  if (exo::WMHelper::HasInstance())
+    exo::WMHelper::GetInstance()->RemoveActivationObserver(this);
+}
+
+void ArcAppPerformanceTracing::OnWindowActivated(ActivationReason reason,
+                                                 aura::Window* gained_active,
+                                                 aura::Window* lost_active) {
+  // Discard any active tracing if any.
+  MaybeStopTracing();
+
+  // Detach previous active window if it is set.
+  DetachActiveWindow();
+
+  // Ignore any non-ARC++ window.
+  if (arc::GetWindowTaskId(gained_active) <= 0)
+    return;
+
+  // Observe active ARC++ window.
+  AttachActiveWindow(gained_active);
+
+  MaybeStartTracing();
+}
+
+void ArcAppPerformanceTracing::OnWindowDestroying(aura::Window* window) {
+  // ARC++ window will be destroyed.
+  DCHECK_EQ(arc_active_window_, window);
+
+  MaybeStopTracing();
+
+  DetachActiveWindow();
+}
+
+void ArcAppPerformanceTracing::OnTaskCreated(int32_t task_id,
+                                             const std::string& package_name,
+                                             const std::string& activity,
+                                             const std::string& intent) {
+  const std::string app_id = ArcAppListPrefs::GetAppId(package_name, activity);
+  task_id_to_app_id_[task_id] = app_id;
+  MaybeStartTracing();
+}
+
+void ArcAppPerformanceTracing::OnTaskDestroyed(int32_t task_id) {
+  task_id_to_app_id_.erase(task_id);
+}
+
+bool ArcAppPerformanceTracing::WasReported(const std::string& category) const {
+  DCHECK(!category.empty());
+  return reported_categories_.count(category);
+}
+
+void ArcAppPerformanceTracing::SetReported(const std::string& category) {
+  DCHECK(!category.empty());
+  reported_categories_.insert(category);
+}
+
+void ArcAppPerformanceTracing::SetTracingPeriodForTesting(
+    const base::TimeDelta& period) {
+  tracing_period_ = period;
+}
+
+void ArcAppPerformanceTracing::MaybeStartTracing() {
+  if (session_) {
+    // We are already tracing, ignore.
+    DCHECK_EQ(session_->window(), arc_active_window_);
+    return;
+  }
+
+  // Check if we have all conditions met, ARC++ window is active and information
+  // is available for associated task.
+  if (!arc_active_window_)
+    return;
+
+  const int task_id = arc::GetWindowTaskId(arc_active_window_);
+  DCHECK_GT(task_id, 0);
+
+  const auto it = task_id_to_app_id_.find(task_id);
+  if (it == task_id_to_app_id_.end()) {
+    // It is normal that information might not be available at this time.
+    return;
+  }
+
+  const std::string& category =
+      AppToCategoryMapper::GetInstance().GetCategory(it->second /* app_id */);
+
+  if (category.empty()) {
+    // App is not recognized as app for tracing, ignore it.
+    return;
+  }
+
+  // Start tracing for |arc_active_window_|.
+  session_ = std::make_unique<ArcAppPerformanceTracingSession>(
+      this, arc_active_window_, category, tracing_period_);
+  session_->Schedule();
+}
+
+void ArcAppPerformanceTracing::MaybeStopTracing() {
+  // Reset tracing if it was set.
+  session_.reset();
+}
+
+void ArcAppPerformanceTracing::AttachActiveWindow(aura::Window* window) {
+  DCHECK(window);
+  DCHECK(!arc_active_window_);
+
+  arc_active_window_ = window;
+  arc_active_window_->AddObserver(this);
+}
+
+void ArcAppPerformanceTracing::DetachActiveWindow() {
+  if (!arc_active_window_)
+    return;
+
+  arc_active_window_->RemoveObserver(this);
+  arc_active_window_ = nullptr;
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h
new file mode 100644
index 0000000..f801c52
--- /dev/null
+++ b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h
@@ -0,0 +1,131 @@
+// Copyright 2019 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_ARC_TRACING_ARC_APP_PERFORMANCE_TRACING_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_TRACING_ARC_APP_PERFORMANCE_TRACING_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "ui/aura/window_observer.h"
+#include "ui/wm/public/activation_change_observer.h"
+
+namespace aura {
+class Window;
+}  // namespace aura
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace arc {
+
+class ArcAppPerformanceTracingSession;
+class ArcBridgeService;
+
+// Service that monitors ARC++ apps, measures and reports performance metrics
+// for the set of predefined apps.
+class ArcAppPerformanceTracing : public KeyedService,
+                                 public wm::ActivationChangeObserver,
+                                 public aura::WindowObserver,
+                                 public ArcAppListPrefs::Observer {
+ public:
+  ArcAppPerformanceTracing(content::BrowserContext* context,
+                           ArcBridgeService* bridge);
+  ~ArcAppPerformanceTracing() override;
+
+  // Returns singleton instance for the given BrowserContext,
+  // or nullptr if the browser |context| is not allowed to use ARC++.
+  static ArcAppPerformanceTracing* GetForBrowserContext(
+      content::BrowserContext* context);
+
+  static void SetFocusAppForTesting(const std::string& package_name,
+                                    const std::string& activity,
+                                    const std::string& category);
+
+  // KeyedService:
+  void Shutdown() override;
+
+  // wm::ActivationChangeObserver:
+  void OnWindowActivated(ActivationReason reason,
+                         aura::Window* gained_active,
+                         aura::Window* lost_active) override;
+
+  // aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override;
+
+  // ArcAppListPrefs::Observer:
+  void OnTaskCreated(int32_t task_id,
+                     const std::string& package_name,
+                     const std::string& activity,
+                     const std::string& intent) override;
+  void OnTaskDestroyed(int32_t task_id) override;
+
+  // Returns true in case |category| was already reported in the current user's
+  // session.
+  bool WasReported(const std::string& category) const;
+  // Marks that |category| is reported in the current user's session.
+  void SetReported(const std::string& category);
+
+  // Sets different tracing |period| for testing.
+  void SetTracingPeriodForTesting(const base::TimeDelta& period);
+
+  // Returns active tracing session or nullptr.
+  ArcAppPerformanceTracingSession* session() { return session_.get(); }
+
+ private:
+  // May be start tracing session if all conditions are met. Window creating is
+  // controlled by Wayland protocol implementation and task creation is reported
+  // using mojom. That introduces the race and following conditions must be met
+  // to start the tracing.
+  //   * Active window is ARC++ window.
+  //   * Task information exists for the window.
+  //   * ARC++ app is in set of predefined apps eligible for tracing.
+  // This does nothing if session was already started.
+  // This is called each time when ARC++ window gets active or ARC++ task
+  // creation is reported.
+  void MaybeStartTracing();
+
+  // Stops tracing session if it was active and cancels any scheduled session.
+  void MaybeStopTracing();
+
+  // Attaches observer to the |window| and stores at as |arc_active_window_|.
+  void AttachActiveWindow(aura::Window* window);
+
+  // Detaches observer from |arc_active_window_| and resets
+  // |arc_active_window_|.
+  void DetachActiveWindow();
+
+  // Unowned pointers.
+  content::BrowserContext* const context_;
+  // Currently active ARC++ app window.
+  aura::Window* arc_active_window_ = nullptr;
+
+  // Maps active tasks to app id.
+  std::map<int, std::string> task_id_to_app_id_;
+
+  // Set of already reported ARC++ apps for the current session. Used to prevent
+  // capturing too frequently.
+  std::set<std::string> reported_categories_;
+
+  // Keeps current active tracing session associated with |arc_active_window_|.
+  std::unique_ptr<ArcAppPerformanceTracingSession> session_;
+
+  // Defines the period to capture tracing results. Can be overwritten for
+  // testing.
+  base::TimeDelta tracing_period_ = base::TimeDelta::FromSeconds(15);
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppPerformanceTracing);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_TRACING_ARC_APP_PERFORMANCE_TRACING_H_
diff --git a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_session.cc b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_session.cc
new file mode 100644
index 0000000..193c0a1
--- /dev/null
+++ b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_session.cc
@@ -0,0 +1,225 @@
+// Copyright 2019 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/arc/tracing/arc_app_performance_tracing_session.h"
+
+#include "base/bind.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h"
+#include "components/exo/shell_surface_util.h"
+#include "components/exo/surface.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/aura/window.h"
+
+namespace arc {
+
+namespace {
+
+// Defines the delay to start tracing after ARC++ window gets activated.
+// This is done to avoid likely redundant statistics collection during the app
+// initialization/loading time.
+constexpr base::TimeDelta kInitTracingDelay = base::TimeDelta::FromMinutes(1);
+
+// Defines the delay to start next session of capturing statistics for the same
+// active app or in case the app was already reported.
+constexpr base::TimeDelta kNextTracingDelay = base::TimeDelta::FromMinutes(20);
+
+// Target FPS, all reference devices has 60 FPS.
+// TODO(khmel), detect this per device.
+constexpr uint64_t kTargetFps = 60;
+
+constexpr base::TimeDelta kTargetFrameTime =
+    base::TimeDelta::FromSeconds(1) / kTargetFps;
+
+// Used for detection the idle. App considered in idle state when there is no
+// any commit for |kIdleThresholdFrames| frames.
+constexpr uint64_t kIdleThresholdFrames = 10;
+
+std::string GetHistogramName(const std::string& category,
+                             const std::string& name) {
+  return base::StringPrintf("Arc.Runtime.Performance.%s.%s", name.c_str(),
+                            category.c_str());
+}
+
+void ReportFPS(const std::string& category_name, double fps) {
+  DCHECK(!category_name.empty());
+  DCHECK_GT(fps, 0);
+  base::UmaHistogramCounts100(GetHistogramName(category_name, "FPS"),
+                              static_cast<int>(std::round(fps)));
+}
+
+void ReportCommitError(const std::string& category_name, double error_mcs) {
+  DCHECK(!category_name.empty());
+  DCHECK_GE(error_mcs, 0);
+  base::UmaHistogramCustomCounts(
+      GetHistogramName(category_name, "CommitDeviation"),
+      static_cast<int>(std::round(error_mcs)), 100 /* min */, 5000 /* max */,
+      50 /* buckets */);
+}
+
+void ReportQuality(const std::string& category_name, double quality) {
+  DCHECK(!category_name.empty());
+  DCHECK_GT(quality, 0);
+  // Report quality from 0 to 100%.
+  const int sample = (int)(quality * 100.0);
+  base::UmaHistogramPercentage(GetHistogramName(category_name, "RenderQuality"),
+                               sample);
+}
+
+}  // namespace
+
+ArcAppPerformanceTracingSession::ArcAppPerformanceTracingSession(
+    ArcAppPerformanceTracing* owner,
+    aura::Window* window,
+    const std::string& category,
+    const base::TimeDelta& tracing_period)
+    : owner_(owner),
+      window_(window),
+      category_(category),
+      tracing_period_(tracing_period) {}
+
+ArcAppPerformanceTracingSession::~ArcAppPerformanceTracingSession() {
+  // Discard any active tracing if any.
+  Stop();
+}
+
+void ArcAppPerformanceTracingSession::Schedule() {
+  DCHECK(!tracing_active_);
+  DCHECK(!tracing_timer_.IsRunning());
+  const base::TimeDelta delay =
+      owner_->WasReported(category_) ? kNextTracingDelay : kInitTracingDelay;
+  tracing_timer_.Start(FROM_HERE, delay,
+                       base::BindOnce(&ArcAppPerformanceTracingSession::Start,
+                                      base::Unretained(this)));
+}
+
+void ArcAppPerformanceTracingSession::OnSurfaceDestroying(
+    exo::Surface* surface) {
+  Stop();
+}
+
+void ArcAppPerformanceTracingSession::OnCommit(exo::Surface* surface) {
+  HandleCommit(base::Time::Now());
+}
+
+void ArcAppPerformanceTracingSession::FireTimerForTesting() {
+  tracing_timer_.FireNow();
+}
+
+void ArcAppPerformanceTracingSession::OnCommitForTesting(
+    const base::Time& timestamp) {
+  HandleCommit(timestamp);
+}
+
+void ArcAppPerformanceTracingSession::Start() {
+  DCHECK(!tracing_timer_.IsRunning());
+
+  VLOG(1) << "Start tracing for the category " << category_ << ".";
+
+  frame_deltas_.clear();
+  last_commit_timestamp_ = base::Time();
+
+  exo::Surface* const surface = exo::GetShellMainSurface(window_);
+  DCHECK(surface);
+  surface->AddSurfaceObserver(this);
+
+  // Schedule result analyzing at the end of tracing.
+  tracing_timer_.Start(FROM_HERE, tracing_period_,
+                       base::BindOnce(&ArcAppPerformanceTracingSession::Analyze,
+                                      base::Unretained(this)));
+  tracing_active_ = true;
+}
+
+void ArcAppPerformanceTracingSession::Stop() {
+  tracing_active_ = false;
+  tracing_timer_.Stop();
+  exo::Surface* const surface = exo::GetShellMainSurface(window_);
+  // Surface might be destroyed.
+  if (surface)
+    surface->RemoveSurfaceObserver(this);
+}
+
+void ArcAppPerformanceTracingSession::HandleCommit(
+    const base::Time& timestamp) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (last_commit_timestamp_.is_null()) {
+    last_commit_timestamp_ = timestamp;
+    return;
+  }
+
+  const base::TimeDelta frame_delta = timestamp - last_commit_timestamp_;
+  last_commit_timestamp_ = timestamp;
+
+  const uint64_t display_frames_passed =
+      (frame_delta + kTargetFrameTime / 2) / kTargetFrameTime;
+  if (display_frames_passed >= kIdleThresholdFrames) {
+    // Idle is detected, try the next time.
+    Stop();
+    Schedule();
+    return;
+  }
+  frame_deltas_.emplace_back(frame_delta);
+}
+
+void ArcAppPerformanceTracingSession::Analyze() {
+  // No more data is needed, stop active tracing.
+  Stop();
+
+  // Check last commit timestamp if we are in idle at this moment.
+  const base::TimeDelta last_frame_delta =
+      base::Time::Now() - last_commit_timestamp_;
+  if (last_frame_delta >= kTargetFrameTime * kIdleThresholdFrames) {
+    // Current idle state is detected, try next time.
+    Schedule();
+    return;
+  }
+
+  VLOG(1) << "Analyze tracing for the category " << category_ << ".";
+
+  DCHECK(!frame_deltas_.empty());
+
+  double vsync_error_deviation_accumulator = 0;
+  for (const auto& frame_delta : frame_deltas_) {
+    // Calculate the number of display frames passed between two updates.
+    // Ideally we should have one frame for target FPS. In case the app drops
+    // frames, the number of dropped frames would be accounted. The result is
+    // fractional part of target frame interval |kTargetFrameTime| and is less
+    // or equal half of it.
+    const uint64_t display_frames_passed =
+        (frame_delta + kTargetFrameTime / 2) / kTargetFrameTime;
+    // Calculate difference from the ideal commit time, that should happen with
+    // equal delay for each display frame.
+    const base::TimeDelta vsync_error =
+        frame_delta - display_frames_passed * kTargetFrameTime;
+    vsync_error_deviation_accumulator +=
+        (vsync_error.InMicrosecondsF() * vsync_error.InMicrosecondsF());
+  }
+  const double vsync_error =
+      sqrt(vsync_error_deviation_accumulator / frame_deltas_.size());
+
+  std::sort(frame_deltas_.begin(), frame_deltas_.end());
+  // Get 10% and 90% indices.
+  const size_t lower_position = frame_deltas_.size() / 10;
+  const size_t upper_position = frame_deltas_.size() - 1 - lower_position;
+  const double quality = frame_deltas_[lower_position].InMicrosecondsF() /
+                         frame_deltas_[upper_position].InMicrosecondsF();
+
+  const double fps = frame_deltas_.size() / tracing_period_.InSecondsF();
+  VLOG(1) << "Analyzing is done for " << category_ << " "
+          << " FPS: " << fps << ", quality: " << quality
+          << ", vsync_error: " << vsync_error;
+
+  ReportFPS(category_, fps);
+  ReportCommitError(category_, vsync_error);
+  ReportQuality(category_, quality);
+
+  owner_->SetReported(category_);
+
+  // Reschedule the next tracing session.
+  Schedule();
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_session.h b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_session.h
new file mode 100644
index 0000000..735d1da
--- /dev/null
+++ b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_session.h
@@ -0,0 +1,96 @@
+// Copyright 2019 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_ARC_TRACING_ARC_APP_PERFORMANCE_TRACING_SESSION_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_TRACING_ARC_APP_PERFORMANCE_TRACING_SESSION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "components/exo/surface_observer.h"
+
+namespace aura {
+class Window;
+}  // namespace aura
+
+namespace exo {
+class Surface;
+}  // namespace exo
+
+namespace arc {
+
+class ArcAppPerformanceTracing;
+
+// Implements Surface commit tracing for the target window.
+class ArcAppPerformanceTracingSession : public exo::SurfaceObserver {
+ public:
+  ArcAppPerformanceTracingSession(ArcAppPerformanceTracing* owner,
+                                  aura::Window* window,
+                                  const std::string& category,
+                                  const base::TimeDelta& tracing_period);
+  ~ArcAppPerformanceTracingSession() override;
+
+  // Schedules tracing with a delay based on condition if tracing category was
+  // previously reported or not. Creator of |ArcAppPerformanceTracingSession| is
+  // responsible for the initial scheduling. This can internally re-scheduled
+  // during the life-cycle of the tracing session.
+  void Schedule();
+
+  // exo::SurfaceObserver:
+  void OnSurfaceDestroying(exo::Surface* surface) override;
+  void OnCommit(exo::Surface* surface) override;
+
+  void FireTimerForTesting();
+  void OnCommitForTesting(const base::Time& timestamp);
+
+  bool tracing_active() const { return tracing_active_; }
+  const aura::Window* window() const { return window_; }
+
+ private:
+  // Starts tracing by observing commits to the |exo::Surface| attached to the
+  // current |window_|.
+  void Start();
+
+  // Stops tracing for the current |window_|.
+  void Stop();
+
+  // Handles the next commit update. This is unified handler for testing and
+  // production code.
+  void HandleCommit(const base::Time& timestamp);
+
+  // Stops current tracing, analyzes captured tracing results and schedules the
+  // next tracing for the current |window_|.
+  void Analyze();
+
+  // Unowned pointer.
+  ArcAppPerformanceTracing* const owner_;
+  aura::Window* const window_;
+
+  // Current tracing category.
+  const std::string category_;
+
+  // Timer to start Surface commit tracing delayed.
+  base::OneShotTimer tracing_timer_;
+
+  // Period for tracing sessions.
+  const base::TimeDelta tracing_period_;
+
+  // Timestamp of last commit event.
+  base::Time last_commit_timestamp_;
+
+  // Accumulator for commit deltas.
+  std::vector<base::TimeDelta> frame_deltas_;
+
+  // Indicates that tracing is in active state.
+  bool tracing_active_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppPerformanceTracingSession);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_TRACING_ARC_APP_PERFORMANCE_TRACING_SESSION_H_
diff --git a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_unittest.cc b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_unittest.cc
new file mode 100644
index 0000000..4f7bdc40
--- /dev/null
+++ b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_unittest.cc
@@ -0,0 +1,259 @@
+// Copyright 2019 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 <memory>
+#include <vector>
+
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h"
+#include "chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_session.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_test.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/exo/shell_surface_util.h"
+#include "components/exo/surface.h"
+#include "components/exo/wm_helper.h"
+#include "components/exo/wm_helper_chromeos.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/public/activation_change_observer.h"
+
+namespace arc {
+
+namespace {
+
+constexpr char kFocusAppPackage[] = "focus.app.package";
+constexpr char kFocusAppActivity[] = "focus.app.package.Activity";
+constexpr char kFocusCategory[] = "OnlineGame";
+constexpr char kNonFocusAppPackage[] = "nonfocus.app.package";
+constexpr char kNonFocusAppActivity[] = "nonfocus.app.package.Activity";
+// For 20 frames.
+constexpr base::TimeDelta kTestPeriod =
+    base::TimeDelta::FromSeconds(1) / (60 / 20);
+
+// Creates app window as ARC++ window.
+views::Widget* CreateArcWindow(const std::string& window_app_id) {
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
+  params.bounds = gfx::Rect(5, 5, 20, 20);
+  params.context = nullptr;
+  views::Widget* widget = new views::Widget();
+  widget->Init(params);
+  // Set ARC id before showing the window to be recognized in
+  // ArcAppWindowLauncherController.
+  exo::SetShellApplicationId(widget->GetNativeWindow(), window_app_id);
+  exo::SetShellMainSurface(widget->GetNativeWindow(), new exo::Surface());
+  widget->Show();
+  widget->Activate();
+  return widget;
+}
+
+// Creates name of histogram with required statistics.
+std::string GetFocusStatisticName(const std::string& name) {
+  return base::StringPrintf("Arc.Runtime.Performance.%s.%s", name.c_str(),
+                            kFocusCategory);
+}
+
+// Reads statistics value from histogram.
+int64_t ReadFocusStatistics(const std::string& name) {
+  const base::HistogramBase* histogram =
+      base::StatisticsRecorder::FindHistogram(GetFocusStatisticName(name));
+  DCHECK(histogram);
+
+  std::unique_ptr<base::HistogramSamples> samples =
+      histogram->SnapshotFinalDelta();
+  DCHECK(samples.get());
+  DCHECK_EQ(1, samples->TotalCount());
+  return samples->sum();
+}
+
+}  // namespace
+
+// BrowserWithTestWindowTest contains required ash/shell support that would not
+// be possible to use directly.
+class ArcAppPerformanceTracingTest : public BrowserWithTestWindowTest {
+ public:
+  ArcAppPerformanceTracingTest() = default;
+  ~ArcAppPerformanceTracingTest() override = default;
+
+  // testing::Test:
+  void SetUp() override {
+    BrowserWithTestWindowTest::SetUp();
+    wm_helper_ = std::make_unique<exo::WMHelperChromeOS>();
+    exo::WMHelper::SetInstance(wm_helper_.get());
+
+    arc_test_.SetUp(profile());
+
+    ArcAppPerformanceTracing::SetFocusAppForTesting(
+        kFocusAppPackage, kFocusAppActivity, kFocusCategory);
+
+    performance_tracing_ = std::make_unique<ArcAppPerformanceTracing>(
+        profile(), nullptr /* bridge, unused */);
+
+    performance_tracing_->SetTracingPeriodForTesting(kTestPeriod);
+  }
+
+  void TearDown() override {
+    performance_tracing_->Shutdown();
+    performance_tracing_.reset();
+    arc_test_.TearDown();
+    exo::WMHelper::SetInstance(nullptr);
+    wm_helper_.reset();
+    BrowserWithTestWindowTest::TearDown();
+  }
+
+ protected:
+  // Ensures that tracing is active.
+  void StartArcFocusAppTracing() {
+    views::Widget* const arc_widget = CreateArcWindow("org.chromium.arc.1");
+    DCHECK(arc_widget && arc_widget->GetNativeWindow());
+    performance_tracing().OnWindowActivated(
+        wm::ActivationChangeObserver::ActivationReason::ACTIVATION_CLIENT,
+        arc_widget->GetNativeWindow(), arc_widget->GetNativeWindow());
+    performance_tracing().OnTaskCreated(1 /* task_Id */, kFocusAppPackage,
+                                        kFocusAppActivity,
+                                        std::string() /* intent */);
+    DCHECK(performance_tracing().session());
+    DCHECK(!performance_tracing().session()->tracing_active());
+    performance_tracing().session()->FireTimerForTesting();
+    DCHECK(performance_tracing().session());
+    DCHECK(performance_tracing().session()->tracing_active());
+  }
+
+  // Sends sequence of commits where each commit is delayed for specific delta
+  // from |deltas|.
+  void PlaySequence(const std::vector<base::TimeDelta>& deltas) {
+    DCHECK(performance_tracing().session());
+    DCHECK(performance_tracing().session()->tracing_active());
+    base::Time timestamp = base::Time::Now();
+    performance_tracing().session()->OnCommitForTesting(timestamp);
+    for (const base::TimeDelta& delta : deltas) {
+      timestamp += delta;
+      performance_tracing().session()->OnCommitForTesting(timestamp);
+    }
+    // Fire timer at the end to finish statistics tracing.
+    performance_tracing().session()->FireTimerForTesting();
+  }
+
+  ArcAppPerformanceTracing& performance_tracing() {
+    return *performance_tracing_;
+  }
+
+ private:
+  ArcAppTest arc_test_;
+  std::unique_ptr<exo::WMHelper> wm_helper_;
+  std::unique_ptr<ArcAppPerformanceTracing> performance_tracing_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppPerformanceTracingTest);
+};
+
+TEST_F(ArcAppPerformanceTracingTest, TracingScheduled) {
+  // By default it is inactive.
+  EXPECT_FALSE(performance_tracing().session());
+
+  // Report task first.
+  performance_tracing().OnTaskCreated(1 /* task_Id */, kFocusAppPackage,
+                                      kFocusAppActivity,
+                                      std::string() /* intent */);
+  EXPECT_FALSE(performance_tracing().session());
+
+  // Create window second.
+  views::Widget* const arc_widget1 = CreateArcWindow("org.chromium.arc.1");
+  ASSERT_TRUE(arc_widget1);
+  ASSERT_TRUE(arc_widget1->GetNativeWindow());
+  performance_tracing().OnWindowActivated(
+      wm::ActivationChangeObserver::ActivationReason::ACTIVATION_CLIENT,
+      arc_widget1->GetNativeWindow(), nullptr /* lost_active */);
+  ASSERT_TRUE(performance_tracing().session());
+  EXPECT_FALSE(performance_tracing().session()->tracing_active());
+
+  // Test reverse order, create window first.
+  views::Widget* const arc_widget2 = CreateArcWindow("org.chromium.arc.2");
+  ASSERT_TRUE(arc_widget2);
+  ASSERT_TRUE(arc_widget2->GetNativeWindow());
+  performance_tracing().OnWindowActivated(
+      wm::ActivationChangeObserver::ActivationReason::ACTIVATION_CLIENT,
+      arc_widget2->GetNativeWindow(), arc_widget2->GetNativeWindow());
+  // Task is not yet created, this also resets previous tracing.
+  EXPECT_FALSE(performance_tracing().session());
+  // Report task second.
+  performance_tracing().OnTaskCreated(2 /* task_Id */, kFocusAppPackage,
+                                      kFocusAppActivity,
+                                      std::string() /* intent */);
+  ASSERT_TRUE(performance_tracing().session());
+  EXPECT_FALSE(performance_tracing().session()->tracing_active());
+}
+
+TEST_F(ArcAppPerformanceTracingTest, TracingNotScheduledForNonFocusApp) {
+  views::Widget* const arc_widget = CreateArcWindow("org.chromium.arc.1");
+  ASSERT_TRUE(arc_widget);
+  ASSERT_TRUE(arc_widget->GetNativeWindow());
+  performance_tracing().OnWindowActivated(
+      wm::ActivationChangeObserver::ActivationReason::ACTIVATION_CLIENT,
+      arc_widget->GetNativeWindow(), arc_widget->GetNativeWindow());
+  EXPECT_FALSE(performance_tracing().session());
+  performance_tracing().OnTaskCreated(1 /* task_Id */, kNonFocusAppPackage,
+                                      kNonFocusAppActivity,
+                                      std::string() /* intent */);
+  EXPECT_FALSE(performance_tracing().session());
+}
+
+TEST_F(ArcAppPerformanceTracingTest, TracingStoppedOnIdle) {
+  StartArcFocusAppTracing();
+  const base::TimeDelta normal_interval = base::TimeDelta::FromSeconds(1) / 60;
+  base::Time timestamp = base::Time::Now();
+  performance_tracing().session()->OnCommitForTesting(timestamp);
+  // Expected updates;
+  timestamp += normal_interval;
+  performance_tracing().session()->OnCommitForTesting(timestamp);
+  ASSERT_TRUE(performance_tracing().session());
+  EXPECT_TRUE(performance_tracing().session()->tracing_active());
+
+  timestamp += normal_interval * 5;
+  performance_tracing().session()->OnCommitForTesting(timestamp);
+  ASSERT_TRUE(performance_tracing().session());
+  EXPECT_TRUE(performance_tracing().session()->tracing_active());
+
+  // Too long update.
+  timestamp += normal_interval * 10;
+  performance_tracing().session()->OnCommitForTesting(timestamp);
+  // Tracing is rescheduled and no longer active.
+  ASSERT_TRUE(performance_tracing().session());
+  EXPECT_FALSE(performance_tracing().session()->tracing_active());
+}
+
+TEST_F(ArcAppPerformanceTracingTest, StatisticsReported) {
+  StartArcFocusAppTracing();
+  const base::TimeDelta normal_interval = base::TimeDelta::FromSeconds(1) / 60;
+  const base::TimeDelta error1 = base::TimeDelta::FromMicroseconds(100);
+  const base::TimeDelta error2 = base::TimeDelta::FromMicroseconds(200);
+  const base::TimeDelta error3 = base::TimeDelta::FromMicroseconds(300);
+  const std::vector<base::TimeDelta> sequence = {
+      normal_interval + error1,
+      normal_interval + error2,
+      // One frame skip
+      normal_interval * 2 + error3,
+      normal_interval - error1,
+      normal_interval - error2,
+      // Two frames skip
+      normal_interval * 3 - error3,
+      normal_interval + error1,
+      normal_interval + error2,
+      normal_interval * 2 + error3,
+      normal_interval - error1,
+      normal_interval * 2 - error2,
+      normal_interval - error3,
+      normal_interval + error1,
+      normal_interval + error2,
+      normal_interval + error3,
+  };
+  EXPECT_FALSE(performance_tracing().WasReported(kFocusCategory));
+  PlaySequence(sequence);
+  EXPECT_TRUE(performance_tracing().WasReported(kFocusCategory));
+  EXPECT_EQ(45L, ReadFocusStatistics("FPS"));
+  EXPECT_EQ(216L, ReadFocusStatistics("CommitDeviation"));
+  EXPECT_EQ(48L, ReadFocusStatistics("RenderQuality"));
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session.cc b/chrome/browser/chromeos/login/demo_mode/demo_session.cc
index f5e140d8..30586fb 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_session.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_session.cc
@@ -37,7 +37,6 @@
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/tpm/install_attributes.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -346,10 +345,6 @@
 // static
 base::Value DemoSession::GetCountryList() {
   base::Value country_list(base::Value::Type::LIST);
-  if (!base::FeatureList::IsEnabled(
-          switches::kSupportCountryCustomizationInDemoMode)) {
-    return country_list;
-  }
   const std::string current_country =
       g_browser_process->local_state()->GetString(prefs::kDemoModeCountry);
   const std::string current_locale = g_browser_process->GetApplicationLocale();
@@ -506,19 +501,15 @@
 void DemoSession::OnSessionStateChanged() {
   switch (session_manager::SessionManager::Get()->session_state()) {
     case session_manager::SessionState::LOGIN_PRIMARY:
-      if (base::FeatureList::IsEnabled(switches::kShowSplashScreenInDemoMode)) {
-        EnsureOfflineResourcesLoaded(base::BindOnce(
-            &DemoSession::ShowSplashScreen, weak_ptr_factory_.GetWeakPtr()));
-      }
+      EnsureOfflineResourcesLoaded(base::BindOnce(
+          &DemoSession::ShowSplashScreen, weak_ptr_factory_.GetWeakPtr()));
       break;
     case session_manager::SessionState::ACTIVE:
       if (ShouldRemoveSplashScreen())
         RemoveSplashScreen();
 
       // SystemTrayClient may not exist in unit tests.
-      if (SystemTrayClient::Get() &&
-          base::FeatureList::IsEnabled(
-              switches::kShowLanguageToggleInDemoMode)) {
+      if (SystemTrayClient::Get()) {
         const std::string current_locale_iso_code =
             ProfileManager::GetActiveUserProfile()->GetPrefs()->GetString(
                 language::prefs::kApplicationLocale);
@@ -566,8 +557,7 @@
 bool DemoSession::ShouldRemoveSplashScreen() {
   // TODO(crbug.com/934979): Launch screensaver after active session starts, so
   // that there's no need to check session state here.
-  return base::FeatureList::IsEnabled(switches::kShowSplashScreenInDemoMode) &&
-         session_manager::SessionManager::Get()->session_state() ==
+  return session_manager::SessionManager::Get()->session_state() ==
              session_manager::SessionState::ACTIVE &&
          screensaver_activated_;
 }
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session.h b/chrome/browser/chromeos/login/demo_mode/demo_session.h
index a161db1..d181f6c 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_session.h
+++ b/chrome/browser/chromeos/login/demo_mode/demo_session.h
@@ -73,9 +73,15 @@
     kMaxValue = kExtensionApi
   };
 
-  // The list of countries that Demo Mode supports.
+  // The list of countries that Demo Mode supports, ie the countries we have
+  // created OUs and admin users for in the admin console.
+  // Sorted by the English name of the country (not the country code), except US
+  // is first.
+  // TODO(crbug.com/983359): Sort these by country name in the current locale
+  // instead of using this hard-coded US-centric order.
   static constexpr char kSupportedCountries[][3] = {
-      "us", "be", "ca", "dk", "fi", "fr", "ie", "lu", "nl", "no", "se", "gb"};
+      "us", "be", "ca", "dk", "fi", "fr", "de",
+      "ie", "jp", "lu", "nl", "no", "se", "gb"};
 
   static std::string DemoConfigToString(DemoModeConfig config);
 
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc b/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc
index 338b7919..3142fc2 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/timer/mock_timer.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
@@ -33,7 +32,6 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/session_manager/core/session_manager.h"
@@ -72,9 +70,6 @@
   ~DemoSessionTest() override = default;
 
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        chromeos::switches::kShowSplashScreenInDemoMode);
-
     ASSERT_TRUE(profile_manager_->SetUp());
     chromeos::DBusThreadManager::Initialize();
     DemoSession::SetDemoConfigForTesting(DemoSession::DemoModeConfig::kOnline);
@@ -158,7 +153,6 @@
   BrowserProcessPlatformPartTestApi browser_process_platform_part_test_api_;
   user_manager::ScopedUserManager scoped_user_manager_;
   chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
-  base::test::ScopedFeatureList scoped_feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(DemoSessionTest);
 };
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc
index e86792c..26a35d1 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc
@@ -13,7 +13,6 @@
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/time/time_to_iso8601.h"
 #include "base/timer/timer.h"
 #include "base/values.h"
@@ -148,8 +147,6 @@
   // LoginTestManager:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     LoginManagerTest::SetUpCommandLine(command_line);
-    scoped_feature_list_.InitAndEnableFeature(
-        chromeos::switches::kSupportCountryCustomizationInDemoMode);
     command_line->AppendSwitchASCII(switches::kArcAvailability,
                                     "officially-supported");
     ASSERT_TRUE(arc::IsArcAvailable());
@@ -460,7 +457,6 @@
   // TODO(agawronska): Maybe create a separate test fixture for offline setup.
   base::ScopedTempDir fake_demo_resources_dir_;
   policy::MockCloudPolicyStore mock_policy_store_;
-  base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<base::AutoReset<bool>> official_build_override_;
 
   DISALLOW_COPY_AND_ASSIGN(DemoSetupTest);
@@ -604,7 +600,9 @@
        {"dk", "Denmark"},
        {"fi", "Finland"},
        {"fr", "France"},
+       {"de", "Germany"},
        {"ie", "Ireland"},
+       {"jp", "Japan"},
        {"lu", "Luxembourg"},
        {"nl", "Netherlands"},
        {"no", "Norway"},
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.cc b/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.cc
index 9e3c5d4..ce20008e 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/chromeos/policy/enrollment_config.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/system/statistics_provider.h"
 #include "chromeos/tpm/install_attributes.h"
@@ -463,14 +462,10 @@
 
 // static
 std::string DemoSetupController::GetSubOrganizationEmail() {
-  if (!base::FeatureList::IsEnabled(
-          switches::kSupportCountryCustomizationInDemoMode)) {
-    return std::string();
-  }
   const std::string country =
       g_browser_process->local_state()->GetString(prefs::kDemoModeCountry);
   const base::flat_set<std::string> kCountriesWithCustomization(
-      {"dk", "fi", "fr", "nl", "no", "se"});
+      {"de", "dk", "fi", "fr", "jp", "nl", "no", "se"});
   if (kCountriesWithCustomization.contains(country))
     return "admin-" + country + "@" + policy::kDemoModeDomain;
   return std::string();
diff --git a/chrome/browser/chromeos/system_logs/OWNERS b/chrome/browser/chromeos/system_logs/OWNERS
index 9fe2069..bd30e9f 100644
--- a/chrome/browser/chromeos/system_logs/OWNERS
+++ b/chrome/browser/chromeos/system_logs/OWNERS
@@ -1,3 +1,4 @@
 afakhry@chromium.org
+jkardatzke@chromium.org
 
 # COMPONENT: Platform>Apps>Feedback
diff --git a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
index f6da479..12056c44 100644
--- a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
+++ b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
@@ -42,6 +42,7 @@
   const char* log_file_relative_path;
 } kUserLogs[] = {
     {"chrome_user_log", "log/chrome"},
+    {"chrome_user_log.PREVIOUS", "log/chrome.PREVIOUS"},
     {"libassistant_user_log", "log/libassistant.log"},
     {"login-times", "login-times"},
     {"logout-times", "logout-times"},
diff --git a/chrome/browser/enterprise_reporting/profile_report_generator.cc b/chrome/browser/enterprise_reporting/profile_report_generator.cc
index fdfe85a6..4aba7780 100644
--- a/chrome/browser/enterprise_reporting/profile_report_generator.cc
+++ b/chrome/browser/enterprise_reporting/profile_report_generator.cc
@@ -36,12 +36,13 @@
 void ProfileReportGenerator::MaybeGenerate(const base::FilePath& path,
                                            const std::string& name,
                                            ReportCallback callback) {
+  DCHECK(!callback_);
   callback_ = std::move(callback);
 
   profile_ = g_browser_process->profile_manager()->GetProfileByPath(path);
 
   if (!profile_) {
-    CheckReportStatusAsync();
+    CheckReportStatus();
     return;
   }
 
@@ -66,7 +67,7 @@
     GetExtensionPolicyInfo();
   }
 
-  CheckReportStatusAsync();
+  CheckReportStatus();
   return;
 }
 
@@ -133,10 +134,4 @@
   std::move(callback_).Run(std::move(report_));
 }
 
-void ProfileReportGenerator::CheckReportStatusAsync() {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&ProfileReportGenerator::CheckReportStatus,
-                                weak_ptr_factory_.GetWeakPtr()));
-}
-
 }  // namespace enterprise_reporting
diff --git a/chrome/browser/enterprise_reporting/profile_report_generator.h b/chrome/browser/enterprise_reporting/profile_report_generator.h
index 64c0c3cd..7372ed2 100644
--- a/chrome/browser/enterprise_reporting/profile_report_generator.h
+++ b/chrome/browser/enterprise_reporting/profile_report_generator.h
@@ -60,7 +60,6 @@
   void OnPluginsLoaded(const std::vector<content::WebPluginInfo>& plugins);
 
   void CheckReportStatus();
-  void CheckReportStatusAsync();
 
   Profile* profile_;
   base::Value policies_;
diff --git a/chrome/browser/enterprise_reporting/report_generator.cc b/chrome/browser/enterprise_reporting/report_generator.cc
index 9f1d61b..b5ecdfb 100644
--- a/chrome/browser/enterprise_reporting/report_generator.cc
+++ b/chrome/browser/enterprise_reporting/report_generator.cc
@@ -29,6 +29,9 @@
 namespace enterprise_reporting {
 namespace {
 
+const size_t kMaximumReportSize =
+    5000000;  // The report size limitation is 5mb.
+
 std::string GetChromePath() {
   base::FilePath path;
   base::PathService::Get(base::DIR_EXE, &path);
@@ -37,15 +40,31 @@
 
 }  // namespace
 
-ReportGenerator::ReportGenerator() = default;
+ReportGenerator::ReportGenerator()
+    : maximum_report_size_(kMaximumReportSize), weak_ptr_factory_(this) {}
+
 ReportGenerator::~ReportGenerator() = default;
 
-std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>>
-ReportGenerator::Generate() {
+void ReportGenerator::Generate(ReportCallback callback) {
+  DCHECK(!callback_);
+  callback_ = std::move(callback);
   CreateBasicRequest();
+
+  if (basic_request_size_ > maximum_report_size_) {
+    // Basic request is already too large so we can't upload any valid report.
+    // Skip all Profiles and response an empty request list.
+    GetNextProfileReport(
+        basic_request_.browser_report().profile_info_list_size());
+    return;
+  }
+
   requests_.push_back(
       std::make_unique<em::ChromeDesktopReportRequest>(basic_request_));
-  return std::move(requests_);
+  GetNextProfileReport(0);
+}
+
+void ReportGenerator::SetMaximumReportSizeForTesting(size_t size) {
+  maximum_report_size_ = size;
 }
 
 void ReportGenerator::CreateBasicRequest() {
@@ -58,6 +77,7 @@
     basic_request_.mutable_browser_report()->add_profile_info_list()->Swap(
         profile.get());
   }
+  basic_request_size_ = basic_request_.ByteSizeLong();
 }
 
 std::unique_ptr<em::OSReport> ReportGenerator::GetOSReport() {
@@ -107,4 +127,57 @@
   return profiles;
 }
 
+void ReportGenerator::GetNextProfileReport(int profile_index) {
+  if (profile_index >=
+      basic_request_.browser_report().profile_info_list_size()) {
+    std::move(callback_).Run(std::move(requests_));
+    return;
+  }
+
+  auto basic_profile_report =
+      basic_request_.browser_report().profile_info_list(profile_index);
+  profile_report_generator_.MaybeGenerate(
+      base::FilePath::FromUTF8Unsafe(basic_profile_report.id()),
+      basic_profile_report.name(),
+      base::BindOnce(&ReportGenerator::OnProfileReportReady,
+                     weak_ptr_factory_.GetWeakPtr(), profile_index));
+}
+
+void ReportGenerator::OnProfileReportReady(
+    int profile_index,
+    std::unique_ptr<em::ChromeUserProfileInfo> profile_report) {
+  // Move to the next Profile if Profile is not loaded and there is no full
+  // report.
+  if (!profile_report) {
+    GetNextProfileReport(profile_index + 1);
+    return;
+  }
+
+  size_t profile_report_size = profile_report->ByteSizeLong();
+  size_t current_request_size = requests_.back()->ByteSizeLong();
+
+  if (current_request_size + profile_report_size <= maximum_report_size_) {
+    // The new full Profile report can be appended into the current request.
+    requests_.back()
+        ->mutable_browser_report()
+        ->mutable_profile_info_list(profile_index)
+        ->Swap(profile_report.get());
+  } else if (basic_request_size_ + profile_report_size <=
+             maximum_report_size_) {
+    // The new full Profile report is too big to be appended into the current
+    // request, move it to the next request if possible.
+    requests_.push_back(
+        std::make_unique<em::ChromeDesktopReportRequest>(basic_request_));
+    requests_.back()
+        ->mutable_browser_report()
+        ->mutable_profile_info_list(profile_index)
+        ->Swap(profile_report.get());
+  }
+  // Else: The new full Profile report is too big to be uploaded, skip this
+  // Profile report.
+  // TODO(crbug.com/956237): Record this event with UMA metrics.
+
+  GetNextProfileReport(profile_index + 1);
+}
+
 }  // namespace enterprise_reporting
diff --git a/chrome/browser/enterprise_reporting/report_generator.h b/chrome/browser/enterprise_reporting/report_generator.h
index 1881c6f24..87e5ddd 100644
--- a/chrome/browser/enterprise_reporting/report_generator.h
+++ b/chrome/browser/enterprise_reporting/report_generator.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "chrome/browser/enterprise_reporting/profile_report_generator.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 
 namespace em = enterprise_management;
@@ -18,10 +19,15 @@
 
 class ReportGenerator {
  public:
+  using ReportCallback = base::OnceCallback<void(
+      std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>>)>;
+
   ReportGenerator();
   ~ReportGenerator();
 
-  std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>> Generate();
+  void Generate(ReportCallback callback);
+
+  void SetMaximumReportSizeForTesting(size_t size);
 
  protected:
   // Creates a basic request that will be used by all Profiles.
@@ -50,10 +56,24 @@
   std::vector<std::unique_ptr<em::ChromeUserProfileInfo>> GetProfiles();
 
  private:
+  void GetNextProfileReport(int profile_index);
+  void OnProfileReportReady(
+      int profile_index,
+      std::unique_ptr<em::ChromeUserProfileInfo> profile_report);
+
+  ProfileReportGenerator profile_report_generator_;
+
+  ReportCallback callback_;
+
   std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>> requests_;
 
   // Basic information that is shared among requests.
   em::ChromeDesktopReportRequest basic_request_;
+  size_t basic_request_size_;
+
+  size_t maximum_report_size_;
+
+  base::WeakPtrFactory<ReportGenerator> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ReportGenerator);
 };
diff --git a/chrome/browser/enterprise_reporting/report_generator_unittest.cc b/chrome/browser/enterprise_reporting/report_generator_unittest.cc
index 7a91250..868c0fc 100644
--- a/chrome/browser/enterprise_reporting/report_generator_unittest.cc
+++ b/chrome/browser/enterprise_reporting/report_generator_unittest.cc
@@ -6,23 +6,30 @@
 
 #include <set>
 
-#include "base/logging.h"
+#include "base/run_loop.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/account_id/account_id.h"
+#include "content/public/browser/plugin_service.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/extension_builder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace em = enterprise_management;
 
 namespace enterprise_reporting {
 namespace {
+
 #if !defined(OS_CHROMEOS)
+constexpr char kProfile[] = "Profile";
+
 // We only upload serial number on Windows.
 void VerifySerialNumber(const std::string& serial_number) {
 #if defined(OS_WIN)
@@ -32,7 +39,14 @@
 #endif
 }
 
-const char kProfile1[] = "Profile";
+// Verify the name is in the set. Remove the name from the set afterwards.
+void FindAndRemoveProfileName(std::set<std::string>* names,
+                              const std::string& name) {
+  auto it = names->find(name);
+  EXPECT_NE(names->end(), it);
+  names->erase(it);
+}
+
 #endif
 }  // namespace
 
@@ -43,7 +57,14 @@
       : profile_manager_(TestingBrowserProcess::GetGlobal()) {}
   ~ReportGeneratorTest() override = default;
 
-  void SetUp() override { ASSERT_TRUE(profile_manager_.SetUp()); }
+  void SetUp() override {
+    ASSERT_TRUE(profile_manager_.SetUp());
+
+    profile_manager_.CreateGuestProfile();
+    profile_manager_.CreateSystemProfile();
+
+    content::PluginService::GetInstance()->Init();
+  }
 
   // Creates |number| of Profiles. Returns the set of their names. The profile
   // names begin with Profile|start_index|. Profile instances are created if
@@ -55,7 +76,7 @@
     std::set<std::string> profile_names;
     for (int i = start_index; i < number; i++) {
       std::string profile_name =
-          std::string(kProfile1) + base::NumberToString(i);
+          std::string(kProfile) + base::NumberToString(i);
       if (is_active) {
         profile_manager_.CreateTestingProfile(profile_name);
       } else {
@@ -66,14 +87,63 @@
       }
       profile_names.insert(profile_name);
     }
-    profile_manager_.CreateGuestProfile();
-    profile_manager_.CreateSystemProfile();
     return profile_names;
   }
 
+  std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>>
+  GenerateRequests() {
+    base::RunLoop run_loop;
+    std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>> rets;
+    generator_.Generate(base::BindLambdaForTesting(
+        [&run_loop,
+         &rets](std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>>
+                    requests) {
+          rets = std::move(requests);
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+    return rets;
+  }
+
+  // Verify the profile report matches actual Profile setup.
+  void VerifyProfileReport(const std::set<std::string>& active_profiles_names,
+                           const std::set<std::string>& inactive_profiles_names,
+                           const em::BrowserReport& actual_browser_report) {
+    int expected_profile_number =
+        active_profiles_names.size() + inactive_profiles_names.size();
+    EXPECT_EQ(expected_profile_number,
+              actual_browser_report.profile_info_list_size());
+
+    auto mutable_active_profiles_names(active_profiles_names);
+    auto mutable_inactive_profiles_names(inactive_profiles_names);
+    for (int i = 0; i < expected_profile_number; i++) {
+      auto actual_profile_info = actual_browser_report.profile_info_list(i);
+      std::string actual_profile_name = actual_profile_info.name();
+
+      // Verify that the profile id is set as profile path.
+      EXPECT_EQ(profile_manager_.profiles_dir()
+                    .AppendASCII(actual_profile_name)
+                    .AsUTF8Unsafe(),
+                actual_profile_info.id());
+
+      EXPECT_TRUE(actual_profile_info.has_is_full_report());
+
+      // Activate profiles have full report while the inactive ones don't.
+      if (actual_profile_info.is_full_report())
+        FindAndRemoveProfileName(&mutable_active_profiles_names,
+                                 actual_profile_name);
+      else
+        FindAndRemoveProfileName(&mutable_inactive_profiles_names,
+                                 actual_profile_name);
+    }
+  }
+
   TestingProfileManager* profile_manager() { return &profile_manager_; }
+  ReportGenerator* generator() { return &generator_; }
 
  private:
+  ReportGenerator generator_;
+
   content::TestBrowserThreadBundle thread_bundle_;
   TestingProfileManager profile_manager_;
 
@@ -81,11 +151,9 @@
 };
 
 TEST_F(ReportGeneratorTest, GenerateBasicReport) {
-  int profile_number = 2;
-  auto profile_names = CreateProfiles(profile_number, /*is_active=*/false);
+  auto profile_names = CreateProfiles(/*number*/ 2, /*is_active=*/false);
 
-  ReportGenerator generator;
-  auto requests = generator.Generate();
+  auto requests = GenerateRequests();
   EXPECT_EQ(1u, requests.size());
 
   auto* basic_request = requests[0].get();
@@ -105,27 +173,93 @@
   EXPECT_NE(std::string(), browser_report.executable_path());
   EXPECT_TRUE(browser_report.has_channel());
 
-  EXPECT_EQ(profile_number, browser_report.profile_info_list_size());
-  for (int i = 0; i < profile_number; i++) {
-    auto profile_info = browser_report.profile_info_list(i);
-    std::string profile_name = profile_info.name();
-
-    // Verify that the profile id is set as profile path.
-    EXPECT_EQ(profile_manager()
-                  ->profiles_dir()
-                  .AppendASCII(profile_name)
-                  .AsUTF8Unsafe(),
-              profile_info.id());
-
-    // Verify that the basic report does not contain any full Profile report.
-    EXPECT_FALSE(profile_info.is_full_report());
-
-    // Verify the profile name is one of the profiles that were created above.
-    auto it = profile_names.find(profile_name);
-    EXPECT_NE(profile_names.end(), it);
-    profile_names.erase(it);
-  }
+  VerifyProfileReport(/*active_profile_names*/ std::set<std::string>(),
+                      profile_names, browser_report);
 }
+
+TEST_F(ReportGeneratorTest, GenerateActiveProfiles) {
+  auto inactive_profiles_names =
+      CreateProfiles(/*number*/ 2, /*is_active=*/false);
+  auto active_profiles_names =
+      CreateProfiles(/*number*/ 2, /*is_active=*/true, /*start_index*/ 2);
+
+  auto requests = GenerateRequests();
+  EXPECT_EQ(1u, requests.size());
+
+  VerifyProfileReport(active_profiles_names, inactive_profiles_names,
+                      requests[0]->browser_report());
+}
+
+TEST_F(ReportGeneratorTest, BasicReportIsTooBig) {
+  CreateProfiles(/*number*/ 2, /*is_active=*/false);
+
+  // Set a super small limitation.
+  generator()->SetMaximumReportSizeForTesting(5);
+
+  // Because the limitation is so small, no request can be created.
+  auto requests = GenerateRequests();
+  EXPECT_EQ(0u, requests.size());
+}
+
+TEST_F(ReportGeneratorTest, ReportSeparation) {
+  auto profile_names = CreateProfiles(/*number*/ 2, /*is_active=*/true);
+
+  // Set the limitation just below the size of the report so that it needs to be
+  // separated into two requests later.
+  auto requests = GenerateRequests();
+  EXPECT_EQ(1u, requests.size());
+  generator()->SetMaximumReportSizeForTesting(requests[0]->ByteSizeLong() - 30);
+
+  std::set<std::string> first_request_profiles, second_request_profiles;
+  first_request_profiles.insert(
+      requests[0]->browser_report().profile_info_list(0).name());
+  second_request_profiles.insert(
+      requests[0]->browser_report().profile_info_list(1).name());
+
+  requests = GenerateRequests();
+
+  // The first profile is activated in the first request only while the second
+  // profile is activated in the second request.
+  EXPECT_EQ(2u, requests.size());
+  VerifyProfileReport(first_request_profiles, second_request_profiles,
+                      requests[0]->browser_report());
+  VerifyProfileReport(second_request_profiles, first_request_profiles,
+                      requests[1]->browser_report());
+}
+
+TEST_F(ReportGeneratorTest, ProfileReportIsTooBig) {
+  TestingProfile* first_profile =
+      profile_manager()->CreateTestingProfile(kProfile);
+  std::set<std::string> first_profile_name = {kProfile};
+
+  // Add more things into the Profile to make the report bigger.
+  extensions::ExtensionRegistry* extension_registry =
+      extensions::ExtensionRegistry::Get(first_profile);
+
+  std::string extension_name =
+      "a super super super super super super super super super super super "
+      "super super super super super super long extension name";
+  extension_registry->AddEnabled(extensions::ExtensionBuilder(extension_name)
+                                     .SetID("abcdefghijklmnoabcdefghijklmnoab")
+                                     .Build());
+
+  // Set the limitation just below the size of the report.
+  auto requests = GenerateRequests();
+  EXPECT_EQ(1u, requests.size());
+  generator()->SetMaximumReportSizeForTesting(requests[0]->ByteSizeLong() - 30);
+
+  // Add a smaller Profile.
+  auto second_profile_name = CreateProfiles(/*number*/ 1, /*is_active=*/true);
+
+  requests = GenerateRequests();
+
+  EXPECT_EQ(1u, requests.size());
+  // Only the second Profile is activated while the first one is too big to be
+  // reported.
+  VerifyProfileReport(second_profile_name, first_profile_name,
+                      requests[0]->browser_report());
+}
+
 #endif
 
 }  // namespace enterprise_reporting
diff --git a/chrome/browser/extensions/api/management/management_api_non_persistent_apitest.cc b/chrome/browser/extensions/api/management/management_api_non_persistent_apitest.cc
index 046eea47..0198b9ed 100644
--- a/chrome/browser/extensions/api/management/management_api_non_persistent_apitest.cc
+++ b/chrome/browser/extensions/api/management/management_api_non_persistent_apitest.cc
@@ -7,8 +7,10 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/result_catcher.h"
+#include "extensions/test/test_extension_dir.h"
 
 namespace extensions {
 
@@ -35,8 +37,6 @@
 
 // Tests management API from a non-persistent extension (event page or
 // Service Worker).
-//
-// TODO(lazyboy): Move ServiceWorkerBasedBackgroundTest.UninstallSelf here.
 class ManagementApiNonPersistentApiTest
     : public ExtensionApiTest,
       public testing::WithParamInterface<ContextType> {
@@ -49,6 +49,44 @@
   }
 };
 
+// Tests chrome.management.uninstallSelf API.
+IN_PROC_BROWSER_TEST_P(ManagementApiNonPersistentApiTest, UninstallSelf) {
+  constexpr char kEventPageBackgroundScript[] = R"({"scripts": ["script.js"]})";
+  constexpr char kServiceWorkerBackgroundScript[] =
+      R"({"service_worker": "script.js"})";
+
+  constexpr char kManifest[] =
+      R"({
+           "name": "Test Extension",
+           "manifest_version": 2,
+           "version": "0.1",
+           "background": %s
+         })";
+  std::string manifest =
+      base::StringPrintf(kManifest, GetParam() == ContextType::kEventPage
+                                        ? kEventPageBackgroundScript
+                                        : kServiceWorkerBackgroundScript);
+
+  // This script uninstalls itself.
+  constexpr char kScript[] =
+      "chrome.management.uninstallSelf({showConfirmDialog: false});";
+
+  TestExtensionDir test_dir;
+
+  test_dir.WriteManifest(manifest);
+  test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
+
+  // Construct this before loading the extension, since the extension will
+  // immediately uninstall itself when it loads.
+  extensions::TestExtensionRegistryObserver observer(
+      extensions::ExtensionRegistry::Get(browser()->profile()));
+
+  base::FilePath path = test_dir.Pack();
+  scoped_refptr<const Extension> extension = LoadExtension(path);
+
+  EXPECT_EQ(extension, observer.WaitForExtensionUninstalled());
+}
+
 // Tests chrome.management.uninstall with a real user gesture
 // (i.e. browserAction.onClicked event).
 IN_PROC_BROWSER_TEST_P(ManagementApiNonPersistentApiTest,
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index 9bbdf975..9b2b499 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -60,7 +60,6 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/browser/service_worker_task_queue.h"
-#include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/common/api/test.h"
 #include "extensions/common/value_builder.h"
 #include "extensions/common/verifier_formats.h"
@@ -1787,35 +1786,6 @@
   EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, UninstallSelf) {
-  constexpr char kManifest[] =
-      R"({
-           "name": "Test Extension",
-           "manifest_version": 2,
-           "version": "0.1",
-           "background": {"service_worker": "script.js"}
-         })";
-
-  // This script uninstalls itself.
-  constexpr char kScript[] =
-      "chrome.management.uninstallSelf({showConfirmDialog: false});";
-
-  TestExtensionDir test_dir;
-
-  test_dir.WriteManifest(kManifest);
-  test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
-
-  // Construct this before loading the extension, since the extension will
-  // immediately uninstall itself when it loads.
-  extensions::TestExtensionRegistryObserver observer(
-      extensions::ExtensionRegistry::Get(browser()->profile()));
-
-  base::FilePath path = test_dir.Pack();
-  scoped_refptr<const Extension> extension = LoadExtension(path);
-
-  EXPECT_EQ(extension, observer.WaitForExtensionUninstalled());
-}
-
 IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
                        PRE_EventsAfterRestart) {
   ExtensionTestMessageListener event_added_listener("ready", false);
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 909c321..ea89020 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2085,7 +2085,8 @@
 const char kWebvrName[] = "WebVR";
 const char kWebvrDescription[] =
     "Enables access to experimental Virtual Reality functionality via the "
-    "WebVR 1.1 API. This feature will eventually be replaced by the WebXR "
+    "WebVR 1.1 API. This flag is deprecated and will be removed as soon as "
+    "Chrome 79. This feature will eventually be replaced by the WebXR "
     "Device API. Warning: Enabling this will also allow WebVR content on "
     "insecure origins to access these powerful APIs, and may pose a security "
     "risk. Controllers are exposed as Gamepads, and WebVR-specific attributes "
diff --git a/chrome/browser/metrics/browser_activity_watcher.cc b/chrome/browser/metrics/browser_activity_watcher.cc
new file mode 100644
index 0000000..3dec1d23
--- /dev/null
+++ b/chrome/browser/metrics/browser_activity_watcher.cc
@@ -0,0 +1,26 @@
+// Copyright 2019 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/metrics/browser_activity_watcher.h"
+
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_list_observer.h"
+
+BrowserActivityWatcher::BrowserActivityWatcher(
+    const base::RepeatingClosure& on_browser_list_change)
+    : on_browser_list_change_(on_browser_list_change) {
+  BrowserList::AddObserver(this);
+}
+
+BrowserActivityWatcher::~BrowserActivityWatcher() {
+  BrowserList::RemoveObserver(this);
+}
+
+void BrowserActivityWatcher::OnBrowserAdded(Browser* browser) {
+  on_browser_list_change_.Run();
+}
+
+void BrowserActivityWatcher::OnBrowserRemoved(Browser* browser) {
+  on_browser_list_change_.Run();
+}
diff --git a/chrome/browser/metrics/browser_activity_watcher.h b/chrome/browser/metrics/browser_activity_watcher.h
new file mode 100644
index 0000000..c6513d6
--- /dev/null
+++ b/chrome/browser/metrics/browser_activity_watcher.h
@@ -0,0 +1,32 @@
+// Copyright 2019 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_METRICS_BROWSER_ACTIVITY_WATCHER_H_
+#define CHROME_BROWSER_METRICS_BROWSER_ACTIVITY_WATCHER_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "chrome/browser/ui/browser_list_observer.h"
+
+// Helper that fires a callback every time a Browser object is added or removed
+// from the BrowserList. This class primarily exists to encapsulate this
+// behavior and reduce the number of platform-specific macros as Android doesn't
+// use BrowserList.
+class BrowserActivityWatcher : public BrowserListObserver {
+ public:
+  explicit BrowserActivityWatcher(
+      const base::RepeatingClosure& on_browser_list_change);
+  ~BrowserActivityWatcher() override;
+
+  // BrowserListObserver:
+  void OnBrowserAdded(Browser* browser) override;
+  void OnBrowserRemoved(Browser* browser) override;
+
+ private:
+  base::RepeatingClosure on_browser_list_change_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserActivityWatcher);
+};
+
+#endif  // CHROME_BROWSER_METRICS_BROWSER_ACTIVITY_WATCHER_H_
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index d2633e4..7f0c076 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -105,6 +105,8 @@
 #if defined(OS_ANDROID)
 #include "chrome/browser/metrics/android_metrics_provider.h"
 #include "chrome/browser/metrics/page_load_metrics_provider.h"
+#else
+#include "chrome/browser/metrics/browser_activity_watcher.h"
 #endif
 
 #if defined(OS_POSIX)
@@ -395,17 +397,9 @@
 
 ChromeMetricsServiceClient::ChromeMetricsServiceClient(
     metrics::MetricsStateManager* state_manager)
-    : metrics_state_manager_(state_manager),
-      waiting_for_collect_final_metrics_step_(false),
-      num_async_histogram_fetches_in_progress_(0)
-#if BUILDFLAG(ENABLE_PLUGINS)
-      ,
-      plugin_metrics_provider_(nullptr)
-#endif
-{
+    : metrics_state_manager_(state_manager) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   RecordCommandLineMetrics();
-  notification_listeners_active_ = RegisterForNotifications();
   incognito_observer_ = std::make_unique<IncognitoObserver>(
       base::BindRepeating(&ChromeMetricsServiceClient::UpdateRunningServices,
                           weak_ptr_factory_.GetWeakPtr()));
@@ -576,9 +570,10 @@
   local_state->ClearPref(prefs::kCrashReportingEnabled);
 #endif
 
-  metrics_service_.reset(
-      new metrics::MetricsService(metrics_state_manager_, this, local_state));
+  metrics_service_ = std::make_unique<metrics::MetricsService>(
+      metrics_state_manager_, this, local_state);
 
+  notification_listeners_active_ = RegisterForNotifications();
   RegisterMetricsServiceProviders();
 
   if (IsMetricsReportingForceEnabled() ||
@@ -886,10 +881,6 @@
 }
 
 bool ChromeMetricsServiceClient::RegisterForNotifications() {
-  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
-                 content::NotificationService::AllSources());
   registrar_.Add(this, chrome::NOTIFICATION_TAB_PARENTED,
                  content::NotificationService::AllSources());
   registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING,
@@ -902,15 +893,19 @@
                  content::NotificationService::AllSources());
   registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
                  content::NotificationService::AllSources());
+  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED,
+                 content::NotificationService::AllBrowserContextsAndSources());
 
   omnibox_url_opened_subscription_ =
       OmniboxEventGlobalTracker::GetInstance()->RegisterCallback(
           base::Bind(&ChromeMetricsServiceClient::OnURLOpenedFromOmnibox,
                      base::Unretained(this)));
 
-  // Observe history deletions for all profiles.
-  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED,
-                 content::NotificationService::AllBrowserContextsAndSources());
+#if !defined(OS_ANDROID)
+  browser_activity_watcher_ = std::make_unique<BrowserActivityWatcher>(
+      base::BindRepeating(&metrics::MetricsService::OnApplicationNotIdle,
+                          base::Unretained(metrics_service_.get())));
+#endif
 
   bool all_profiles_succeeded = true;
   for (Profile* profile :
@@ -964,10 +959,6 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   switch (type) {
-    case chrome::NOTIFICATION_BROWSER_OPENED:
-      metrics_service_->OnApplicationNotIdle();
-      break;
-    case chrome::NOTIFICATION_BROWSER_CLOSED:
     case chrome::NOTIFICATION_TAB_PARENTED:
     case chrome::NOTIFICATION_TAB_CLOSING:
     case content::NOTIFICATION_LOAD_STOP:
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.h b/chrome/browser/metrics/chrome_metrics_service_client.h
index 46d0889..e19b078 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.h
+++ b/chrome/browser/metrics/chrome_metrics_service_client.h
@@ -31,6 +31,7 @@
 #include "ppapi/buildflags/buildflags.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 
+class BrowserActivityWatcher;
 class PluginMetricsProvider;
 class Profile;
 class PrefRegistrySimple;
@@ -176,21 +177,21 @@
   std::unique_ptr<IncognitoObserver> incognito_observer_;
 
   // Whether we registered all notification listeners successfully.
-  bool notification_listeners_active_;
+  bool notification_listeners_active_ = false;
 
   // Saved callback received from CollectFinalMetricsForLog().
   base::Closure collect_final_metrics_done_callback_;
 
   // Indicates that collect final metrics step is running.
-  bool waiting_for_collect_final_metrics_step_;
+  bool waiting_for_collect_final_metrics_step_ = false;
 
   // Number of async histogram fetch requests in progress.
-  int num_async_histogram_fetches_in_progress_;
+  int num_async_histogram_fetches_in_progress_ = 0;
 
 #if BUILDFLAG(ENABLE_PLUGINS)
   // The PluginMetricsProvider instance that was registered with
   // MetricsService. Has the same lifetime as |metrics_service_|.
-  PluginMetricsProvider* plugin_metrics_provider_;
+  PluginMetricsProvider* plugin_metrics_provider_ = nullptr;
 #endif
 
   // Callback to determine whether or not a cellular network is currently being
@@ -202,6 +203,10 @@
   std::unique_ptr<base::CallbackList<void(OmniboxLog*)>::Subscription>
       omnibox_url_opened_subscription_;
 
+#if !defined(OS_ANDROID)
+  std::unique_ptr<BrowserActivityWatcher> browser_activity_watcher_;
+#endif
+
   base::WeakPtrFactory<ChromeMetricsServiceClient> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ChromeMetricsServiceClient);
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index d291e24..5d6d5a8a 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -12,6 +12,7 @@
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/macros.h"
+#include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_tokenizer.h"
@@ -26,12 +27,138 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/logging_chrome.h"
 #include "components/metrics/call_stack_profile_metrics_provider.h"
+#include "components/omnibox/browser/omnibox_event_global_tracker.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 
+#if !defined(OS_ANDROID)
+#include "chrome/browser/metrics/browser_activity_watcher.h"
+#endif
+
 using content::BrowserThread;
 
+namespace {
+
+// This class ensures that the thread watching is actively taking place. Only
+// one instance of this class exists.
+class ThreadWatcherObserver : public content::NotificationObserver {
+ public:
+  // |wakeup_interval| specifies how often to wake up thread watchers due to
+  // new user activity.
+  static void Start(const base::TimeDelta& wakeup_interval);
+  static void Stop();
+
+ private:
+  explicit ThreadWatcherObserver(const base::TimeDelta& wakeup_interval);
+  ~ThreadWatcherObserver() override;
+
+  // content::NotificationObserver:
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
+  // Called when a URL is opened from the Omnibox.
+  void OnURLOpenedFromOmnibox(OmniboxLog* log);
+
+  // Called when user activity is detected.
+  void OnUserActivityDetected();
+
+#if !defined(OS_ANDROID)
+  std::unique_ptr<BrowserActivityWatcher> browser_activity_watcher_;
+#endif
+
+  content::NotificationRegistrar registrar_;
+
+  // This is the last time when woke all thread watchers up.
+  base::TimeTicks last_wakeup_time_;
+
+  // It is the time interval between wake up calls to thread watchers.
+  const base::TimeDelta wakeup_interval_;
+
+  // Subscription for receiving callbacks that a URL was opened from the
+  // omnibox.
+  std::unique_ptr<base::CallbackList<void(OmniboxLog*)>::Subscription>
+      omnibox_url_opened_subscription_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadWatcherObserver);
+};
+
+ThreadWatcherObserver* g_thread_watcher_observer_ = nullptr;
+
+ThreadWatcherObserver::ThreadWatcherObserver(
+    const base::TimeDelta& wakeup_interval)
+    : last_wakeup_time_(base::TimeTicks::Now()),
+      wakeup_interval_(wakeup_interval) {
+  DCHECK(!g_thread_watcher_observer_);
+  g_thread_watcher_observer_ = this;
+
+#if !defined(OS_ANDROID)
+  browser_activity_watcher_ = std::make_unique<BrowserActivityWatcher>(
+      base::BindRepeating(&ThreadWatcherObserver::OnUserActivityDetected,
+                          base::Unretained(this)));
+#endif
+
+  registrar_.Add(this, chrome::NOTIFICATION_TAB_PARENTED,
+                 content::NotificationService::AllSources());
+  registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING,
+                 content::NotificationService::AllSources());
+  registrar_.Add(this, content::NOTIFICATION_LOAD_START,
+                 content::NotificationService::AllSources());
+  registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
+                 content::NotificationService::AllSources());
+  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
+                 content::NotificationService::AllSources());
+  registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
+                 content::NotificationService::AllSources());
+  omnibox_url_opened_subscription_ =
+      OmniboxEventGlobalTracker::GetInstance()->RegisterCallback(
+          base::Bind(&ThreadWatcherObserver::OnURLOpenedFromOmnibox,
+                     base::Unretained(this)));
+}
+
+ThreadWatcherObserver::~ThreadWatcherObserver() {
+  DCHECK_EQ(this, g_thread_watcher_observer_);
+  g_thread_watcher_observer_ = nullptr;
+}
+
+// static
+void ThreadWatcherObserver::Start(const base::TimeDelta& wakeup_interval) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  new ThreadWatcherObserver(wakeup_interval);
+}
+
+// static
+void ThreadWatcherObserver::Stop() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  delete g_thread_watcher_observer_;
+}
+
+void ThreadWatcherObserver::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  OnUserActivityDetected();
+}
+
+void ThreadWatcherObserver::OnURLOpenedFromOmnibox(OmniboxLog* log) {
+  OnUserActivityDetected();
+}
+
+void ThreadWatcherObserver::OnUserActivityDetected() {
+  // There is some user activity, see if thread watchers are to be awakened.
+  base::TimeTicks now = base::TimeTicks::Now();
+  if ((now - last_wakeup_time_) < wakeup_interval_)
+    return;
+  last_wakeup_time_ = now;
+  WatchDogThread::PostTask(FROM_HERE,
+                           base::Bind(&ThreadWatcherList::WakeUpAll));
+}
+
+}  // namespace
+
 // ThreadWatcher methods and members.
 ThreadWatcher::ThreadWatcher(const WatchingParams& params)
     : thread_id_(params.thread_id),
@@ -354,7 +481,7 @@
                    &unresponsive_threshold,
                    &crash_on_hang_threads);
 
-  ThreadWatcherObserver::SetupNotifications(
+  ThreadWatcherObserver::Start(
       base::TimeDelta::FromSeconds(kSleepSeconds * unresponsive_threshold));
 
   WatchDogThread::PostTask(
@@ -376,7 +503,7 @@
 // static
 void ThreadWatcherList::StopWatchingAll() {
   // TODO(rtenneti): Enable ThreadWatcher.
-  ThreadWatcherObserver::RemoveNotifications();
+  ThreadWatcherObserver::Stop();
   DeleteAll();
 }
 
@@ -607,92 +734,6 @@
   g_stopped_ = stopped;
 }
 
-// ThreadWatcherObserver methods and members.
-//
-// static
-ThreadWatcherObserver*
-ThreadWatcherObserver::g_thread_watcher_observer_ = nullptr;
-
-ThreadWatcherObserver::ThreadWatcherObserver(
-    const base::TimeDelta& wakeup_interval)
-    : last_wakeup_time_(base::TimeTicks::Now()),
-      wakeup_interval_(wakeup_interval) {
-  CHECK(!g_thread_watcher_observer_);
-  g_thread_watcher_observer_ = this;
-}
-
-ThreadWatcherObserver::~ThreadWatcherObserver() {
-  DCHECK(this == g_thread_watcher_observer_);
-  g_thread_watcher_observer_ = nullptr;
-}
-
-// static
-void ThreadWatcherObserver::SetupNotifications(
-    const base::TimeDelta& wakeup_interval) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  ThreadWatcherObserver* observer = new ThreadWatcherObserver(wakeup_interval);
-  observer->registrar_.Add(
-      observer,
-      chrome::NOTIFICATION_BROWSER_OPENED,
-      content::NotificationService::AllBrowserContextsAndSources());
-  observer->registrar_.Add(observer,
-                           chrome::NOTIFICATION_BROWSER_CLOSED,
-                           content::NotificationService::AllSources());
-  observer->registrar_.Add(observer,
-                           chrome::NOTIFICATION_TAB_PARENTED,
-                           content::NotificationService::AllSources());
-  observer->registrar_.Add(observer,
-                           chrome::NOTIFICATION_TAB_CLOSING,
-                           content::NotificationService::AllSources());
-  observer->registrar_.Add(observer,
-                           content::NOTIFICATION_LOAD_START,
-                           content::NotificationService::AllSources());
-  observer->registrar_.Add(observer,
-                           content::NOTIFICATION_LOAD_STOP,
-                           content::NotificationService::AllSources());
-  observer->registrar_.Add(observer,
-                           content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                           content::NotificationService::AllSources());
-  observer->registrar_.Add(observer,
-                           content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
-                           content::NotificationService::AllSources());
-  observer->omnibox_url_opened_subscription_ =
-      OmniboxEventGlobalTracker::GetInstance()->RegisterCallback(
-          base::Bind(&ThreadWatcherObserver::OnURLOpenedFromOmnibox,
-                     base::Unretained(observer)));
-}
-
-// static
-void ThreadWatcherObserver::RemoveNotifications() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (!g_thread_watcher_observer_)
-    return;
-  g_thread_watcher_observer_->registrar_.RemoveAll();
-  delete g_thread_watcher_observer_;
-}
-
-void ThreadWatcherObserver::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  OnUserActivityDetected();
-}
-
-void ThreadWatcherObserver::OnURLOpenedFromOmnibox(OmniboxLog* log) {
-  OnUserActivityDetected();
-}
-
-void ThreadWatcherObserver::OnUserActivityDetected() {
-  // There is some user activity, see if thread watchers are to be awakened.
-  base::TimeTicks now = base::TimeTicks::Now();
-  if ((now - last_wakeup_time_) < wakeup_interval_)
-    return;
-  last_wakeup_time_ = now;
-  WatchDogThread::PostTask(
-      FROM_HERE,
-      base::Bind(&ThreadWatcherList::WakeUpAll));
-}
-
 // WatchDogThread methods and members.
 
 // This lock protects g_watchdog_thread.
diff --git a/chrome/browser/metrics/thread_watcher.h b/chrome/browser/metrics/thread_watcher.h
index de3f755..4e130b1 100644
--- a/chrome/browser/metrics/thread_watcher.h
+++ b/chrome/browser/metrics/thread_watcher.h
@@ -39,18 +39,17 @@
 #ifndef CHROME_BROWSER_METRICS_THREAD_WATCHER_H_
 #define CHROME_BROWSER_METRICS_THREAD_WATCHER_H_
 
+#include <stdint.h>
+
 #include <map>
 #include <string>
 #include <vector>
 
-#include <stdint.h>
-
 #include "base/command_line.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/metrics/histogram.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
@@ -59,15 +58,15 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/metrics/call_stack_profile_params.h"
-#include "components/omnibox/browser/omnibox_event_global_tracker.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 
 class CustomThreadWatcher;
 class StartupTimeBomb;
 class ThreadWatcherList;
-class ThreadWatcherObserver;
+
+namespace base {
+class HistogramBase;
+}
 
 // This class performs health check on threads that would like to be watched.
 class ThreadWatcher {
@@ -439,61 +438,6 @@
   DISALLOW_COPY_AND_ASSIGN(ThreadWatcherList);
 };
 
-// This class ensures that the thread watching is actively taking place. Only
-// one instance of this class exists.
-class ThreadWatcherObserver : public content::NotificationObserver {
- public:
-  // Registers |g_thread_watcher_observer_| as the Notifications observer.
-  // |wakeup_interval| specifies how often to wake up thread watchers. This
-  // method is accessible on UI thread.
-  static void SetupNotifications(const base::TimeDelta& wakeup_interval);
-
-  // Removes all ints from |registrar_| and deletes
-  // |g_thread_watcher_observer_|. This method is accessible on UI thread.
-  static void RemoveNotifications();
-
- private:
-  // Constructor of |g_thread_watcher_observer_| singleton.
-  explicit ThreadWatcherObserver(const base::TimeDelta& wakeup_interval);
-
-  // Destructor of |g_thread_watcher_observer_| singleton.
-  ~ThreadWatcherObserver() override;
-
-  // This ensures all thread watchers are active because there is some user
-  // activity. It will wake up all thread watchers every |wakeup_interval_|
-  // seconds. This is the implementation of content::NotificationObserver. When
-  // a matching notification is posted to the notification service, this method
-  // is called.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
-  // Called when a URL is opened from the Omnibox.
-  void OnURLOpenedFromOmnibox(OmniboxLog* log);
-
-  // Called when user activity is detected.
-  void OnUserActivityDetected();
-
-  // The singleton of this class.
-  static ThreadWatcherObserver* g_thread_watcher_observer_;
-
-  // The registrar that holds ints to be observed.
-  content::NotificationRegistrar registrar_;
-
-  // This is the last time when woke all thread watchers up.
-  base::TimeTicks last_wakeup_time_;
-
-  // It is the time interval between wake up calls to thread watchers.
-  const base::TimeDelta wakeup_interval_;
-
-  // Subscription for receiving callbacks that a URL was opened from the
-  // omnibox.
-  std::unique_ptr<base::CallbackList<void(OmniboxLog*)>::Subscription>
-      omnibox_url_opened_subscription_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadWatcherObserver);
-};
-
 // Class for WatchDogThread and in its Init method, we start watching UI, IO,
 // DB, FILE, CACHED threads.
 class WatchDogThread : public base::Thread {
diff --git a/chrome/browser/performance_manager/mechanisms/working_set_trimmer.cc b/chrome/browser/performance_manager/mechanisms/working_set_trimmer.cc
new file mode 100644
index 0000000..c8d2e5e8
--- /dev/null
+++ b/chrome/browser/performance_manager/mechanisms/working_set_trimmer.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 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/performance_manager/mechanisms/working_set_trimmer.h"
+
+#include "base/no_destructor.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer_win.h"
+#elif defined(OS_CHROMEOS)
+#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos.h"
+#endif
+
+namespace performance_manager {
+namespace mechanism {
+namespace {
+
+// The NoOpWorkingSetTrimmer provides an implementation of a working set trimmer
+// that does nothing on unsupported platforms.
+class NoOpWorkingSetTrimmer : public WorkingSetTrimmer {
+ public:
+  ~NoOpWorkingSetTrimmer() override = default;
+  NoOpWorkingSetTrimmer() = default;
+
+  // WorkingSetTrimmer implementation:
+  bool PlatformSupportsWorkingSetTrim() override { return false; }
+  bool TrimWorkingSet(const ProcessNode* node) override { return false; }
+};
+
+}  // namespace
+
+WorkingSetTrimmer* WorkingSetTrimmer::GetInstance() {
+#if defined(OS_WIN)
+  static base::NoDestructor<WorkingSetTrimmerWin> trimmer;
+#elif defined(OS_CHROMEOS)
+  static base::NoDestructor<WorkingSetTrimmerChromeOS> trimmer;
+#else
+  static base::NoDestructor<NoOpWorkingSetTrimmer> trimmer;
+#endif
+  return trimmer.get();
+}
+
+}  // namespace mechanism
+}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/mechanisms/working_set_trimmer.h b/chrome/browser/performance_manager/mechanisms/working_set_trimmer.h
new file mode 100644
index 0000000..eab5544
--- /dev/null
+++ b/chrome/browser/performance_manager/mechanisms/working_set_trimmer.h
@@ -0,0 +1,47 @@
+// Copyright 2019 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_PERFORMANCE_MANAGER_MECHANISMS_WORKING_SET_TRIMMER_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_MECHANISMS_WORKING_SET_TRIMMER_H_
+
+#include "base/macros.h"
+#include "base/no_destructor.h"
+
+namespace performance_manager {
+
+class ProcessNode;
+
+namespace mechanism {
+
+// A WorkingSetTrimmer will reduce a ProcessNode's memory footprint by giving a
+// hint to the operating system that this processes memory may be reclaimed or
+// trimmed.
+class WorkingSetTrimmer {
+ public:
+  virtual ~WorkingSetTrimmer() = default;
+
+  // GetInstance will return the singleton instance of a working set trimmer for
+  // this platform.
+  static WorkingSetTrimmer* GetInstance();
+
+  // Returns true if the WorkingSetTrimmer is supported on the current platform.
+  virtual bool PlatformSupportsWorkingSetTrim() = 0;
+
+  // Returns true if working set trim succeeded for the provided ProcessNode.
+  virtual bool TrimWorkingSet(const ProcessNode* process_node) = 0;
+
+ protected:
+  // A WorkingSetTrimmer should never be created directly it should only be
+  // retrieved via WorkingSetTrimmer::GetInstance().
+  WorkingSetTrimmer() = default;
+
+ private:
+  friend class base::NoDestructor<WorkingSetTrimmer>;
+  DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmer);
+};
+
+}  // namespace mechanism
+}  // namespace performance_manager
+
+#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_MECHANISMS_WORKING_SET_TRIMMER_H_
diff --git a/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos.cc b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos.cc
new file mode 100644
index 0000000..3d5db7f
--- /dev/null
+++ b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos.cc
@@ -0,0 +1,52 @@
+// Copyright 2019 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/performance_manager/mechanisms/working_set_trimmer_chromeos.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/performance_manager/public/graph/process_node.h"
+
+namespace performance_manager {
+namespace mechanism {
+namespace {
+
+// The chromeos kernel supports per-process reclaim if there exists a /reclaim
+// file in a procfs node. We will simply stat /proc/self/reclaim to detect this
+// support.
+bool KernelSupportsReclaim() {
+  return base::PathExists(base::FilePath("/proc/self/reclaim"));
+}
+
+}  // namespace
+
+WorkingSetTrimmerChromeOS::WorkingSetTrimmerChromeOS() = default;
+WorkingSetTrimmerChromeOS::~WorkingSetTrimmerChromeOS() = default;
+
+bool WorkingSetTrimmerChromeOS::PlatformSupportsWorkingSetTrim() {
+  static const bool kPlatformSupported = KernelSupportsReclaim();
+  return kPlatformSupported;
+}
+
+bool WorkingSetTrimmerChromeOS::TrimWorkingSet(
+    const ProcessNode* process_node) {
+  if (!process_node->GetProcess().IsValid())
+    return false;
+
+  const std::string reclaim_file =
+      base::StringPrintf("/proc/%d/reclaim", process_node->GetProcessId());
+  const std::string kReclaimMode = "all";
+  ssize_t written = base::WriteFile(base::FilePath(reclaim_file),
+                                    kReclaimMode.c_str(), kReclaimMode.size());
+
+  // We won't log an error if reclaim failed due to the process being dead.
+  PLOG_IF(ERROR, written < 0 && errno != ENOENT)
+      << "Write failed on " << reclaim_file << " mode: " << kReclaimMode;
+  return written > 0;
+}
+
+}  // namespace mechanism
+}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos.h b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos.h
new file mode 100644
index 0000000..f792ae6
--- /dev/null
+++ b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_chromeos.h
@@ -0,0 +1,39 @@
+// Copyright 2019 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_PERFORMANCE_MANAGER_MECHANISMS_WORKING_SET_TRIMMER_CHROMEOS_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_MECHANISMS_WORKING_SET_TRIMMER_CHROMEOS_H_
+
+#include "base/no_destructor.h"
+#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer.h"
+
+namespace performance_manager {
+namespace mechanism {
+
+// WorkingSetTrimmerChromeOS is the platform specific implementation of a
+// working set trimmer for ChromeOS. This class should not be used directly it
+// should be used via the WorkingSetTrimmer::GetInstance() method.
+class WorkingSetTrimmerChromeOS : public WorkingSetTrimmer {
+ public:
+  ~WorkingSetTrimmerChromeOS() override;
+
+  // WorkingSetTrimmer implementation:
+  bool PlatformSupportsWorkingSetTrim() override;
+  bool TrimWorkingSet(const ProcessNode* process_node) override;
+
+ private:
+  friend class base::NoDestructor<WorkingSetTrimmerChromeOS>;
+
+  // The constructor is made private to prevent instantiation of this class
+  // directly, it should always be retrieved via
+  // WorkingSetTrimmer::GetInstance().
+  WorkingSetTrimmerChromeOS();
+
+  DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmerChromeOS);
+};
+
+}  // namespace mechanism
+}  // namespace performance_manager
+
+#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_MECHANISMS_WORKING_SET_TRIMMER_CHROMEOS_H_
diff --git a/chrome/browser/performance_manager/mechanisms/working_set_trimmer_win.cc b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_win.cc
new file mode 100644
index 0000000..0b04769
--- /dev/null
+++ b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_win.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 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/performance_manager/mechanisms/working_set_trimmer_win.h"
+
+#include <windows.h>  // Must be in front of other Windows header files.
+
+#include <psapi.h>
+
+#include "base/logging.h"
+#include "base/process/process.h"
+#include "chrome/browser/performance_manager/public/graph/process_node.h"
+
+namespace performance_manager {
+namespace mechanism {
+
+WorkingSetTrimmerWin::WorkingSetTrimmerWin() = default;
+WorkingSetTrimmerWin::~WorkingSetTrimmerWin() = default;
+
+bool WorkingSetTrimmerWin::TrimWorkingSet(const ProcessNode* process_node) {
+  // Open a new handle to the process with the specific access needed.
+  const base::Process& process = process_node->GetProcess();
+  if (!process.IsValid())
+    return false;
+
+  base::Process process_copy = base::Process::OpenWithAccess(
+      process.Pid(), PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_QUOTA);
+  if (!process_copy.IsValid()) {
+    DPLOG(ERROR) << "Working set not emptied because process handle could not "
+                    "be obtained.";
+    return false;
+  }
+
+  BOOL empty_working_set_success = ::EmptyWorkingSet(process.Handle());
+  DPLOG_IF(ERROR, !empty_working_set_success)
+      << "Working set not emptied because EmptyWorkingSet() failed";
+  return empty_working_set_success;
+}
+
+bool WorkingSetTrimmerWin::PlatformSupportsWorkingSetTrim() {
+  return true;
+}
+
+}  // namespace mechanism
+}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/mechanisms/working_set_trimmer_win.h b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_win.h
new file mode 100644
index 0000000..a495b34
--- /dev/null
+++ b/chrome/browser/performance_manager/mechanisms/working_set_trimmer_win.h
@@ -0,0 +1,37 @@
+// Copyright 2019 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_PERFORMANCE_MANAGER_MECHANISMS_WORKING_SET_TRIMMER_WIN_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_MECHANISMS_WORKING_SET_TRIMMER_WIN_H_
+
+#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer.h"
+
+namespace performance_manager {
+namespace mechanism {
+
+// WorkingSetTrimmerWin is the platform specific implementation of a
+// working set trimmer for Windows. This class should not be used directly it
+// should be used via the WorkingSetTrimmer::GetIntsance() method.
+class WorkingSetTrimmerWin : public WorkingSetTrimmer {
+ public:
+  ~WorkingSetTrimmerWin() override;
+
+  bool PlatformSupportsWorkingSetTrim() override;
+  bool TrimWorkingSet(const ProcessNode* process_node) override;
+
+ private:
+  friend class base::NoDestructor<WorkingSetTrimmerWin>;
+
+  // The constructor is made private to prevent instantiation of this class
+  // directly, it should always be retrieved via
+  // WorkingSetTrimmer::GetIntsance().
+  WorkingSetTrimmerWin();
+
+  DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmerWin);
+};
+
+}  // namespace mechanism
+}  // namespace performance_manager
+
+#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_MECHANISMS_WORKING_SET_TRIMMER_WIN_H_
diff --git a/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.cc b/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.cc
new file mode 100644
index 0000000..253eb0ef
--- /dev/null
+++ b/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.cc
@@ -0,0 +1,44 @@
+// 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/performance_manager/observers/working_set_trimmer_observer_win.h"
+
+#include "base/logging.h"
+#include "base/process/process.h"
+#include "base/time/time.h"
+#include "chrome/browser/performance_manager/graph/node_base.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
+#include "chrome/browser/performance_manager/mechanisms/working_set_trimmer.h"
+
+namespace performance_manager {
+
+WorkingSetTrimmer::WorkingSetTrimmer() = default;
+WorkingSetTrimmer::~WorkingSetTrimmer() = default;
+
+void WorkingSetTrimmer::OnPassedToGraph(Graph* graph) {
+  RegisterObservers(graph);
+}
+
+void WorkingSetTrimmer::OnTakenFromGraph(Graph* graph) {
+  UnregisterObservers(graph);
+}
+
+void WorkingSetTrimmer::OnAllFramesInProcessFrozen(
+    const ProcessNode* process_node) {
+  auto* trimmer = mechanism::WorkingSetTrimmer::GetInstance();
+
+  if (process_node->GetProcess().IsValid() &&
+      trimmer->PlatformSupportsWorkingSetTrim())
+    trimmer->TrimWorkingSet(process_node);
+}
+
+void WorkingSetTrimmer::RegisterObservers(Graph* graph) {
+  graph->AddProcessNodeObserver(this);
+}
+
+void WorkingSetTrimmer::UnregisterObservers(Graph* graph) {
+  graph->RemoveProcessNodeObserver(this);
+}
+
+}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/observers/working_set_trimmer_win.h b/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h
similarity index 96%
rename from chrome/browser/performance_manager/observers/working_set_trimmer_win.h
rename to chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h
index a6332ff..f333c68 100644
--- a/chrome/browser/performance_manager/observers/working_set_trimmer_win.h
+++ b/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_WORKING_SET_TRIMMER_WIN_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_WORKING_SET_TRIMMER_WIN_H_
+#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_WORKING_SET_TRIMMER_OBSERVER_WIN_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_WORKING_SET_TRIMMER_OBSERVER_WIN_H_
 
 #include "base/macros.h"
 #include "chrome/browser/performance_manager/public/graph/graph.h"
@@ -53,4 +53,4 @@
 
 }  // namespace performance_manager
 
-#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_WORKING_SET_TRIMMER_WIN_H_
+#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_OBSERVERS_WORKING_SET_TRIMMER_OBSERVER_WIN_H_
diff --git a/chrome/browser/performance_manager/observers/working_set_trimmer_win_unittest.cc b/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win_unittest.cc
similarity index 99%
rename from chrome/browser/performance_manager/observers/working_set_trimmer_win_unittest.cc
rename to chrome/browser/performance_manager/observers/working_set_trimmer_observer_win_unittest.cc
index 8b85acc..3d6113b 100644
--- a/chrome/browser/performance_manager/observers/working_set_trimmer_win_unittest.cc
+++ b/chrome/browser/performance_manager/observers/working_set_trimmer_observer_win_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/performance_manager/observers/working_set_trimmer_win.h"
+#include "chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h"
 
 #include <windows.h>  // Must be in front of other Windows header files.
 
diff --git a/chrome/browser/performance_manager/observers/working_set_trimmer_win.cc b/chrome/browser/performance_manager/observers/working_set_trimmer_win.cc
deleted file mode 100644
index 112443f..0000000
--- a/chrome/browser/performance_manager/observers/working_set_trimmer_win.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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/performance_manager/observers/working_set_trimmer_win.h"
-
-#include <windows.h>  // Must be in front of other Windows header files.
-
-#include <psapi.h>
-
-#include "base/logging.h"
-#include "base/process/process.h"
-#include "base/time/time.h"
-#include "chrome/browser/performance_manager/graph/node_base.h"
-#include "chrome/browser/performance_manager/graph/process_node_impl.h"
-
-namespace performance_manager {
-
-namespace {
-
-// Empties the working set of a process with id |process_id| and creation time
-// |process_creation_time|. The creation time is verified to ensure that we
-// don't empty the working set of the wrong process if the target process exits
-// and its id is reused.
-void EmptyWorkingSet(const base::Process& process,
-                     base::Time process_creation_time) {
-  // Open a new handle to the process with the specific access needed.
-  base::Process process_copy = base::Process::OpenWithAccess(
-      process.Pid(), PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_QUOTA);
-  if (!process_copy.IsValid()) {
-    DPLOG(ERROR) << "Working set not emptied because process handle could not "
-                    "be obtained.";
-    return;
-  }
-
-#if DCHECK_IS_ON()
-  BOOL empty_working_set_success =
-#endif
-      ::EmptyWorkingSet(process.Handle());
-  DPLOG_IF(ERROR, !empty_working_set_success)
-      << "Working set not emptied because EmptyWorkingSet() failed";
-}
-
-}  // namespace
-
-WorkingSetTrimmer::WorkingSetTrimmer() = default;
-WorkingSetTrimmer::~WorkingSetTrimmer() = default;
-
-void WorkingSetTrimmer::OnPassedToGraph(Graph* graph) {
-  RegisterObservers(graph);
-}
-
-void WorkingSetTrimmer::OnTakenFromGraph(Graph* graph) {
-  UnregisterObservers(graph);
-}
-
-void WorkingSetTrimmer::OnAllFramesInProcessFrozen(
-    const ProcessNode* process_node) {
-  if (process_node->GetProcess().IsValid())
-    EmptyWorkingSet(process_node->GetProcess(), process_node->GetLaunchTime());
-}
-
-void WorkingSetTrimmer::RegisterObservers(Graph* graph) {
-  graph->AddProcessNodeObserver(this);
-}
-
-void WorkingSetTrimmer::UnregisterObservers(Graph* graph) {
-  graph->RemoveProcessNodeObserver(this);
-}
-
-}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/performance_manager.cc b/chrome/browser/performance_manager/performance_manager.cc
index dde96f45..b181b5f 100644
--- a/chrome/browser/performance_manager/performance_manager.cc
+++ b/chrome/browser/performance_manager/performance_manager.cc
@@ -23,7 +23,7 @@
 #include "chrome/browser/performance_manager/graph/system_node_impl.h"
 #include "chrome/browser/performance_manager/observers/isolation_context_metrics.h"
 #include "chrome/browser/performance_manager/observers/metrics_collector.h"
-#include "chrome/browser/performance_manager/observers/working_set_trimmer_win.h"
+#include "chrome/browser/performance_manager/observers/working_set_trimmer_observer_win.h"
 #include "content/public/browser/system_connector.h"
 #include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
 
diff --git a/chrome/browser/policy/e2e_test/.vpython b/chrome/browser/policy/e2e_test/.vpython
index 7d94b3b..36533163 100644
--- a/chrome/browser/policy/e2e_test/.vpython
+++ b/chrome/browser/policy/e2e_test/.vpython
@@ -11,7 +11,7 @@
 
 wheel: <
   name: "infra/celab/celab/windows-amd64"
-  version: "t5ee9dgnv7arG5o74SeesxNLMN-f5Z-RLd0IX9YQvrcC"
+  version: "IhQLTIwNFOxhnKFZWQyr4I6GS8ehFvEFtaQaZmN7ubsC"
 >
 
 # googleapiclient
diff --git a/chrome/browser/policy/e2e_test/tests/bookmarkbar_enabled/bookmarkbar_webdriver.py b/chrome/browser/policy/e2e_test/tests/bookmarkbar_enabled/bookmarkbar_webdriver.py
index ba6e9e6..500f0aa 100644
--- a/chrome/browser/policy/e2e_test/tests/bookmarkbar_enabled/bookmarkbar_webdriver.py
+++ b/chrome/browser/policy/e2e_test/tests/bookmarkbar_enabled/bookmarkbar_webdriver.py
@@ -19,11 +19,12 @@
 
 try:
   app = Application(backend="uia")
-  app.connect(title_re='.*Chrome')
+  app.connect(title_re='.*Chrome|.*Chromium')
   app.top_window().child_window(title="Bookmarks", control_type="ToolBar") \
       .print_control_identifiers()
   print "Bookmarkbar is found"
-except ElementNotFoundError:
+except ElementNotFoundError as error:
+  print error
   print "Bookmarkbar is missing"
 finally:
   driver.quit()
diff --git a/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py b/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py
index 36c36def..33f513c 100644
--- a/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py
+++ b/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py
@@ -36,7 +36,7 @@
     user_data_dir = r'c:\temp\user1'
     self.RunCommand(
         'client2012',
-        'if exist %s rmdir /s /q %s' % (user_data_dir, user_data_dir))
+        'cmd /C if exist %s rmdir /s /q %s' % (user_data_dir, user_data_dir))
     dir = os.path.dirname(os.path.abspath(__file__))
     user_data_dir_arg = '--user_data_dir=%s' % user_data_dir
     urls = ['https://www.cnn.com/', 'https://www.youtube.com/']
diff --git a/chrome/browser/previews/previews_prober.cc b/chrome/browser/previews/previews_prober.cc
index 62b7386..b12762a 100644
--- a/chrome/browser/previews/previews_prober.cc
+++ b/chrome/browser/previews/previews_prober.cc
@@ -514,6 +514,11 @@
   return entry.value().is_success();
 }
 
+void PreviewsProber::SetOnCompleteCallback(
+    PreviewsProberOnCompleteCallback callback) {
+  on_complete_callback_ = std::move(callback);
+}
+
 void PreviewsProber::RecordProbeResult(bool success) {
   PreviewsProberCacheEntry entry;
   entry.set_is_success(success);
@@ -533,6 +538,9 @@
     RemoveOldestDictionaryEntry(update.Get());
 
   cached_probe_results_ = update.Get()->CreateDeepCopy();
+
+  if (on_complete_callback_)
+    on_complete_callback_.Run(success);
 }
 
 std::string PreviewsProber::GetCacheKeyForCurrentNetwork() const {
diff --git a/chrome/browser/previews/previews_prober.h b/chrome/browser/previews/previews_prober.h
index 46dd1ca..099f5bf 100644
--- a/chrome/browser/previews/previews_prober.h
+++ b/chrome/browser/previews/previews_prober.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <string>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
@@ -39,6 +40,8 @@
 class SharedURLLoaderFactory;
 }  // namespace network
 
+typedef base::RepeatingCallback<void(bool)> PreviewsProberOnCompleteCallback;
+
 // This class is a utility to probe a given URL with a given set of behaviors.
 // This can be used for determining whether a specific network resource is
 // available or accessible by Chrome.
@@ -161,6 +164,10 @@
   // network::NetworkConnectionTracker::NetworkConnectionObserver:
   void OnConnectionChanged(network::mojom::ConnectionType type) override;
 
+  // Sets a repeating callback to notify the completion of a probe and whether
+  // it was successful.
+  void SetOnCompleteCallback(PreviewsProberOnCompleteCallback callback);
+
  protected:
   // Exposes |tick_clock| and |clock| for testing.
   PreviewsProber(
@@ -273,6 +280,10 @@
       application_status_listener_;
 #endif
 
+  // An optional callback to notify of a completed probe. This callback passes a
+  // bool to indicate success of the completed probe.
+  PreviewsProberOnCompleteCallback on_complete_callback_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<PreviewsProber> weak_factory_{this};
diff --git a/chrome/browser/previews/previews_prober_unittest.cc b/chrome/browser/previews/previews_prober_unittest.cc
index cdb2ea6..22a095c4c 100644
--- a/chrome/browser/previews/previews_prober_unittest.cc
+++ b/chrome/browser/previews/previews_prober_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/previews/previews_prober.h"
 
+#include "base/bind.h"
 #include "build/build_config.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
@@ -116,12 +117,16 @@
       const PreviewsProber::TimeoutPolicy& timeout_policy) {
     net::HttpRequestHeaders headers;
     headers.SetHeader("X-Testing", "Hello world");
-    return std::make_unique<TestPreviewsProber>(
-        delegate, test_shared_loader_factory_, &test_prefs_,
-        PreviewsProber::ClientName::kLitepages, kTestUrl,
-        PreviewsProber::HttpMethod::kGet, headers, retry_policy, timeout_policy,
-        1, kCacheRevalidateAfter, thread_bundle_.GetMockTickClock(),
-        thread_bundle_.GetMockClock());
+    std::unique_ptr<TestPreviewsProber> prober =
+        std::make_unique<TestPreviewsProber>(
+            delegate, test_shared_loader_factory_, &test_prefs_,
+            PreviewsProber::ClientName::kLitepages, kTestUrl,
+            PreviewsProber::HttpMethod::kGet, headers, retry_policy,
+            timeout_policy, 1, kCacheRevalidateAfter,
+            thread_bundle_.GetMockTickClock(), thread_bundle_.GetMockClock());
+    prober->SetOnCompleteCallback(base::BindRepeating(
+        &PreviewsProberTest::OnProbeComplete, base::Unretained(this)));
+    return prober;
   }
 
   void RunUntilIdle() { thread_bundle_.RunUntilIdle(); }
@@ -180,12 +185,17 @@
     }
   }
 
+  void OnProbeComplete(bool success) { callback_result_ = success; }
+
+  base::Optional<bool> callback_result() { return callback_result_; }
+
  private:
   content::TestBrowserThreadBundle thread_bundle_;
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
   TestDelegate test_delegate_;
   TestingPrefServiceSimple test_prefs_;
+  base::Optional<bool> callback_result_;
 };
 
 TEST_F(PreviewsProberTest, OK) {
@@ -200,6 +210,21 @@
   EXPECT_FALSE(prober->is_active());
 }
 
+TEST_F(PreviewsProberTest, OK_Callback) {
+  std::unique_ptr<PreviewsProber> prober = NewProber();
+  EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
+
+  prober->SendNowIfInactive(false);
+  VerifyRequest();
+
+  MakeResponseAndWait(net::HTTP_OK, net::OK);
+  EXPECT_TRUE(prober->LastProbeWasSuccessful().value());
+  EXPECT_FALSE(prober->is_active());
+
+  EXPECT_TRUE(callback_result().has_value());
+  EXPECT_TRUE(callback_result().value());
+}
+
 TEST_F(PreviewsProberTest, MultipleStart) {
   std::unique_ptr<PreviewsProber> prober = NewProber();
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
@@ -374,6 +399,21 @@
   EXPECT_FALSE(prober->is_active());
 }
 
+TEST_F(PreviewsProberTest, NetError_Callback) {
+  std::unique_ptr<PreviewsProber> prober = NewProber();
+  EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
+
+  prober->SendNowIfInactive(false);
+  VerifyRequest();
+
+  MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED);
+  EXPECT_FALSE(prober->LastProbeWasSuccessful().value());
+  EXPECT_FALSE(prober->is_active());
+
+  EXPECT_TRUE(callback_result().has_value());
+  EXPECT_FALSE(callback_result().value());
+}
+
 TEST_F(PreviewsProberTest, HttpError) {
   std::unique_ptr<PreviewsProber> prober = NewProber();
   EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc
index d3ee033..bb91d47 100644
--- a/chrome/browser/push_messaging/push_messaging_browsertest.cc
+++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -122,6 +122,7 @@
 
 void DidRegister(base::Closure done_callback,
                  const std::string& registration_id,
+                 const GURL& endpoint,
                  const std::vector<uint8_t>& p256dh,
                  const std::vector<uint8_t>& auth,
                  blink::mojom::PushRegistrationStatus status) {
@@ -488,8 +489,7 @@
                                                std::string* out_token) {
   size_t last_slash = endpoint.rfind('/');
 
-  ASSERT_EQ(push_service()->GetEndpoint(standard_protocol).spec(),
-            endpoint.substr(0, last_slash + 1));
+  ASSERT_EQ(kPushMessagingGcmEndpoint, endpoint.substr(0, last_slash + 1));
 
   ASSERT_LT(last_slash + 1, endpoint.length());  // Token must not be empty.
 
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc
index b2824174..2079297 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -498,12 +498,6 @@
       /* was_encrypted= */ true, error_message, "" /* payload */);
 }
 
-// GetEndpoint method ----------------------------------------------------------
-
-GURL PushMessagingServiceImpl::GetEndpoint(bool standard_protocol) {
-  return GURL(kPushMessagingGcmEndpoint);
-}
-
 // Subscribe and GetPermissionStatus methods -----------------------------------
 
 void PushMessagingServiceImpl::SubscribeFromDocument(
@@ -647,16 +641,18 @@
 void PushMessagingServiceImpl::SubscribeEnd(
     RegisterCallback callback,
     const std::string& subscription_id,
+    const GURL& endpoint,
     const std::vector<uint8_t>& p256dh,
     const std::vector<uint8_t>& auth,
     blink::mojom::PushRegistrationStatus status) {
-  std::move(callback).Run(subscription_id, p256dh, auth, status);
+  std::move(callback).Run(subscription_id, endpoint, p256dh, auth, status);
 }
 
 void PushMessagingServiceImpl::SubscribeEndWithError(
     RegisterCallback callback,
     blink::mojom::PushRegistrationStatus status) {
   SubscribeEnd(std::move(callback), std::string() /* subscription_id */,
+               GURL::EmptyGURL() /* endpoint */,
                std::vector<uint8_t>() /* p256dh */,
                std::vector<uint8_t>() /* auth */, status);
 }
@@ -673,7 +669,9 @@
       blink::mojom::PushRegistrationStatus::SERVICE_ERROR;
 
   switch (result) {
-    case InstanceID::SUCCESS:
+    case InstanceID::SUCCESS: {
+      const GURL endpoint = CreateEndpoint(subscription_id);
+
       // Make sure that this subscription has associated encryption keys prior
       // to returning it to the developer - they'll need this information in
       // order to send payloads to the user.
@@ -682,8 +680,9 @@
           base::BindOnce(
               &PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo,
               weak_factory_.GetWeakPtr(), app_identifier, std::move(callback),
-              subscription_id));
+              subscription_id, endpoint));
       return;
+    }
     case InstanceID::INVALID_PARAMETER:
     case InstanceID::DISABLED:
     case InstanceID::ASYNC_OPERATION_PENDING:
@@ -705,6 +704,7 @@
     const PushMessagingAppIdentifier& app_identifier,
     RegisterCallback callback,
     const std::string& subscription_id,
+    const GURL& endpoint,
     std::string p256dh,
     std::string auth_secret) {
   if (p256dh.empty()) {
@@ -718,7 +718,7 @@
 
   IncreasePushSubscriptionCount(1, false /* is_pending */);
 
-  SubscribeEnd(std::move(callback), subscription_id,
+  SubscribeEnd(std::move(callback), subscription_id, endpoint,
                std::vector<uint8_t>(p256dh.begin(), p256dh.end()),
                std::vector<uint8_t>(auth_secret.begin(), auth_secret.end()),
                blink::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE);
@@ -737,15 +737,17 @@
           profile_, origin, service_worker_registration_id);
 
   if (app_identifier.is_null()) {
-    callback.Run(false /* is_valid */, std::vector<uint8_t>() /* p256dh */,
+    callback.Run(false /* is_valid */, GURL::EmptyGURL() /*endpoint*/,
+                 std::vector<uint8_t>() /* p256dh */,
                  std::vector<uint8_t>() /* auth */);
     return;
   }
 
+  const GURL endpoint = CreateEndpoint(subscription_id);
   const std::string& app_id = app_identifier.app_id();
-  base::Callback<void(bool)> validate_cb =
-      base::Bind(&PushMessagingServiceImpl::DidValidateSubscription,
-                 weak_factory_.GetWeakPtr(), app_id, sender_id, callback);
+  base::Callback<void(bool)> validate_cb = base::Bind(
+      &PushMessagingServiceImpl::DidValidateSubscription,
+      weak_factory_.GetWeakPtr(), app_id, sender_id, endpoint, callback);
 
   if (PushMessagingAppIdentifier::UseInstanceID(app_id)) {
     GetInstanceIDDriver()->GetInstanceID(app_id)->ValidateToken(
@@ -760,10 +762,12 @@
 void PushMessagingServiceImpl::DidValidateSubscription(
     const std::string& app_id,
     const std::string& sender_id,
+    const GURL& endpoint,
     const SubscriptionInfoCallback& callback,
     bool is_valid) {
   if (!is_valid) {
-    callback.Run(false /* is_valid */, std::vector<uint8_t>() /* p256dh */,
+    callback.Run(false /* is_valid */, GURL::EmptyGURL() /* endpoint */,
+                 std::vector<uint8_t>() /* p256dh */,
                  std::vector<uint8_t>() /* auth */);
     return;
   }
@@ -771,16 +775,18 @@
   GetEncryptionInfoForAppId(
       app_id, sender_id,
       base::BindOnce(&PushMessagingServiceImpl::DidGetEncryptionInfo,
-                     weak_factory_.GetWeakPtr(), callback));
+                     weak_factory_.GetWeakPtr(), endpoint, callback));
 }
 
 void PushMessagingServiceImpl::DidGetEncryptionInfo(
+    const GURL& endpoint,
     const SubscriptionInfoCallback& callback,
     std::string p256dh,
     std::string auth_secret) const {
   // I/O errors might prevent the GCM Driver from retrieving a key-pair.
   bool is_valid = !p256dh.empty();
-  callback.Run(is_valid, std::vector<uint8_t>(p256dh.begin(), p256dh.end()),
+  callback.Run(is_valid, endpoint,
+               std::vector<uint8_t>(p256dh.begin(), p256dh.end()),
                std::vector<uint8_t>(auth_secret.begin(), auth_secret.end()));
 }
 
@@ -1131,6 +1137,13 @@
   }
 }
 
+GURL PushMessagingServiceImpl::CreateEndpoint(
+    const std::string& subscription_id) const {
+  const GURL endpoint(kPushMessagingGcmEndpoint + subscription_id);
+  DCHECK(endpoint.is_valid());
+  return endpoint;
+}
+
 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const {
   gcm::GCMProfileService* gcm_profile_service =
       gcm::GCMProfileServiceFactory::GetForProfile(profile_);
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.h b/chrome/browser/push_messaging/push_messaging_service_impl.h
index de7fda9..0fd5fa7 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.h
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.h
@@ -90,7 +90,6 @@
   bool CanHandle(const std::string& app_id) const override;
 
   // content::PushMessagingService implementation:
-  GURL GetEndpoint(bool standard_protocol) override;
   void SubscribeFromDocument(const GURL& requesting_origin,
                              int64_t service_worker_registration_id,
                              int renderer_id,
@@ -173,6 +172,7 @@
 
   void SubscribeEnd(RegisterCallback callback,
                     const std::string& subscription_id,
+                    const GURL& endpoint,
                     const std::vector<uint8_t>& p256dh,
                     const std::vector<uint8_t>& auth,
                     blink::mojom::PushRegistrationStatus status);
@@ -190,6 +190,7 @@
       const PushMessagingAppIdentifier& app_identifier,
       RegisterCallback callback,
       const std::string& subscription_id,
+      const GURL& endpoint,
       std::string p256dh,
       std::string auth_secret);
 
@@ -197,10 +198,12 @@
 
   void DidValidateSubscription(const std::string& app_id,
                                const std::string& sender_id,
+                               const GURL& endpoint,
                                const SubscriptionInfoCallback& callback,
                                bool is_valid);
 
-  void DidGetEncryptionInfo(const SubscriptionInfoCallback& callback,
+  void DidGetEncryptionInfo(const GURL& endpoint,
+                            const SubscriptionInfoCallback& callback,
                             std::string p256dh,
                             std::string auth_secret) const;
 
@@ -254,6 +257,10 @@
       const std::string& sender_id,
       gcm::GCMEncryptionProvider::EncryptionInfoCallback callback);
 
+  // Returns the URL used to send push messages to the subscription identified
+  // by |subscription_id|.
+  GURL CreateEndpoint(const std::string& subscription_id) const;
+
   gcm::GCMDriver* GetGCMDriver() const;
 
   instance_id::InstanceIDDriver* GetInstanceIDDriver() const;
diff --git a/chrome/browser/push_messaging/push_messaging_service_unittest.cc b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
index d018607..15091682 100644
--- a/chrome/browser/push_messaging/push_messaging_service_unittest.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
@@ -104,10 +104,12 @@
 
   // Callback to use when the subscription may have been subscribed.
   void DidRegister(std::string* subscription_id_out,
+                   GURL* endpoint_out,
                    std::vector<uint8_t>* p256dh_out,
                    std::vector<uint8_t>* auth_out,
                    base::Closure done_callback,
                    const std::string& registration_id,
+                   const GURL& endpoint,
                    const std::vector<uint8_t>& p256dh,
                    const std::vector<uint8_t>& auth,
                    blink::mojom::PushRegistrationStatus status) {
@@ -115,6 +117,7 @@
               status);
 
     *subscription_id_out = registration_id;
+    *endpoint_out = endpoint;
     *p256dh_out = p256dh;
     *auth_out = auth;
 
@@ -161,6 +164,7 @@
             push_service->GetPermissionStatus(origin, true));
 
   std::string subscription_id;
+  GURL endpoint;
   std::vector<uint8_t> p256dh, auth;
 
   base::RunLoop run_loop;
@@ -175,13 +179,16 @@
   push_service->SubscribeFromWorker(
       origin, kTestServiceWorkerId, std::move(options),
       base::Bind(&PushMessagingServiceTest::DidRegister, base::Unretained(this),
-                 &subscription_id, &p256dh, &auth, run_loop.QuitClosure()));
+                 &subscription_id, &endpoint, &p256dh, &auth,
+                 run_loop.QuitClosure()));
 
   EXPECT_EQ(0u, subscription_id.size());  // this must be asynchronous
 
   run_loop.Run();
 
   ASSERT_GT(subscription_id.size(), 0u);
+  ASSERT_TRUE(endpoint.is_valid());
+  ASSERT_GT(endpoint.spec().size(), 0u);
   ASSERT_GT(p256dh.size(), 0u);
   ASSERT_GT(auth.size(), 0u);
 
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
index 86327b1b..f8645597 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
@@ -116,10 +116,14 @@
   // instantiated. No TabLifecycleUnit is created for these tabs.
 
   DCHECK(intervention_policy_database_);
-  browser_tab_strip_tracker_.Init();
 
-  auto* perf_man = performance_manager::PerformanceManager::GetInstance();
-  if (perf_man) {
+  browser_tab_strip_tracker_.Init();
+}
+
+TabLifecycleUnitSource::~TabLifecycleUnitSource() = default;
+
+void TabLifecycleUnitSource::Start() {
+  if (auto* perf_man = performance_manager::PerformanceManager::GetInstance()) {
     // The performance manager dies on its own sequence, so posting unretained
     // is fine.
     perf_man->CallOnGraph(
@@ -133,8 +137,6 @@
   }
 }
 
-TabLifecycleUnitSource::~TabLifecycleUnitSource() = default;
-
 // static
 TabLifecycleUnitExternal* TabLifecycleUnitSource::GetTabLifecycleUnitExternal(
     content::WebContents* web_contents) {
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
index 4d368c9..be57555 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
@@ -46,6 +46,10 @@
       UsageClock* usage_clock);
   ~TabLifecycleUnitSource() override;
 
+  // Should be called once all the dependencies of this class have been created
+  // (e.g. the global PerformanceManager instance).
+  void Start();
+
   // Returns the TabLifecycleUnitExternal instance associated with
   // |web_contents|, or nullptr if |web_contents| isn't a tab.
   static TabLifecycleUnitExternal* GetTabLifecycleUnitExternal(
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 8f5e271..b830dcb 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/performance_manager/performance_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/resource_coordinator/background_tab_navigation_throttle.h"
+#include "chrome/browser/resource_coordinator/resource_coordinator_parts.h"
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
 #include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
@@ -222,6 +223,10 @@
                        std::make_unique<ResourceCoordinatorSignalObserver>(
                            weak_ptr_factory_.GetWeakPtr())));
   }
+
+  g_browser_process->resource_coordinator_parts()
+      ->tab_lifecycle_unit_source()
+      ->Start();
 }
 
 LifecycleUnitVector TabManager::GetSortedLifecycleUnits() {
diff --git a/chrome/browser/resources/chromeos/password_change/confirm_password_change.html b/chrome/browser/resources/chromeos/password_change/confirm_password_change.html
index 8a7e0071..0048694 100644
--- a/chrome/browser/resources/chromeos/password_change/confirm_password_change.html
+++ b/chrome/browser/resources/chromeos/password_change/confirm_password_change.html
@@ -29,10 +29,6 @@
           width: 100%;
         }
 
-        .label {
-          @apply --cr-form-field-label;
-        }
-
         #prompt {
           margin-bottom: 20px;
         }
@@ -95,4 +91,4 @@
 <body>
   <confirm-password-change id="main-element"></confirm-password-change>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index 7a096da8..0545c31e 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -111,12 +111,6 @@
 const RESIZE_TIMEOUT_DELAY = 66;
 
 /**
- * Timeout delay in ms before starting the reorder flow.
- * @const {number}
- */
-const REORDER_TIMEOUT_DELAY = 1000;
-
-/**
  * Maximum number of tiles if custom links is enabled.
  * @const {number}
  */
@@ -1109,40 +1103,14 @@
  * @param {!Element} tile Tile on which to set the event listeners.
  */
 function setupReorder(tile) {
-  // Starts the reorder flow after the user has held the mouse button down for
-  // |REORDER_TIMEOUT_DELAY|.
+  // Starts the reorder flow.
   tile.addEventListener('mousedown', (event) => {
     // Do not reorder if the edit menu was clicked or if ctrl/shift/alt/meta is
     // also held down.
     if (event.button == 0 /* LEFT CLICK */ && !event.ctrlKey &&
         !event.shiftKey && !event.altKey && !event.metaKey &&
-        !event.target.classList.contains(CLASSES.MD_MENU)) {
-      let timeout = -1;
-
-      // Cancel the timeout if the user drags the mouse off the tile and
-      // releases or if the mouse if released.
-      const dragend = () => {
-        window.clearTimeout(timeout);
-      };
-      document.addEventListener('dragend', dragend, {once: true});
-
-      const mouseup = () => {
-        if (event.button == 0 /* LEFT CLICK */) {
-          window.clearTimeout(timeout);
-        }
-      };
-      document.addEventListener('mouseup', mouseup, {once: true});
-
-      const timeoutFunc = (dragend_in, mouseup_in) => {
-        if (!reordering) {
-          startReorder(tile);
-        }
-        document.removeEventListener('dragend', dragend_in);
-        document.removeEventListener('mouseup', mouseup_in);
-      };
-      // Wait for |REORDER_TIMEOUT_DELAY| before starting the reorder flow.
-      timeout = window.setTimeout(
-          timeoutFunc.bind(dragend, mouseup), REORDER_TIMEOUT_DELAY);
+        !event.target.classList.contains(CLASSES.MD_MENU) && !reordering) {
+      startReorder(tile);
     }
   });
 
diff --git a/chrome/browser/resources/settings/autofill_page/address_edit_dialog.html b/chrome/browser/resources/settings/autofill_page/address_edit_dialog.html
index ea5962b..b2eb9d4 100644
--- a/chrome/browser/resources/settings/autofill_page/address_edit_dialog.html
+++ b/chrome/browser/resources/settings/autofill_page/address_edit_dialog.html
@@ -3,6 +3,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
@@ -13,7 +14,7 @@
 
 <dom-module id="settings-address-edit-dialog">
   <template>
-    <style include="settings-shared md-select">
+    <style include="cr-shared-style settings-shared md-select">
       :host {
         white-space: nowrap;
       }
@@ -37,14 +38,6 @@
         --md-select-width: var(--settings-input-max-width);
       }
 
-      #select-label {
-        @apply --cr-form-field-label;
-      }
-
-      :host-context([dir=rtl]) #select-label {
-        transform-origin: right;
-      }
-
       .long {
         width: var(--settings-input-max-width);
       }
@@ -93,7 +86,9 @@
           </div>
         </template>
         <div id="select-row" class="address-row">
-          <div id="select-label">$i18n{addressCountry}</div>
+          <label id="select-label" class="cr-form-field-label">
+            $i18n{addressCountry}
+          </label>
           <select class="md-select" aria-labelledby="select-label"
               value="[[countryCode_]]" on-change="onCountryChange_">
             <option value=""></option>
diff --git a/chrome/browser/resources/settings/autofill_page/credit_card_edit_dialog.html b/chrome/browser/resources/settings/autofill_page/credit_card_edit_dialog.html
index 79f81ebe..30f32f21 100644
--- a/chrome/browser/resources/settings/autofill_page/credit_card_edit_dialog.html
+++ b/chrome/browser/resources/settings/autofill_page/credit_card_edit_dialog.html
@@ -3,6 +3,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
@@ -11,7 +12,7 @@
 
 <dom-module id="settings-credit-card-edit-dialog">
   <template>
-    <style include="settings-shared md-select">
+    <style include="cr-shared-style settings-shared md-select">
       cr-input {
         --cr-input-error-display: none;
         margin-bottom: var(--cr-form-field-bottom-spacing);
@@ -56,10 +57,6 @@
       #year {
         width: 100px;
       }
-
-      label {
-        @apply --cr-form-field-label;
-      }
     </style>
     <cr-dialog id="dialog" close-text="$i18n{close}">
       <div slot="title">[[title_]]</div>
@@ -72,10 +69,12 @@
             value="{{creditCard.cardNumber}}"
             on-input="onCreditCardNameOrNumberChanged_">
         </cr-input>
-        <label>$i18n{creditCardExpiration}</label>
+        <label id="creditCardExpiration" class="cr-form-field-label">
+          $i18n{creditCardExpiration}
+        </label>
         <select class="md-select" id="month" value="[[expirationMonth_]]"
             on-change="onMonthChange_"
-            aria-label="$i18n{creditCardExpirationMonth}">
+            aria-labelledby="creditCardExpiration">
           <template is="dom-repeat" items="[[monthList_]]">
             <option>[[item]]</option>
           </template>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index 57ea8e7..80d61cd9 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -44,7 +44,6 @@
       }
 
       #advancedToggle {
-        @apply --cr-actionable;
         --ink-color: currentColor;
         align-items: center;
         background: transparent;
diff --git a/chrome/browser/resources/settings/controls/settings_radio_group.html b/chrome/browser/resources/settings/controls/settings_radio_group.html
index 1e37711..ff6a6759 100644
--- a/chrome/browser/resources/settings/controls/settings_radio_group.html
+++ b/chrome/browser/resources/settings/controls/settings_radio_group.html
@@ -9,9 +9,9 @@
 <dom-module id="settings-radio-group">
   <template>
     <style include="settings-shared"></style>
-    <div>[[label]]</div>
     <cr-radio-group selected="[[selected]]"
-        on-selected-changed="onSelectedChanged_">
+        on-selected-changed="onSelectedChanged_"
+        aria-label$="[[groupAriaLabel]]">
       <slot></slot>
     </cr-radio-group>
   </template>
diff --git a/chrome/browser/resources/settings/controls/settings_radio_group.js b/chrome/browser/resources/settings/controls/settings_radio_group.js
index 622ae66b..542e6df 100644
--- a/chrome/browser/resources/settings/controls/settings_radio_group.js
+++ b/chrome/browser/resources/settings/controls/settings_radio_group.js
@@ -18,6 +18,8 @@
   behaviors: [PrefControlBehavior],
 
   properties: {
+    groupAriaLabel: String,
+
     selected: String,
   },
 
diff --git a/chrome/browser/resources/settings/controls/settings_textarea.html b/chrome/browser/resources/settings/controls/settings_textarea.html
index 4ecd58d..0d6cf96 100644
--- a/chrome/browser/resources/settings/controls/settings_textarea.html
+++ b/chrome/browser/resources/settings/controls/settings_textarea.html
@@ -1,11 +1,12 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input_style_css.html">
 
 <dom-module id="settings-textarea">
   <template>
-    <style include="cr-hidden-style cr-input-style">
+    <style include="cr-hidden-style cr-input-style cr-shared-style">
       textarea {
         display: block;
         resize: none;
@@ -19,7 +20,9 @@
         position: static;
       }
     </style>
-    <div id="label" hidden="[[!label]]">[[label]]</div>
+    <div id="label" class="cr-form-field-label" hidden="[[!label]]">
+      [[label]]
+    </div>
     <div id="input-container">
       <!-- The textarea is limited to |rows| height. If the content exceeds the
            bounds, it scrolls by default. No space or comments are allowed
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_radio_button.html b/chrome/browser/resources/settings/multidevice_page/multidevice_radio_button.html
index 44a0ea6..c1f52cdc 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_radio_button.html
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_radio_button.html
@@ -30,7 +30,15 @@
       }
     </style>
 
-    <div class="disc-wrapper">
+    <div
+        aria-checked$="[[getAriaChecked_(checked)]]"
+        aria-disabled$="[[getAriaDisabled_(disabled)]]"
+        aria-labelledby="labelWrapper"
+        class="disc-wrapper"
+        id="button"
+        role="radio"
+        tabindex="0"
+        on-keydown="onInputKeydown_">
       <div class="disc-border"></div>
       <div class="disc"></div>
     </div>
diff --git a/chrome/browser/resources/settings/on_startup_page/on_startup_page.html b/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
index f4bdec1..1d7e888 100644
--- a/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
+++ b/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
@@ -17,7 +17,8 @@
     </style>
     <div class="settings-box block first">
       <settings-radio-group id="onStartupRadioGroup"
-          pref="{{prefs.session.restore_on_startup}}">
+          pref="{{prefs.session.restore_on_startup}}"
+          group-aria-label="$i18n{onStartup}">
         <controlled-radio-button name="[[prefValues_.OPEN_NEW_TAB]]"
             pref="[[prefs.session.restore_on_startup]]"
             label="$i18n{onStartupOpenNewTab}"
diff --git a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html
index 4a3b960..8bb189b 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html
+++ b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html
@@ -19,10 +19,6 @@
 <dom-module id="kerberos-add-account-dialog">
   <template>
     <style include="settings-shared action-link">
-      .label {
-        @apply --cr-form-field-label;
-      }
-
       #advancedConfigDesc {
         align-items: center;
         display: flex;
@@ -141,4 +137,4 @@
     </template>
   </template>
   <script src="kerberos_add_account_dialog.js"></script>
-</dom-module>
\ No newline at end of file
+</dom-module>
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
index 7a89bdc..98020db 100644
--- a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
+++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
@@ -4,6 +4,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html">
 <link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
@@ -15,7 +16,7 @@
 
 <dom-module id="add-printer-discovery-dialog">
   <template>
-    <style include="cups-printer-shared">
+    <style include="cr-shared-style cups-printer-shared">
       add-printer-list {
         max-height: 310px;
         overflow-y: auto;
@@ -101,7 +102,9 @@
         </div>
         <div class="settings-box two-line">
           <div class="start">
-            <div id="printerProtocol" class="label">$i18n{printerProtocol}</div>
+            <div id="printerProtocol" class="cr-form-field-label">
+              $i18n{printerProtocol}
+            </div>
             <div class="secondary">
               <select class="md-select" aria-labelledby="printerProtocol"
                   value="[[newPrinter.printerProtocol]]"
@@ -186,7 +189,7 @@
               value="{{activePrinter.ppdModel}}">
           </cr-searchable-drop-down>
         </div>
-        <div id="ppdLabel" class="field-label">
+        <div id="ppdLabel" class="cr-form-field-label">
           <span>$i18n{selectDriver}</span>
           <a href="$i18n{printingCUPSPrintPpdLearnMoreUrl}" target="_blank">
               $i18n{learnMore}
diff --git a/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html b/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html
index bf90be8..793770fd 100644
--- a/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html
+++ b/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html
@@ -6,6 +6,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_scrollable_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/html/chromeos/onc_mojo.html">
 <link rel="import" href="../i18n_setup.html">
 <link rel="import" href="cups_add_printer_dialog_elements.html">
@@ -15,7 +16,7 @@
 
 <dom-module id="settings-cups-edit-printer-dialog">
   <template>
-    <style include="cups-printer-shared"></style>
+    <style include="cr-shared-style cups-printer-shared"></style>
     <add-printer-dialog>
       <div slot="dialog-title">$i18n{editPrinterDialogTitle}
         <div id="general-error-container" hidden="[[!errorText_]]">
@@ -49,7 +50,9 @@
         </div>
         <div class="settings-box two-line">
           <div class="start">
-            <div id="printerProtocol" class="label">$i18n{printerProtocol}</div>
+            <div id="printerProtocol" class="cr-form-field-label">
+              $i18n{printerProtocol}
+            </div>
             <div class="secondary">
               <select class="md-select" aria-labelledby="printerProtocol"
                   value="[[pendingPrinter_.printerProtocol]]"
@@ -114,7 +117,7 @@
               readonly="[[!isOnline_]]">
           </cr-searchable-drop-down>
         </div>
-        <div id="ppdLabel" class="field-label">
+        <div id="ppdLabel" class="cr-form-field-label">
           <span>$i18n{selectDriver}</span>
           <a href="$i18n{printingCUPSPrintPpdLearnMoreUrl}" target="_blank">
               $i18n{learnMore}
diff --git a/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html b/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html
index 20108ee6..cda0410 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html
+++ b/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html
@@ -17,10 +17,6 @@
         align-items: flex-start;
       }
 
-      [slot='dialog-body'] .settings-box .start .label {
-        @apply --cr-form-field-label;
-      }
-
       [slot='dialog-body'] .settings-box cr-input {
         width: 100%;
       }
@@ -77,12 +73,12 @@
         border: none;
         box-sizing: border-box;
         color: var(--paper-grey-800);
+        cursor: pointer;
         font: inherit;
         min-height: 32px;
         padding: 0 24px;
         text-align: start;
         width: 100%;
-        @apply --cr-actionable;
       }
 
       .list-item:focus {
@@ -94,9 +90,8 @@
         font: inherit;
       }
 
-      .field-label {
+      #ppdLabel {
         padding-inline-start: 20px;
-        @apply --cr-form-field-label;
       }
 
       #general-error-container {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style_css.html b/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style_css.html
index 6e51989..96d00fb 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style_css.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/shared/action_link_style_css.html
@@ -8,11 +8,11 @@
   <template>
     <style>
       button.action-link {
-        @apply --cr-actionable;
         -webkit-appearance: none;
         background: none;
         border: none;
         color: var(--cr-link-color);
+        cursor: pointer;
         display: inline-block;
         font-family: inherit;
         text-decoration: none;
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc b/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc
index 212c5f4..de20b5ee 100644
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc
@@ -272,13 +272,7 @@
 
   exo::Surface* const surface = exo::GetShellMainSurface(arc_active_window_);
   DCHECK(surface);
-  surface->SetCommitCallback(base::BindRepeating(
-      &ArcGraphicsTracingHandler::OnCommit, weak_ptr_factory_.GetWeakPtr()));
-}
-
-void ArcGraphicsTracingHandler::OnCommit(exo::Surface* surface) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  jank_detector_->OnSample();
+  surface->AddSurfaceObserver(this);
 }
 
 void ArcGraphicsTracingHandler::OnJankDetected(const base::Time& timestamp) {
@@ -318,6 +312,15 @@
   }
 }
 
+void ArcGraphicsTracingHandler::OnSurfaceDestroying(exo::Surface* surface) {
+  DiscardActiveArcWindow();
+}
+
+void ArcGraphicsTracingHandler::OnCommit(exo::Surface* surface) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  jank_detector_->OnSample();
+}
+
 void ArcGraphicsTracingHandler::UpdateActiveArcWindowInfo() {
   DCHECK(arc_active_window_);
   base::DictionaryValue task_information;
@@ -348,8 +351,8 @@
     return;
 
   exo::Surface* const surface = exo::GetShellMainSurface(arc_active_window_);
-  DCHECK(surface);
-  surface->SetCommitCallback(exo::Surface::CommitCallback());
+  if (surface)
+    surface->RemoveSurfaceObserver(this);
 
   arc_active_window_->RemovePreTargetHandler(this);
   arc_active_window_->RemoveObserver(this);
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h b/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h
index dc37db9..4f613c1a 100644
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h
+++ b/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/exo/surface_observer.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "ui/aura/window_observer.h"
 #include "ui/events/event_handler.h"
@@ -36,7 +37,8 @@
 class ArcGraphicsTracingHandler : public content::WebUIMessageHandler,
                                   public wm::ActivationChangeObserver,
                                   public aura::WindowObserver,
-                                  public ui::EventHandler {
+                                  public ui::EventHandler,
+                                  public exo::SurfaceObserver {
  public:
   ArcGraphicsTracingHandler();
   ~ArcGraphicsTracingHandler() override;
@@ -58,6 +60,10 @@
   // ui::EventHandler:
   void OnKeyEvent(ui::KeyEvent* event) override;
 
+  // exo::SurfaceObserver:
+  void OnSurfaceDestroying(exo::Surface* surface) override;
+  void OnCommit(exo::Surface* surface) override;
+
  private:
   void Activate();
   void StartTracing();
@@ -84,9 +90,6 @@
   // Stops tracking ARC window for janks.
   void DiscardActiveArcWindow();
 
-  // Called from exo::Surface on commit.
-  void OnCommit(exo::Surface* surface);
-
   // Called in case jank is detected in active ARC window.
   void OnJankDetected(const base::Time& timestamp);
 
diff --git a/chrome/browser/vr/webxr_vr_input_browser_test.cc b/chrome/browser/vr/webxr_vr_input_browser_test.cc
index fd9b4ea..38d30db1 100644
--- a/chrome/browser/vr/webxr_vr_input_browser_test.cc
+++ b/chrome/browser/vr/webxr_vr_input_browser_test.cc
@@ -696,7 +696,7 @@
       t->GetFileUrlForHtmlTestFile("test_webxr_input"));
   t->EnterSessionWithUserGestureOrFail();
 
-  unsigned int num_iterations = 10;
+  unsigned int num_iterations = 5;
   t->RunJavaScriptOrFail("stepSetupListeners(" +
                          base::NumberToString(num_iterations) + ")");
 
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index 69fc81c..9c40a2ec 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -539,10 +539,14 @@
     return;
   }
 
+  bool is_ble = *authenticator.AuthenticatorTransport() ==
+                AuthenticatorTransport::kBluetoothLowEnergy;
   AuthenticatorReference authenticator_reference(
       authenticator.GetId(), authenticator.GetDisplayName(),
-      *authenticator.AuthenticatorTransport(), authenticator.IsInPairingMode(),
-      authenticator.IsPaired(), authenticator.RequiresBlePairingPin());
+      *authenticator.AuthenticatorTransport(),
+      is_ble && authenticator.IsInPairingMode(),
+      is_ble && authenticator.IsPaired(),
+      is_ble && authenticator.RequiresBlePairingPin());
 
   if (authenticator_reference.is_paired &&
       authenticator_reference.transport ==
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index d944436..e905fe92 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -97,6 +97,7 @@
       "$root_gen_dir/chrome/invalidations_resources.pak",
       "$root_gen_dir/chrome/net_internals_resources.pak",
       "$root_gen_dir/chrome/quota_internals_resources.pak",
+      "$root_gen_dir/components/autofill/core/browser/autofill_address_rewriter_resources.pak",
       "$root_gen_dir/components/components_resources.pak",
       "$root_gen_dir/content/browser/tracing/tracing_resources.pak",
       "$root_gen_dir/content/content_resources.pak",
@@ -112,6 +113,7 @@
       "//chrome/browser/resources:net_internals_resources",
       "//chrome/browser/resources:quota_internals_resources",
       "//chrome/common:resources",
+      "//components/autofill/core/browser:autofill_address_rewriter_resources",
       "//components/resources",
       "//content:resources",
       "//content/browser/tracing:resources",
diff --git a/chrome/common/extensions/api/accessibility_private.json b/chrome/common/extensions/api/accessibility_private.json
index 32ce4504..d4ac406 100644
--- a/chrome/common/extensions/api/accessibility_private.json
+++ b/chrome/common/extensions/api/accessibility_private.json
@@ -403,6 +403,18 @@
           }
         ],
         "platforms": ["chromeos"]
+      },
+      {
+        "name": "openSettingsSubpage",
+        "type": "function",
+        "description": "Opens a specified settings subpage. To open a page with url chrome://settings/manageAccessibility/tts, pass in the substring 'manageAccessibility/tts'.",
+        "parameters": [
+          {
+            "name": "subpage",
+            "type": "string"
+          }
+        ],
+        "platforms": ["chromeos"]
       }
     ],
     "events": [
diff --git a/chrome/installer/mac/notarize_thing.py b/chrome/installer/mac/notarize_thing.py
index a53cbb7d..e4f41c4 100755
--- a/chrome/installer/mac/notarize_thing.py
+++ b/chrome/installer/mac/notarize_thing.py
@@ -15,7 +15,7 @@
 
 def main():
     parser = argparse.ArgumentParser(
-        'Notarize and staple an application binary or archive.')
+        description='Notarize and staple an application binary or archive.')
     parser.add_argument(
         '--user',
         '-u',
@@ -28,6 +28,13 @@
         help='The password or password reference (e.g. @keychain, see '
         '`xcrun altool -h`) to access the Apple notary service.')
     parser.add_argument(
+        '--asc-provider',
+        help='The ASC provider string to be used as the `--asc-provider` '
+        'argument to `xcrun altool`, to be used when --user is associated with '
+        'with multiple Apple developer teams. See `xcrun altool -h`. Run '
+        '`iTMSTransporter -m provider -account_type itunes_connect -v off -u '
+        'USERNAME -p PASSWORD` to list valid providers.')
+    parser.add_argument(
         '--no-staple',
         action='store_true',
         help='Wait for notarization results, but do not staple after '
@@ -56,7 +63,8 @@
 
         config_class = OverrideBundleIDConfig
 
-    config = config_class('notused', None, args.user, args.password)
+    config = config_class('notused', None, args.user, args.password,
+                          args.asc_provider)
 
     uuids = []
     for path in args.file:
diff --git a/chrome/installer/mac/sign_chrome.py b/chrome/installer/mac/sign_chrome.py
index fa3a8820..3f0f301 100755
--- a/chrome/installer/mac/sign_chrome.py
+++ b/chrome/installer/mac/sign_chrome.py
@@ -73,6 +73,13 @@
         help='The password or password reference (e.g. @keychain, see '
         '`xcrun altool -h`) used to authenticate to the Apple notary service.')
     parser.add_argument(
+        '--notary-asc-provider',
+        help='The ASC provider string to be used as the `--asc-provider` '
+        'argument to `xcrun altool`, to be used when --notary-user is '
+        'associated with multiple Apple developer teams. See `xcrun altool -h. '
+        'Run `iTMSTransporter -m provider -account_type itunes_connect -v off '
+        '-u USERNAME -p PASSWORD` to list valid providers.')
+    parser.add_argument(
         '--development',
         action='store_true',
         help='The specified identity is for development. Certain codesign '
@@ -114,9 +121,9 @@
             parser.error('The --notary-user and --notary-password arguments '
                          'are required with --notarize.')
 
-    config = create_config(
-        (args.identity, args.keychain, args.notary_user, args.notary_password),
-        args.development)
+    config = create_config((args.identity, args.keychain, args.notary_user,
+                            args.notary_password, args.notary_asc_provider),
+                           args.development)
     paths = model.Paths(args.input, args.output, None)
 
     if not os.path.exists(paths.output):
diff --git a/chrome/installer/mac/signing/config.py.in b/chrome/installer/mac/signing/config.py.in
index 0abdb133..71e0dede 100644
--- a/chrome/installer/mac/signing/config.py.in
+++ b/chrome/installer/mac/signing/config.py.in
@@ -22,7 +22,8 @@
                  identity,
                  keychain=None,
                  notary_user=None,
-                 notary_password=None):
+                 notary_password=None,
+                 notary_asc_provider=None):
         """Creates a CodeSignConfig that will sign the product using the static
         properties on the class, using the code signing identity passed to the
         constructor, which is found in the specified keychain.
@@ -38,12 +39,16 @@
             notary_password: Optional string password or password reference
                 (e.g. @keychain, see `xcrun altool -h`) that will be used to
                 authenticate to Apple's notary service if notarizing.
+            notary_asc_provider: Optitonal string that will be used as the
+                `--asc-provider` argument to `xcrun altool`, to be used when
+                notary_user is associatetd with multiple Apple developer teams.
         """
         assert identity
         self._identity = identity
         self._keychain = keychain
         self._notary_user = notary_user
         self._notary_password = notary_password
+        self._notary_asc_provider = notary_asc_provider
 
     @property
     def identity(self):
@@ -72,6 +77,13 @@
         return self._notary_password
 
     @property
+    def notary_asc_provider(self):
+        """Returns the ASC provider for authenticating to Apple's notary service
+        when notary_user is associatetd with multiple Apple developer teams.
+        """
+        return self._notary_asc_provider
+
+    @property
     def app_product(self):
         """Returns the product name that is used for the outer .app bundle.
         This is displayed to the user in Finder.
diff --git a/chrome/installer/mac/signing/model.py b/chrome/installer/mac/signing/model.py
index 92554732..5107735 100644
--- a/chrome/installer/mac/signing/model.py
+++ b/chrome/installer/mac/signing/model.py
@@ -257,7 +257,7 @@
 
         return DistributionCodeSignConfig(
             base_config.identity, base_config.keychain, base_config.notary_user,
-            base_config.notary_password)
+            base_config.notary_password, base_config.notary_asc_provider)
 
 
 class Paths(object):
diff --git a/chrome/installer/mac/signing/notarize.py b/chrome/installer/mac/signing/notarize.py
index b91e14b..001fb83 100644
--- a/chrome/installer/mac/signing/notarize.py
+++ b/chrome/installer/mac/signing/notarize.py
@@ -33,12 +33,15 @@
     Returns:
         A UUID from the notary service that represents the request.
     """
-    output = commands.run_command_output([
+    command = [
         'xcrun', 'altool', '--notarize-app', '--file', path,
         '--primary-bundle-id', config.base_bundle_id, '--username',
         config.notary_user, '--password', config.notary_password,
         '--output-format', 'xml'
-    ])
+    ]
+    if config.notary_asc_provider is not None:
+        command.extend(['--asc-provider', config.notary_asc_provider])
+    output = commands.run_command_output(command)
     plist = plistlib.loads(output)
     uuid = plist['notarization-upload']['RequestUUID']
     print('Submitted {} for notarization, request UUID: {}.'.format(path, uuid))
@@ -71,11 +74,15 @@
     while len(wait_set) > 0:
         for uuid in list(wait_set):
             try:
-                output = commands.run_command_output([
+                command = [
                     'xcrun', 'altool', '--notarization-info', uuid,
                     '--username', config.notary_user, '--password',
                     config.notary_password, '--output-format', 'xml'
-                ])
+                ]
+                if config.notary_asc_provider is not None:
+                    command.extend(
+                        ['--asc-provider', config.notary_asc_provider])
+                output = commands.run_command_output(command)
             except subprocess.CalledProcessError as e:
                 # A notarization request might report as "not found" immediately
                 # after submission, which causes altool to exit non-zero. Check
diff --git a/chrome/installer/mac/signing/notarize_test.py b/chrome/installer/mac/signing/notarize_test.py
index fbedc34..bed24f8 100644
--- a/chrome/installer/mac/signing/notarize_test.py
+++ b/chrome/installer/mac/signing/notarize_test.py
@@ -40,6 +40,25 @@
             '--output-format', 'xml'
         ])
 
+    @mock.patch('signing.commands.run_command_output')
+    def test_valid_upload_with_asc_provider(self, run_command_output):
+        run_command_output.return_value = _make_plist({
+            'notarization-upload': {
+                'RequestUUID': '746f1537-0613-4e49-a9a0-869f2c9dc8e5'
+            },
+        })
+        config = test_config.TestConfig(
+            notary_asc_provider='[NOTARY-ASC-PROVIDER]')
+        uuid = notarize.submit('/tmp/file.dmg', config)
+
+        self.assertEqual('746f1537-0613-4e49-a9a0-869f2c9dc8e5', uuid)
+        run_command_output.assert_called_once_with([
+            'xcrun', 'altool', '--notarize-app', '--file', '/tmp/file.dmg',
+            '--primary-bundle-id', 'test.signing.bundle_id', '--username',
+            '[NOTARY-USER]', '--password', '[NOTARY-PASSWORD]',
+            '--output-format', 'xml', '--asc-provider', '[NOTARY-ASC-PROVIDER]'
+        ])
+
 
 class TestWaitForResults(unittest.TestCase):
 
@@ -66,6 +85,32 @@
         ])
 
     @mock.patch('signing.commands.run_command_output')
+    def test_success_with_asc_provider(self, run_command_output):
+        run_command_output.return_value = _make_plist({
+            'notarization-info': {
+                'Date': '2019-07-08T20:11:24Z',
+                'LogFileURL': 'https://example.com/log.json',
+                'RequestUUID': '0a88b2d8-4098-4d3a-8461-5b543b479d15',
+                'Status': 'success',
+                'Status Code': 0
+            }
+        })
+        uuid = '0a88b2d8-4098-4d3a-8461-5b543b479d15'
+        uuids = [uuid]
+        self.assertEqual(
+            uuids,
+            list(
+                notarize.wait_for_results(
+                    uuids,
+                    test_config.TestConfig(
+                        notary_asc_provider='[NOTARY-ASC-PROVIDER]'))))
+        run_command_output.assert_called_once_with([
+            'xcrun', 'altool', '--notarization-info', uuid, '--username',
+            '[NOTARY-USER]', '--password', '[NOTARY-PASSWORD]',
+            '--output-format', 'xml', '--asc-provider', '[NOTARY-ASC-PROVIDER]'
+        ])
+
+    @mock.patch('signing.commands.run_command_output')
     def test_failure(self, run_command_output):
         run_command_output.return_value = _make_plist({
             'notarization-info': {
diff --git a/chrome/installer/mac/signing/pipeline.py b/chrome/installer/mac/signing/pipeline.py
index f8318c3b..2a05fce 100644
--- a/chrome/installer/mac/signing/pipeline.py
+++ b/chrome/installer/mac/signing/pipeline.py
@@ -289,7 +289,7 @@
                                             dist_config.dmg_basename + '.zip')
                     commands.run_command([
                         'zip', '--recurse-paths', '--symlinks', '--quiet',
-                        '--no-dir-entries', zip_file, dist_config.app_dir
+                        zip_file, dist_config.app_dir
                     ],
                                          cwd=dest_dir)
                     uuid = notarize.submit(zip_file, dist_config)
diff --git a/chrome/installer/mac/signing/pipeline_test.py b/chrome/installer/mac/signing/pipeline_test.py
index a0d65d8..5cfd0c7 100644
--- a/chrome/installer/mac/signing/pipeline_test.py
+++ b/chrome/installer/mac/signing/pipeline_test.py
@@ -483,8 +483,7 @@
             # Prepare the app for notarization.
             mock.call.run_command([
                 'zip', '--recurse-paths', '--symlinks', '--quiet',
-                '--no-dir-entries', '$W_1/AppProduct-99.0.9999.99.zip',
-                'App Product.app'
+                '$W_1/AppProduct-99.0.9999.99.zip', 'App Product.app'
             ],
                                   cwd='$W_1/AppProduct-99.0.9999.99'),
             mock.call.submit('$W_1/AppProduct-99.0.9999.99.zip', mock.ANY),
@@ -531,8 +530,7 @@
             # Prepare the app for notarization.
             mock.call.run_command([
                 'zip', '--recurse-paths', '--symlinks', '--quiet',
-                '--no-dir-entries', '$W_1/AppProduct-99.0.9999.99.zip',
-                'App Product.app'
+                '$W_1/AppProduct-99.0.9999.99.zip', 'App Product.app'
             ],
                                   cwd='$W_1/AppProduct-99.0.9999.99'),
             mock.call.submit('$W_1/AppProduct-99.0.9999.99.zip', mock.ANY),
diff --git a/chrome/installer/mac/signing/test_config.py b/chrome/installer/mac/signing/test_config.py
index 01ae57eb..5d618582 100644
--- a/chrome/installer/mac/signing/test_config.py
+++ b/chrome/installer/mac/signing/test_config.py
@@ -10,15 +10,17 @@
 config = imp.load_source('signing.config', os.path.join(THIS_DIR,
                                                         'config.py.in'))
 
+
 class TestConfig(config.CodeSignConfig):
 
     def __init__(self,
                  identity='[IDENTITY]',
                  keychain='[KEYCHAIN]',
                  notary_user='[NOTARY-USER]',
-                 notary_password='[NOTARY-PASSWORD]'):
+                 notary_password='[NOTARY-PASSWORD]',
+                 notary_asc_provider=None):
         super(TestConfig, self).__init__(identity, keychain, notary_user,
-                                         notary_password)
+                                         notary_password, notary_asc_provider)
 
     @property
     def app_product(self):
diff --git a/chrome/renderer/media/cast_receiver_audio_valve.cc b/chrome/renderer/media/cast_receiver_audio_valve.cc
index e13ab140..c2d5b856 100644
--- a/chrome/renderer/media/cast_receiver_audio_valve.cc
+++ b/chrome/renderer/media/cast_receiver_audio_valve.cc
@@ -39,19 +39,7 @@
 
   base::AutoLock lock(lock_);
   if (cb_) {
-    // The AudioCapturerSource::Callback interface provides timing information
-    // only as a relative delay value that means "captured N milliseconds ago."
-    // Therefore, translate the playout time to these semantics.  Since playout
-    // time is generally in the future, because audio should be decoded well
-    // ahead of when it should be played out, the audio delay value will
-    // generally be negative.
-    //
-    // TimeTicks::Now() is being called after the |lock_| was acquired in order
-    // to provide the most accurate delay value.
-    const int audio_delay_milliseconds =
-        (base::TimeTicks::Now() - playout_time).InMilliseconds();
-
-    cb_->Capture(&audio_bus, audio_delay_milliseconds, 1.0 /* volume */,
+    cb_->Capture(&audio_bus, playout_time, 1.0 /* volume */,
                  false /* key_pressed */);
   }
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b116e3f..c6deee2 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2981,7 +2981,7 @@
     "../browser/performance_manager/observers/graph_observer_unittest.cc",
     "../browser/performance_manager/observers/isolation_context_metrics_unittest.cc",
     "../browser/performance_manager/observers/metrics_collector_unittest.cc",
-    "../browser/performance_manager/observers/working_set_trimmer_win_unittest.cc",
+    "../browser/performance_manager/observers/working_set_trimmer_observer_win_unittest.cc",
     "../browser/performance_manager/performance_manager_tab_helper_unittest.cc",
     "../browser/performance_manager/performance_manager_test_harness.cc",
     "../browser/performance_manager/performance_manager_test_harness.h",
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
index ac3d1034f..27c5dbe 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -27,25 +27,7 @@
 const char kInspectorContextError[] =
     "Cannot find execution context with given id";
 const char kInspectorInvalidURL[] = "Cannot navigate to invalid URL";
-
-Status ParseInspectorError(const std::string& error_json) {
-  std::unique_ptr<base::Value> error =
-      base::JSONReader::ReadDeprecated(error_json);
-  base::DictionaryValue* error_dict;
-  if (!error || !error->GetAsDictionary(&error_dict))
-    return Status(kUnknownError, "inspector error with no error message");
-  std::string error_message;
-  bool error_found = error_dict->GetString("message", &error_message);
-  if (error_found) {
-    if (error_message == kInspectorDefaultContextError ||
-        error_message == kInspectorContextError) {
-      return Status(kNoSuchExecutionContext);
-    } else if (error_message == kInspectorInvalidURL) {
-      return Status(kInvalidArgument);
-    }
-  }
-  return Status(kUnknownError, "unhandled inspector error: " + error_json);
-}
+static constexpr int kInvalidParamsInspectorCode = -32602;
 
 class ScopedIncrementer {
  public:
@@ -358,7 +340,7 @@
       CHECK_EQ(response_info->state, kReceived);
       internal::InspectorCommandResponse& response = response_info->response;
       if (!response.result)
-        return ParseInspectorError(response.error);
+        return internal::ParseInspectorError(response.error);
       *result = std::move(response.result);
     }
   } else {
@@ -642,4 +624,26 @@
   return false;
 }
 
+Status ParseInspectorError(const std::string& error_json) {
+  std::unique_ptr<base::Value> error =
+      base::JSONReader::ReadDeprecated(error_json);
+  base::DictionaryValue* error_dict;
+  if (!error || !error->GetAsDictionary(&error_dict))
+    return Status(kUnknownError, "inspector error with no error message");
+  std::string error_message;
+  bool error_found = error_dict->GetString("message", &error_message);
+  if (error_found) {
+    if (error_message == kInspectorDefaultContextError ||
+        error_message == kInspectorContextError) {
+      return Status(kNoSuchExecutionContext);
+    } else if (error_message == kInspectorInvalidURL) {
+      return Status(kInvalidArgument);
+    }
+    base::Optional<int> error_code = error_dict->FindIntPath("code");
+    if (error_code == kInvalidParamsInspectorCode)
+      return Status(kInvalidArgument, error_message);
+  }
+  return Status(kUnknownError, "unhandled inspector error: " + error_json);
+}
+
 }  // namespace internal
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.h b/chrome/test/chromedriver/chrome/devtools_client_impl.h
index 36707d7..3dafe86d 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.h
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.h
@@ -193,6 +193,8 @@
     InspectorEvent* event,
     InspectorCommandResponse* command_response);
 
+Status ParseInspectorError(const std::string& error_json);
+
 }  // namespace internal
 
 #endif  // CHROME_TEST_CHROMEDRIVER_CHROME_DEVTOOLS_CLIENT_IMPL_H_
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
index b82b37f5..435271b5 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
@@ -574,6 +574,34 @@
   ASSERT_EQ(1, key);
 }
 
+TEST(ParseInspectorError, EmptyError) {
+  Status status = internal::ParseInspectorError("");
+  ASSERT_EQ(kUnknownError, status.code());
+  ASSERT_EQ("unknown error: inspector error with no error message",
+            status.message());
+}
+
+TEST(ParseInspectorError, InvalidUrlError) {
+  Status status = internal::ParseInspectorError(
+      "{\"message\": \"Cannot navigate to invalid URL\"}");
+  ASSERT_EQ(kInvalidArgument, status.code());
+}
+
+TEST(ParseInspectorError, InvalidArgumentCode) {
+  Status status = internal::ParseInspectorError(
+      "{\"code\": -32602, \"message\": \"Error description\"}");
+  ASSERT_EQ(kInvalidArgument, status.code());
+  ASSERT_EQ("invalid argument: Error description", status.message());
+}
+
+TEST(ParseInspectorError, UnknownError) {
+  const std::string error("{\"code\": 10, \"message\": \"Error description\"}");
+  Status status = internal::ParseInspectorError(error);
+  ASSERT_EQ(kUnknownError, status.code());
+  ASSERT_EQ("unknown error: unhandled inspector error: " + error,
+            status.message());
+}
+
 TEST_F(DevToolsClientImplTest, HandleEventsUntil) {
   MockListener listener;
   SyncWebSocketFactory factory =
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage.html b/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage.html
new file mode 100644
index 0000000..192ce1c26
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage.html
@@ -0,0 +1,6 @@
+<!--
+ * Copyright 2019 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.
+-->
+<script src="open_settings_subpage.js"></script>
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage.js b/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage.js
new file mode 100644
index 0000000..0541fb5
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage.js
@@ -0,0 +1,6 @@
+// Copyright 2019 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.
+
+chrome.accessibilityPrivate.openSettingsSubpage('manageAccessibility/tts');
+chrome.test.notifyPass();
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage_invalid_subpage.html b/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage_invalid_subpage.html
new file mode 100644
index 0000000..909d161
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage_invalid_subpage.html
@@ -0,0 +1,6 @@
+<!--
+ * Copyright 2019 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.
+-->
+<script src="open_settings_subpage_invalid_subpage.js"></script>
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage_invalid_subpage.js b/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage_invalid_subpage.js
new file mode 100644
index 0000000..fa6c4d9
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/open_settings_subpage_invalid_subpage.js
@@ -0,0 +1,6 @@
+// Copyright 2019 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.
+
+chrome.accessibilityPrivate.openSettingsSubpage('fakeSettingsPage');
+chrome.test.notifyPass();
diff --git a/chrome/test/data/webui/cr_elements/cr_input_test.js b/chrome/test/data/webui/cr_elements/cr_input_test.js
index 87509dda..2ae7271ce 100644
--- a/chrome/test/data/webui/cr_elements/cr_input_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_input_test.js
@@ -146,7 +146,7 @@
     assertEquals('none', getComputedStyle(crInput.$.label).display);
     crInput.label = 'foobar';
     assertEquals('block', getComputedStyle(crInput.$.label).display);
-    assertEquals('foobar', label.textContent);
+    assertEquals('foobar', label.textContent.trim());
   });
 
   test('valueSetCorrectly', function() {
diff --git a/chrome/test/data/webui/settings/settings_textarea_tests.js b/chrome/test/data/webui/settings/settings_textarea_tests.js
index 24fbfb1..9ff2c4c 100644
--- a/chrome/test/data/webui/settings/settings_textarea_tests.js
+++ b/chrome/test/data/webui/settings/settings_textarea_tests.js
@@ -38,7 +38,7 @@
     assertTrue(label.hidden);
     settingsTextarea.label = 'foobar';
     assertFalse(label.hidden);
-    assertEquals('foobar', label.textContent);
+    assertEquals('foobar', label.textContent.trim());
     assertEquals('foobar', textarea.getAttribute('aria-label'));
   });
 
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index f02b1ca8..a94a156 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -381,8 +381,16 @@
       "exo/wayland_server_controller.h",
       "exo/wm_helper_cast_shell.cc",
       "exo/wm_helper_cast_shell.h",
+      "webview/webview_controller.cc",
+      "webview/webview_controller.h",
+      "webview/webview_grpc_service.cc",
+      "webview/webview_grpc_service.h",
+      "webview/webview_layout_manager.cc",
+      "webview/webview_layout_manager.h",
     ]
+    configs += [ "//third_party/grpc:grpc_config" ]
     deps += [
+      "//chromecast/browser/webview/proto",
       "//components/exo",
       "//components/exo/wayland",
       "//services/viz/privileged/interfaces/compositing",
diff --git a/chromecast/browser/webview/DEPS b/chromecast/browser/webview/DEPS
new file mode 100644
index 0000000..17f9c9f
--- /dev/null
+++ b/chromecast/browser/webview/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+components/exo",
+  "+third_party/grpc",
+]
diff --git a/chromecast/browser/webview/proto/BUILD.gn b/chromecast/browser/webview/proto/BUILD.gn
new file mode 100644
index 0000000..78f5860
--- /dev/null
+++ b/chromecast/browser/webview/proto/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/grpc/grpc_library.gni")
+
+cc_grpc_library("proto") {
+  sources = [
+    "webview.proto",
+  ]
+}
diff --git a/chromecast/browser/webview/proto/webview.proto b/chromecast/browser/webview/proto/webview.proto
new file mode 100644
index 0000000..c6311258
--- /dev/null
+++ b/chromecast/browser/webview/proto/webview.proto
@@ -0,0 +1,126 @@
+// Copyright 2019 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.
+
+// This provides an API to create and control webviews via gRPC.
+// Each webview is a separate bidirectional message stream, the client creates
+// a new one by sending a WebviewCreate message first. Subsequently, the client
+// navigates and injects input as desired and the server will respond with
+// event messages whenever page state changes, whether or not in direct response
+// to client actions, eg if the renderer crashes.
+
+syntax = "proto3";
+option optimize_for = LITE_RUNTIME;
+package chromecast.webview;
+
+message AccessibilityTreeInfo {
+  string ax_tree_id = 1;
+}
+
+// Create a new, empty webview
+message WebviewCreateRequest {
+  // This identifies the surface that this webview will display into.
+  // It should be unique and the same as whatever was set into
+  // |aura_surface_set_client_surface_id| on the wayland surface.
+  // It is an error to attempt to create a webview if the surface
+  // does not yet exist.
+  int32 webview_id = 1;
+  // This is the cast window ID that will be assigned to the web contents
+  // window.
+  int32 window_id = 2;
+}
+
+message WebviewCreateResponse {
+  AccessibilityTreeInfo accessibility_info = 1;
+}
+
+// These are a translation of ui::Event and children.
+message KeyInput {
+  int32 key_code = 1;
+  int32 dom_code = 2;
+  int32 dom_key = 3;
+  bool is_char = 4;
+}
+
+message TouchInput {
+  float x = 1;
+  float y = 2;
+  float root_x = 3;
+  float root_y = 4;
+  int32 pointer_type = 5;
+  int32 pointer_id = 6;
+  float radius_x = 7;
+  float radius_y = 8;
+  float force = 9;
+  float twist = 10;
+  float tilt_x = 11;
+  float tilt_y = 12;
+  float tangential_pressure = 13;
+}
+
+message MouseEvent {
+  float x = 1;
+  float y = 2;
+  float root_x = 3;
+  float root_y = 4;
+  int32 changed_button_flags = 5;
+}
+
+message InputEvent {
+  int32 event_type = 1;
+  int32 flags = 2;
+  int64 timestamp = 3;
+  KeyInput key = 4;
+  TouchInput touch = 5;
+  MouseEvent mouse = 6;
+}
+
+// Navigate this webview to the provided url.
+message NavigateRequest {
+  string url = 1;
+}
+
+message AsyncPageEvent {
+  enum State {
+    IDLE = 0;
+    LOADING = 1;
+    LOADED = 2;
+    CLOSED = 3;
+    DESTROYED = 4;
+    ERROR = 5;
+  }
+  // This is always set to the current state.
+  State current_page_state = 1;
+  // These will be set if the event just happened.
+  int32 stopped_error_code = 2;
+  bool resource_load_failed = 3;
+  bool did_first_visually_non_empty_paint = 4;
+}
+
+message StopPageRequest {
+  int32 error_code = 1;
+}
+
+message WebviewRequest {
+  oneof type {
+    // This must be the first message.
+    WebviewCreateRequest create = 1;
+    // No response.
+    InputEvent input = 2;
+    // Expect page events to follow.
+    NavigateRequest navigate = 3;
+    // Expect page events to follow.
+    StopPageRequest stop_page = 4;
+  }
+}
+
+message WebviewResponse {
+  oneof type {
+    WebviewCreateResponse create_response = 1;
+    AsyncPageEvent page_event = 2;
+  }
+}
+
+service WebviewService {
+  rpc CreateWebview(stream WebviewRequest) returns (stream WebviewResponse);
+}
diff --git a/chromecast/browser/webview/webview_controller.cc b/chromecast/browser/webview/webview_controller.cc
new file mode 100644
index 0000000..887fe25
--- /dev/null
+++ b/chromecast/browser/webview/webview_controller.cc
@@ -0,0 +1,192 @@
+// Copyright 2019 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 "chromecast/browser/webview/webview_controller.h"
+
+#include "chromecast/base/version.h"
+#include "chromecast/browser/cast_web_contents_impl.h"
+#include "chromecast/browser/webview/proto/webview.pb.h"
+#include "chromecast/browser/webview/webview_layout_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/events/event.h"
+
+namespace chromecast {
+
+WebviewController::WebviewController(content::BrowserContext* browser_context,
+                                     Client* client)
+    : client_(client) {
+  content::WebContents::CreateParams create_params(browser_context, nullptr);
+  contents_ = content::WebContents::Create(create_params);
+  CastWebContents::InitParams cast_contents_init;
+  cast_contents_init.is_root_window = true;
+  cast_contents_init.enabled_for_dev = CAST_IS_DEBUG_BUILD();
+  cast_contents_init.delegate = this;
+  cast_web_contents_ = std::make_unique<CastWebContentsImpl>(
+      contents_.get(), cast_contents_init);
+
+  std::unique_ptr<webview::WebviewResponse> response =
+      std::make_unique<webview::WebviewResponse>();
+  auto ax_id = contents_->GetMainFrame()->GetAXTreeID().ToString();
+  response->mutable_create_response()
+      ->mutable_accessibility_info()
+      ->set_ax_tree_id(ax_id);
+  client->EnqueueSend(std::move(response));
+}
+
+WebviewController::~WebviewController() {}
+
+void WebviewController::ProcessRequest(const webview::WebviewRequest& request) {
+  switch (request.type_case()) {
+    case webview::WebviewRequest::kInput:
+      ProcessInputEvent(request.input());
+      break;
+
+    case webview::WebviewRequest::kNavigate:
+      if (request.has_navigate()) {
+        LOG(INFO) << "Navigate webview to " << request.navigate().url();
+        stopped_ = false;
+        cast_web_contents_->LoadUrl(GURL(request.navigate().url()));
+      } else {
+        client_->OnError("navigate() not supplied");
+      }
+      break;
+
+    case webview::WebviewRequest::kStopPage:
+      if (request.has_stop_page()) {
+        cast_web_contents_->Stop(request.stop_page().error_code());
+      } else {
+        client_->OnError("stop_page() not supplied");
+      }
+      break;
+
+    default:
+      client_->OnError("Unknown request code");
+      break;
+  }
+}
+
+void WebviewController::ClosePage() {
+  cast_web_contents_->ClosePage();
+}
+
+void WebviewController::AttachTo(aura::Window* window, int window_id) {
+  auto* contents_window = contents_->GetNativeView();
+  window->SetLayoutManager(new WebviewLayoutManager(contents_window));
+  contents_window->set_id(window_id);
+  contents_window->SetBounds(gfx::Rect(window->bounds().size()));
+  contents_window->Show();
+  window->AddChild(contents_->GetNativeView());
+}
+
+void WebviewController::ProcessInputEvent(const webview::InputEvent& ev) {
+  ui::EventHandler* handler = contents_->GetNativeView()->delegate();
+  ui::EventType type = static_cast<ui::EventType>(ev.event_type());
+  switch (type) {
+    case ui::ET_TOUCH_RELEASED:
+    case ui::ET_TOUCH_PRESSED:
+    case ui::ET_TOUCH_MOVED:
+    case ui::ET_TOUCH_CANCELLED:
+      if (ev.has_touch()) {
+        auto& touch = ev.touch();
+        ui::TouchEvent evt(
+            type, gfx::PointF(touch.x(), touch.y()),
+            gfx::PointF(touch.root_x(), touch.root_y()),
+            base::TimeTicks() +
+                base::TimeDelta::FromMicroseconds(ev.timestamp()),
+            ui::PointerDetails(
+                static_cast<ui::EventPointerType>(touch.pointer_type()),
+                static_cast<ui::PointerId>(touch.pointer_id()),
+                touch.radius_x(), touch.radius_y(), touch.force(),
+                touch.twist(), touch.tilt_x(), touch.tilt_y(),
+                touch.tangential_pressure()),
+            ev.flags());
+        handler->OnTouchEvent(&evt);
+      } else {
+        client_->OnError("touch() not supplied for touch event");
+      }
+      break;
+    case ui::ET_MOUSE_PRESSED:
+    case ui::ET_MOUSE_DRAGGED:
+    case ui::ET_MOUSE_RELEASED:
+    case ui::ET_MOUSE_MOVED:
+    case ui::ET_MOUSE_ENTERED:
+    case ui::ET_MOUSE_EXITED:
+    case ui::ET_MOUSEWHEEL:
+    case ui::ET_MOUSE_CAPTURE_CHANGED:
+      if (ev.has_mouse()) {
+        auto& mouse = ev.mouse();
+        ui::MouseEvent evt(
+            type, gfx::PointF(mouse.x(), mouse.y()),
+            gfx::PointF(mouse.root_x(), mouse.root_y()),
+            base::TimeTicks() +
+                base::TimeDelta::FromMicroseconds(ev.timestamp()),
+            ev.flags(), mouse.changed_button_flags());
+        handler->OnMouseEvent(&evt);
+      } else {
+        client_->OnError("mouse() not supplied for mouse event");
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+webview::AsyncPageEvent_State WebviewController::current_state() {
+  // The PB enum is defined identically.
+  return static_cast<webview::AsyncPageEvent_State>(
+      cast_web_contents_->page_state());
+}
+
+void WebviewController::OnPageStateChanged(CastWebContents* cast_web_contents) {
+  if (client_) {
+    std::unique_ptr<webview::WebviewResponse> response =
+        std::make_unique<webview::WebviewResponse>();
+    auto* event = response->mutable_page_event();
+    event->set_current_page_state(current_state());
+    client_->EnqueueSend(std::move(response));
+  }
+}
+
+void WebviewController::OnPageStopped(CastWebContents* cast_web_contents,
+                                      int error_code) {
+  stopped_ = true;
+  if (client_) {
+    std::unique_ptr<webview::WebviewResponse> response =
+        std::make_unique<webview::WebviewResponse>();
+    auto* event = response->mutable_page_event();
+    event->set_current_page_state(current_state());
+    event->set_stopped_error_code(error_code);
+    client_->EnqueueSend(std::move(response));
+  } else {
+    // Can't destroy in an observer callback, so post a task to do it.
+    base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+  }
+}
+
+void WebviewController::ResourceLoadFailed(CastWebContents* cast_web_contents) {
+  if (client_) {
+    std::unique_ptr<webview::WebviewResponse> response =
+        std::make_unique<webview::WebviewResponse>();
+    auto* event = response->mutable_page_event();
+    event->set_current_page_state(current_state());
+    event->set_resource_load_failed(true);
+    client_->EnqueueSend(std::move(response));
+  }
+}
+
+void WebviewController::Destroy() {
+  // This webview is now abandoned and should close.
+  client_ = nullptr;
+  if (stopped_) {
+    // If the page has been stopped this can be deleted immediately.
+    delete this;
+  } else {
+    // This will eventually call OnPageStopped.
+    cast_web_contents_->ClosePage();
+  }
+}
+
+}  // namespace chromecast
diff --git a/chromecast/browser/webview/webview_controller.h b/chromecast/browser/webview/webview_controller.h
new file mode 100644
index 0000000..627b03e
--- /dev/null
+++ b/chromecast/browser/webview/webview_controller.h
@@ -0,0 +1,82 @@
+// Copyright 2019 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 CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_CONTROLLER_H_
+#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_CONTROLLER_H_
+
+#include <memory>
+#include <string>
+
+#include "chromecast/browser/cast_web_contents.h"
+#include "chromecast/browser/webview/proto/webview.pb.h"
+
+namespace aura {
+class Window;
+}  // namespace aura
+
+namespace chromecast {
+class CastWebContents;
+}  // namespace chromecast
+
+namespace content {
+class BrowserContext;
+class WebContents;
+}  // namespace content
+
+namespace chromecast {
+
+// This owns a WebContents and CastWebContents and processes proto commands
+// to allow the web contents to be controlled and embedded.
+class WebviewController : public CastWebContents::Delegate,
+                          public CastWebContents::Observer {
+ public:
+  class Client {
+   public:
+    virtual ~Client() {}
+    virtual void EnqueueSend(
+        std::unique_ptr<webview::WebviewResponse> response) = 0;
+    virtual void OnError(const std::string& error_message) = 0;
+  };
+  WebviewController(content::BrowserContext* browser_context, Client* client);
+  ~WebviewController() override;
+
+  // Cause the controller to be destroyed after giving the webpage a chance to
+  // run unload events. This unsets the client so no more messages will be
+  // sent.
+  void Destroy();
+
+  // Close the page. This will cause a stopped response to eventually be sent.
+  void ClosePage();
+
+  void ProcessRequest(const webview::WebviewRequest& request);
+
+  // Attach this web contents to an aura window as a child.
+  void AttachTo(aura::Window* window, int window_id);
+
+ private:
+  webview::AsyncPageEvent_State current_state();
+
+  void ProcessInputEvent(const webview::InputEvent& ev);
+
+  bool Check(bool condition, const char* error);
+
+  // CastWebContents::Delegate
+  void OnPageStateChanged(CastWebContents* cast_web_contents) override;
+  void OnPageStopped(CastWebContents* cast_web_contents,
+                     int error_code) override;
+
+  // CastWebContents::Observer
+  void ResourceLoadFailed(CastWebContents* cast_web_contents) override;
+
+  Client* client_;  // Not owned.
+  std::unique_ptr<content::WebContents> contents_;
+  std::unique_ptr<CastWebContents> cast_web_contents_;
+  bool stopped_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(WebviewController);
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_CONTROLLER_H_
diff --git a/chromecast/browser/webview/webview_grpc_service.cc b/chromecast/browser/webview/webview_grpc_service.cc
new file mode 100644
index 0000000..b702725
--- /dev/null
+++ b/chromecast/browser/webview/webview_grpc_service.cc
@@ -0,0 +1,273 @@
+// Copyright 2019 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 "chromecast/browser/webview/webview_grpc_service.h"
+
+#include <deque>
+#include <mutex>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "chromecast/browser/cast_browser_context.h"
+#include "chromecast/browser/cast_browser_process.h"
+#include "chromecast/browser/webview/webview_controller.h"
+#include "components/exo/surface.h"
+#include "components/exo/wm_helper.h"
+#include "third_party/grpc/src/include/grpcpp/grpcpp.h"
+#include "third_party/grpc/src/include/grpcpp/security/server_credentials.h"
+#include "third_party/grpc/src/include/grpcpp/server_builder.h"
+
+namespace chromecast {
+namespace {
+
+aura::Window* FindChildWindowWithID(aura::Window* window, int id) {
+  if (window->GetProperty(exo::kClientSurfaceIdKey) == id)
+    return window;
+  for (auto* w : window->children()) {
+    auto* ret = FindChildWindowWithID(w, id);
+    if (ret)
+      return ret;
+  }
+  return nullptr;
+}
+
+typedef base::RepeatingCallback<void(bool)> GrpcCallback;
+
+// Threading model and life cycle.
+// WebviewRpcInstance creates copies of itself and deletes itself as needed.
+// Instances are deleted when the GRPC Finish request completes and there are
+// no other outstanding read or write operations.
+// Deletion bounces off the webview thread to synchronize with request
+// processing.
+class WebviewRpcInstance : public WebviewController::Client {
+ public:
+  WebviewRpcInstance(webview::WebviewService::AsyncService* service,
+                     grpc::ServerCompletionQueue* cq,
+                     scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+  ~WebviewRpcInstance() override;
+
+ private:
+  void InitComplete(bool ok);
+  void ReadComplete(bool ok);
+  void WriteComplete(bool ok);
+  void FinishComplete(bool ok);
+  bool Initialize();
+
+  void StartRead();
+  void CreateWebview(int app_id, int window_id);
+
+  void ProcessRequestOnWebviewThread(
+      std::unique_ptr<webview::WebviewRequest> request);
+
+  void EnqueueSend(std::unique_ptr<webview::WebviewResponse> response) override;
+  void OnError(const std::string& error_message) override;
+
+  GrpcCallback init_callback_;
+  GrpcCallback read_callback_;
+  GrpcCallback write_callback_;
+  GrpcCallback destroy_callback_;
+
+  grpc::ServerContext ctx_;
+  webview::WebviewService::AsyncService* service_;
+  grpc::ServerCompletionQueue* cq_;
+  std::unique_ptr<webview::WebviewRequest> request_;
+  grpc::ServerAsyncReaderWriter<webview::WebviewResponse,
+                                webview::WebviewRequest>
+      io_;
+  std::unique_ptr<WebviewController> webview_;
+
+  std::mutex send_lock_;
+  bool errored_ = false;
+  std::string error_message_;
+  bool send_pending_ = false;
+  bool destroying_ = false;
+  std::deque<std::unique_ptr<webview::WebviewResponse>> pending_messages_;
+
+  grpc::WriteOptions write_options_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebviewRpcInstance);
+};
+
+WebviewRpcInstance::WebviewRpcInstance(
+    webview::WebviewService::AsyncService* service,
+    grpc::ServerCompletionQueue* cq,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    : service_(service), cq_(cq), io_(&ctx_), task_runner_(task_runner) {
+  write_options_.clear_buffer_hint();
+  write_options_.clear_corked();
+
+  init_callback_ = base::BindRepeating(&WebviewRpcInstance::InitComplete,
+                                       base::Unretained(this));
+  read_callback_ = base::BindRepeating(&WebviewRpcInstance::ReadComplete,
+                                       base::Unretained(this));
+  write_callback_ = base::BindRepeating(&WebviewRpcInstance::WriteComplete,
+                                        base::Unretained(this));
+  destroy_callback_ = base::BindRepeating(&WebviewRpcInstance::FinishComplete,
+                                          base::Unretained(this));
+
+  service_->RequestCreateWebview(&ctx_, &io_, cq_, cq_, &init_callback_);
+}
+
+WebviewRpcInstance::~WebviewRpcInstance() {
+  DCHECK(destroying_);
+  if (webview_) {
+    webview_.release()->Destroy();
+  }
+}
+
+void WebviewRpcInstance::FinishComplete(bool ok) {
+  // Bounce off of the webview thread to allow it to complete any pending work.
+  destroying_ = true;
+  if (!send_pending_) {
+    task_runner_->DeleteSoon(FROM_HERE, this);
+  }
+}
+
+void WebviewRpcInstance::ProcessRequestOnWebviewThread(
+    std::unique_ptr<webview::WebviewRequest> request) {
+  webview_->ProcessRequest(*request.get());
+}
+
+void WebviewRpcInstance::InitComplete(bool ok) {
+  request_ = std::make_unique<webview::WebviewRequest>();
+  io_.Read(request_.get(), &read_callback_);
+
+  // Create a new instance to handle new requests.
+  // Instances of this class delete themselves.
+  new WebviewRpcInstance(service_, cq_, task_runner_);
+}
+
+void WebviewRpcInstance::ReadComplete(bool ok) {
+  if (!ok) {
+    io_.Finish(grpc::Status(), &destroy_callback_);
+  } else if (webview_) {
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&WebviewRpcInstance::ProcessRequestOnWebviewThread,
+                       base::Unretained(this),
+                       base::Passed(std::move(request_))));
+
+    request_ = std::make_unique<webview::WebviewRequest>();
+    io_.Read(request_.get(), &read_callback_);
+  } else if (!Initialize()) {
+    io_.Finish(grpc::Status(grpc::FAILED_PRECONDITION, "Failed initialization"),
+               &destroy_callback_);
+  }
+  // In this case initialization is pending and the main webview thread will
+  // start the first read.
+}
+
+bool WebviewRpcInstance::Initialize() {
+  if (request_->type_case() != webview::WebviewRequest::kCreate)
+    return false;
+
+  // This needs to be done on a valid thread.
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&WebviewRpcInstance::CreateWebview, base::Unretained(this),
+                     request_->create().webview_id(),
+                     request_->create().window_id()));
+  return true;
+}
+
+void WebviewRpcInstance::CreateWebview(int app_id, int window_id) {
+  auto* root_window =
+      exo::WMHelper::GetInstance()->GetRootWindowForNewWindows();
+  auto* surface_window = FindChildWindowWithID(root_window, app_id);
+  if (!surface_window) {
+    OnError("Failed to find valid surface to display webview on");
+    return;
+  }
+
+  content::BrowserContext* browser_context =
+      shell::CastBrowserProcess::GetInstance()->browser_context();
+  webview_ = std::make_unique<WebviewController>(browser_context, this);
+  webview_->AttachTo(surface_window, window_id);
+
+  // Begin reading again.
+  io_.Read(request_.get(), &read_callback_);
+}
+
+void WebviewRpcInstance::WriteComplete(bool ok) {
+  std::unique_lock<std::mutex> l(send_lock_);
+  send_pending_ = false;
+  if (destroying_) {
+    // It is possible for the read & finish to complete while a write is
+    // outstanding, in that case just re-call it to delete this instance.
+    FinishComplete(true);
+  } else if (errored_) {
+    io_.Finish(grpc::Status(grpc::UNKNOWN, error_message_), &destroy_callback_);
+  } else if (!pending_messages_.empty()) {
+    send_pending_ = true;
+    io_.Write(*pending_messages_.front().get(), write_options_,
+              &write_callback_);
+    pending_messages_.pop_front();
+  }
+}
+
+void WebviewRpcInstance::EnqueueSend(
+    std::unique_ptr<webview::WebviewResponse> response) {
+  std::unique_lock<std::mutex> l(send_lock_);
+  if (errored_ || destroying_)
+    return;
+  if (!send_pending_ && pending_messages_.empty()) {
+    send_pending_ = true;
+    io_.Write(*response.get(), write_options_, &write_callback_);
+  } else {
+    pending_messages_.emplace_back(std::move(response));
+  }
+}
+
+void WebviewRpcInstance::OnError(const std::string& error_message) {
+  std::unique_lock<std::mutex> l(send_lock_);
+  errored_ = true;
+  error_message_ = error_message;
+
+  if (!send_pending_)
+    io_.Finish(grpc::Status(grpc::UNKNOWN, error_message_), &destroy_callback_);
+  send_pending_ = true;
+}
+
+}  // namespace
+
+WebviewAsyncService::WebviewAsyncService(
+    scoped_refptr<base::SingleThreadTaskRunner> webview_task_runner)
+    : webview_task_runner_(std::move(webview_task_runner)) {}
+
+WebviewAsyncService::~WebviewAsyncService() {
+  if (server_) {
+    server_->Shutdown();
+    cq_->Shutdown();
+
+    base::PlatformThread::Join(rpc_thread_);
+  }
+}
+
+void WebviewAsyncService::StartWithSocket(const base::FilePath& socket_path) {
+  DCHECK(!server_.get());
+
+  grpc::ServerBuilder builder;
+  builder.AddListeningPort("unix:" + socket_path.value(),
+                           grpc::InsecureServerCredentials());
+  builder.RegisterService(&service_);
+  cq_ = builder.AddCompletionQueue();
+  server_ = builder.BuildAndStart();
+  base::PlatformThread::Create(0, this, &rpc_thread_);
+}
+
+void WebviewAsyncService::ThreadMain() {
+  base::PlatformThread::SetName("CastWebviewGrpcMessagePump");
+
+  void* tag;
+  bool ok;
+  // This self-deletes.
+  new WebviewRpcInstance(&service_, cq_.get(), webview_task_runner_);
+  // This thread is joined when this service is destroyed.
+  while (cq_->Next(&tag, &ok)) {
+    reinterpret_cast<GrpcCallback*>(tag)->Run(ok);
+  }
+}
+
+}  // namespace chromecast
diff --git a/chromecast/browser/webview/webview_grpc_service.h b/chromecast/browser/webview/webview_grpc_service.h
new file mode 100644
index 0000000..2b99784
--- /dev/null
+++ b/chromecast/browser/webview/webview_grpc_service.h
@@ -0,0 +1,43 @@
+// Copyright 2019 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 CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_GRPC_SERVICE_H_
+#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_GRPC_SERVICE_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chromecast/browser/webview/proto/webview.grpc.pb.h"
+#include "third_party/grpc/src/include/grpcpp/server.h"
+
+namespace chromecast {
+
+// This is a service that provides a GRPC interface to create and control
+// webviews. See the proto file for commands.
+class WebviewAsyncService : public base::PlatformThread::Delegate {
+ public:
+  explicit WebviewAsyncService(
+      scoped_refptr<base::SingleThreadTaskRunner> webview_task_runner);
+  ~WebviewAsyncService() override;
+
+  // Start the server listening on an address, eg "localhost:12345".
+  void StartWithSocket(const base::FilePath& socket_path);
+
+ private:
+  void ThreadMain() override;
+
+  base::PlatformThreadHandle rpc_thread_;
+  scoped_refptr<base::SingleThreadTaskRunner> webview_task_runner_;
+  std::unique_ptr<grpc::ServerCompletionQueue> cq_;
+  webview::WebviewService::AsyncService service_;
+  std::unique_ptr<grpc::Server> server_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebviewAsyncService);
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_GRPC_SERVICE_H_
diff --git a/chromecast/browser/webview/webview_layout_manager.cc b/chromecast/browser/webview/webview_layout_manager.cc
new file mode 100644
index 0000000..24d2319
--- /dev/null
+++ b/chromecast/browser/webview/webview_layout_manager.cc
@@ -0,0 +1,34 @@
+// Copyright 2019 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 "chromecast/browser/webview/webview_layout_manager.h"
+
+#include "ui/aura/window.h"
+
+namespace chromecast {
+
+WebviewLayoutManager::WebviewLayoutManager(aura::Window* web_contents_window)
+    : web_contents_window_(web_contents_window) {}
+
+WebviewLayoutManager::~WebviewLayoutManager() {}
+
+void WebviewLayoutManager::OnWindowResized() {
+  web_contents_window_->SetBounds(web_contents_window_->parent()->bounds());
+}
+
+void WebviewLayoutManager::OnWindowAddedToLayout(aura::Window* child) {}
+
+void WebviewLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {}
+
+void WebviewLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {}
+
+void WebviewLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
+                                                          bool visible) {}
+
+void WebviewLayoutManager::SetChildBounds(aura::Window* child,
+                                          const gfx::Rect& requested_bounds) {
+  SetChildBoundsDirect(child, requested_bounds);
+}
+
+}  // namespace chromecast
diff --git a/chromecast/browser/webview/webview_layout_manager.h b/chromecast/browser/webview/webview_layout_manager.h
new file mode 100644
index 0000000..6127b02
--- /dev/null
+++ b/chromecast/browser/webview/webview_layout_manager.h
@@ -0,0 +1,36 @@
+// Copyright 2019 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 CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_LAYOUT_MANAGER_H_
+#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_LAYOUT_MANAGER_H_
+
+#include "base/macros.h"
+#include "ui/aura/layout_manager.h"
+
+namespace chromecast {
+
+// Resizes the provided window to be the parent window's size.
+class WebviewLayoutManager : public aura::LayoutManager {
+ public:
+  explicit WebviewLayoutManager(aura::Window* web_contents_window);
+  ~WebviewLayoutManager() override;
+
+  void OnWindowResized() override;
+  void OnWindowAddedToLayout(aura::Window* child) override;
+  void OnWillRemoveWindowFromLayout(aura::Window* child) override;
+  void OnWindowRemovedFromLayout(aura::Window* child) override;
+  void OnChildWindowVisibilityChanged(aura::Window* child,
+                                      bool visible) override;
+  void SetChildBounds(aura::Window* child,
+                      const gfx::Rect& requested_bounds) override;
+
+ private:
+  aura::Window* web_contents_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebviewLayoutManager);
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_LAYOUT_MANAGER_H_
diff --git a/chromeos/constants/chromeos_switches.cc b/chromeos/constants/chromeos_switches.cc
index 519fa00..5bf95a70 100644
--- a/chromeos/constants/chromeos_switches.cc
+++ b/chromeos/constants/chromeos_switches.cc
@@ -53,18 +53,9 @@
 const base::Feature kAmbientModeFeature{"ChromeOSAmbientMode",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kShowLanguageToggleInDemoMode{
-    "ShowLanguageToggleInDemoMode", base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kShowPlayInDemoMode{"ShowPlayInDemoMode",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kShowSplashScreenInDemoMode{
-    "ShowSplashScreenInDemoMode", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kSupportCountryCustomizationInDemoMode{
-    "SupportCountryCustomizationInDemoMode", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Please keep the order of these switches synchronized with the header file
 // (i.e. in alphabetical order).
 
diff --git a/chromeos/constants/chromeos_switches.h b/chromeos/constants/chromeos_switches.h
index 624482bf..463c2fe8 100644
--- a/chromeos/constants/chromeos_switches.h
+++ b/chromeos/constants/chromeos_switches.h
@@ -208,23 +208,10 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kParentalControlsSettings;
 
-// Controls whether to show the system tray language toggle in Demo Mode.
-COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
-extern const base::Feature kShowLanguageToggleInDemoMode;
-
 // Controls whether to show the Play Store icon in Demo Mode.
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kShowPlayInDemoMode;
 
-// Controls whether to show a static splash screen instead of the user pods
-// before demo sessions log in.
-COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
-extern const base::Feature kShowSplashScreenInDemoMode;
-
-// Controls whether to support country-level customization in Demo Mode.
-COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
-extern const base::Feature kSupportCountryCustomizationInDemoMode;
-
 // Returns true if the system should wake in response to wifi traffic.
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool WakeOnWifiEnabled();
 
diff --git a/chromeos/dbus/services/service_provider_test_helper.cc b/chromeos/dbus/services/service_provider_test_helper.cc
index d740434..164664a5 100644
--- a/chromeos/dbus/services/service_provider_test_helper.cc
+++ b/chromeos/dbus/services/service_provider_test_helper.cc
@@ -35,6 +35,7 @@
     const std::string& interface_name,
     const std::string& exported_method_name,
     CrosDBusService::ServiceProviderInterface* service_provider) {
+  exported_method_name_ = exported_method_name;
   // Create a mock bus.
   dbus::Bus::Options options;
   options.bus_type = dbus::Bus::SYSTEM;
@@ -50,8 +51,9 @@
   // |mock_exported_object_|'s ExportMethod() will use
   // |MockExportedObject().
   EXPECT_CALL(*mock_exported_object_.get(),
-              ExportMethod(interface_name, exported_method_name, _, _))
-      .WillOnce(Invoke(this, &ServiceProviderTestHelper::MockExportMethod));
+              ExportMethod(interface_name, _, _, _))
+      .WillRepeatedly(
+          Invoke(this, &ServiceProviderTestHelper::MockExportMethod));
 
   // Create a mock object proxy, with which we call a method of
   // |mock_exported_object_|.
@@ -114,7 +116,9 @@
   // Tell the call back that the method is exported successfully.
   on_exported_callback.Run(interface_name, method_name, true);
   // Capture the callback, so we can run this at a later time.
-  method_callback_ = method_callback;
+  if (method_name == exported_method_name_) {
+    method_callback_ = method_callback;
+  }
 }
 
 std::unique_ptr<dbus::Response> ServiceProviderTestHelper::CallMethodAndBlock(
diff --git a/chromeos/dbus/services/service_provider_test_helper.h b/chromeos/dbus/services/service_provider_test_helper.h
index fc4e1e8..343f9df 100644
--- a/chromeos/dbus/services/service_provider_test_helper.h
+++ b/chromeos/dbus/services/service_provider_test_helper.h
@@ -95,6 +95,7 @@
   dbus::ExportedObject::MethodCallCallback method_callback_;
   dbus::ObjectProxy::SignalCallback on_signal_callback_;
   std::unique_ptr<base::MessageLoop> message_loop_;
+  std::string exported_method_name_;
 };
 
 }  // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_input_impl.cc b/chromeos/services/assistant/platform/audio_input_impl.cc
index 5546547..400878f 100644
--- a/chromeos/services/assistant/platform/audio_input_impl.cc
+++ b/chromeos/services/assistant/platform/audio_input_impl.cc
@@ -216,7 +216,7 @@
 
 // Runs on audio service thread.
 void AudioInputImpl::Capture(const media::AudioBus* audio_source,
-                             int audio_delay_milliseconds,
+                             base::TimeTicks audio_capture_time,
                              double volume,
                              bool key_pressed) {
   DCHECK_EQ(g_current_format.num_channels, audio_source->channels());
@@ -230,10 +230,8 @@
   int64_t time = 0;
   // Only provide accurate timestamp when eraser is enabled, otherwise it seems
   // break normal libassistant voice recognition.
-  if (features::IsAudioEraserEnabled()) {
-    time = base::TimeTicks::Now().since_origin().InMicroseconds() -
-           1000 * audio_delay_milliseconds;
-  }
+  if (features::IsAudioEraserEnabled())
+    time = audio_capture_time.since_origin().InMicroseconds();
   AudioInputBufferImpl input_buffer(buffer.data(), audio_source->frames());
   {
     base::AutoLock lock(lock_);
diff --git a/chromeos/services/assistant/platform/audio_input_impl.h b/chromeos/services/assistant/platform/audio_input_impl.h
index 1657a7f2..8c87f32 100644
--- a/chromeos/services/assistant/platform/audio_input_impl.h
+++ b/chromeos/services/assistant/platform/audio_input_impl.h
@@ -54,7 +54,7 @@
 
   // media::AudioCapturerSource::CaptureCallback overrides:
   void Capture(const media::AudioBus* audio_source,
-               int audio_delay_milliseconds,
+               base::TimeTicks audio_capture_time,
                double volume,
                bool key_pressed) override;
   void OnCaptureError(const std::string& message) override;
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 33f87c7..087d036 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -397,6 +397,7 @@
 
 repack("components_tests_pak") {
   sources = [
+    "$root_gen_dir/components/autofill/core/browser/autofill_address_rewriter_resources.pak",
     "$root_gen_dir/components/components_resources.pak",
     "$root_gen_dir/components/omnibox/resources/omnibox_resources_en-US.pak",
     "$root_gen_dir/components/strings/components_locale_settings_en-US.pak",
@@ -405,6 +406,7 @@
 
   output = "$root_out_dir/components_tests_resources.pak"
   deps = [
+    "//components/autofill/core/browser:autofill_address_rewriter_resources",
     "//components/omnibox/resources:omnibox_resources",
     "//components/resources",
     "//components/strings",
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc
index 0a12aaad..e3293d02 100644
--- a/components/arc/arc_features.cc
+++ b/components/arc/arc_features.cc
@@ -10,6 +10,11 @@
 const base::Feature kAvailableForChildAccountFeature{
     "ArcAvailableForChildAccount", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Controls whether ARC++ app runtime performance statistics collection is
+// enabled.
+const base::Feature kAppRuntimePerormanceStatistics{
+    "AppRuntimePerormanceStatistics", base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Controls ACTION_BOOT_COMPLETED broadcast for third party applications on ARC.
 // When disabled, third party apps will not receive this broadcast.
 const base::Feature kBootCompletedBroadcastFeature {
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h
index caf7edab..ea3a7987 100644
--- a/components/arc/arc_features.h
+++ b/components/arc/arc_features.h
@@ -13,6 +13,7 @@
 
 // Please keep alphabetized.
 extern const base::Feature kAvailableForChildAccountFeature;
+extern const base::Feature kAppRuntimePerormanceStatistics;
 extern const base::Feature kBootCompletedBroadcastFeature;
 extern const base::Feature kCleanArcDataOnRegularToChildTransitionFeature;
 extern const base::Feature kCustomTabsExperimentFeature;
diff --git a/components/arc/arc_util.cc b/components/arc/arc_util.cc
index ce030e00..bdd297a 100644
--- a/components/arc/arc_util.cc
+++ b/components/arc/arc_util.cc
@@ -179,6 +179,8 @@
 }
 
 int GetWindowTaskId(const aura::Window* window) {
+  if (!window)
+    return kNoTaskId;
   const std::string* arc_app_id = exo::GetShellApplicationId(window);
   if (!arc_app_id)
     return kNoTaskId;
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 9d3e4e6..82fe5c8d 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -6,6 +6,18 @@
 import("//build/config/jumbo.gni")
 import("//build/util/version.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
+import("//tools/grit/grit_rule.gni")
+
+grit("autofill_address_rewriter_resources") {
+  source = "autofill_address_rewriter_resources.grd"
+  outputs = [
+    "grit/autofill_address_rewriter_resources.h",
+    "grit/autofill_address_rewriter_resources_map.cc",
+    "grit/autofill_address_rewriter_resources_map.h",
+    "autofill_address_rewriter_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/components/autofill/core/browser"
+}
 
 jumbo_static_library("browser") {
   sources = [
@@ -16,7 +28,6 @@
     "address_normalizer_impl.h",
     "address_rewriter.cc",
     "address_rewriter.h",
-    "address_rewriter_rules.cc",
     "autocomplete_history_manager.cc",
     "autocomplete_history_manager.h",
     "autofill-inl.h",
@@ -327,6 +338,7 @@
     "//third_party/libaddressinput",
   ]
   deps = [
+    ":autofill_address_rewriter_resources",
     "proto:legacy_proto_bridge",
     "//base",
     "//base:i18n",
@@ -356,6 +368,7 @@
     "//third_party/icu",
     "//third_party/libphonenumber",
     "//third_party/re2",
+    "//third_party/zlib/google:compression_utils",
     "//ui/accessibility:accessibility",
     "//ui/base",
     "//ui/gfx",
@@ -448,6 +461,7 @@
   ]
 
   deps = [
+    ":autofill_address_rewriter_resources",
     "//base",
     "//base/test:test_support",
     "//components/autofill/core/browser",
@@ -617,6 +631,7 @@
   defines = [ "CHROME_VERSION_MAJOR=" + chrome_version_major ]
 
   deps = [
+    ":autofill_address_rewriter_resources",
     ":browser",
     ":test_support",
     ":unit_tests_bundle_data",
diff --git a/components/autofill/core/browser/address_rewrite_rules/AD.txt b/components/autofill/core/browser/address_rewrite_rules/AD.txt
new file mode 100644
index 0000000..10134e5
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/AD.txt
@@ -0,0 +1,25 @@
+\bparroquia\s+de\s+andorra\s+la\s+vella\b	07
+\bprincipal\s+de\s+andorra\b	07
+\bprincipat\s+de\s+andorra\b	07
+\bsant\s+julia\s+de\s+loria\b	06
+\bescaldes\s+engordany\b	08
+\bandorra\s+la\s+vella\b	07
+\bcarrer\s+del\b	
+\bla\s+massana\b	04
+\bsant\s+julia\b	06
+\bcarrer\s+de\b	
+\bandorra\b	07
+\bcanillo\b	02
+\bmassana\b	04
+\bencamp\b	03
+\bordino\b	05
+\bc\s+del\b	
+\bc\s+de\b	
+\bad\b	07
+\ban\b	07
+\bca\b	02
+\bee\b	08
+\ben\b	03
+\bjl\b	06
+\bma\b	04
+\bor\b	05
diff --git a/components/autofill/core/browser/address_rewrite_rules/AR.txt b/components/autofill/core/browser/address_rewrite_rules/AR.txt
new file mode 100644
index 0000000..0b8f948
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/AR.txt
@@ -0,0 +1,42 @@
+\btierra\s+del\s+fuego\s+antartida\s+e\s+islas\s+del\s+atlantico\s+sur\b	tierra del fuego
+\bciudad\s+autonoma\s+de\s+buenos\s+aires\b	caba
+\bla\s+ciudad\s+de\s+buenos\s+aires\b	caba
+\bcapital\s+federal\b	caba
+\bdiecinueve\b	19
+\bdiecisiete\b	17
+\bargentina\b	ar
+\bboulevard\b	bv
+\bdieciocho\b	18
+\bdieciseis\b	16
+\bavenida\b	av
+\bcatorce\b	14
+\bprimera\b	1a
+\bsegunda\b	2a
+\bseptima\b	7a
+\btercera\b	3a
+\bcuarta\b	4a
+\bcuatro\b	4
+\boctava\b	8a
+\bpasaje\b	pje
+\bquince\b	15
+\bquinta\b	5a
+\bveinte\b	20
+\bcinco\b	5
+\bnueve\b	9
+\bsexta\b	6a
+\bsiete\b	7
+\btrece\b	13
+\bdiez\b	10
+\bdoce\b	12
+\bocho\b	8
+\bonce\b	11
+\bseis\b	6
+\btres\b	3
+\bdel\b	
+\bdos\b	2
+\blas\b	
+\blos\b	
+\buno\b	1
+\bde\b	
+\bel\b	
+\ble\b	
diff --git a/components/autofill/core/browser/address_rewrite_rules/AU.txt b/components/autofill/core/browser/address_rewrite_rules/AU.txt
new file mode 100644
index 0000000..73e3eb3
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/AU.txt
@@ -0,0 +1,71 @@
+\baustralian\s+capital\s+territory\b	act
+\bjervis\s+bay\s+territory\b	jbt
+\bnorthern\s+territory\b	nt
+\bwestern\s+australia\b	wa
+\bnew\s+south\s+wales\b	nsw
+\bsouth\s+australia\b	sa
+\bqueensland\b	qld
+\baustralia\b	au
+\bboulevard\b	blvd
+\bcrescent\b	cres
+\btasmania\b	tas
+\bvictoria\b	vic
+\bhighway\b	hwy
+\bparkway\b	pkwy
+\ba\\.c\\.t\\.\b	act
+\bau\\-act\b	act
+\bau\\-jbt\b	jbt
+\bau\\-nsw\b	nsw
+\bau\\-qld\b	qld
+\bau\\-tas\b	tas
+\bau\\-vic\b	vic
+\bavenue\b	ave
+\bcommon\b	comm
+\bj\\.b\\.t\\.\b	jbt
+\bn\\.s\\.w\\.\b	nsw
+\bparade\b	pde
+\bstreet\b	st
+\ba\\.c\\.t\b	act
+\bau\\-nt\b	nt
+\bau\\-sa\b	sa
+\bau\\-wa\b	wa
+\bcourt\b	ct
+\bdrive\b	dr
+\beight\b	8
+\bj\\.b\\.t\b	jbt
+\bmount\b	mt
+\bn\\.s\\.w\b	nsw
+\bnorth\b	n
+\bplace\b	pl
+\bpoint\b	pt
+\bsaint\b	st
+\bseven\b	7
+\bsouth\b	s
+\bthree\b	3
+\beast\b	e
+\bfive\b	5
+\bfour\b	4
+\blane\b	ln
+\bn\\.t\\.\b	nt
+\bnine\b	9
+\broad\b	rd
+\bs\\.a\\.\b	sa
+\bw\\.a\\.\b	wa
+\bwest\b	w
+\baus\b	au
+\bmt\\.\b	mt
+\bn\\.t\b	nt
+\bnth\b	n
+\bone\b	1
+\bpt\\.\b	pt
+\bs\\.a\b	sa
+\bsix\b	6
+\bst\\.\b	st
+\bsth\b	s
+\bten\b	10
+\btwo\b	2
+\bw\\.a\b	wa
+\be\\.\b	e
+\bn\\.\b	n
+\bs\\.\b	s
+\bw\\.\b	w
diff --git a/components/autofill/core/browser/address_rewrite_rules/BE.txt b/components/autofill/core/browser/address_rewrite_rules/BE.txt
new file mode 100644
index 0000000..39bb586
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/BE.txt
@@ -0,0 +1,124 @@
+\barrondissement\s+administratif\s+de\b	
+\barrondissement\s+administratif\s+d\b	
+\bbrussels\s+hoofdstedelijk\s+gewest\b	brussel
+\bbrussel\s+hoofdstedelijk\s+gewest\b	brussel
+\bregion\s+de\s+bruxelles\s+capitale\b	brussel
+\bseptieme\s+division\s+francaise\b	7eme division frcse
+\bonze\s+lieve\s+heersebeestjes\b	onze lieve heersbeestjes
+\bregion\s+brussel\s+hauptstadt\b	brussel
+\balbert\s+en\s+marie\s+louise\b	a & m l
+\balbert\s+et\s+marie\s+louise\b	a & m l
+\bandree\s+payfa\s+fosseprez\b	a payfa fosseprez
+\bseptieme\s+d\s+i\s+francaise\b	7eme division frcse
+\bwereldtentoonstellings\b	wereldtentoonstelings
+\bberchem\s+sainte\s+agathe\b	st agatha berchem
+\bflandres\s+occidentales\b	westflandern
+\bsaint\s+josse\s+ten\s+noode\b	saint josse
+\bflandre\s+occidentales\b	westflandern
+\bflandres\s+occidentale\b	westflandern
+\bhenri\s+victor\s+wolvens\b	h v wolvens
+\bjoseph\s+van\s+boterdael\b	joseph van boterdae
+\bmarilyn\s+monroegaarde\b	marilyn monroe
+\bflandre\s+occidentale\b	westflandern
+\bflandres\s+orientales\b	ostflandern
+\bwoluwe\s+saint\s+pierre\b	st pieters woluwe
+\bbruxelles\s+capitale\b	brussel
+\bflandre\s+orientales\b	ostflandern
+\bflandres\s+orientale\b	ostflandern
+\bhendrik\s+conscience\b	henri conscience
+\bleonoardo\s+da\s+vinci\b	leonard de vinci
+\bwallonisch\s+brabant\b	waals brabant
+\bwallonische\s+region\b	wallonie
+\bbischoffsheimlaan\b	bischoffsheim
+\bbrouck\s+du\s+tilleul\b	brouck au tilleul
+\bflandre\s+orientale\b	ostflandern
+\bleonardo\s+da\s+vinci\b	leonard de vinci
+\barmand\s+scheitler\b	armand scheiter
+\bflamisch\s+brabant\b	vlaams brabant
+\bflamische\s+region\b	vlaams gewest
+\bhenri\s+wafelaerts\b	henri wafelaert
+\bpieter\s+hauwaerts\b	pierre hauwaerts
+\bregion\s+wallonien\b	wallonie
+\brennequin\s+sualem\b	renkin sualem
+\baugust\s+de\s+boeck\b	a de boeck
+\bbrabant\s+flamand\b	vlaams brabant
+\bbruxelles\s+ville\b	brussel
+\bflamisch\s+region\b	vlaams gewest
+\bgodefroid\s+kurth\b	godfroid kurth
+\boost\s+vlaanderen\b	ostflandern
+\bregion\s+flamande\b	vlaams gewest
+\bregion\s+wallonne\b	wallonie
+\bwest\s+vlaanderen\b	westflandern
+\barrondissement\b	
+\bbrabant\s+wallon\b	waals brabant
+\blimburg\s+strium\b	limburg stirum
+\bde\s+ribaucourt\b	ribaucourt
+\bmichel\s+angelo\b	michel ange
+\bpater\s+damiaan\b	pater damian
+\bprofondeville\b	profondville
+\bsint\s+lenaerts\b	sint lenaarts
+\bsualem\s+renkin\b	renkin sualem
+\bdendermondse\b	dendermonde
+\bminnezangers\b	menestrelen
+\bvooruitgangs\b	vooruitgang
+\bwaals\s+gewest\b	wallonie
+\bcortenbergh\b	cortenberg
+\bjette\s+jetse\b	jette
+\bl\s+urbanisme\b	i urbanisme
+\bprovince\s+de\b	
+\bprovince\s+du\b	
+\bpuits\s+no\s+iv\b	puits n4
+\bterhulpense\b	terhulpse
+\bhenegouwen\b	hainaut
+\blanguesdoc\b	languedoc
+\bluxembourg\b	luxemburg
+\bprovince\s+d\b	
+\bpuit\s+no\s+iv\b	puits n4
+\bvan\s+volxem\b	volxem
+\bantwerpen\b	anvers
+\bboulevard\b	bd
+\bbruxelles\b	brussel
+\bluitenant\b	liutenant
+\bwallonien\b	wallonie
+\bwestphael\b	wesphal
+\bbelgique\b	be
+\bbrussels\b	brussel
+\bchaussee\b	chee
+\bhennegau\b	hainaut
+\blimbourg\b	limburg
+\bsteenweg\b	stwg
+\bterrasse\b	tsse
+\bwestphal\b	wesphal
+\bavenues\b	av
+\bbelgien\b	be
+\bbelgium\b	be
+\bde\s+wand\b	wand
+\bimpasse\b	imp
+\bjettese\b	jetse
+\bluttich\b	luik
+\bprovinz\b	
+\bstrasse\b	str
+\ballees\b	all
+\bavenue\b	av
+\bbelgie\b	be
+\bcentre\b	ctre
+\bsainte\b	st
+\bsquare\b	sq
+\bstraat\b	str
+\ballee\b	all
+\bliege\b	luik
+\bnamur\b	namen
+\bpiein\b	pl
+\bplace\b	pl
+\bplatz\b	pl
+\bplein\b	pl
+\broute\b	rte
+\bsaint\b	st
+\bsankt\b	st
+\bthier\b	their
+\bsint\b	st
+\bdes\b	d
+\brue\b	r
+\bste\b	st
+\bde\b	d
+\bdu\b	d
diff --git a/components/autofill/core/browser/address_rewrite_rules/BR.txt b/components/autofill/core/browser/address_rewrite_rules/BR.txt
new file mode 100644
index 0000000..06de9fb
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/BR.txt
@@ -0,0 +1,135 @@
+\brio\s+grande\s+do\s+norte\b	rn
+\bmato\s+grosso\s+do\s+sul\b	ms
+\brio\s+grande\s+do\s+sul\b	rs
+\bdistrito\s+federal\b	df
+\bdecimo\s+primeiro\b	11
+\bdecimo\s+terceiro\b	13
+\bespirito\s+santo\b	es
+\brio\s+de\s+janeiro\b	rj
+\bsanta\s+catarina\b	sc
+\bvinte\s+e\s+quatro\b	24
+\bdecimo\s+oitavo\b	18
+\bdecimo\s+quarto\b	14
+\bdecimo\s+quinto\b	15
+\bdecimo\s+setimo\b	17
+\bvinte\s+e\s+cinco\b	25
+\bdecimo\s+sexto\b	16
+\bminas\s+gerais\b	mg
+\bvinte\s+e\s+dois\b	22
+\bvinte\s+e\s+nove\b	29
+\bvinte\s+e\s+oito\b	28
+\bvinte\s+e\s+seis\b	26
+\bvinte\s+e\s+sete\b	27
+\bvinte\s+e\s+tres\b	23
+\bdecimo\s+nono\b	19
+\bmato\s+grosso\b	mt
+\bcomandante\b	com
+\bgovernador\b	gov
+\bpernambuco\b	pe
+\bpresidente\b	pres
+\bvinte\s+e\s+um\b	21
+\bcinquenta\b	50
+\bdezesseis\b	16
+\bdezessete\b	17
+\bduodecimo\b	12
+\bprofessor\b	prof
+\brepublica\b	rep
+\bsao\s+paulo\b	sp
+\btocantins\b	to
+\bamazonas\b	am
+\bdezenove\b	19
+\bmaranhao\b	ma
+\bprimeiro\b	1
+\bprincesa\b	prsa
+\bquarenta\b	40
+\brondonia\b	ro
+\bsargento\b	sct
+\bsessenta\b	60
+\bterceiro\b	3
+\bvigesimo\b	20
+\balagoas\b	al
+\balameda\b	al
+\bavenida\b	av
+\bcatorze\b	14
+\bcoronel\b	cel
+\bdezoito\b	18
+\bestrada\b	estr
+\bnoventa\b	90
+\boitenta\b	80
+\bparaiba\b	pb
+\broraima\b	rr
+\bsegundo\b	2
+\bsenador\b	sen
+\bsergipe\b	se
+\bsetenta\b	70
+\bbrasil\b	b
+\bbrazil\b	b
+\bdecimo\b	x
+\bdoutor\b	dr
+\boitavo\b	8
+\bparana\b	pr
+\bprincs\b	prsa
+\bquarto\b	4
+\bquatro\b	4
+\bquinto\b	5
+\bquinze\b	15
+\bsetimo\b	7
+\btrinta\b	30
+\bamapa\b	ap
+\bbahia\b	ba
+\bbarao\b	b
+\bceara\b	ce
+\bcinco\b	5
+\bconde\b	cde
+\bduque\b	dq
+\bgoias\b	go
+\bnorte\b	n
+\boeste\b	w
+\bpadre\b	pe
+\bpiaui\b	pi
+\bsanta\b	sta
+\bsexto\b	6
+\btreze\b	13
+\bviela\b	ve
+\bvinte\b	20
+\bacre\b	ac
+\bbaia\b	ba
+\bdois\b	2
+\bdoze\b	12
+\beste\b	e
+\blote\b	lt
+\bnono\b	9
+\bnove\b	9
+\boito\b	8
+\bonze\b	11
+\bpara\b	pa
+\bsala\b	s
+\bseis\b	6
+\bsete\b	7
+\btres\b	3
+\bviii\b	8
+\bcem\b	100
+\bdas\b	
+\bdez\b	x
+\bdos\b	
+\biii\b	3
+\brua\b	r
+\bsan\b	s
+\bsgt\b	sct
+\bsul\b	s
+\bvii\b	7
+\b10\b	x
+\bbr\b	b
+\bda\b	
+\bde\b	
+\bdo\b	
+\bel\b	
+\bii\b	2
+\biv\b	4
+\bix\b	9
+\bsl\b	s
+\bum\b	1
+\bvi\b	6
+\bvl\b	ve
+\bi\b	1
+\bv\b	5
diff --git a/components/autofill/core/browser/address_rewrite_rules/CA.txt b/components/autofill/core/browser/address_rewrite_rules/CA.txt
new file mode 100644
index 0000000..0ab6a0d
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/CA.txt
@@ -0,0 +1,215 @@
+\bdsl\s+de\s+grand\s+sault\s+falls\s+grand\s+sault\s+grand\s+falls\b	grand falls
+\bsainte\s+catherine\s+de\s+la\s+jacques\s+cartier\b	ste catherine de la j cartier
+\bmadawaska\s+maliseet\s+frst\s+nation\b	madawaska
+\bregional\s+county\s+municipality\b	
+\bshediac\s+bridge\s+shediac\s+river\b	shediac bridge
+\bnewfoundland\s+and\s+labrador\b	nl
+\bterritoires\s+du\s+nord\s+ouest\b	nt
+\bdsl\s+de\s+grand\s+sault\s+falls\b	grand falls
+\bregional\s+municipality\s+of\b	
+\bgrand\s+sault\s+grand\s+falls\b	grand falls
+\bterre\s+neuve\s+et\s+labrador\b	nl
+\bbay\s+de\s+verde\s+peninsula\b	bvd
+\bile\s+du\s+prince\s+edouard\b	pe
+\bnorthwest\s+territories\b	nt
+\bregional\s+municipality\b	
+\bcolombie\s+britannique\b	bc
+\bprince\s+edward\s+island\b	pe
+\bregional\s+district\s+of\b	
+\bfrench\s+village\s+york\b	french village
+\bhead\s+of\s+bay\s+despoir\b	head bay d\'espoir
+\bterritoire\s+du\s+yukon\b	yt
+\bnouveau\s+brunswick\b	nb
+\bregional\s+district\b	
+\bbritish\s+columbia\b	bc
+\bcanton\s+stanstead\b	stanstead
+\bmd\s+of\s+bonnyville\b	bonnyville
+\bnouvelle\s+ecosse\b	ns
+\bst\s+george\s+brant\b	saint george
+\byukon\s+territory\b	yt
+\bchisholm\s+mills\b	chisholm
+\bsackville\s+road\b	sackville
+\bnational\s+park\b	
+\bnew\s+brunswick\b	nb
+\bplacentia\s+bay\b	pb
+\bbeaver\s+brook\b	beaverbrook
+\bmetropolitan\b	
+\bnewfoundland\b	nl
+\brichibouctou\b	richibucto
+\bsaskatchewan\b	sk
+\bfortune\s+bay\b	fb
+\bnova\s+scotia\b	ns
+\bsubdivision\b	subdiv
+\bsutton\s+west\b	sutton
+\bterre\s+neuve\b	nl
+\btownship\s+of\b	
+\btrinity\s+bay\b	tb
+\bbelliveaus\b	belliveau
+\bconcession\b	conc
+\bcul\s+de\s+sac\b	cds
+\bcul\\-de\\-sac\b	cds
+\bde\s+riviere\b	riviere
+\bexpressway\b	expy
+\bmackinnons\b	mckinnons
+\bnorth\s+side\b	northside
+\bpine\s+ridge\b	pineridge
+\brond\s+point\b	rdpt
+\brond\\-point\b	rdpt
+\balternate\b	alt
+\bautoroute\b	aut
+\bboulevard\b	blvd
+\bcarrefour\b	carref
+\bcounty\s+of\b	
+\bcroissant\b	crois
+\bdiversion\b	divers
+\bechangeur\b	ech
+\besplanade\b	espl
+\bextension\b	exten
+\bhalf\s+moon\b	halfmoon
+\bhighlands\b	hghlds
+\bkuskonook\b	kuskanook
+\bpromenade\b	prom
+\bturnabout\b	trnabt
+\bbusiness\b	bus
+\bcrescent\b	cres
+\bcrossing\b	cross
+\bjunction\b	
+\bmanitoba\b	mb
+\bmountain\b	mtn
+\boak\s+hill\b	oakhill
+\bpleasent\b	pleasant
+\bterrasse\b	tsse
+\btownline\b	tline
+\btownship\b	
+\balberta\b	ab
+\bby\s+pass\b	bypass
+\bcircuit\b	circt
+\bcity\s+of\b	
+\bcorners\b	crnrs
+\bestates\b	estate
+\bfreeway\b	fwy
+\bgardens\b	gdns
+\bgrounds\b	grnds
+\bharbour\b	harbr
+\bheights\b	hts
+\bherbert\b	hebert
+\bhighway\b	hwy
+\bimpasse\b	imp
+\bkeenans\b	keenan
+\bl\'islet\b	
+\bla\s+have\b	lahave
+\blanding\b	landng
+\blookout\b	lkout
+\bnarrows\b	
+\bnunavut\b	nu
+\bontario\b	on
+\borchard\b	orch
+\bparkway\b	pky
+\bpassage\b	pass
+\bpathway\b	ptway
+\bplateau\b	plat
+\breserve\b	
+\bsentier\b	sent
+\bstation\b	
+\bterrace\b	terr
+\bthicket\b	thick
+\btown\s+of\b	
+\bvillage\b	
+\bavenue\b	av
+\bbakers\b	baker
+\bcanada\b	ca
+\bcanton\b	
+\bcenter\b	
+\bcentre\b	
+\bchemin\b	ch
+\bcircle\b	cir
+\bcounty\b	
+\bharbor\b	harbr
+\bisland\b	
+\bl\'isle\b	isle
+\blimits\b	lmts
+\bmackay\b	mckay
+\bmcgrey\b	mcgray
+\bpointe\b	pte
+\bquebec\b	qc
+\bruelle\b	rle
+\bsainte\b	
+\bsiding\b	
+\bsmiths\b	smith
+\bsquare\b	sq
+\bstreet\b	
+\bvalley\b	
+\bcarre\b	car
+\bclose\b	cl
+\bcourt\b	crt
+\bdrive\b	dr
+\bfirst\b	fst
+\bforks\b	
+\bgrove\b	grv
+\bmanns\b	mann
+\bmetro\b	
+\bmount\b	mt
+\bnorth\b	n
+\bouest\b	o
+\bplace\b	pl
+\bpoint\b	pt
+\brange\b	rg
+\broute\b	rt
+\bsaint\b	
+\bsouth\b	s
+\btrail\b	trl
+\byukon\b	yt
+\bboul\b	blvd
+\bcity\b	
+\bcove\b	
+\beast\b	
+\bfrst\b	fst
+\blake\b	
+\blane\b	ln
+\bnord\b	n
+\bpark\b	
+\bpkwy\b	pky
+\broad\b	
+\bwest\b	o
+\bave\b	av
+\bbay\b	
+\bbdv\b	
+\bblp\b	
+\bcan\b	ca
+\bcbd\b	
+\bctr\b	
+\bdes\b	
+\bere\b	
+\best\b	
+\bile\b	
+\blab\b	
+\bndb\b	
+\bnth\b	n
+\bont\b	on
+\bpei\b	pe
+\brte\b	rt
+\bsal\b	
+\bsmb\b	
+\bste\b	
+\bsth\b	s
+\bsud\b	s
+\bbb\b	
+\bcb\b	
+\bco\b	
+\bd\'\b	
+\bde\b	
+\bdu\b	
+\ber\b	
+\bfn\b	
+\bgb\b	
+\bnd\b	
+\bpk\b	
+\brd\b	
+\bre\b	
+\bst\b	
+\bth\b	
+\bwb\b	
+\bc\b	
+\bd\b	
+\be\b	
+\bw\b	o
diff --git a/components/autofill/core/browser/address_rewrite_rules/CH.txt b/components/autofill/core/browser/address_rewrite_rules/CH.txt
new file mode 100644
index 0000000..31efd7b
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/CH.txt
@@ -0,0 +1,199 @@
+\bappenzell\s+rhodes\s+exterieures\b	ar
+\bappenzell\s+ausserrhoden\b	ar
+\bappenzell\s+innerrhoden\b	ai
+\bjura\s+north\s+vaudois\b	jura nord vaudois
+\bprettigovia\s+davos\b	davos
+\bbasel\s+landschaft\b	bl
+\bprattigau\s+davos\b	davos
+\bsankt\s+silvester\b	st silvester
+\bbale\s+campagne\b	bl
+\bbasilea\s+citta\b	bs
+\bsankt\s+stephan\b	st stephan
+\bwallis\s+valais\b	vs
+\bdix\s+huitieme\b	18
+\bdix\s+neuvieme\b	19
+\bdix\s+septieme\b	17
+\bsaint\s+gallen\b	sg
+\bsankt\s+gallen\b	sg
+\bschaffhausen\b	sh
+\bbasel\s+stadt\b	bs
+\bbelinzonese\b	bellinzona
+\bquatorzieme\b	14
+\bsaint\s+gallo\b	sg
+\bsan\s+nazzaro\b	s nazzaro
+\bsan\s+vittore\b	s vittore
+\bsankt\s+gallo\b	sg
+\bschaffhouse\b	sh
+\bswitzerland\b	ch
+\bwinterthour\b	winterthur
+\bbale\s+ville\b	bs
+\bbasel\s+city\b	bs
+\bbasel\s+land\b	bl
+\bbasel\s+stad\b	bs
+\bbazel\s+stad\b	bs
+\bbellinzone\b	bellinzona
+\benclave\s+de\b	
+\bgraubunden\b	gr
+\bsaint\s+gall\b	sg
+\bsan\s+gallen\b	sg
+\bsankt\s+gall\b	sg
+\bst\\.\s+gallen\b	sg
+\bvaud\s+waadt\b	vd
+\bwaadt\s+vaud\b	vd
+\bcinquieme\b	5
+\blaufental\b	laufen
+\bneuchatel\b	ne
+\bneuenburg\b	ne
+\bnidwalden\b	nw
+\bquatrieme\b	4
+\bquinzieme\b	15
+\bsan\s+gallo\b	sg
+\bsciaffusa\b	sh
+\bsolothurn\b	so
+\bst\s+gallen\b	sg
+\bst\\.\s+gallo\b	sg
+\bthurgovia\b	tg
+\bthurgovie\b	tg
+\btreizieme\b	13
+\btroisieme\b	3
+\bvingtieme\b	20
+\bd\\\\\'uster\b	uster
+\bdeuxieme\b	2
+\bdouzieme\b	12
+\bfreiburg\b	fr
+\bfribourg\b	fr
+\bfriburgo\b	fr
+\bgessenay\b	saanen
+\bgrigioni\b	gr
+\bhuitieme\b	8
+\bmaloggia\b	maloja
+\bneuvieme\b	9
+\bnidvaldo\b	nw
+\bobwalden\b	ow
+\bpremiere\b	1
+\bsan\s+gall\b	sg
+\bseizieme\b	16
+\bseptieme\b	7
+\bst\s+gallo\b	sg
+\bst\\.\s+gall\b	sg
+\bturgovia\b	tg
+\bzofingue\b	zofingen
+\bargovia\b	ag
+\bargovie\b	ag
+\bdixieme\b	x
+\bfriburg\b	fr
+\bginevra\b	ge
+\bglarona\b	gl
+\bgrisons\b	gr
+\blucerna\b	lu
+\blucerne\b	lu
+\bnidwald\b	nw
+\bobvaldo\b	ow
+\bonzieme\b	11
+\bschweiz\b	ch
+\bschwytz\b	sz
+\bsixieme\b	6
+\bsoletta\b	so
+\bsoleure\b	so
+\bst\s+gall\b	sg
+\bthurgau\b	tg
+\bturicum\b	zh
+\bvallais\b	vs
+\bvallese\b	vs
+\bzuerich\b	zh
+\baargau\b	ag
+\bbienna\b	biel
+\bbienne\b	biel
+\bbrigue\b	brig
+\bgeneva\b	ge
+\bgeneve\b	ge
+\bglaris\b	gl
+\bglarus\b	gl
+\blaufon\b	laufen
+\bluzern\b	lu
+\bobwald\b	ow
+\bregion\b	
+\bsainte\b	
+\bschwyz\b	sz
+\bsvitto\b	sz
+\btessin\b	ti
+\bthoune\b	thun
+\bticino\b	ti
+\bvalais\b	vs
+\bwallis\b	vs
+\bzurich\b	zh
+\bzurigo\b	zh
+\baaray\b	aarau
+\bberna\b	be
+\bberne\b	be
+\bbriga\b	brig
+\bde\s+l\'\b	
+\bde\s+la\b	
+\bet\s+du\b	
+\bgiura\b	ju
+\bmount\b	mt
+\bnorth\b	n
+\bouest\b	o
+\bsaint\b	
+\bsouth\b	s
+\bstadt\b	
+\bviege\b	visp
+\bwaadt\b	vd
+\bxviii\b	18
+\bbern\b	be
+\bgenf\b	ge
+\bieme\b	
+\bjura\b	ju
+\bnord\b	n
+\bstad\b	
+\bvaud\b	vd
+\bviii\b	8
+\bwest\b	o
+\bxiii\b	13
+\bxvii\b	17
+\bzoug\b	zg
+\bzugo\b	zg
+\bdes\b	
+\beme\b	
+\bere\b	
+\best\b	
+\biii\b	3
+\bles\b	
+\bmte\b	mt
+\bste\b	
+\bsud\b	s
+\bsur\b	
+\buri\b	ur
+\bvii\b	7
+\bxii\b	12
+\bxiv\b	14
+\bxix\b	19
+\bxvi\b	16
+\bzug\b	zg
+\b10\b	x
+\bd\'\b	
+\bde\b	
+\bdu\b	
+\ben\b	
+\ber\b	
+\bii\b	2
+\bin\b	
+\biv\b	4
+\bix\b	9
+\bl\'\b	
+\bla\b	
+\ble\b	
+\bnd\b	
+\bof\b	
+\brd\b	
+\bre\b	
+\bst\b	
+\bth\b	
+\bvi\b	6
+\bxi\b	11
+\bxv\b	15
+\bxx\b	20
+\be\b	
+\bi\b	1
+\bv\b	5
+\bw\b	o
diff --git a/components/autofill/core/browser/address_rewrite_rules/CL.txt b/components/autofill/core/browser/address_rewrite_rules/CL.txt
new file mode 100644
index 0000000..6cab67578
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/CL.txt
@@ -0,0 +1,32 @@
+\baisen\s+del\s+general\s+carlos\s+ibanez\s+del\s+campo\b	11
+\blibertador\s+general\s+bernardo\s+o\'higgins\b	6
+\bmetropolitana\s+de\s+santiago\s+de\s+chile\b	rm
+\bmagallanes\s+y\s+la\s+antartica\s+chilena\b	12
+\bmetropolitana\s+de\s+santiago\b	rm
+\barica\s+y\s+parinacota\b	15
+\bmetropolitana\b	rm
+\bla\s+araucania\b	9
+\bantofagasta\b	2
+\bvalparaiso\b	5
+\blos\s+lagos\b	x
+\bcoquimbo\b	4
+\blos\s+rios\b	14
+\btarapaca\b	1
+\batacama\b	3
+\bbio\s+bio\b	8
+\bchile\b	cl
+\bmaule\b	7
+\bviii\b	8
+\biii\b	3
+\bvii\b	7
+\bxii\b	12
+\bxiv\b	14
+\b10\b	x
+\bii\b	2
+\biv\b	4
+\bix\b	9
+\bvi\b	6
+\bxi\b	11
+\bxv\b	15
+\bi\b	1
+\bv\b	5
diff --git a/components/autofill/core/browser/address_rewrite_rules/CO.txt b/components/autofill/core/browser/address_rewrite_rules/CO.txt
new file mode 100644
index 0000000..bc1ca7b8
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/CO.txt
@@ -0,0 +1,2 @@
+\bcolombia\b	co
+\bcolumbia\b	co
diff --git a/components/autofill/core/browser/address_rewrite_rules/DE.txt b/components/autofill/core/browser/address_rewrite_rules/DE.txt
new file mode 100644
index 0000000..a24134c
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/DE.txt
@@ -0,0 +1,41 @@
+\bfederal\s+republic\s+of\s+germany\b	de
+\bbundesrepublik\s+deutschland\b	de
+\bfreie\s+hansestadt\s+bremen\b	hb
+\bmecklenburg\s+vorpommern\b	mv
+\bnorth\s+rhine\s+westphalia\b	nw
+\brhineland\s+palatinate\b	rp
+\bnordrhein\s+westfalen\b	nw
+\bschleswig\s+holstein\b	sh
+\bbaden\s+wurttemberg\b	bw
+\bregionalverband\b	
+\brheinland\s+pfalz\b	rp
+\bsachsen\s+anhalt\b	st
+\bniedersachsen\b	ni
+\bsaxony\s+anhalt\b	st
+\blower\s+saxony\b	ni
+\bstadtverband\b	
+\bbrandenburg\b	bb
+\bdeutschland\b	de
+\blandkreis\b	
+\bthuringen\b	th
+\bthuringia\b	th
+\bsaarland\b	sl
+\bbavaria\b	by
+\bcologne\b	koln
+\bgermany\b	de
+\bhamburg\b	hh
+\bsachsen\b	sn
+\bstrasse\b	str
+\bbayern\b	by
+\bberlin\b	be
+\bbremen\b	hb
+\bhessen\b	he
+\bsaxony\b	sn
+\bsudost\b	se
+\bhesse\b	he
+\bsankt\b	st
+\bstadt\b	
+\bnord\b	n
+\bwest\b	w
+\bost\b	o
+\bsud\b	s
diff --git a/components/autofill/core/browser/address_rewrite_rules/DK.txt b/components/autofill/core/browser/address_rewrite_rules/DK.txt
new file mode 100644
index 0000000..be4aef6
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/DK.txt
@@ -0,0 +1,29 @@
+\bgrabrodrestraede\b	grabrodrestr
+\barnold\s+nielsens\b	arn nielsens
+\bhaveforeningen\b	f
+\bhaveforening\b	f
+\bmunicipality\b	
+\bbispebjergs\b	bispebjerg
+\btengslemark\b	tengslemrk
+\bboulevard\b	boul
+\blillerod\b	allerod
+\bdanmark\b	dk
+\bdenmark\b	dk
+\bkommune\b	
+\bkvarter\b	kvater
+\bpladsen\b	plads
+\bboulev\b	boul
+\bgammel\b	gl
+\blokken\b	lokke
+\bnummer\b	nr
+\bsondre\b	s
+\bgamle\b	gl
+\bnorre\b	n
+\bsankt\b	sct
+\bnord\b	n
+\bvest\b	v
+\bndr\b	n
+\bost\b	o
+\bsdr\b	s
+\bskt\b	sct
+\bsyd\b	s
diff --git a/components/autofill/core/browser/address_rewrite_rules/ES.txt b/components/autofill/core/browser/address_rewrite_rules/ES.txt
new file mode 100644
index 0000000..a559a4c
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/ES.txt
@@ -0,0 +1,100 @@
+\bsanta\s+cruz\s+de\s+tenerife\b	tf
+\bbalearic\s+islands\b	pm
+\bislas\s+baleares\b	pm
+\billes\s+balears\b	pm
+\bciudad\s+real\b	cr
+\bguadalajara\b	gu
+\bla\s+corunna\b	c
+\bla\s+corunya\b	c
+\blas\s+palmas\b	gc
+\bpontevedra\b	po
+\bvalladolid\b	va
+\bbarcelona\b	b
+\bcantabria\b	s
+\bcastellon\b	cs
+\besplugues\b	esplugas
+\bguipuscoa\b	ss
+\bguipuzcoa\b	ss
+\bla\s+coruna\b	c
+\bsalamanca\b	sa
+\bsaragossa\b	z
+\btarragona\b	t
+\ba\s+coruna\b	c
+\balbacete\b	ab
+\balicante\b	
+\basturias\b	o
+\bcastello\b	cs
+\bgipuzkoa\b	ss
+\bla\s+rioja\b	lo
+\bnafarroa\b	na
+\bpalencia\b	p
+\bvalencia\b	v
+\bzaragoza\b	z
+\balacant\b	
+\balmeria\b	
+\bavenida\b	av
+\bbadajoz\b	ba
+\bbizkaia\b	bi
+\bcaceres\b	cc
+\bcordoba\b	co
+\bcordova\b	co
+\bgranada\b	gr
+\bnavarra\b	na
+\bnavarre\b	na
+\bourense\b	or
+\bsegovia\b	sg
+\bsevilla\b	se
+\bseville\b	se
+\bvizcaya\b	bi
+\bbiscay\b	bi
+\bburgos\b	bu
+\bcoruna\b	c
+\bcuenca\b	cu
+\bespana\b	es
+\bgerona\b	gi
+\bgirona\b	gi
+\bhuelva\b	h
+\bhuesca\b	hu
+\blerida\b	
+\blleida\b	
+\bmadrid\b	m
+\bmalaga\b	ma
+\bmurcia\b	mu
+\borense\b	or
+\bteruel\b	te
+\btoledo\b	to
+\bzamora\b	za
+\balava\b	vi
+\baraba\b	vi
+\bavila\b	av
+\bcadiz\b	ca
+\bnorte\b	n
+\bnorth\b	n
+\boeste\b	o
+\bsoria\b	so
+\bsouth\b	s
+\bspain\b	es
+\beast\b	e
+\beste\b	e
+\bjaen\b	j
+\bleon\b	le
+\blugo\b	lu
+\bwest\b	o
+\bc\\.\\/\b	c
+\bc\\/\\.\b	c
+\bdal\b	
+\bdel\b	
+\blas\b	
+\bles\b	
+\blos\b	
+\bsur\b	s
+\bal\b	
+\bc\\/\b	c
+\bde\b	
+\bel\b	
+\ben\b	
+\bla\b	
+\bof\b	
+\ba\b	
+\bd\b	
+\bl\b	
diff --git a/components/autofill/core/browser/address_rewrite_rules/FR.txt b/components/autofill/core/browser/address_rewrite_rules/FR.txt
new file mode 100644
index 0000000..efef68c9a
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/FR.txt
@@ -0,0 +1,220 @@
+\bprovence\s+alpes\s+cote\s+d\s+azur\b	u
+\balpes\s+de\s+haute\s+provence\b	04
+\barnouville\s+les\s+gonesse\b	arnouville
+\bterritoire\s+de\s+belfort\b	90
+\blanguedoc\s+roussillon\b	k
+\bpyrenees\s+atlantiques\b	64
+\bpyrenees\s+orientales\b	66
+\bmeurthe\s+et\s+moselle\b	54
+\bnord\s+pas\s+de\s+calais\b	o
+\bchampagne\s+ardenne\b	g
+\bcharente\s+maritime\b	17
+\bseine\s+saint\s+denis\b	93
+\bbouches\s+du\s+rhone\b	13
+\bloire\s+atlantique\b	44
+\bpays\s+de\s+la\s+loire\b	r
+\bpoitou\s+charentes\b	t
+\balpes\s+maritimes\b	06
+\bbasse\s+normandie\b	p
+\bhaute\s+normandie\b	q
+\bille\s+et\s+vilaine\b	35
+\btarn\s+et\s+garonne\b	82
+\bdepartementale\b	d
+\bhaute\s+pyrenees\b	65
+\bhauts\s+de\s+seine\b	92
+\bindre\s+et\s+loire\b	37
+\blot\s+et\s+garonne\b	47
+\blower\s+normandy\b	p
+\bmaine\s+et\s+loire\b	49
+\bsaone\s+et\s+loire\b	71
+\bseine\s+maritime\b	76
+\bupper\s+normandy\b	q
+\bcotes\s+d\s+armor\b	22
+\bdepartemental\b	d
+\bfranche\s+comte\b	1
+\bhaute\s+garonne\b	31
+\bile\s+de\s+france\b	j
+\bmidi\s+pyrenees\b	n
+\bpas\s+de\s+calais\b	62
+\bseine\s+et\s+mame\b	77
+\bcorse\s+du\s+sud\b	2a
+\bdix\s+huitieme\b	18
+\bdix\s+neuvieme\b	19
+\bdix\s+septieme\b	17
+\beure\s+et\s+loir\b	28
+\bhaute\s+savoie\b	74
+\bhaute\s+vienne\b	87
+\bloir\s+et\s+cher\b	41
+\bval\s+de\s+marne\b	94
+\bcouffouleux\b	coufouleux
+\bdeux\s+sevres\b	79
+\bhaute\s+alpes\b	05
+\bhaute\s+corse\b	2b
+\bhaute\s+loire\b	43
+\bhaute\s+marne\b	52
+\bhaute\s+saone\b	70
+\bpuy\s+de\s+dome\b	63
+\bquatorzieme\b	14
+\brhone\s+alpes\b	5
+\bacquitaine\b	b
+\benclave\s+de\b	
+\bval\s+d\s+oise\b	95
+\baquitaine\b	b
+\bboulevard\b	bd
+\bbourgogne\b	d
+\bcinquieme\b	5
+\bcote\s+d\s+or\b	21
+\bfinistere\b	29
+\bhaut\s+rhin\b	68
+\bmoribihan\b	56
+\bnationale\b	n
+\bquatrieme\b	4
+\bquinzieme\b	15
+\btreizieme\b	13
+\btroisieme\b	3
+\bvingtieme\b	20
+\ballemont\b	allemond
+\bardennes\b	08
+\bauvergne\b	c
+\baveryron\b	12
+\bbas\s+rhin\b	67
+\bbretagne\b	
+\bbrittany\b	
+\bburgundy\b	d
+\bcalvados\b	14
+\bcharente\b	16
+\bdeuxieme\b	2
+\bdordogne\b	24
+\bdouzieme\b	12
+\bhuitieme\b	8
+\bla\s+croix\b	lacroix
+\blimousin\b	l
+\blorraine\b	m
+\bneuvieme\b	9
+\bpicardie\b	s
+\bpremiere\b	1
+\bseizieme\b	16
+\bseptieme\b	7
+\bvaucluse\b	84
+\byvelines\b	78
+\bardeche\b	07
+\bcorreze\b	19
+\bcorsica\b	h
+\bdixieme\b	x
+\bessonne\b	91
+\bgironde\b	33
+\bherault\b	34
+\bmayenne\b	53
+\bmoselle\b	57
+\bonzieme\b	11
+\bpicardy\b	s
+\bsixieme\b	6
+\ballier\b	03
+\balsace\b	a
+\bariege\b	09
+\bavenue\b	ave
+\bcantal\b	15
+\bcentre\b	f
+\bcreuse\b	23
+\bfrance\b	fr
+\bgrande\b	gd
+\blandes\b	40
+\bloiret\b	45
+\blozere\b	48
+\bmanche\b	50
+\bnievre\b	58
+\bregion\b	
+\bsainte\b	
+\bsarthe\b	72
+\bsavoie\b	73
+\bvendee\b	85
+\bvienne\b	86
+\bvosges\b	88
+\baisne\b	02
+\bcorse\b	h
+\bde\s+l\'\b	
+\bde\s+la\b	
+\bdoubs\b	25
+\bdrome\b	26
+\bet\s+du\b	
+\bgrand\b	gd
+\bindre\b	36
+\bisere\b	38
+\bloire\b	42
+\bmarne\b	51
+\bmeuse\b	55
+\bmount\b	mt
+\bnorth\b	n
+\bouest\b	o
+\bparis\b	
+\brhone\b	69
+\bsaint\b	
+\bsomme\b	80
+\bsouth\b	s
+\bvilla\b	vil
+\bxviii\b	18
+\byonne\b	89
+\baude\b	11
+\bcher\b	18
+\beure\b	27
+\bgard\b	30
+\bgers\b	32
+\bieme\b	
+\bjura\b	39
+\bnord\b	n
+\boise\b	60
+\borne\b	61
+\btarn\b	81
+\bviii\b	8
+\bwest\b	o
+\bxiii\b	13
+\bxvii\b	17
+\bain\b	01
+\bdes\b	
+\beme\b	
+\bere\b	
+\best\b	
+\bgde\b	gd
+\biii\b	3
+\bles\b	
+\blot\b	46
+\bmte\b	mt
+\bste\b	
+\bsud\b	s
+\bsur\b	
+\bvar\b	83
+\bvii\b	7
+\bxii\b	12
+\bxiv\b	14
+\bxix\b	19
+\bxvi\b	16
+\b10\b	x
+\b59\b	n
+\b75\b	
+\bd\'\b	
+\bde\b	
+\bdu\b	
+\ben\b	
+\ber\b	
+\bgr\b	gd
+\bii\b	2
+\bin\b	
+\biv\b	4
+\bix\b	9
+\bl\'\b	
+\bla\b	
+\ble\b	
+\bnd\b	
+\bof\b	
+\brd\b	
+\bre\b	
+\bst\b	
+\bth\b	
+\bvi\b	6
+\bxi\b	11
+\bxv\b	15
+\bxx\b	20
+\be\b	
+\bi\b	1
+\bv\b	5
+\bw\b	o
diff --git a/components/autofill/core/browser/address_rewrite_rules/GB.txt b/components/autofill/core/browser/address_rewrite_rules/GB.txt
new file mode 100644
index 0000000..ddc51ba
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/GB.txt
@@ -0,0 +1,288 @@
+\bbath\s+and\s+north\s+east\s+somerset\b	gb-bas
+\bdungannon\s+and\s+south\s+tyrone\b	gb-dgn
+\bcheshire\s+west\s+and\s+chester\b	gb-chw
+\bnewry\s+and\s+mourne\s+district\b	gb-nym
+\beast\s+riding\s+of\s+yorkshire\b	gb-ery
+\bmetropolitan\s+borough\s+of\b	
+\bnorth\s+east\s+lincolnshire\b	gb-nel
+\bhammersmith\s+and\s+fulham\b	gb-hmf
+\bkensington\s+and\s+chelsea\b	gb-kec
+\bwindsor\s+and\s+maidenhead\b	gb-wnm
+\bblackburn\s+with\s+darwen\b	gb-bbd
+\bdumfries\s+and\s+galloway\b	gb-dgy
+\bsouth\s+gloucestershire\b	gb-sgc
+\bthe\s+vale\s+of\s+glamorgan\b	gb-vgl
+\bbarking\s+and\s+dagenham\b	gb-bdg
+\bcentral\s+bedfordshire\b	gb-cbf
+\bkingston\s+upon\s+thames\b	gb-ktt
+\bredcar\s+and\s+cleveland\b	gb-rcc
+\brhondda\\,\s+cynon\\,\s+taff\b	gb-rct
+\brichmond\s+upon\s+thames\b	gb-ric
+\bthe\s+scottish\s+borders\b	gb-scb
+\beast\s+dunbartonshire\b	gb-edu
+\bnewcastle\s+upon\s+tyne\b	gb-net
+\bwest\s+dunbartonshire\b	gb-wdu
+\bkingston\s+upon\s+hull\b	gb-khl
+\bliverpool\s+district\b	gb-liv
+\bnorth\s+lincolnshire\b	gb-nln
+\btelford\s+and\s+wrekin\b	gb-tfw
+\bbrighton\s+and\s+hove\b	gb-bnh
+\bcity\s+of\s+edinburgh\b	gb-edh
+\beast\s+renfrewshire\b	gb-erw
+\bkirklees\s+district\b	gb-kir
+\blondon\s+borough\s+of\b	
+\bneath\s+port\s+talbot\b	gb-ntl
+\bnorth\s+lanarkshire\b	gb-nlk
+\bperth\s+and\s+kinross\b	gb-pkn
+\bsouth\s+lanarkshire\b	gb-slk
+\bbracknell\s+forest\b	gb-brc
+\bclackmannanshire\b	gb-clk
+\bisle\s+of\s+anglesey\b	gb-agy
+\bnorthamptonshire\b	gb-nth
+\bnorthern\s+ireland\b	n.i.
+\bshetland\s+islands\b	gb-zet
+\bstockton\\-on\\-tees\b	gb-stt
+\bargyll\s+and\s+bute\b	gb-agb
+\bbuckinghamshire\b	gb-bkm
+\bcarmarthenshire\b	gb-cmn
+\bcity\s+of\s+bristol\b	gb-bst
+\bgloucestershire\b	gb-gls
+\bnorth\s+yorkshire\b	gb-nyk
+\bnottinghamshire\b	gb-ntt
+\bsefton\s+district\b	gb-sft
+\bsouthend\\-on\\-sea\b	gb-sos
+\bcambridgeshire\b	gb-cam
+\bcity\s+of\s+london\b	gb-lnd
+\bleeds\s+district\b	gb-lds
+\bleicestershire\b	gb-lec
+\bmerthyr\s+tydfil\b	gb-mty
+\bnorth\s+ayrshire\b	gb-nay
+\bnorth\s+somerset\b	gb-nsm
+\bnorth\s+tyneside\b	gb-nty
+\bnorthumberland\b	gb-nbl
+\borkney\s+islands\b	gb-ork
+\bsouth\s+ayrshire\b	gb-say
+\bsouth\s+tyneside\b	gb-sty
+\bstoke\\-on\\-trent\b	gb-ste
+\bwaltham\s+forest\b	gb-wft
+\bwest\s+berkshire\b	gb-wbk
+\bworcestershire\b	gb-wor
+\baberdeen\s+city\b	gb-abe
+\baberdeenshire\b	gb-abd
+\bblaenau\s+gwent\b	gb-bgw
+\bcarrickfergus\b	gb-ckf
+\bcheshire\s+east\b	gb-che
+\bcounty\s+durham\b	gb-dur
+\beast\s+ayrshire\b	gb-eay
+\bherefordshire\b	gb-hef
+\bhertfordshire\b	gb-hrt
+\bisle\s+of\s+wight\b	gb-iow
+\bmiddlesbrough\b	gb-mdb
+\bmilton\s+keynes\b	gb-mik
+\bmonmouthshire\b	gb-mon
+\bpembrokeshire\b	gb-pem
+\bstaffordshire\b	gb-sts
+\btower\s+hamlets\b	gb-twh
+\bwolverhampton\b	gb-wlv
+\bdenbighshire\b	gb-den
+\beast\s+lothian\b	gb-eln
+\bfulmodestone\b	fulmodeston
+\bglasgow\s+city\b	gb-glg
+\blincolnshire\b	gb-lin
+\bnewtownabbey\b	gb-nta
+\bpeterborough\b	gb-pte
+\brenfrewshire\b	gb-rfw
+\bwarwickshire\b	gb-war
+\bwest\s+lothian\b	gb-wln
+\bbournemouth\b	gb-bmh
+\bcastlereagh\b	gb-csr
+\bdundee\s+city\b	gb-dnd
+\bdunnamanagh\b	dunamanagh
+\beast\s+sussex\b	gb-esx
+\beilean\s+siar\b	gb-els
+\bking\'s\s+stag\b	king stag
+\bmagherafelt\b	gb-mft
+\boxfordshire\b	gb-oxf
+\bsouthampton\b	gb-sth
+\bwest\s+sussex\b	gb-wsx
+\bwestminster\b	gb-wsm
+\bballymoney\b	gb-bly
+\bbirmingham\b	gb-bir
+\bborough\s+of\b	
+\bcaerphilly\b	gb-cay
+\bcalderdale\b	gb-cld
+\bceredigion\b	gb-cgn
+\bculnacnock\b	culnacnoc
+\bdarlington\b	gb-dal
+\bderbyshire\b	gb-dby
+\bflintshire\b	gb-fln
+\bgroesllwyd\b	groes-lwyd
+\bhartlepool\b	gb-hpl
+\bhillingdon\b	gb-hil
+\binverclyde\b	gb-ivc
+\blancashire\b	gb-lan
+\bmanchester\b	gb-man
+\bmidlothian\b	gb-mln
+\bn\\.\s+ireland\b	n.i.
+\bnorth\s+down\b	gb-ndn
+\bnottingham\b	gb-ngm
+\bportsmouth\b	gb-por
+\bshropshire\b	gb-shr
+\bst\\.\s+helens\b	gb-shn
+\bsunderland\b	gb-snd
+\bwandsworth\b	gb-wnd
+\bwarrington\b	gb-wrt
+\bballymena\b	gb-bla
+\bbanbridge\b	gb-bnb
+\bblackpool\b	gb-bpl
+\bboulevard\b	blvd
+\bcoleraine\b	gb-clr
+\bcookstown\b	gb-ckt
+\bcraigavon\b	gb-cgv
+\bdoncaster\b	gb-dnc
+\bfermanagh\b	gb-fer
+\bgateshead\b	gb-gat
+\bgreenwich\b	gb-gre
+\bhampshire\b	gb-ham
+\bislington\b	gb-isl
+\bleicester\b	gb-lce
+\bn\s+ireland\b	n.i.
+\bn\\.ireland\b	n.i.
+\bredbridge\b	gb-rdb
+\brotherham\b	gb-rot
+\bsheffield\b	gb-shf
+\bsouthwark\b	gb-swk
+\bstockport\b	gb-skp
+\bwakefield\b	gb-wkf
+\bwiltshire\b	gb-wil
+\bwokingham\b	gb-wok
+\bbarnsley\b	gb-bns
+\bbradford\b	gb-brd
+\bbridgend\b	gb-bge
+\bcheshire\b	gb-chs
+\bcornwall\b	gb-con
+\bcoventry\b	gb-cov
+\bcrescent\b	cres
+\bdistrict\b	
+\bhare\s+law\b	harelaw
+\bharingey\b	gb-hry
+\bhavering\b	gb-hav
+\bhighland\b	gb-hld
+\bhounslow\b	gb-hns
+\bknowsley\b	gb-kwl
+\blewisham\b	gb-lew
+\blimavady\b	gb-lmv
+\bplymouth\b	gb-ply
+\brochdale\b	gb-rch
+\bsandwell\b	gb-saw
+\bscotland\b	gb-sct
+\bsolihull\b	gb-sol
+\bsomerset\b	gb-som
+\bstirling\b	gb-stg
+\bstrabane\b	gb-stb
+\btameside\b	gb-tam
+\bthurrock\b	gb-thr
+\btrafford\b	gb-trf
+\bbedford\b	gb-bdf
+\bbelfast\b	gb-bfs
+\bbritain\b	gb
+\bbromley\b	gb-bry
+\bcardiff\b	gb-crf
+\bcity\s+of\b	
+\bcroydon\b	gb-cry
+\bcumbria\b	gb-cma
+\benfield\b	gb-enf
+\bengland\b	eng
+\bfalkirk\b	gb-fal
+\bgwynedd\b	gb-gwn
+\bhackney\b	gb-hck
+\bhighway\b	hwy
+\bkingdom\b	gb
+\blambeth\b	gb-lbh
+\blisburn\b	gb-lsb
+\bnewport\b	gb-nwp
+\bnorfolk\b	gb-nfk
+\bparkway\b	pkwy
+\breading\b	gb-rdg
+\brutland\b	gb-rut
+\bsalford\b	gb-slf
+\bsuffolk\b	gb-sfk
+\bswansea\b	gb-swa
+\bswindon\b	gb-swd
+\btorfaen\b	gb-tof
+\bwalsall\b	gb-wll
+\bwrexham\b	gb-wrx
+\bavenue\b	ave
+\bcommon\b	comm
+\bgb\\-ans\b	angus
+\bgb\\-ant\b	antrim
+\bgb\\-ard\b	ards
+\bgb\\-arm\b	armagh
+\bgb\\-ben\b	brent
+\bgb\\-bex\b	bexley
+\bgb\\-bne\b	barnet
+\bgb\\-bol\b	bolton
+\bgb\\-bur\b	bury
+\bgb\\-cmd\b	camden
+\bgb\\-cwy\b	conwy
+\bgb\\-der\b	derby
+\bgb\\-dev\b	devon
+\bgb\\-dor\b	dorset
+\bgb\\-dow\b	down
+\bgb\\-dry\b	derry
+\bgb\\-dud\b	dudley
+\bgb\\-eal\b	ealing
+\bgb\\-eng\b	eng
+\bgb\\-ess\b	essex
+\bgb\\-fif\b	fife
+\bgb\\-ken\b	kent
+\bgb\\-lrn\b	larne
+\bgb\\-lut\b	luton
+\bgb\\-mry\b	moray
+\bgb\\-myl\b	moyle
+\bgb\\-nir\b	n.i.
+\bgb\\-omh\b	omagh
+\bgb\\-pol\b	poole
+\bgb\\-pow\b	powys
+\bgb\\-wgn\b	wigan
+\bgb\\-wls\b	wales
+\bgb\\-yor\b	york
+\bhalton\b	gb-hal
+\bharrow\b	gb-hrw
+\bmedway\b	gb-mdw
+\bmerton\b	gb-mrt
+\bnewham\b	gb-nwm
+\boldham\b	gb-old
+\bparade\b	pde
+\bslough\b	gb-slg
+\bstreet\b	st
+\bsurrey\b	gb-sry
+\bsutton\b	gb-stn
+\btorbay\b	gb-tob
+\bwirral\b	gb-wrl
+\bcourt\b	ct
+\bdrive\b	dr
+\bmount\b	mt
+\bnorth\b	n
+\bplace\b	pl
+\bpoint\b	pt
+\bsaint\b	st
+\bsouth\b	s
+\beast\b	e
+\bg\\.b\\.\b	gb
+\blane\b	ln
+\broad\b	rd
+\bu\\.k\\.\b	gb
+\bwest\b	w
+\bg\\.b\b	gb
+\bmt\\.\b	mt
+\bnth\b	n
+\bpt\\.\b	pt
+\bst\\.\b	st
+\bsth\b	s
+\bu\\.k\b	gb
+\be\\.\b	e
+\bn\\.\b	n
+\bs\\.\b	s
+\buk\b	gb
+\bw\\.\b	w
diff --git a/components/autofill/core/browser/address_rewrite_rules/GR.txt b/components/autofill/core/browser/address_rewrite_rules/GR.txt
new file mode 100644
index 0000000..1834192
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/GR.txt
@@ -0,0 +1,94 @@
+\banatoliki\s+makedonia\s+kai\s+thraki\b	a
+\baitolia\s+kai\s+akarnania\b	01
+\bkentriki\s+makedonia\b	b
+\bdytiki\s+makedonia\b	c
+\baitoloakarnania\b	01
+\bdytiki\s+ellada\b	g
+\bsterea\s+ellada\b	h
+\bvoreio\s+aigaio\b	k
+\bmetamorfossi\b	metamorfosi
+\bnotio\s+aigaio\b	l
+\bpeloponnisos\b	j
+\bthessaloniki\b	54
+\bdodekanisos\b	81
+\bionia\s+nisia\b	f
+\bkaissariani\b	kesariani
+\banatolikos\b	e
+\bchalkidiki\b	64
+\bkefallonia\b	23
+\bperifereia\b	periphery
+\bthesprotia\b	32
+\bagio\s+oros\b	69
+\bcholargos\b	holargos
+\bevrytania\b	05
+\bfthiotida\b	06
+\bkorinthia\b	15
+\bnomarchia\b	nomo
+\bthessalia\b	e
+\bzakynthos\b	21
+\bargolida\b	11
+\bchaidari\b	haidari
+\bchalkida\b	halkida
+\bioannina\b	33
+\birakleio\b	91
+\bkarditsa\b	41
+\bkastoria\b	56
+\bkifissia\b	kifisia
+\bkyklades\b	82
+\bmagnisia\b	43
+\bmaroussi\b	marousi
+\bmessinia\b	17
+\brethymni\b	93
+\brethymno\b	93
+\banatoli\b	e
+\barkadia\b	12
+\bdytikos\b	w
+\bflorina\b	63
+\bgrevena\b	51
+\bimathia\b	53
+\bipeiros\b	d
+\bkerkyra\b	22
+\blakonia\b	16
+\blasithi\b	92
+\blefkada\b	24
+\bpapagou\b	papagos
+\bpiraeus\b	pireas
+\bpreveza\b	34
+\btrikala\b	44
+\bvoiotia\b	03
+\bvoreioy\b	n
+\bachaia\b	13
+\battiki\b	i
+\bchania\b	94
+\bevvoia\b	04
+\bfokida\b	07
+\bkavala\b	55
+\bkilkis\b	57
+\bkozani\b	58
+\blarisa\b	42
+\blesvos\b	83
+\bnotioy\b	s
+\bpieria\b	61
+\brodopi\b	73
+\bserres\b	62
+\bvoreio\b	n
+\bxanthi\b	72
+\bchios\b	85
+\bdrama\b	52
+\bevros\b	71
+\bhania\b	94
+\bileia\b	14
+\bkriti\b	m
+\bnorth\b	n
+\bnotio\b	s
+\bpella\b	59
+\bsamos\b	84
+\bsouth\b	s
+\barta\b	31
+\bdysi\b	w
+\beast\b	e
+\bhios\b	85
+\bkato\b	s
+\bwest\b	w
+\ba\s+1\b	i
+\bano\b	n
diff --git a/components/autofill/core/browser/address_rewrite_rules/HK.txt b/components/autofill/core/browser/address_rewrite_rules/HK.txt
new file mode 100644
index 0000000..426d7d0
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/HK.txt
@@ -0,0 +1,50 @@
+\bboulevard\b	blvd
+\bhong\s+kong\b	hk
+\bcrescent\b	cres
+\bdistrict\b	
+\bhongkong\b	hk
+\bjunction\b	jct
+\bcentral\b	c
+\bhighway\b	hwy
+\bparkway\b	pkwy
+\bseventh\b	7
+\bavenue\b	ave
+\bbypass\b	pass
+\bcentre\b	center
+\bcommon\b	comm
+\beighth\b	8
+\bfourth\b	4
+\bparade\b	pde
+\bsecond\b	2
+\bstreet\b	st
+\bcourt\b	ct
+\bdrive\b	dr
+\beight\b	8
+\bfifth\b	5
+\bfirst\b	1
+\bmount\b	mt
+\bninth\b	9
+\bnorth\b	n
+\bplace\b	pl
+\bpoint\b	pt
+\bsaint\b	st
+\bseven\b	7
+\bsixth\b	6
+\bsouth\b	s
+\btenth\b	10
+\bthird\b	3
+\bthree\b	3
+\beast\b	e
+\bfive\b	5
+\bfour\b	4
+\blane\b	ln
+\bnine\b	9
+\broad\b	rd
+\bwest\b	w
+\bh\s+k\b	hk
+\bnth\b	n
+\bone\b	1
+\bsix\b	6
+\bsth\b	s
+\bten\b	10
+\btwo\b	2
diff --git a/components/autofill/core/browser/address_rewrite_rules/ID.txt b/components/autofill/core/browser/address_rewrite_rules/ID.txt
new file mode 100644
index 0000000..97210462
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/ID.txt
@@ -0,0 +1,70 @@
+\bspecial\s+region\s+of\s+yogyakarta\b	yo
+\bnanggroe\s+aceh\s+darussalam\b	ac
+\bbangka\s+belitung\s+islands\b	bb
+\bnaggroe\s+aceh\s+darussalam\b	ac
+\bspecial\s+region\s+of\s+papua\b	pa
+\bspecial\s+region\s+of\s+aceh\b	ac
+\bcentral\s+kalimantan\b	kt
+\bsoutheast\s+sulawesi\b	sg
+\bcentral\s+sulawesi\b	st
+\bbangka\s+belitung\b	bb
+\bjakarta\s+pusat\b	jk
+\bjakarta\s+utara\b	jk
+\bcentral\s+java\b	jt
+\briau\s+islands\b	kr
+\bdki\s+jakarta\b	jk
+\bjawa\s+tengah\b	jt
+\byogyakarta\b	yo
+\bgorontalo\b	go
+\bindonesia\b	id
+\bbengkulu\b	be
+\bnational\b	nasional
+\bjakarta\b	jk
+\blampung\b	la
+\bselatan\b	s
+\bbanten\b	bt
+\bmaluku\b	ma
+\bnumber\b	#
+\bbarat\b	w
+\bblock\b	blk
+\bjalan\b	jl
+\bjambi\b	ja
+\bnorth\b	n
+\bpapua\b	pa
+\bsouth\b	s
+\btimur\b	e
+\butara\b	n
+\bxviii\b	18
+\baceh\b	ac
+\bbali\b	ba
+\bblk\\.\b	blk
+\bblok\b	blk
+\beast\b	e
+\bjln\\.\b	jl
+\briau\b	ri
+\broad\b	rd
+\bviii\b	8
+\bwest\b	w
+\bxiii\b	13
+\bxvii\b	17
+\biii\b	3
+\bjl\\.\b	jl
+\bjln\b	jl
+\bno\\.\b	#
+\bnum\b	#
+\bvii\b	7
+\bxii\b	12
+\bxiv\b	14
+\bxix\b	19
+\bxvi\b	16
+\b10\b	x
+\bii\b	2
+\biv\b	4
+\bix\b	9
+\bno\b	#
+\bvi\b	6
+\bxi\b	11
+\bxv\b	15
+\bxx\b	20
+\bi\b	1
+\bv\b	5
diff --git a/components/autofill/core/browser/address_rewrite_rules/IE.txt b/components/autofill/core/browser/address_rewrite_rules/IE.txt
new file mode 100644
index 0000000..3f8a51b
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/IE.txt
@@ -0,0 +1,50 @@
+\broscommon\b	rn
+\btipperary\b	ta
+\bwaterford\b	wd
+\bwestmeath\b	wh
+\bkilkenny\b	kk
+\blimerick\b	lk
+\blongford\b	ld
+\bmonaghan\b	mn
+\bdonegal\b	dl
+\bireland\b	ie
+\bkildare\b	ke
+\bleitrim\b	lm
+\bterrace\b	tce
+\bwexford\b	wx
+\bwicklow\b	ww
+\bavenue\b	ave
+\bcarlow\b	cw
+\bcenter\b	cntr
+\bcounty\b	ck
+\bdublin\b	d
+\bgalway\b	g
+\blaoise\b	ls
+\boffaly\b	oy
+\bstreet\b	st
+\bcavan\b	cn
+\bclare\b	ce
+\bcourt\b	ct
+\bdrive\b	dr
+\bkerry\b	ky
+\blaois\b	ls
+\blouth\b	lh
+\bmeath\b	mh
+\bnorth\b	n
+\bplace\b	pl
+\bsaint\b	st
+\bsligo\b	so
+\bsouth\b	s
+\bcork\b	ck
+\beast\b	e
+\blane\b	ln
+\bmayo\b	mo
+\broad\b	rd
+\bwalk\b	wk
+\bwest\b	w
+\byard\b	yd
+\bway\b	wy
+\bco\b	ck
+\bdn\b	d
+\bgy\b	g
+\bty\b	ta
diff --git a/components/autofill/core/browser/address_rewrite_rules/IN.txt b/components/autofill/core/browser/address_rewrite_rules/IN.txt
new file mode 100644
index 0000000..17e913d4
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/IN.txt
@@ -0,0 +1,129 @@
+\bthiruvananthapuram\b	tvpm
+\bazimabad\s+kusumpur\b	patna
+\bjammu\s+and\s+kashmir\b	j&k
+\btiruvananthapuram\b	tvpm
+\bchandigarh\s+city\b	ch
+\bjammu\s+\\&\s+kashmir\b	j&k
+\bgovt\s+of\s+india\b	goi
+\binternational\b	intl
+\bvisakhapatnam\b	vskp
+\bchickmagalur\b	chicmagalur
+\bchikmagaluru\b	chicmagalur
+\bchikmagalur\b	chicmagalur
+\bcross\\-roads\b	xrd
+\bpataliputra\b	patna
+\branga\s+reddy\b	rangareddi
+\bchandigarh\b	ch
+\bcross\\-road\b	xrd
+\bcrossroads\b	xrd
+\bgovernment\b	goi
+\bpatliputra\b	patna
+\buniversity\b	uni
+\bvijayawada\b	bza
+\bahmedabad\b	ahd
+\bbangalore\b	blr
+\bbengaluru\b	blr
+\bchar\\-rast\b	chaurah
+\bchaurasta\b	chaurah
+\bchourasta\b	chaurah
+\bcrossroad\b	xrd
+\bhyderabad\b	hyd
+\bi\\.n\\.d\\.i\\.a\b	in
+\bvijaywada\b	bza
+\bcalcutta\b	kol
+\bchourast\b	chaurah
+\bchowrast\b	chaurah
+\bcrossing\b	xrd
+\bcrossrds\b	xrd
+\bjunction\b	jn.
+\bkolkatta\b	kol
+\bvaranasi\b	banaras
+\bamdavad\b	ahd
+\bbenaras\b	banaras
+\bchennai\b	che
+\bcollege\b	clg
+\bcrossrd\b	xrd
+\bgateway\b	gtwy
+\bheights\b	hts
+\bkeralam\b	kl
+\bkolkata\b	kol
+\bkolkota\b	kol
+\bseventh\b	7
+\bvruttha\b	cir.
+\bx\s+roads\b	xrd
+\bbombay\b	bom
+\bcenter\b	cen
+\bcentre\b	cen
+\bchowdi\b	chok
+\bcircle\b	cir.
+\beighth\b	8
+\bforest\b	frst
+\bfourth\b	4
+\bgarden\b	gdn
+\bgatewy\b	gtwy
+\bgatway\b	gtwy
+\bheight\b	hts
+\bkavala\b	jn.
+\bkerala\b	kl
+\bmadras\b	che
+\bmumbai\b	bom
+\bnumber\b	#
+\braasta\b	rasta
+\bsecond\b	2
+\bstreet\b	st
+\bx\s+road\b	xrd
+\bxroads\b	xrd
+\bcentr\b	cen
+\bchauk\b	chok
+\bchouk\b	chok
+\bchowk\b	chok
+\bcnter\b	cen
+\bdelhi\b	del
+\bfifth\b	5
+\bfirst\b	1
+\bgalli\b	gali
+\bgardn\b	gdn
+\bgrden\b	gdn
+\bgtway\b	gtwy
+\bindia\b	in
+\bj\s+\\&\s+k\b	j&k
+\bmukku\b	jn.
+\bnaaka\b	jn.
+\bninth\b	9
+\bnorth\b	n
+\bpally\b	palli
+\bround\b	cir.
+\broute\b	rt
+\bsixth\b	6
+\bsouth\b	s
+\btenth\b	10
+\bthird\b	3
+\bvizag\b	vskp
+\bxroad\b	xrd
+\bcent\b	cen
+\bcntr\b	cen
+\beast\b	e
+\bgarh\b	gad
+\bgrdn\b	gdn
+\bhght\b	hts
+\bhgts\b	hts
+\bj\s+\\&k\b	j&k
+\bjct\\.\b	jn.
+\bjnct\b	jn.
+\bpeth\b	pet
+\brnd\\.\b	cir.
+\broad\b	rd
+\bstr\\.\b	st
+\buniv\b	uni
+\bwest\b	w
+\bx\\-rd\b	xrd
+\bxrds\b	xrd
+\bcha\b	ch
+\bctr\b	cen
+\bmum\b	bom
+\bno\\.\b	#
+\bnum\b	#
+\brte\b	rt
+\bst\\.\b	st
+\bstr\b	st
+\bno\b	#
diff --git a/components/autofill/core/browser/address_rewrite_rules/IT.txt b/components/autofill/core/browser/address_rewrite_rules/IT.txt
new file mode 100644
index 0000000..1c9b4149
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/IT.txt
@@ -0,0 +1,291 @@
+\bbarletta\s+andria\s+trani\b	bt
+\bfriuli\s+venezia\s+giulia\b	36
+\bverbano\s+cusio\s+ossola\b	vb
+\btrentino\s+alto\s+adige\b	32
+\bstrada\s+provinciale\b	sp
+\bcarbonia\s+iglesias\b	ci
+\btrentino\s+sudtirol\b	32
+\bstrada\s+regionale\b	sr
+\bventiquattresimo\b	24
+\bdiciassettesimo\b	17
+\bmedio\s+campidano\b	vs
+\bmonza\s+e\s+brianza\b	mb
+\bpesaro\s+e\s+urbino\b	pu
+\bquattordicesimo\b	14
+\breggio\s+calabria\b	rc
+\bstrada\s+comunale\b	sc
+\bventicinquesimo\b	25
+\bdiciannovesimo\b	19
+\bemilia\s+romagna\b	45
+\bstrada\s+statali\b	ss
+\bvallee\s+d\s+aoste\b	23
+\bventisettesimo\b	27
+\bascoli\s+piceno\b	ap
+\bcaltanissetta\b	cl
+\bmassa\s+carrara\b	ms
+\breggio\s+emilia\b	re
+\bvalle\s+d\s+aosta\b	23
+\bventinovesimo\b	29
+\bventitreesimo\b	23
+\bvibo\s+valentia\b	vv
+\bdiciottesimo\b	18
+\bforli\s+cesena\b	fc
+\bolbia\s+tempio\b	ot
+\bquindicesimo\b	15
+\bventiduesimo\b	22
+\bventiquattro\b	24
+\bventottesimo\b	28
+\balessandria\b	
+\bdiciassette\b	17
+\bquattordici\b	14
+\btredicesimo\b	13
+\bvalle\s+aosta\b	23
+\bventicinque\b	25
+\bventisesimo\b	26
+\bventunesimo\b	21
+\bbasilicata\b	77
+\bcampobasso\b	cb
+\bdiciannove\b	19
+\bdodicesimo\b	12
+\breggimento\b	rgt
+\bsedicesimo\b	16
+\btrentesimo\b	30
+\bundicesimo\b	11
+\bventisette\b	27
+\bagrigento\b	ag
+\bbenevento\b	bn
+\bcatanzaro\b	cz
+\bfrosinone\b	fr
+\bla\s+spezia\b	sp
+\blombardia\b	25
+\bogliastra\b	og
+\bpordenone\b	pn
+\bventesimo\b	20
+\bventinove\b	29
+\bavellino\b	av
+\bbrindisi\b	br
+\bcagliari\b	ca
+\bcalabria\b	78
+\bcampania\b	72
+\bdiciotto\b	18
+\bgrosseto\b	gr
+\bl\s+aquila\b	aq
+\bmacerata\b	mc
+\boristano\b	or
+\bpiacenza\b	pc
+\bpiemonte\b	21
+\bquindici\b	15
+\bsardegna\b	88
+\bsiracusa\b	sr
+\btraversa\b	trav
+\bventidue\b	22
+\bventisei\b	26
+\bventitre\b	23
+\bventotto\b	28
+\bvercelli\b	vc
+\babruzzo\b	65
+\bbelluno\b	bl
+\bbergamo\b	bg
+\bbologna\b	bo
+\bbolzano\b	bz
+\bbrescia\b	bs
+\bcaserta\b	ce
+\bcatania\b	ct
+\bcosenza\b	cs
+\bcremona\b	cr
+\bcrotone\b	kr
+\bferrara\b	fe
+\bfirenze\b	fi
+\bgorizia\b	go
+\bimperia\b	im
+\bisernia\b	is
+\bliguria\b	42
+\blivorno\b	li
+\bmantova\b	mn
+\bmessina\b	me
+\bpalermo\b	pa
+\bperugia\b	pg
+\bpescara\b	pe
+\bpistoia\b	pt
+\bpotenza\b	pz
+\bquattro\b	4
+\bravenna\b	ra
+\bsalerno\b	sa
+\bsassari\b	ss
+\bsecondo\b	2
+\bsettimo\b	7
+\bsicilia\b	82
+\bsondrio\b	so
+\btaranto\b	ta
+\btoscana\b	52
+\btrapani\b	tp
+\btredici\b	13
+\btreviso\b	tv
+\btrieste\b	ts
+\bvenezia\b	ve
+\bventuno\b	21
+\bvicenza\b	6
+\bviterbo\b	vt
+\bancona\b	an
+\barezzo\b	ar
+\bbiella\b	bi
+\bchieti\b	ch
+\bcinque\b	5
+\bdecimo\b	x
+\bdodici\b	12
+\bfoggia\b	fg
+\bgenova\b	ge
+\bitalia\b	it
+\blatina\b	lt
+\bmarche\b	57
+\bmatera\b	mt
+\bmilano\b	mi
+\bmodena\b	mo
+\bmolise\b	67
+\bnapoli\b	na
+\bnovara\b	no
+\bottavo\b	8
+\bpadova\b	pd
+\bpuglia\b	75
+\bquarto\b	4
+\bquinto\b	5
+\bragusa\b	rg
+\brimini\b	rn
+\brovigo\b	ro
+\bsavona\b	sv
+\bsedici\b	16
+\bteramo\b	te
+\btorino\b	to
+\btrenta\b	30
+\btrento\b	tn
+\bumbria\b	55
+\bundici\b	11
+\bvarese\b	va
+\bveneto\b	34
+\bverona\b	vr
+\bxxviii\b	28
+\baosta\b	ao
+\baoste\b	ao
+\bbozen\b	bz
+\bcuneo\b	cn
+\bdagli\b	
+\bdalla\b	
+\bdalle\b	
+\bdallo\b	
+\bdegli\b	
+\bdella\b	
+\bdelle\b	
+\bdello\b	
+\bdieci\b	x
+\bfermo\b	fm
+\bitaly\b	it
+\blazio\b	62
+\blecce\b	
+\blecco\b	lc
+\blucca\b	lu
+\bnegli\b	
+\bnella\b	
+\bnelle\b	
+\bnello\b	
+\bnorth\b	n
+\bnuoro\b	nu
+\bovest\b	o
+\bparma\b	pr
+\bpavia\b	pv
+\bprato\b	po
+\bprimo\b	
+\brieti\b	ri
+\bsesto\b	6
+\bsette\b	7
+\bsiena\b	si
+\bsouth\b	s
+\bsugli\b	
+\bsulla\b	
+\bsulle\b	
+\bsullo\b	
+\bterni\b	tr
+\bterzo\b	3
+\budine\b	ud
+\bventi\b	20
+\bxviii\b	18
+\bxxiii\b	23
+\bxxvii\b	27
+\bagli\b	
+\balla\b	
+\balle\b	
+\ballo\b	
+\basti\b	at
+\bbari\b	ba
+\bcomo\b	co
+\bdall\b	
+\bdell\b	
+\beast\b	e
+\benna\b	
+\blodi\b	
+\bnell\b	
+\bnono\b	9
+\bnord\b	n
+\bnove\b	9
+\botto\b	8
+\bpisa\b	pi
+\broma\b	rm
+\bsull\b	
+\bviii\b	8
+\bwest\b	o
+\bxiii\b	13
+\bxvii\b	17
+\bxxii\b	22
+\bxxiv\b	24
+\bxxix\b	29
+\bxxvi\b	26
+\ball\b	
+\bdai\b	
+\bdal\b	
+\bdei\b	
+\bdel\b	
+\bdue\b	2
+\best\b	e
+\bgli\b	
+\biii\b	3
+\bles\b	
+\bnei\b	
+\bnel\b	
+\bsei\b	6
+\bsud\b	s
+\bsui\b	
+\bsul\b	
+\btre\b	3
+\buno\b	
+\bvii\b	7
+\bxii\b	12
+\bxiv\b	14
+\bxix\b	19
+\bxvi\b	16
+\bxxi\b	21
+\bxxv\b	25
+\bxxx\b	30
+\b10\b	x
+\bai\b	
+\bal\b	
+\bda\b	
+\bdi\b	
+\ben\b	
+\bii\b	2
+\bil\b	
+\bin\b	
+\biv\b	4
+\bix\b	9
+\bla\b	
+\ble\b	
+\blo\b	
+\bsu\b	
+\bvi\b	6
+\bxi\b	11
+\bxv\b	15
+\bxx\b	20
+\ba\b	
+\bd\b	
+\bi\b	
+\bl\b	
+\bv\b	5
+\bw\b	o
diff --git a/components/autofill/core/browser/address_rewrite_rules/LU.txt b/components/autofill/core/browser/address_rewrite_rules/LU.txt
new file mode 100644
index 0000000..0da792f
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/LU.txt
@@ -0,0 +1,47 @@
+\berpeldange\s+\\-\s+lez\s+\\-\s+bous\b	erpeldange
+\bhostert\s+niederanven\b	hostert
+\bgoebelsmuehle\b	goebelsmuhle
+\bbuederscheid\b	buderscheid
+\bschwebsingen\b	schwebsange
+\brammeldange\b	rameldange
+\bcul\s+de\s+sac\b	cds
+\bcul\\-de\\-sac\b	cds
+\bgeyershaff\b	geyershof
+\blexembourg\b	lu
+\bluxembourg\b	lu
+\brond\\-point\b	rdpt
+\bboulevard\b	boul
+\bcarrefour\b	carref
+\bcroissant\b	crois
+\bdiversion\b	divers
+\bechangeur\b	ech
+\besplanade\b	esp
+\bluxemburg\b	lu
+\bpromenade\b	prom
+\bcapellen\b	cap
+\bterrasse\b	tsse
+\bcircuit\b	circt
+\bimpasse\b	imp
+\bplateau\b	plat
+\bsentier\b	sent
+\bstrasse\b	str
+\bavenue\b	av
+\bcenter\b	c
+\bcentre\b	c
+\bchemin\b	ch
+\bpointe\b	pte
+\bruelle\b	rle
+\bcarre\b	car
+\bcourt\b	crt
+\bdrive\b	dr
+\bpoint\b	pt
+\broute\b	rte
+\bespl\b	esp
+\bave\b	av
+\bctr\b	c
+\bdes\b	
+\blux\b	lu
+\brue\b	r
+\bde\b	
+\bdu\b	
+\bd\b	
diff --git a/components/autofill/core/browser/address_rewrite_rules/MX.txt b/components/autofill/core/browser/address_rewrite_rules/MX.txt
new file mode 100644
index 0000000..a5ac3b1e
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/MX.txt
@@ -0,0 +1,82 @@
+\bcoahuila\s+de\s+zaragoza\b	coahuila
+\bbaja\s+california\s+sur\b	b c s
+\bestado\s+de\s+mexico\b	me
+\bbaja\s+california\b	b c
+\baguascalientes\b	ag
+\bveracruz\s+llave\b	veracruz
+\bprolongacion\b	prol
+\bquintana\s+roo\b	qr
+\bdiecinueve\b	19
+\bdiecisiete\b	17
+\bgobernador\b	gob
+\bguanajuato\b	gt
+\blicenciado\b	lic
+\bpresbitero\b	pbro
+\bsan\s+isidro\b	s isidro
+\bseptiembre\b	sept
+\bdieciocho\b	18
+\bdieciseis\b	16
+\bfrancisco\b	fco
+\bingeniero\b	ing
+\brepublica\b	rep
+\barticulo\b	art
+\bguerrero\b	gr
+\bhacienda\b	hda
+\bponiente\b	pte
+\bprofesor\b	prof
+\bsan\s+juan\b	s juan
+\bavenida\b	av
+\bcaptain\b	cap
+\bcatorce\b	14
+\bfebrero\b	feb
+\bgeneral\b	gral
+\bhidalgo\b	hg
+\bjalisco\b	ja
+\boriente\b	ote
+\bprimera\b	1a
+\bprivada\b	priv
+\bsegunda\b	2a
+\bseptima\b	7a
+\bsinaloa\b	si
+\btercera\b	3a
+\bciudad\b	cd
+\bcuarta\b	4a
+\bcuatro\b	4
+\bdoctor\b	dr
+\bmexico\b	me
+\bmx\s+mex\b	me
+\boaxaca\b	oa
+\boctava\b	8a
+\bpuebla\b	pu
+\bpuerto\b	pto
+\bquince\b	15
+\bquinta\b	5a
+\bveinte\b	20
+\bcinco\b	5
+\bmaria\b	ma
+\bnorte\b	nte
+\bnueve\b	9
+\boeste\b	pte
+\bq\s+roo\b	qr
+\bsanta\b	sta
+\bsexta\b	6a
+\bsiete\b	7
+\btrece\b	13
+\bdiez\b	10
+\bdoce\b	12
+\beste\b	ote
+\bocho\b	8
+\bonce\b	11
+\bseis\b	6
+\btres\b	3
+\bags\b	ag
+\bdel\b	
+\bdos\b	2
+\blas\b	
+\blos\b	
+\bq\s+r\b	qr
+\buno\b	1
+\bde\b	
+\bel\b	
+\ble\b	
+\bmx\b	me
diff --git a/components/autofill/core/browser/address_rewrite_rules/MY.txt b/components/autofill/core/browser/address_rewrite_rules/MY.txt
new file mode 100644
index 0000000..28b88ea
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/MY.txt
@@ -0,0 +1 @@
+\bmalaysia\b	my
diff --git a/components/autofill/core/browser/address_rewrite_rules/NL.txt b/components/autofill/core/browser/address_rewrite_rules/NL.txt
new file mode 100644
index 0000000..b367fcf
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/NL.txt
@@ -0,0 +1,74 @@
+\bwesterhaar\s+vriezenveensewijk\b	westerhaar-vriezenv wijk
+\bnoord\s+brabant\b	nb
+\bnoord\s+holland\b	nh
+\bnoord\\-brabant\b	nb
+\bnoord\\-holland\b	nh
+\balphen\s+chaam\b	ac
+\bburgemeester\b	burg
+\bnoordbrabant\b	nb
+\bs\s+gravenhage\b	sgravenhage
+\bzuid\s+holland\b	zh
+\bzuid\\-holland\b	zh
+\bmonseigneur\b	mgr
+\bnetherlands\b	nl
+\bnordholland\b	nh
+\bzuidholland\b	zh
+\bgelderland\b	ge
+\bnoordzijde\b	nz
+\boverijssel\b	ov
+\bflevoland\b	fl
+\bfriesland\b	fr
+\bgroningen\b	gn
+\bnederland\b	nl
+\boostzijde\b	oz
+\bprofessor\b	prof
+\brotterdam\b	rt
+\bwestzijde\b	wz
+\bzuidzijde\b	zz
+\baan\s+den\b	ad
+\bachtste\b	8
+\bdominee\b	ds
+\bdrenthe\b	dr
+\blimburg\b	l
+\bmeester\b	mr
+\bnegende\b	9
+\butrecht\b	u
+\bzeeland\b	z
+\bzevende\b	7
+\baan\s+de\b	ad
+\bdoctor\b	dr
+\beerste\b	1
+\bstraat\b	str
+\btweede\b	2
+\bvierde\b	4
+\bvijfde\b	5
+\bderde\b	3
+\bnl\\-dr\b	dr
+\bnl\\-fl\b	fl
+\bnl\\-fr\b	fr
+\bnl\\-ge\b	ge
+\bnl\\-gr\b	gn
+\bnl\\-li\b	l
+\bnl\\-nb\b	nb
+\bnl\\-nh\b	nh
+\bnl\\-ov\b	ov
+\bnl\\-ut\b	u
+\bnl\\-ze\b	z
+\bnl\\-zh\b	zh
+\bzesde\b	6
+\bsint\b	st
+\ba\s+d\b	ad
+\bgld\b	ge
+\bn\s+z\b	nz
+\bo\s+z\b	oz
+\bw\s+z\b	wz
+\bz\s+z\b	zz
+\bzld\b	z
+\bgl\b	ge
+\bgr\b	gn
+\blb\b	l
+\bli\b	l
+\but\b	u
+\bze\b	z
+\bzl\b	z
+\b\\#\b	
diff --git a/components/autofill/core/browser/address_rewrite_rules/NZ.txt b/components/autofill/core/browser/address_rewrite_rules/NZ.txt
new file mode 100644
index 0000000..eff70c9
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/NZ.txt
@@ -0,0 +1,37 @@
+\brural\s+delivery\b	
+\bocean\s+beach\b	oceanbeach
+\blong\s+beach\b	longbeach
+\bboulevard\b	blvd
+\bcrescent\b	cres
+\bheights\b	hts
+\bhighway\b	hwy
+\bparkway\b	pkwy
+\bzealand\b	nz
+\bavenue\b	ave
+\bcommon\b	comm
+\bparade\b	pde
+\bstreet\b	st
+\bcourt\b	ct
+\bdrive\b	dr
+\bmount\b	mt
+\bnorth\b	n
+\bplace\b	pl
+\bpoint\b	pt
+\bsaint\b	st
+\bsouth\b	s
+\beast\b	e
+\blane\b	ln
+\bn\\.z\\.\b	nz
+\broad\b	rd
+\bwest\b	w
+\bmt\\.\b	mt
+\bn\\.z\b	nz
+\bnth\b	n
+\bpt\\.\b	pt
+\bst\\.\b	st
+\bsth\b	s
+\be\\.\b	e
+\bn\\.\b	n
+\bs\\.\b	s
+\bw\\.\b	w
+\bd\b	
diff --git a/components/autofill/core/browser/address_rewrite_rules/PE.txt b/components/autofill/core/browser/address_rewrite_rules/PE.txt
new file mode 100644
index 0000000..4aafd6e
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/PE.txt
@@ -0,0 +1,8 @@
+\bavenida\b	av
+\bperu\b	pe
+\bdel\b	
+\blas\b	
+\blos\b	
+\bde\b	
+\bel\b	
+\ble\b	
diff --git a/components/autofill/core/browser/address_rewrite_rules/PH.txt b/components/autofill/core/browser/address_rewrite_rules/PH.txt
new file mode 100644
index 0000000..d884de2
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/PH.txt
@@ -0,0 +1,18 @@
+\bphilippines\b	ph
+\bboulevard\b	blvd
+\bextension\b	ext
+\bbarangay\b	
+\bcaptain\b	cap
+\bgeneral\b	gen
+\bavenue\b	av
+\bdoctor\b	dr
+\bstreet\b	st
+\bnorth\b	n
+\bsouth\b	s
+\bbrgy\b	
+\beast\b	e
+\bextn\b	ext
+\broad\b	rd
+\bwest\b	w
+\bave\b	av
+\bbgy\b	
diff --git a/components/autofill/core/browser/address_rewrite_rules/PL.txt b/components/autofill/core/browser/address_rewrite_rules/PL.txt
new file mode 100644
index 0000000..e02474c7
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/PL.txt
@@ -0,0 +1,43 @@
+\bkuyavian\s+pomeranian\b	kp
+\bzachodniopomorskie\b	zp
+\bwarmian\s+masurian\b	wn
+\bwest\s+pomeranian\b	zp
+\bgreater\s+poland\b	wp
+\blower\s+silesian\b	ds
+\bswietokrzyskie\b	sk
+\blesser\s+poland\b	mp
+\bsubcarpathian\b	pk
+\bwielkopolskie\b	wp
+\bdolnoslaskie\b	ds
+\bpodkarpackie\b	pk
+\bmalopolskie\b	mp
+\bmazowieckie\b	ma
+\bpomeranian\b	pm
+\blubelskie\b	lu
+\bmarszalek\b	marsz
+\bpodlaskie\b	pd
+\bpomorskie\b	pm
+\bwarminsko\b	wn
+\bkujawsko\b	kp
+\blubuskie\b	lb
+\bmasovian\b	ma
+\bopolskie\b	op
+\bpoludnie\b	south
+\bsilesian\b	sl
+\bwschodni\b	w
+\bzachodni\b	z
+\blodzkie\b	ld
+\bosiedle\b	os
+\bsilesia\b	sl
+\bslaskie\b	sl
+\blublin\b	lu
+\blubusz\b	lb
+\bpoland\b	pl
+\bpolnoc\b	north
+\bwschod\b	w
+\bzachod\b	z
+\bopole\b	op
+\beast\b	w
+\blodz\b	ld
+\bwest\b	z
+\bwlkp\b	wp
diff --git a/components/autofill/core/browser/address_rewrite_rules/PR.txt b/components/autofill/core/browser/address_rewrite_rules/PR.txt
new file mode 100644
index 0000000..ef229ff4
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/PR.txt
@@ -0,0 +1,30 @@
+\bsan\s+juan\s+antiguo\b	old san juan
+\bpuerto\s+rico\b	pr
+\bcarretera\b	carr
+\bmal\s+paso\b	malpaso
+\bavenida\b	av
+\bbulevar\b	blvd
+\bcamino\b	cm
+\bcalle\b	cll
+\bcourt\b	ct
+\bnorth\b	n
+\bpaseo\b	pso
+\bplaza\b	plz
+\bsaint\b	st
+\bsouth\b	s
+\bave\\.\b	av
+\beast\b	e
+\blane\b	ln
+\bp\\.r\\.\b	pr
+\broad\b	rd
+\bwest\b	w
+\bave\b	av
+\bcam\b	cm
+\bnth\b	n
+\bp\\.r\b	pr
+\bst\\.\b	st
+\bsth\b	s
+\be\\.\b	e
+\bn\\.\b	n
+\bs\\.\b	s
+\bw\\.\b	w
diff --git a/components/autofill/core/browser/address_rewrite_rules/PT.txt b/components/autofill/core/browser/address_rewrite_rules/PT.txt
new file mode 100644
index 0000000..342bb8e
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/PT.txt
@@ -0,0 +1,34 @@
+\bestrada\s+nacional\b	n
+\bviana\s+do\s+castelo\b	18
+\bcastelo\s+branco\b	09
+\bportalegre\b	08
+\bvila\s+real\b	15
+\bbraganca\b	14
+\bportugal\b	pt
+\bsantarem\b	03
+\bcoimbra\b	11
+\bsetubal\b	04
+\baveiro\b	12
+\bdoctor\b	dr
+\bdoutor\b	dr
+\bguarda\b	10
+\bleiria\b	02
+\blisbon\b	01
+\bbraga\b	17
+\bevora\b	07
+\bnorth\b	n
+\bporto\b	16
+\bsouth\b	s
+\bviseu\b	13
+\bbeja\b	05
+\bfaro\b	06
+\bwest\b	w
+\bdas\b	
+\bdos\b	
+\bsao\b	s
+\bda\b	
+\bde\b	
+\bdo\b	
+\bem\b	m
+\ben\b	n
+\be\b	
diff --git a/components/autofill/core/browser/address_rewrite_rules/README.md b/components/autofill/core/browser/address_rewrite_rules/README.md
new file mode 100644
index 0000000..77f2fbc
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/README.md
@@ -0,0 +1 @@
+The .txt files in this directory are generated. Update instructions for Googlers available at: [go/address_rewrite_rules](https://goto.google.com/address_rewrite_rules).
\ No newline at end of file
diff --git a/components/autofill/core/browser/address_rewrite_rules/RO.txt b/components/autofill/core/browser/address_rewrite_rules/RO.txt
new file mode 100644
index 0000000..0ab3bbf4
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/RO.txt
@@ -0,0 +1 @@
+\bromania\b	ro
diff --git a/components/autofill/core/browser/address_rewrite_rules/RU.txt b/components/autofill/core/browser/address_rewrite_rules/RU.txt
new file mode 100644
index 0000000..a4baa50
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/RU.txt
@@ -0,0 +1,21 @@
+\bавтодорога\b	а/д
+\bнабережная\b	наб
+\bтерритория\b	тер
+\bпереулок\b	пер
+\bпроспект\b	пр
+\bбульвар\b	б-р
+\bквартал\b	кв-л
+\bплощадь\b	пл
+\brussia\b	ru
+\bдорога\b	дор
+\bпроезд\b	пр-д
+\bроссия\b	ru
+\bбульв\b	б-р
+\bлиния\b	лин
+\bпр\\-кт\b	пр
+\bпросп\b	пр
+\bтупик\b	туп
+\bулица\b	ул
+\bшоссе\b	ш
+\bпрот\b	пр
+\bбул\b	б-р
diff --git a/components/autofill/core/browser/address_rewrite_rules/SE.txt b/components/autofill/core/browser/address_rewrite_rules/SE.txt
new file mode 100644
index 0000000..cf8d276
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/SE.txt
@@ -0,0 +1,45 @@
+\bvastra\s+goetalands\b	o
+\bvastra\s+goetaland\b	o
+\boestergoetlands\b	e
+\bvasternorrlands\b	y
+\boestergoetland\b	e
+\bvastergoetland\b	e
+\bvasternorrland\b	y
+\bsodermanlands\b	d
+\bvasterbottens\b	ac
+\bjoenkoepings\b	f
+\bsodermanland\b	d
+\bvasterbotten\b	ac
+\bvastmanlands\b	u
+\bjoenkoeping\b	f
+\bnorrbottens\b	bd
+\bvastmanland\b	u
+\bgavleborgs\b	x
+\bkronobergs\b	g
+\bnorrbotten\b	bd
+\bstockholms\b	ab
+\bgavleborg\b	x
+\bjamtlands\b	z
+\bkronoberg\b	g
+\bstockholm\b	ab
+\bvarmlands\b	s
+\bblekinge\b	k
+\bdalarnas\b	w
+\bgotlands\b	i
+\bhallands\b	n
+\bjamtland\b	z
+\boerebros\b	t
+\bvarmland\b	s
+\bdalarna\b	w
+\bgotland\b	i
+\bhalland\b	n
+\boerebro\b	t
+\bsverige\b	se
+\buppsala\b	c
+\bkalmar\b	h
+\bsoeder\b	s
+\bsweden\b	se
+\bskane\b	m
+\bnorr\b	n
+\boest\b	o
+\bvast\b	v
diff --git a/components/autofill/core/browser/address_rewrite_rules/TH.txt b/components/autofill/core/browser/address_rewrite_rules/TH.txt
new file mode 100644
index 0000000..146b1d9
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/TH.txt
@@ -0,0 +1,2 @@
+\bประเทศไทย\b	th
+\bthailand\b	th
diff --git a/components/autofill/core/browser/address_rewrite_rules/TR.txt b/components/autofill/core/browser/address_rewrite_rules/TR.txt
new file mode 100644
index 0000000..82c9238
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/TR.txt
@@ -0,0 +1,2 @@
+\bturkiye\b	tr
+\bturkey\b	tr
diff --git a/components/autofill/core/browser/address_rewrite_rules/US.txt b/components/autofill/core/browser/address_rewrite_rules/US.txt
new file mode 100644
index 0000000..791e127
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/US.txt
@@ -0,0 +1,699 @@
+\bjoint\s+base\s+elmendorf\s+richardson\b	jber
+\bwashington\s+district\s+of\s+columbia\b	dc
+\bfederated\s+states\s+of\s+micronesia\b	fm
+\bjoint\s+base\s+pearl\s+harbor\s+hickam\b	jbphh
+\bnational\s+forest\s+development\b	nat for dev
+\bmartin\s+luther\s+king\s+junior\b	mlk
+\barmed\s+forces\s+middle\s+east\b	ae
+\bmarine\s+corps\s+base\s+hawaii\b	mcbh kanehoe bay
+\bnational\s+for\s+development\b	nat for dev
+\bnorthern\s+mariana\s+islands\b	mp
+\bunited\s+states\s+of\s+america\b	us
+\bmartin\s+luther\s+king\s+jnr\b	mlk
+\bnat\s+forest\s+development\b	nat for dev
+\barmed\s+forces\s+americas\b	aa
+\bmartin\s+luther\s+king\s+jr\b	mlk
+\barmed\s+forces\s+pacific\b	ap
+\bdistrict\s+of\s+columbia\b	dc
+\barmed\s+forces\s+africa\b	ae
+\barmed\s+forces\s+canada\b	ae
+\barmed\s+forces\s+europe\b	ae
+\bnat\s+for\s+development\b	nat for dev
+\bnational\s+forest\s+dev\b	nat for dev
+\bjoint\s+reserve\s+base\b	jrb
+\blincolns\s+new\s+salem\b	lincoln nw sl
+\bmartin\s+luther\s+king\b	mlk
+\bmetropolitan\s+area\b	
+\bnational\s+monument\b	national mo
+\bcolorado\s+springs\b	co spgs
+\bdist\s+of\s+columbia\b	dc
+\bfrancis\s+e\s+warren\b	fe warren
+\bmarshall\s+islands\b	mh
+\bnational\s+for\s+dev\b	nat for dev
+\bwashington\s+state\b	wa
+\bcharlottesville\b	charlottesvle
+\badministration\b	admn
+\bair\s+force\s+base\b	afb
+\bamerican\s+samoa\b	as
+\bbradford\s+woods\b	bradfordwoods
+\bchristiansberg\b	christiansbrg
+\bcrawfordsville\b	crawfordsvlle
+\bfarm\s+to\s+market\b	fm
+\bforest\s+service\b	frst srvc
+\bfredericksburg\b	fredericksbrg
+\bhendersonville\b	hendersonvlle
+\bjeffersonville\b	jeffersonvlle
+\bjohn\s+f\s+kennedy\b	jfk
+\blittle\s+diomede\b	diomede
+\bmechanicsville\b	mechanicsvlle
+\bnat\s+forest\s+dev\b	nat for dev
+\bnew\s+york\s+state\b	ny
+\bnorth\s+carolina\b	nc
+\bnorthumberland\b	northumberlnd
+\bsalt\s+lake\s+city\b	slc
+\bsouth\s+carolina\b	sc
+\bvirgin\s+islands\b	vi
+\bwashington\s+d\s+c\b	dc
+\barmy\s+airfield\b	army af
+\binternational\b	intl
+\bjf\s+kennedy\s+ap\b	jfk airport
+\bmassachusetts\b	ma
+\bnational\s+park\b	ntpk
+\bnew\s+hampshire\b	nh
+\bnew\s+york\s+city\b	ny
+\bunited\s+states\b	us
+\bwashington\s+dc\b	dc
+\bwest\s+virginia\b	wv
+\bbristle\s+cone\b	bristlecone
+\bfrst\s+service\b	frst srvc
+\bminers\s+mills\b	miners mill
+\bnorth\s+dakota\b	nd
+\bpennsylvania\b	pa
+\brhode\s+island\b	ri
+\bservice\s+road\b	service rd
+\bsouth\s+dakota\b	sd
+\bswan\s+quarter\b	swanquarter
+\bbloomington\b	blmngtn
+\bchevy\s+chase\b	chevy chs
+\bclutch\s+city\b	houston
+\bconnecticut\b	ct
+\bforest\s+srvc\b	frst srvc
+\bfrenchville\b	frnchvl
+\bgood\s+fellow\b	goodfellow
+\bhigh\s+bridge\b	highbridge
+\blos\s+angeles\b	la
+\bloxahatchee\b	lox
+\bmississippi\b	ms
+\bobservatory\b	obs
+\bpuerto\s+rico\b	pr
+\brural\s+route\b	rr
+\bspringfield\b	spfld
+\byellowstone\b	yelwstn
+\balpen\s+glow\b	alpenglow
+\bambassador\b	amb
+\bbernardino\b	bernrdno
+\bbloomfield\b	bloomfld
+\bbrownstown\b	brownstwn
+\bburlington\b	burlngtn
+\bcalifornia\b	ca
+\bcapistrano\b	capo
+\bchristmass\b	chirstmas
+\bcincinnati\b	cin
+\bcottonwood\b	ctwd
+\bcrossroads\b	xrds
+\bexpressway\b	exp
+\bextensions\b	exts
+\bfarmington\b	farmingtn
+\bnew\s+jersey\b	nj
+\bnew\s+mexico\b	nm
+\bpittsburgh\b	pgh
+\bplantation\b	plt
+\bprovidence\b	providnce
+\bsouth\s+lake\b	southlake
+\bthroughway\b	trwy
+\btrafficway\b	trfy
+\buniversity\b	univ
+\bwashington\b	wa
+\bwest\s+point\b	westpoint
+\bbellerose\b	bellrs
+\bboulevard\b	blvd
+\bburlingtn\b	burlngtn
+\bchair\s+bar\b	chairbar
+\bchicester\b	chicstr
+\bcity\s+base\b	cb
+\bcleveland\b	cleve
+\bcommunity\b	cmnty
+\bcrossroad\b	xrd
+\bextension\b	ext
+\bfairmount\b	fairmt
+\bfernandez\b	fdez
+\bfrancisco\b	fran
+\bhighlands\b	hlds
+\bho\'olehua\b	hoolehua
+\bhomestead\b	hmstd
+\bjunctions\b	jcts
+\blexington\b	lxngtn
+\blouisiana\b	la
+\bmilwaukee\b	milw
+\bminnesota\b	mn
+\bmountains\b	mtns
+\brichfield\b	richfld
+\bstravenue\b	stra
+\btennessee\b	
+\bterritory\b	
+\btown\s+line\b	t l
+\bunderpass\b	upas
+\bwashingtn\b	wa
+\bwisconsin\b	wi
+\barkansas\b	ar
+\bbig\s+bend\b	bg bnd
+\bblooming\b	blmng
+\bbullrush\b	bulrush
+\bcauseway\b	cswy
+\bcolorado\b	co
+\bcottonwd\b	ctwd
+\bcrescent\b	cres
+\bcrossing\b	xing
+\bcrossrds\b	xrds
+\bdelaware\b	de
+\bdowntown\b	
+\bhartford\b	hartfrd
+\billinois\b	il
+\bjunction\b	jt
+\bkentucky\b	ky
+\bla\s+salle\b	lasalle
+\bmaryland\b	md
+\bmichelle\b	michele
+\bmichigan\b	mi
+\bmissouri\b	mo
+\bmotorway\b	mtwy
+\bmountain\b	mnt
+\bnational\b	nl
+\bnebraska\b	ne
+\bnew\s+york\b	ny
+\boklahoma\b	ok
+\boverpass\b	opas
+\bparkways\b	pkwys
+\brichland\b	richlnd
+\btownline\b	t l
+\btownship\b	tp
+\bturnpike\b	tpk
+\bvillages\b	vlgs
+\bvilliage\b	vil
+\bvirginia\b	va
+\balabama\b	al
+\bamerica\b	us
+\barizona\b	az
+\bavenida\b	av
+\bcapitol\b	capital
+\bcausway\b	cswy
+\bcenters\b	ctrs
+\bcentral\b	
+\bchicago\b	chgo
+\bcircles\b	cirs
+\bcollege\b	clg
+\bcolonel\b	col
+\bcorners\b	cors
+\bcountry\b	cntry
+\bcrecent\b	cres
+\bcresent\b	cres
+\bcrossrd\b	xrd
+\bcrssing\b	xing
+\bestates\b	ests
+\bexpress\b	exp
+\bflorida\b	fl
+\bfreeway\b	fwy
+\bgardens\b	gdns
+\bgateway\b	gtwy
+\bgeorgia\b	ga
+\bharbors\b	hbrs
+\bheights\b	ht
+\bhighway\b	hwy
+\bhollows\b	hllw
+\bindiana\b	in
+\bislands\b	is
+\bjohnson\b	jhnsn
+\bjuncton\b	jt
+\blanding\b	lndg
+\bmeadows\b	mdws
+\bmission\b	msn
+\bmontana\b	mt
+\bmountin\b	mnt
+\borchard\b	orch
+\bparkway\b	pky
+\bpassage\b	psge
+\bphoenix\b	phx
+\bplaines\b	plns
+\bpotsdam\b	potsdm
+\bprairie\b	pr
+\branches\b	rnchs
+\branchos\b	rnchs
+\bseventh\b	7
+\bsprings\b	spg
+\bsquares\b	sqs
+\bstation\b	sta
+\bstraven\b	stra
+\bstreets\b	sts
+\bstrvnue\b	stra
+\bterrace\b	ter
+\btownshp\b	tp
+\btunnels\b	tunl
+\bvalleys\b	vlys
+\bvermont\b	vt
+\bviaduct\b	via
+\bvillage\b	vil
+\bwilliam\b	wm
+\bwshngtn\b	wa
+\bwyoming\b	wy
+\balaska\b	ak
+\barcade\b	arc
+\bavenue\b	av
+\bbarrio\b	bo
+\bbluffs\b	blfs
+\bbottom\b	bot
+\bbranch\b	br
+\bbridge\b	brg
+\bbrooks\b	brks
+\bbypass\b	byp
+\bcamino\b	cm
+\bcanyon\b	cyn
+\bcarlin\b	carlan
+\bcenter\b	cen
+\bcentre\b	cen
+\bcircle\b	cir
+\bcliffs\b	clfs
+\bcommon\b	cmn
+\bcorner\b	cor
+\bcorpus\b	crp
+\bcounty\b	
+\bcourse\b	crse
+\bcourts\b	cts
+\bcrscnt\b	cres
+\bcrsent\b	cres
+\bcrssng\b	xing
+\bdesert\b	dsrt
+\bdivide\b	dv
+\bdrives\b	drs
+\beighth\b	8
+\bestate\b	est
+\bextnsn\b	ext
+\bfields\b	flds
+\bforest\b	frst
+\bforges\b	frgs
+\bfourth\b	4
+\bfreewy\b	fwy
+\bgarden\b	gdn
+\bgatewy\b	gtwy
+\bgatway\b	gtwy
+\bgreens\b	grns
+\bgroves\b	grvs
+\bharbor\b	hbr
+\bhawaii\b	hi
+\bheight\b	ht
+\bhighwy\b	hwy
+\bhollow\b	hllw
+\bisland\b	is
+\bislnds\b	is
+\bjction\b	jt
+\bjunctn\b	jt
+\bkansas\b	ks
+\bknolls\b	knls
+\blagoon\b	lagn
+\blights\b	lgts
+\blittle\b	ltl
+\bmanors\b	mnrs
+\bmeadow\b	mdw
+\bmedows\b	mdws
+\bmiddle\b	mid
+\bmntain\b	mnt
+\bnevada\b	nv
+\bobispo\b	obisp
+\borchrd\b	orch
+\boregon\b	or
+\bparish\b	
+\bparkwy\b	pky
+\bplains\b	plns
+\bpoints\b	pts
+\bpuerto\b	pto
+\bquarry\b	qry
+\bradial\b	rad
+\bradiel\b	rad
+\brancho\b	rncho
+\branchs\b	rnchs
+\brapids\b	rpds
+\bridges\b	rdgs
+\bschool\b	sch
+\bsecond\b	2
+\bsenior\b	sr
+\bshoals\b	shls
+\bshoars\b	shrs
+\bshores\b	shrs
+\bskyway\b	skwy
+\bspring\b	spg
+\bsprngs\b	spg
+\bsquare\b	sq
+\bstrave\b	stra
+\bstravn\b	stra
+\bstream\b	strm
+\bstreet\b	st
+\bstreme\b	strm
+\bsumitt\b	smt
+\bsummit\b	smt
+\bsydney\b	sidney
+\btraces\b	trce
+\btracks\b	trk
+\btrails\b	tr
+\btunnel\b	tunl
+\bturnpk\b	tpk
+\btwnshp\b	tp
+\bunions\b	uns
+\bvalley\b	vl
+\bviadct\b	via
+\bvillag\b	vil
+\bwaters\b	wtr
+\bxroads\b	xrds
+\ba\s+f\s+b\b	afb
+\ballee\b	aly
+\balley\b	aly
+\bannex\b	anx
+\bavenu\b	av
+\bavnue\b	av
+\bbayoo\b	byu
+\bbayou\b	byu
+\bbeach\b	bch
+\bblack\b	blk
+\bbluff\b	blf
+\bbottm\b	bot
+\bboulv\b	blvd
+\bbrdge\b	brg
+\bbrnch\b	br
+\bbrook\b	brk
+\bburgs\b	bgs
+\bbypas\b	byp
+\bcalif\b	ca
+\bcalle\b	cll
+\bcanyn\b	cyn
+\bcentr\b	cen
+\bcircl\b	cir
+\bcliff\b	clf
+\bcnter\b	cen
+\bcourt\b	ct
+\bcoves\b	cvs
+\bcrcle\b	cir
+\bcreek\b	ck
+\bcrest\b	crst
+\bcrsnt\b	cres
+\bcurve\b	curv
+\bdepot\b	dep
+\bdrive\b	dr
+\beight\b	8
+\bfalls\b	fls
+\bferry\b	fry
+\bfield\b	fld
+\bfifth\b	5
+\bfirst\b	1
+\bflats\b	flts
+\bfords\b	frds
+\bforge\b	frg
+\bforks\b	fks
+\bfrway\b	fwy
+\bgardn\b	gdn
+\bglens\b	glns
+\bgrand\b	grnd
+\bgrden\b	gdn
+\bgrdns\b	gdns
+\bgreen\b	grn
+\bgrove\b	grv
+\bgtway\b	gtwy
+\bharbr\b	hbr
+\bhaven\b	hvn
+\bhills\b	hl
+\bhiway\b	hwy
+\bholws\b	hllw
+\bhouse\b	hse
+\bhrbor\b	hbr
+\bidaho\b	id
+\binlet\b	inlt
+\bisles\b	isle
+\bislnd\b	is
+\bjctns\b	jcts
+\bknoll\b	knl
+\blakes\b	lks
+\blanes\b	la
+\blight\b	lgt
+\blndng\b	lndg
+\blocks\b	lcks
+\blodge\b	ldg
+\bloops\b	loop
+\blower\b	lo
+\bm\s+l\s+k\b	mlk
+\bmaine\b	me
+\bmanor\b	mnr
+\bmills\b	mls
+\bmissn\b	msn
+\bmntns\b	mtns
+\bmount\b	mt
+\bn\s+y\s+c\b	ny
+\bninth\b	9
+\bnorth\b	n
+\bpalau\b	pw
+\bpalms\b	plms
+\bpaseo\b	pso
+\bpaths\b	path
+\bpikes\b	pike
+\bpines\b	pnes
+\bpkway\b	pky
+\bplace\b	pl
+\bplain\b	pln
+\bplaza\b	plz
+\bpoint\b	pt
+\bponds\b	pnds
+\bports\b	prts
+\branch\b	rch
+\brapid\b	rpd
+\bridge\b	rdg
+\briver\b	riv
+\broads\b	rds
+\broute\b	rt
+\bsaint\b	st
+\bseven\b	7
+\bshoal\b	shl
+\bshoar\b	shr
+\bshore\b	shr
+\bsixth\b	6
+\bsouth\b	s
+\bspace\b	sp
+\bspngs\b	spg
+\bsprgs\b	spg
+\bsprng\b	spg
+\bstatn\b	sta
+\bstrav\b	stra
+\bstrvn\b	stra
+\bsumit\b	smt
+\btenth\b	10
+\btexas\b	tx
+\bthird\b	3
+\bthree\b	3
+\btrace\b	trce
+\btrack\b	trk
+\btrail\b	tr
+\btrnpk\b	tpk
+\btunel\b	tunl
+\btunls\b	tunl
+\btunnl\b	tunl
+\bu\s+s\s+a\b	us
+\bunion\b	un
+\bvally\b	vl
+\bverdi\b	verde
+\bviews\b	vws
+\bville\b	vl
+\bvillg\b	vil
+\bvista\b	vis
+\bwells\b	wls
+\bwoods\b	wds
+\bworks\b	wks
+\bxroad\b	xrd
+\bally\b	aly
+\banex\b	anx
+\bariz\b	az
+\baven\b	av
+\bbend\b	bnd
+\bbluf\b	blf
+\bboul\b	blvd
+\bburg\b	bg
+\bbyng\b	bing
+\bbypa\b	byp
+\bbyps\b	byp
+\bcamp\b	cp
+\bcape\b	cpe
+\bcent\b	cen
+\bcirc\b	cir
+\bcity\b	cy
+\bclub\b	clb
+\bcntr\b	cen
+\bcnyn\b	cyn
+\bcolo\b	co
+\bconn\b	ct
+\bcove\b	cv
+\bcrcl\b	cir
+\bdale\b	dl
+\bdriv\b	dr
+\beast\b	e
+\bexpr\b	exp
+\bexpw\b	exp
+\bexpy\b	exp
+\bextn\b	ext
+\bfarm\b	frm
+\bfive\b	5
+\bflat\b	flt
+\bford\b	frd
+\bforg\b	frg
+\bfork\b	frk
+\bfort\b	ft
+\bfour\b	4
+\bfrks\b	fks
+\bfrry\b	fry
+\bfrwy\b	fwy
+\bglen\b	gln
+\bgrdn\b	gdn
+\bgrov\b	grv
+\bguam\b	gu
+\bharb\b	hbr
+\bhavn\b	hvn
+\bhght\b	ht
+\bhgts\b	ht
+\bhill\b	hl
+\bhiwy\b	hwy
+\bholw\b	hllw
+\bhway\b	hwy
+\biowa\b	ia
+\bjctn\b	jt
+\bjnct\b	jt
+\bkans\b	ks
+\bkeys\b	kys
+\bknol\b	knl
+\blake\b	lk
+\blane\b	la
+\bldge\b	ldg
+\blitl\b	ltl
+\bloaf\b	lf
+\block\b	lck
+\blodg\b	ldg
+\bmass\b	ma
+\bmich\b	mi
+\bmile\b	mle
+\bmill\b	ml
+\bminn\b	mn
+\bmiss\b	ms
+\bmntn\b	mnt
+\bmssn\b	msn
+\bmtin\b	mnt
+\bnebr\b	ne
+\bneck\b	nck
+\bnine\b	9
+\bohio\b	oh
+\bokla\b	ok
+\boreg\b	or
+\boval\b	ovl
+\bpalm\b	plm
+\bpark\b	pk
+\bpass\b	ps
+\bpine\b	pne
+\bpkwy\b	pky
+\bplza\b	plz
+\bport\b	prt
+\bradl\b	rad
+\brdge\b	rdg
+\brest\b	rst
+\brivr\b	riv
+\brnch\b	rch
+\broad\b	rd
+\bspgs\b	spg
+\bspng\b	spg
+\bsprg\b	spg
+\bsqre\b	sq
+\bsqrs\b	sqs
+\bstrt\b	st
+\btenn\b	
+\bterr\b	ter
+\btown\b	
+\btpke\b	tpk
+\btrak\b	trk
+\btrks\b	trk
+\btrls\b	tr
+\btrpk\b	tpk
+\btwln\b	t l
+\btwsp\b	tp
+\butah\b	ut
+\bvdct\b	via
+\bview\b	vw
+\bvill\b	vil
+\bvist\b	vis
+\bvlly\b	vl
+\bvsta\b	vis
+\bwash\b	wa
+\bwell\b	wl
+\bwest\b	w
+\bx\s+rd\b	xrd
+\bala\b	al
+\bave\b	av
+\bavn\b	av
+\bbtm\b	bot
+\bcam\b	cm
+\bcmp\b	cp
+\bcrk\b	ck
+\bcrt\b	ct
+\bctr\b	cen
+\bcty\b	cy
+\bd\s+c\b	dc
+\bdam\b	dm
+\bdiv\b	dv
+\bdpt\b	dep
+\bdrv\b	dr
+\bdvd\b	dv
+\bfla\b	fl
+\bfrt\b	ft
+\bhei\b	ht
+\bhls\b	hl
+\bhts\b	ht
+\bill\b	il
+\bind\b	in
+\bisl\b	is
+\biss\b	is
+\bjct\b	jt
+\bkan\b	ks
+\bkey\b	ky
+\bl\s+a\b	la
+\blke\b	lk
+\blwr\b	lo
+\bmtn\b	mnt
+\bn\s+c\b	nc
+\bn\s+d\b	nd
+\bn\s+h\b	nh
+\bn\s+j\b	nj
+\bn\s+m\b	nm
+\bn\s+y\b	ny
+\bneb\b	ne
+\bnev\b	nv
+\bnth\b	n
+\bntl\b	nl
+\bnyc\b	ny
+\bnys\b	ny
+\bone\b	1
+\bore\b	or
+\bp\s+r\b	pr
+\bprk\b	pk
+\bprr\b	pr
+\br\s+i\b	ri
+\brte\b	rt
+\brvr\b	riv
+\bs\s+c\b	sc
+\bs\s+d\b	sd
+\bsan\b	sn
+\bsix\b	6
+\bspr\b	spg
+\bsqr\b	sq
+\bsqu\b	sq
+\bsth\b	s
+\bstn\b	sta
+\bstr\b	st
+\bten\b	10
+\btrl\b	tr
+\btwo\b	2
+\btwp\b	tp
+\bu\s+s\b	us
+\busa\b	us
+\bv\s+i\b	vi
+\bvlg\b	vil
+\bvly\b	vl
+\bvst\b	vis
+\bw\s+v\b	wv
+\bway\b	wy
+\bwis\b	wi
+\bwva\b	wv
+\bcr\b	ck
+\bln\b	la
+\btn\b	
+\btw\b	tp
+\bvy\b	vl
+\b\\#\b	
diff --git a/components/autofill/core/browser/address_rewrite_rules/VN.txt b/components/autofill/core/browser/address_rewrite_rules/VN.txt
new file mode 100644
index 0000000..b84abe98
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/VN.txt
@@ -0,0 +1,19 @@
+\bthi\s+tran\s+van\s+dien\b	ttvan dien
+\bho\s+chi\s+minh\s+city\b	hcm
+\bho\s+chi\s+minh\b	hcm
+\bthanh\s+pho\b	tp
+\bthi\s+tran\b	tt
+\btpha\s+noi\b	ha noi
+\bviet\s+nam\b	vn
+\bvietnam\b	vn
+\bphuong\b	p
+\bthi\s+xa\b	tx
+\bhuyen\b	h.
+\bhcmc\b	hcm
+\bquan\b	q.
+\bph\\.\b	p
+\btp\\.\b	tp
+\btt\\.\b	tt
+\btx\\.\b	tx
+\bp\\.\b	p
+\bxa\b	x.
diff --git a/components/autofill/core/browser/address_rewrite_rules/ZA.txt b/components/autofill/core/browser/address_rewrite_rules/ZA.txt
new file mode 100644
index 0000000..3f686fe
--- /dev/null
+++ b/components/autofill/core/browser/address_rewrite_rules/ZA.txt
@@ -0,0 +1,30 @@
+\brepublic\s+of\s+south\s+africa\b	sa
+\bkwazulu\s+natal\b	nl
+\bnorthern\s+cape\b	nc
+\beastern\s+cape\b	ec
+\bkwazulunatal\b	nl
+\bsouth\s+africa\b	sa
+\bwestern\s+cape\b	wc
+\bfree\s+state\b	fs
+\bmpumalanga\b	mp
+\bnoord\s+kaap\b	nc
+\bnorth\s+west\b	nw
+\bboulevard\b	blvd
+\bfreestate\b	fs
+\bnoordwes\b	nw
+\boos\s+kaap\b	ec
+\bvrystaat\b	fs
+\bwes\s+kaap\b	wc
+\bgauteng\b	gp
+\bhighway\b	hwy
+\blimpopo\b	lp
+\bavenue\b	ave
+\bstreet\b	st
+\bdrive\b	dr
+\bnatal\b	nl
+\bsaint\b	st
+\broad\b	rd
+\bkzn\b	nl
+\bgt\b	gp
+\bza\b	sa
+\bzn\b	nl
diff --git a/components/autofill/core/browser/address_rewriter.cc b/components/autofill/core/browser/address_rewriter.cc
index 00c86e2..1b85a50 100644
--- a/components/autofill/core/browser/address_rewriter.cc
+++ b/components/autofill/core/browser/address_rewriter.cc
@@ -9,32 +9,69 @@
 
 #include "base/i18n/case_conversion.h"
 #include "base/memory/singleton.h"
+#include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/grit/autofill_address_rewriter_resources_map.h"
 #include "third_party/re2/src/re2/re2.h"
+#include "third_party/zlib/google/compression_utils.h"
+#include "ui/base/resource/resource_bundle.h"
 
 namespace autofill {
 namespace {
 
-// Import in the internal rule table symbols. The data is defined in
-// components/autofill/core/browser/address_rewriter_rules.cc
-using internal::RegionInfo;
-using internal::kRuleTable;
-using internal::kRuleTableSize;
-
 // Aliases for the types used by the compiled rules cache.
-using CompiledRule = std::pair<std::unique_ptr<re2::RE2>, const char *>;
+using CompiledRule = std::pair<std::unique_ptr<re2::RE2>, std::string>;
 using CompiledRuleVector = std::vector<CompiledRule>;
 using CompiledRuleCache = std::unordered_map<std::string, CompiledRuleVector>;
 
-// Helper function to find the rules associated with |region|. Note that this
-// requires that kRuleTable be sorted by region.
-static const RegionInfo* GetRegionInfo(const base::StringPiece& region) {
-  const RegionInfo* begin = kRuleTable;
-  const RegionInfo* end = kRuleTable + kRuleTableSize;
-  const RegionInfo* iter = std::lower_bound(begin, end, region);
-  if (iter != end && region == iter->region)
-    return iter;
-  return nullptr;
+// Helper function to convert region to mapping key string.
+std::string GetMapKey(const std::string& region) {
+  return base::StrCat({"IDR_ADDRESS_REWRITER_", region, "_RULES"});
+}
+
+// Helper function to extract region rules data into |out_data|.
+static bool ExtractRegionRulesData(const std::string& region,
+                                   std::string* out_data) {
+  int resource_id = 0;
+  std::string resource_key = GetMapKey(region);
+  for (size_t i = 0; i < kAutofillAddressRewriterResourcesSize; ++i) {
+    if (kAutofillAddressRewriterResources[i].name == resource_key) {
+      resource_id = kAutofillAddressRewriterResources[i].value;
+      break;
+    }
+  }
+
+  if (!resource_id)
+    return false;
+
+  // Gets and uncompresses resource data.
+  base::StringPiece raw_resource =
+      ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id);
+  compression::GzipUncompress(raw_resource, out_data);
+
+  return true;
+}
+
+// Helper function to populate |compiled_rules| by parsing |data_string|.
+void CompileRulesFromData(const std::string& data_string,
+                          CompiledRuleVector* compiled_rules) {
+  base::StringPiece data = data_string;
+  re2::RE2::Options options;
+  options.set_utf8(true);
+  options.set_word_boundary(true);
+
+  size_t token_end = 0;
+  while (!data.empty()) {
+    token_end = data.find('\t');
+    re2::StringPiece pattern_re2(data.data(), token_end);
+    auto pattern = std::make_unique<re2::RE2>(pattern_re2, options);
+    data.remove_prefix(token_end + 1);
+
+    token_end = data.find('\n');
+    std::string rewrite_string = data.substr(0, token_end).as_string();
+    compiled_rules->emplace_back(std::move(pattern), std::move(rewrite_string));
+    data.remove_prefix(token_end + 1);
+  }
 }
 
 // The cache of compiled string replacement rules, keyed by region. This class
@@ -61,25 +98,26 @@
       return &cache_iter->second;
 
     // Cache miss. Look for the raw rules. If none, then return nullptr.
-    const RegionInfo* region_info = GetRegionInfo(region);
-    if (region_info == nullptr)
+    std::string region_rules;
+    bool region_found = ExtractRegionRulesData(region, &region_rules);
+
+    if (!region_found)
       return nullptr;
 
-    // Add a new rule vector the the cache and populate it with compiled rules.
-    re2::RE2::Options options;
-    options.set_utf8(true);
-    options.set_word_boundary(true);
+    // Add a new rule vector to the cache and populate it with compiled rules.
     CompiledRuleVector& compiled_rules = data_[region];
+    CompileRulesFromData(region_rules, &compiled_rules);
 
-    compiled_rules.reserve(region_info->num_rules);
+    // Return a pointer to the data.
+    return &compiled_rules;
+  }
 
-    const char* iterator = region_info->rules;
-    for(size_t i = 0; i < region_info->num_rules; ++i){
-      auto pattern = std::make_unique<re2::RE2>(iterator, options);
-      iterator += strlen(iterator) + 1;
-      compiled_rules.emplace_back(std::move(pattern), iterator);
-      iterator += strlen(iterator) + 1;
-    }
+  // Uses a string of data to create and return a pointer to a
+  // CompiledRuleVector. Used for creating unit_tests.
+  const CompiledRuleVector* CreateRulesForData(const std::string& data) {
+    // Compiled rules vector must be kept in cache to be used elsewhere.
+    CompiledRuleVector& compiled_rules = data_[data];
+    CompileRulesFromData(data, &compiled_rules);
 
     // Return a pointer to the data.
     return &compiled_rules;
@@ -112,6 +150,15 @@
   return rewriter;
 }
 
+AddressRewriter AddressRewriter::ForCustomRules(
+    const std::string& custom_rules) {
+  const CompiledRuleVector* rules =
+      Cache::GetInstance()->CreateRulesForData(custom_rules);
+  AddressRewriter rewriter;
+  rewriter.impl_ = rules;
+  return rewriter;
+}
+
 base::string16 AddressRewriter::Rewrite(const base::string16& text) const {
   if (impl_ == nullptr)
     return base::CollapseWhitespace(text, true);
diff --git a/components/autofill/core/browser/address_rewriter.h b/components/autofill/core/browser/address_rewriter.h
index 145e12ba..4323a76 100644
--- a/components/autofill/core/browser/address_rewriter.h
+++ b/components/autofill/core/browser/address_rewriter.h
@@ -19,6 +19,9 @@
   // Get an AddressRewrite instance which applies the rules for |country_code|.
   static AddressRewriter ForCountryCode(const base::string16& country_code);
 
+  // Gets an AddressRewrite instance for tests with custom rules.
+  static AddressRewriter ForCustomRules(const std::string& custom_rules);
+
   // Apply the rewrite rules to |text| and return the result.
   base::string16 Rewrite(const base::string16& text) const;
 
@@ -27,32 +30,6 @@
   const void* impl_ = nullptr;
 };
 
-// Implementation details follow. Not part of the public interface.
-namespace internal {
-
-// The structure used to statically define a set of rules for a region.
-struct RegionInfo {
-  const char* region;
-  const char* rules;
-  size_t num_rules;
-
-  bool operator<(const base::StringPiece& region) const {
-    return base::CompareCaseInsensitiveASCII(this->region, region) < 0;
-  }
-
-  bool operator==(const base::StringPiece& region) const {
-    return base::EqualsCaseInsensitiveASCII(this->region, region);
-  }
-};
-
-// The statically defined rule table, sorted by region.
-extern const internal::RegionInfo kRuleTable[];
-
-// The size (in records) of the statically defined rule table.
-extern const size_t kRuleTableSize;
-
-}  // namespace internal
-
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_REWRITER_H_
diff --git a/components/autofill/core/browser/address_rewriter_rules.cc b/components/autofill/core/browser/address_rewriter_rules.cc
deleted file mode 100644
index c728865..0000000
--- a/components/autofill/core/browser/address_rewriter_rules.cc
+++ /dev/null
@@ -1,3604 +0,0 @@
-// Copyright 2016 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.
-//
-// Generated 2019-07-04T15:44:33Z
-
-#include "components/autofill/core/browser/address_rewriter.h"
-
-namespace autofill {
-namespace internal {
-namespace {
-
-const char* kRules_AD =
-"\\bparroquia\\s+de\\s+andorra\\s+la\\s+vella\\b\00007\000"
-"\\bprincipal\\s+de\\s+andorra\\b\00007\000"
-"\\bprincipat\\s+de\\s+andorra\\b\00007\000"
-"\\bsant\\s+julia\\s+de\\s+loria\\b\00006\000"
-"\\bescaldes\\s+engordany\\b\00008\000"
-"\\bandorra\\s+la\\s+vella\\b\00007\000"
-"\\bcarrer\\s+del\\b\000\000"
-"\\bla\\s+massana\\b\00004\000"
-"\\bsant\\s+julia\\b\00006\000"
-"\\bcarrer\\s+de\\b\000\000"
-"\\bandorra\\b\00007\000"
-"\\bcanillo\\b\00002\000"
-"\\bmassana\\b\00004\000"
-"\\bencamp\\b\00003\000"
-"\\bordino\\b\00005\000"
-"\\bc\\s+del\\b\000\000"
-"\\bc\\s+de\\b\000\000"
-"\\bad\\b\00007\000"
-"\\ban\\b\00007\000"
-"\\bca\\b\00002\000"
-"\\bee\\b\00008\000"
-"\\ben\\b\00003\000"
-"\\bjl\\b\00006\000"
-"\\bma\\b\00004\000"
-"\\bor\\b\00005\000"
-;
-int kNumRules_AD = 25;
-
-const char* kRules_AR =
-"\\btierra\\s+del\\s+fuego\\s+antartida\\s+e\\s+islas\\s+del\\s+atlantico\\s+sur\\b\000tierra del fuego\000"
-"\\bciudad\\s+autonoma\\s+de\\s+buenos\\s+aires\\b\000caba\000"
-"\\bla\\s+ciudad\\s+de\\s+buenos\\s+aires\\b\000caba\000"
-"\\bcapital\\s+federal\\b\000caba\000"
-"\\bdiecinueve\\b\00019\000"
-"\\bdiecisiete\\b\00017\000"
-"\\bargentina\\b\000ar\000"
-"\\bboulevard\\b\000bv\000"
-"\\bdieciocho\\b\00018\000"
-"\\bdieciseis\\b\00016\000"
-"\\bavenida\\b\000av\000"
-"\\bcatorce\\b\00014\000"
-"\\bprimera\\b\0001a\000"
-"\\bsegunda\\b\0002a\000"
-"\\bseptima\\b\0007a\000"
-"\\btercera\\b\0003a\000"
-"\\bcuarta\\b\0004a\000"
-"\\bcuatro\\b\0004\000"
-"\\boctava\\b\0008a\000"
-"\\bpasaje\\b\000pje\000"
-"\\bquince\\b\00015\000"
-"\\bquinta\\b\0005a\000"
-"\\bveinte\\b\00020\000"
-"\\bcinco\\b\0005\000"
-"\\bnueve\\b\0009\000"
-"\\bsexta\\b\0006a\000"
-"\\bsiete\\b\0007\000"
-"\\btrece\\b\00013\000"
-"\\bdiez\\b\00010\000"
-"\\bdoce\\b\00012\000"
-"\\bocho\\b\0008\000"
-"\\bonce\\b\00011\000"
-"\\bseis\\b\0006\000"
-"\\btres\\b\0003\000"
-"\\bdel\\b\000\000"
-"\\bdos\\b\0002\000"
-"\\blas\\b\000\000"
-"\\blos\\b\000\000"
-"\\buno\\b\0001\000"
-"\\bde\\b\000\000"
-"\\bel\\b\000\000"
-"\\ble\\b\000\000"
-;
-int kNumRules_AR = 42;
-
-const char* kRules_AU =
-"\\baustralian\\s+capital\\s+territory\\b\000act\000"
-"\\bjervis\\s+bay\\s+territory\\b\000jbt\000"
-"\\bnorthern\\s+territory\\b\000nt\000"
-"\\bwestern\\s+australia\\b\000wa\000"
-"\\bnew\\s+south\\s+wales\\b\000nsw\000"
-"\\bsouth\\s+australia\\b\000sa\000"
-"\\bqueensland\\b\000qld\000"
-"\\baustralia\\b\000au\000"
-"\\bboulevard\\b\000blvd\000"
-"\\bcrescent\\b\000cres\000"
-"\\btasmania\\b\000tas\000"
-"\\bvictoria\\b\000vic\000"
-"\\bhighway\\b\000hwy\000"
-"\\bparkway\\b\000pkwy\000"
-"\\ba\\.c\\.t\\.\\b\000act\000"
-"\\bau\\-act\\b\000act\000"
-"\\bau\\-jbt\\b\000jbt\000"
-"\\bau\\-nsw\\b\000nsw\000"
-"\\bau\\-qld\\b\000qld\000"
-"\\bau\\-tas\\b\000tas\000"
-"\\bau\\-vic\\b\000vic\000"
-"\\bavenue\\b\000ave\000"
-"\\bcommon\\b\000comm\000"
-"\\bj\\.b\\.t\\.\\b\000jbt\000"
-"\\bn\\.s\\.w\\.\\b\000nsw\000"
-"\\bparade\\b\000pde\000"
-"\\bstreet\\b\000st\000"
-"\\ba\\.c\\.t\\b\000act\000"
-"\\bau\\-nt\\b\000nt\000"
-"\\bau\\-sa\\b\000sa\000"
-"\\bau\\-wa\\b\000wa\000"
-"\\bcourt\\b\000ct\000"
-"\\bdrive\\b\000dr\000"
-"\\beight\\b\0008\000"
-"\\bj\\.b\\.t\\b\000jbt\000"
-"\\bmount\\b\000mt\000"
-"\\bn\\.s\\.w\\b\000nsw\000"
-"\\bnorth\\b\000n\000"
-"\\bplace\\b\000pl\000"
-"\\bpoint\\b\000pt\000"
-"\\bsaint\\b\000st\000"
-"\\bseven\\b\0007\000"
-"\\bsouth\\b\000s\000"
-"\\bthree\\b\0003\000"
-"\\beast\\b\000e\000"
-"\\bfive\\b\0005\000"
-"\\bfour\\b\0004\000"
-"\\blane\\b\000ln\000"
-"\\bn\\.t\\.\\b\000nt\000"
-"\\bnine\\b\0009\000"
-"\\broad\\b\000rd\000"
-"\\bs\\.a\\.\\b\000sa\000"
-"\\bw\\.a\\.\\b\000wa\000"
-"\\bwest\\b\000w\000"
-"\\baus\\b\000au\000"
-"\\bmt\\.\\b\000mt\000"
-"\\bn\\.t\\b\000nt\000"
-"\\bnth\\b\000n\000"
-"\\bone\\b\0001\000"
-"\\bpt\\.\\b\000pt\000"
-"\\bs\\.a\\b\000sa\000"
-"\\bsix\\b\0006\000"
-"\\bst\\.\\b\000st\000"
-"\\bsth\\b\000s\000"
-"\\bten\\b\00010\000"
-"\\btwo\\b\0002\000"
-"\\bw\\.a\\b\000wa\000"
-"\\be\\.\\b\000e\000"
-"\\bn\\.\\b\000n\000"
-"\\bs\\.\\b\000s\000"
-"\\bw\\.\\b\000w\000"
-;
-int kNumRules_AU = 71;
-
-const char* kRules_BE =
-"\\barrondissement\\s+administratif\\s+de\\b\000\000"
-"\\barrondissement\\s+administratif\\s+d\\b\000\000"
-"\\bbrussels\\s+hoofdstedelijk\\s+gewest\\b\000brussel\000"
-"\\bbrussel\\s+hoofdstedelijk\\s+gewest\\b\000brussel\000"
-"\\bregion\\s+de\\s+bruxelles\\s+capitale\\b\000brussel\000"
-"\\bseptieme\\s+division\\s+francaise\\b\0007eme division frcse\000"
-"\\bonze\\s+lieve\\s+heersebeestjes\\b\000onze lieve heersbeestjes\000"
-"\\bregion\\s+brussel\\s+hauptstadt\\b\000brussel\000"
-"\\balbert\\s+en\\s+marie\\s+louise\\b\000a & m l\000"
-"\\balbert\\s+et\\s+marie\\s+louise\\b\000a & m l\000"
-"\\bandree\\s+payfa\\s+fosseprez\\b\000a payfa fosseprez\000"
-"\\bseptieme\\s+d\\s+i\\s+francaise\\b\0007eme division frcse\000"
-"\\bwereldtentoonstellings\\b\000wereldtentoonstelings\000"
-"\\bberchem\\s+sainte\\s+agathe\\b\000st agatha berchem\000"
-"\\bflandres\\s+occidentales\\b\000westflandern\000"
-"\\bsaint\\s+josse\\s+ten\\s+noode\\b\000saint josse\000"
-"\\bflandre\\s+occidentales\\b\000westflandern\000"
-"\\bflandres\\s+occidentale\\b\000westflandern\000"
-"\\bhenri\\s+victor\\s+wolvens\\b\000h v wolvens\000"
-"\\bjoseph\\s+van\\s+boterdael\\b\000joseph van boterdae\000"
-"\\bmarilyn\\s+monroegaarde\\b\000marilyn monroe\000"
-"\\bflandre\\s+occidentale\\b\000westflandern\000"
-"\\bflandres\\s+orientales\\b\000ostflandern\000"
-"\\bwoluwe\\s+saint\\s+pierre\\b\000st pieters woluwe\000"
-"\\bbruxelles\\s+capitale\\b\000brussel\000"
-"\\bflandre\\s+orientales\\b\000ostflandern\000"
-"\\bflandres\\s+orientale\\b\000ostflandern\000"
-"\\bhendrik\\s+conscience\\b\000henri conscience\000"
-"\\bleonoardo\\s+da\\s+vinci\\b\000leonard de vinci\000"
-"\\bwallonisch\\s+brabant\\b\000waals brabant\000"
-"\\bwallonische\\s+region\\b\000wallonie\000"
-"\\bbischoffsheimlaan\\b\000bischoffsheim\000"
-"\\bbrouck\\s+du\\s+tilleul\\b\000brouck au tilleul\000"
-"\\bflandre\\s+orientale\\b\000ostflandern\000"
-"\\bleonardo\\s+da\\s+vinci\\b\000leonard de vinci\000"
-"\\barmand\\s+scheitler\\b\000armand scheiter\000"
-"\\bflamisch\\s+brabant\\b\000vlaams brabant\000"
-"\\bflamische\\s+region\\b\000vlaams gewest\000"
-"\\bhenri\\s+wafelaerts\\b\000henri wafelaert\000"
-"\\bpieter\\s+hauwaerts\\b\000pierre hauwaerts\000"
-"\\bregion\\s+wallonien\\b\000wallonie\000"
-"\\brennequin\\s+sualem\\b\000renkin sualem\000"
-"\\baugust\\s+de\\s+boeck\\b\000a de boeck\000"
-"\\bbrabant\\s+flamand\\b\000vlaams brabant\000"
-"\\bbruxelles\\s+ville\\b\000brussel\000"
-"\\bflamisch\\s+region\\b\000vlaams gewest\000"
-"\\bgodefroid\\s+kurth\\b\000godfroid kurth\000"
-"\\boost\\s+vlaanderen\\b\000ostflandern\000"
-"\\bregion\\s+flamande\\b\000vlaams gewest\000"
-"\\bregion\\s+wallonne\\b\000wallonie\000"
-"\\bwest\\s+vlaanderen\\b\000westflandern\000"
-"\\barrondissement\\b\000\000"
-"\\bbrabant\\s+wallon\\b\000waals brabant\000"
-"\\blimburg\\s+strium\\b\000limburg stirum\000"
-"\\bde\\s+ribaucourt\\b\000ribaucourt\000"
-"\\bmichel\\s+angelo\\b\000michel ange\000"
-"\\bpater\\s+damiaan\\b\000pater damian\000"
-"\\bprofondeville\\b\000profondville\000"
-"\\bsint\\s+lenaerts\\b\000sint lenaarts\000"
-"\\bsualem\\s+renkin\\b\000renkin sualem\000"
-"\\bdendermondse\\b\000dendermonde\000"
-"\\bminnezangers\\b\000menestrelen\000"
-"\\bvooruitgangs\\b\000vooruitgang\000"
-"\\bwaals\\s+gewest\\b\000wallonie\000"
-"\\bcortenbergh\\b\000cortenberg\000"
-"\\bjette\\s+jetse\\b\000jette\000"
-"\\bl\\s+urbanisme\\b\000i urbanisme\000"
-"\\bprovince\\s+de\\b\000\000"
-"\\bprovince\\s+du\\b\000\000"
-"\\bpuits\\s+no\\s+iv\\b\000puits n4\000"
-"\\bterhulpense\\b\000terhulpse\000"
-"\\bhenegouwen\\b\000hainaut\000"
-"\\blanguesdoc\\b\000languedoc\000"
-"\\bluxembourg\\b\000luxemburg\000"
-"\\bprovince\\s+d\\b\000\000"
-"\\bpuit\\s+no\\s+iv\\b\000puits n4\000"
-"\\bvan\\s+volxem\\b\000volxem\000"
-"\\bantwerpen\\b\000anvers\000"
-"\\bboulevard\\b\000bd\000"
-"\\bbruxelles\\b\000brussel\000"
-"\\bluitenant\\b\000liutenant\000"
-"\\bwallonien\\b\000wallonie\000"
-"\\bwestphael\\b\000wesphal\000"
-"\\bbelgique\\b\000be\000"
-"\\bbrussels\\b\000brussel\000"
-"\\bchaussee\\b\000chee\000"
-"\\bhennegau\\b\000hainaut\000"
-"\\blimbourg\\b\000limburg\000"
-"\\bsteenweg\\b\000stwg\000"
-"\\bterrasse\\b\000tsse\000"
-"\\bwestphal\\b\000wesphal\000"
-"\\bavenues\\b\000av\000"
-"\\bbelgien\\b\000be\000"
-"\\bbelgium\\b\000be\000"
-"\\bde\\s+wand\\b\000wand\000"
-"\\bimpasse\\b\000imp\000"
-"\\bjettese\\b\000jetse\000"
-"\\bluttich\\b\000luik\000"
-"\\bprovinz\\b\000\000"
-"\\bstrasse\\b\000str\000"
-"\\ballees\\b\000all\000"
-"\\bavenue\\b\000av\000"
-"\\bbelgie\\b\000be\000"
-"\\bcentre\\b\000ctre\000"
-"\\bsainte\\b\000st\000"
-"\\bsquare\\b\000sq\000"
-"\\bstraat\\b\000str\000"
-"\\ballee\\b\000all\000"
-"\\bliege\\b\000luik\000"
-"\\bnamur\\b\000namen\000"
-"\\bpiein\\b\000pl\000"
-"\\bplace\\b\000pl\000"
-"\\bplatz\\b\000pl\000"
-"\\bplein\\b\000pl\000"
-"\\broute\\b\000rte\000"
-"\\bsaint\\b\000st\000"
-"\\bsankt\\b\000st\000"
-"\\bthier\\b\000their\000"
-"\\bsint\\b\000st\000"
-"\\bdes\\b\000d\000"
-"\\brue\\b\000r\000"
-"\\bste\\b\000st\000"
-"\\bde\\b\000d\000"
-"\\bdu\\b\000d\000"
-;
-int kNumRules_BE = 124;
-
-const char* kRules_BR =
-"\\brio\\s+grande\\s+do\\s+norte\\b\000rn\000"
-"\\bmato\\s+grosso\\s+do\\s+sul\\b\000ms\000"
-"\\brio\\s+grande\\s+do\\s+sul\\b\000rs\000"
-"\\bdistrito\\s+federal\\b\000df\000"
-"\\bdecimo\\s+primeiro\\b\00011\000"
-"\\bdecimo\\s+terceiro\\b\00013\000"
-"\\bespirito\\s+santo\\b\000es\000"
-"\\brio\\s+de\\s+janeiro\\b\000rj\000"
-"\\bsanta\\s+catarina\\b\000sc\000"
-"\\bvinte\\s+e\\s+quatro\\b\00024\000"
-"\\bdecimo\\s+oitavo\\b\00018\000"
-"\\bdecimo\\s+quarto\\b\00014\000"
-"\\bdecimo\\s+quinto\\b\00015\000"
-"\\bdecimo\\s+setimo\\b\00017\000"
-"\\bvinte\\s+e\\s+cinco\\b\00025\000"
-"\\bdecimo\\s+sexto\\b\00016\000"
-"\\bminas\\s+gerais\\b\000mg\000"
-"\\bvinte\\s+e\\s+dois\\b\00022\000"
-"\\bvinte\\s+e\\s+nove\\b\00029\000"
-"\\bvinte\\s+e\\s+oito\\b\00028\000"
-"\\bvinte\\s+e\\s+seis\\b\00026\000"
-"\\bvinte\\s+e\\s+sete\\b\00027\000"
-"\\bvinte\\s+e\\s+tres\\b\00023\000"
-"\\bdecimo\\s+nono\\b\00019\000"
-"\\bmato\\s+grosso\\b\000mt\000"
-"\\bcomandante\\b\000com\000"
-"\\bgovernador\\b\000gov\000"
-"\\bpernambuco\\b\000pe\000"
-"\\bpresidente\\b\000pres\000"
-"\\bvinte\\s+e\\s+um\\b\00021\000"
-"\\bcinquenta\\b\00050\000"
-"\\bdezesseis\\b\00016\000"
-"\\bdezessete\\b\00017\000"
-"\\bduodecimo\\b\00012\000"
-"\\bprofessor\\b\000prof\000"
-"\\brepublica\\b\000rep\000"
-"\\bsao\\s+paulo\\b\000sp\000"
-"\\btocantins\\b\000to\000"
-"\\bamazonas\\b\000am\000"
-"\\bdezenove\\b\00019\000"
-"\\bmaranhao\\b\000ma\000"
-"\\bprimeiro\\b\0001\000"
-"\\bprincesa\\b\000prsa\000"
-"\\bquarenta\\b\00040\000"
-"\\brondonia\\b\000ro\000"
-"\\bsargento\\b\000sct\000"
-"\\bsessenta\\b\00060\000"
-"\\bterceiro\\b\0003\000"
-"\\bvigesimo\\b\00020\000"
-"\\balagoas\\b\000al\000"
-"\\balameda\\b\000al\000"
-"\\bavenida\\b\000av\000"
-"\\bcatorze\\b\00014\000"
-"\\bcoronel\\b\000cel\000"
-"\\bdezoito\\b\00018\000"
-"\\bestrada\\b\000estr\000"
-"\\bnoventa\\b\00090\000"
-"\\boitenta\\b\00080\000"
-"\\bparaiba\\b\000pb\000"
-"\\broraima\\b\000rr\000"
-"\\bsegundo\\b\0002\000"
-"\\bsenador\\b\000sen\000"
-"\\bsergipe\\b\000se\000"
-"\\bsetenta\\b\00070\000"
-"\\bbrasil\\b\000b\000"
-"\\bbrazil\\b\000b\000"
-"\\bdecimo\\b\000x\000"
-"\\bdoutor\\b\000dr\000"
-"\\boitavo\\b\0008\000"
-"\\bparana\\b\000pr\000"
-"\\bprincs\\b\000prsa\000"
-"\\bquarto\\b\0004\000"
-"\\bquatro\\b\0004\000"
-"\\bquinto\\b\0005\000"
-"\\bquinze\\b\00015\000"
-"\\bsetimo\\b\0007\000"
-"\\btrinta\\b\00030\000"
-"\\bamapa\\b\000ap\000"
-"\\bbahia\\b\000ba\000"
-"\\bbarao\\b\000b\000"
-"\\bceara\\b\000ce\000"
-"\\bcinco\\b\0005\000"
-"\\bconde\\b\000cde\000"
-"\\bduque\\b\000dq\000"
-"\\bgoias\\b\000go\000"
-"\\bnorte\\b\000n\000"
-"\\boeste\\b\000w\000"
-"\\bpadre\\b\000pe\000"
-"\\bpiaui\\b\000pi\000"
-"\\bsanta\\b\000sta\000"
-"\\bsexto\\b\0006\000"
-"\\btreze\\b\00013\000"
-"\\bviela\\b\000ve\000"
-"\\bvinte\\b\00020\000"
-"\\bacre\\b\000ac\000"
-"\\bbaia\\b\000ba\000"
-"\\bdois\\b\0002\000"
-"\\bdoze\\b\00012\000"
-"\\beste\\b\000e\000"
-"\\blote\\b\000lt\000"
-"\\bnono\\b\0009\000"
-"\\bnove\\b\0009\000"
-"\\boito\\b\0008\000"
-"\\bonze\\b\00011\000"
-"\\bpara\\b\000pa\000"
-"\\bsala\\b\000s\000"
-"\\bseis\\b\0006\000"
-"\\bsete\\b\0007\000"
-"\\btres\\b\0003\000"
-"\\bviii\\b\0008\000"
-"\\bcem\\b\000100\000"
-"\\bdas\\b\000\000"
-"\\bdez\\b\000x\000"
-"\\bdos\\b\000\000"
-"\\biii\\b\0003\000"
-"\\brua\\b\000r\000"
-"\\bsan\\b\000s\000"
-"\\bsgt\\b\000sct\000"
-"\\bsul\\b\000s\000"
-"\\bvii\\b\0007\000"
-"\\b10\\b\000x\000"
-"\\bbr\\b\000b\000"
-"\\bda\\b\000\000"
-"\\bde\\b\000\000"
-"\\bdo\\b\000\000"
-"\\bel\\b\000\000"
-"\\bii\\b\0002\000"
-"\\biv\\b\0004\000"
-"\\bix\\b\0009\000"
-"\\bsl\\b\000s\000"
-"\\bum\\b\0001\000"
-"\\bvi\\b\0006\000"
-"\\bvl\\b\000ve\000"
-"\\bi\\b\0001\000"
-"\\bv\\b\0005\000"
-;
-int kNumRules_BR = 135;
-
-const char* kRules_CA =
-"\\bdsl\\s+de\\s+grand\\s+sault\\s+falls\\s+grand\\s+sault\\s+grand\\s+falls\\b\000grand falls\000"
-"\\bsainte\\s+catherine\\s+de\\s+la\\s+jacques\\s+cartier\\b\000ste catherine de la j cartier\000"
-"\\bmadawaska\\s+maliseet\\s+frst\\s+nation\\b\000madawaska\000"
-"\\bregional\\s+county\\s+municipality\\b\000\000"
-"\\bshediac\\s+bridge\\s+shediac\\s+river\\b\000shediac bridge\000"
-"\\bnewfoundland\\s+and\\s+labrador\\b\000nl\000"
-"\\bterritoires\\s+du\\s+nord\\s+ouest\\b\000nt\000"
-"\\bdsl\\s+de\\s+grand\\s+sault\\s+falls\\b\000grand falls\000"
-"\\bregional\\s+municipality\\s+of\\b\000\000"
-"\\bgrand\\s+sault\\s+grand\\s+falls\\b\000grand falls\000"
-"\\bterre\\s+neuve\\s+et\\s+labrador\\b\000nl\000"
-"\\bbay\\s+de\\s+verde\\s+peninsula\\b\000bvd\000"
-"\\bile\\s+du\\s+prince\\s+edouard\\b\000pe\000"
-"\\bnorthwest\\s+territories\\b\000nt\000"
-"\\bregional\\s+municipality\\b\000\000"
-"\\bcolombie\\s+britannique\\b\000bc\000"
-"\\bprince\\s+edward\\s+island\\b\000pe\000"
-"\\bregional\\s+district\\s+of\\b\000\000"
-"\\bfrench\\s+village\\s+york\\b\000french village\000"
-"\\bhead\\s+of\\s+bay\\s+despoir\\b\000head bay d\'espoir\000"
-"\\bterritoire\\s+du\\s+yukon\\b\000yt\000"
-"\\bnouveau\\s+brunswick\\b\000nb\000"
-"\\bregional\\s+district\\b\000\000"
-"\\bbritish\\s+columbia\\b\000bc\000"
-"\\bcanton\\s+stanstead\\b\000stanstead\000"
-"\\bmd\\s+of\\s+bonnyville\\b\000bonnyville\000"
-"\\bnouvelle\\s+ecosse\\b\000ns\000"
-"\\bst\\s+george\\s+brant\\b\000saint george\000"
-"\\byukon\\s+territory\\b\000yt\000"
-"\\bchisholm\\s+mills\\b\000chisholm\000"
-"\\bsackville\\s+road\\b\000sackville\000"
-"\\bnational\\s+park\\b\000\000"
-"\\bnew\\s+brunswick\\b\000nb\000"
-"\\bplacentia\\s+bay\\b\000pb\000"
-"\\bbeaver\\s+brook\\b\000beaverbrook\000"
-"\\bmetropolitan\\b\000\000"
-"\\bnewfoundland\\b\000nl\000"
-"\\brichibouctou\\b\000richibucto\000"
-"\\bsaskatchewan\\b\000sk\000"
-"\\bfortune\\s+bay\\b\000fb\000"
-"\\bnova\\s+scotia\\b\000ns\000"
-"\\bsubdivision\\b\000subdiv\000"
-"\\bsutton\\s+west\\b\000sutton\000"
-"\\bterre\\s+neuve\\b\000nl\000"
-"\\btownship\\s+of\\b\000\000"
-"\\btrinity\\s+bay\\b\000tb\000"
-"\\bbelliveaus\\b\000belliveau\000"
-"\\bconcession\\b\000conc\000"
-"\\bcul\\s+de\\s+sac\\b\000cds\000"
-"\\bcul\\-de\\-sac\\b\000cds\000"
-"\\bde\\s+riviere\\b\000riviere\000"
-"\\bexpressway\\b\000expy\000"
-"\\bmackinnons\\b\000mckinnons\000"
-"\\bnorth\\s+side\\b\000northside\000"
-"\\bpine\\s+ridge\\b\000pineridge\000"
-"\\brond\\s+point\\b\000rdpt\000"
-"\\brond\\-point\\b\000rdpt\000"
-"\\balternate\\b\000alt\000"
-"\\bautoroute\\b\000aut\000"
-"\\bboulevard\\b\000blvd\000"
-"\\bcarrefour\\b\000carref\000"
-"\\bcounty\\s+of\\b\000\000"
-"\\bcroissant\\b\000crois\000"
-"\\bdiversion\\b\000divers\000"
-"\\bechangeur\\b\000ech\000"
-"\\besplanade\\b\000espl\000"
-"\\bextension\\b\000exten\000"
-"\\bhalf\\s+moon\\b\000halfmoon\000"
-"\\bhighlands\\b\000hghlds\000"
-"\\bkuskonook\\b\000kuskanook\000"
-"\\bpromenade\\b\000prom\000"
-"\\bturnabout\\b\000trnabt\000"
-"\\bbusiness\\b\000bus\000"
-"\\bcrescent\\b\000cres\000"
-"\\bcrossing\\b\000cross\000"
-"\\bjunction\\b\000\000"
-"\\bmanitoba\\b\000mb\000"
-"\\bmountain\\b\000mtn\000"
-"\\boak\\s+hill\\b\000oakhill\000"
-"\\bpleasent\\b\000pleasant\000"
-"\\bterrasse\\b\000tsse\000"
-"\\btownline\\b\000tline\000"
-"\\btownship\\b\000\000"
-"\\balberta\\b\000ab\000"
-"\\bby\\s+pass\\b\000bypass\000"
-"\\bcircuit\\b\000circt\000"
-"\\bcity\\s+of\\b\000\000"
-"\\bcorners\\b\000crnrs\000"
-"\\bestates\\b\000estate\000"
-"\\bfreeway\\b\000fwy\000"
-"\\bgardens\\b\000gdns\000"
-"\\bgrounds\\b\000grnds\000"
-"\\bharbour\\b\000harbr\000"
-"\\bheights\\b\000hts\000"
-"\\bherbert\\b\000hebert\000"
-"\\bhighway\\b\000hwy\000"
-"\\bimpasse\\b\000imp\000"
-"\\bkeenans\\b\000keenan\000"
-"\\bl\'islet\\b\000\000"
-"\\bla\\s+have\\b\000lahave\000"
-"\\blanding\\b\000landng\000"
-"\\blookout\\b\000lkout\000"
-"\\bnarrows\\b\000\000"
-"\\bnunavut\\b\000nu\000"
-"\\bontario\\b\000on\000"
-"\\borchard\\b\000orch\000"
-"\\bparkway\\b\000pky\000"
-"\\bpassage\\b\000pass\000"
-"\\bpathway\\b\000ptway\000"
-"\\bplateau\\b\000plat\000"
-"\\breserve\\b\000\000"
-"\\bsentier\\b\000sent\000"
-"\\bstation\\b\000\000"
-"\\bterrace\\b\000terr\000"
-"\\bthicket\\b\000thick\000"
-"\\btown\\s+of\\b\000\000"
-"\\bvillage\\b\000\000"
-"\\bavenue\\b\000av\000"
-"\\bbakers\\b\000baker\000"
-"\\bcanada\\b\000ca\000"
-"\\bcanton\\b\000\000"
-"\\bcenter\\b\000\000"
-"\\bcentre\\b\000\000"
-"\\bchemin\\b\000ch\000"
-"\\bcircle\\b\000cir\000"
-"\\bcounty\\b\000\000"
-"\\bharbor\\b\000harbr\000"
-"\\bisland\\b\000\000"
-"\\bl\'isle\\b\000isle\000"
-"\\blimits\\b\000lmts\000"
-"\\bmackay\\b\000mckay\000"
-"\\bmcgrey\\b\000mcgray\000"
-"\\bpointe\\b\000pte\000"
-"\\bquebec\\b\000qc\000"
-"\\bruelle\\b\000rle\000"
-"\\bsainte\\b\000\000"
-"\\bsiding\\b\000\000"
-"\\bsmiths\\b\000smith\000"
-"\\bsquare\\b\000sq\000"
-"\\bstreet\\b\000\000"
-"\\bvalley\\b\000\000"
-"\\bcarre\\b\000car\000"
-"\\bclose\\b\000cl\000"
-"\\bcourt\\b\000crt\000"
-"\\bdrive\\b\000dr\000"
-"\\bfirst\\b\000fst\000"
-"\\bforks\\b\000\000"
-"\\bgrove\\b\000grv\000"
-"\\bmanns\\b\000mann\000"
-"\\bmetro\\b\000\000"
-"\\bmount\\b\000mt\000"
-"\\bnorth\\b\000n\000"
-"\\bouest\\b\000o\000"
-"\\bplace\\b\000pl\000"
-"\\bpoint\\b\000pt\000"
-"\\brange\\b\000rg\000"
-"\\broute\\b\000rt\000"
-"\\bsaint\\b\000\000"
-"\\bsouth\\b\000s\000"
-"\\btrail\\b\000trl\000"
-"\\byukon\\b\000yt\000"
-"\\bboul\\b\000blvd\000"
-"\\bcity\\b\000\000"
-"\\bcove\\b\000\000"
-"\\beast\\b\000\000"
-"\\bfrst\\b\000fst\000"
-"\\blake\\b\000\000"
-"\\blane\\b\000ln\000"
-"\\bnord\\b\000n\000"
-"\\bpark\\b\000\000"
-"\\bpkwy\\b\000pky\000"
-"\\broad\\b\000\000"
-"\\bwest\\b\000o\000"
-"\\bave\\b\000av\000"
-"\\bbay\\b\000\000"
-"\\bbdv\\b\000\000"
-"\\bblp\\b\000\000"
-"\\bcan\\b\000ca\000"
-"\\bcbd\\b\000\000"
-"\\bctr\\b\000\000"
-"\\bdes\\b\000\000"
-"\\bere\\b\000\000"
-"\\best\\b\000\000"
-"\\bile\\b\000\000"
-"\\blab\\b\000\000"
-"\\bndb\\b\000\000"
-"\\bnth\\b\000n\000"
-"\\bont\\b\000on\000"
-"\\bpei\\b\000pe\000"
-"\\brte\\b\000rt\000"
-"\\bsal\\b\000\000"
-"\\bsmb\\b\000\000"
-"\\bste\\b\000\000"
-"\\bsth\\b\000s\000"
-"\\bsud\\b\000s\000"
-"\\bbb\\b\000\000"
-"\\bcb\\b\000\000"
-"\\bco\\b\000\000"
-"\\bd\'\\b\000\000"
-"\\bde\\b\000\000"
-"\\bdu\\b\000\000"
-"\\ber\\b\000\000"
-"\\bfn\\b\000\000"
-"\\bgb\\b\000\000"
-"\\bnd\\b\000\000"
-"\\bpk\\b\000\000"
-"\\brd\\b\000\000"
-"\\bre\\b\000\000"
-"\\bst\\b\000\000"
-"\\bth\\b\000\000"
-"\\bwb\\b\000\000"
-"\\bc\\b\000\000"
-"\\bd\\b\000\000"
-"\\be\\b\000\000"
-"\\bw\\b\000o\000"
-;
-int kNumRules_CA = 215;
-
-const char* kRules_CH =
-"\\bappenzell\\s+rhodes\\s+exterieures\\b\000ar\000"
-"\\bappenzell\\s+ausserrhoden\\b\000ar\000"
-"\\bappenzell\\s+innerrhoden\\b\000ai\000"
-"\\bjura\\s+north\\s+vaudois\\b\000jura nord vaudois\000"
-"\\bprettigovia\\s+davos\\b\000davos\000"
-"\\bbasel\\s+landschaft\\b\000bl\000"
-"\\bprattigau\\s+davos\\b\000davos\000"
-"\\bsankt\\s+silvester\\b\000st silvester\000"
-"\\bbale\\s+campagne\\b\000bl\000"
-"\\bbasilea\\s+citta\\b\000bs\000"
-"\\bsankt\\s+stephan\\b\000st stephan\000"
-"\\bwallis\\s+valais\\b\000vs\000"
-"\\bdix\\s+huitieme\\b\00018\000"
-"\\bdix\\s+neuvieme\\b\00019\000"
-"\\bdix\\s+septieme\\b\00017\000"
-"\\bsaint\\s+gallen\\b\000sg\000"
-"\\bsankt\\s+gallen\\b\000sg\000"
-"\\bschaffhausen\\b\000sh\000"
-"\\bbasel\\s+stadt\\b\000bs\000"
-"\\bbelinzonese\\b\000bellinzona\000"
-"\\bquatorzieme\\b\00014\000"
-"\\bsaint\\s+gallo\\b\000sg\000"
-"\\bsan\\s+nazzaro\\b\000s nazzaro\000"
-"\\bsan\\s+vittore\\b\000s vittore\000"
-"\\bsankt\\s+gallo\\b\000sg\000"
-"\\bschaffhouse\\b\000sh\000"
-"\\bswitzerland\\b\000ch\000"
-"\\bwinterthour\\b\000winterthur\000"
-"\\bbale\\s+ville\\b\000bs\000"
-"\\bbasel\\s+city\\b\000bs\000"
-"\\bbasel\\s+land\\b\000bl\000"
-"\\bbasel\\s+stad\\b\000bs\000"
-"\\bbazel\\s+stad\\b\000bs\000"
-"\\bbellinzone\\b\000bellinzona\000"
-"\\benclave\\s+de\\b\000\000"
-"\\bgraubunden\\b\000gr\000"
-"\\bsaint\\s+gall\\b\000sg\000"
-"\\bsan\\s+gallen\\b\000sg\000"
-"\\bsankt\\s+gall\\b\000sg\000"
-"\\bst\\.\\s+gallen\\b\000sg\000"
-"\\bvaud\\s+waadt\\b\000vd\000"
-"\\bwaadt\\s+vaud\\b\000vd\000"
-"\\bcinquieme\\b\0005\000"
-"\\blaufental\\b\000laufen\000"
-"\\bneuchatel\\b\000ne\000"
-"\\bneuenburg\\b\000ne\000"
-"\\bnidwalden\\b\000nw\000"
-"\\bquatrieme\\b\0004\000"
-"\\bquinzieme\\b\00015\000"
-"\\bsan\\s+gallo\\b\000sg\000"
-"\\bsciaffusa\\b\000sh\000"
-"\\bsolothurn\\b\000so\000"
-"\\bst\\s+gallen\\b\000sg\000"
-"\\bst\\.\\s+gallo\\b\000sg\000"
-"\\bthurgovia\\b\000tg\000"
-"\\bthurgovie\\b\000tg\000"
-"\\btreizieme\\b\00013\000"
-"\\btroisieme\\b\0003\000"
-"\\bvingtieme\\b\00020\000"
-"\\bd\\\\\'uster\\b\000uster\000"
-"\\bdeuxieme\\b\0002\000"
-"\\bdouzieme\\b\00012\000"
-"\\bfreiburg\\b\000fr\000"
-"\\bfribourg\\b\000fr\000"
-"\\bfriburgo\\b\000fr\000"
-"\\bgessenay\\b\000saanen\000"
-"\\bgrigioni\\b\000gr\000"
-"\\bhuitieme\\b\0008\000"
-"\\bmaloggia\\b\000maloja\000"
-"\\bneuvieme\\b\0009\000"
-"\\bnidvaldo\\b\000nw\000"
-"\\bobwalden\\b\000ow\000"
-"\\bpremiere\\b\0001\000"
-"\\bsan\\s+gall\\b\000sg\000"
-"\\bseizieme\\b\00016\000"
-"\\bseptieme\\b\0007\000"
-"\\bst\\s+gallo\\b\000sg\000"
-"\\bst\\.\\s+gall\\b\000sg\000"
-"\\bturgovia\\b\000tg\000"
-"\\bzofingue\\b\000zofingen\000"
-"\\bargovia\\b\000ag\000"
-"\\bargovie\\b\000ag\000"
-"\\bdixieme\\b\000x\000"
-"\\bfriburg\\b\000fr\000"
-"\\bginevra\\b\000ge\000"
-"\\bglarona\\b\000gl\000"
-"\\bgrisons\\b\000gr\000"
-"\\blucerna\\b\000lu\000"
-"\\blucerne\\b\000lu\000"
-"\\bnidwald\\b\000nw\000"
-"\\bobvaldo\\b\000ow\000"
-"\\bonzieme\\b\00011\000"
-"\\bschweiz\\b\000ch\000"
-"\\bschwytz\\b\000sz\000"
-"\\bsixieme\\b\0006\000"
-"\\bsoletta\\b\000so\000"
-"\\bsoleure\\b\000so\000"
-"\\bst\\s+gall\\b\000sg\000"
-"\\bthurgau\\b\000tg\000"
-"\\bturicum\\b\000zh\000"
-"\\bvallais\\b\000vs\000"
-"\\bvallese\\b\000vs\000"
-"\\bzuerich\\b\000zh\000"
-"\\baargau\\b\000ag\000"
-"\\bbienna\\b\000biel\000"
-"\\bbienne\\b\000biel\000"
-"\\bbrigue\\b\000brig\000"
-"\\bgeneva\\b\000ge\000"
-"\\bgeneve\\b\000ge\000"
-"\\bglaris\\b\000gl\000"
-"\\bglarus\\b\000gl\000"
-"\\blaufon\\b\000laufen\000"
-"\\bluzern\\b\000lu\000"
-"\\bobwald\\b\000ow\000"
-"\\bregion\\b\000\000"
-"\\bsainte\\b\000\000"
-"\\bschwyz\\b\000sz\000"
-"\\bsvitto\\b\000sz\000"
-"\\btessin\\b\000ti\000"
-"\\bthoune\\b\000thun\000"
-"\\bticino\\b\000ti\000"
-"\\bvalais\\b\000vs\000"
-"\\bwallis\\b\000vs\000"
-"\\bzurich\\b\000zh\000"
-"\\bzurigo\\b\000zh\000"
-"\\baaray\\b\000aarau\000"
-"\\bberna\\b\000be\000"
-"\\bberne\\b\000be\000"
-"\\bbriga\\b\000brig\000"
-"\\bde\\s+l\'\\b\000\000"
-"\\bde\\s+la\\b\000\000"
-"\\bet\\s+du\\b\000\000"
-"\\bgiura\\b\000ju\000"
-"\\bmount\\b\000mt\000"
-"\\bnorth\\b\000n\000"
-"\\bouest\\b\000o\000"
-"\\bsaint\\b\000\000"
-"\\bsouth\\b\000s\000"
-"\\bstadt\\b\000\000"
-"\\bviege\\b\000visp\000"
-"\\bwaadt\\b\000vd\000"
-"\\bxviii\\b\00018\000"
-"\\bbern\\b\000be\000"
-"\\bgenf\\b\000ge\000"
-"\\bieme\\b\000\000"
-"\\bjura\\b\000ju\000"
-"\\bnord\\b\000n\000"
-"\\bstad\\b\000\000"
-"\\bvaud\\b\000vd\000"
-"\\bviii\\b\0008\000"
-"\\bwest\\b\000o\000"
-"\\bxiii\\b\00013\000"
-"\\bxvii\\b\00017\000"
-"\\bzoug\\b\000zg\000"
-"\\bzugo\\b\000zg\000"
-"\\bdes\\b\000\000"
-"\\beme\\b\000\000"
-"\\bere\\b\000\000"
-"\\best\\b\000\000"
-"\\biii\\b\0003\000"
-"\\bles\\b\000\000"
-"\\bmte\\b\000mt\000"
-"\\bste\\b\000\000"
-"\\bsud\\b\000s\000"
-"\\bsur\\b\000\000"
-"\\buri\\b\000ur\000"
-"\\bvii\\b\0007\000"
-"\\bxii\\b\00012\000"
-"\\bxiv\\b\00014\000"
-"\\bxix\\b\00019\000"
-"\\bxvi\\b\00016\000"
-"\\bzug\\b\000zg\000"
-"\\b10\\b\000x\000"
-"\\bd\'\\b\000\000"
-"\\bde\\b\000\000"
-"\\bdu\\b\000\000"
-"\\ben\\b\000\000"
-"\\ber\\b\000\000"
-"\\bii\\b\0002\000"
-"\\bin\\b\000\000"
-"\\biv\\b\0004\000"
-"\\bix\\b\0009\000"
-"\\bl\'\\b\000\000"
-"\\bla\\b\000\000"
-"\\ble\\b\000\000"
-"\\bnd\\b\000\000"
-"\\bof\\b\000\000"
-"\\brd\\b\000\000"
-"\\bre\\b\000\000"
-"\\bst\\b\000\000"
-"\\bth\\b\000\000"
-"\\bvi\\b\0006\000"
-"\\bxi\\b\00011\000"
-"\\bxv\\b\00015\000"
-"\\bxx\\b\00020\000"
-"\\be\\b\000\000"
-"\\bi\\b\0001\000"
-"\\bv\\b\0005\000"
-"\\bw\\b\000o\000"
-;
-int kNumRules_CH = 199;
-
-const char* kRules_CL =
-"\\baisen\\s+del\\s+general\\s+carlos\\s+ibanez\\s+del\\s+campo\\b\00011\000"
-"\\blibertador\\s+general\\s+bernardo\\s+o\'higgins\\b\0006\000"
-"\\bmetropolitana\\s+de\\s+santiago\\s+de\\s+chile\\b\000rm\000"
-"\\bmagallanes\\s+y\\s+la\\s+antartica\\s+chilena\\b\00012\000"
-"\\bmetropolitana\\s+de\\s+santiago\\b\000rm\000"
-"\\barica\\s+y\\s+parinacota\\b\00015\000"
-"\\bmetropolitana\\b\000rm\000"
-"\\bla\\s+araucania\\b\0009\000"
-"\\bantofagasta\\b\0002\000"
-"\\bvalparaiso\\b\0005\000"
-"\\blos\\s+lagos\\b\000x\000"
-"\\bcoquimbo\\b\0004\000"
-"\\blos\\s+rios\\b\00014\000"
-"\\btarapaca\\b\0001\000"
-"\\batacama\\b\0003\000"
-"\\bbio\\s+bio\\b\0008\000"
-"\\bchile\\b\000cl\000"
-"\\bmaule\\b\0007\000"
-"\\bviii\\b\0008\000"
-"\\biii\\b\0003\000"
-"\\bvii\\b\0007\000"
-"\\bxii\\b\00012\000"
-"\\bxiv\\b\00014\000"
-"\\b10\\b\000x\000"
-"\\bii\\b\0002\000"
-"\\biv\\b\0004\000"
-"\\bix\\b\0009\000"
-"\\bvi\\b\0006\000"
-"\\bxi\\b\00011\000"
-"\\bxv\\b\00015\000"
-"\\bi\\b\0001\000"
-"\\bv\\b\0005\000"
-;
-int kNumRules_CL = 32;
-
-const char* kRules_CO =
-"\\bcolombia\\b\000co\000"
-"\\bcolumbia\\b\000co\000"
-;
-int kNumRules_CO = 2;
-
-const char* kRules_DE =
-"\\bfederal\\s+republic\\s+of\\s+germany\\b\000de\000"
-"\\bbundesrepublik\\s+deutschland\\b\000de\000"
-"\\bfreie\\s+hansestadt\\s+bremen\\b\000hb\000"
-"\\bmecklenburg\\s+vorpommern\\b\000mv\000"
-"\\bnorth\\s+rhine\\s+westphalia\\b\000nw\000"
-"\\brhineland\\s+palatinate\\b\000rp\000"
-"\\bnordrhein\\s+westfalen\\b\000nw\000"
-"\\bschleswig\\s+holstein\\b\000sh\000"
-"\\bbaden\\s+wurttemberg\\b\000bw\000"
-"\\bregionalverband\\b\000\000"
-"\\brheinland\\s+pfalz\\b\000rp\000"
-"\\bsachsen\\s+anhalt\\b\000st\000"
-"\\bniedersachsen\\b\000ni\000"
-"\\bsaxony\\s+anhalt\\b\000st\000"
-"\\blower\\s+saxony\\b\000ni\000"
-"\\bstadtverband\\b\000\000"
-"\\bbrandenburg\\b\000bb\000"
-"\\bdeutschland\\b\000de\000"
-"\\blandkreis\\b\000\000"
-"\\bthuringen\\b\000th\000"
-"\\bthuringia\\b\000th\000"
-"\\bsaarland\\b\000sl\000"
-"\\bbavaria\\b\000by\000"
-"\\bcologne\\b\000koln\000"
-"\\bgermany\\b\000de\000"
-"\\bhamburg\\b\000hh\000"
-"\\bsachsen\\b\000sn\000"
-"\\bstrasse\\b\000str\000"
-"\\bbayern\\b\000by\000"
-"\\bberlin\\b\000be\000"
-"\\bbremen\\b\000hb\000"
-"\\bhessen\\b\000he\000"
-"\\bsaxony\\b\000sn\000"
-"\\bsudost\\b\000se\000"
-"\\bhesse\\b\000he\000"
-"\\bsankt\\b\000st\000"
-"\\bstadt\\b\000\000"
-"\\bnord\\b\000n\000"
-"\\bwest\\b\000w\000"
-"\\bost\\b\000o\000"
-"\\bsud\\b\000s\000"
-;
-int kNumRules_DE = 41;
-
-const char* kRules_DK =
-"\\bgrabrodrestraede\\b\000grabrodrestr\000"
-"\\barnold\\s+nielsens\\b\000arn nielsens\000"
-"\\bhaveforeningen\\b\000haveforening\000"
-"\\bmunicipality\\b\000\000"
-"\\bbispebjergs\\b\000bispebjerg\000"
-"\\btengslemark\\b\000tengslemrk\000"
-"\\bboulevard\\b\000boul\000"
-"\\blillerod\\b\000allerod\000"
-"\\bdanmark\\b\000dk\000"
-"\\bdenmark\\b\000dk\000"
-"\\bkommune\\b\000\000"
-"\\bkvarter\\b\000kvater\000"
-"\\bpladsen\\b\000plads\000"
-"\\bboulev\\b\000boul\000"
-"\\bgammel\\b\000gl\000"
-"\\blokken\\b\000lokke\000"
-"\\bnummer\\b\000nr\000"
-"\\bsondre\\b\000s\000"
-"\\bgamle\\b\000gl\000"
-"\\bnorre\\b\000n\000"
-"\\bsankt\\b\000sct\000"
-"\\bnord\\b\000n\000"
-"\\bvest\\b\000v\000"
-"\\bndr\\b\000n\000"
-"\\bost\\b\000o\000"
-"\\bsdr\\b\000s\000"
-"\\bskt\\b\000sct\000"
-"\\bsyd\\b\000s\000"
-;
-int kNumRules_DK = 28;
-
-const char* kRules_ES =
-"\\bsanta\\s+cruz\\s+de\\s+tenerife\\b\000tf\000"
-"\\bbalearic\\s+islands\\b\000pm\000"
-"\\bislas\\s+baleares\\b\000pm\000"
-"\\billes\\s+balears\\b\000pm\000"
-"\\bciudad\\s+real\\b\000cr\000"
-"\\bguadalajara\\b\000gu\000"
-"\\bla\\s+corunna\\b\000c\000"
-"\\bla\\s+corunya\\b\000c\000"
-"\\blas\\s+palmas\\b\000gc\000"
-"\\bpontevedra\\b\000po\000"
-"\\bvalladolid\\b\000va\000"
-"\\bbarcelona\\b\000b\000"
-"\\bcantabria\\b\000s\000"
-"\\bcastellon\\b\000cs\000"
-"\\besplugues\\b\000esplugas\000"
-"\\bguipuscoa\\b\000ss\000"
-"\\bguipuzcoa\\b\000ss\000"
-"\\bla\\s+coruna\\b\000c\000"
-"\\bsalamanca\\b\000sa\000"
-"\\bsaragossa\\b\000z\000"
-"\\btarragona\\b\000t\000"
-"\\ba\\s+coruna\\b\000c\000"
-"\\balbacete\\b\000ab\000"
-"\\balicante\\b\000\000"
-"\\basturias\\b\000o\000"
-"\\bcastello\\b\000cs\000"
-"\\bgipuzkoa\\b\000ss\000"
-"\\bla\\s+rioja\\b\000lo\000"
-"\\bnafarroa\\b\000na\000"
-"\\bpalencia\\b\000p\000"
-"\\bvalencia\\b\000v\000"
-"\\bzaragoza\\b\000z\000"
-"\\balacant\\b\000\000"
-"\\balmeria\\b\000\000"
-"\\bavenida\\b\000av\000"
-"\\bbadajoz\\b\000ba\000"
-"\\bbizkaia\\b\000bi\000"
-"\\bcaceres\\b\000cc\000"
-"\\bcordoba\\b\000co\000"
-"\\bcordova\\b\000co\000"
-"\\bgranada\\b\000gr\000"
-"\\bnavarra\\b\000na\000"
-"\\bnavarre\\b\000na\000"
-"\\bourense\\b\000or\000"
-"\\bsegovia\\b\000sg\000"
-"\\bsevilla\\b\000se\000"
-"\\bseville\\b\000se\000"
-"\\bvizcaya\\b\000bi\000"
-"\\bbiscay\\b\000bi\000"
-"\\bburgos\\b\000bu\000"
-"\\bcoruna\\b\000c\000"
-"\\bcuenca\\b\000cu\000"
-"\\bespana\\b\000es\000"
-"\\bgerona\\b\000gi\000"
-"\\bgirona\\b\000gi\000"
-"\\bhuelva\\b\000h\000"
-"\\bhuesca\\b\000hu\000"
-"\\blerida\\b\000\000"
-"\\blleida\\b\000\000"
-"\\bmadrid\\b\000m\000"
-"\\bmalaga\\b\000ma\000"
-"\\bmurcia\\b\000mu\000"
-"\\borense\\b\000or\000"
-"\\bteruel\\b\000te\000"
-"\\btoledo\\b\000to\000"
-"\\bzamora\\b\000za\000"
-"\\balava\\b\000vi\000"
-"\\baraba\\b\000vi\000"
-"\\bavila\\b\000av\000"
-"\\bcadiz\\b\000ca\000"
-"\\bnorte\\b\000n\000"
-"\\bnorth\\b\000n\000"
-"\\boeste\\b\000o\000"
-"\\bsoria\\b\000so\000"
-"\\bsouth\\b\000s\000"
-"\\bspain\\b\000es\000"
-"\\beast\\b\000e\000"
-"\\beste\\b\000e\000"
-"\\bjaen\\b\000j\000"
-"\\bleon\\b\000le\000"
-"\\blugo\\b\000lu\000"
-"\\bwest\\b\000o\000"
-"\\bc\\.\\/\\b\000c\000"
-"\\bc\\/\\.\\b\000c\000"
-"\\bdal\\b\000\000"
-"\\bdel\\b\000\000"
-"\\blas\\b\000\000"
-"\\bles\\b\000\000"
-"\\blos\\b\000\000"
-"\\bsur\\b\000s\000"
-"\\bal\\b\000\000"
-"\\bc\\/\\b\000c\000"
-"\\bde\\b\000\000"
-"\\bel\\b\000\000"
-"\\ben\\b\000\000"
-"\\bla\\b\000\000"
-"\\bof\\b\000\000"
-"\\ba\\b\000\000"
-"\\bd\\b\000\000"
-"\\bl\\b\000\000"
-;
-int kNumRules_ES = 100;
-
-const char* kRules_FR =
-"\\bprovence\\s+alpes\\s+cote\\s+d\\s+azur\\b\000u\000"
-"\\balpes\\s+de\\s+haute\\s+provence\\b\00004\000"
-"\\barnouville\\s+les\\s+gonesse\\b\000arnouville\000"
-"\\bterritoire\\s+de\\s+belfort\\b\00090\000"
-"\\blanguedoc\\s+roussillon\\b\000k\000"
-"\\bpyrenees\\s+atlantiques\\b\00064\000"
-"\\bpyrenees\\s+orientales\\b\00066\000"
-"\\bmeurthe\\s+et\\s+moselle\\b\00054\000"
-"\\bnord\\s+pas\\s+de\\s+calais\\b\000o\000"
-"\\bchampagne\\s+ardenne\\b\000g\000"
-"\\bcharente\\s+maritime\\b\00017\000"
-"\\bseine\\s+saint\\s+denis\\b\00093\000"
-"\\bbouches\\s+du\\s+rhone\\b\00013\000"
-"\\bloire\\s+atlantique\\b\00044\000"
-"\\bpays\\s+de\\s+la\\s+loire\\b\000r\000"
-"\\bpoitou\\s+charentes\\b\000t\000"
-"\\balpes\\s+maritimes\\b\00006\000"
-"\\bbasse\\s+normandie\\b\000p\000"
-"\\bhaute\\s+normandie\\b\000q\000"
-"\\bille\\s+et\\s+vilaine\\b\00035\000"
-"\\btarn\\s+et\\s+garonne\\b\00082\000"
-"\\bdepartementale\\b\000d\000"
-"\\bhaute\\s+pyrenees\\b\00065\000"
-"\\bhauts\\s+de\\s+seine\\b\00092\000"
-"\\bindre\\s+et\\s+loire\\b\00037\000"
-"\\blot\\s+et\\s+garonne\\b\00047\000"
-"\\blower\\s+normandy\\b\000p\000"
-"\\bmaine\\s+et\\s+loire\\b\00049\000"
-"\\bsaone\\s+et\\s+loire\\b\00071\000"
-"\\bseine\\s+maritime\\b\00076\000"
-"\\bupper\\s+normandy\\b\000q\000"
-"\\bcotes\\s+d\\s+armor\\b\00022\000"
-"\\bdepartemental\\b\000d\000"
-"\\bfranche\\s+comte\\b\0001\000"
-"\\bhaute\\s+garonne\\b\00031\000"
-"\\bile\\s+de\\s+france\\b\000j\000"
-"\\bmidi\\s+pyrenees\\b\000n\000"
-"\\bpas\\s+de\\s+calais\\b\00062\000"
-"\\bseine\\s+et\\s+mame\\b\00077\000"
-"\\bcorse\\s+du\\s+sud\\b\0002a\000"
-"\\bdix\\s+huitieme\\b\00018\000"
-"\\bdix\\s+neuvieme\\b\00019\000"
-"\\bdix\\s+septieme\\b\00017\000"
-"\\beure\\s+et\\s+loir\\b\00028\000"
-"\\bhaute\\s+savoie\\b\00074\000"
-"\\bhaute\\s+vienne\\b\00087\000"
-"\\bloir\\s+et\\s+cher\\b\00041\000"
-"\\bval\\s+de\\s+marne\\b\00094\000"
-"\\bcouffouleux\\b\000coufouleux\000"
-"\\bdeux\\s+sevres\\b\00079\000"
-"\\bhaute\\s+alpes\\b\00005\000"
-"\\bhaute\\s+corse\\b\0002b\000"
-"\\bhaute\\s+loire\\b\00043\000"
-"\\bhaute\\s+marne\\b\00052\000"
-"\\bhaute\\s+saone\\b\00070\000"
-"\\bpuy\\s+de\\s+dome\\b\00063\000"
-"\\bquatorzieme\\b\00014\000"
-"\\brhone\\s+alpes\\b\0005\000"
-"\\bacquitaine\\b\000b\000"
-"\\benclave\\s+de\\b\000\000"
-"\\bval\\s+d\\s+oise\\b\00095\000"
-"\\baquitaine\\b\000b\000"
-"\\bboulevard\\b\000bd\000"
-"\\bbourgogne\\b\000d\000"
-"\\bcinquieme\\b\0005\000"
-"\\bcote\\s+d\\s+or\\b\00021\000"
-"\\bfinistere\\b\00029\000"
-"\\bhaut\\s+rhin\\b\00068\000"
-"\\bmoribihan\\b\00056\000"
-"\\bnationale\\b\000n\000"
-"\\bquatrieme\\b\0004\000"
-"\\bquinzieme\\b\00015\000"
-"\\btreizieme\\b\00013\000"
-"\\btroisieme\\b\0003\000"
-"\\bvingtieme\\b\00020\000"
-"\\ballemont\\b\000allemond\000"
-"\\bardennes\\b\00008\000"
-"\\bauvergne\\b\000c\000"
-"\\baveryron\\b\00012\000"
-"\\bbas\\s+rhin\\b\00067\000"
-"\\bbretagne\\b\000\000"
-"\\bbrittany\\b\000\000"
-"\\bburgundy\\b\000d\000"
-"\\bcalvados\\b\00014\000"
-"\\bcharente\\b\00016\000"
-"\\bdeuxieme\\b\0002\000"
-"\\bdordogne\\b\00024\000"
-"\\bdouzieme\\b\00012\000"
-"\\bhuitieme\\b\0008\000"
-"\\bla\\s+croix\\b\000lacroix\000"
-"\\blimousin\\b\000l\000"
-"\\blorraine\\b\000m\000"
-"\\bneuvieme\\b\0009\000"
-"\\bpicardie\\b\000s\000"
-"\\bpremiere\\b\0001\000"
-"\\bseizieme\\b\00016\000"
-"\\bseptieme\\b\0007\000"
-"\\bvaucluse\\b\00084\000"
-"\\byvelines\\b\00078\000"
-"\\bardeche\\b\00007\000"
-"\\bcorreze\\b\00019\000"
-"\\bcorsica\\b\000h\000"
-"\\bdixieme\\b\000x\000"
-"\\bessonne\\b\00091\000"
-"\\bgironde\\b\00033\000"
-"\\bherault\\b\00034\000"
-"\\bmayenne\\b\00053\000"
-"\\bmoselle\\b\00057\000"
-"\\bonzieme\\b\00011\000"
-"\\bpicardy\\b\000s\000"
-"\\bsixieme\\b\0006\000"
-"\\ballier\\b\00003\000"
-"\\balsace\\b\000a\000"
-"\\bariege\\b\00009\000"
-"\\bavenue\\b\000ave\000"
-"\\bcantal\\b\00015\000"
-"\\bcentre\\b\000f\000"
-"\\bcreuse\\b\00023\000"
-"\\bfrance\\b\000fr\000"
-"\\bgrande\\b\000gd\000"
-"\\blandes\\b\00040\000"
-"\\bloiret\\b\00045\000"
-"\\blozere\\b\00048\000"
-"\\bmanche\\b\00050\000"
-"\\bnievre\\b\00058\000"
-"\\bregion\\b\000\000"
-"\\bsainte\\b\000\000"
-"\\bsarthe\\b\00072\000"
-"\\bsavoie\\b\00073\000"
-"\\bvendee\\b\00085\000"
-"\\bvienne\\b\00086\000"
-"\\bvosges\\b\00088\000"
-"\\baisne\\b\00002\000"
-"\\bcorse\\b\000h\000"
-"\\bde\\s+l\'\\b\000\000"
-"\\bde\\s+la\\b\000\000"
-"\\bdoubs\\b\00025\000"
-"\\bdrome\\b\00026\000"
-"\\bet\\s+du\\b\000\000"
-"\\bgrand\\b\000gd\000"
-"\\bindre\\b\00036\000"
-"\\bisere\\b\00038\000"
-"\\bloire\\b\00042\000"
-"\\bmarne\\b\00051\000"
-"\\bmeuse\\b\00055\000"
-"\\bmount\\b\000mt\000"
-"\\bnorth\\b\000n\000"
-"\\bouest\\b\000o\000"
-"\\bparis\\b\000\000"
-"\\brhone\\b\00069\000"
-"\\bsaint\\b\000\000"
-"\\bsomme\\b\00080\000"
-"\\bsouth\\b\000s\000"
-"\\bvilla\\b\000vil\000"
-"\\bxviii\\b\00018\000"
-"\\byonne\\b\00089\000"
-"\\baude\\b\00011\000"
-"\\bcher\\b\00018\000"
-"\\beure\\b\00027\000"
-"\\bgard\\b\00030\000"
-"\\bgers\\b\00032\000"
-"\\bieme\\b\000\000"
-"\\bjura\\b\00039\000"
-"\\bnord\\b\000n\000"
-"\\boise\\b\00060\000"
-"\\borne\\b\00061\000"
-"\\btarn\\b\00081\000"
-"\\bviii\\b\0008\000"
-"\\bwest\\b\000o\000"
-"\\bxiii\\b\00013\000"
-"\\bxvii\\b\00017\000"
-"\\bain\\b\00001\000"
-"\\bdes\\b\000\000"
-"\\beme\\b\000\000"
-"\\bere\\b\000\000"
-"\\best\\b\000\000"
-"\\bgde\\b\000gd\000"
-"\\biii\\b\0003\000"
-"\\bles\\b\000\000"
-"\\blot\\b\00046\000"
-"\\bmte\\b\000mt\000"
-"\\bste\\b\000\000"
-"\\bsud\\b\000s\000"
-"\\bsur\\b\000\000"
-"\\bvar\\b\00083\000"
-"\\bvii\\b\0007\000"
-"\\bxii\\b\00012\000"
-"\\bxiv\\b\00014\000"
-"\\bxix\\b\00019\000"
-"\\bxvi\\b\00016\000"
-"\\b10\\b\000x\000"
-"\\b59\\b\000n\000"
-"\\b75\\b\000\000"
-"\\bd\'\\b\000\000"
-"\\bde\\b\000\000"
-"\\bdu\\b\000\000"
-"\\ben\\b\000\000"
-"\\ber\\b\000\000"
-"\\bgr\\b\000gd\000"
-"\\bii\\b\0002\000"
-"\\bin\\b\000\000"
-"\\biv\\b\0004\000"
-"\\bix\\b\0009\000"
-"\\bl\'\\b\000\000"
-"\\bla\\b\000\000"
-"\\ble\\b\000\000"
-"\\bnd\\b\000\000"
-"\\bof\\b\000\000"
-"\\brd\\b\000\000"
-"\\bre\\b\000\000"
-"\\bst\\b\000\000"
-"\\bth\\b\000\000"
-"\\bvi\\b\0006\000"
-"\\bxi\\b\00011\000"
-"\\bxv\\b\00015\000"
-"\\bxx\\b\00020\000"
-"\\be\\b\000\000"
-"\\bi\\b\0001\000"
-"\\bv\\b\0005\000"
-"\\bw\\b\000o\000"
-;
-int kNumRules_FR = 220;
-
-const char* kRules_GB =
-"\\bbath\\s+and\\s+north\\s+east\\s+somerset\\b\000gb-bas\000"
-"\\bdungannon\\s+and\\s+south\\s+tyrone\\b\000gb-dgn\000"
-"\\bcheshire\\s+west\\s+and\\s+chester\\b\000gb-chw\000"
-"\\bnewry\\s+and\\s+mourne\\s+district\\b\000gb-nym\000"
-"\\beast\\s+riding\\s+of\\s+yorkshire\\b\000gb-ery\000"
-"\\bmetropolitan\\s+borough\\s+of\\b\000\000"
-"\\bnorth\\s+east\\s+lincolnshire\\b\000gb-nel\000"
-"\\bhammersmith\\s+and\\s+fulham\\b\000gb-hmf\000"
-"\\bkensington\\s+and\\s+chelsea\\b\000gb-kec\000"
-"\\bwindsor\\s+and\\s+maidenhead\\b\000gb-wnm\000"
-"\\bblackburn\\s+with\\s+darwen\\b\000gb-bbd\000"
-"\\bdumfries\\s+and\\s+galloway\\b\000gb-dgy\000"
-"\\bsouth\\s+gloucestershire\\b\000gb-sgc\000"
-"\\bthe\\s+vale\\s+of\\s+glamorgan\\b\000gb-vgl\000"
-"\\bbarking\\s+and\\s+dagenham\\b\000gb-bdg\000"
-"\\bcentral\\s+bedfordshire\\b\000gb-cbf\000"
-"\\bkingston\\s+upon\\s+thames\\b\000gb-ktt\000"
-"\\bredcar\\s+and\\s+cleveland\\b\000gb-rcc\000"
-"\\brhondda\\,\\s+cynon\\,\\s+taff\\b\000gb-rct\000"
-"\\brichmond\\s+upon\\s+thames\\b\000gb-ric\000"
-"\\bthe\\s+scottish\\s+borders\\b\000gb-scb\000"
-"\\beast\\s+dunbartonshire\\b\000gb-edu\000"
-"\\bnewcastle\\s+upon\\s+tyne\\b\000gb-net\000"
-"\\bwest\\s+dunbartonshire\\b\000gb-wdu\000"
-"\\bkingston\\s+upon\\s+hull\\b\000gb-khl\000"
-"\\bliverpool\\s+district\\b\000gb-liv\000"
-"\\bnorth\\s+lincolnshire\\b\000gb-nln\000"
-"\\btelford\\s+and\\s+wrekin\\b\000gb-tfw\000"
-"\\bbrighton\\s+and\\s+hove\\b\000gb-bnh\000"
-"\\bcity\\s+of\\s+edinburgh\\b\000gb-edh\000"
-"\\beast\\s+renfrewshire\\b\000gb-erw\000"
-"\\bkirklees\\s+district\\b\000gb-kir\000"
-"\\blondon\\s+borough\\s+of\\b\000\000"
-"\\bneath\\s+port\\s+talbot\\b\000gb-ntl\000"
-"\\bnorth\\s+lanarkshire\\b\000gb-nlk\000"
-"\\bperth\\s+and\\s+kinross\\b\000gb-pkn\000"
-"\\bsouth\\s+lanarkshire\\b\000gb-slk\000"
-"\\bbracknell\\s+forest\\b\000gb-brc\000"
-"\\bclackmannanshire\\b\000gb-clk\000"
-"\\bisle\\s+of\\s+anglesey\\b\000gb-agy\000"
-"\\bnorthamptonshire\\b\000gb-nth\000"
-"\\bnorthern\\s+ireland\\b\000n.i.\000"
-"\\bshetland\\s+islands\\b\000gb-zet\000"
-"\\bstockton\\-on\\-tees\\b\000gb-stt\000"
-"\\bargyll\\s+and\\s+bute\\b\000gb-agb\000"
-"\\bbuckinghamshire\\b\000gb-bkm\000"
-"\\bcarmarthenshire\\b\000gb-cmn\000"
-"\\bcity\\s+of\\s+bristol\\b\000gb-bst\000"
-"\\bgloucestershire\\b\000gb-gls\000"
-"\\bnorth\\s+yorkshire\\b\000gb-nyk\000"
-"\\bnottinghamshire\\b\000gb-ntt\000"
-"\\bsefton\\s+district\\b\000gb-sft\000"
-"\\bsouthend\\-on\\-sea\\b\000gb-sos\000"
-"\\bcambridgeshire\\b\000gb-cam\000"
-"\\bcity\\s+of\\s+london\\b\000gb-lnd\000"
-"\\bleeds\\s+district\\b\000gb-lds\000"
-"\\bleicestershire\\b\000gb-lec\000"
-"\\bmerthyr\\s+tydfil\\b\000gb-mty\000"
-"\\bnorth\\s+ayrshire\\b\000gb-nay\000"
-"\\bnorth\\s+somerset\\b\000gb-nsm\000"
-"\\bnorth\\s+tyneside\\b\000gb-nty\000"
-"\\bnorthumberland\\b\000gb-nbl\000"
-"\\borkney\\s+islands\\b\000gb-ork\000"
-"\\bsouth\\s+ayrshire\\b\000gb-say\000"
-"\\bsouth\\s+tyneside\\b\000gb-sty\000"
-"\\bstoke\\-on\\-trent\\b\000gb-ste\000"
-"\\bwaltham\\s+forest\\b\000gb-wft\000"
-"\\bwest\\s+berkshire\\b\000gb-wbk\000"
-"\\bworcestershire\\b\000gb-wor\000"
-"\\baberdeen\\s+city\\b\000gb-abe\000"
-"\\baberdeenshire\\b\000gb-abd\000"
-"\\bblaenau\\s+gwent\\b\000gb-bgw\000"
-"\\bcarrickfergus\\b\000gb-ckf\000"
-"\\bcheshire\\s+east\\b\000gb-che\000"
-"\\bcounty\\s+durham\\b\000gb-dur\000"
-"\\beast\\s+ayrshire\\b\000gb-eay\000"
-"\\bherefordshire\\b\000gb-hef\000"
-"\\bhertfordshire\\b\000gb-hrt\000"
-"\\bisle\\s+of\\s+wight\\b\000gb-iow\000"
-"\\bmiddlesbrough\\b\000gb-mdb\000"
-"\\bmilton\\s+keynes\\b\000gb-mik\000"
-"\\bmonmouthshire\\b\000gb-mon\000"
-"\\bpembrokeshire\\b\000gb-pem\000"
-"\\bstaffordshire\\b\000gb-sts\000"
-"\\btower\\s+hamlets\\b\000gb-twh\000"
-"\\bwolverhampton\\b\000gb-wlv\000"
-"\\bdenbighshire\\b\000gb-den\000"
-"\\beast\\s+lothian\\b\000gb-eln\000"
-"\\bfulmodestone\\b\000fulmodeston\000"
-"\\bglasgow\\s+city\\b\000gb-glg\000"
-"\\blincolnshire\\b\000gb-lin\000"
-"\\bnewtownabbey\\b\000gb-nta\000"
-"\\bpeterborough\\b\000gb-pte\000"
-"\\brenfrewshire\\b\000gb-rfw\000"
-"\\bwarwickshire\\b\000gb-war\000"
-"\\bwest\\s+lothian\\b\000gb-wln\000"
-"\\bbournemouth\\b\000gb-bmh\000"
-"\\bcastlereagh\\b\000gb-csr\000"
-"\\bdundee\\s+city\\b\000gb-dnd\000"
-"\\bdunnamanagh\\b\000dunamanagh\000"
-"\\beast\\s+sussex\\b\000gb-esx\000"
-"\\beilean\\s+siar\\b\000gb-els\000"
-"\\bking\'s\\s+stag\\b\000king stag\000"
-"\\bmagherafelt\\b\000gb-mft\000"
-"\\boxfordshire\\b\000gb-oxf\000"
-"\\bsouthampton\\b\000gb-sth\000"
-"\\bwest\\s+sussex\\b\000gb-wsx\000"
-"\\bwestminster\\b\000gb-wsm\000"
-"\\bballymoney\\b\000gb-bly\000"
-"\\bbirmingham\\b\000gb-bir\000"
-"\\bborough\\s+of\\b\000\000"
-"\\bcaerphilly\\b\000gb-cay\000"
-"\\bcalderdale\\b\000gb-cld\000"
-"\\bceredigion\\b\000gb-cgn\000"
-"\\bculnacnock\\b\000culnacnoc\000"
-"\\bdarlington\\b\000gb-dal\000"
-"\\bderbyshire\\b\000gb-dby\000"
-"\\bflintshire\\b\000gb-fln\000"
-"\\bgroesllwyd\\b\000groes-lwyd\000"
-"\\bhartlepool\\b\000gb-hpl\000"
-"\\bhillingdon\\b\000gb-hil\000"
-"\\binverclyde\\b\000gb-ivc\000"
-"\\blancashire\\b\000gb-lan\000"
-"\\bmanchester\\b\000gb-man\000"
-"\\bmidlothian\\b\000gb-mln\000"
-"\\bn\\.\\s+ireland\\b\000n.i.\000"
-"\\bnorth\\s+down\\b\000gb-ndn\000"
-"\\bnottingham\\b\000gb-ngm\000"
-"\\bportsmouth\\b\000gb-por\000"
-"\\bshropshire\\b\000gb-shr\000"
-"\\bst\\.\\s+helens\\b\000gb-shn\000"
-"\\bsunderland\\b\000gb-snd\000"
-"\\bwandsworth\\b\000gb-wnd\000"
-"\\bwarrington\\b\000gb-wrt\000"
-"\\bballymena\\b\000gb-bla\000"
-"\\bbanbridge\\b\000gb-bnb\000"
-"\\bblackpool\\b\000gb-bpl\000"
-"\\bboulevard\\b\000blvd\000"
-"\\bcoleraine\\b\000gb-clr\000"
-"\\bcookstown\\b\000gb-ckt\000"
-"\\bcraigavon\\b\000gb-cgv\000"
-"\\bdoncaster\\b\000gb-dnc\000"
-"\\bfermanagh\\b\000gb-fer\000"
-"\\bgateshead\\b\000gb-gat\000"
-"\\bgreenwich\\b\000gb-gre\000"
-"\\bhampshire\\b\000gb-ham\000"
-"\\bislington\\b\000gb-isl\000"
-"\\bleicester\\b\000gb-lce\000"
-"\\bn\\s+ireland\\b\000n.i.\000"
-"\\bn\\.ireland\\b\000n.i.\000"
-"\\bredbridge\\b\000gb-rdb\000"
-"\\brotherham\\b\000gb-rot\000"
-"\\bsheffield\\b\000gb-shf\000"
-"\\bsouthwark\\b\000gb-swk\000"
-"\\bstockport\\b\000gb-skp\000"
-"\\bwakefield\\b\000gb-wkf\000"
-"\\bwiltshire\\b\000gb-wil\000"
-"\\bwokingham\\b\000gb-wok\000"
-"\\bbarnsley\\b\000gb-bns\000"
-"\\bbradford\\b\000gb-brd\000"
-"\\bbridgend\\b\000gb-bge\000"
-"\\bcheshire\\b\000gb-chs\000"
-"\\bcornwall\\b\000gb-con\000"
-"\\bcoventry\\b\000gb-cov\000"
-"\\bcrescent\\b\000cres\000"
-"\\bdistrict\\b\000\000"
-"\\bhare\\s+law\\b\000harelaw\000"
-"\\bharingey\\b\000gb-hry\000"
-"\\bhavering\\b\000gb-hav\000"
-"\\bhighland\\b\000gb-hld\000"
-"\\bhounslow\\b\000gb-hns\000"
-"\\bknowsley\\b\000gb-kwl\000"
-"\\blewisham\\b\000gb-lew\000"
-"\\blimavady\\b\000gb-lmv\000"
-"\\bplymouth\\b\000gb-ply\000"
-"\\brochdale\\b\000gb-rch\000"
-"\\bsandwell\\b\000gb-saw\000"
-"\\bscotland\\b\000gb-sct\000"
-"\\bsolihull\\b\000gb-sol\000"
-"\\bsomerset\\b\000gb-som\000"
-"\\bstirling\\b\000gb-stg\000"
-"\\bstrabane\\b\000gb-stb\000"
-"\\btameside\\b\000gb-tam\000"
-"\\bthurrock\\b\000gb-thr\000"
-"\\btrafford\\b\000gb-trf\000"
-"\\bbedford\\b\000gb-bdf\000"
-"\\bbelfast\\b\000gb-bfs\000"
-"\\bbromley\\b\000gb-bry\000"
-"\\bcardiff\\b\000gb-crf\000"
-"\\bcity\\s+of\\b\000\000"
-"\\bcroydon\\b\000gb-cry\000"
-"\\bcumbria\\b\000gb-cma\000"
-"\\benfield\\b\000gb-enf\000"
-"\\bengland\\b\000eng\000"
-"\\bfalkirk\\b\000gb-fal\000"
-"\\bgwynedd\\b\000gb-gwn\000"
-"\\bhackney\\b\000gb-hck\000"
-"\\bhighway\\b\000hwy\000"
-"\\blambeth\\b\000gb-lbh\000"
-"\\blisburn\\b\000gb-lsb\000"
-"\\bnewport\\b\000gb-nwp\000"
-"\\bnorfolk\\b\000gb-nfk\000"
-"\\bparkway\\b\000pkwy\000"
-"\\breading\\b\000gb-rdg\000"
-"\\brutland\\b\000gb-rut\000"
-"\\bsalford\\b\000gb-slf\000"
-"\\bsuffolk\\b\000gb-sfk\000"
-"\\bswansea\\b\000gb-swa\000"
-"\\bswindon\\b\000gb-swd\000"
-"\\btorfaen\\b\000gb-tof\000"
-"\\bwalsall\\b\000gb-wll\000"
-"\\bwrexham\\b\000gb-wrx\000"
-"\\bavenue\\b\000ave\000"
-"\\bcommon\\b\000comm\000"
-"\\bgb\\-ans\\b\000angus\000"
-"\\bgb\\-ant\\b\000antrim\000"
-"\\bgb\\-ard\\b\000ards\000"
-"\\bgb\\-arm\\b\000armagh\000"
-"\\bgb\\-ben\\b\000brent\000"
-"\\bgb\\-bex\\b\000bexley\000"
-"\\bgb\\-bne\\b\000barnet\000"
-"\\bgb\\-bol\\b\000bolton\000"
-"\\bgb\\-bur\\b\000bury\000"
-"\\bgb\\-cmd\\b\000camden\000"
-"\\bgb\\-cwy\\b\000conwy\000"
-"\\bgb\\-der\\b\000derby\000"
-"\\bgb\\-dev\\b\000devon\000"
-"\\bgb\\-dor\\b\000dorset\000"
-"\\bgb\\-dow\\b\000down\000"
-"\\bgb\\-dry\\b\000derry\000"
-"\\bgb\\-dud\\b\000dudley\000"
-"\\bgb\\-eal\\b\000ealing\000"
-"\\bgb\\-eng\\b\000eng\000"
-"\\bgb\\-ess\\b\000essex\000"
-"\\bgb\\-fif\\b\000fife\000"
-"\\bgb\\-ken\\b\000kent\000"
-"\\bgb\\-lrn\\b\000larne\000"
-"\\bgb\\-lut\\b\000luton\000"
-"\\bgb\\-mry\\b\000moray\000"
-"\\bgb\\-myl\\b\000moyle\000"
-"\\bgb\\-nir\\b\000n.i.\000"
-"\\bgb\\-omh\\b\000omagh\000"
-"\\bgb\\-pol\\b\000poole\000"
-"\\bgb\\-pow\\b\000powys\000"
-"\\bgb\\-wgn\\b\000wigan\000"
-"\\bgb\\-wls\\b\000wales\000"
-"\\bgb\\-yor\\b\000york\000"
-"\\bhalton\\b\000gb-hal\000"
-"\\bharrow\\b\000gb-hrw\000"
-"\\bmedway\\b\000gb-mdw\000"
-"\\bmerton\\b\000gb-mrt\000"
-"\\bnewham\\b\000gb-nwm\000"
-"\\boldham\\b\000gb-old\000"
-"\\bparade\\b\000pde\000"
-"\\bslough\\b\000gb-slg\000"
-"\\bstreet\\b\000st\000"
-"\\bsurrey\\b\000gb-sry\000"
-"\\bsutton\\b\000gb-stn\000"
-"\\btorbay\\b\000gb-tob\000"
-"\\bwirral\\b\000gb-wrl\000"
-"\\bcourt\\b\000ct\000"
-"\\bdrive\\b\000dr\000"
-"\\bmount\\b\000mt\000"
-"\\bnorth\\b\000n\000"
-"\\bplace\\b\000pl\000"
-"\\bpoint\\b\000pt\000"
-"\\bsaint\\b\000st\000"
-"\\bsouth\\b\000s\000"
-"\\beast\\b\000e\000"
-"\\bg\\.b\\.\\b\000gb\000"
-"\\blane\\b\000ln\000"
-"\\broad\\b\000rd\000"
-"\\bu\\.k\\.\\b\000gb\000"
-"\\bwest\\b\000w\000"
-"\\bg\\.b\\b\000gb\000"
-"\\bmt\\.\\b\000mt\000"
-"\\bnth\\b\000n\000"
-"\\bpt\\.\\b\000pt\000"
-"\\bst\\.\\b\000st\000"
-"\\bsth\\b\000s\000"
-"\\bu\\.k\\b\000gb\000"
-"\\be\\.\\b\000e\000"
-"\\bn\\.\\b\000n\000"
-"\\bs\\.\\b\000s\000"
-"\\buk\\b\000gb\000"
-"\\bw\\.\\b\000w\000"
-;
-int kNumRules_GB = 286;
-
-const char* kRules_GR =
-"\\banatoliki\\s+makedonia\\s+kai\\s+thraki\\b\000a\000"
-"\\baitolia\\s+kai\\s+akarnania\\b\00001\000"
-"\\bkentriki\\s+makedonia\\b\000b\000"
-"\\bdytiki\\s+makedonia\\b\000c\000"
-"\\baitoloakarnania\\b\00001\000"
-"\\bdytiki\\s+ellada\\b\000g\000"
-"\\bsterea\\s+ellada\\b\000h\000"
-"\\bvoreio\\s+aigaio\\b\000k\000"
-"\\bmetamorfossi\\b\000metamorfosi\000"
-"\\bnotio\\s+aigaio\\b\000l\000"
-"\\bpeloponnisos\\b\000j\000"
-"\\bthessaloniki\\b\00054\000"
-"\\bdodekanisos\\b\00081\000"
-"\\bionia\\s+nisia\\b\000f\000"
-"\\bkaissariani\\b\000kesariani\000"
-"\\banatolikos\\b\000e\000"
-"\\bchalkidiki\\b\00064\000"
-"\\bkefallonia\\b\00023\000"
-"\\bperifereia\\b\000periphery\000"
-"\\bthesprotia\\b\00032\000"
-"\\bagio\\s+oros\\b\00069\000"
-"\\bcholargos\\b\000holargos\000"
-"\\bevrytania\\b\00005\000"
-"\\bfthiotida\\b\00006\000"
-"\\bkorinthia\\b\00015\000"
-"\\bnomarchia\\b\000nomo\000"
-"\\bthessalia\\b\000e\000"
-"\\bzakynthos\\b\00021\000"
-"\\bargolida\\b\00011\000"
-"\\bchaidari\\b\000haidari\000"
-"\\bchalkida\\b\000halkida\000"
-"\\bioannina\\b\00033\000"
-"\\birakleio\\b\00091\000"
-"\\bkarditsa\\b\00041\000"
-"\\bkastoria\\b\00056\000"
-"\\bkifissia\\b\000kifisia\000"
-"\\bkyklades\\b\00082\000"
-"\\bmagnisia\\b\00043\000"
-"\\bmaroussi\\b\000marousi\000"
-"\\bmessinia\\b\00017\000"
-"\\brethymni\\b\00093\000"
-"\\brethymno\\b\00093\000"
-"\\banatoli\\b\000e\000"
-"\\barkadia\\b\00012\000"
-"\\bdytikos\\b\000w\000"
-"\\bflorina\\b\00063\000"
-"\\bgrevena\\b\00051\000"
-"\\bimathia\\b\00053\000"
-"\\bipeiros\\b\000d\000"
-"\\bkerkyra\\b\00022\000"
-"\\blakonia\\b\00016\000"
-"\\blasithi\\b\00092\000"
-"\\blefkada\\b\00024\000"
-"\\bpapagou\\b\000papagos\000"
-"\\bpiraeus\\b\000pireas\000"
-"\\bpreveza\\b\00034\000"
-"\\btrikala\\b\00044\000"
-"\\bvoiotia\\b\00003\000"
-"\\bvoreioy\\b\000n\000"
-"\\bachaia\\b\00013\000"
-"\\battiki\\b\000i\000"
-"\\bchania\\b\00094\000"
-"\\bevvoia\\b\00004\000"
-"\\bfokida\\b\00007\000"
-"\\bkavala\\b\00055\000"
-"\\bkilkis\\b\00057\000"
-"\\bkozani\\b\00058\000"
-"\\blarisa\\b\00042\000"
-"\\blesvos\\b\00083\000"
-"\\bnotioy\\b\000s\000"
-"\\bpieria\\b\00061\000"
-"\\brodopi\\b\00073\000"
-"\\bserres\\b\00062\000"
-"\\bvoreio\\b\000n\000"
-"\\bxanthi\\b\00072\000"
-"\\bchios\\b\00085\000"
-"\\bdrama\\b\00052\000"
-"\\bevros\\b\00071\000"
-"\\bhania\\b\00094\000"
-"\\bileia\\b\00014\000"
-"\\bkriti\\b\000m\000"
-"\\bnorth\\b\000n\000"
-"\\bnotio\\b\000s\000"
-"\\bpella\\b\00059\000"
-"\\bsamos\\b\00084\000"
-"\\bsouth\\b\000s\000"
-"\\barta\\b\00031\000"
-"\\bdysi\\b\000w\000"
-"\\beast\\b\000e\000"
-"\\bhios\\b\00085\000"
-"\\bkato\\b\000s\000"
-"\\bwest\\b\000w\000"
-"\\ba\\s+1\\b\000i\000"
-"\\bano\\b\000n\000"
-;
-int kNumRules_GR = 94;
-
-const char* kRules_HK =
-"\\bboulevard\\b\000blvd\000"
-"\\bhong\\s+kong\\b\000hk\000"
-"\\bcrescent\\b\000cres\000"
-"\\bdistrict\\b\000\000"
-"\\bhongkong\\b\000hk\000"
-"\\bjunction\\b\000jct\000"
-"\\bcentral\\b\000c\000"
-"\\bhighway\\b\000hwy\000"
-"\\bparkway\\b\000pkwy\000"
-"\\bseventh\\b\0007\000"
-"\\bavenue\\b\000ave\000"
-"\\bcentre\\b\000center\000"
-"\\bcommon\\b\000comm\000"
-"\\beighth\\b\0008\000"
-"\\bfourth\\b\0004\000"
-"\\bparade\\b\000pde\000"
-"\\bsecond\\b\0002\000"
-"\\bstreet\\b\000st\000"
-"\\bcourt\\b\000ct\000"
-"\\bdrive\\b\000dr\000"
-"\\beight\\b\0008\000"
-"\\bfifth\\b\0005\000"
-"\\bfirst\\b\0001\000"
-"\\bmount\\b\000mt\000"
-"\\bninth\\b\0009\000"
-"\\bnorth\\b\000n\000"
-"\\bplace\\b\000pl\000"
-"\\bpoint\\b\000pt\000"
-"\\bsaint\\b\000st\000"
-"\\bseven\\b\0007\000"
-"\\bsixth\\b\0006\000"
-"\\bsouth\\b\000s\000"
-"\\btenth\\b\00010\000"
-"\\bthird\\b\0003\000"
-"\\bthree\\b\0003\000"
-"\\beast\\b\000e\000"
-"\\bfive\\b\0005\000"
-"\\bfour\\b\0004\000"
-"\\blane\\b\000ln\000"
-"\\bnine\\b\0009\000"
-"\\broad\\b\000rd\000"
-"\\bwest\\b\000w\000"
-"\\bh\\s+k\\b\000hk\000"
-"\\bnth\\b\000n\000"
-"\\bone\\b\0001\000"
-"\\bsix\\b\0006\000"
-"\\bsth\\b\000s\000"
-"\\bten\\b\00010\000"
-"\\btwo\\b\0002\000"
-;
-int kNumRules_HK = 49;
-
-const char* kRules_ID =
-"\\bspecial\\s+region\\s+of\\s+yogyakarta\\b\000yo\000"
-"\\bnanggroe\\s+aceh\\s+darussalam\\b\000ac\000"
-"\\bbangka\\s+belitung\\s+islands\\b\000bb\000"
-"\\bnaggroe\\s+aceh\\s+darussalam\\b\000ac\000"
-"\\bspecial\\s+region\\s+of\\s+papua\\b\000pa\000"
-"\\bspecial\\s+region\\s+of\\s+aceh\\b\000ac\000"
-"\\bcentral\\s+kalimantan\\b\000kt\000"
-"\\bsoutheast\\s+sulawesi\\b\000sg\000"
-"\\bcentral\\s+sulawesi\\b\000st\000"
-"\\bbangka\\s+belitung\\b\000bb\000"
-"\\bjakarta\\s+pusat\\b\000jk\000"
-"\\bjakarta\\s+utara\\b\000jk\000"
-"\\bcentral\\s+java\\b\000jt\000"
-"\\briau\\s+islands\\b\000kr\000"
-"\\bdki\\s+jakarta\\b\000jk\000"
-"\\bjawa\\s+tengah\\b\000jt\000"
-"\\byogyakarta\\b\000yo\000"
-"\\bgorontalo\\b\000go\000"
-"\\bindonesia\\b\000id\000"
-"\\bbengkulu\\b\000be\000"
-"\\bnational\\b\000nasional\000"
-"\\bjakarta\\b\000jk\000"
-"\\blampung\\b\000la\000"
-"\\bselatan\\b\000s\000"
-"\\bbanten\\b\000bt\000"
-"\\bmaluku\\b\000ma\000"
-"\\bnumber\\b\000#\000"
-"\\bbarat\\b\000w\000"
-"\\bblock\\b\000blk\000"
-"\\bjalan\\b\000jl\000"
-"\\bjambi\\b\000ja\000"
-"\\bnorth\\b\000n\000"
-"\\bpapua\\b\000pa\000"
-"\\bsouth\\b\000s\000"
-"\\btimur\\b\000e\000"
-"\\butara\\b\000n\000"
-"\\bxviii\\b\00018\000"
-"\\baceh\\b\000ac\000"
-"\\bbali\\b\000ba\000"
-"\\bblk\\.\\b\000blk\000"
-"\\bblok\\b\000blk\000"
-"\\beast\\b\000e\000"
-"\\bjln\\.\\b\000jl\000"
-"\\briau\\b\000ri\000"
-"\\broad\\b\000rd\000"
-"\\bviii\\b\0008\000"
-"\\bwest\\b\000w\000"
-"\\bxiii\\b\00013\000"
-"\\bxvii\\b\00017\000"
-"\\biii\\b\0003\000"
-"\\bjl\\.\\b\000jl\000"
-"\\bjln\\b\000jl\000"
-"\\bno\\.\\b\000#\000"
-"\\bnum\\b\000#\000"
-"\\bvii\\b\0007\000"
-"\\bxii\\b\00012\000"
-"\\bxiv\\b\00014\000"
-"\\bxix\\b\00019\000"
-"\\bxvi\\b\00016\000"
-"\\b10\\b\000x\000"
-"\\bii\\b\0002\000"
-"\\biv\\b\0004\000"
-"\\bix\\b\0009\000"
-"\\bno\\b\000#\000"
-"\\bvi\\b\0006\000"
-"\\bxi\\b\00011\000"
-"\\bxv\\b\00015\000"
-"\\bxx\\b\00020\000"
-"\\bi\\b\0001\000"
-"\\bv\\b\0005\000"
-;
-int kNumRules_ID = 70;
-
-const char* kRules_IE =
-"\\broscommon\\b\000rn\000"
-"\\btipperary\\b\000ta\000"
-"\\bwaterford\\b\000wd\000"
-"\\bwestmeath\\b\000wh\000"
-"\\bkilkenny\\b\000kk\000"
-"\\blimerick\\b\000lk\000"
-"\\blongford\\b\000ld\000"
-"\\bmonaghan\\b\000mn\000"
-"\\bdonegal\\b\000dl\000"
-"\\bireland\\b\000ie\000"
-"\\bkildare\\b\000ke\000"
-"\\bleitrim\\b\000lm\000"
-"\\bterrace\\b\000tce\000"
-"\\bwexford\\b\000wx\000"
-"\\bwicklow\\b\000ww\000"
-"\\bavenue\\b\000ave\000"
-"\\bcarlow\\b\000cw\000"
-"\\bcenter\\b\000cntr\000"
-"\\bcounty\\b\000ck\000"
-"\\bdublin\\b\000d\000"
-"\\bgalway\\b\000g\000"
-"\\blaoise\\b\000ls\000"
-"\\boffaly\\b\000oy\000"
-"\\bstreet\\b\000st\000"
-"\\bcavan\\b\000cn\000"
-"\\bclare\\b\000ce\000"
-"\\bcourt\\b\000ct\000"
-"\\bdrive\\b\000dr\000"
-"\\bkerry\\b\000ky\000"
-"\\blaois\\b\000ls\000"
-"\\blouth\\b\000lh\000"
-"\\bmeath\\b\000mh\000"
-"\\bnorth\\b\000n\000"
-"\\bplace\\b\000pl\000"
-"\\bsaint\\b\000st\000"
-"\\bsligo\\b\000so\000"
-"\\bsouth\\b\000s\000"
-"\\bcork\\b\000ck\000"
-"\\beast\\b\000e\000"
-"\\blane\\b\000ln\000"
-"\\bmayo\\b\000mo\000"
-"\\broad\\b\000rd\000"
-"\\bwalk\\b\000wk\000"
-"\\bwest\\b\000w\000"
-"\\byard\\b\000yd\000"
-"\\bway\\b\000wy\000"
-"\\bco\\b\000ck\000"
-"\\bdn\\b\000d\000"
-"\\bgy\\b\000g\000"
-"\\bty\\b\000ta\000"
-;
-int kNumRules_IE = 50;
-
-const char* kRules_IN =
-"\\bthiruvananthapuram\\b\000tvpm\000"
-"\\bazimabad\\s+kusumpur\\b\000patna\000"
-"\\bjammu\\s+and\\s+kashmir\\b\000j&k\000"
-"\\btiruvananthapuram\\b\000tvpm\000"
-"\\bchandigarh\\s+city\\b\000ch\000"
-"\\bjammu\\s+\\&\\s+kashmir\\b\000j&k\000"
-"\\bgovt\\s+of\\s+india\\b\000goi\000"
-"\\binternational\\b\000intl\000"
-"\\bvisakhapatnam\\b\000vskp\000"
-"\\bchickmagalur\\b\000chicmagalur\000"
-"\\bchikmagaluru\\b\000chicmagalur\000"
-"\\bchikmagalur\\b\000chicmagalur\000"
-"\\bcross\\-roads\\b\000xrd\000"
-"\\bpataliputra\\b\000patna\000"
-"\\branga\\s+reddy\\b\000rangareddi\000"
-"\\bchandigarh\\b\000ch\000"
-"\\bcross\\-road\\b\000xrd\000"
-"\\bcrossroads\\b\000xrd\000"
-"\\bgovernment\\b\000goi\000"
-"\\bpatliputra\\b\000patna\000"
-"\\buniversity\\b\000uni\000"
-"\\bvijayawada\\b\000bza\000"
-"\\bahmedabad\\b\000ahd\000"
-"\\bbangalore\\b\000blr\000"
-"\\bbengaluru\\b\000blr\000"
-"\\bchar\\-rast\\b\000chaurah\000"
-"\\bchaurasta\\b\000chaurah\000"
-"\\bchourasta\\b\000chaurah\000"
-"\\bcrossroad\\b\000xrd\000"
-"\\bhyderabad\\b\000hyd\000"
-"\\bi\\.n\\.d\\.i\\.a\\b\000in\000"
-"\\bvijaywada\\b\000bza\000"
-"\\bcalcutta\\b\000kol\000"
-"\\bchourast\\b\000chaurah\000"
-"\\bchowrast\\b\000chaurah\000"
-"\\bcrossing\\b\000xrd\000"
-"\\bcrossrds\\b\000xrd\000"
-"\\bjunction\\b\000jn.\000"
-"\\bkolkatta\\b\000kol\000"
-"\\bvaranasi\\b\000banaras\000"
-"\\bamdavad\\b\000ahd\000"
-"\\bbenaras\\b\000banaras\000"
-"\\bchennai\\b\000che\000"
-"\\bcollege\\b\000clg\000"
-"\\bcrossrd\\b\000xrd\000"
-"\\bgateway\\b\000gtwy\000"
-"\\bheights\\b\000hts\000"
-"\\bkeralam\\b\000kl\000"
-"\\bkolkata\\b\000kol\000"
-"\\bkolkota\\b\000kol\000"
-"\\bseventh\\b\0007\000"
-"\\bvruttha\\b\000cir.\000"
-"\\bx\\s+roads\\b\000xrd\000"
-"\\bbombay\\b\000bom\000"
-"\\bcenter\\b\000cen\000"
-"\\bcentre\\b\000cen\000"
-"\\bchowdi\\b\000chok\000"
-"\\bcircle\\b\000cir.\000"
-"\\beighth\\b\0008\000"
-"\\bforest\\b\000frst\000"
-"\\bfourth\\b\0004\000"
-"\\bgarden\\b\000gdn\000"
-"\\bgatewy\\b\000gtwy\000"
-"\\bgatway\\b\000gtwy\000"
-"\\bheight\\b\000hts\000"
-"\\bkavala\\b\000jn.\000"
-"\\bkerala\\b\000kl\000"
-"\\bmadras\\b\000che\000"
-"\\bmumbai\\b\000bom\000"
-"\\bnumber\\b\000#\000"
-"\\braasta\\b\000rasta\000"
-"\\bsecond\\b\0002\000"
-"\\bstreet\\b\000st\000"
-"\\bx\\s+road\\b\000xrd\000"
-"\\bxroads\\b\000xrd\000"
-"\\bcentr\\b\000cen\000"
-"\\bchauk\\b\000chok\000"
-"\\bchouk\\b\000chok\000"
-"\\bchowk\\b\000chok\000"
-"\\bcnter\\b\000cen\000"
-"\\bdelhi\\b\000del\000"
-"\\bfifth\\b\0005\000"
-"\\bfirst\\b\0001\000"
-"\\bgalli\\b\000gali\000"
-"\\bgardn\\b\000gdn\000"
-"\\bgrden\\b\000gdn\000"
-"\\bgtway\\b\000gtwy\000"
-"\\bindia\\b\000in\000"
-"\\bj\\s+\\&\\s+k\\b\000j&k\000"
-"\\bmukku\\b\000jn.\000"
-"\\bnaaka\\b\000jn.\000"
-"\\bninth\\b\0009\000"
-"\\bnorth\\b\000n\000"
-"\\bpally\\b\000palli\000"
-"\\bround\\b\000cir.\000"
-"\\broute\\b\000rt\000"
-"\\bsixth\\b\0006\000"
-"\\bsouth\\b\000s\000"
-"\\btenth\\b\00010\000"
-"\\bthird\\b\0003\000"
-"\\bvizag\\b\000vskp\000"
-"\\bxroad\\b\000xrd\000"
-"\\bcent\\b\000cen\000"
-"\\bcntr\\b\000cen\000"
-"\\beast\\b\000e\000"
-"\\bgarh\\b\000gad\000"
-"\\bgrdn\\b\000gdn\000"
-"\\bhght\\b\000hts\000"
-"\\bhgts\\b\000hts\000"
-"\\bj\\s+\\&k\\b\000j&k\000"
-"\\bjct\\.\\b\000jn.\000"
-"\\bjnct\\b\000jn.\000"
-"\\bpeth\\b\000pet\000"
-"\\brnd\\.\\b\000cir.\000"
-"\\broad\\b\000rd\000"
-"\\bstr\\.\\b\000st\000"
-"\\buniv\\b\000uni\000"
-"\\bwest\\b\000w\000"
-"\\bx\\-rd\\b\000xrd\000"
-"\\bxrds\\b\000xrd\000"
-"\\bcha\\b\000ch\000"
-"\\bctr\\b\000cen\000"
-"\\bmum\\b\000bom\000"
-"\\bno\\.\\b\000#\000"
-"\\bnum\\b\000#\000"
-"\\brte\\b\000rt\000"
-"\\bst\\.\\b\000st\000"
-"\\bstr\\b\000st\000"
-"\\bno\\b\000#\000"
-;
-int kNumRules_IN = 129;
-
-const char* kRules_IT =
-"\\bbarletta\\s+andria\\s+trani\\b\000bt\000"
-"\\bfriuli\\s+venezia\\s+giulia\\b\00036\000"
-"\\bverbano\\s+cusio\\s+ossola\\b\000vb\000"
-"\\btrentino\\s+alto\\s+adige\\b\00032\000"
-"\\bstrada\\s+provinciale\\b\000sp\000"
-"\\bcarbonia\\s+iglesias\\b\000ci\000"
-"\\btrentino\\s+sudtirol\\b\00032\000"
-"\\bstrada\\s+regionale\\b\000sr\000"
-"\\bventiquattresimo\\b\00024\000"
-"\\bdiciassettesimo\\b\00017\000"
-"\\bmedio\\s+campidano\\b\000vs\000"
-"\\bmonza\\s+e\\s+brianza\\b\000mb\000"
-"\\bpesaro\\s+e\\s+urbino\\b\000pu\000"
-"\\bquattordicesimo\\b\00014\000"
-"\\breggio\\s+calabria\\b\000rc\000"
-"\\bstrada\\s+comunale\\b\000sc\000"
-"\\bventicinquesimo\\b\00025\000"
-"\\bdiciannovesimo\\b\00019\000"
-"\\bemilia\\s+romagna\\b\00045\000"
-"\\bstrada\\s+statali\\b\000ss\000"
-"\\bvallee\\s+d\\s+aoste\\b\00023\000"
-"\\bventisettesimo\\b\00027\000"
-"\\bascoli\\s+piceno\\b\000ap\000"
-"\\bcaltanissetta\\b\000cl\000"
-"\\bmassa\\s+carrara\\b\000ms\000"
-"\\breggio\\s+emilia\\b\000re\000"
-"\\bvalle\\s+d\\s+aosta\\b\00023\000"
-"\\bventinovesimo\\b\00029\000"
-"\\bventitreesimo\\b\00023\000"
-"\\bvibo\\s+valentia\\b\000vv\000"
-"\\bdiciottesimo\\b\00018\000"
-"\\bforli\\s+cesena\\b\000fc\000"
-"\\bolbia\\s+tempio\\b\000ot\000"
-"\\bquindicesimo\\b\00015\000"
-"\\bventiduesimo\\b\00022\000"
-"\\bventiquattro\\b\00024\000"
-"\\bventottesimo\\b\00028\000"
-"\\balessandria\\b\000\000"
-"\\bdiciassette\\b\00017\000"
-"\\bquattordici\\b\00014\000"
-"\\btredicesimo\\b\00013\000"
-"\\bvalle\\s+aosta\\b\00023\000"
-"\\bventicinque\\b\00025\000"
-"\\bventisesimo\\b\00026\000"
-"\\bventunesimo\\b\00021\000"
-"\\bbasilicata\\b\00077\000"
-"\\bcampobasso\\b\000cb\000"
-"\\bdiciannove\\b\00019\000"
-"\\bdodicesimo\\b\00012\000"
-"\\breggimento\\b\000rgt\000"
-"\\bsedicesimo\\b\00016\000"
-"\\btrentesimo\\b\00030\000"
-"\\bundicesimo\\b\00011\000"
-"\\bventisette\\b\00027\000"
-"\\bagrigento\\b\000ag\000"
-"\\bbenevento\\b\000bn\000"
-"\\bcatanzaro\\b\000cz\000"
-"\\bfrosinone\\b\000fr\000"
-"\\bla\\s+spezia\\b\000sp\000"
-"\\blombardia\\b\00025\000"
-"\\bogliastra\\b\000og\000"
-"\\bpordenone\\b\000pn\000"
-"\\bventesimo\\b\00020\000"
-"\\bventinove\\b\00029\000"
-"\\bavellino\\b\000av\000"
-"\\bbrindisi\\b\000br\000"
-"\\bcagliari\\b\000ca\000"
-"\\bcalabria\\b\00078\000"
-"\\bcampania\\b\00072\000"
-"\\bdiciotto\\b\00018\000"
-"\\bgrosseto\\b\000gr\000"
-"\\bl\\s+aquila\\b\000aq\000"
-"\\bmacerata\\b\000mc\000"
-"\\boristano\\b\000or\000"
-"\\bpiacenza\\b\000pc\000"
-"\\bpiemonte\\b\00021\000"
-"\\bquindici\\b\00015\000"
-"\\bsardegna\\b\00088\000"
-"\\bsiracusa\\b\000sr\000"
-"\\btraversa\\b\000trav\000"
-"\\bventidue\\b\00022\000"
-"\\bventisei\\b\00026\000"
-"\\bventitre\\b\00023\000"
-"\\bventotto\\b\00028\000"
-"\\bvercelli\\b\000vc\000"
-"\\babruzzo\\b\00065\000"
-"\\bbelluno\\b\000bl\000"
-"\\bbergamo\\b\000bg\000"
-"\\bbologna\\b\000bo\000"
-"\\bbolzano\\b\000bz\000"
-"\\bbrescia\\b\000bs\000"
-"\\bcaserta\\b\000ce\000"
-"\\bcatania\\b\000ct\000"
-"\\bcosenza\\b\000cs\000"
-"\\bcremona\\b\000cr\000"
-"\\bcrotone\\b\000kr\000"
-"\\bferrara\\b\000fe\000"
-"\\bfirenze\\b\000fi\000"
-"\\bgorizia\\b\000go\000"
-"\\bimperia\\b\000im\000"
-"\\bisernia\\b\000is\000"
-"\\bliguria\\b\00042\000"
-"\\blivorno\\b\000li\000"
-"\\bmantova\\b\000mn\000"
-"\\bmessina\\b\000me\000"
-"\\bpalermo\\b\000pa\000"
-"\\bperugia\\b\000pg\000"
-"\\bpescara\\b\000pe\000"
-"\\bpistoia\\b\000pt\000"
-"\\bpotenza\\b\000pz\000"
-"\\bquattro\\b\0004\000"
-"\\bravenna\\b\000ra\000"
-"\\bsalerno\\b\000sa\000"
-"\\bsassari\\b\000ss\000"
-"\\bsecondo\\b\0002\000"
-"\\bsettimo\\b\0007\000"
-"\\bsicilia\\b\00082\000"
-"\\bsondrio\\b\000so\000"
-"\\btaranto\\b\000ta\000"
-"\\btoscana\\b\00052\000"
-"\\btrapani\\b\000tp\000"
-"\\btredici\\b\00013\000"
-"\\btreviso\\b\000tv\000"
-"\\btrieste\\b\000ts\000"
-"\\bvenezia\\b\000ve\000"
-"\\bventuno\\b\00021\000"
-"\\bvicenza\\b\0006\000"
-"\\bviterbo\\b\000vt\000"
-"\\bancona\\b\000an\000"
-"\\barezzo\\b\000ar\000"
-"\\bbiella\\b\000bi\000"
-"\\bchieti\\b\000ch\000"
-"\\bcinque\\b\0005\000"
-"\\bdecimo\\b\000x\000"
-"\\bdodici\\b\00012\000"
-"\\bfoggia\\b\000fg\000"
-"\\bgenova\\b\000ge\000"
-"\\bitalia\\b\000it\000"
-"\\blatina\\b\000lt\000"
-"\\bmarche\\b\00057\000"
-"\\bmatera\\b\000mt\000"
-"\\bmilano\\b\000mi\000"
-"\\bmodena\\b\000mo\000"
-"\\bmolise\\b\00067\000"
-"\\bnapoli\\b\000na\000"
-"\\bnovara\\b\000no\000"
-"\\bottavo\\b\0008\000"
-"\\bpadova\\b\000pd\000"
-"\\bpuglia\\b\00075\000"
-"\\bquarto\\b\0004\000"
-"\\bquinto\\b\0005\000"
-"\\bragusa\\b\000rg\000"
-"\\brimini\\b\000rn\000"
-"\\brovigo\\b\000ro\000"
-"\\bsavona\\b\000sv\000"
-"\\bsedici\\b\00016\000"
-"\\bteramo\\b\000te\000"
-"\\btorino\\b\000to\000"
-"\\btrenta\\b\00030\000"
-"\\btrento\\b\000tn\000"
-"\\bumbria\\b\00055\000"
-"\\bundici\\b\00011\000"
-"\\bvarese\\b\000va\000"
-"\\bveneto\\b\00034\000"
-"\\bverona\\b\000vr\000"
-"\\bxxviii\\b\00028\000"
-"\\baosta\\b\000ao\000"
-"\\baoste\\b\000ao\000"
-"\\bbozen\\b\000bz\000"
-"\\bcuneo\\b\000cn\000"
-"\\bdagli\\b\000\000"
-"\\bdalla\\b\000\000"
-"\\bdalle\\b\000\000"
-"\\bdallo\\b\000\000"
-"\\bdegli\\b\000\000"
-"\\bdella\\b\000\000"
-"\\bdelle\\b\000\000"
-"\\bdello\\b\000\000"
-"\\bdieci\\b\000x\000"
-"\\bfermo\\b\000fm\000"
-"\\bitaly\\b\000it\000"
-"\\blazio\\b\00062\000"
-"\\blecce\\b\000\000"
-"\\blecco\\b\000lc\000"
-"\\blucca\\b\000lu\000"
-"\\bnegli\\b\000\000"
-"\\bnella\\b\000\000"
-"\\bnelle\\b\000\000"
-"\\bnello\\b\000\000"
-"\\bnorth\\b\000n\000"
-"\\bnuoro\\b\000nu\000"
-"\\bovest\\b\000o\000"
-"\\bparma\\b\000pr\000"
-"\\bpavia\\b\000pv\000"
-"\\bprato\\b\000po\000"
-"\\bprimo\\b\000\000"
-"\\brieti\\b\000ri\000"
-"\\bsesto\\b\0006\000"
-"\\bsette\\b\0007\000"
-"\\bsiena\\b\000si\000"
-"\\bsouth\\b\000s\000"
-"\\bsugli\\b\000\000"
-"\\bsulla\\b\000\000"
-"\\bsulle\\b\000\000"
-"\\bsullo\\b\000\000"
-"\\bterni\\b\000tr\000"
-"\\bterzo\\b\0003\000"
-"\\budine\\b\000ud\000"
-"\\bventi\\b\00020\000"
-"\\bxviii\\b\00018\000"
-"\\bxxiii\\b\00023\000"
-"\\bxxvii\\b\00027\000"
-"\\bagli\\b\000\000"
-"\\balla\\b\000\000"
-"\\balle\\b\000\000"
-"\\ballo\\b\000\000"
-"\\basti\\b\000at\000"
-"\\bbari\\b\000ba\000"
-"\\bcomo\\b\000co\000"
-"\\bdall\\b\000\000"
-"\\bdell\\b\000\000"
-"\\beast\\b\000e\000"
-"\\benna\\b\000\000"
-"\\blodi\\b\000\000"
-"\\bnell\\b\000\000"
-"\\bnono\\b\0009\000"
-"\\bnord\\b\000n\000"
-"\\bnove\\b\0009\000"
-"\\botto\\b\0008\000"
-"\\bpisa\\b\000pi\000"
-"\\broma\\b\000rm\000"
-"\\bsull\\b\000\000"
-"\\bviii\\b\0008\000"
-"\\bwest\\b\000o\000"
-"\\bxiii\\b\00013\000"
-"\\bxvii\\b\00017\000"
-"\\bxxii\\b\00022\000"
-"\\bxxiv\\b\00024\000"
-"\\bxxix\\b\00029\000"
-"\\bxxvi\\b\00026\000"
-"\\ball\\b\000\000"
-"\\bdai\\b\000\000"
-"\\bdal\\b\000\000"
-"\\bdei\\b\000\000"
-"\\bdel\\b\000\000"
-"\\bdue\\b\0002\000"
-"\\best\\b\000e\000"
-"\\bgli\\b\000\000"
-"\\biii\\b\0003\000"
-"\\bles\\b\000\000"
-"\\bnei\\b\000\000"
-"\\bnel\\b\000\000"
-"\\bsei\\b\0006\000"
-"\\bsud\\b\000s\000"
-"\\bsui\\b\000\000"
-"\\bsul\\b\000\000"
-"\\btre\\b\0003\000"
-"\\buno\\b\000\000"
-"\\bvii\\b\0007\000"
-"\\bxii\\b\00012\000"
-"\\bxiv\\b\00014\000"
-"\\bxix\\b\00019\000"
-"\\bxvi\\b\00016\000"
-"\\bxxi\\b\00021\000"
-"\\bxxv\\b\00025\000"
-"\\bxxx\\b\00030\000"
-"\\b10\\b\000x\000"
-"\\bai\\b\000\000"
-"\\bal\\b\000\000"
-"\\bda\\b\000\000"
-"\\bdi\\b\000\000"
-"\\ben\\b\000\000"
-"\\bii\\b\0002\000"
-"\\bil\\b\000\000"
-"\\bin\\b\000\000"
-"\\biv\\b\0004\000"
-"\\bix\\b\0009\000"
-"\\bla\\b\000\000"
-"\\ble\\b\000\000"
-"\\blo\\b\000\000"
-"\\bsu\\b\000\000"
-"\\bvi\\b\0006\000"
-"\\bxi\\b\00011\000"
-"\\bxv\\b\00015\000"
-"\\bxx\\b\00020\000"
-"\\ba\\b\000\000"
-"\\bd\\b\000\000"
-"\\bi\\b\000\000"
-"\\bl\\b\000\000"
-"\\bv\\b\0005\000"
-"\\bw\\b\000o\000"
-;
-int kNumRules_IT = 291;
-
-const char* kRules_LU =
-"\\berpeldange\\s+\\-\\s+lez\\s+\\-\\s+bous\\b\000erpeldange\000"
-"\\bhostert\\s+niederanven\\b\000hostert\000"
-"\\bgoebelsmuehle\\b\000goebelsmuhle\000"
-"\\bbuederscheid\\b\000buderscheid\000"
-"\\bschwebsingen\\b\000schwebsange\000"
-"\\brammeldange\\b\000rameldange\000"
-"\\bcul\\s+de\\s+sac\\b\000cds\000"
-"\\bcul\\-de\\-sac\\b\000cds\000"
-"\\bgeyershaff\\b\000geyershof\000"
-"\\blexembourg\\b\000lu\000"
-"\\bluxembourg\\b\000lu\000"
-"\\brond\\-point\\b\000rdpt\000"
-"\\bboulevard\\b\000boul\000"
-"\\bcarrefour\\b\000carref\000"
-"\\bcroissant\\b\000crois\000"
-"\\bdiversion\\b\000divers\000"
-"\\bechangeur\\b\000ech\000"
-"\\besplanade\\b\000esp\000"
-"\\bluxemburg\\b\000lu\000"
-"\\bpromenade\\b\000prom\000"
-"\\bcapellen\\b\000cap\000"
-"\\bterrasse\\b\000tsse\000"
-"\\bcircuit\\b\000circt\000"
-"\\bimpasse\\b\000imp\000"
-"\\bplateau\\b\000plat\000"
-"\\bsentier\\b\000sent\000"
-"\\bstrasse\\b\000str\000"
-"\\bavenue\\b\000av\000"
-"\\bcenter\\b\000c\000"
-"\\bcentre\\b\000c\000"
-"\\bchemin\\b\000ch\000"
-"\\bpointe\\b\000pte\000"
-"\\bruelle\\b\000rle\000"
-"\\bcarre\\b\000car\000"
-"\\bcourt\\b\000crt\000"
-"\\bdrive\\b\000dr\000"
-"\\bpoint\\b\000pt\000"
-"\\broute\\b\000rte\000"
-"\\bespl\\b\000esp\000"
-"\\bave\\b\000av\000"
-"\\bctr\\b\000c\000"
-"\\bdes\\b\000\000"
-"\\blux\\b\000lu\000"
-"\\brue\\b\000r\000"
-"\\bde\\b\000\000"
-"\\bdu\\b\000\000"
-"\\bd\\b\000\000"
-;
-int kNumRules_LU = 47;
-
-const char* kRules_MX =
-"\\bcoahuila\\s+de\\s+zaragoza\\b\000coahuila\000"
-"\\bbaja\\s+california\\s+sur\\b\000b c s\000"
-"\\bestado\\s+de\\s+mexico\\b\000me\000"
-"\\bbaja\\s+california\\b\000b c\000"
-"\\baguascalientes\\b\000ag\000"
-"\\bveracruz\\s+llave\\b\000veracruz\000"
-"\\bprolongacion\\b\000prol\000"
-"\\bquintana\\s+roo\\b\000qr\000"
-"\\bdiecinueve\\b\00019\000"
-"\\bdiecisiete\\b\00017\000"
-"\\bgobernador\\b\000gob\000"
-"\\bguanajuato\\b\000gt\000"
-"\\blicenciado\\b\000lic\000"
-"\\bpresbitero\\b\000pbro\000"
-"\\bsan\\s+isidro\\b\000s isidro\000"
-"\\bseptiembre\\b\000sept\000"
-"\\bdieciocho\\b\00018\000"
-"\\bdieciseis\\b\00016\000"
-"\\bfrancisco\\b\000fco\000"
-"\\bingeniero\\b\000ing\000"
-"\\brepublica\\b\000rep\000"
-"\\barticulo\\b\000art\000"
-"\\bguerrero\\b\000gr\000"
-"\\bhacienda\\b\000hda\000"
-"\\bponiente\\b\000pte\000"
-"\\bprofesor\\b\000prof\000"
-"\\bsan\\s+juan\\b\000s juan\000"
-"\\bavenida\\b\000av\000"
-"\\bcaptain\\b\000cap\000"
-"\\bcatorce\\b\00014\000"
-"\\bfebrero\\b\000feb\000"
-"\\bgeneral\\b\000gral\000"
-"\\bhidalgo\\b\000hg\000"
-"\\bjalisco\\b\000ja\000"
-"\\boriente\\b\000ote\000"
-"\\bprimera\\b\0001a\000"
-"\\bprivada\\b\000priv\000"
-"\\bsegunda\\b\0002a\000"
-"\\bseptima\\b\0007a\000"
-"\\bsinaloa\\b\000si\000"
-"\\btercera\\b\0003a\000"
-"\\bciudad\\b\000cd\000"
-"\\bcuarta\\b\0004a\000"
-"\\bcuatro\\b\0004\000"
-"\\bdoctor\\b\000dr\000"
-"\\bmexico\\b\000me\000"
-"\\bmx\\s+mex\\b\000me\000"
-"\\boaxaca\\b\000oa\000"
-"\\boctava\\b\0008a\000"
-"\\bpuebla\\b\000pu\000"
-"\\bpuerto\\b\000pto\000"
-"\\bquince\\b\00015\000"
-"\\bquinta\\b\0005a\000"
-"\\bveinte\\b\00020\000"
-"\\bcinco\\b\0005\000"
-"\\bmaria\\b\000ma\000"
-"\\bnorte\\b\000nte\000"
-"\\bnueve\\b\0009\000"
-"\\boeste\\b\000pte\000"
-"\\bq\\s+roo\\b\000qr\000"
-"\\bsanta\\b\000sta\000"
-"\\bsexta\\b\0006a\000"
-"\\bsiete\\b\0007\000"
-"\\btrece\\b\00013\000"
-"\\bdiez\\b\00010\000"
-"\\bdoce\\b\00012\000"
-"\\beste\\b\000ote\000"
-"\\bocho\\b\0008\000"
-"\\bonce\\b\00011\000"
-"\\bseis\\b\0006\000"
-"\\btres\\b\0003\000"
-"\\bags\\b\000ag\000"
-"\\bdel\\b\000\000"
-"\\bdos\\b\0002\000"
-"\\blas\\b\000\000"
-"\\blos\\b\000\000"
-"\\bq\\s+r\\b\000qr\000"
-"\\buno\\b\0001\000"
-"\\bde\\b\000\000"
-"\\bel\\b\000\000"
-"\\ble\\b\000\000"
-"\\bmx\\b\000me\000"
-;
-int kNumRules_MX = 82;
-
-const char* kRules_MY =
-"\\bmalaysia\\b\000my\000"
-;
-int kNumRules_MY = 1;
-
-const char* kRules_NL =
-"\\bwesterhaar\\s+vriezenveensewijk\\b\000westerhaar-vriezenv wijk\000"
-"\\bnoord\\s+brabant\\b\000nb\000"
-"\\bnoord\\s+holland\\b\000nh\000"
-"\\bnoord\\-brabant\\b\000nb\000"
-"\\bnoord\\-holland\\b\000nh\000"
-"\\balphen\\s+chaam\\b\000ac\000"
-"\\bburgemeester\\b\000burg\000"
-"\\bnoordbrabant\\b\000nb\000"
-"\\bs\\s+gravenhage\\b\000sgravenhage\000"
-"\\bzuid\\s+holland\\b\000zh\000"
-"\\bzuid\\-holland\\b\000zh\000"
-"\\bmonseigneur\\b\000mgr\000"
-"\\bnetherlands\\b\000nl\000"
-"\\bnordholland\\b\000nh\000"
-"\\bzuidholland\\b\000zh\000"
-"\\bgelderland\\b\000ge\000"
-"\\bnoordzijde\\b\000nz\000"
-"\\boverijssel\\b\000ov\000"
-"\\bflevoland\\b\000fl\000"
-"\\bfriesland\\b\000fr\000"
-"\\bgroningen\\b\000gn\000"
-"\\bnederland\\b\000nl\000"
-"\\boostzijde\\b\000oz\000"
-"\\bprofessor\\b\000prof\000"
-"\\brotterdam\\b\000rt\000"
-"\\bwestzijde\\b\000wz\000"
-"\\bzuidzijde\\b\000zz\000"
-"\\baan\\s+den\\b\000ad\000"
-"\\bachtste\\b\0008\000"
-"\\bdominee\\b\000ds\000"
-"\\bdrenthe\\b\000dr\000"
-"\\blimburg\\b\000l\000"
-"\\bmeester\\b\000mr\000"
-"\\bnegende\\b\0009\000"
-"\\butrecht\\b\000u\000"
-"\\bzeeland\\b\000z\000"
-"\\bzevende\\b\0007\000"
-"\\baan\\s+de\\b\000ad\000"
-"\\bdoctor\\b\000dr\000"
-"\\beerste\\b\0001\000"
-"\\bstraat\\b\000str\000"
-"\\btweede\\b\0002\000"
-"\\bvierde\\b\0004\000"
-"\\bvijfde\\b\0005\000"
-"\\bderde\\b\0003\000"
-"\\bnl\\-dr\\b\000dr\000"
-"\\bnl\\-fl\\b\000fl\000"
-"\\bnl\\-fr\\b\000fr\000"
-"\\bnl\\-ge\\b\000ge\000"
-"\\bnl\\-gr\\b\000gn\000"
-"\\bnl\\-li\\b\000l\000"
-"\\bnl\\-nb\\b\000nb\000"
-"\\bnl\\-nh\\b\000nh\000"
-"\\bnl\\-ov\\b\000ov\000"
-"\\bnl\\-ut\\b\000u\000"
-"\\bnl\\-ze\\b\000z\000"
-"\\bnl\\-zh\\b\000zh\000"
-"\\bzesde\\b\0006\000"
-"\\bsint\\b\000st\000"
-"\\ba\\s+d\\b\000ad\000"
-"\\bgld\\b\000ge\000"
-"\\bn\\s+z\\b\000nz\000"
-"\\bo\\s+z\\b\000oz\000"
-"\\bw\\s+z\\b\000wz\000"
-"\\bz\\s+z\\b\000zz\000"
-"\\bzld\\b\000z\000"
-"\\bgl\\b\000ge\000"
-"\\bgr\\b\000gn\000"
-"\\blb\\b\000l\000"
-"\\bli\\b\000l\000"
-"\\but\\b\000u\000"
-"\\bze\\b\000z\000"
-"\\bzl\\b\000z\000"
-"\\b\\#\\b\000\000"
-;
-int kNumRules_NL = 74;
-
-const char* kRules_NZ =
-"\\brural\\s+delivery\\b\000\000"
-"\\bocean\\s+beach\\b\000oceanbeach\000"
-"\\blong\\s+beach\\b\000longbeach\000"
-"\\bboulevard\\b\000blvd\000"
-"\\bcrescent\\b\000cres\000"
-"\\bheights\\b\000hts\000"
-"\\bhighway\\b\000hwy\000"
-"\\bparkway\\b\000pkwy\000"
-"\\bavenue\\b\000ave\000"
-"\\bcommon\\b\000comm\000"
-"\\bparade\\b\000pde\000"
-"\\bstreet\\b\000st\000"
-"\\bcourt\\b\000ct\000"
-"\\bdrive\\b\000dr\000"
-"\\bmount\\b\000mt\000"
-"\\bnorth\\b\000n\000"
-"\\bplace\\b\000pl\000"
-"\\bpoint\\b\000pt\000"
-"\\bsaint\\b\000st\000"
-"\\bsouth\\b\000s\000"
-"\\beast\\b\000e\000"
-"\\blane\\b\000ln\000"
-"\\bn\\.z\\.\\b\000nz\000"
-"\\broad\\b\000rd\000"
-"\\bwest\\b\000w\000"
-"\\bmt\\.\\b\000mt\000"
-"\\bn\\.z\\b\000nz\000"
-"\\bnth\\b\000n\000"
-"\\bpt\\.\\b\000pt\000"
-"\\bst\\.\\b\000st\000"
-"\\bsth\\b\000s\000"
-"\\be\\.\\b\000e\000"
-"\\bn\\.\\b\000n\000"
-"\\bs\\.\\b\000s\000"
-"\\bw\\.\\b\000w\000"
-;
-int kNumRules_NZ = 35;
-
-const char* kRules_PE =
-"\\bavenida\\b\000av\000"
-"\\bperu\\b\000pe\000"
-"\\bdel\\b\000\000"
-"\\blas\\b\000\000"
-"\\blos\\b\000\000"
-"\\bde\\b\000\000"
-"\\bel\\b\000\000"
-"\\ble\\b\000\000"
-;
-int kNumRules_PE = 8;
-
-const char* kRules_PH =
-"\\bphilippines\\b\000ph\000"
-"\\bboulevard\\b\000blvd\000"
-"\\bextension\\b\000ext\000"
-"\\bbarangay\\b\000\000"
-"\\bcaptain\\b\000cap\000"
-"\\bgeneral\\b\000gen\000"
-"\\bavenue\\b\000av\000"
-"\\bdoctor\\b\000dr\000"
-"\\bstreet\\b\000st\000"
-"\\bnorth\\b\000n\000"
-"\\bsouth\\b\000s\000"
-"\\bbrgy\\b\000\000"
-"\\beast\\b\000e\000"
-"\\bextn\\b\000ext\000"
-"\\broad\\b\000rd\000"
-"\\bwest\\b\000w\000"
-"\\bave\\b\000av\000"
-"\\bbgy\\b\000\000"
-;
-int kNumRules_PH = 18;
-
-const char* kRules_PL =
-"\\bkuyavian\\s+pomeranian\\b\000kp\000"
-"\\bzachodniopomorskie\\b\000zp\000"
-"\\bwarmian\\s+masurian\\b\000wn\000"
-"\\bwest\\s+pomeranian\\b\000zp\000"
-"\\bgreater\\s+poland\\b\000wp\000"
-"\\blower\\s+silesian\\b\000ds\000"
-"\\bswietokrzyskie\\b\000sk\000"
-"\\blesser\\s+poland\\b\000mp\000"
-"\\bsubcarpathian\\b\000pk\000"
-"\\bwielkopolskie\\b\000wp\000"
-"\\bdolnoslaskie\\b\000ds\000"
-"\\bpodkarpackie\\b\000pk\000"
-"\\bmalopolskie\\b\000mp\000"
-"\\bmazowieckie\\b\000ma\000"
-"\\bpomeranian\\b\000pm\000"
-"\\blubelskie\\b\000lu\000"
-"\\bmarszalek\\b\000marsz\000"
-"\\bpodlaskie\\b\000pd\000"
-"\\bpomorskie\\b\000pm\000"
-"\\bwarminsko\\b\000wn\000"
-"\\bkujawsko\\b\000kp\000"
-"\\blubuskie\\b\000lb\000"
-"\\bmasovian\\b\000ma\000"
-"\\bopolskie\\b\000op\000"
-"\\bpoludnie\\b\000south\000"
-"\\bsilesian\\b\000sl\000"
-"\\bwschodni\\b\000w\000"
-"\\bzachodni\\b\000z\000"
-"\\blodzkie\\b\000ld\000"
-"\\bosiedle\\b\000os\000"
-"\\bsilesia\\b\000sl\000"
-"\\bslaskie\\b\000sl\000"
-"\\blublin\\b\000lu\000"
-"\\blubusz\\b\000lb\000"
-"\\bpoland\\b\000pl\000"
-"\\bpolnoc\\b\000north\000"
-"\\bwschod\\b\000w\000"
-"\\bzachod\\b\000z\000"
-"\\bopole\\b\000op\000"
-"\\beast\\b\000w\000"
-"\\blodz\\b\000ld\000"
-"\\bwest\\b\000z\000"
-"\\bwlkp\\b\000wp\000"
-;
-int kNumRules_PL = 43;
-
-const char* kRules_PR =
-"\\bsan\\s+juan\\s+antiguo\\b\000old san juan\000"
-"\\bpuerto\\s+rico\\b\000pr\000"
-"\\bcarretera\\b\000carr\000"
-"\\bmal\\s+paso\\b\000malpaso\000"
-"\\bavenida\\b\000av\000"
-"\\bbulevar\\b\000blvd\000"
-"\\bcamino\\b\000cm\000"
-"\\bcalle\\b\000cll\000"
-"\\bcourt\\b\000ct\000"
-"\\bnorth\\b\000n\000"
-"\\bpaseo\\b\000pso\000"
-"\\bplaza\\b\000plz\000"
-"\\bsaint\\b\000st\000"
-"\\bsouth\\b\000s\000"
-"\\bave\\.\\b\000av\000"
-"\\beast\\b\000e\000"
-"\\blane\\b\000ln\000"
-"\\bp\\.r\\.\\b\000pr\000"
-"\\broad\\b\000rd\000"
-"\\bwest\\b\000w\000"
-"\\bave\\b\000av\000"
-"\\bcam\\b\000cm\000"
-"\\bnth\\b\000n\000"
-"\\bp\\.r\\b\000pr\000"
-"\\bst\\.\\b\000st\000"
-"\\bsth\\b\000s\000"
-"\\be\\.\\b\000e\000"
-"\\bn\\.\\b\000n\000"
-"\\bs\\.\\b\000s\000"
-"\\bw\\.\\b\000w\000"
-;
-int kNumRules_PR = 30;
-
-const char* kRules_PT =
-"\\bestrada\\s+nacional\\b\000n\000"
-"\\bviana\\s+do\\s+castelo\\b\00018\000"
-"\\bcastelo\\s+branco\\b\00009\000"
-"\\bportalegre\\b\00008\000"
-"\\bvila\\s+real\\b\00015\000"
-"\\bbraganca\\b\00014\000"
-"\\bportugal\\b\000pt\000"
-"\\bsantarem\\b\00003\000"
-"\\bcoimbra\\b\00011\000"
-"\\bsetubal\\b\00004\000"
-"\\baveiro\\b\00012\000"
-"\\bdoctor\\b\000dr\000"
-"\\bdoutor\\b\000dr\000"
-"\\bguarda\\b\00010\000"
-"\\bleiria\\b\00002\000"
-"\\blisbon\\b\00001\000"
-"\\bbraga\\b\00017\000"
-"\\bevora\\b\00007\000"
-"\\bnorth\\b\000n\000"
-"\\bporto\\b\00016\000"
-"\\bsouth\\b\000s\000"
-"\\bviseu\\b\00013\000"
-"\\bbeja\\b\00005\000"
-"\\bfaro\\b\00006\000"
-"\\bwest\\b\000w\000"
-"\\bdas\\b\000\000"
-"\\bdos\\b\000\000"
-"\\bsao\\b\000s\000"
-"\\bda\\b\000\000"
-"\\bde\\b\000\000"
-"\\bdo\\b\000\000"
-"\\bem\\b\000m\000"
-"\\ben\\b\000n\000"
-"\\be\\b\000\000"
-;
-int kNumRules_PT = 34;
-
-const char* kRules_RO =
-"\\bromania\\b\000ro\000"
-;
-int kNumRules_RO = 1;
-
-const char* kRules_RU =
-"\\bавтодорога\\b\000а/д\000"
-"\\bнабережная\\b\000наб\000"
-"\\bтерритория\\b\000тер\000"
-"\\bпереулок\\b\000пер\000"
-"\\bпроспект\\b\000пр\000"
-"\\bбульвар\\b\000б-р\000"
-"\\bквартал\\b\000кв-л\000"
-"\\bплощадь\\b\000пл\000"
-"\\brussia\\b\000ru\000"
-"\\bдорога\\b\000дор\000"
-"\\bпроезд\\b\000пр-д\000"
-"\\bроссия\\b\000ru\000"
-"\\bбульв\\b\000б-р\000"
-"\\bлиния\\b\000лин\000"
-"\\bпр\\-кт\\b\000пр\000"
-"\\bпросп\\b\000пр\000"
-"\\bтупик\\b\000туп\000"
-"\\bулица\\b\000ул\000"
-"\\bшоссе\\b\000ш\000"
-"\\bпрот\\b\000пр\000"
-"\\bбул\\b\000б-р\000"
-;
-int kNumRules_RU = 21;
-
-const char* kRules_SE =
-"\\bvastra\\s+goetalands\\b\000o\000"
-"\\bvastra\\s+goetaland\\b\000o\000"
-"\\boestergoetlands\\b\000e\000"
-"\\bvasternorrlands\\b\000y\000"
-"\\boestergoetland\\b\000e\000"
-"\\bvastergoetland\\b\000e\000"
-"\\bvasternorrland\\b\000y\000"
-"\\bsodermanlands\\b\000d\000"
-"\\bvasterbottens\\b\000ac\000"
-"\\bjoenkoepings\\b\000f\000"
-"\\bsodermanland\\b\000d\000"
-"\\bvasterbotten\\b\000ac\000"
-"\\bvastmanlands\\b\000u\000"
-"\\bjoenkoeping\\b\000f\000"
-"\\bnorrbottens\\b\000bd\000"
-"\\bvastmanland\\b\000u\000"
-"\\bgavleborgs\\b\000x\000"
-"\\bkronobergs\\b\000g\000"
-"\\bnorrbotten\\b\000bd\000"
-"\\bstockholms\\b\000ab\000"
-"\\bgavleborg\\b\000x\000"
-"\\bjamtlands\\b\000z\000"
-"\\bkronoberg\\b\000g\000"
-"\\bstockholm\\b\000ab\000"
-"\\bvarmlands\\b\000s\000"
-"\\bblekinge\\b\000k\000"
-"\\bdalarnas\\b\000w\000"
-"\\bgotlands\\b\000i\000"
-"\\bhallands\\b\000n\000"
-"\\bjamtland\\b\000z\000"
-"\\boerebros\\b\000t\000"
-"\\bvarmland\\b\000s\000"
-"\\bdalarna\\b\000w\000"
-"\\bgotland\\b\000i\000"
-"\\bhalland\\b\000n\000"
-"\\boerebro\\b\000t\000"
-"\\bsverige\\b\000se\000"
-"\\buppsala\\b\000c\000"
-"\\bkalmar\\b\000h\000"
-"\\bsoeder\\b\000s\000"
-"\\bsweden\\b\000se\000"
-"\\bskane\\b\000m\000"
-"\\bnorr\\b\000n\000"
-"\\boest\\b\000o\000"
-"\\bvast\\b\000v\000"
-;
-int kNumRules_SE = 45;
-
-const char* kRules_TH =
-"\\bประเทศไทย\\b\000th\000"
-"\\bthailand\\b\000th\000"
-;
-int kNumRules_TH = 2;
-
-const char* kRules_TR =
-"\\bturkiye\\b\000tr\000"
-"\\bturkey\\b\000tr\000"
-;
-int kNumRules_TR = 2;
-
-const char* kRules_US =
-"\\bjoint\\s+base\\s+elmendorf\\s+richardson\\b\000jber\000"
-"\\bwashington\\s+district\\s+of\\s+columbia\\b\000dc\000"
-"\\bfederated\\s+states\\s+of\\s+micronesia\\b\000fm\000"
-"\\bjoint\\s+base\\s+pearl\\s+harbor\\s+hickam\\b\000jbphh\000"
-"\\bnational\\s+forest\\s+development\\b\000nat for dev\000"
-"\\bmartin\\s+luther\\s+king\\s+junior\\b\000mlk\000"
-"\\barmed\\s+forces\\s+middle\\s+east\\b\000ae\000"
-"\\bmarine\\s+corps\\s+base\\s+hawaii\\b\000mcbh kanehoe bay\000"
-"\\bnational\\s+for\\s+development\\b\000nat for dev\000"
-"\\bnorthern\\s+mariana\\s+islands\\b\000mp\000"
-"\\bunited\\s+states\\s+of\\s+america\\b\000us\000"
-"\\bmartin\\s+luther\\s+king\\s+jnr\\b\000mlk\000"
-"\\bnat\\s+forest\\s+development\\b\000nat for dev\000"
-"\\barmed\\s+forces\\s+americas\\b\000aa\000"
-"\\bmartin\\s+luther\\s+king\\s+jr\\b\000mlk\000"
-"\\barmed\\s+forces\\s+pacific\\b\000ap\000"
-"\\bdistrict\\s+of\\s+columbia\\b\000dc\000"
-"\\barmed\\s+forces\\s+africa\\b\000ae\000"
-"\\barmed\\s+forces\\s+canada\\b\000ae\000"
-"\\barmed\\s+forces\\s+europe\\b\000ae\000"
-"\\bnat\\s+for\\s+development\\b\000nat for dev\000"
-"\\bnational\\s+forest\\s+dev\\b\000nat for dev\000"
-"\\bjoint\\s+reserve\\s+base\\b\000jrb\000"
-"\\blincolns\\s+new\\s+salem\\b\000lincoln nw sl\000"
-"\\bmartin\\s+luther\\s+king\\b\000mlk\000"
-"\\bmetropolitan\\s+area\\b\000\000"
-"\\bnational\\s+monument\\b\000national mo\000"
-"\\bcolorado\\s+springs\\b\000co spgs\000"
-"\\bdist\\s+of\\s+columbia\\b\000dc\000"
-"\\bfrancis\\s+e\\s+warren\\b\000fe warren\000"
-"\\bmarshall\\s+islands\\b\000mh\000"
-"\\bnational\\s+for\\s+dev\\b\000nat for dev\000"
-"\\bwashington\\s+state\\b\000wa\000"
-"\\bcharlottesville\\b\000charlottesvle\000"
-"\\badministration\\b\000admn\000"
-"\\bair\\s+force\\s+base\\b\000afb\000"
-"\\bamerican\\s+samoa\\b\000as\000"
-"\\bbradford\\s+woods\\b\000bradfordwoods\000"
-"\\bchristiansberg\\b\000christiansbrg\000"
-"\\bcrawfordsville\\b\000crawfordsvlle\000"
-"\\bfarm\\s+to\\s+market\\b\000fm\000"
-"\\bforest\\s+service\\b\000frst srvc\000"
-"\\bfredericksburg\\b\000fredericksbrg\000"
-"\\bhendersonville\\b\000hendersonvlle\000"
-"\\bjeffersonville\\b\000jeffersonvlle\000"
-"\\bjohn\\s+f\\s+kennedy\\b\000jfk\000"
-"\\blittle\\s+diomede\\b\000diomede\000"
-"\\bmechanicsville\\b\000mechanicsvlle\000"
-"\\bnat\\s+forest\\s+dev\\b\000nat for dev\000"
-"\\bnew\\s+york\\s+state\\b\000ny\000"
-"\\bnorth\\s+carolina\\b\000nc\000"
-"\\bnorthumberland\\b\000northumberlnd\000"
-"\\bsalt\\s+lake\\s+city\\b\000slc\000"
-"\\bsouth\\s+carolina\\b\000sc\000"
-"\\bvirgin\\s+islands\\b\000vi\000"
-"\\bwashington\\s+d\\s+c\\b\000dc\000"
-"\\barmy\\s+airfield\\b\000army af\000"
-"\\binternational\\b\000intl\000"
-"\\bjf\\s+kennedy\\s+ap\\b\000jfk airport\000"
-"\\bmassachusetts\\b\000ma\000"
-"\\bnational\\s+park\\b\000ntpk\000"
-"\\bnew\\s+hampshire\\b\000nh\000"
-"\\bnew\\s+york\\s+city\\b\000ny\000"
-"\\bunited\\s+states\\b\000us\000"
-"\\bwashington\\s+dc\\b\000dc\000"
-"\\bwest\\s+virginia\\b\000wv\000"
-"\\bbristle\\s+cone\\b\000bristlecone\000"
-"\\bfrst\\s+service\\b\000frst srvc\000"
-"\\bminers\\s+mills\\b\000miners mill\000"
-"\\bnorth\\s+dakota\\b\000nd\000"
-"\\bpennsylvania\\b\000pa\000"
-"\\brhode\\s+island\\b\000ri\000"
-"\\bservice\\s+road\\b\000service rd\000"
-"\\bsouth\\s+dakota\\b\000sd\000"
-"\\bswan\\s+quarter\\b\000swanquarter\000"
-"\\bbloomington\\b\000blmngtn\000"
-"\\bchevy\\s+chase\\b\000chevy chs\000"
-"\\bclutch\\s+city\\b\000houston\000"
-"\\bconnecticut\\b\000ct\000"
-"\\bforest\\s+srvc\\b\000frst srvc\000"
-"\\bfrenchville\\b\000frnchvl\000"
-"\\bgood\\s+fellow\\b\000goodfellow\000"
-"\\bhigh\\s+bridge\\b\000highbridge\000"
-"\\blos\\s+angeles\\b\000la\000"
-"\\bloxahatchee\\b\000lox\000"
-"\\bmississippi\\b\000ms\000"
-"\\bobservatory\\b\000obs\000"
-"\\bpuerto\\s+rico\\b\000pr\000"
-"\\brural\\s+route\\b\000rr\000"
-"\\bspringfield\\b\000spfld\000"
-"\\byellowstone\\b\000yelwstn\000"
-"\\balpen\\s+glow\\b\000alpenglow\000"
-"\\bambassador\\b\000amb\000"
-"\\bbernardino\\b\000bernrdno\000"
-"\\bbloomfield\\b\000bloomfld\000"
-"\\bbrownstown\\b\000brownstwn\000"
-"\\bburlington\\b\000burlngtn\000"
-"\\bcalifornia\\b\000ca\000"
-"\\bcapistrano\\b\000capo\000"
-"\\bchristmass\\b\000chirstmas\000"
-"\\bcincinnati\\b\000cin\000"
-"\\bcottonwood\\b\000ctwd\000"
-"\\bcrossroads\\b\000xrds\000"
-"\\bexpressway\\b\000exp\000"
-"\\bextensions\\b\000exts\000"
-"\\bfarmington\\b\000farmingtn\000"
-"\\bnew\\s+jersey\\b\000nj\000"
-"\\bnew\\s+mexico\\b\000nm\000"
-"\\bpittsburgh\\b\000pgh\000"
-"\\bplantation\\b\000plt\000"
-"\\bprovidence\\b\000providnce\000"
-"\\bsouth\\s+lake\\b\000southlake\000"
-"\\bthroughway\\b\000trwy\000"
-"\\btrafficway\\b\000trfy\000"
-"\\buniversity\\b\000univ\000"
-"\\bwashington\\b\000wa\000"
-"\\bwest\\s+point\\b\000westpoint\000"
-"\\bbellerose\\b\000bellrs\000"
-"\\bboulevard\\b\000blvd\000"
-"\\bburlingtn\\b\000burlngtn\000"
-"\\bchair\\s+bar\\b\000chairbar\000"
-"\\bchicester\\b\000chicstr\000"
-"\\bcity\\s+base\\b\000cb\000"
-"\\bcleveland\\b\000cleve\000"
-"\\bcommunity\\b\000cmnty\000"
-"\\bcrossroad\\b\000xrd\000"
-"\\bextension\\b\000ext\000"
-"\\bfairmount\\b\000fairmt\000"
-"\\bfernandez\\b\000fdez\000"
-"\\bfrancisco\\b\000fran\000"
-"\\bhighlands\\b\000hlds\000"
-"\\bho\'olehua\\b\000hoolehua\000"
-"\\bhomestead\\b\000hmstd\000"
-"\\bjunctions\\b\000jcts\000"
-"\\blexington\\b\000lxngtn\000"
-"\\blouisiana\\b\000la\000"
-"\\bmilwaukee\\b\000milw\000"
-"\\bminnesota\\b\000mn\000"
-"\\bmountains\\b\000mtns\000"
-"\\brichfield\\b\000richfld\000"
-"\\bstravenue\\b\000stra\000"
-"\\btennessee\\b\000\000"
-"\\bterritory\\b\000\000"
-"\\btown\\s+line\\b\000t l\000"
-"\\bunderpass\\b\000upas\000"
-"\\bwashingtn\\b\000wa\000"
-"\\bwisconsin\\b\000wi\000"
-"\\barkansas\\b\000ar\000"
-"\\bbig\\s+bend\\b\000bg bnd\000"
-"\\bblooming\\b\000blmng\000"
-"\\bbullrush\\b\000bulrush\000"
-"\\bcauseway\\b\000cswy\000"
-"\\bcolorado\\b\000co\000"
-"\\bcottonwd\\b\000ctwd\000"
-"\\bcrescent\\b\000cres\000"
-"\\bcrossing\\b\000xing\000"
-"\\bcrossrds\\b\000xrds\000"
-"\\bdelaware\\b\000de\000"
-"\\bdowntown\\b\000\000"
-"\\bhartford\\b\000hartfrd\000"
-"\\billinois\\b\000il\000"
-"\\bjunction\\b\000jt\000"
-"\\bkentucky\\b\000ky\000"
-"\\bla\\s+salle\\b\000lasalle\000"
-"\\bmaryland\\b\000md\000"
-"\\bmichelle\\b\000michele\000"
-"\\bmichigan\\b\000mi\000"
-"\\bmissouri\\b\000mo\000"
-"\\bmotorway\\b\000mtwy\000"
-"\\bmountain\\b\000mnt\000"
-"\\bnational\\b\000nl\000"
-"\\bnebraska\\b\000ne\000"
-"\\bnew\\s+york\\b\000ny\000"
-"\\boklahoma\\b\000ok\000"
-"\\boverpass\\b\000opas\000"
-"\\bparkways\\b\000pkwys\000"
-"\\brichland\\b\000richlnd\000"
-"\\btownline\\b\000t l\000"
-"\\btownship\\b\000tp\000"
-"\\bturnpike\\b\000tpk\000"
-"\\bvillages\\b\000vlgs\000"
-"\\bvilliage\\b\000vil\000"
-"\\bvirginia\\b\000va\000"
-"\\balabama\\b\000al\000"
-"\\bamerica\\b\000us\000"
-"\\barizona\\b\000az\000"
-"\\bavenida\\b\000av\000"
-"\\bcapitol\\b\000capital\000"
-"\\bcausway\\b\000cswy\000"
-"\\bcenters\\b\000ctrs\000"
-"\\bcentral\\b\000\000"
-"\\bchicago\\b\000chgo\000"
-"\\bcircles\\b\000cirs\000"
-"\\bcollege\\b\000clg\000"
-"\\bcolonel\\b\000col\000"
-"\\bcorners\\b\000cors\000"
-"\\bcountry\\b\000cntry\000"
-"\\bcrecent\\b\000cres\000"
-"\\bcresent\\b\000cres\000"
-"\\bcrossrd\\b\000xrd\000"
-"\\bcrssing\\b\000xing\000"
-"\\bestates\\b\000ests\000"
-"\\bexpress\\b\000exp\000"
-"\\bflorida\\b\000fl\000"
-"\\bfreeway\\b\000fwy\000"
-"\\bgardens\\b\000gdns\000"
-"\\bgateway\\b\000gtwy\000"
-"\\bgeorgia\\b\000ga\000"
-"\\bharbors\\b\000hbrs\000"
-"\\bheights\\b\000ht\000"
-"\\bhighway\\b\000hwy\000"
-"\\bhollows\\b\000hllw\000"
-"\\bindiana\\b\000in\000"
-"\\bislands\\b\000is\000"
-"\\bjohnson\\b\000jhnsn\000"
-"\\bjuncton\\b\000jt\000"
-"\\blanding\\b\000lndg\000"
-"\\bmeadows\\b\000mdws\000"
-"\\bmission\\b\000msn\000"
-"\\bmontana\\b\000mt\000"
-"\\bmountin\\b\000mnt\000"
-"\\borchard\\b\000orch\000"
-"\\bparkway\\b\000pky\000"
-"\\bpassage\\b\000psge\000"
-"\\bphoenix\\b\000phx\000"
-"\\bplaines\\b\000plns\000"
-"\\bpotsdam\\b\000potsdm\000"
-"\\bprairie\\b\000pr\000"
-"\\branches\\b\000rnchs\000"
-"\\branchos\\b\000rnchs\000"
-"\\bseventh\\b\0007\000"
-"\\bsprings\\b\000spg\000"
-"\\bsquares\\b\000sqs\000"
-"\\bstation\\b\000sta\000"
-"\\bstraven\\b\000stra\000"
-"\\bstreets\\b\000sts\000"
-"\\bstrvnue\\b\000stra\000"
-"\\bterrace\\b\000ter\000"
-"\\btownshp\\b\000tp\000"
-"\\btunnels\\b\000tunl\000"
-"\\bvalleys\\b\000vlys\000"
-"\\bvermont\\b\000vt\000"
-"\\bviaduct\\b\000via\000"
-"\\bvillage\\b\000vil\000"
-"\\bwilliam\\b\000wm\000"
-"\\bwshngtn\\b\000wa\000"
-"\\bwyoming\\b\000wy\000"
-"\\balaska\\b\000ak\000"
-"\\barcade\\b\000arc\000"
-"\\bavenue\\b\000av\000"
-"\\bbarrio\\b\000bo\000"
-"\\bbluffs\\b\000blfs\000"
-"\\bbottom\\b\000bot\000"
-"\\bbranch\\b\000br\000"
-"\\bbridge\\b\000brg\000"
-"\\bbrooks\\b\000brks\000"
-"\\bbypass\\b\000byp\000"
-"\\bcamino\\b\000cm\000"
-"\\bcanyon\\b\000cyn\000"
-"\\bcarlin\\b\000carlan\000"
-"\\bcenter\\b\000cen\000"
-"\\bcentre\\b\000cen\000"
-"\\bcircle\\b\000cir\000"
-"\\bcliffs\\b\000clfs\000"
-"\\bcommon\\b\000cmn\000"
-"\\bcorner\\b\000cor\000"
-"\\bcorpus\\b\000crp\000"
-"\\bcounty\\b\000\000"
-"\\bcourse\\b\000crse\000"
-"\\bcourts\\b\000cts\000"
-"\\bcrscnt\\b\000cres\000"
-"\\bcrsent\\b\000cres\000"
-"\\bcrssng\\b\000xing\000"
-"\\bdesert\\b\000dsrt\000"
-"\\bdivide\\b\000dv\000"
-"\\bdrives\\b\000drs\000"
-"\\beighth\\b\0008\000"
-"\\bestate\\b\000est\000"
-"\\bextnsn\\b\000ext\000"
-"\\bfields\\b\000flds\000"
-"\\bforest\\b\000frst\000"
-"\\bforges\\b\000frgs\000"
-"\\bfourth\\b\0004\000"
-"\\bfreewy\\b\000fwy\000"
-"\\bgarden\\b\000gdn\000"
-"\\bgatewy\\b\000gtwy\000"
-"\\bgatway\\b\000gtwy\000"
-"\\bgreens\\b\000grns\000"
-"\\bgroves\\b\000grvs\000"
-"\\bharbor\\b\000hbr\000"
-"\\bhawaii\\b\000hi\000"
-"\\bheight\\b\000ht\000"
-"\\bhighwy\\b\000hwy\000"
-"\\bhollow\\b\000hllw\000"
-"\\bisland\\b\000is\000"
-"\\bislnds\\b\000is\000"
-"\\bjction\\b\000jt\000"
-"\\bjunctn\\b\000jt\000"
-"\\bkansas\\b\000ks\000"
-"\\bknolls\\b\000knls\000"
-"\\blagoon\\b\000lagn\000"
-"\\blights\\b\000lgts\000"
-"\\blittle\\b\000ltl\000"
-"\\bmanors\\b\000mnrs\000"
-"\\bmeadow\\b\000mdw\000"
-"\\bmedows\\b\000mdws\000"
-"\\bmiddle\\b\000mid\000"
-"\\bmntain\\b\000mnt\000"
-"\\bnevada\\b\000nv\000"
-"\\bobispo\\b\000obisp\000"
-"\\borchrd\\b\000orch\000"
-"\\boregon\\b\000or\000"
-"\\bparish\\b\000\000"
-"\\bparkwy\\b\000pky\000"
-"\\bplains\\b\000plns\000"
-"\\bpoints\\b\000pts\000"
-"\\bpuerto\\b\000pto\000"
-"\\bquarry\\b\000qry\000"
-"\\bradial\\b\000rad\000"
-"\\bradiel\\b\000rad\000"
-"\\brancho\\b\000rncho\000"
-"\\branchs\\b\000rnchs\000"
-"\\brapids\\b\000rpds\000"
-"\\bridges\\b\000rdgs\000"
-"\\bschool\\b\000sch\000"
-"\\bsecond\\b\0002\000"
-"\\bsenior\\b\000sr\000"
-"\\bshoals\\b\000shls\000"
-"\\bshoars\\b\000shrs\000"
-"\\bshores\\b\000shrs\000"
-"\\bskyway\\b\000skwy\000"
-"\\bspring\\b\000spg\000"
-"\\bsprngs\\b\000spg\000"
-"\\bsquare\\b\000sq\000"
-"\\bstrave\\b\000stra\000"
-"\\bstravn\\b\000stra\000"
-"\\bstream\\b\000strm\000"
-"\\bstreet\\b\000st\000"
-"\\bstreme\\b\000strm\000"
-"\\bsumitt\\b\000smt\000"
-"\\bsummit\\b\000smt\000"
-"\\bsydney\\b\000sidney\000"
-"\\btraces\\b\000trce\000"
-"\\btracks\\b\000trk\000"
-"\\btrails\\b\000tr\000"
-"\\btunnel\\b\000tunl\000"
-"\\bturnpk\\b\000tpk\000"
-"\\btwnshp\\b\000tp\000"
-"\\bunions\\b\000uns\000"
-"\\bvalley\\b\000vl\000"
-"\\bviadct\\b\000via\000"
-"\\bvillag\\b\000vil\000"
-"\\bwaters\\b\000wtr\000"
-"\\bxroads\\b\000xrds\000"
-"\\ba\\s+f\\s+b\\b\000afb\000"
-"\\ballee\\b\000aly\000"
-"\\balley\\b\000aly\000"
-"\\bannex\\b\000anx\000"
-"\\bavenu\\b\000av\000"
-"\\bavnue\\b\000av\000"
-"\\bbayoo\\b\000byu\000"
-"\\bbayou\\b\000byu\000"
-"\\bbeach\\b\000bch\000"
-"\\bblack\\b\000blk\000"
-"\\bbluff\\b\000blf\000"
-"\\bbottm\\b\000bot\000"
-"\\bboulv\\b\000blvd\000"
-"\\bbrdge\\b\000brg\000"
-"\\bbrnch\\b\000br\000"
-"\\bbrook\\b\000brk\000"
-"\\bburgs\\b\000bgs\000"
-"\\bbypas\\b\000byp\000"
-"\\bcalif\\b\000ca\000"
-"\\bcalle\\b\000cll\000"
-"\\bcanyn\\b\000cyn\000"
-"\\bcentr\\b\000cen\000"
-"\\bcircl\\b\000cir\000"
-"\\bcliff\\b\000clf\000"
-"\\bcnter\\b\000cen\000"
-"\\bcourt\\b\000ct\000"
-"\\bcoves\\b\000cvs\000"
-"\\bcrcle\\b\000cir\000"
-"\\bcreek\\b\000ck\000"
-"\\bcrest\\b\000crst\000"
-"\\bcrsnt\\b\000cres\000"
-"\\bcurve\\b\000curv\000"
-"\\bdepot\\b\000dep\000"
-"\\bdrive\\b\000dr\000"
-"\\beight\\b\0008\000"
-"\\bfalls\\b\000fls\000"
-"\\bferry\\b\000fry\000"
-"\\bfield\\b\000fld\000"
-"\\bfifth\\b\0005\000"
-"\\bfirst\\b\0001\000"
-"\\bflats\\b\000flts\000"
-"\\bfords\\b\000frds\000"
-"\\bforge\\b\000frg\000"
-"\\bforks\\b\000fks\000"
-"\\bfrway\\b\000fwy\000"
-"\\bgardn\\b\000gdn\000"
-"\\bglens\\b\000glns\000"
-"\\bgrand\\b\000grnd\000"
-"\\bgrden\\b\000gdn\000"
-"\\bgrdns\\b\000gdns\000"
-"\\bgreen\\b\000grn\000"
-"\\bgrove\\b\000grv\000"
-"\\bgtway\\b\000gtwy\000"
-"\\bharbr\\b\000hbr\000"
-"\\bhaven\\b\000hvn\000"
-"\\bhills\\b\000hl\000"
-"\\bhiway\\b\000hwy\000"
-"\\bholws\\b\000hllw\000"
-"\\bhouse\\b\000hse\000"
-"\\bhrbor\\b\000hbr\000"
-"\\bidaho\\b\000id\000"
-"\\binlet\\b\000inlt\000"
-"\\bisles\\b\000isle\000"
-"\\bislnd\\b\000is\000"
-"\\bjctns\\b\000jcts\000"
-"\\bknoll\\b\000knl\000"
-"\\blakes\\b\000lks\000"
-"\\blanes\\b\000la\000"
-"\\blight\\b\000lgt\000"
-"\\blndng\\b\000lndg\000"
-"\\blocks\\b\000lcks\000"
-"\\blodge\\b\000ldg\000"
-"\\bloops\\b\000loop\000"
-"\\blower\\b\000lo\000"
-"\\bm\\s+l\\s+k\\b\000mlk\000"
-"\\bmaine\\b\000me\000"
-"\\bmanor\\b\000mnr\000"
-"\\bmills\\b\000mls\000"
-"\\bmissn\\b\000msn\000"
-"\\bmntns\\b\000mtns\000"
-"\\bmount\\b\000mt\000"
-"\\bn\\s+y\\s+c\\b\000ny\000"
-"\\bninth\\b\0009\000"
-"\\bnorth\\b\000n\000"
-"\\bpalau\\b\000pw\000"
-"\\bpalms\\b\000plms\000"
-"\\bpaseo\\b\000pso\000"
-"\\bpaths\\b\000path\000"
-"\\bpikes\\b\000pike\000"
-"\\bpines\\b\000pnes\000"
-"\\bpkway\\b\000pky\000"
-"\\bplace\\b\000pl\000"
-"\\bplain\\b\000pln\000"
-"\\bplaza\\b\000plz\000"
-"\\bpoint\\b\000pt\000"
-"\\bponds\\b\000pnds\000"
-"\\bports\\b\000prts\000"
-"\\branch\\b\000rch\000"
-"\\brapid\\b\000rpd\000"
-"\\bridge\\b\000rdg\000"
-"\\briver\\b\000riv\000"
-"\\broads\\b\000rds\000"
-"\\broute\\b\000rt\000"
-"\\bsaint\\b\000st\000"
-"\\bseven\\b\0007\000"
-"\\bshoal\\b\000shl\000"
-"\\bshoar\\b\000shr\000"
-"\\bshore\\b\000shr\000"
-"\\bsixth\\b\0006\000"
-"\\bsouth\\b\000s\000"
-"\\bspace\\b\000sp\000"
-"\\bspngs\\b\000spg\000"
-"\\bsprgs\\b\000spg\000"
-"\\bsprng\\b\000spg\000"
-"\\bstatn\\b\000sta\000"
-"\\bstrav\\b\000stra\000"
-"\\bstrvn\\b\000stra\000"
-"\\bsumit\\b\000smt\000"
-"\\btenth\\b\00010\000"
-"\\btexas\\b\000tx\000"
-"\\bthird\\b\0003\000"
-"\\bthree\\b\0003\000"
-"\\btrace\\b\000trce\000"
-"\\btrack\\b\000trk\000"
-"\\btrail\\b\000tr\000"
-"\\btrnpk\\b\000tpk\000"
-"\\btunel\\b\000tunl\000"
-"\\btunls\\b\000tunl\000"
-"\\btunnl\\b\000tunl\000"
-"\\bu\\s+s\\s+a\\b\000us\000"
-"\\bunion\\b\000un\000"
-"\\bvally\\b\000vl\000"
-"\\bverdi\\b\000verde\000"
-"\\bviews\\b\000vws\000"
-"\\bville\\b\000vl\000"
-"\\bvillg\\b\000vil\000"
-"\\bvista\\b\000vis\000"
-"\\bwells\\b\000wls\000"
-"\\bwoods\\b\000wds\000"
-"\\bworks\\b\000wks\000"
-"\\bxroad\\b\000xrd\000"
-"\\bally\\b\000aly\000"
-"\\banex\\b\000anx\000"
-"\\bariz\\b\000az\000"
-"\\baven\\b\000av\000"
-"\\bbend\\b\000bnd\000"
-"\\bbluf\\b\000blf\000"
-"\\bboul\\b\000blvd\000"
-"\\bburg\\b\000bg\000"
-"\\bbyng\\b\000bing\000"
-"\\bbypa\\b\000byp\000"
-"\\bbyps\\b\000byp\000"
-"\\bcamp\\b\000cp\000"
-"\\bcape\\b\000cpe\000"
-"\\bcent\\b\000cen\000"
-"\\bcirc\\b\000cir\000"
-"\\bcity\\b\000cy\000"
-"\\bclub\\b\000clb\000"
-"\\bcntr\\b\000cen\000"
-"\\bcnyn\\b\000cyn\000"
-"\\bcolo\\b\000co\000"
-"\\bconn\\b\000ct\000"
-"\\bcove\\b\000cv\000"
-"\\bcrcl\\b\000cir\000"
-"\\bdale\\b\000dl\000"
-"\\bdriv\\b\000dr\000"
-"\\beast\\b\000e\000"
-"\\bexpr\\b\000exp\000"
-"\\bexpw\\b\000exp\000"
-"\\bexpy\\b\000exp\000"
-"\\bextn\\b\000ext\000"
-"\\bfarm\\b\000frm\000"
-"\\bfive\\b\0005\000"
-"\\bflat\\b\000flt\000"
-"\\bford\\b\000frd\000"
-"\\bforg\\b\000frg\000"
-"\\bfork\\b\000frk\000"
-"\\bfort\\b\000ft\000"
-"\\bfour\\b\0004\000"
-"\\bfrks\\b\000fks\000"
-"\\bfrry\\b\000fry\000"
-"\\bfrwy\\b\000fwy\000"
-"\\bglen\\b\000gln\000"
-"\\bgrdn\\b\000gdn\000"
-"\\bgrov\\b\000grv\000"
-"\\bguam\\b\000gu\000"
-"\\bharb\\b\000hbr\000"
-"\\bhavn\\b\000hvn\000"
-"\\bhght\\b\000ht\000"
-"\\bhgts\\b\000ht\000"
-"\\bhill\\b\000hl\000"
-"\\bhiwy\\b\000hwy\000"
-"\\bholw\\b\000hllw\000"
-"\\bhway\\b\000hwy\000"
-"\\biowa\\b\000ia\000"
-"\\bjctn\\b\000jt\000"
-"\\bjnct\\b\000jt\000"
-"\\bkans\\b\000ks\000"
-"\\bkeys\\b\000kys\000"
-"\\bknol\\b\000knl\000"
-"\\blake\\b\000lk\000"
-"\\blane\\b\000la\000"
-"\\bldge\\b\000ldg\000"
-"\\blitl\\b\000ltl\000"
-"\\bloaf\\b\000lf\000"
-"\\block\\b\000lck\000"
-"\\blodg\\b\000ldg\000"
-"\\bmass\\b\000ma\000"
-"\\bmich\\b\000mi\000"
-"\\bmile\\b\000mle\000"
-"\\bmill\\b\000ml\000"
-"\\bminn\\b\000mn\000"
-"\\bmiss\\b\000ms\000"
-"\\bmntn\\b\000mnt\000"
-"\\bmssn\\b\000msn\000"
-"\\bmtin\\b\000mnt\000"
-"\\bnebr\\b\000ne\000"
-"\\bneck\\b\000nck\000"
-"\\bnine\\b\0009\000"
-"\\bohio\\b\000oh\000"
-"\\bokla\\b\000ok\000"
-"\\boreg\\b\000or\000"
-"\\boval\\b\000ovl\000"
-"\\bpalm\\b\000plm\000"
-"\\bpark\\b\000pk\000"
-"\\bpass\\b\000ps\000"
-"\\bpine\\b\000pne\000"
-"\\bpkwy\\b\000pky\000"
-"\\bplza\\b\000plz\000"
-"\\bport\\b\000prt\000"
-"\\bradl\\b\000rad\000"
-"\\brdge\\b\000rdg\000"
-"\\brest\\b\000rst\000"
-"\\brivr\\b\000riv\000"
-"\\brnch\\b\000rch\000"
-"\\broad\\b\000rd\000"
-"\\bspgs\\b\000spg\000"
-"\\bspng\\b\000spg\000"
-"\\bsprg\\b\000spg\000"
-"\\bsqre\\b\000sq\000"
-"\\bsqrs\\b\000sqs\000"
-"\\bstrt\\b\000st\000"
-"\\btenn\\b\000\000"
-"\\bterr\\b\000ter\000"
-"\\btown\\b\000\000"
-"\\btpke\\b\000tpk\000"
-"\\btrak\\b\000trk\000"
-"\\btrks\\b\000trk\000"
-"\\btrls\\b\000tr\000"
-"\\btrpk\\b\000tpk\000"
-"\\btwln\\b\000t l\000"
-"\\btwsp\\b\000tp\000"
-"\\butah\\b\000ut\000"
-"\\bvdct\\b\000via\000"
-"\\bview\\b\000vw\000"
-"\\bvill\\b\000vil\000"
-"\\bvist\\b\000vis\000"
-"\\bvlly\\b\000vl\000"
-"\\bvsta\\b\000vis\000"
-"\\bwash\\b\000wa\000"
-"\\bwell\\b\000wl\000"
-"\\bwest\\b\000w\000"
-"\\bx\\s+rd\\b\000xrd\000"
-"\\bala\\b\000al\000"
-"\\bave\\b\000av\000"
-"\\bavn\\b\000av\000"
-"\\bbtm\\b\000bot\000"
-"\\bcam\\b\000cm\000"
-"\\bcmp\\b\000cp\000"
-"\\bcrk\\b\000ck\000"
-"\\bcrt\\b\000ct\000"
-"\\bctr\\b\000cen\000"
-"\\bcty\\b\000cy\000"
-"\\bd\\s+c\\b\000dc\000"
-"\\bdam\\b\000dm\000"
-"\\bdiv\\b\000dv\000"
-"\\bdpt\\b\000dep\000"
-"\\bdrv\\b\000dr\000"
-"\\bdvd\\b\000dv\000"
-"\\bfla\\b\000fl\000"
-"\\bfrt\\b\000ft\000"
-"\\bhei\\b\000ht\000"
-"\\bhls\\b\000hl\000"
-"\\bhts\\b\000ht\000"
-"\\bill\\b\000il\000"
-"\\bind\\b\000in\000"
-"\\bisl\\b\000is\000"
-"\\biss\\b\000is\000"
-"\\bjct\\b\000jt\000"
-"\\bkan\\b\000ks\000"
-"\\bkey\\b\000ky\000"
-"\\bl\\s+a\\b\000la\000"
-"\\blke\\b\000lk\000"
-"\\blwr\\b\000lo\000"
-"\\bmtn\\b\000mnt\000"
-"\\bn\\s+c\\b\000nc\000"
-"\\bn\\s+d\\b\000nd\000"
-"\\bn\\s+h\\b\000nh\000"
-"\\bn\\s+j\\b\000nj\000"
-"\\bn\\s+m\\b\000nm\000"
-"\\bn\\s+y\\b\000ny\000"
-"\\bneb\\b\000ne\000"
-"\\bnev\\b\000nv\000"
-"\\bnth\\b\000n\000"
-"\\bntl\\b\000nl\000"
-"\\bnyc\\b\000ny\000"
-"\\bnys\\b\000ny\000"
-"\\bone\\b\0001\000"
-"\\bore\\b\000or\000"
-"\\bp\\s+r\\b\000pr\000"
-"\\bprk\\b\000pk\000"
-"\\bprr\\b\000pr\000"
-"\\br\\s+i\\b\000ri\000"
-"\\brte\\b\000rt\000"
-"\\brvr\\b\000riv\000"
-"\\bs\\s+c\\b\000sc\000"
-"\\bs\\s+d\\b\000sd\000"
-"\\bsan\\b\000sn\000"
-"\\bsix\\b\0006\000"
-"\\bspr\\b\000spg\000"
-"\\bsqr\\b\000sq\000"
-"\\bsqu\\b\000sq\000"
-"\\bsth\\b\000s\000"
-"\\bstn\\b\000sta\000"
-"\\bstr\\b\000st\000"
-"\\bten\\b\00010\000"
-"\\btrl\\b\000tr\000"
-"\\btwo\\b\0002\000"
-"\\btwp\\b\000tp\000"
-"\\bu\\s+s\\b\000us\000"
-"\\busa\\b\000us\000"
-"\\bv\\s+i\\b\000vi\000"
-"\\bvlg\\b\000vil\000"
-"\\bvly\\b\000vl\000"
-"\\bvst\\b\000vis\000"
-"\\bw\\s+v\\b\000wv\000"
-"\\bway\\b\000wy\000"
-"\\bwis\\b\000wi\000"
-"\\bwva\\b\000wv\000"
-"\\bcr\\b\000ck\000"
-"\\bln\\b\000la\000"
-"\\btn\\b\000\000"
-"\\btw\\b\000tp\000"
-"\\bvy\\b\000vl\000"
-"\\b\\#\\b\000\000"
-;
-int kNumRules_US = 699;
-
-const char* kRules_VN =
-"\\bthi\\s+tran\\s+van\\s+dien\\b\000ttvan dien\000"
-"\\bho\\s+chi\\s+minh\\s+city\\b\000hcm\000"
-"\\bho\\s+chi\\s+minh\\b\000hcm\000"
-"\\bthanh\\s+pho\\b\000tp\000"
-"\\bthi\\s+tran\\b\000tt\000"
-"\\btpha\\s+noi\\b\000ha noi\000"
-"\\bviet\\s+nam\\b\000vn\000"
-"\\bvietnam\\b\000vn\000"
-"\\bphuong\\b\000p\000"
-"\\bthi\\s+xa\\b\000tx\000"
-"\\bhuyen\\b\000h.\000"
-"\\bhcmc\\b\000hcm\000"
-"\\bquan\\b\000q.\000"
-"\\bph\\.\\b\000p\000"
-"\\btp\\.\\b\000tp\000"
-"\\btt\\.\\b\000tt\000"
-"\\btx\\.\\b\000tx\000"
-"\\bp\\.\\b\000p\000"
-"\\bxa\\b\000x.\000"
-;
-int kNumRules_VN = 19;
-
-const char* kRules_ZA =
-"\\brepublic\\s+of\\s+south\\s+africa\\b\000sa\000"
-"\\bkwazulu\\s+natal\\b\000nl\000"
-"\\bnorthern\\s+cape\\b\000nc\000"
-"\\beastern\\s+cape\\b\000ec\000"
-"\\bkwazulunatal\\b\000nl\000"
-"\\bsouth\\s+africa\\b\000sa\000"
-"\\bwestern\\s+cape\\b\000wc\000"
-"\\bfree\\s+state\\b\000fs\000"
-"\\bmpumalanga\\b\000mp\000"
-"\\bnoord\\s+kaap\\b\000nc\000"
-"\\bnorth\\s+west\\b\000nw\000"
-"\\bboulevard\\b\000blvd\000"
-"\\bfreestate\\b\000fs\000"
-"\\bnoordwes\\b\000nw\000"
-"\\boos\\s+kaap\\b\000ec\000"
-"\\bvrystaat\\b\000fs\000"
-"\\bwes\\s+kaap\\b\000wc\000"
-"\\bgauteng\\b\000gp\000"
-"\\bhighway\\b\000hwy\000"
-"\\blimpopo\\b\000lp\000"
-"\\bavenue\\b\000ave\000"
-"\\bstreet\\b\000st\000"
-"\\bdrive\\b\000dr\000"
-"\\bnatal\\b\000nl\000"
-"\\bsaint\\b\000st\000"
-"\\broad\\b\000rd\000"
-"\\bkzn\\b\000nl\000"
-"\\bgt\\b\000gp\000"
-"\\bza\\b\000sa\000"
-"\\bzn\\b\000nl\000"
-;
-int kNumRules_ZA = 30;
-
-}  // namespace
-
-const RegionInfo kRuleTable[] = {
-   {"AD", kRules_AD, kNumRules_AD},
-   {"AR", kRules_AR, kNumRules_AR},
-   {"AU", kRules_AU, kNumRules_AU},
-   {"BE", kRules_BE, kNumRules_BE},
-   {"BR", kRules_BR, kNumRules_BR},
-   {"CA", kRules_CA, kNumRules_CA},
-   {"CH", kRules_CH, kNumRules_CH},
-   {"CL", kRules_CL, kNumRules_CL},
-   {"CO", kRules_CO, kNumRules_CO},
-   {"DE", kRules_DE, kNumRules_DE},
-   {"DK", kRules_DK, kNumRules_DK},
-   {"ES", kRules_ES, kNumRules_ES},
-   {"FR", kRules_FR, kNumRules_FR},
-   {"GB", kRules_GB, kNumRules_GB},
-   {"GR", kRules_GR, kNumRules_GR},
-   {"HK", kRules_HK, kNumRules_HK},
-   {"ID", kRules_ID, kNumRules_ID},
-   {"IE", kRules_IE, kNumRules_IE},
-   {"IN", kRules_IN, kNumRules_IN},
-   {"IT", kRules_IT, kNumRules_IT},
-   {"LU", kRules_LU, kNumRules_LU},
-   {"MX", kRules_MX, kNumRules_MX},
-   {"MY", kRules_MY, kNumRules_MY},
-   {"NL", kRules_NL, kNumRules_NL},
-   {"NZ", kRules_NZ, kNumRules_NZ},
-   {"PE", kRules_PE, kNumRules_PE},
-   {"PH", kRules_PH, kNumRules_PH},
-   {"PL", kRules_PL, kNumRules_PL},
-   {"PR", kRules_PR, kNumRules_PR},
-   {"PT", kRules_PT, kNumRules_PT},
-   {"RO", kRules_RO, kNumRules_RO},
-   {"RU", kRules_RU, kNumRules_RU},
-   {"SE", kRules_SE, kNumRules_SE},
-   {"TH", kRules_TH, kNumRules_TH},
-   {"TR", kRules_TR, kNumRules_TR},
-   {"US", kRules_US, kNumRules_US},
-   {"VN", kRules_VN, kNumRules_VN},
-   {"ZA", kRules_ZA, kNumRules_ZA},
-};
-
-const size_t kRuleTableSize = sizeof(kRuleTable)/sizeof(kRuleTable[0]);
-}  // namespace internal
-}  // namespace autofill
diff --git a/components/autofill/core/browser/address_rewriter_unittest.cc b/components/autofill/core/browser/address_rewriter_unittest.cc
index 67d97dc..e36f2fe 100644
--- a/components/autofill/core/browser/address_rewriter_unittest.cc
+++ b/components/autofill/core/browser/address_rewriter_unittest.cc
@@ -21,12 +21,25 @@
   EXPECT_NE(ad.Rewrite(kSomeRandomText), ad.Rewrite(kOtherRandomText));
 }
 
+TEST(AddressRewriterTest, LastRule) {
+  AddressRewriter last_rule = AddressRewriter::ForCustomRules("1\t2\n3\t4\n");
+  AddressRewriter large_rewrite =
+      AddressRewriter::ForCustomRules("1\tonelongrewrite\n2\tshort\n");
+
+  EXPECT_EQ(last_rule.Rewrite(UTF8ToUTF16("3")),
+            last_rule.Rewrite(UTF8ToUTF16("4")));
+  // Checks if last rule works when previous rewrite is larger than last rule.
+  EXPECT_EQ(large_rewrite.Rewrite(UTF8ToUTF16("2")),
+            large_rewrite.Rewrite(UTF8ToUTF16("short")));
+}
+
 TEST(AddressRewriterTest, AD) {
   AddressRewriter ad = AddressRewriter::ForCountryCode(UTF8ToUTF16("ad"));
   EXPECT_EQ(ad.Rewrite(UTF8ToUTF16("parroquia de andorra la vella")),
             ad.Rewrite(UTF8ToUTF16("andorra la vella")));
   EXPECT_EQ(ad.Rewrite(UTF8ToUTF16("principal de andorra")),
             ad.Rewrite(UTF8ToUTF16("an")));
+  EXPECT_EQ(ad.Rewrite(UTF8ToUTF16("or")), ad.Rewrite(UTF8ToUTF16("ordino")));
 }
 
 TEST(AddressRewriterTest, AR) {
diff --git a/components/autofill/core/browser/autofill_address_rewriter_resources.grd b/components/autofill/core/browser/autofill_address_rewriter_resources.grd
new file mode 100644
index 0000000..18f5ec1
--- /dev/null
+++ b/components/autofill/core/browser/autofill_address_rewriter_resources.grd
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+  <grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+    <outputs>
+      <output filename="grit/autofill_address_rewriter_resources.h" type="rc_header">
+          <emit emit_type="prepend">
+          </emit>
+        </output>
+      <output filename="autofill_address_rewriter_resources.pak" type="data_package" />
+      <output filename="grit/autofill_address_rewriter_resources_map.cc" type="resource_map_source" />
+      <output filename="grit/autofill_address_rewriter_resources_map.h" type="resource_map_header" />
+    </outputs>
+  <release seq="1">
+    <includes>
+      <include name="IDR_ADDRESS_REWRITER_AD_RULES" file="address_rewrite_rules/AD.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_AR_RULES" file="address_rewrite_rules/AR.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_AU_RULES" file="address_rewrite_rules/AU.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_BE_RULES" file="address_rewrite_rules/BE.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_BR_RULES" file="address_rewrite_rules/BR.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_CA_RULES" file="address_rewrite_rules/CA.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_CH_RULES" file="address_rewrite_rules/CH.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_CL_RULES" file="address_rewrite_rules/CL.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_CO_RULES" file="address_rewrite_rules/CO.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_DE_RULES" file="address_rewrite_rules/DE.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_DK_RULES" file="address_rewrite_rules/DK.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_ES_RULES" file="address_rewrite_rules/ES.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_FR_RULES" file="address_rewrite_rules/FR.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_GB_RULES" file="address_rewrite_rules/GB.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_GR_RULES" file="address_rewrite_rules/GR.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_HK_RULES" file="address_rewrite_rules/HK.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_ID_RULES" file="address_rewrite_rules/ID.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_IE_RULES" file="address_rewrite_rules/IE.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_IN_RULES" file="address_rewrite_rules/IN.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_IT_RULES" file="address_rewrite_rules/IT.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_LU_RULES" file="address_rewrite_rules/LU.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_MX_RULES" file="address_rewrite_rules/MX.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_MY_RULES" file="address_rewrite_rules/MY.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_NL_RULES" file="address_rewrite_rules/NL.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_NZ_RULES" file="address_rewrite_rules/NZ.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_PE_RULES" file="address_rewrite_rules/PE.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_PH_RULES" file="address_rewrite_rules/PH.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_PL_RULES" file="address_rewrite_rules/PL.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_PR_RULES" file="address_rewrite_rules/PR.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_PT_RULES" file="address_rewrite_rules/PT.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_RO_RULES" file="address_rewrite_rules/RO.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_RU_RULES" file="address_rewrite_rules/RU.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_SE_RULES" file="address_rewrite_rules/SE.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_TH_RULES" file="address_rewrite_rules/TH.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_TR_RULES" file="address_rewrite_rules/TR.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_US_RULES" file="address_rewrite_rules/US.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_VN_RULES" file="address_rewrite_rules/VN.txt" type="BINDATA" compress="gzip"/>
+      <include name="IDR_ADDRESS_REWRITER_ZA_RULES" file="address_rewrite_rules/ZA.txt" type="BINDATA" compress="gzip"/>
+    </includes>
+  </release>
+</grit>
\ No newline at end of file
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc
index be6390df..c27fa41 100644
--- a/components/cronet/url_request_context_config.cc
+++ b/components/cronet/url_request_context_config.cc
@@ -377,25 +377,26 @@
       int quic_idle_connection_timeout_seconds = 0;
       if (quic_args->GetInteger(kQuicIdleConnectionTimeoutSeconds,
                                 &quic_idle_connection_timeout_seconds)) {
-        session_params->quic_params.idle_connection_timeout_seconds =
-            quic_idle_connection_timeout_seconds;
+        session_params->quic_params.idle_connection_timeout =
+            base::TimeDelta::FromSeconds(quic_idle_connection_timeout_seconds);
       }
 
       int quic_max_time_before_crypto_handshake_seconds = 0;
       if (quic_args->GetInteger(
               kQuicMaxTimeBeforeCryptoHandshakeSeconds,
               &quic_max_time_before_crypto_handshake_seconds)) {
-        session_params->quic_params.max_time_before_crypto_handshake_seconds =
-            quic_max_time_before_crypto_handshake_seconds;
+        session_params->quic_params.max_time_before_crypto_handshake =
+            base::TimeDelta::FromSeconds(
+                quic_max_time_before_crypto_handshake_seconds);
       }
 
       int quic_max_idle_time_before_crypto_handshake_seconds = 0;
       if (quic_args->GetInteger(
               kQuicMaxIdleTimeBeforeCryptoHandshakeSeconds,
               &quic_max_idle_time_before_crypto_handshake_seconds)) {
-        session_params->quic_params
-            .max_idle_time_before_crypto_handshake_seconds =
-            quic_max_idle_time_before_crypto_handshake_seconds;
+        session_params->quic_params.max_idle_time_before_crypto_handshake =
+            base::TimeDelta::FromSeconds(
+                quic_max_idle_time_before_crypto_handshake_seconds);
       }
 
       bool quic_close_sessions_on_ip_change = false;
@@ -495,9 +496,9 @@
       if (quic_args->GetInteger(
               kQuicRetransmittableOnWireTimeoutMilliseconds,
               &quic_retransmittable_on_wire_timeout_milliseconds)) {
-        session_params->quic_params
-            .retransmittable_on_wire_timeout_milliseconds =
-            quic_retransmittable_on_wire_timeout_milliseconds;
+        session_params->quic_params.retransmittable_on_wire_timeout =
+            base::TimeDelta::FromMilliseconds(
+                quic_retransmittable_on_wire_timeout_milliseconds);
       }
 
       bool quic_retry_on_alternate_network_before_handshake = false;
diff --git a/components/cronet/url_request_context_config_unittest.cc b/components/cronet/url_request_context_config_unittest.cc
index 3478267..718b2f3 100644
--- a/components/cronet/url_request_context_config_unittest.cc
+++ b/components/cronet/url_request_context_config_unittest.cc
@@ -197,8 +197,8 @@
   // Check max_server_configs_stored_in_properties.
   EXPECT_EQ(2u, params->quic_params.max_server_configs_stored_in_properties);
 
-  // Check idle_connection_timeout_seconds.
-  EXPECT_EQ(300, params->quic_params.idle_connection_timeout_seconds);
+  // Check idle_connection_timeout.
+  EXPECT_EQ(300, params->quic_params.idle_connection_timeout.InSeconds());
 
   EXPECT_TRUE(params->quic_params.close_sessions_on_ip_change);
   EXPECT_FALSE(params->quic_params.goaway_sessions_on_ip_change);
@@ -691,8 +691,9 @@
   EXPECT_TRUE(params->quic_params.migrate_sessions_on_network_change_v2);
   EXPECT_TRUE(params->quic_params.migrate_sessions_early_v2);
   EXPECT_TRUE(params->quic_params.retry_on_alternate_network_before_handshake);
-  EXPECT_EQ(1000,
-            params->quic_params.retransmittable_on_wire_timeout_milliseconds);
+  EXPECT_EQ(
+      1000,
+      params->quic_params.retransmittable_on_wire_timeout.InMilliseconds());
   EXPECT_TRUE(params->quic_params.migrate_idle_sessions);
   EXPECT_EQ(base::TimeDelta::FromSeconds(15),
             params->quic_params.idle_session_migration_period);
@@ -857,9 +858,11 @@
   const net::HttpNetworkSession::Params* params =
       context->GetNetworkSessionParams();
 
-  EXPECT_EQ(7, params->quic_params.max_time_before_crypto_handshake_seconds);
-  EXPECT_EQ(11,
-            params->quic_params.max_idle_time_before_crypto_handshake_seconds);
+  EXPECT_EQ(7,
+            params->quic_params.max_time_before_crypto_handshake.InSeconds());
+  EXPECT_EQ(
+      11,
+      params->quic_params.max_idle_time_before_crypto_handshake.InSeconds());
 }
 
 TEST(URLURLRequestContextConfigTest, SetQuicConnectionOptions) {
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 94dcc0d..832ae9b 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -537,8 +537,8 @@
 void Surface::Commit() {
   TRACE_EVENT0("exo", "Surface::Commit");
 
-  if (!commit_callback_.is_null())
-    commit_callback_.Run(this);
+  for (auto& observer : observers_)
+    observer.OnCommit(this);
 
   needs_commit_surface_ = true;
   if (delegate_)
@@ -785,10 +785,6 @@
   return observers_.HasObserver(observer);
 }
 
-void Surface::SetCommitCallback(CommitCallback callback) {
-  commit_callback_ = std::move(callback);
-}
-
 std::unique_ptr<base::trace_event::TracedValue> Surface::AsTracedValue() const {
   std::unique_ptr<base::trace_event::TracedValue> value(
       new base::trace_event::TracedValue());
diff --git a/components/exo/surface.h b/components/exo/surface.h
index fb77ed4..bbe21ecd 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -66,8 +66,6 @@
  public:
   using PropertyDeallocator = void (*)(int64_t value);
 
-  using CommitCallback = base::RepeatingCallback<void(Surface*)>;
-
   Surface();
   ~Surface();
 
@@ -226,9 +224,6 @@
   void RemoveSurfaceObserver(SurfaceObserver* observer);
   bool HasSurfaceObserver(const SurfaceObserver* observer) const;
 
-  // Sets/resets commit callback. Used by |ArcGraphicsTracingHandler|.
-  void SetCommitCallback(CommitCallback callback);
-
   // Returns a trace value representing the state of the surface.
   std::unique_ptr<base::trace_event::TracedValue> AsTracedValue() const;
 
@@ -432,8 +427,6 @@
 
   // Surface observer list. Surface does not own the observers.
   base::ObserverList<SurfaceObserver, true>::Unchecked observers_;
-  // Called on each commit. May not be set.
-  CommitCallback commit_callback_;
 
   // Whether this surface is tracking occlusion for the client.
   bool is_tracking_occlusion_ = false;
diff --git a/components/exo/surface_observer.h b/components/exo/surface_observer.h
index 69c5a09..078d29d 100644
--- a/components/exo/surface_observer.h
+++ b/components/exo/surface_observer.h
@@ -19,6 +19,9 @@
   // changes.
   virtual void OnWindowOcclusionChanged(Surface* surface) {}
 
+  // Called on each commit.
+  virtual void OnCommit(Surface* surface) {}
+
  protected:
   virtual ~SurfaceObserver() {}
 };
diff --git a/components/mirroring/service/session.cc b/components/mirroring/service/session.cc
index 93b4d8e..0e7a514 100644
--- a/components/mirroring/service/session.cc
+++ b/components/mirroring/service/session.cc
@@ -44,14 +44,14 @@
 #include "net/base/ip_endpoint.h"
 #include "services/viz/public/cpp/gpu/gpu.h"
 
-using media::cast::FrameSenderConfig;
-using media::cast::RtpPayloadType;
 using media::cast::CastTransportStatus;
 using media::cast::Codec;
 using media::cast::FrameEvent;
-using media::cast::PacketEvent;
+using media::cast::FrameSenderConfig;
 using media::cast::OperationalStatus;
 using media::cast::Packet;
+using media::cast::PacketEvent;
+using media::cast::RtpPayloadType;
 using media::mojom::RemotingSinkAudioCapability;
 using media::mojom::RemotingSinkVideoCapability;
 using mirroring::mojom::SessionError;
@@ -347,7 +347,7 @@
 
   // Called on audio thread.
   void Capture(const media::AudioBus* audio_bus,
-               int audio_delay_milliseconds,
+               base::TimeTicks audio_capture_time,
                double volume,
                bool key_pressed) override {
     // TODO(xjz): Don't copy the audio data. Instead, send |audio_bus| directly
@@ -355,10 +355,7 @@
     std::unique_ptr<media::AudioBus> captured_audio =
         media::AudioBus::Create(audio_bus->channels(), audio_bus->frames());
     audio_bus->CopyTo(captured_audio.get());
-    const base::TimeTicks recorded_time =
-        base::TimeTicks::Now() -
-        base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
-    audio_data_callback_.Run(std::move(captured_audio), recorded_time);
+    audio_data_callback_.Run(std::move(captured_audio), audio_capture_time);
   }
 
   void OnCaptureError(const std::string& message) override {
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc
index 409c0685..7979448 100644
--- a/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -477,27 +477,29 @@
     int idle_connection_timeout_seconds =
         GetQuicIdleConnectionTimeoutSeconds(quic_trial_params);
     if (idle_connection_timeout_seconds != 0) {
-      params->quic_params.idle_connection_timeout_seconds =
-          idle_connection_timeout_seconds;
+      params->quic_params.idle_connection_timeout =
+          base::TimeDelta::FromSeconds(idle_connection_timeout_seconds);
     }
     int reduced_ping_timeout_seconds =
         GetQuicReducedPingTimeoutSeconds(quic_trial_params);
     if (reduced_ping_timeout_seconds > 0 &&
         reduced_ping_timeout_seconds < quic::kPingTimeoutSecs) {
-      params->quic_params.reduced_ping_timeout_seconds =
-          reduced_ping_timeout_seconds;
+      params->quic_params.reduced_ping_timeout =
+          base::TimeDelta::FromSeconds(reduced_ping_timeout_seconds);
     }
     int max_time_before_crypto_handshake_seconds =
         GetQuicMaxTimeBeforeCryptoHandshakeSeconds(quic_trial_params);
     if (max_time_before_crypto_handshake_seconds > 0) {
-      params->quic_params.max_time_before_crypto_handshake_seconds =
-          max_time_before_crypto_handshake_seconds;
+      params->quic_params.max_time_before_crypto_handshake =
+          base::TimeDelta::FromSeconds(
+              max_time_before_crypto_handshake_seconds);
     }
     int max_idle_time_before_crypto_handshake_seconds =
         GetQuicMaxIdleTimeBeforeCryptoHandshakeSeconds(quic_trial_params);
     if (max_idle_time_before_crypto_handshake_seconds > 0) {
-      params->quic_params.max_idle_time_before_crypto_handshake_seconds =
-          max_idle_time_before_crypto_handshake_seconds;
+      params->quic_params.max_idle_time_before_crypto_handshake =
+          base::TimeDelta::FromSeconds(
+              max_idle_time_before_crypto_handshake_seconds);
     }
     params->quic_params.race_cert_verification =
         ShouldQuicRaceCertVerification(quic_trial_params);
@@ -516,14 +518,16 @@
     int initial_rtt_for_handshake_milliseconds =
         GetQuicInitialRttForHandshakeMilliseconds(quic_trial_params);
     if (initial_rtt_for_handshake_milliseconds > 0) {
-      params->quic_params.initial_rtt_for_handshake_milliseconds =
-          initial_rtt_for_handshake_milliseconds;
+      params->quic_params.initial_rtt_for_handshake =
+          base::TimeDelta::FromMilliseconds(
+              initial_rtt_for_handshake_milliseconds);
     }
     int retransmittable_on_wire_timeout_milliseconds =
         GetQuicRetransmittableOnWireTimeoutMilliseconds(quic_trial_params);
     if (retransmittable_on_wire_timeout_milliseconds > 0) {
-      params->quic_params.retransmittable_on_wire_timeout_milliseconds =
-          retransmittable_on_wire_timeout_milliseconds;
+      params->quic_params.retransmittable_on_wire_timeout =
+          base::TimeDelta::FromMilliseconds(
+              retransmittable_on_wire_timeout_milliseconds);
     }
     params->quic_params.migrate_idle_sessions =
         ShouldQuicMigrateIdleSessions(quic_trial_params);
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index d1f13354..4db23a0 100644
--- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -112,14 +112,14 @@
   EXPECT_FALSE(params_.enable_server_push_cancellation);
   EXPECT_FALSE(params_.quic_params.close_sessions_on_ip_change);
   EXPECT_FALSE(params_.quic_params.goaway_sessions_on_ip_change);
-  EXPECT_EQ(net::kIdleConnectionTimeoutSeconds,
-            params_.quic_params.idle_connection_timeout_seconds);
-  EXPECT_EQ(quic::kPingTimeoutSecs,
-            params_.quic_params.reduced_ping_timeout_seconds);
-  EXPECT_EQ(quic::kMaxTimeForCryptoHandshakeSecs,
-            params_.quic_params.max_time_before_crypto_handshake_seconds);
-  EXPECT_EQ(quic::kInitialIdleTimeoutSecs,
-            params_.quic_params.max_idle_time_before_crypto_handshake_seconds);
+  EXPECT_EQ(net::kIdleConnectionTimeout,
+            params_.quic_params.idle_connection_timeout);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(quic::kPingTimeoutSecs),
+            params_.quic_params.reduced_ping_timeout);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(quic::kMaxTimeForCryptoHandshakeSecs),
+            params_.quic_params.max_time_before_crypto_handshake);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(quic::kInitialIdleTimeoutSecs),
+            params_.quic_params.max_idle_time_before_crypto_handshake);
   EXPECT_FALSE(params_.quic_params.race_cert_verification);
   EXPECT_FALSE(params_.quic_params.estimate_initial_rtt);
   EXPECT_FALSE(params_.quic_params.migrate_sessions_on_network_change_v2);
@@ -127,11 +127,10 @@
   EXPECT_FALSE(params_.quic_params.retry_on_alternate_network_before_handshake);
   EXPECT_FALSE(params_.quic_params.migrate_idle_sessions);
   EXPECT_FALSE(params_.quic_params.go_away_on_path_degrading);
-  EXPECT_EQ(0, params_.quic_params.initial_rtt_for_handshake_milliseconds);
+  EXPECT_TRUE(params_.quic_params.initial_rtt_for_handshake.is_zero());
   EXPECT_FALSE(params_.quic_params.allow_server_migration);
   EXPECT_TRUE(params_.quic_host_whitelist.empty());
-  EXPECT_EQ(0,
-            params_.quic_params.retransmittable_on_wire_timeout_milliseconds);
+  EXPECT_TRUE(params_.quic_params.retransmittable_on_wire_timeout.is_zero());
 
   net::HttpNetworkSession::Params default_params;
   EXPECT_EQ(default_params.quic_params.supported_versions,
@@ -237,8 +236,8 @@
 
   ParseFieldTrials();
 
-  EXPECT_EQ(1000,
-            params_.quic_params.retransmittable_on_wire_timeout_milliseconds);
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000),
+            params_.quic_params.retransmittable_on_wire_timeout);
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
@@ -250,7 +249,8 @@
 
   ParseFieldTrials();
 
-  EXPECT_EQ(300, params_.quic_params.idle_connection_timeout_seconds);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(300),
+            params_.quic_params.idle_connection_timeout);
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
@@ -260,8 +260,8 @@
   variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
   base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
   ParseFieldTrials();
-  EXPECT_EQ(quic::kPingTimeoutSecs,
-            params_.quic_params.reduced_ping_timeout_seconds);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(quic::kPingTimeoutSecs),
+            params_.quic_params.reduced_ping_timeout);
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
@@ -271,8 +271,8 @@
   variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
   base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
   ParseFieldTrials();
-  EXPECT_EQ(quic::kPingTimeoutSecs,
-            params_.quic_params.reduced_ping_timeout_seconds);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(quic::kPingTimeoutSecs),
+            params_.quic_params.reduced_ping_timeout);
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
@@ -282,7 +282,8 @@
   variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
   base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
   ParseFieldTrials();
-  EXPECT_EQ(10, params_.quic_params.reduced_ping_timeout_seconds);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(10),
+            params_.quic_params.reduced_ping_timeout);
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
@@ -292,7 +293,8 @@
   variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
   base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
   ParseFieldTrials();
-  EXPECT_EQ(7, params_.quic_params.max_time_before_crypto_handshake_seconds);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(7),
+            params_.quic_params.max_time_before_crypto_handshake);
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
@@ -302,8 +304,8 @@
   variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
   base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
   ParseFieldTrials();
-  EXPECT_EQ(quic::kMaxTimeForCryptoHandshakeSecs,
-            params_.quic_params.max_time_before_crypto_handshake_seconds);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(quic::kMaxTimeForCryptoHandshakeSecs),
+            params_.quic_params.max_time_before_crypto_handshake);
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
@@ -313,8 +315,8 @@
   variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
   base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
   ParseFieldTrials();
-  EXPECT_EQ(11,
-            params_.quic_params.max_idle_time_before_crypto_handshake_seconds);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(11),
+            params_.quic_params.max_idle_time_before_crypto_handshake);
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
@@ -324,8 +326,8 @@
   variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
   base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
   ParseFieldTrials();
-  EXPECT_EQ(quic::kInitialIdleTimeoutSecs,
-            params_.quic_params.max_idle_time_before_crypto_handshake_seconds);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(quic::kInitialIdleTimeoutSecs),
+            params_.quic_params.max_idle_time_before_crypto_handshake);
 }
 
 TEST_F(NetworkSessionConfiguratorTest, QuicRaceCertVerification) {
@@ -861,7 +863,8 @@
 
   ParseFieldTrials();
 
-  EXPECT_EQ(500, params_.quic_params.initial_rtt_for_handshake_milliseconds);
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(500),
+            params_.quic_params.initial_rtt_for_handshake);
 }
 
 }  // namespace network_session_configurator
diff --git a/components/ntp_snippets/OWNERS b/components/ntp_snippets/OWNERS
index 21f8d6d..bedbf1a 100644
--- a/components/ntp_snippets/OWNERS
+++ b/components/ntp_snippets/OWNERS
@@ -1,5 +1,8 @@
 fgorski@chromium.org
 pnoland@chromium.org
+harringtond@chromium.org
+carlosk@chromium.org
+dimich@chromium.org
 zea@chromium.org
 
 # For ios:
diff --git a/components/ntp_snippets/remote/remote_suggestion.cc b/components/ntp_snippets/remote/remote_suggestion.cc
index 6a9851b..58c71138 100644
--- a/components/ntp_snippets/remote/remote_suggestion.cc
+++ b/components/ntp_snippets/remote/remote_suggestion.cc
@@ -87,15 +87,18 @@
   snippet->fetch_date_ = fetch_date;
 
   if (!(dict.GetString("title", &snippet->title_) &&
-        dict.GetString("snippet", &snippet->snippet_) &&
         GetTimeValue(dict, "creationTime", &snippet->publish_date_) &&
         GetTimeValue(dict, "expirationTime", &snippet->expiry_date_) &&
-        GetURLValue(dict, "imageUrl", &snippet->salient_image_url_) &&
         dict.GetString("attribution", &snippet->publisher_name_) &&
         GetURLValue(dict, "fullPageUrl", &snippet->url_))) {
     return nullptr;
   }
-  GetURLValue(dict, "ampUrl", &snippet->amp_url_);  // May fail; OK.
+
+  // Optional fields.
+  dict.GetString("snippet", &snippet->snippet_);
+  GetURLValue(dict, "imageUrl", &snippet->salient_image_url_);
+  GetURLValue(dict, "ampUrl", &snippet->amp_url_);
+
   // TODO(sfiera): also favicon URL.
 
   const base::Value* image_dominant_color_value =
diff --git a/components/ntp_snippets/remote/remote_suggestion.h b/components/ntp_snippets/remote/remote_suggestion.h
index 446493fa..7bd138d 100644
--- a/components/ntp_snippets/remote/remote_suggestion.h
+++ b/components/ntp_snippets/remote/remote_suggestion.h
@@ -93,8 +93,7 @@
 
   // If this suggestion has all the data we need to show a full card to the user
   bool is_complete() const {
-    return !id().empty() && !title().empty() && !snippet().empty() &&
-           salient_image_url().is_valid() && !publish_date().is_null() &&
+    return !id().empty() && !title().empty() && !publish_date().is_null() &&
            !expiry_date().is_null() && !publisher_name().empty();
   }
 
diff --git a/components/ntp_snippets/remote/remote_suggestion_unittest.cc b/components/ntp_snippets/remote/remote_suggestion_unittest.cc
index be203fc..f771301c 100644
--- a/components/ntp_snippets/remote/remote_suggestion_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestion_unittest.cc
@@ -24,91 +24,7 @@
 using ::testing::IsNull;
 using ::testing::NotNull;
 
-std::unique_ptr<RemoteSuggestion> SnippetFromContentSuggestionJSON(
-    const std::string& json,
-    const base::Time& fetch_date) {
-  auto json_value = base::JSONReader::ReadDeprecated(json);
-  base::DictionaryValue* json_dict;
-  if (!json_value->GetAsDictionary(&json_dict)) {
-    return nullptr;
-  }
-  return RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json_dict, kArticlesRemoteId, fetch_date);
-}
-
-TEST(RemoteSuggestionTest, FromContentSuggestionsDictionary) {
-  const std::string kJsonStr = R"(
-    {
-      "ids" : ["http://localhost/foobar"],
-      "title" : "Foo Barred from Baz",
-      "snippet" : "...",
-      "fullPageUrl" : "http://localhost/foobar",
-      "creationTime" : "2016-06-30T11:01:37.000Z",
-      "expirationTime" : "2016-07-01T11:01:37.000Z",
-      "attribution" : "Foo News",
-      "imageUrl" : "http://localhost/foobar.jpg",
-      "ampUrl" : "http://localhost/amp",
-      "faviconUrl" : "http://localhost/favicon.ico",
-      "score": 9001,
-      "notificationInfo": {
-        "shouldNotify": true,
-        "deadline": "2016-06-30T13:01:37.000Z"
-      },
-      "imageDominantColor": 4289379276
-    }
-  )";
-  const base::Time fetch_date = DeserializeTime(1466634774L);
-  auto snippet = SnippetFromContentSuggestionJSON(kJsonStr, fetch_date);
-  ASSERT_THAT(snippet, NotNull());
-
-  EXPECT_EQ(snippet->id(), "http://localhost/foobar");
-  EXPECT_EQ(snippet->title(), "Foo Barred from Baz");
-  EXPECT_EQ(snippet->snippet(), "...");
-  EXPECT_EQ(snippet->salient_image_url(), GURL("http://localhost/foobar.jpg"));
-  ASSERT_TRUE(snippet->optional_image_dominant_color().has_value());
-  EXPECT_EQ(*snippet->optional_image_dominant_color(), 4289379276u);
-  EXPECT_EQ(snippet->score(), 9001);
-  auto unix_publish_date = snippet->publish_date() - base::Time::UnixEpoch();
-  auto expiry_duration = snippet->expiry_date() - snippet->publish_date();
-  EXPECT_FLOAT_EQ(unix_publish_date.InSecondsF(), 1467284497.000000f);
-  EXPECT_FLOAT_EQ(expiry_duration.InSecondsF(), 86400.000000f);
-
-  EXPECT_EQ(snippet->publisher_name(), "Foo News");
-  EXPECT_EQ(snippet->url(), GURL("http://localhost/foobar"));
-  EXPECT_EQ(snippet->amp_url(), GURL("http://localhost/amp"));
-
-  EXPECT_TRUE(snippet->should_notify());
-  auto notification_duration =
-      snippet->notification_deadline() - snippet->publish_date();
-  EXPECT_EQ(7200.0f, notification_duration.InSecondsF());
-  EXPECT_EQ(fetch_date, snippet->fetch_date());
-}
-
-TEST(RemoteSuggestionTest,
-     ShouldSupportMultipleIdsFromContentSuggestionsServer) {
-  const std::string kJsonStr = R"(
-    {
-      "ids" : ["http://localhost/foobar", "012345"],
-      "title" : "Foo Barred from Baz",
-      "snippet" : "...",
-      "fullPageUrl" : "http://localhost/foobar",
-      "creationTime" : "2016-06-30T11:01:37.000Z",
-      "expirationTime" : "2016-07-01T11:01:37.000Z",
-      "attribution" : "Foo News",
-      "imageUrl" : "http://localhost/foobar.jpg",
-      "ampUrl" : "http://localhost/amp",
-      "faviconUrl" : "http://localhost/favicon.ico"
-    }
-  )";
-  auto snippet = SnippetFromContentSuggestionJSON(kJsonStr, base::Time());
-  ASSERT_THAT(snippet, NotNull());
-
-  EXPECT_EQ(snippet->id(), "http://localhost/foobar");
-  EXPECT_THAT(snippet->GetAllIDs(),
-              ElementsAre("http://localhost/foobar", "012345"));
-}
-
-TEST(RemoteSuggestionTest, CreateFromProtoToProtoRoundtrip) {
+SnippetProto TestSnippetProto() {
   SnippetProto proto;
   proto.add_ids("foo");
   proto.add_ids("bar");
@@ -118,7 +34,7 @@
   proto.set_image_dominant_color(4289379276);
   proto.set_publish_date(1476095492);
   proto.set_expiry_date(1476354691);
-  proto.set_score(0.1f);
+  proto.set_score(1.5f);
   proto.set_dismissed(false);
   proto.set_remote_category_id(1);
   proto.set_fetch_date(1476364691);
@@ -128,6 +44,88 @@
   source->set_publisher_name("Great Suggestions Inc.");
   source->set_amp_url("http://cdn.ampproject.org/c/foo/");
   proto.set_rank(7);
+  return proto;
+}
+
+base::DictionaryValue TestSnippetJsonValue() {
+  const char kJsonStr[] = R"(
+    {
+      "ids" : ["foo", "bar"],
+      "title" : "a suggestion title",
+      "snippet" : "the snippet describing the suggestion.",
+      "fullPageUrl" : "http://cool-suggestions.com/",
+      "creationTime" : "2016-06-30T11:01:37.000Z",
+      "expirationTime" : "2016-07-01T11:01:37.000Z",
+      "attribution" : "Great Suggestions Inc.",
+      "imageUrl" : "http://google.com/logo/",
+      "ampUrl" : "http://cdn.ampproject.org/c/foo/",
+      "faviconUrl" : "http://localhost/favicon.ico",
+      "score": 1.5,
+      "notificationInfo": {
+        "shouldNotify": true,
+        "deadline": "2016-06-30T13:01:37.000Z"
+      },
+      "imageDominantColor": 4289379276
+    }
+  )";
+
+  auto json_parsed = base::JSONReader::ReadAndReturnValueWithError(
+      kJsonStr, base::JSON_PARSE_RFC);
+  CHECK(json_parsed.value) << "error_message: " << json_parsed.error_message;
+  auto dict = base::DictionaryValue::From(
+      std::make_unique<base::Value>(std::move(json_parsed).value.value()));
+  return std::move(*dict);
+}
+
+TEST(RemoteSuggestionTest, FromContentSuggestionsDictionary) {
+  base::DictionaryValue snippet_dict = TestSnippetJsonValue();
+  const base::Time fetch_date = DeserializeTime(1466634774L);
+  std::unique_ptr<RemoteSuggestion> snippet =
+      RemoteSuggestion::CreateFromContentSuggestionsDictionary(
+          snippet_dict, kArticlesRemoteId, fetch_date);
+  ASSERT_THAT(snippet, NotNull());
+
+  EXPECT_EQ(snippet->id(), "foo");
+  EXPECT_THAT(snippet->GetAllIDs(), ElementsAre("foo", "bar"));
+  EXPECT_EQ(snippet->title(), "a suggestion title");
+  EXPECT_EQ(snippet->snippet(), "the snippet describing the suggestion.");
+  EXPECT_EQ(snippet->salient_image_url(), GURL("http://google.com/logo/"));
+  ASSERT_TRUE(snippet->optional_image_dominant_color().has_value());
+  EXPECT_EQ(*snippet->optional_image_dominant_color(), 4289379276u);
+  EXPECT_EQ(1.5, snippet->score());
+  auto unix_publish_date = snippet->publish_date() - base::Time::UnixEpoch();
+  auto expiry_duration = snippet->expiry_date() - snippet->publish_date();
+  EXPECT_FLOAT_EQ(unix_publish_date.InSecondsF(), 1467284497.000000f);
+  EXPECT_FLOAT_EQ(expiry_duration.InSecondsF(), 86400.000000f);
+
+  EXPECT_EQ(snippet->publisher_name(), "Great Suggestions Inc.");
+  EXPECT_EQ(snippet->url(), GURL("http://cool-suggestions.com/"));
+  EXPECT_EQ(snippet->amp_url(), GURL("http://cdn.ampproject.org/c/foo/"));
+
+  EXPECT_TRUE(snippet->should_notify());
+  auto notification_duration =
+      snippet->notification_deadline() - snippet->publish_date();
+  EXPECT_EQ(7200.0f, notification_duration.InSecondsF());
+  EXPECT_EQ(fetch_date, snippet->fetch_date());
+}
+
+TEST(RemoteSuggestionTest,
+     FromContentSuggestionsDictionaryWithoutImageOrSnippet) {
+  base::DictionaryValue snippet_dict = TestSnippetJsonValue();
+  ASSERT_TRUE(snippet_dict.RemovePath("imageUrl"));
+  ASSERT_TRUE(snippet_dict.RemovePath("snippet"));
+  const base::Time fetch_date = DeserializeTime(1466634774L);
+  std::unique_ptr<RemoteSuggestion> snippet =
+      RemoteSuggestion::CreateFromContentSuggestionsDictionary(
+          snippet_dict, kArticlesRemoteId, fetch_date);
+  ASSERT_THAT(snippet, NotNull());
+
+  EXPECT_EQ(GURL(), snippet->salient_image_url());
+  EXPECT_EQ("", snippet->snippet());
+}
+
+TEST(RemoteSuggestionTest, CreateFromProtoToProtoRoundtrip) {
+  SnippetProto proto = TestSnippetProto();
 
   std::unique_ptr<RemoteSuggestion> snippet =
       RemoteSuggestion::CreateFromProto(proto);
@@ -146,21 +144,8 @@
 }
 
 TEST(RemoteSuggestionTest, CreateFromProtoIgnoreMissingFetchDate) {
-  SnippetProto proto;
-  proto.add_ids("foo");
-  proto.add_ids("bar");
-  proto.set_title("a suggestion title");
-  proto.set_snippet("the snippet describing the suggestion.");
-  proto.set_salient_image_url("http://google.com/logo/");
-  proto.set_publish_date(1476095492);
-  proto.set_expiry_date(1476354691);
-  proto.set_score(0.1f);
-  proto.set_dismissed(false);
-  proto.set_remote_category_id(1);
-  auto* source = proto.mutable_source();
-  source->set_url("http://cool-suggestions.com/");
-  source->set_publisher_name("Great Suggestions Inc.");
-  source->set_amp_url("http://cdn.ampproject.org/c/foo/");
+  SnippetProto proto = TestSnippetProto();
+  proto.clear_fetch_date();
 
   std::unique_ptr<RemoteSuggestion> snippet =
       RemoteSuggestion::CreateFromProto(proto);
@@ -169,22 +154,8 @@
 }
 
 TEST(RemoteSuggestionTest, CreateFromProtoIgnoreMissingImageDominantColor) {
-  SnippetProto proto;
-  proto.add_ids("foo");
-  proto.add_ids("bar");
-  proto.set_title("a suggestion title");
-  proto.set_snippet("the snippet describing the suggestion.");
-  proto.set_salient_image_url("http://google.com/logo/");
-  proto.set_publish_date(1476095492);
-  proto.set_expiry_date(1476354691);
-  proto.set_score(0.1f);
-  proto.set_dismissed(false);
-  proto.set_remote_category_id(1);
-  auto* source = proto.mutable_source();
-  source->set_url("http://cool-suggestions.com/");
-  source->set_publisher_name("Great Suggestions Inc.");
-  source->set_amp_url("http://cdn.ampproject.org/c/foo/");
-
+  SnippetProto proto = TestSnippetProto();
+  proto.clear_image_dominant_color();
   std::unique_ptr<RemoteSuggestion> snippet =
       RemoteSuggestion::CreateFromProto(proto);
   ASSERT_THAT(snippet, NotNull());
@@ -194,34 +165,26 @@
   EXPECT_FALSE(snippet->optional_image_dominant_color().has_value());
 }
 
-std::unique_ptr<base::DictionaryValue> ContentSuggestionSnippet() {
-  const std::string kJsonStr = R"(
-    {
-      "ids" : ["http://localhost/foobar"],
-      "title" : "Foo Barred from Baz",
-      "snippet" : "...",
-      "fullPageUrl" : "http://localhost/foobar",
-      "creationTime" : "2016-06-30T11:01:37.000Z",
-      "expirationTime" : "2016-07-01T11:01:37.000Z",
-      "attribution" : "Foo News",
-      "imageUrl" : "http://localhost/foobar.jpg",
-      "ampUrl" : "http://localhost/amp",
-      "faviconUrl" : "http://localhost/favicon.ico",
-      "score": 9001
-    }
-  )";
-  auto json_value = base::JSONReader::ReadDeprecated(kJsonStr);
-  base::DictionaryValue* json_dict;
-  CHECK(json_value->GetAsDictionary(&json_dict));
-  return json_dict->CreateDeepCopy();
+TEST(RemoteSuggestionTest, CreateFromProtoIgnoreMissingSalientImageAndSnippet) {
+  SnippetProto proto = TestSnippetProto();
+  proto.clear_salient_image_url();
+  proto.clear_snippet();
+  std::unique_ptr<RemoteSuggestion> snippet =
+      RemoteSuggestion::CreateFromProto(proto);
+  ASSERT_THAT(snippet, NotNull());
+  // The snippet database relies on the fact that the first id in the protocol
+  // buffer is considered the unique id.
+  EXPECT_EQ(snippet->id(), "foo");
+  EXPECT_EQ(GURL(), snippet->salient_image_url());
+  EXPECT_EQ("", snippet->snippet());
 }
 
 TEST(RemoteSuggestionTest, NotifcationInfoAllSpecified) {
-  auto json = ContentSuggestionSnippet();
-  json->SetBoolean("notificationInfo.shouldNotify", true);
-  json->SetString("notificationInfo.deadline", "2016-06-30T13:01:37.000Z");
+  auto json = TestSnippetJsonValue();
+  json.SetBoolean("notificationInfo.shouldNotify", true);
+  json.SetString("notificationInfo.deadline", "2016-06-30T13:01:37.000Z");
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   EXPECT_TRUE(snippet->should_notify());
   EXPECT_EQ(7200.0f,
             (snippet->notification_deadline() - snippet->publish_date())
@@ -229,92 +192,96 @@
 }
 
 TEST(RemoteSuggestionTest, NotificationInfoDeadlineInvalid) {
-  auto json = ContentSuggestionSnippet();
-  json->SetBoolean("notificationInfo.shouldNotify", true);
-  json->SetInteger("notificationInfo.notificationDeadline", 0);
+  auto json = TestSnippetJsonValue();
+  json.SetBoolean("notificationInfo.shouldNotify", true);
+  json.SetString("notificationInfo.deadline", "abcd");
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   EXPECT_TRUE(snippet->should_notify());
   EXPECT_EQ(base::Time::Max(), snippet->notification_deadline());
 }
 
 TEST(RemoteSuggestionTest, NotificationInfoDeadlineAbsent) {
-  auto json = ContentSuggestionSnippet();
-  json->SetBoolean("notificationInfo.shouldNotify", true);
+  auto json = TestSnippetJsonValue();
+  json.SetBoolean("notificationInfo.shouldNotify", true);
+  json.RemovePath("notificationInfo.deadline");
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   EXPECT_TRUE(snippet->should_notify());
   EXPECT_EQ(base::Time::Max(), snippet->notification_deadline());
 }
 
 TEST(RemoteSuggestionTest, NotificationInfoShouldNotifyInvalid) {
-  auto json = ContentSuggestionSnippet();
-  json->SetString("notificationInfo.shouldNotify", "non-bool");
+  auto json = TestSnippetJsonValue();
+  json.SetString("notificationInfo.shouldNotify", "non-bool");
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   EXPECT_FALSE(snippet->should_notify());
 }
 
 TEST(RemoteSuggestionTest, NotificationInfoAbsent) {
-  auto json = ContentSuggestionSnippet();
+  auto json = TestSnippetJsonValue();
+  json.SetBoolean("notificationInfo.shouldNotify", false);
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   EXPECT_FALSE(snippet->should_notify());
 }
 
-TEST(RemoteSuggestionTest, ToContentSuggestion) {
-  auto json = ContentSuggestionSnippet();
+TEST(RemoteSuggestionTest, ToContentSuggestionWithoutNotificationInfo) {
+  auto json = TestSnippetJsonValue();
+  json.RemovePath("notificationInfo");
   const base::Time fetch_date = DeserializeTime(1466634774L);
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, fetch_date);
+      json, 0, fetch_date);
   ASSERT_THAT(snippet, NotNull());
   ContentSuggestion sugg = snippet->ToContentSuggestion(
       Category::FromKnownCategory(KnownCategories::ARTICLES));
 
   EXPECT_THAT(sugg.id().category(),
               Eq(Category::FromKnownCategory(KnownCategories::ARTICLES)));
-  EXPECT_THAT(sugg.id().id_within_category(), Eq("http://localhost/foobar"));
-  EXPECT_THAT(sugg.url(), Eq(GURL("http://localhost/amp")));
-  EXPECT_THAT(sugg.title(), Eq(base::UTF8ToUTF16("Foo Barred from Baz")));
-  EXPECT_THAT(sugg.snippet_text(), Eq(base::UTF8ToUTF16("...")));
+  EXPECT_THAT(sugg.id().id_within_category(), Eq("foo"));
+  EXPECT_THAT(sugg.url(), Eq(GURL("http://cdn.ampproject.org/c/foo/")));
+  EXPECT_THAT(sugg.title(), Eq(base::UTF8ToUTF16("a suggestion title")));
+  EXPECT_THAT(sugg.snippet_text(),
+              Eq(base::UTF8ToUTF16("the snippet describing the suggestion.")));
   EXPECT_THAT(sugg.publish_date().ToJavaTime(), Eq(1467284497000));
-  EXPECT_THAT(sugg.publisher_name(), Eq(base::UTF8ToUTF16("Foo News")));
-  EXPECT_THAT(sugg.score(), Eq(9001));
-  EXPECT_THAT(sugg.salient_image_url(),
-              Eq(GURL("http://localhost/foobar.jpg")));
+  EXPECT_THAT(sugg.publisher_name(),
+              Eq(base::UTF8ToUTF16("Great Suggestions Inc.")));
+  EXPECT_THAT(sugg.score(), Eq(1.5));
+  EXPECT_THAT(sugg.salient_image_url(), Eq(GURL("http://google.com/logo/")));
   EXPECT_THAT(sugg.notification_extra(), IsNull());
   EXPECT_THAT(sugg.fetch_date(), Eq(fetch_date));
 }
 
 TEST(RemoteSuggestionTest, ToContentSuggestionWithNotificationInfo) {
-  auto json = ContentSuggestionSnippet();
-  json->SetBoolean("notificationInfo.shouldNotify", true);
-  json->SetString("notificationInfo.deadline", "2016-06-30T13:01:37.000Z");
+  auto json = TestSnippetJsonValue();
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   ASSERT_THAT(snippet, NotNull());
   ContentSuggestion sugg = snippet->ToContentSuggestion(
       Category::FromKnownCategory(KnownCategories::ARTICLES));
 
   EXPECT_THAT(sugg.id().category(),
               Eq(Category::FromKnownCategory(KnownCategories::ARTICLES)));
-  EXPECT_THAT(sugg.id().id_within_category(), Eq("http://localhost/foobar"));
-  EXPECT_THAT(sugg.url(), Eq(GURL("http://localhost/amp")));
-  EXPECT_THAT(sugg.title(), Eq(base::UTF8ToUTF16("Foo Barred from Baz")));
-  EXPECT_THAT(sugg.snippet_text(), Eq(base::UTF8ToUTF16("...")));
+  EXPECT_THAT(sugg.id().id_within_category(), Eq("foo"));
+  EXPECT_THAT(sugg.url(), Eq(GURL("http://cdn.ampproject.org/c/foo/")));
+  EXPECT_THAT(sugg.title(), Eq(base::UTF8ToUTF16("a suggestion title")));
+  EXPECT_THAT(sugg.snippet_text(),
+              Eq(base::UTF8ToUTF16("the snippet describing the suggestion.")));
   EXPECT_THAT(sugg.publish_date().ToJavaTime(), Eq(1467284497000));
-  EXPECT_THAT(sugg.publisher_name(), Eq(base::UTF8ToUTF16("Foo News")));
-  EXPECT_THAT(sugg.score(), Eq(9001));
+  EXPECT_THAT(sugg.publisher_name(),
+              Eq(base::UTF8ToUTF16("Great Suggestions Inc.")));
+  EXPECT_THAT(sugg.score(), Eq(1.5));
   ASSERT_THAT(sugg.notification_extra(), NotNull());
   EXPECT_THAT(sugg.notification_extra()->deadline.ToJavaTime(),
               Eq(1467291697000));
 }
 
 TEST(RemoteSuggestionTest, ToContentSuggestionWithContentTypeVideo) {
-  auto json = ContentSuggestionSnippet();
-  json->SetString("contentType", "VIDEO");
+  auto json = TestSnippetJsonValue();
+  json.SetString("contentType", "VIDEO");
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   ASSERT_THAT(snippet, NotNull());
   ContentSuggestion content_suggestion = snippet->ToContentSuggestion(
       Category::FromKnownCategory(KnownCategories::ARTICLES));
@@ -323,10 +290,10 @@
 }
 
 TEST(RemoteSuggestionTest, ToContentSuggestionWithContentTypeUnknown) {
-  auto json = ContentSuggestionSnippet();
-  json->SetString("contentType", "UNKNOWN");
+  auto json = TestSnippetJsonValue();
+  json.SetString("contentType", "UNKNOWN");
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   ASSERT_THAT(snippet, NotNull());
   ContentSuggestion content_suggestion = snippet->ToContentSuggestion(
       Category::FromKnownCategory(KnownCategories::ARTICLES));
@@ -335,9 +302,9 @@
 }
 
 TEST(RemoteSuggestionTest, ToContentSuggestionWithMissingContentType) {
-  auto json = ContentSuggestionSnippet();
+  auto json = TestSnippetJsonValue();
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   ASSERT_THAT(snippet, NotNull());
   ContentSuggestion content_suggestion = snippet->ToContentSuggestion(
       Category::FromKnownCategory(KnownCategories::ARTICLES));
@@ -346,12 +313,12 @@
 }
 
 TEST(RemoteSuggestionTest, ToContentSuggestionWithLargeImageDominantColor) {
-  auto json = ContentSuggestionSnippet();
+  auto json = TestSnippetJsonValue();
   // JSON does not support unsigned types. As a result the value is parsed as
   // int if it fits and as double otherwise.
-  json->SetDouble("imageDominantColor", 4289379276.);
+  json.SetDouble("imageDominantColor", 4289379276.);
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   ASSERT_THAT(snippet, NotNull());
   ContentSuggestion content_suggestion = snippet->ToContentSuggestion(
       Category::FromKnownCategory(KnownCategories::ARTICLES));
@@ -362,12 +329,12 @@
 }
 
 TEST(RemoteSuggestionTest, ToContentSuggestionWithSmallImageDominantColor) {
-  auto json = ContentSuggestionSnippet();
+  auto json = TestSnippetJsonValue();
   // JSON does not support unsigned types. As a result the value is parsed as
   // int if it fits and as double otherwise.
-  json->SetInteger("imageDominantColor", 16777216 /*=0x1000000*/);
+  json.SetInteger("imageDominantColor", 16777216 /*=0x1000000*/);
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   ASSERT_THAT(snippet, NotNull());
   ContentSuggestion content_suggestion = snippet->ToContentSuggestion(
       Category::FromKnownCategory(KnownCategories::ARTICLES));
@@ -378,9 +345,10 @@
 }
 
 TEST(RemoteSuggestionTest, ToContentSuggestionWithoutImageDominantColor) {
-  auto json = ContentSuggestionSnippet();
+  auto json = TestSnippetJsonValue();
+  json.RemovePath("imageDominantColor");
   auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
-      *json, 0, base::Time());
+      json, 0, base::Time());
   ASSERT_THAT(snippet, NotNull());
   ContentSuggestion content_suggestion = snippet->ToContentSuggestion(
       Category::FromKnownCategory(KnownCategories::ARTICLES));
diff --git a/components/policy/core/common/policy_statistics_collector.cc b/components/policy/core/common/policy_statistics_collector.cc
index 0176205..537a0f3 100644
--- a/components/policy/core/common/policy_statistics_collector.cc
+++ b/components/policy/core/common/policy_statistics_collector.cc
@@ -64,8 +64,7 @@
 }
 
 void PolicyStatisticsCollector::RecordPolicyGroupWithConflicts(int id) {
-  base::UmaHistogramSparse("Enterprise.Policies.AtomicGroupSourceConflicts",
-                           id);
+  base::UmaHistogramSparse("Enterprise.Policies.SourceConflicts", id);
 }
 
 void PolicyStatisticsCollector::RecordPolicyIgnoredByAtomicGroup(int id) {
diff --git a/components/policy/resources/policy_templates.gni b/components/policy/resources/policy_templates.gni
index 7699bf3..05132943 100644
--- a/components/policy/resources/policy_templates.gni
+++ b/components/policy/resources/policy_templates.gni
@@ -14,53 +14,18 @@
 # Languages we're going to process. Should match the XX-YY of the translated
 # policy_templates_XX-YY.json files, see policy_templates.grd.
 policy_templates_languages = [
-  "am",
-  "ar-EG",
-  "bg-BG",
-  "ms-BN",
-  "ca-ES",
-  "cs-CZ",
-  "da-DK",
   "de-DE",
-  "el-GR",
-  "en-GB",
   "en-US",
   "es-ES",
   "es-419",
-  "et-EE",
-  "fa-IR",
-  "fi-FI",
-  "fil",
   "fr-FR",
-  "gu-IN",
-  "he-IL",
-  "hi-IN",
-  "hr-HR",
-  "hu-HU",
   "id-ID",
   "it-IT",
   "ja-JP",
-  "kn-IN",
   "ko-KR",
-  "lt-LT",
-  "lv-LV",
-  "ml",
-  "mr-IN",
-  "ms-MY",
   "nl-NL",
-  "nb-NO",
-  "pl-PL",
   "pt-BR",
-  "pt-PT",
-  "ro-RO",
   "ru-RU",
-  "sk-SK",
-  "sl-SI",
-  "Cy-sr-SP",
-  "sv-SE",
-  "sw-KE",
-  "ta-IN",
-  "te-IN",
   "th-TH",
   "tr-TR",
   "uk-UA",
@@ -73,57 +38,21 @@
 #   - '_' instead of '-'
 #   - 'en' instead of 'en-US'
 mac_policy_templates_languages = [
-  "am",
-  "ar_EG",
-  "bg_BG",
-  "ms_BN",
-  "ca_ES",
-  "cs_CZ",
-  "da_DK",
   "de_DE",
-  "el_GR",
-  "en_GB",
   "en",
   "es_ES",
   "es_419",
-  "et_EE",
-  "fa_IR",
-  "fi_FI",
-  "fil",
   "fr_FR",
-  "gu_IN",
-  "he_IL",
-  "hi_IN",
-  "hr_HR",
-  "hu_HU",
   "id_ID",
   "it_IT",
   "ja_JP",
-  "kn_IN",
   "ko_KR",
-  "lt_LT",
-  "lv_LV",
-  "ml",
-  "mr_IN",
-  "ms_MY",
   "nl_NL",
-  "nb_NO",
-  "pl_PL",
   "pt_BR",
-  "pt_PT",
-  "ro_RO",
   "ru_RU",
-  "sk_SK",
-  "sl_SI",
-  "Cy_sr_SP",
-  "sv_SE",
-  "sw_KE",
-  "ta_IN",
-  "te_IN",
   "th_TH",
   "tr_TR",
   "uk_UA",
-  "vi_VN",
   "zh_CN",
   "zh_TW",
 ]
diff --git a/components/policy/resources/policy_templates.grd b/components/policy/resources/policy_templates.grd
index f934523..afdacf2 100644
--- a/components/policy/resources/policy_templates.grd
+++ b/components/policy/resources/policy_templates.grd
@@ -8,53 +8,18 @@
 <grit base_dir="." latest_public_release="0" current_release="1"
       output_all_resource_defines="false" source_lang_id="en" enc_check="möl">
   <outputs>
-    <output filename="app/policy/translations/policy_templates_am.json" type="policy_templates" lang="am" />
-    <output filename="app/policy/translations/policy_templates_ar-EG.json" type="policy_templates" lang="ar" />
-    <output filename="app/policy/translations/policy_templates_bg-BG.json" type="policy_templates" lang="bg" />
-    <output filename="app/policy/translations/policy_templates_ms-BN.json" type="policy_templates" lang="bn" />
-    <output filename="app/policy/translations/policy_templates_ca-ES.json" type="policy_templates" lang="ca" />
-    <output filename="app/policy/translations/policy_templates_cs-CZ.json" type="policy_templates" lang="cs" />
-    <output filename="app/policy/translations/policy_templates_da-DK.json" type="policy_templates" lang="da" />
     <output filename="app/policy/translations/policy_templates_de-DE.json" type="policy_templates" lang="de" />
-    <output filename="app/policy/translations/policy_templates_el-GR.json" type="policy_templates" lang="el" />
-    <output filename="app/policy/translations/policy_templates_en-GB.json" type="policy_templates" lang="en-GB" />
     <output filename="app/policy/translations/policy_templates_en-US.json" type="policy_templates" lang="en" />
     <output filename="app/policy/translations/policy_templates_es-ES.json" type="policy_templates" lang="es" />
     <output filename="app/policy/translations/policy_templates_es-419.json" type="policy_templates" lang="es-419" />
-    <output filename="app/policy/translations/policy_templates_et-EE.json" type="policy_templates" lang="et" />
-    <output filename="app/policy/translations/policy_templates_fa-IR.json" type="policy_templates" lang="fa" />
-    <output filename="app/policy/translations/policy_templates_fi-FI.json" type="policy_templates" lang="fi" />
-    <output filename="app/policy/translations/policy_templates_fil.json" type="policy_templates" lang="fil" />
     <output filename="app/policy/translations/policy_templates_fr-FR.json" type="policy_templates" lang="fr" />
-    <output filename="app/policy/translations/policy_templates_gu-IN.json" type="policy_templates" lang="gu" />
-    <output filename="app/policy/translations/policy_templates_he-IL.json" type="policy_templates" lang="he" />
-    <output filename="app/policy/translations/policy_templates_hi-IN.json" type="policy_templates" lang="hi" />
-    <output filename="app/policy/translations/policy_templates_hr-HR.json" type="policy_templates" lang="hr" />
-    <output filename="app/policy/translations/policy_templates_hu-HU.json" type="policy_templates" lang="hu" />
     <output filename="app/policy/translations/policy_templates_id-ID.json" type="policy_templates" lang="id" />
     <output filename="app/policy/translations/policy_templates_it-IT.json" type="policy_templates" lang="it" />
     <output filename="app/policy/translations/policy_templates_ja-JP.json" type="policy_templates" lang="ja" />
-    <output filename="app/policy/translations/policy_templates_kn-IN.json" type="policy_templates" lang="kn" />
     <output filename="app/policy/translations/policy_templates_ko-KR.json" type="policy_templates" lang="ko" />
-    <output filename="app/policy/translations/policy_templates_lt-LT.json" type="policy_templates" lang="lt" />
-    <output filename="app/policy/translations/policy_templates_lv-LV.json" type="policy_templates" lang="lv" />
-    <output filename="app/policy/translations/policy_templates_ml.json" type="policy_templates" lang="ml" />
-    <output filename="app/policy/translations/policy_templates_mr-IN.json" type="policy_templates" lang="mr" />
-    <output filename="app/policy/translations/policy_templates_ms-MY.json" type="policy_templates" lang="ms" />
     <output filename="app/policy/translations/policy_templates_nl-NL.json" type="policy_templates" lang="nl" />
-    <output filename="app/policy/translations/policy_templates_nb-NO.json" type="policy_templates" lang="no" />
-    <output filename="app/policy/translations/policy_templates_pl-PL.json" type="policy_templates" lang="pl" />
     <output filename="app/policy/translations/policy_templates_pt-BR.json" type="policy_templates" lang="pt-BR" />
-    <output filename="app/policy/translations/policy_templates_pt-PT.json" type="policy_templates" lang="pt-PT" />
-    <output filename="app/policy/translations/policy_templates_ro-RO.json" type="policy_templates" lang="ro" />
     <output filename="app/policy/translations/policy_templates_ru-RU.json" type="policy_templates" lang="ru" />
-    <output filename="app/policy/translations/policy_templates_sk-SK.json" type="policy_templates" lang="sk" />
-    <output filename="app/policy/translations/policy_templates_sl-SI.json" type="policy_templates" lang="sl" />
-    <output filename="app/policy/translations/policy_templates_Cy-sr-SP.json" type="policy_templates" lang="sr" />
-    <output filename="app/policy/translations/policy_templates_sv-SE.json" type="policy_templates" lang="sv" />
-    <output filename="app/policy/translations/policy_templates_sw-KE.json" type="policy_templates" lang="sw" />
-    <output filename="app/policy/translations/policy_templates_ta-IN.json" type="policy_templates" lang="ta" />
-    <output filename="app/policy/translations/policy_templates_te-IN.json" type="policy_templates" lang="te" />
     <output filename="app/policy/translations/policy_templates_th-TH.json" type="policy_templates" lang="th" />
     <output filename="app/policy/translations/policy_templates_tr-TR.json" type="policy_templates" lang="tr" />
     <output filename="app/policy/translations/policy_templates_uk-UA.json" type="policy_templates" lang="uk" />
@@ -63,53 +28,17 @@
     <output filename="app/policy/translations/policy_templates_zh-TW.json" type="policy_templates" lang="zh-TW" />
   </outputs>
   <translations>
-    <file path="policy_templates_am.xtb" lang="am" />
-    <file path="policy_templates_ar.xtb" lang="ar" />
-    <file path="policy_templates_bg.xtb" lang="bg" />
-    <file path="policy_templates_bn.xtb" lang="bn" />
-    <file path="policy_templates_ca.xtb" lang="ca" />
-    <file path="policy_templates_cs.xtb" lang="cs" />
-    <file path="policy_templates_da.xtb" lang="da" />
     <file path="policy_templates_de.xtb" lang="de" />
-    <file path="policy_templates_el.xtb" lang="el" />
-    <file path="policy_templates_en-GB.xtb" lang="en-GB" />
     <file path="policy_templates_es.xtb" lang="es" />
     <file path="policy_templates_es-419.xtb" lang="es-419" />
-    <file path="policy_templates_et.xtb" lang="et" />
-    <file path="policy_templates_fa.xtb" lang="fa" />
-    <file path="policy_templates_fi.xtb" lang="fi" />
-    <file path="policy_templates_fil.xtb" lang="fil" />
     <file path="policy_templates_fr.xtb" lang="fr" />
-    <file path="policy_templates_gu.xtb" lang="gu" />
-    <file path="policy_templates_hi.xtb" lang="hi" />
-    <file path="policy_templates_hr.xtb" lang="hr" />
-    <file path="policy_templates_hu.xtb" lang="hu" />
     <file path="policy_templates_id.xtb" lang="id" />
     <file path="policy_templates_it.xtb" lang="it" />
-    <!-- The translation console uses 'iw' for Hebrew, but we use 'he'. -->
-    <file path="policy_templates_iw.xtb" lang="he" />
     <file path="policy_templates_ja.xtb" lang="ja" />
-    <file path="policy_templates_kn.xtb" lang="kn" />
     <file path="policy_templates_ko.xtb" lang="ko" />
-    <file path="policy_templates_lt.xtb" lang="lt" />
-    <file path="policy_templates_lv.xtb" lang="lv" />
-    <file path="policy_templates_ml.xtb" lang="ml" />
-    <file path="policy_templates_mr.xtb" lang="mr" />
-    <file path="policy_templates_ms.xtb" lang="ms" />
     <file path="policy_templates_nl.xtb" lang="nl" />
-    <file path="policy_templates_no.xtb" lang="no" />
-    <file path="policy_templates_pl.xtb" lang="pl" />
     <file path="policy_templates_pt-BR.xtb" lang="pt-BR" />
-    <file path="policy_templates_pt-PT.xtb" lang="pt-PT" />
-    <file path="policy_templates_ro.xtb" lang="ro" />
     <file path="policy_templates_ru.xtb" lang="ru" />
-    <file path="policy_templates_sk.xtb" lang="sk" />
-    <file path="policy_templates_sl.xtb" lang="sl" />
-    <file path="policy_templates_sr.xtb" lang="sr" />
-    <file path="policy_templates_sv.xtb" lang="sv" />
-    <file path="policy_templates_sw.xtb" lang="sw" />
-    <file path="policy_templates_ta.xtb" lang="ta" />
-    <file path="policy_templates_te.xtb" lang="te" />
     <file path="policy_templates_th.xtb" lang="th" />
     <file path="policy_templates_tr.xtb" lang="tr" />
     <file path="policy_templates_uk.xtb" lang="uk" />
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 9ad77e6..6d542601 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -9242,7 +9242,7 @@
 
           If this policy is left unset, Accessibility options will not appear in the system tray menu, but the user can cause the Accessibility options to appear via the Settings page.
 
-          When accessiblity features are enabled (by other means, e.g by a key combination), Accessibility options will always appear in system tray menu.'''
+          When accessiblity features are enabled by other means (e.g by a key combination), Accessibility options will always appear in system tray menu.'''
     },
     {
       'name': 'LargeCursorEnabled',
diff --git a/components/printing/renderer/BUILD.gn b/components/printing/renderer/BUILD.gn
index a3e925a1..9f7dda5 100644
--- a/components/printing/renderer/BUILD.gn
+++ b/components/printing/renderer/BUILD.gn
@@ -6,17 +6,9 @@
   sources = [
     "print_render_frame_helper.cc",
     "print_render_frame_helper.h",
-    "print_render_frame_helper_linux.cc",
     "print_render_frame_helper_mac.mm",
   ]
 
-  if (is_android) {
-    # Add back the Linux file which Android shares.
-    set_sources_assignment_filter([])
-    sources += [ "print_render_frame_helper_linux.cc" ]
-    set_sources_assignment_filter(sources_assignment_filter)
-  }
-
   deps = [
     "//base",
     "//components/printing/common",
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index 49f2cb6c..ef580254 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -1778,7 +1778,6 @@
   }
 }
 
-#if defined(OS_MACOSX) || defined(OS_WIN)
 bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
                                               int page_count,
                                               bool is_pdf) {
@@ -1794,9 +1793,18 @@
   CHECK(metafile.Init());
 
   PrintHostMsg_DidPrintDocument_Params page_params;
+  gfx::Size* page_size_in_dpi;
+  gfx::Rect* content_area_in_dpi;
+#if defined(OS_MACOSX) || defined(OS_WIN)
+  page_size_in_dpi = &page_params.page_size;
+  content_area_in_dpi = &page_params.content_area;
+#else
+  page_size_in_dpi = nullptr;
+  content_area_in_dpi = nullptr;
+#endif
   PrintPageInternal(print_params, printed_pages[0], page_count,
-                    print_params.scale_factor, frame, &metafile,
-                    &page_params.page_size, &page_params.content_area);
+                    GetScaleFactor(print_params.scale_factor, is_pdf), frame,
+                    &metafile, page_size_in_dpi, content_area_in_dpi);
   for (size_t i = 1; i < printed_pages.size(); ++i) {
     PrintPageInternal(print_params, printed_pages[i], page_count,
                       GetScaleFactor(print_params.scale_factor, is_pdf), frame,
@@ -1819,7 +1827,6 @@
   Send(new PrintHostMsg_DidPrintDocument(routing_id(), page_params));
   return true;
 }
-#endif  // defined(OS_MACOSX) || defined(OS_WIN)
 
 void PrintRenderFrameHelper::FinishFramePrinting() {
   prep_frame_view_.reset();
diff --git a/components/printing/renderer/print_render_frame_helper_linux.cc b/components/printing/renderer/print_render_frame_helper_linux.cc
deleted file mode 100644
index e92009c..0000000
--- a/components/printing/renderer/print_render_frame_helper_linux.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2012 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 "components/printing/renderer/print_render_frame_helper.h"
-
-#include <stddef.h>
-
-#include "base/logging.h"
-#include "base/process/process_handle.h"
-#include "build/build_config.h"
-#include "components/printing/common/print_messages.h"
-#include "printing/buildflags/buildflags.h"
-#include "printing/metafile_skia.h"
-
-namespace printing {
-
-bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
-                                              int page_count,
-                                              bool is_pdf) {
-  const PrintMsg_PrintPages_Params& params = *print_pages_params_;
-  const PrintMsg_Print_Params& print_params = params.params;
-
-  std::vector<int> printed_pages = GetPrintedPages(params, page_count);
-  if (printed_pages.empty())
-    return false;
-
-  MetafileSkia metafile(print_params.printed_doc_type,
-                        print_params.document_cookie);
-  CHECK(metafile.Init());
-
-  for (int page_number : printed_pages) {
-    PrintPageInternal(print_params, page_number, page_count,
-                      GetScaleFactor(print_params.scale_factor, is_pdf), frame,
-                      &metafile, nullptr, nullptr);
-  }
-
-  // blink::printEnd() for PDF should be called before metafile is closed.
-  FinishFramePrinting();
-
-  metafile.FinishDocument();
-
-  PrintHostMsg_DidPrintDocument_Params page_params;
-  if (!CopyMetafileDataToReadOnlySharedMem(metafile, &page_params.content)) {
-    return false;
-  }
-
-  page_params.document_cookie = print_params.document_cookie;
-  Send(new PrintHostMsg_DidPrintDocument(routing_id(), page_params));
-  return true;
-}
-
-}  // namespace printing
diff --git a/components/ui_devtools/css_agent.cc b/components/ui_devtools/css_agent.cc
index 37e9a10..d6fce623 100644
--- a/components/ui_devtools/css_agent.cc
+++ b/components/ui_devtools/css_agent.cc
@@ -42,15 +42,6 @@
 }
 
 std::unique_ptr<CSS::CSSProperty> BuildCSSProperty(const std::string& name,
-                                                   int value) {
-  return CSS::CSSProperty::create()
-      .setRange(BuildDefaultSourceRange())
-      .setName(name)
-      .setValue(base::NumberToString(value))
-      .build();
-}
-
-std::unique_ptr<CSS::CSSProperty> BuildCSSProperty(const std::string& name,
                                                    const std::string& value) {
   return CSS::CSSProperty::create()
       .setRange(BuildDefaultSourceRange())
@@ -59,16 +50,6 @@
       .build();
 }
 
-std::unique_ptr<Array<CSS::CSSProperty>> BuildCSSPropertyArray(
-    const gfx::Rect& bounds) {
-  auto cssProperties = std::make_unique<Array<CSS::CSSProperty>>();
-  cssProperties->emplace_back(BuildCSSProperty(kHeight, bounds.height()));
-  cssProperties->emplace_back(BuildCSSProperty(kWidth, bounds.width()));
-  cssProperties->emplace_back(BuildCSSProperty(kX, bounds.x()));
-  cssProperties->emplace_back(BuildCSSProperty(kY, bounds.y()));
-  return cssProperties;
-}
-
 std::unique_ptr<Array<CSS::CSSProperty>> BuildCSSProperties(
     const std::vector<UIElement::UIProperty>& properties_vector) {
   auto css_properties = std::make_unique<Array<protocol::CSS::CSSProperty>>();
@@ -79,32 +60,6 @@
   return css_properties;
 }
 
-std::unique_ptr<CSS::CSSStyle> BuildCSSStyle(UIElement* ui_element) {
-  gfx::Rect bounds;
-  ui_element->GetBounds(&bounds);
-  std::unique_ptr<Array<CSS::CSSProperty>> css_properties(
-      BuildCSSPropertyArray(bounds));
-
-  if (ui_element->type() != VIEW) {
-    bool visible;
-    ui_element->GetVisible(&visible);
-    css_properties->emplace_back(BuildCSSProperty(kVisibility, visible));
-  }
-
-  const std::vector<std::pair<std::string, std::string>> properties(
-      ui_element->GetCustomProperties());
-  for (const auto& it : properties)
-    css_properties->emplace_back(BuildCSSProperty(it.first, it.second));
-
-  return CSS::CSSStyle::create()
-      .setRange(BuildDefaultSourceRange())
-      .setStyleSheetId(base::NumberToString(ui_element->node_id()))
-      .setCssProperties(std::move(css_properties))
-      .setShorthandEntries(
-          std::make_unique<Array<protocol::CSS::ShorthandEntry>>())
-      .build();
-}
-
 std::unique_ptr<CSS::CSSStyle> BuildCSSStyle(
     std::string stylesheet_uid,
     const std::vector<UIElement::UIProperty>& properties) {
@@ -288,15 +243,6 @@
   InvalidateStyleSheet(ui_element);
 }
 
-std::unique_ptr<CSS::CSSStyle> CSSAgent::GetStylesForUIElement(
-    UIElement* ui_element) {
-  gfx::Rect bounds;
-  bool visible = false;
-  return GetPropertiesForUIElement(ui_element, &bounds, &visible)
-             ? BuildCSSStyle(ui_element)
-             : nullptr;
-}
-
 void CSSAgent::InvalidateStyleSheet(UIElement* ui_element) {
   // The stylesheetId for each node is equivalent to a string of its
   // node_id + "_" + index of CSS::RuleMatch in vector.
diff --git a/components/ui_devtools/css_agent_unittest.cc b/components/ui_devtools/css_agent_unittest.cc
index cae67e7..55061d6c 100644
--- a/components/ui_devtools/css_agent_unittest.cc
+++ b/components/ui_devtools/css_agent_unittest.cc
@@ -19,11 +19,6 @@
       : UIElement(UIElementType::ROOT, ui_element_delegate, nullptr) {}
 
   ~FakeUIElement() override {}
-  // Return a vector of pairs of properties' names and values.
-  std::vector<std::pair<std::string, std::string>> GetCustomProperties()
-      const override {
-    return {};
-  }
   void GetBounds(gfx::Rect* bounds) const override { *bounds = bounds_; }
   void SetBounds(const gfx::Rect& bounds) override { bounds_ = bounds; }
   void GetVisible(bool* visible) const override { *visible = visible_; }
diff --git a/components/ui_devtools/root_element.cc b/components/ui_devtools/root_element.cc
index 6ca9be95..59582f3 100644
--- a/components/ui_devtools/root_element.cc
+++ b/components/ui_devtools/root_element.cc
@@ -14,12 +14,6 @@
 
 RootElement::~RootElement() {}
 
-std::vector<std::pair<std::string, std::string>>
-RootElement::GetCustomProperties() const {
-  NOTREACHED();
-  return {};
-}
-
 void RootElement::GetBounds(gfx::Rect* bounds) const {
   NOTREACHED();
 }
diff --git a/components/ui_devtools/root_element.h b/components/ui_devtools/root_element.h
index c1ded3a..4b1a95e4 100644
--- a/components/ui_devtools/root_element.h
+++ b/components/ui_devtools/root_element.h
@@ -16,8 +16,6 @@
   ~RootElement() override;
 
   // UIElement:
-  std::vector<std::pair<std::string, std::string>> GetCustomProperties()
-      const override;
   void GetBounds(gfx::Rect* bounds) const override;
   void SetBounds(const gfx::Rect& bounds) override;
   void GetVisible(bool* visible) const override;
diff --git a/components/ui_devtools/ui_element.h b/components/ui_devtools/ui_element.h
index 214c967..0d26d3b 100644
--- a/components/ui_devtools/ui_element.h
+++ b/components/ui_devtools/ui_element.h
@@ -87,10 +87,6 @@
   template <class T>
   int FindUIElementIdForBackendElement(T* element) const;
 
-  // Returns properties' names and values.
-  virtual std::vector<std::pair<std::string, std::string>> GetCustomProperties()
-      const = 0;
-
   // Returns properties grouped by the class they are from.
   virtual std::vector<ClassProperties> GetCustomPropertiesForMatchedStyle()
       const;
diff --git a/components/ui_devtools/views/element_utility.cc b/components/ui_devtools/views/element_utility.cc
index f315b4cf..eb1eef6d 100644
--- a/components/ui_devtools/views/element_utility.cc
+++ b/components/ui_devtools/views/element_utility.cc
@@ -9,47 +9,6 @@
 
 namespace ui_devtools {
 
-// TODO(khamasaki): Remove AppendLayerProperties.
-void AppendLayerProperties(
-    const ui::Layer* layer,
-    std::vector<std::pair<std::string, std::string>>* ret) {
-  ret->emplace_back("layer-type", LayerTypeToString(layer->type()));
-  ret->emplace_back("has-layer-mask",
-                    layer->layer_mask_layer() ? "true" : "false");
-  ret->emplace_back("layer-opacity", base::NumberToString((layer->opacity())));
-  ret->emplace_back("layer-combined-opacity",
-                    base::NumberToString(layer->GetCombinedOpacity()));
-  ret->emplace_back("background-blur",
-                    base::NumberToString(layer->background_blur()));
-  ret->emplace_back("layer-blur", base::NumberToString(layer->layer_blur()));
-  ret->emplace_back("layer-saturation",
-                    base::NumberToString(layer->layer_saturation()));
-  ret->emplace_back("layer-brightness",
-                    base::NumberToString(layer->layer_brightness()));
-  ret->emplace_back("layer-grayscale",
-                    base::NumberToString(layer->layer_grayscale()));
-  const ui::Layer::ShapeRects* alpha_shape_bounds = layer->alpha_shape();
-  if (alpha_shape_bounds && alpha_shape_bounds->size()) {
-    gfx::Rect bounding_box;
-    for (auto& shape_bound : *alpha_shape_bounds)
-      bounding_box.Union(shape_bound);
-    ret->emplace_back("alpha-shape-bounding-box", bounding_box.ToString());
-  }
-  const cc::Layer* cc_layer = layer->cc_layer_for_testing();
-  if (cc_layer) {
-    // Property trees must be updated in order to get valid render surface
-    // reasons.
-    if (!cc_layer->layer_tree_host() ||
-        cc_layer->layer_tree_host()->property_trees()->needs_rebuild)
-      return;
-    cc::RenderSurfaceReason render_surface = cc_layer->GetRenderSurfaceReason();
-    if (render_surface != cc::RenderSurfaceReason::kNone) {
-      ret->emplace_back("render-surface-reason",
-                        cc::RenderSurfaceReasonToString(render_surface));
-    }
-  }
-}
-
 void AppendLayerPropertiesMatchedStyle(
     const ui::Layer* layer,
     std::vector<UIElement::UIProperty>* ret) {
diff --git a/components/ui_devtools/views/element_utility.h b/components/ui_devtools/views/element_utility.h
index b80a628..7aa19a1f 100644
--- a/components/ui_devtools/views/element_utility.h
+++ b/components/ui_devtools/views/element_utility.h
@@ -21,10 +21,6 @@
 // Appends Layer properties to ret (ex: layer-type, layer-mask, etc).
 // This is used to display information about the layer on devtools.
 // Note that ret may not be empty when it's passed in.
-void AppendLayerProperties(
-    const ui::Layer* layer,
-    std::vector<std::pair<std::string, std::string>>* ret);
-
 void AppendLayerPropertiesMatchedStyle(const ui::Layer* layer,
                                        std::vector<UIElement::UIProperty>* ret);
 
diff --git a/components/ui_devtools/views/view_element.cc b/components/ui_devtools/views/view_element.cc
index fbad7fc..9756c6f 100644
--- a/components/ui_devtools/views/view_element.cc
+++ b/components/ui_devtools/views/view_element.cc
@@ -59,30 +59,6 @@
   delegate()->OnUIElementBoundsChanged(this);
 }
 
-std::vector<std::pair<std::string, std::string>>
-ViewElement::GetCustomProperties() const {
-  std::vector<std::pair<std::string, std::string>> ret;
-
-  views::metadata::ClassMetaData* metadata = view_->GetClassMetaData();
-  for (views::metadata::MemberMetaDataBase* member : *metadata) {
-    ret.emplace_back(member->member_name(),
-                     base::UTF16ToUTF8(member->GetValueAsString(view_)));
-  }
-
-  ret.emplace_back("is-drawn", view_->IsDrawn() ? "true" : "false");
-  ui::Layer* layer = view_->layer();
-  if (layer) {
-    ret.emplace_back("layer", layer->name());
-    AppendLayerProperties(layer, &ret);
-  }
-
-  base::string16 description = view_->GetTooltipText(gfx::Point());
-  if (!description.empty())
-    ret.emplace_back("tooltip", base::UTF16ToUTF8(description));
-
-  return ret;
-}
-
 std::vector<UIElement::ClassProperties>
 ViewElement::GetCustomPropertiesForMatchedStyle() const {
   std::vector<UIElement::ClassProperties> ret;
diff --git a/components/ui_devtools/views/view_element.h b/components/ui_devtools/views/view_element.h
index acc3313..cbde863 100644
--- a/components/ui_devtools/views/view_element.h
+++ b/components/ui_devtools/views/view_element.h
@@ -31,8 +31,6 @@
   void OnViewBoundsChanged(views::View* view) override;
 
   // UIElement:
-  std::vector<std::pair<std::string, std::string>> GetCustomProperties()
-      const override;
   std::vector<UIElement::ClassProperties> GetCustomPropertiesForMatchedStyle()
       const override;
   void GetBounds(gfx::Rect* bounds) const override;
diff --git a/components/ui_devtools/views/view_element_unittest.cc b/components/ui_devtools/views/view_element_unittest.cc
index 826eac8..41a6a7c5 100644
--- a/components/ui_devtools/views/view_element_unittest.cc
+++ b/components/ui_devtools/views/view_element_unittest.cc
@@ -9,58 +9,78 @@
 #include "components/ui_devtools/ui_devtools_unittest_utils.h"
 #include "ui/views/test/views_test_base.h"
 
+namespace ui_devtools {
+
 namespace {
 
-size_t GetPropertyIndex(ui_devtools::ViewElement* element,
-                        const std::string& property_name) {
-  auto props = element->GetCustomProperties();
-  for (size_t index = 0; index < props.size(); ++index) {
-    if (props[index].first == property_name)
-      return index;
+// Returns a pair of the ClassProperties index and UIProperty index
+std::pair<size_t, size_t> GetPropertyIndices(ui_devtools::ViewElement* element,
+                                             const std::string& property_name) {
+  std::vector<UIElement::ClassProperties> props =
+      element->GetCustomPropertiesForMatchedStyle();
+  for (size_t cp_index = 0; cp_index < props.size(); ++cp_index) {
+    for (size_t uip_index = 0; uip_index < props[cp_index].properties_.size();
+         ++uip_index) {
+      if (props[cp_index].properties_[uip_index].name_ == property_name)
+        return std::make_pair(cp_index, uip_index);
+    }
   }
   DCHECK(false) << "Property " << property_name << " can not be found.";
-  return 0;
+  return std::make_pair(-1, -1);
 }
 
 void TestBooleanCustomPropertySetting(ui_devtools::ViewElement* element,
                                       const std::string& property_name,
                                       bool init_value) {
-  size_t index = GetPropertyIndex(element, property_name);
+  std::pair<size_t, size_t> indices =
+      GetPropertyIndices(element, property_name);
   std::string old_value(init_value ? "true" : "false");
-  auto props = element->GetCustomProperties();
-  EXPECT_EQ(props[index].second, old_value);
+  std::vector<UIElement::ClassProperties> props =
+      element->GetCustomPropertiesForMatchedStyle();
+  std::vector<UIElement::UIProperty> ui_props =
+      props[indices.first].properties_;
+  EXPECT_EQ(ui_props[indices.second].value_, old_value);
 
   // Check the property can be set accordingly.
   std::string new_value(init_value ? "false" : "true");
   std::string separator(":");
   element->SetPropertiesFromString(property_name + separator + new_value);
-  props = element->GetCustomProperties();
-  EXPECT_EQ(props[index].first, property_name);
-  EXPECT_EQ(props[index].second, new_value);
+  props = element->GetCustomPropertiesForMatchedStyle();
+  ui_props = props[indices.first].properties_;
+  EXPECT_EQ(ui_props[indices.second].name_, property_name);
+  EXPECT_EQ(ui_props[indices.second].value_, new_value);
 
   element->SetPropertiesFromString(property_name + separator + old_value);
-  props = element->GetCustomProperties();
-  EXPECT_EQ(props[index].first, property_name);
-  EXPECT_EQ(props[index].second, old_value);
+  props = element->GetCustomPropertiesForMatchedStyle();
+  ui_props = props[indices.first].properties_;
+  EXPECT_EQ(ui_props[indices.second].name_, property_name);
+  EXPECT_EQ(ui_props[indices.second].value_, old_value);
 }
 
 }  // namespace
 
-namespace ui_devtools {
-
 using ::testing::_;
 
 class NamedTestView : public views::View {
  public:
-  static const char kViewClassName[];
-  const char* GetClassName() const override { return kViewClassName; }
+  METADATA_HEADER(NamedTestView);
 
   // For custom properties test.
   base::string16 GetTooltipText(const gfx::Point& p) const override {
     return base::ASCIIToUTF16("This is the tooltip");
   }
+
+  int GetBoolProperty() const { return bool_property_; }
+  void SetBoolProperty(bool bool_property) { bool_property_ = bool_property; }
+
+ private:
+  bool bool_property_ = false;
 };
-const char NamedTestView::kViewClassName[] = "NamedTestView";
+
+BEGIN_METADATA(NamedTestView)
+METADATA_PARENT_CLASS(views::View)
+ADD_PROPERTY_METADATA(NamedTestView, bool, BoolProperty)
+END_METADATA()
 
 class ViewElementTest : public views::ViewsTestBase {
  public:
@@ -119,19 +139,25 @@
 TEST_F(ViewElementTest, SetPropertiesFromString) {
   static const char* kEnabledProperty = "Enabled";
   TestBooleanCustomPropertySetting(element(), kEnabledProperty, true);
+  std::pair<size_t, size_t> indices =
+      GetPropertyIndices(element(), kEnabledProperty);
 
   // Test setting a non-existent property has no effect.
   element()->SetPropertiesFromString("Enable:false");
-  auto props = element()->GetCustomProperties();
-  size_t index = GetPropertyIndex(element(), kEnabledProperty);
-  EXPECT_EQ(props[index].first, kEnabledProperty);
-  EXPECT_EQ(props[index].second, "true");
+  std::vector<UIElement::ClassProperties> props =
+      element()->GetCustomPropertiesForMatchedStyle();
+  std::vector<UIElement::UIProperty> ui_props =
+      props[indices.first].properties_;
+
+  EXPECT_EQ(ui_props[indices.second].name_, kEnabledProperty);
+  EXPECT_EQ(ui_props[indices.second].value_, "true");
 
   // Test setting empty string for property value has no effect.
   element()->SetPropertiesFromString("Enabled:");
-  props = element()->GetCustomProperties();
-  EXPECT_EQ(props[index].first, kEnabledProperty);
-  EXPECT_EQ(props[index].second, "true");
+  props = element()->GetCustomPropertiesForMatchedStyle();
+  ui_props = props[indices.first].properties_;
+  EXPECT_EQ(ui_props[indices.second].name_, kEnabledProperty);
+  EXPECT_EQ(ui_props[indices.second].value_, "true");
 
   // Ensure setting pure whitespace doesn't crash.
   ASSERT_NO_FATAL_FAILURE(element()->SetPropertiesFromString("   \n  "));
@@ -141,6 +167,10 @@
   TestBooleanCustomPropertySetting(element(), "Visible", true);
 }
 
+TEST_F(ViewElementTest, SettingSubclassBoolProperty) {
+  TestBooleanCustomPropertySetting(element(), "BoolProperty", false);
+}
+
 TEST_F(ViewElementTest, GetBounds) {
   gfx::Rect bounds;
 
@@ -156,23 +186,40 @@
 }
 
 TEST_F(ViewElementTest, GetCustomProperties) {
-  auto props = element()->GetCustomProperties();
-  // There could be a number of properties from metadata.
-  DCHECK_GE(props.size(), 1U);
+  std::vector<UIElement::ClassProperties> props =
+      element()->GetCustomPropertiesForMatchedStyle();
 
-  // The very last property is "tooltip".
-  EXPECT_EQ(props.back().first, "tooltip");
-  EXPECT_EQ(props.back().second, "This is the tooltip");
+  // The ClassProperties vector should be of size 2.
+  DCHECK_EQ(props.size(), 2U);
+
+  std::pair<size_t, size_t> indices =
+      GetPropertyIndices(element(), "BoolProperty");
+  // The BoolProperty property should be in the second ClassProperties object in
+  // the vector.
+  DCHECK_EQ(indices.first, 0U);
+
+  indices = GetPropertyIndices(element(), "tooltip");
+  // The tooltip property should be in the second ClassProperties object in the
+  // vector.
+  DCHECK_EQ(indices.first, 1U);
+
+  std::vector<UIElement::UIProperty> ui_props =
+      props[indices.first].properties_;
+
+  EXPECT_EQ(ui_props[indices.second].name_, "tooltip");
+  EXPECT_EQ(ui_props[indices.second].value_, "This is the tooltip");
 }
 
 TEST_F(ViewElementTest, CheckCustomProperties) {
-  auto props = element()->GetCustomProperties();
+  std::vector<UIElement::ClassProperties> props =
+      element()->GetCustomPropertiesForMatchedStyle();
   DCHECK_GT(props.size(), 1U);
+  DCHECK_GT(props[1].properties_.size(), 1U);
 
   // Check visibility information is passed in.
   bool is_visible_set = false;
-  for (size_t i = 0; i < props.size() - 1; ++i) {
-    if (props[i].first == "Visible")
+  for (size_t i = 0; i < props[1].properties_.size(); ++i) {
+    if (props[1].properties_[i].name_ == "Visible")
       is_visible_set = true;
   }
   EXPECT_TRUE(is_visible_set);
diff --git a/components/ui_devtools/views/widget_element.cc b/components/ui_devtools/views/widget_element.cc
index 7be557d..41094c6 100644
--- a/components/ui_devtools/views/widget_element.cc
+++ b/components/ui_devtools/views/widget_element.cc
@@ -46,11 +46,6 @@
   widget_ = nullptr;
 }
 
-std::vector<std::pair<std::string, std::string>>
-WidgetElement::GetCustomProperties() const {
-  return {};
-}
-
 void WidgetElement::GetBounds(gfx::Rect* bounds) const {
   *bounds = widget_->GetRestoredBounds();
 }
diff --git a/components/ui_devtools/views/widget_element.h b/components/ui_devtools/views/widget_element.h
index d37e6c2..e82758f 100644
--- a/components/ui_devtools/views/widget_element.h
+++ b/components/ui_devtools/views/widget_element.h
@@ -36,8 +36,6 @@
   void OnWidgetDestroyed(views::Widget* widget) override;
 
   // UIElement:
-  std::vector<std::pair<std::string, std::string>> GetCustomProperties()
-      const override;
   void GetBounds(gfx::Rect* bounds) const override;
   void SetBounds(const gfx::Rect& bounds) override;
   void GetVisible(bool* visible) const override;
diff --git a/components/ui_devtools/views/window_element.cc b/components/ui_devtools/views/window_element.cc
index d6cd15d..a6db840 100644
--- a/components/ui_devtools/views/window_element.cc
+++ b/components/ui_devtools/views/window_element.cc
@@ -66,27 +66,6 @@
   delegate()->OnUIElementBoundsChanged(this);
 }
 
-std::vector<std::pair<std::string, std::string>>
-WindowElement::GetCustomProperties() const {
-  std::vector<std::pair<std::string, std::string>> ret;
-
-  std::string state_str =
-      aura::Window::OcclusionStateToString(window_->occlusion_state());
-  // change OcclusionState::UNKNOWN to UNKNOWN
-  state_str = state_str.substr(state_str.find("::") + 2);
-  ret.emplace_back("occlusion-state", state_str);
-  ret.emplace_back("surface", window_->GetSurfaceId().is_valid()
-                                  ? window_->GetSurfaceId().ToString()
-                                  : "none");
-  ret.emplace_back("capture", window_->HasCapture() ? "true" : "false");
-  ret.emplace_back("is-activatable",
-                   wm::CanActivateWindow(window_) ? "true" : "false");
-  ui::Layer* layer = window_->layer();
-  if (layer)
-    AppendLayerProperties(layer, &ret);
-  return ret;
-}
-
 std::vector<UIElement::ClassProperties>
 WindowElement::GetCustomPropertiesForMatchedStyle() const {
   std::vector<UIElement::ClassProperties> ret;
diff --git a/components/ui_devtools/views/window_element.h b/components/ui_devtools/views/window_element.h
index 9b063624..edc5c78 100644
--- a/components/ui_devtools/views/window_element.h
+++ b/components/ui_devtools/views/window_element.h
@@ -34,8 +34,6 @@
                              ui::PropertyChangeReason reason) override;
 
   // UIElement:
-  std::vector<std::pair<std::string, std::string>> GetCustomProperties()
-      const override;
   std::vector<UIElement::ClassProperties> GetCustomPropertiesForMatchedStyle()
       const override;
   void GetBounds(gfx::Rect* bounds) const override;
diff --git a/components/ui_devtools/viz/frame_sink_element.cc b/components/ui_devtools/viz/frame_sink_element.cc
index 90c0b03a..5447cf12 100644
--- a/components/ui_devtools/viz/frame_sink_element.cc
+++ b/components/ui_devtools/viz/frame_sink_element.cc
@@ -33,14 +33,15 @@
 
 FrameSinkElement::~FrameSinkElement() {}
 
-std::vector<std::pair<std::string, std::string>>
-FrameSinkElement::GetCustomProperties() const {
-  std::vector<std::pair<std::string, std::string>> v;
+std::vector<UIElement::ClassProperties>
+FrameSinkElement::GetCustomPropertiesForMatchedStyle() const {
+  std::vector<UIElement::ClassProperties> ret;
+  std::vector<UIElement::UIProperty> properties;
 
   // Hierarchical information about the FrameSink.
-  v.push_back(std::make_pair("Is root", is_root_ ? "true" : "false"));
-  v.push_back(std::make_pair("Has created frame sink",
-                             has_created_frame_sink_ ? "true" : "false"));
+  properties.emplace_back("Is root", is_root_ ? "true" : "false");
+  properties.emplace_back("Has created frame sink",
+                          has_created_frame_sink_ ? "true" : "false");
 
   // LastUsedBeingFrameArgs information.
   const viz::CompositorFrameSinkSupport* support =
@@ -49,14 +50,14 @@
     const viz::BeginFrameArgs args =
         static_cast<const viz::BeginFrameObserver*>(support)
             ->LastUsedBeginFrameArgs();
-    v.push_back(std::make_pair("SourceId", std::to_string(args.source_id)));
-    v.push_back(
-        std::make_pair("SequenceNumber", std::to_string(args.sequence_number)));
-    v.push_back(std::make_pair(
-        "FrameType",
-        std::string(viz::BeginFrameArgs::TypeToString(args.type))));
+    properties.emplace_back("SourceId", base::NumberToString(args.source_id));
+    properties.emplace_back("SequenceNumber",
+                            base::NumberToString(args.sequence_number));
+    properties.emplace_back(
+        "FrameType", std::string(viz::BeginFrameArgs::TypeToString(args.type)));
   }
-  return v;
+  ret.emplace_back("FrameSink", properties);
+  return ret;
 }
 
 void FrameSinkElement::GetBounds(gfx::Rect* bounds) const {
diff --git a/components/ui_devtools/viz/frame_sink_element.h b/components/ui_devtools/viz/frame_sink_element.h
index 152048f5..ec163bb6 100644
--- a/components/ui_devtools/viz/frame_sink_element.h
+++ b/components/ui_devtools/viz/frame_sink_element.h
@@ -36,7 +36,7 @@
   bool has_created_frame_sink() const { return has_created_frame_sink_; }
 
   // UIElement:
-  std::vector<std::pair<std::string, std::string>> GetCustomProperties()
+  std::vector<UIElement::ClassProperties> GetCustomPropertiesForMatchedStyle()
       const override;
   void GetBounds(gfx::Rect* bounds) const override;
   void SetBounds(const gfx::Rect& bounds) override;
diff --git a/components/ui_devtools/viz/surface_element.cc b/components/ui_devtools/viz/surface_element.cc
index 54838ed..e374049 100644
--- a/components/ui_devtools/viz/surface_element.cc
+++ b/components/ui_devtools/viz/surface_element.cc
@@ -35,11 +35,6 @@
 
 SurfaceElement::~SurfaceElement() = default;
 
-std::vector<std::pair<std::string, std::string>>
-SurfaceElement::GetCustomProperties() const {
-  return {};
-}
-
 void SurfaceElement::GetBounds(gfx::Rect* bounds) const {
   // We cannot really know real bounds on the surface unless we do
   // aggregation. Here we just return size of the surface.
diff --git a/components/ui_devtools/viz/surface_element.h b/components/ui_devtools/viz/surface_element.h
index 547a100e..2b621a2 100644
--- a/components/ui_devtools/viz/surface_element.h
+++ b/components/ui_devtools/viz/surface_element.h
@@ -25,8 +25,6 @@
   ~SurfaceElement() override;
 
   // UIElement:
-  std::vector<std::pair<std::string, std::string>> GetCustomProperties()
-      const override;
   void GetBounds(gfx::Rect* bounds) const override;
   void SetBounds(const gfx::Rect& bounds) override;
   void GetVisible(bool* visible) const override;
diff --git a/components/viz/common/display/renderer_settings.h b/components/viz/common/display/renderer_settings.h
index d433fb2..e3325536 100644
--- a/components/viz/common/display/renderer_settings.h
+++ b/components/viz/common/display/renderer_settings.h
@@ -32,7 +32,6 @@
   bool tint_gl_composited_content = false;
   bool show_overdraw_feedback = false;
   bool use_skia_renderer = false;
-  bool use_skia_renderer_non_ddl = false;
   bool allow_overlays = true;
   bool dont_round_texture_sizes_for_pixel_tests = false;
   int highp_threshold_min = 0;
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc
index 07c852fd..541424af 100644
--- a/components/viz/common/features.cc
+++ b/components/viz/common/features.cc
@@ -41,10 +41,6 @@
 const base::Feature kUseSkiaRenderer{"UseSkiaRenderer",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Use the SkiaRenderer without DDL.
-const base::Feature kUseSkiaRendererNonDDL{"UseSkiaRendererNonDDL",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Use the SkiaRenderer to record SkPicture.
 const base::Feature kRecordSkPicture{"RecordSkPicture",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
@@ -101,18 +97,6 @@
   return enabled;
 }
 
-bool IsUsingSkiaRendererNonDDL() {
-  // We require OOP-D everywhere but WebView.
-  bool enabled = base::FeatureList::IsEnabled(kUseSkiaRendererNonDDL);
-#if !defined(OS_ANDROID)
-  if (enabled && !IsVizDisplayCompositorEnabled()) {
-    DLOG(ERROR) << "UseSkiaRendererNonDDL requires VizDisplayCompositor.";
-    return false;
-  }
-#endif  // !defined(OS_ANDROID)
-  return enabled;
-}
-
 bool IsRecordingSkPicture() {
   return IsUsingSkiaRenderer() &&
          base::FeatureList::IsEnabled(kRecordSkPicture);
diff --git a/components/viz/common/features.h b/components/viz/common/features.h
index c232bf45..1b14d5d 100644
--- a/components/viz/common/features.h
+++ b/components/viz/common/features.h
@@ -15,7 +15,6 @@
 VIZ_COMMON_EXPORT extern const base::Feature kEnableVizHitTestSurfaceLayer;
 VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaForGLReadback;
 VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaRenderer;
-VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaRendererNonDDL;
 VIZ_COMMON_EXPORT extern const base::Feature kRecordSkPicture;
 VIZ_COMMON_EXPORT extern const base::Feature kVizDisplayCompositor;
 
@@ -26,7 +25,6 @@
 VIZ_COMMON_EXPORT bool IsVizHitTestingSurfaceLayerEnabled();
 VIZ_COMMON_EXPORT bool IsUsingSkiaForGLReadback();
 VIZ_COMMON_EXPORT bool IsUsingSkiaRenderer();
-VIZ_COMMON_EXPORT bool IsUsingSkiaRendererNonDDL();
 VIZ_COMMON_EXPORT bool IsRecordingSkPicture();
 
 }  // namespace features
diff --git a/components/viz/host/renderer_settings_creation.cc b/components/viz/host/renderer_settings_creation.cc
index 3b99fdc3..cf3b10a 100644
--- a/components/viz/host/renderer_settings_creation.cc
+++ b/components/viz/host/renderer_settings_creation.cc
@@ -64,8 +64,6 @@
   renderer_settings.allow_antialiasing =
       !command_line->HasSwitch(switches::kDisableCompositedAntialiasing);
   renderer_settings.use_skia_renderer = features::IsUsingSkiaRenderer();
-  renderer_settings.use_skia_renderer_non_ddl =
-      features::IsUsingSkiaRendererNonDDL();
 #if defined(OS_MACOSX)
   renderer_settings.allow_overlays =
       ui::RemoteLayerAPISupported() &&
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 0f33808..14835cbf 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -338,9 +338,7 @@
   resource_provider_ = std::make_unique<DisplayResourceProvider>(
       mode, output_surface_->context_provider(), bitmap_manager_,
       enable_shared_images);
-  const bool use_skia_renderer =
-      settings_.use_skia_renderer || settings_.use_skia_renderer_non_ddl;
-  if (use_skia_renderer && mode == DisplayResourceProvider::kGpu) {
+  if (settings_.use_skia_renderer && mode == DisplayResourceProvider::kGpu) {
     // Default to use DDL if skia_output_surface is not null.
     if (skia_output_surface_) {
       renderer_ = std::make_unique<SkiaRenderer>(
diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.cc b/components/viz/service/display_embedder/output_surface_provider_impl.cc
index 136fa317..c56bd88 100644
--- a/components/viz/service/display_embedder/output_surface_provider_impl.cc
+++ b/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -111,21 +111,16 @@
   if (!gpu_compositing) {
     output_surface = std::make_unique<SoftwareOutputSurface>(
         CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client));
-  } else if (renderer_settings.use_skia_renderer ||
-             renderer_settings.use_skia_renderer_non_ddl) {
+  } else if (renderer_settings.use_skia_renderer) {
 #if defined(OS_MACOSX)
     // TODO(penghuang): Support SkiaRenderer for all platforms.
     NOTIMPLEMENTED();
     return nullptr;
 #else
-    if (renderer_settings.use_skia_renderer_non_ddl) {
-      NOTIMPLEMENTED();
-    } else {
-      output_surface = std::make_unique<SkiaOutputSurfaceImpl>(
-          std::make_unique<SkiaOutputSurfaceDependencyImpl>(gpu_service_impl_,
-                                                            surface_handle),
-          renderer_settings);
-    }
+    output_surface = std::make_unique<SkiaOutputSurfaceImpl>(
+        std::make_unique<SkiaOutputSurfaceDependencyImpl>(gpu_service_impl_,
+                                                          surface_handle),
+        renderer_settings);
 #endif
   } else {
     DCHECK(task_executor_);
diff --git a/content/browser/appcache/appcache_fuzzer.cc b/content/browser/appcache/appcache_fuzzer.cc
index 5c24a86..99af899 100644
--- a/content/browser/appcache/appcache_fuzzer.cc
+++ b/content/browser/appcache/appcache_fuzzer.cc
@@ -13,6 +13,7 @@
 #include "base/test/test_timeouts.h"
 #include "content/browser/appcache/appcache_fuzzer.pb.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/test/test_content_browser_client.h"
@@ -47,8 +48,8 @@
 
   void InitializeAppCacheService(
       network::TestURLLoaderFactory* mock_url_loader_factory) {
-    appcache_service =
-        base::MakeRefCounted<ChromeAppCacheService>(/*proxy=*/nullptr);
+    appcache_service = base::MakeRefCounted<ChromeAppCacheService>(
+        /*proxy=*/nullptr, /*partition=*/nullptr);
 
     scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter =
         base::MakeRefCounted<URLLoaderFactoryGetter>();
@@ -58,9 +59,11 @@
         loader_factory_getter.get());
 
     base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
-        base::BindOnce(&ChromeAppCacheService::InitializeOnIOThread,
+        FROM_HERE,
+        {NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()},
+        base::BindOnce(&ChromeAppCacheService::InitializeOnLoaderThread,
                        appcache_service, base::FilePath(),
+                       /*browser_context=*/nullptr,
                        /*resource_context=*/nullptr,
                        /*request_context_getter=*/nullptr,
                        /*special_storage_policy=*/nullptr));
diff --git a/content/browser/appcache/appcache_internals_ui.cc b/content/browser/appcache/appcache_internals_ui.cc
index 0a713e2..7fb985e 100644
--- a/content/browser/appcache/appcache_internals_ui.cc
+++ b/content/browser/appcache/appcache_internals_ui.cc
@@ -19,6 +19,7 @@
 #include "base/values.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_response.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/grit/content_resources.h"
 #include "content/public/browser/browser_context.h"
@@ -162,9 +163,11 @@
 
 void AppCacheInternalsUI::Proxy::Initialize(
     const scoped_refptr<ChromeAppCacheService>& chrome_appcache_service) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+  if (!BrowserThread::CurrentlyOn(
+          NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID())) {
     base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
+        FROM_HERE,
+        {NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()},
         base::BindOnce(&Proxy::Initialize, this, chrome_appcache_service));
     return;
   }
@@ -178,9 +181,12 @@
 }
 
 void AppCacheInternalsUI::Proxy::Shutdown() {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
-                             base::BindOnce(&Proxy::Shutdown, this));
+  if (!BrowserThread::CurrentlyOn(
+          NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID())) {
+    base::PostTaskWithTraits(
+        FROM_HERE,
+        {NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()},
+        base::BindOnce(&Proxy::Shutdown, this));
     return;
   }
   shutdown_called_ = true;
@@ -192,9 +198,11 @@
 }
 
 void AppCacheInternalsUI::Proxy::RequestAllAppCacheInfo() {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+  if (!BrowserThread::CurrentlyOn(
+          NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID())) {
     base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
+        FROM_HERE,
+        {NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()},
         base::BindOnce(&Proxy::RequestAllAppCacheInfo, this));
     return;
   }
@@ -210,17 +218,23 @@
 void AppCacheInternalsUI::Proxy::OnAllAppCacheInfoReady(
     scoped_refptr<AppCacheInfoCollection> collection,
     int net_result_code) {
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&AppCacheInternalsUI::OnAllAppCacheInfoReady,
-                     appcache_internals_ui_, collection, partition_path_));
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    appcache_internals_ui_->OnAllAppCacheInfoReady(collection, partition_path_);
+  } else {
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::UI},
+        base::BindOnce(&AppCacheInternalsUI::OnAllAppCacheInfoReady,
+                       appcache_internals_ui_, collection, partition_path_));
+  }
 }
 
 void AppCacheInternalsUI::Proxy::DeleteAppCache(
     const std::string& manifest_url) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+  if (!BrowserThread::CurrentlyOn(
+          NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID())) {
     base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
+        FROM_HERE,
+        {NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()},
         base::BindOnce(&Proxy::DeleteAppCache, this, manifest_url));
     return;
   }
@@ -234,18 +248,25 @@
 void AppCacheInternalsUI::Proxy::OnAppCacheInfoDeleted(
     const std::string& manifest_url,
     int net_result_code) {
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&AppCacheInternalsUI::OnAppCacheInfoDeleted,
-                     appcache_internals_ui_, partition_path_, manifest_url,
-                     net_result_code == net::OK));
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    appcache_internals_ui_->OnAppCacheInfoDeleted(partition_path_, manifest_url,
+                                                  net_result_code == net::OK);
+  } else {
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::UI},
+        base::BindOnce(&AppCacheInternalsUI::OnAppCacheInfoDeleted,
+                       appcache_internals_ui_, partition_path_, manifest_url,
+                       net_result_code == net::OK));
+  }
 }
 
 void AppCacheInternalsUI::Proxy::RequestAppCacheDetails(
     const std::string& manifest_url) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+  if (!BrowserThread::CurrentlyOn(
+          NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID())) {
     base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
+        FROM_HERE,
+        {NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()},
         base::BindOnce(&Proxy::RequestAppCacheDetails, this, manifest_url));
     return;
   }
@@ -266,18 +287,25 @@
     std::sort(resource_info_vector->begin(), resource_info_vector->end(),
               SortByResourceUrl);
   }
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&AppCacheInternalsUI::OnAppCacheDetailsReady,
-                     appcache_internals_ui_, partition_path_,
-                     manifest_gurl.spec(), std::move(resource_info_vector)));
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    appcache_internals_ui_->OnAppCacheDetailsReady(
+        partition_path_, manifest_gurl.spec(), std::move(resource_info_vector));
+  } else {
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::UI},
+        base::BindOnce(&AppCacheInternalsUI::OnAppCacheDetailsReady,
+                       appcache_internals_ui_, partition_path_,
+                       manifest_gurl.spec(), std::move(resource_info_vector)));
+  }
 }
 
 void AppCacheInternalsUI::Proxy::RequestFileDetails(
     const ProxyResponseEnquiry& response_enquiry) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+  if (!BrowserThread::CurrentlyOn(
+          NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID())) {
     base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
+        FROM_HERE,
+        {NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()},
         base::BindOnce(&Proxy::RequestFileDetails, this, response_enquiry));
     return;
   }
@@ -334,17 +362,27 @@
   if (shutdown_called_)
     return;
   if (!response_info || net_result_code < 0) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(&AppCacheInternalsUI::OnFileDetailsFailed,
-                       appcache_internals_ui_, response_enquiry,
-                       net_result_code));
+    if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+      appcache_internals_ui_->OnFileDetailsFailed(response_enquiry,
+                                                  net_result_code);
+    } else {
+      base::PostTaskWithTraits(
+          FROM_HERE, {BrowserThread::UI},
+          base::BindOnce(&AppCacheInternalsUI::OnFileDetailsFailed,
+                         appcache_internals_ui_, response_enquiry,
+                         net_result_code));
+    }
   } else {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(&AppCacheInternalsUI::OnFileDetailsReady,
-                       appcache_internals_ui_, response_enquiry, response_info,
-                       response_data, net_result_code));
+    if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+      appcache_internals_ui_->OnFileDetailsReady(
+          response_enquiry, response_info, response_data, net_result_code);
+    } else {
+      base::PostTaskWithTraits(
+          FROM_HERE, {BrowserThread::UI},
+          base::BindOnce(&AppCacheInternalsUI::OnFileDetailsReady,
+                         appcache_internals_ui_, response_enquiry,
+                         response_info, response_data, net_result_code));
+    }
   }
   preparing_response_ = false;
   HandleFileDetailsRequest();
diff --git a/content/browser/appcache/appcache_navigation_handle.cc b/content/browser/appcache/appcache_navigation_handle.cc
index 4ffc31c..d7e033a1 100644
--- a/content/browser/appcache/appcache_navigation_handle.cc
+++ b/content/browser/appcache/appcache_navigation_handle.cc
@@ -8,6 +8,7 @@
 #include "base/task/post_task.h"
 #include "content/browser/appcache/appcache_navigation_handle_core.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -21,24 +22,34 @@
                                                            appcache_host_id_,
                                                            process_id)) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&AppCacheNavigationHandleCore::Initialize,
-                     base::Unretained(core_.get())));
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    core_->Initialize();
+  } else {
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::IO},
+        base::BindOnce(&AppCacheNavigationHandleCore::Initialize,
+                       base::Unretained(core_.get())));
+  }
 }
 
 AppCacheNavigationHandle::~AppCacheNavigationHandle() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // Delete the AppCacheNavigationHandleCore on the IO thread.
-  BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, core_.release());
+  if (!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    // Delete the AppCacheNavigationHandleCore on the IO thread.
+    BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, core_.release());
+  }
 }
 
 void AppCacheNavigationHandle::SetProcessId(int process_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&AppCacheNavigationHandleCore::SetProcessId,
-                     base::Unretained(core_.get()), process_id));
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    core_->SetProcessId(process_id);
+  } else {
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::IO},
+        base::BindOnce(&AppCacheNavigationHandleCore::SetProcessId,
+                       base::Unretained(core_.get()), process_id));
+  }
 }
 
 }  // namespace content
diff --git a/content/browser/appcache/appcache_navigation_handle_core.cc b/content/browser/appcache/appcache_navigation_handle_core.cc
index bb6e8ac..8dbfa2de 100644
--- a/content/browser/appcache/appcache_navigation_handle_core.cc
+++ b/content/browser/appcache/appcache_navigation_handle_core.cc
@@ -14,6 +14,7 @@
 #include "content/browser/appcache/appcache_navigation_handle.h"
 #include "content/browser/appcache/appcache_service_impl.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/child_process_host.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -48,13 +49,15 @@
 }
 
 AppCacheNavigationHandleCore::~AppCacheNavigationHandleCore() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   precreated_host_.reset(nullptr);
   g_appcache_handle_map.Get().erase(appcache_host_id_);
 }
 
 void AppCacheNavigationHandleCore::Initialize() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   DCHECK(precreated_host_.get() == nullptr);
   precreated_host_ = std::make_unique<AppCacheHost>(
       appcache_host_id_, process_id_, MSG_ROUTING_NONE, mojo::NullRemote(),
@@ -68,7 +71,8 @@
 // static
 std::unique_ptr<AppCacheHost> AppCacheNavigationHandleCore::GetPrecreatedHost(
     const base::UnguessableToken& host_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   auto index = g_appcache_handle_map.Get().find(host_id);
   if (index != g_appcache_handle_map.Get().end()) {
     AppCacheNavigationHandleCore* instance = index->second;
diff --git a/content/browser/appcache/appcache_service_impl.cc b/content/browser/appcache/appcache_service_impl.cc
index 4a575c6c..9f432ef 100644
--- a/content/browser/appcache/appcache_service_impl.cc
+++ b/content/browser/appcache/appcache_service_impl.cc
@@ -28,6 +28,7 @@
 #include "content/browser/appcache/appcache_quota_client.h"
 #include "content/browser/appcache/appcache_response.h"
 #include "content/browser/appcache/appcache_storage_impl.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "net/base/io_buffer.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
@@ -371,7 +372,8 @@
 // AppCacheServiceImpl -------
 
 AppCacheServiceImpl::AppCacheServiceImpl(
-    storage::QuotaManagerProxy* quota_manager_proxy)
+    storage::QuotaManagerProxy* quota_manager_proxy,
+    base::WeakPtr<StoragePartitionImpl> partition)
     : db_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
            base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
@@ -379,7 +381,8 @@
       quota_client_(nullptr),
       quota_manager_proxy_(quota_manager_proxy),
       request_context_(nullptr),
-      force_keep_session_state_(false) {
+      force_keep_session_state_(false),
+      partition_(std::move(partition)) {
   if (quota_manager_proxy_.get()) {
     // The operator new is used here because this AppCacheQuotaClient instance
     // deletes itself after both the QuotaManager and the AppCacheService are
@@ -531,7 +534,8 @@
     int32_t render_frame_id,
     int process_id,
     mojo::ReportBadMessageCallback bad_message_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   if (GetHost(host_id)) {
     std::move(bad_message_callback).Run("ACSI_REGISTER");
     return;
diff --git a/content/browser/appcache/appcache_service_impl.h b/content/browser/appcache/appcache_service_impl.h
index a799e61..cd17f3bb 100644
--- a/content/browser/appcache/appcache_service_impl.h
+++ b/content/browser/appcache/appcache_service_impl.h
@@ -49,6 +49,7 @@
 class AppCacheServiceImplTest;
 class AppCacheStorageImplTest;
 class AppCacheStorage;
+class StoragePartitionImpl;
 
 // Refcounted container to manage the lifetime of the old storage instance
 // during Reinitialization.
@@ -96,7 +97,8 @@
   };
 
   // If not using quota management, the proxy may be NULL.
-  explicit AppCacheServiceImpl(storage::QuotaManagerProxy* quota_manager_proxy);
+  AppCacheServiceImpl(storage::QuotaManagerProxy* quota_manager_proxy,
+                      base::WeakPtr<StoragePartitionImpl> partition);
   ~AppCacheServiceImpl() override;
 
   void Initialize(const base::FilePath& cache_directory);
@@ -194,6 +196,8 @@
     return url_loader_factory_getter_.get();
   }
 
+  base::WeakPtr<StoragePartitionImpl> partition() { return partition_; }
+
   // Returns a pointer to a registered host. It retains ownership.
   AppCacheHost* GetHost(const base::UnguessableToken& host_id);
   bool EraseHost(const base::UnguessableToken& host_id);
@@ -242,6 +246,9 @@
   // URLLoaderFactoryGetter instance which is used to get to the network
   // URL loader factory.
   scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter_;
+  // If NavigationLoaderOnUI is enabled, |partition_| will be used to get the
+  // network URL loader factory.
+  base::WeakPtr<StoragePartitionImpl> partition_;
 
  private:
   // TODO: Once we remove 'blink::mojom::AppCacheBackend', remove this together.
diff --git a/content/browser/appcache/appcache_service_unittest.cc b/content/browser/appcache/appcache_service_unittest.cc
index dd94bef5..9d57dc5 100644
--- a/content/browser/appcache/appcache_service_unittest.cc
+++ b/content/browser/appcache/appcache_service_unittest.cc
@@ -100,7 +100,7 @@
       : kOriginURL("http://hello/"),
         kOrigin(url::Origin::Create(kOriginURL)),
         kManifestUrl(kOriginURL.Resolve("manifest")),
-        service_(std::make_unique<AppCacheServiceImpl>(nullptr)),
+        service_(std::make_unique<AppCacheServiceImpl>(nullptr, nullptr)),
         delete_result_(net::OK),
         delete_completion_count_(0) {
     // Setup to use mock storage.
@@ -342,7 +342,7 @@
   const base::TimeDelta kOneHour(base::TimeDelta::FromHours(1));
 
   // Do things get initialized as expected?
-  auto service = std::make_unique<AppCacheServiceImpl>(nullptr);
+  auto service = std::make_unique<AppCacheServiceImpl>(nullptr, nullptr);
   EXPECT_TRUE(service->last_reinit_time_.is_null());
   EXPECT_FALSE(service->reinit_timer_.IsRunning());
   EXPECT_EQ(kNoDelay, service->next_reinit_delay_);
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index c9b42b0a..f881195 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -637,13 +637,7 @@
 }
 
 void AppCacheStorageImpl::StoreGroupAndCacheTask::GetQuotaThenSchedule() {
-  storage::QuotaManager* quota_manager = nullptr;
-  if (storage_->service()->quota_manager_proxy()) {
-    quota_manager =
-        storage_->service()->quota_manager_proxy()->quota_manager();
-  }
-
-  if (!quota_manager) {
+  if (!storage_->service()->quota_manager_proxy()) {
     if (storage_->service()->special_storage_policy() &&
         storage_->service()->special_storage_policy()->IsStorageUnlimited(
             group_record_.origin.GetURL()))
@@ -654,8 +648,9 @@
 
   // We have to ask the quota manager for the value.
   storage_->pending_quota_queries_.insert(this);
-  quota_manager->GetUsageAndQuota(
-      group_record_.origin, blink::mojom::StorageType::kTemporary,
+  storage_->service()->quota_manager_proxy()->GetUsageAndQuota(
+      base::ThreadTaskRunnerHandle::Get().get(), group_record_.origin,
+      blink::mojom::StorageType::kTemporary,
       base::BindOnce(&StoreGroupAndCacheTask::OnQuotaCallback, this));
 }
 
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
index 8e172ff..1e2d927e 100644
--- a/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -169,51 +169,9 @@
     AppCacheStorageImplTest* test_;
   };
 
-  class MockQuotaManager : public storage::QuotaManager {
-   public:
-    MockQuotaManager()
-        : QuotaManager(true /* is_incognito */,
-                       base::FilePath(),
-                       io_runner.get(),
-                       nullptr,
-                       storage::GetQuotaSettingsFunc()),
-          async_(false) {}
-
-    void GetUsageAndQuota(const url::Origin& /* origin */,
-                          StorageType type,
-                          UsageAndQuotaCallback callback) override {
-      EXPECT_EQ(StorageType::kTemporary, type);
-      if (async_) {
-        base::SequencedTaskRunnerHandle::Get()->PostTask(
-            FROM_HERE,
-            base::BindOnce(&MockQuotaManager::CallCallback,
-                           base::Unretained(this), std::move(callback)));
-        return;
-      }
-      CallCallback(std::move(callback));
-    }
-
-    void CallCallback(UsageAndQuotaCallback callback) {
-      std::move(callback).Run(blink::mojom::QuotaStatusCode::kOk, 0,
-                              kMockQuota);
-    }
-
-    bool async_;
-
-   protected:
-    ~MockQuotaManager() override {}
-  };
-
   class MockQuotaManagerProxy : public storage::QuotaManagerProxy {
    public:
-    MockQuotaManagerProxy()
-        : QuotaManagerProxy(nullptr, nullptr),
-          notify_storage_accessed_count_(0),
-          notify_storage_modified_count_(0),
-          last_delta_(0),
-          mock_manager_(base::MakeRefCounted<MockQuotaManager>()) {
-      manager_ = mock_manager_.get();
-    }
+    MockQuotaManagerProxy() : QuotaManagerProxy(nullptr, nullptr) {}
 
     void NotifyStorageAccessed(storage::QuotaClient::ID client_id,
                                const url::Origin& origin,
@@ -246,13 +204,24 @@
     void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner,
                           const url::Origin& origin,
                           StorageType type,
-                          UsageAndQuotaCallback callback) override {}
+                          UsageAndQuotaCallback callback) override {
+      EXPECT_EQ(StorageType::kTemporary, type);
+      if (async_) {
+        original_task_runner->PostTask(
+            FROM_HERE,
+            base::BindOnce(std::move(callback),
+                           blink::mojom::QuotaStatusCode::kOk, 0, kMockQuota));
+        return;
+      }
+      std::move(callback).Run(blink::mojom::QuotaStatusCode::kOk, 0,
+                              kMockQuota);
+    }
 
-    int notify_storage_accessed_count_;
-    int notify_storage_modified_count_;
+    int notify_storage_accessed_count_ = 0;
+    int notify_storage_modified_count_ = 0;
     url::Origin last_origin_;
-    int last_delta_;
-    scoped_refptr<MockQuotaManager> mock_manager_;
+    int last_delta_ = 0;
+    bool async_ = false;
 
    protected:
     ~MockQuotaManagerProxy() override {}
@@ -335,7 +304,7 @@
 
   void SetUpTest() {
     DCHECK(io_runner->BelongsToCurrentThread());
-    service_ = std::make_unique<AppCacheServiceImpl>(nullptr);
+    service_ = std::make_unique<AppCacheServiceImpl>(nullptr, nullptr);
     service_->Initialize(base::FilePath());
     mock_quota_manager_proxy_ = base::MakeRefCounted<MockQuotaManagerProxy>();
     service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
@@ -565,7 +534,7 @@
     // and hold a ref to the group to simulate the CacheHost holding that ref.
 
     // Have the quota manager return asynchronously for this test.
-    mock_quota_manager_proxy_->mock_manager_->async_ = true;
+    mock_quota_manager_proxy_->async_ = true;
 
     // Conduct the store test.
     storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
@@ -1657,7 +1626,7 @@
     }
 
     // Recreate the service to point at the db and corruption on disk.
-    service_ = std::make_unique<AppCacheServiceImpl>(nullptr);
+    service_ = std::make_unique<AppCacheServiceImpl>(nullptr, nullptr);
     auto loader_factory_getter = base::MakeRefCounted<URLLoaderFactoryGetter>();
     loader_factory_getter->SetNetworkFactoryForTesting(
         &mock_url_loader_factory_, /* is_corb_enabled = */ true);
diff --git a/content/browser/appcache/appcache_subresource_url_factory.cc b/content/browser/appcache/appcache_subresource_url_factory.cc
index 3232aae4..b305ce0a 100644
--- a/content/browser/appcache/appcache_subresource_url_factory.cc
+++ b/content/browser/appcache/appcache_subresource_url_factory.cc
@@ -15,6 +15,8 @@
 #include "content/browser/appcache/appcache_url_loader_job.h"
 #include "content/browser/appcache/appcache_url_loader_request.h"
 #include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
+#include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_client.h"
@@ -65,7 +67,8 @@
         network_loader_factory_(std::move(network_loader_factory)),
         local_client_binding_(this),
         host_(appcache_host) {
-    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    DCHECK_CURRENTLY_ON(
+        NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
     remote_binding_.set_connection_error_handler(base::BindOnce(
         &SubresourceLoader::OnConnectionError, base::Unretained(this)));
     base::SequencedTaskRunnerHandle::Get()->PostTask(
@@ -339,10 +342,20 @@
     base::WeakPtr<AppCacheHost> host,
     network::mojom::URLLoaderFactoryPtr* loader_factory) {
   DCHECK(host.get());
-  scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory =
-      host->service()
-          ->url_loader_factory_getter()
-          ->GetNetworkFactoryWithCORBEnabled();
+  scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory;
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    // The partition has shutdown, return without binding |loader_factory|.
+    if (!host->service()->partition())
+      return;
+    network_loader_factory =
+        host->service()
+            ->partition()
+            ->GetURLLoaderFactoryForBrowserProcessWithCORBEnabled();
+  } else {
+    network_loader_factory = host->service()
+                                 ->url_loader_factory_getter()
+                                 ->GetNetworkFactoryWithCORBEnabled();
+  }
   // This instance is effectively reference counted by the number of pipes open
   // to it and will get deleted when all clients drop their connections.
   // Please see OnConnectionError() for details.
@@ -363,7 +376,8 @@
     const network::ResourceRequest& request,
     network::mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
 
   // TODO(943887): Replace HasSecurityState() call with something that can
   // preserve security state after process shutdown. The security state check
diff --git a/content/browser/appcache/appcache_update_url_fetcher.cc b/content/browser/appcache/appcache_update_url_fetcher.cc
index d246f58..23ea9767 100644
--- a/content/browser/appcache/appcache_update_url_fetcher.cc
+++ b/content/browser/appcache/appcache_update_url_fetcher.cc
@@ -33,6 +33,7 @@
       buffer_size_(buffer_size),
       request_(std::make_unique<UpdateURLLoaderRequest>(
           job->service_->url_loader_factory_getter(),
+          job->service_->partition(),
           url,
           buffer_size,
           this)) {
@@ -249,7 +250,8 @@
 
   result_ = AppCacheUpdateJob::UPDATE_OK;
   request_ = std::make_unique<UpdateURLLoaderRequest>(
-      job_->service_->url_loader_factory_getter(), url_, buffer_size_, this);
+      job_->service_->url_loader_factory_getter(), job_->service_->partition(),
+      url_, buffer_size_, this);
   Start();
   return true;
 }
diff --git a/content/browser/appcache/appcache_update_url_loader_request.cc b/content/browser/appcache/appcache_update_url_loader_request.cc
index f232fbc..71eb340 100644
--- a/content/browser/appcache/appcache_update_url_loader_request.cc
+++ b/content/browser/appcache/appcache_update_url_loader_request.cc
@@ -7,6 +7,8 @@
 #include "base/bind.h"
 #include "content/browser/appcache/appcache_request_handler.h"
 #include "content/browser/appcache/appcache_update_url_fetcher.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
+#include "content/browser/storage_partition_impl.h"
 #include "net/base/ip_endpoint.h"
 #include "net/http/http_response_info.h"
 #include "net/url_request/url_request_context.h"
@@ -55,12 +57,21 @@
   network::mojom::URLLoaderClientPtr client;
   client_binding_.Bind(mojo::MakeRequest(&client));
 
-  loader_factory_getter_->GetNetworkFactoryWithCORBEnabled()
-      ->CreateLoaderAndStart(
-          mojo::MakeRequest(&url_loader_), -1, -1,
-          network::mojom::kURLLoadOptionSendSSLInfoWithResponse, request_,
-          std::move(client),
-          net::MutableNetworkTrafficAnnotationTag(kAppCacheTrafficAnnotation));
+  scoped_refptr<network::SharedURLLoaderFactory> loader;
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    // The partition has shutdown, return without making the request.
+    if (!partition_)
+      return;
+    loader = partition_->GetURLLoaderFactoryForBrowserProcessWithCORBEnabled();
+  } else {
+    loader = loader_factory_getter_->GetNetworkFactoryWithCORBEnabled();
+  }
+
+  loader->CreateLoaderAndStart(
+      mojo::MakeRequest(&url_loader_), -1, -1,
+      network::mojom::kURLLoadOptionSendSSLInfoWithResponse, request_,
+      std::move(client),
+      net::MutableNetworkTrafficAnnotationTag(kAppCacheTrafficAnnotation));
 }
 
 void AppCacheUpdateJob::UpdateURLLoaderRequest::SetExtraRequestHeaders(
@@ -199,11 +210,13 @@
 
 AppCacheUpdateJob::UpdateURLLoaderRequest::UpdateURLLoaderRequest(
     URLLoaderFactoryGetter* loader_factory_getter,
+    base::WeakPtr<StoragePartitionImpl> partition,
     const GURL& url,
     int buffer_size,
     URLFetcher* fetcher)
     : fetcher_(fetcher),
       loader_factory_getter_(loader_factory_getter),
+      partition_(std::move(partition)),
       client_binding_(this),
       buffer_size_(buffer_size),
       handle_watcher_(FROM_HERE,
diff --git a/content/browser/appcache/appcache_update_url_loader_request.h b/content/browser/appcache/appcache_update_url_loader_request.h
index 0acbf478..1d7cf543 100644
--- a/content/browser/appcache/appcache_update_url_loader_request.h
+++ b/content/browser/appcache/appcache_update_url_loader_request.h
@@ -35,6 +35,7 @@
     : public network::mojom::URLLoaderClient {
  public:
   UpdateURLLoaderRequest(URLLoaderFactoryGetter* loader_factory_getter,
+                         base::WeakPtr<StoragePartitionImpl> partition,
                          const GURL& url,
                          int buffer_size,
                          URLFetcher* fetcher);
@@ -118,6 +119,9 @@
   // Used to retrieve the network URLLoader interface to issue network
   // requests
   scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter_;
+  // If NavigationLoaderOnUI is enabled, |partition_| is used to get the network
+  // URLLoader.
+  base::WeakPtr<StoragePartitionImpl> partition_;
 
   network::ResourceRequest request_;
   network::ResourceResponseHead response_;
diff --git a/content/browser/appcache/chrome_appcache_service.cc b/content/browser/appcache/chrome_appcache_service.cc
index 9c51ed8..54ae9fb 100644
--- a/content/browser/appcache/chrome_appcache_service.cc
+++ b/content/browser/appcache/chrome_appcache_service.cc
@@ -8,9 +8,10 @@
 
 #include "base/files/file_path.h"
 #include "content/browser/appcache/appcache_storage_impl.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/resource_context.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/quota/quota_manager.h"
@@ -19,17 +20,22 @@
 namespace content {
 
 ChromeAppCacheService::ChromeAppCacheService(
-    storage::QuotaManagerProxy* quota_manager_proxy)
-    : AppCacheServiceImpl(quota_manager_proxy), resource_context_(nullptr) {}
+    storage::QuotaManagerProxy* quota_manager_proxy,
+    base::WeakPtr<StoragePartitionImpl> partition)
+    : AppCacheServiceImpl(quota_manager_proxy, std::move(partition)) {}
 
-void ChromeAppCacheService::InitializeOnIOThread(
+void ChromeAppCacheService::InitializeOnLoaderThread(
     const base::FilePath& cache_path,
+    BrowserContext* browser_context,
     ResourceContext* resource_context,
     scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
 
   cache_path_ = cache_path;
+  DCHECK(!(browser_context && resource_context));
+  browser_context_ = browser_context;
   resource_context_ = resource_context;
 
   // The |request_context_getter| can be NULL in some unit tests.
@@ -94,32 +100,47 @@
 
 void ChromeAppCacheService::Shutdown() {
   receivers_.Clear();
+  partition_ = nullptr;
 }
 
 bool ChromeAppCacheService::CanLoadAppCache(const GURL& manifest_url,
                                             const GURL& first_party) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
   // We don't prompt for read access.
-  return GetContentClient()->browser()->AllowAppCache(
+  if (browser_context_) {
+    return GetContentClient()->browser()->AllowAppCache(
+        manifest_url, first_party, browser_context_);
+  }
+  return GetContentClient()->browser()->AllowAppCacheOnIO(
       manifest_url, first_party, resource_context_);
 }
 
 bool ChromeAppCacheService::CanCreateAppCache(
     const GURL& manifest_url, const GURL& first_party) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  return GetContentClient()->browser()->AllowAppCache(
+  DCHECK_CURRENTLY_ON(
+      NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID());
+  if (browser_context_) {
+    return GetContentClient()->browser()->AllowAppCache(
+        manifest_url, first_party, browser_context_);
+  }
+  return GetContentClient()->browser()->AllowAppCacheOnIO(
       manifest_url, first_party, resource_context_);
 }
 
 ChromeAppCacheService::~ChromeAppCacheService() {}
 
 void ChromeAppCacheService::DeleteOnCorrectThread() const {
-  if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+  if (BrowserThread::CurrentlyOn(
+          NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID())) {
     delete this;
     return;
   }
-  if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) {
-    BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, this);
+  if (BrowserThread::IsThreadInitialized(
+          NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID())) {
+    BrowserThread::DeleteSoon(
+        NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID(),
+        FROM_HERE, this);
     return;
   }
   // Better to leak than crash on shutdown.
diff --git a/content/browser/appcache/chrome_appcache_service.h b/content/browser/appcache/chrome_appcache_service.h
index 2c22218..ad7d1586 100644
--- a/content/browser/appcache/chrome_appcache_service.h
+++ b/content/browser/appcache/chrome_appcache_service.h
@@ -30,6 +30,7 @@
 }
 
 namespace content {
+class BrowserContext;
 class ResourceContext;
 
 struct ChromeAppCacheServiceDeleter;
@@ -51,11 +52,17 @@
       public AppCacheServiceImpl,
       public AppCachePolicy {
  public:
-  explicit ChromeAppCacheService(storage::QuotaManagerProxy* proxy);
+  ChromeAppCacheService(storage::QuotaManagerProxy* proxy,
+                        base::WeakPtr<StoragePartitionImpl> partition);
 
-  // If |cache_path| is empty we will use in-memory structs.
-  void InitializeOnIOThread(
+  // If |cache_path| is empty we will use in-memory structs. If the
+  // NavigationLoaderOnUI feature is enabled, this is run on the UI thread with
+  // |browser_context| set and |resource_context| null. If it is disabled, this
+  // is run on the IO thread with |resource_context| set and |browser_context|
+  // null.
+  void InitializeOnLoaderThread(
       const base::FilePath& cache_path,
+      BrowserContext* browser_context,
       ResourceContext* resource_context,
       scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy);
@@ -103,7 +110,8 @@
 
   void DeleteOnCorrectThread() const;
 
-  ResourceContext* resource_context_;
+  BrowserContext* browser_context_ = nullptr;
+  ResourceContext* resource_context_ = nullptr;
   base::FilePath cache_path_;
   mojo::UniqueReceiverSet<blink::mojom::AppCacheBackend> receivers_;
 
diff --git a/content/browser/appcache/chrome_appcache_service_unittest.cc b/content/browser/appcache/chrome_appcache_service_unittest.cc
index 1ad9f28..aea927f 100644
--- a/content/browser/appcache/chrome_appcache_service_unittest.cc
+++ b/content/browser/appcache/chrome_appcache_service_unittest.cc
@@ -68,14 +68,16 @@
 ChromeAppCacheServiceTest::CreateAppCacheServiceImpl(
     const base::FilePath& appcache_path,
     bool init_storage) {
-  auto appcache_service = base::MakeRefCounted<ChromeAppCacheService>(nullptr);
+  auto appcache_service =
+      base::MakeRefCounted<ChromeAppCacheService>(nullptr, nullptr);
   auto mock_policy = base::MakeRefCounted<MockSpecialStoragePolicy>();
   mock_policy->AddProtected(kProtectedManifestURL.GetOrigin());
   mock_policy->AddSessionOnly(kSessionOnlyManifestURL.GetOrigin());
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&ChromeAppCacheService::InitializeOnIOThread,
+      base::BindOnce(&ChromeAppCacheService::InitializeOnLoaderThread,
                      appcache_service, appcache_path,
+                     nullptr /* browser_context */,
                      browser_context_.GetResourceContext(),
                      base::RetainedRef(browser_context_.GetRequestContext()),
                      std::move(mock_policy)));
diff --git a/content/browser/appcache/mock_appcache_service.h b/content/browser/appcache/mock_appcache_service.h
index 1941d28..a7cc48e4 100644
--- a/content/browser/appcache/mock_appcache_service.h
+++ b/content/browser/appcache/mock_appcache_service.h
@@ -16,7 +16,7 @@
 class MockAppCacheService : public AppCacheServiceImpl {
  public:
   MockAppCacheService()
-      : AppCacheServiceImpl(nullptr),
+      : AppCacheServiceImpl(nullptr, nullptr),
         mock_delete_appcaches_for_origin_result_(net::OK),
         delete_called_count_(0) {
     storage_ = std::make_unique<MockAppCacheStorage>(this);
diff --git a/content/browser/find_in_page_client.cc b/content/browser/find_in_page_client.cc
index 7812fe0c..50b7a19 100644
--- a/content/browser/find_in_page_client.cc
+++ b/content/browser/find_in_page_client.cc
@@ -4,17 +4,18 @@
 
 #include "content/browser/find_in_page_client.h"
 
+#include <utility>
+
 #include "content/browser/find_request_manager.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 
 namespace content {
 
 FindInPageClient::FindInPageClient(FindRequestManager* find_request_manager,
                                    RenderFrameHostImpl* rfh)
-    : frame_(rfh), find_request_manager_(find_request_manager), binding_(this) {
-  blink::mojom::FindInPageClientPtr client;
-  binding_.Bind(MakeRequest(&client));
-  frame_->GetFindInPage()->SetClient(std::move(client));
+    : frame_(rfh), find_request_manager_(find_request_manager) {
+  frame_->GetFindInPage()->SetClient(receiver_.BindNewPipeAndPassRemote());
 }
 
 FindInPageClient::~FindInPageClient() {}
diff --git a/content/browser/find_in_page_client.h b/content/browser/find_in_page_client.h
index 083e457..a79c1a56 100644
--- a/content/browser/find_in_page_client.h
+++ b/content/browser/find_in_page_client.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_BROWSER_FIND_IN_PAGE_CLIENT_H_
 #define CONTENT_BROWSER_FIND_IN_PAGE_CLIENT_H_
 
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
 
 namespace content {
@@ -43,7 +43,7 @@
                         blink::mojom::FindMatchUpdateType update_type);
   RenderFrameHostImpl* const frame_;
   FindRequestManager* const find_request_manager_;
-  mojo::Binding<blink::mojom::FindInPageClient> binding_;
+  mojo::Receiver<blink::mojom::FindInPageClient> receiver_{this};
   int number_of_matches_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(FindInPageClient);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 145bfe5..cc14ab2 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -68,6 +68,7 @@
 #include "content/browser/installedapp/installed_app_provider_impl_default.h"
 #include "content/browser/interface_provider_filtering.h"
 #include "content/browser/keyboard_lock/keyboard_lock_service_impl.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/loader/prefetch_url_loader_service.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/log_console_message.h"
@@ -4885,9 +4886,9 @@
   // TODO(crbug.com/979296): Consider changing this code to copy an origin
   // instead of creating one from a URL which lacks opacity information.
   if (!is_same_document) {
-    base::Optional<url::Origin> top_frame_origin =
-        frame_tree_node_->IsMainFrame() ? url::Origin::Create(common_params.url)
-                                        : frame_tree_->root()->current_origin();
+    url::Origin top_frame_origin = frame_tree_node_->IsMainFrame()
+                                       ? url::Origin::Create(common_params.url)
+                                       : frame_tree_->root()->current_origin();
     network_isolation_key_ = net::NetworkIsolationKey(top_frame_origin);
   }
 
@@ -5450,10 +5451,10 @@
   return mojo_image_downloader_;
 }
 
-const blink::mojom::FindInPageAssociatedPtr&
+const mojo::AssociatedRemote<blink::mojom::FindInPage>&
 RenderFrameHostImpl::GetFindInPage() {
   if (!find_in_page_ || !find_in_page_.is_bound() ||
-      find_in_page_.encountered_error())
+      !find_in_page_.is_connected())
     GetRemoteAssociatedInterfaces()->GetInterface(&find_in_page_);
   return find_in_page_;
 }
@@ -6254,13 +6255,19 @@
   auto* appcache_service_impl = static_cast<AppCacheServiceImpl*>(
       GetProcess()->GetStoragePartition()->GetAppCacheService());
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&AppCacheServiceImpl::RegisterHostForFrame,
-                     appcache_service_impl->AsWeakPtr(),
-                     std::move(host_receiver), std::move(frontend_remote),
-                     host_id, routing_id_, GetProcess()->GetID(),
-                     mojo::GetBadMessageCallback()));
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    appcache_service_impl->RegisterHostForFrame(
+        std::move(host_receiver), std::move(frontend_remote), host_id,
+        routing_id_, GetProcess()->GetID(), mojo::GetBadMessageCallback());
+  } else {
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::IO},
+        base::BindOnce(&AppCacheServiceImpl::RegisterHostForFrame,
+                       appcache_service_impl->AsWeakPtr(),
+                       std::move(host_receiver), std::move(frontend_remote),
+                       host_id, routing_id_, GetProcess()->GetID(),
+                       mojo::GetBadMessageCallback()));
+  }
 }
 
 std::unique_ptr<NavigationRequest>
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 2234375..a75c8be 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -739,8 +739,8 @@
   // Returns the Mojo ImageDownloader service.
   const blink::mojom::ImageDownloaderPtr& GetMojoImageDownloader();
 
-  // Returns pointer to renderer side FindInPage associated with this frame.
-  const blink::mojom::FindInPageAssociatedPtr& GetFindInPage();
+  // Returns remote to renderer side FindInPage associated with this frame.
+  const mojo::AssociatedRemote<blink::mojom::FindInPage>& GetFindInPage();
 
   // Resets the loading state. Following this call, the RenderFrameHost will be
   // in a non-loading state.
@@ -1895,7 +1895,7 @@
   blink::mojom::ImageDownloaderPtr mojo_image_downloader_;
 
   // Holder of Mojo connection with FindInPage service in Blink.
-  blink::mojom::FindInPageAssociatedPtr find_in_page_;
+  mojo::AssociatedRemote<blink::mojom::FindInPage> find_in_page_;
 
   // Holds a NavigationRequest when it's about to commit, ie. after
   // OnCrossDocumentCommitProcessed has returned a positive answer for this
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 26e18d241..21b79bb 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -100,14 +100,6 @@
 
 namespace {
 
-// Returns the BrowserThread::ID that the URLLoaderRequestController will be
-// running on.
-BrowserThread::ID GetLoaderRequestControllerThreadID() {
-  return NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()
-             ? BrowserThread::UI
-             : BrowserThread::IO;
-}
-
 class NavigationLoaderInterceptorBrowserContainer
     : public NavigationLoaderInterceptor {
  public:
@@ -670,7 +662,8 @@
     }
 
     if (IsNavigationLoaderOnUIEnabled()) {
-      CreateInterceptorsForUI(request_info, service_worker_navigation_handle);
+      CreateInterceptorsForUI(request_info, service_worker_navigation_handle,
+                              appcache_handle_core);
     } else {
       CreateInterceptorsForIO(
           request_info, service_worker_navigation_handle_core,
@@ -701,7 +694,8 @@
 
   void CreateInterceptorsForUI(
       NavigationRequestInfo* request_info,
-      ServiceWorkerNavigationHandle* service_worker_navigation_handle) {
+      ServiceWorkerNavigationHandle* service_worker_navigation_handle,
+      AppCacheNavigationHandleCore* appcache_handle_core) {
     // Set up an interceptor for service workers.
     if (service_worker_navigation_handle) {
       std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
@@ -714,6 +708,17 @@
         interceptors_.push_back(std::move(service_worker_interceptor));
     }
 
+    // Set-up an interceptor for AppCache if non-null |appcache_handle_core|
+    // is given.
+    if (appcache_handle_core) {
+      CHECK(appcache_handle_core->host());
+      std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
+          AppCacheRequestHandler::InitializeForMainResourceNetworkService(
+              *resource_request_, appcache_handle_core->host()->GetWeakPtr());
+      if (appcache_interceptor)
+        interceptors_.push_back(std::move(appcache_interceptor));
+    }
+
     // See if embedders want to add interceptors.
     std::vector<std::unique_ptr<URLLoaderRequestInterceptor>>
         browser_interceptors =
@@ -1127,7 +1132,7 @@
       base::Optional<url::Origin> origin =
           url::Origin::Create(resource_request_->url);
       resource_request_->trusted_network_isolation_key =
-          net::NetworkIsolationKey(origin, origin);
+          net::NetworkIsolationKey(origin.value(), origin);
     }
 
     resource_request_->referrer = GURL(redirect_info_.new_referrer);
@@ -1927,6 +1932,13 @@
          base::FeatureList::IsEnabled(features::kNavigationLoaderOnUI);
 }
 
+// static
+BrowserThread::ID
+NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID() {
+  return IsNavigationLoaderOnUIEnabled() ? BrowserThread::UI
+                                         : BrowserThread::IO;
+}
+
 void NavigationURLLoaderImpl::OnRequestStarted(base::TimeTicks timestamp) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   delegate_->OnRequestStarted(timestamp);
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index f49c6c5..3e0c3855 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -110,6 +110,10 @@
   // Returns true if URLLoaderRequestController will be run on the UI thread.
   static bool IsNavigationLoaderOnUIEnabled();
 
+  // Returns the BrowserThread::ID that the URLLoaderRequestController will be
+  // running on.
+  static BrowserThread::ID GetLoaderRequestControllerThreadID();
+
  private:
   class URLLoaderRequestController;
   void OnRequestStarted(base::TimeTicks timestamp);
diff --git a/content/browser/push_messaging/push_messaging_manager.cc b/content/browser/push_messaging/push_messaging_manager.cc
index c8c04277..f38ac3231 100644
--- a/content/browser/push_messaging/push_messaging_manager.cc
+++ b/content/browser/push_messaging/push_messaging_manager.cc
@@ -104,14 +104,6 @@
   return "";
 }
 
-// Returns whether |application_server_key| contains a valid application server
-// key, that is, a NIST P-256 public key in uncompressed format.
-bool IsApplicationServerKey(
-    const std::vector<uint8_t>& application_server_key) {
-  return application_server_key.size() == 65 &&
-         application_server_key[0] == 0x04;
-}
-
 // Returns application_server_key if non-empty, otherwise checks if
 // stored_sender_id may be used as a fallback and if so, returns
 // stored_sender_id instead.
@@ -177,9 +169,9 @@
   void GetSubscriptionDidGetInfoOnUI(GetSubscriptionCallback callback,
                                      const GURL& origin,
                                      int64_t service_worker_registration_id,
-                                     const GURL& endpoint,
                                      const std::string& application_server_key,
                                      bool is_valid,
+                                     const GURL& endpoint,
                                      const std::vector<uint8_t>& p256dh,
                                      const std::vector<uint8_t>& auth);
 
@@ -222,6 +214,7 @@
 
   void DidRegister(RegisterData data,
                    const std::string& push_subscription_id,
+                   const GURL& endpoint,
                    const std::vector<uint8_t>& p256dh,
                    const std::vector<uint8_t>& auth,
                    blink::mojom::PushRegistrationStatus status);
@@ -281,12 +274,6 @@
 
   PushMessagingService* service = ui_core_->service();
   service_available_ = !!service;
-
-  if (service_available_) {
-    default_endpoint_ = service->GetEndpoint(false /* standard_protocol */);
-    web_push_protocol_endpoint_ =
-        service->GetEndpoint(true /* standard_protocol */);
-  }
 }
 
 PushMessagingManager::~PushMessagingManager() {}
@@ -523,6 +510,7 @@
 void PushMessagingManager::Core::DidRegister(
     RegisterData data,
     const std::string& push_subscription_id,
+    const GURL& endpoint,
     const std::vector<uint8_t>& p256dh,
     const std::vector<uint8_t>& auth,
     blink::mojom::PushRegistrationStatus status) {
@@ -541,7 +529,7 @@
         FROM_HERE, {BrowserThread::IO},
         base::BindOnce(&PushMessagingManager::PersistRegistrationOnIO,
                        io_parent_, std::move(data), push_subscription_id,
-                       p256dh, auth,
+                       endpoint, p256dh, auth,
                        subscription_changed
                            ? blink::mojom::PushRegistrationStatus::
                                  SUCCESS_NEW_SUBSCRIPTION_FROM_PUSH_SERVICE
@@ -558,6 +546,7 @@
 void PushMessagingManager::PersistRegistrationOnIO(
     RegisterData data,
     const std::string& push_subscription_id,
+    const GURL& endpoint,
     const std::vector<uint8_t>& p256dh,
     const std::vector<uint8_t>& auth,
     blink::mojom::PushRegistrationStatus status) {
@@ -573,21 +562,21 @@
       {{kPushRegistrationIdServiceWorkerKey, push_subscription_id},
        {kPushSenderIdServiceWorkerKey, application_server_key}},
       base::BindOnce(&PushMessagingManager::DidPersistRegistrationOnIO,
-                     weak_factory_.GetWeakPtr(), std::move(data),
-                     push_subscription_id, p256dh, auth, status));
+                     weak_factory_.GetWeakPtr(), std::move(data), endpoint,
+                     p256dh, auth, status));
 }
 
 void PushMessagingManager::DidPersistRegistrationOnIO(
     RegisterData data,
-    const std::string& push_subscription_id,
+    const GURL& endpoint,
     const std::vector<uint8_t>& p256dh,
     const std::vector<uint8_t>& auth,
     blink::mojom::PushRegistrationStatus push_registration_status,
     blink::ServiceWorkerStatusCode service_worker_status) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (service_worker_status == blink::ServiceWorkerStatusCode::kOk) {
-    SendSubscriptionSuccess(std::move(data), push_registration_status,
-                            push_subscription_id, p256dh, auth);
+    SendSubscriptionSuccess(std::move(data), push_registration_status, endpoint,
+                            p256dh, auth);
   } else {
     // TODO(johnme): Unregister, so PushMessagingServiceImpl can decrease count.
     SendSubscriptionError(std::move(data),
@@ -606,7 +595,7 @@
 void PushMessagingManager::SendSubscriptionSuccess(
     RegisterData data,
     blink::mojom::PushRegistrationStatus status,
-    const std::string& push_subscription_id,
+    const GURL& endpoint,
     const std::vector<uint8_t>& p256dh,
     const std::vector<uint8_t>& auth) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -620,10 +609,6 @@
     return;
   }
 
-  const GURL endpoint = CreateEndpoint(
-      IsApplicationServerKey(data.options->application_server_key),
-      push_subscription_id);
-
   std::move(data.callback)
       .Run(status, blink::mojom::PushSubscription::New(
                        endpoint, std::move(data.options), p256dh, auth));
@@ -803,12 +788,6 @@
 
       const GURL origin = registration->scope().GetOrigin();
 
-      const bool uses_standard_protocol =
-          IsApplicationServerKey(std::vector<uint8_t>(
-              application_server_key.begin(), application_server_key.end()));
-      const GURL endpoint =
-          CreateEndpoint(uses_standard_protocol, push_subscription_id);
-
       base::PostTaskWithTraits(
           FROM_HERE, {BrowserThread::UI},
           base::BindOnce(&Core::GetSubscriptionInfoOnUI,
@@ -818,7 +797,7 @@
                          base::Bind(&Core::GetSubscriptionDidGetInfoOnUI,
                                     ui_core_weak_ptr_, base::Passed(&callback),
                                     origin, service_worker_registration_id,
-                                    endpoint, application_server_key)));
+                                    application_server_key)));
 
       return;
     }
@@ -863,9 +842,9 @@
     GetSubscriptionCallback callback,
     const GURL& origin,
     int64_t service_worker_registration_id,
-    const GURL& endpoint,
     const std::string& application_server_key,
     bool is_valid,
+    const GURL& endpoint,
     const std::vector<uint8_t>& p256dh,
     const std::vector<uint8_t>& auth) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -947,9 +926,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   PushMessagingService* push_service = service();
   if (!push_service) {
-    std::move(callback).Run(false /* is_valid */,
-                            std::vector<uint8_t>() /* p256dh */,
-                            std::vector<uint8_t>() /* auth */);
+    std::move(callback).Run(
+        false /* is_valid */, GURL::EmptyGURL() /* endpoint */,
+        std::vector<uint8_t>() /* p256dh */, std::vector<uint8_t>() /* auth */);
     return;
   }
 
@@ -958,15 +937,6 @@
                                     std::move(callback));
 }
 
-GURL PushMessagingManager::CreateEndpoint(
-    bool standard_protocol,
-    const std::string& subscription_id) const {
-  const GURL& base =
-      standard_protocol ? web_push_protocol_endpoint_ : default_endpoint_;
-
-  return GURL(base.spec() + subscription_id);
-}
-
 PushMessagingService* PushMessagingManager::Core::service() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   RenderProcessHost* process_host =
diff --git a/content/browser/push_messaging/push_messaging_manager.h b/content/browser/push_messaging/push_messaging_manager.h
index c3436f9..47a67524 100644
--- a/content/browser/push_messaging/push_messaging_manager.h
+++ b/content/browser/push_messaging/push_messaging_manager.h
@@ -85,13 +85,14 @@
   // Called via PostTask from UI thread.
   void PersistRegistrationOnIO(RegisterData data,
                                const std::string& push_subscription_id,
+                               const GURL& endpoint,
                                const std::vector<uint8_t>& p256dh,
                                const std::vector<uint8_t>& auth,
                                blink::mojom::PushRegistrationStatus status);
 
   void DidPersistRegistrationOnIO(
       RegisterData data,
-      const std::string& push_subscription_id,
+      const GURL& endpoint,
       const std::vector<uint8_t>& p256dh,
       const std::vector<uint8_t>& auth,
       blink::mojom::PushRegistrationStatus push_registration_status,
@@ -103,7 +104,7 @@
   // Called both from IO thread, and via PostTask from UI thread.
   void SendSubscriptionSuccess(RegisterData data,
                                blink::mojom::PushRegistrationStatus status,
-                               const std::string& push_subscription_id,
+                               const GURL& endpoint,
                                const std::vector<uint8_t>& p256dh,
                                const std::vector<uint8_t>& auth);
 
@@ -127,11 +128,6 @@
 
   // Helper methods on either thread -------------------------------------------
 
-  // Creates an endpoint for |subscription_id| with either the default protocol,
-  // or the standardized Web Push Protocol, depending on |standard_protocol|.
-  GURL CreateEndpoint(bool standard_protocol,
-                      const std::string& subscription_id) const;
-
   // Inner core of this message filter which lives on the UI thread.
   std::unique_ptr<Core, BrowserThread::DeleteOnUIThread> ui_core_;
 
@@ -147,9 +143,6 @@
   // Will be ChildProcessHost::kInvalidUniqueID in requests from Service Worker.
   int render_frame_id_;
 
-  GURL default_endpoint_;
-  GURL web_push_protocol_endpoint_;
-
   mojo::ReceiverSet<blink::mojom::PushMessaging> receivers_;
 
   base::WeakPtrFactory<PushMessagingManager> weak_factory_{this};
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 9f76f47..263cdf45 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -45,14 +45,12 @@
 #include "components/viz/common/surfaces/local_surface_id_allocation.h"
 #include "components/viz/common/viz_utils.h"
 #include "components/viz/host/host_display_client.h"
-#include "components/viz/service/display/display.h"
 #include "components/viz/service/display/display_scheduler.h"
 #include "components/viz/service/display/output_surface.h"
 #include "components/viz/service/display/output_surface_client.h"
 #include "components/viz/service/display/output_surface_frame.h"
 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/compositor/surface_utils.h"
 #include "content/browser/gpu/compositor_util.h"
@@ -415,10 +413,9 @@
       needs_animate_(false),
       pending_frames_(0U),
       layer_tree_frame_sink_request_pending_(false),
-      enable_surface_synchronization_(
-          features::IsSurfaceSynchronizationEnabled()),
-      enable_viz_(features::IsVizDisplayCompositorEnabled()),
       weak_factory_(this) {
+  CHECK(features::IsVizDisplayCompositorEnabled());
+  CHECK(features::IsSurfaceSynchronizationEnabled());
   DCHECK(client);
 
   SetRootWindow(root_window);
@@ -457,7 +454,6 @@
   // handle visibility, swapping begin frame sources, etc.
   // These checks ensure we have no begin frame source, and that we don't need
   // to register one on the new window.
-  DCHECK(!display_);
   DCHECK(!window_);
 
   scoped_refptr<cc::Layer> root_layer;
@@ -542,7 +538,7 @@
 
   cc::LayerTreeSettings settings;
   settings.use_zero_copy = true;
-  settings.enable_surface_synchronization = enable_surface_synchronization_;
+  settings.enable_surface_synchronization = true;
   settings.build_hit_test_data = features::IsVizHitTestingSurfaceLayerEnabled();
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -614,38 +610,21 @@
   // https://crbug.com/899705
   SCOPED_UMA_HISTOGRAM_LONG_TIMER("CompositorImplAndroid.TearDownDisplayTime");
 
-  if (enable_viz_) {
-    // Make a best effort to try to complete pending readbacks.
-    // TODO(crbug.com/637035): Consider doing this in a better way,
-    // ideally with the guarantee of readbacks completing.
-    if (display_private_ && HavePendingReadbacks()) {
-      // Note that while this is not a Sync IPC, the call to
-      // InvalidateFrameSinkId below will end up triggering a sync call to
-      // FrameSinkManager::DestroyCompositorFrameSink, as this is the root
-      // frame sink. Because |display_private_| is an associated interface to
-      // FrameSinkManager, this subsequent sync call will ensure ordered
-      // execution of this call.
-      display_private_->ForceImmediateDrawAndSwapIfPossible();
-    }
-
-    GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
-    display_private_.reset();
-  } else {
-    // Make a best effort to try to complete pending readbacks.
-    // TODO(crbug.com/637035): Consider doing this in a better way,
-    // ideally with the guarantee of readbacks completing.
-    if (display_ && HavePendingReadbacks())
-      display_->ForceImmediateDrawAndSwapIfPossible();
-
-    if (display_) {
-      CompositorDependenciesAndroid::Get()
-          .frame_sink_manager_impl()
-          ->UnregisterBeginFrameSource(root_window_->GetBeginFrameSource());
-    }
-
-    GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
-    display_.reset();
+  // Make a best effort to try to complete pending readbacks.
+  // TODO(crbug.com/637035): Consider doing this in a better way,
+  // ideally with the guarantee of readbacks completing.
+  if (display_private_ && HavePendingReadbacks()) {
+    // Note that while this is not a Sync IPC, the call to
+    // InvalidateFrameSinkId below will end up triggering a sync call to
+    // FrameSinkManager::DestroyCompositorFrameSink, as this is the root
+    // frame sink. Because |display_private_| is an associated interface to
+    // FrameSinkManager, this subsequent sync call will ensure ordered
+    // execution of this call.
+    display_private_->ForceImmediateDrawAndSwapIfPossible();
   }
+
+  GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
+  display_private_.reset();
 }
 
 void CompositorImpl::RegisterRootFrameSink() {
@@ -665,8 +644,6 @@
     host_->SetViewportSizeAndScale(size_, root_window_->GetDipScale(),
                                    GenerateLocalSurfaceId());
   }
-  if (display_)
-    display_->Resize(size);
 
   if (display_private_)
     display_private_->Resize(size);
@@ -779,12 +756,10 @@
   display_color_space_ = display::Screen::GetScreen()
                              ->GetDisplayNearestWindow(root_window_)
                              .color_space();
-  gpu::SurfaceHandle surface_handle =
-      enable_viz_ ? gpu::kNullSurfaceHandle : surface_handle_;
   auto context_provider =
       base::MakeRefCounted<viz::ContextProviderCommandBuffer>(
           std::move(gpu_channel_host), factory->GetGpuMemoryBufferManager(),
-          stream_id, stream_priority, surface_handle,
+          stream_id, stream_priority, gpu::kNullSurfaceHandle,
           GURL(std::string("chrome://gpu/CompositorImpl::") +
                std::string("CompositorContextProvider")),
           automatic_flushes, support_locking, support_grcontext,
@@ -794,12 +769,7 @@
           viz::command_buffer_metrics::ContextType::BROWSER_COMPOSITOR);
   auto result = context_provider->BindToCurrentThread();
 
-  if (surface_handle != gpu::kNullSurfaceHandle) {
-    // Only use OnContextCreationResult for onscreen contexts, where recovering
-    // from a surface initialization failure is possible by re-creating the
-    // native window.
-    OnContextCreationResult(result);
-  } else if (result == gpu::ContextResult::kFatalFailure) {
+  if (result == gpu::ContextResult::kFatalFailure) {
     LOG(FATAL) << "Fatal failure in creating offscreen context";
   }
 
@@ -808,72 +778,7 @@
     return;
   }
 
-  if (enable_viz_) {
-    InitializeVizLayerTreeFrameSink(std::move(context_provider));
-  } else {
-    // Unretained is safe this owns viz::Display which owns OutputSurface.
-    auto display_output_surface = std::make_unique<AndroidOutputSurface>(
-        context_provider, base::BindRepeating(&CompositorImpl::DidSwapBuffers,
-                                              base::Unretained(this)));
-    InitializeDisplay(std::move(display_output_surface),
-                      std::move(context_provider));
-  }
-}
-
-void CompositorImpl::InitializeDisplay(
-    std::unique_ptr<viz::OutputSurface> display_output_surface,
-    scoped_refptr<viz::ContextProvider> context_provider) {
-  DCHECK(layer_tree_frame_sink_request_pending_);
-
-  pending_frames_ = 0;
-
-  if (context_provider) {
-    gpu_capabilities_ = context_provider->ContextCapabilities();
-  }
-
-  viz::FrameSinkManagerImpl* manager =
-      CompositorDependenciesAndroid::Get().frame_sink_manager_impl();
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
-      base::ThreadTaskRunnerHandle::Get();
-  auto scheduler = std::make_unique<viz::DisplayScheduler>(
-      root_window_->GetBeginFrameSource(), task_runner.get(),
-      display_output_surface->capabilities().max_frames_pending);
-
-  viz::RendererSettings renderer_settings;
-  renderer_settings.allow_antialiasing = false;
-  renderer_settings.highp_threshold_min = 2048;
-  renderer_settings.auto_resize_output_surface = false;
-  renderer_settings.initial_screen_size =
-      display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(root_window_)
-          .GetSizeInPixel();
-  auto* gpu_memory_buffer_manager = BrowserMainLoop::GetInstance()
-                                        ->gpu_channel_establish_factory()
-                                        ->GetGpuMemoryBufferManager();
-
-  // Don't re-register BeginFrameSource on context loss.
-  const bool should_register_begin_frame_source = !display_;
-
-  display_ = std::make_unique<viz::Display>(
-      nullptr, renderer_settings, frame_sink_id_,
-      std::move(display_output_surface), std::move(scheduler), task_runner);
-
-  auto layer_tree_frame_sink = std::make_unique<viz::DirectLayerTreeFrameSink>(
-      frame_sink_id_, GetHostFrameSinkManager(), manager, display_.get(),
-      nullptr /* display_client */, context_provider,
-      nullptr /* worker_context_provider */, task_runner,
-      gpu_memory_buffer_manager);
-
-  display_->SetVisible(true);
-  display_->Resize(size_);
-  display_->SetColorSpace(display_color_space_, display_color_space_);
-  if (should_register_begin_frame_source) {
-    CompositorDependenciesAndroid::Get()
-        .frame_sink_manager_impl()
-        ->RegisterBeginFrameSource(root_window_->GetBeginFrameSource(),
-                                   frame_sink_id_);
-  }
-  host_->SetLayerTreeFrameSink(std::move(layer_tree_frame_sink));
+  InitializeVizLayerTreeFrameSink(std::move(context_provider));
 }
 
 void CompositorImpl::DidSwapBuffers(const gfx::Size& swap_size) {
@@ -996,10 +901,6 @@
 }
 
 void CompositorImpl::SetVSyncPaused(bool paused) {
-  // No action needed in non-Viz mode, as VSync is handled in WindowAndroid.
-  if (!enable_viz_)
-    return;
-
   if (vsync_paused_ == paused)
     return;
 
@@ -1021,7 +922,6 @@
 
 void CompositorImpl::InitializeVizLayerTreeFrameSink(
     scoped_refptr<viz::ContextProviderCommandBuffer> context_provider) {
-  DCHECK(enable_viz_);
   DCHECK(root_window_);
 
   pending_frames_ = 0;
@@ -1095,12 +995,8 @@
 }
 
 viz::LocalSurfaceIdAllocation CompositorImpl::GenerateLocalSurfaceId() {
-  if (enable_surface_synchronization_) {
-    local_surface_id_allocator_.GenerateId();
-    return local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation();
-  }
-
-  return viz::LocalSurfaceIdAllocation();
+  local_surface_id_allocator_.GenerateId();
+  return local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation();
 }
 
 void CompositorImpl::OnContextCreationResult(
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 995a380..d5aebb25 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -53,7 +53,6 @@
 }
 
 namespace viz {
-class Display;
 class FrameSinkId;
 class HostDisplayClient;
 class OutputSurface;
@@ -221,8 +220,6 @@
   std::unique_ptr<cc::LayerTreeHost> host_;
   ui::ResourceManagerImpl resource_manager_;
 
-  std::unique_ptr<viz::Display> display_;
-
   gfx::ColorSpace display_color_space_;
   gfx::Size size_;
   bool requires_alpha_channel_ = false;
@@ -254,12 +251,6 @@
       pending_child_frame_sink_ids_;
   bool has_submitted_frame_since_became_visible_ = false;
 
-  // If true, we are using surface synchronization.
-  const bool enable_surface_synchronization_;
-
-  // If true, we are using a Viz process.
-  const bool enable_viz_;
-
   // Viz-specific members for communicating with the display.
   viz::mojom::DisplayPrivateAssociatedPtr display_private_;
   std::unique_ptr<viz::HostDisplayClient> display_client_;
diff --git a/content/browser/renderer_host/delegated_frame_host_client_android.cc b/content/browser/renderer_host/delegated_frame_host_client_android.cc
index ed5e6a7..45dc009b 100644
--- a/content/browser/renderer_host/delegated_frame_host_client_android.cc
+++ b/content/browser/renderer_host/delegated_frame_host_client_android.cc
@@ -15,26 +15,6 @@
 
 DelegatedFrameHostClientAndroid::~DelegatedFrameHostClientAndroid() {}
 
-void DelegatedFrameHostClientAndroid::SetBeginFrameSource(
-    viz::BeginFrameSource* begin_frame_source) {
-  render_widget_host_view_->SetBeginFrameSource(begin_frame_source);
-}
-
-void DelegatedFrameHostClientAndroid::DidReceiveCompositorFrameAck(
-    const std::vector<viz::ReturnedResource>& resources) {
-  render_widget_host_view_->DidReceiveCompositorFrameAck(resources);
-}
-
-void DelegatedFrameHostClientAndroid::DidPresentCompositorFrames(
-    const viz::FrameTimingDetailsMap& timing_details) {
-  render_widget_host_view_->DidPresentCompositorFrames(timing_details);
-}
-
-void DelegatedFrameHostClientAndroid::ReclaimResources(
-    const std::vector<viz::ReturnedResource>& resources) {
-  render_widget_host_view_->ReclaimResources(resources);
-}
-
 void DelegatedFrameHostClientAndroid::OnFrameTokenChanged(
     uint32_t frame_token) {
   render_widget_host_view_->OnFrameTokenChangedForView(frame_token);
diff --git a/content/browser/renderer_host/delegated_frame_host_client_android.h b/content/browser/renderer_host/delegated_frame_host_client_android.h
index 823c313..1cc4128 100644
--- a/content/browser/renderer_host/delegated_frame_host_client_android.h
+++ b/content/browser/renderer_host/delegated_frame_host_client_android.h
@@ -23,13 +23,6 @@
 
  private:
   // DelegatedFrameHostAndroid::Client implementation.
-  void SetBeginFrameSource(viz::BeginFrameSource* begin_frame_source) override;
-  void DidPresentCompositorFrames(
-      const viz::FrameTimingDetailsMap& timing_details) override;
-  void DidReceiveCompositorFrameAck(
-      const std::vector<viz::ReturnedResource>& resources) override;
-  void ReclaimResources(
-      const std::vector<viz::ReturnedResource>& resources) override;
   void OnFrameTokenChanged(uint32_t frame_token) override;
   void WasEvicted() override;
 
diff --git a/content/browser/renderer_host/input/fling_browsertest.cc b/content/browser/renderer_host/input/fling_browsertest.cc
index c9b521f9..ee7fef5 100644
--- a/content/browser/renderer_host/input/fling_browsertest.cc
+++ b/content/browser/renderer_host/input/fling_browsertest.cc
@@ -453,7 +453,8 @@
   // Scroll the parent down so that it is scrollable upward.
 
   // Initialize observer before scrolling changes the position of the OOPIF.
-  HitTestTransformChangeObserver observer(child_view_->GetFrameSinkId());
+  HitTestRegionObserver observer(child_view_->GetFrameSinkId());
+  observer.WaitForHitTestData();
 
   EXPECT_TRUE(
       ExecJs(GetRootNode()->current_frame_host(), "window.scrollTo(0, 20)"));
@@ -463,8 +464,7 @@
   WaitForFrameScroll(GetRootNode(), 19);
   SynchronizeThreads();
 
-  // Wait for hit test data to change after scroll happens.
-  observer.WaitForTransformChangeInHitTestData();
+  observer.WaitForHitTestDataChange();
 
   // Fling and wait for the parent to scroll up.
   auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
diff --git a/content/browser/renderer_host/input/touch_action_browsertest.cc b/content/browser/renderer_host/input/touch_action_browsertest.cc
index 4805119..65f4d2d 100644
--- a/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -31,6 +31,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/hit_test_region_observer.h"
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "third_party/blink/public/platform/web_input_event.h"
@@ -167,11 +168,12 @@
     TitleWatcher watcher(shell()->web_contents(), ready_title);
     ignore_result(watcher.WaitAndGetTitle());
 
-    // We need to wait until at least one frame has been composited
-    // otherwise the injection of the synthetic gestures may get
-    // dropped because of MainThread/Impl thread sync of touch event
-    // regions.
-    frame_observer_->WaitForAnyFrameSubmission();
+    // We need to wait until hit test data is available. We use our own
+    // HitTestRegionObserver here, rather than
+    // WaitForHitTestDataOrChildSurfaceReady, because we have the
+    // RenderWidgetHostImpl available.
+    HitTestRegionObserver observer(host->GetFrameSinkId());
+    observer.WaitForHitTestData();
   }
 
   // ContentBrowserTest:
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 716ce08..ff4ede7 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -102,6 +102,7 @@
 #include "content/browser/histogram_controller.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/loader/resource_message_filter.h"
 #include "content/browser/loader/url_loader_factory_impl.h"
 #include "content/browser/media/capture/audio_mirroring_manager.h"
@@ -2152,10 +2153,19 @@
       base::BindRepeating(&CreateReportingServiceProxy, GetID()));
 #endif  // BUILDFLAG(ENABLE_REPORTING)
 
-  registry->AddInterface(base::BindRepeating(
-      &ChromeAppCacheService::CreateBackendForRequest,
-      base::Unretained(storage_partition_impl_->GetAppCacheService()),
-      GetID()));
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    AddUIThreadInterface(
+        registry.get(),
+        base::BindRepeating(
+            &ChromeAppCacheService::CreateBackendForRequest,
+            base::Unretained(storage_partition_impl_->GetAppCacheService()),
+            GetID()));
+  } else {
+    registry->AddInterface(base::BindRepeating(
+        &ChromeAppCacheService::CreateBackendForRequest,
+        base::Unretained(storage_partition_impl_->GetAppCacheService()),
+        GetID()));
+  }
 
   AddUIThreadInterface(
       registry.get(),
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index d392b81..3c41b162 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -244,9 +244,10 @@
   if (using_browser_compositor_) {
     delegated_frame_host_client_ =
         std::make_unique<DelegatedFrameHostClientAndroid>(this);
+    DCHECK(features::IsSurfaceSynchronizationEnabled());
     delegated_frame_host_ = std::make_unique<ui::DelegatedFrameHostAndroid>(
         &view_, GetHostFrameSinkManager(), delegated_frame_host_client_.get(),
-        host()->GetFrameSinkId(), features::IsSurfaceSynchronizationEnabled());
+        host()->GetFrameSinkId());
     if (is_showing_) {
       delegated_frame_host_->WasShown(
           local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
@@ -1083,25 +1084,7 @@
     const viz::LocalSurfaceId& local_surface_id,
     viz::CompositorFrame frame,
     base::Optional<viz::HitTestRegionList> hit_test_region_list) {
-  if (!delegated_frame_host_) {
-    DCHECK(!using_browser_compositor_);
-    return;
-  }
-
-  DCHECK(!frame.render_pass_list.empty());
-
-  viz::RenderPass* root_pass = frame.render_pass_list.back().get();
-  current_surface_size_ = root_pass->output_rect.size();
-  bool is_transparent = root_pass->has_transparent_background;
-
-  viz::CompositorFrameMetadata metadata = frame.metadata.Clone();
-
-  delegated_frame_host_->SubmitCompositorFrame(
-      local_surface_id, std::move(frame), std::move(hit_test_region_list));
-
-  // As the metadata update may trigger view invalidation, always call it after
-  // any potential compositor scheduling.
-  OnFrameMetadataUpdated(std::move(metadata), is_transparent);
+  NOTREACHED();
 }
 
 void RenderWidgetHostViewAndroid::OnDidNotProduceFrame(
@@ -1112,8 +1095,7 @@
     DCHECK(!using_browser_compositor_);
     return;
   }
-
-  delegated_frame_host_->DidNotProduceFrame(ack);
+  NOTREACHED();
 }
 
 void RenderWidgetHostViewAndroid::ClearCompositorFrame() {
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 8c399416..12a2be4 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -2729,13 +2729,8 @@
 
 // This test tests that browser process hittesting ignores frames with
 // pointer-events: none.
-// TODO(https://crbug.com/968970): Flaky failures on all bots.
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       DISABLED_SurfaceHitTestPointerEventsNoneChanged) {
-  // In /2 hit testing, OOPIFs with pointer-events: none are ignored and no hit
-  // test data is submitted. To make sure we wait enough time until child frame
-  // fully loaded, we add a 1x1 pixel OOPIF for the test to track the process of
-  // /2 hit testing.
+                       SurfaceHitTestPointerEventsNoneChanged) {
   GURL main_url(embedded_test_server()->GetURL(
       "/frame_tree/page_with_positioned_frame_pointer-events_none.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -2786,35 +2781,26 @@
               kHitTestTolerance);
   EXPECT_FALSE(child_frame_monitor.EventWasReceived());
 
-  // Remove pointer-events: none property from iframe, also remove child2 to
-  // properly notify the observer the update.
-  // Wait for the confirmation of the deletion so that surface hit test is aware
-  // of the change of pointer-events property. When viz hit testing is enabled,
-  // we do not need to wait.
-  EXPECT_TRUE(ExecuteScript(web_contents(),
-                            "document.getElementsByTagName('iframe')[0].style."
-                            "pointerEvents = 'auto';\n"));
+  HitTestRegionObserver hit_test_data_change_observer(
+      root_view->GetRootFrameSinkId());
+  hit_test_data_change_observer.WaitForHitTestData();
 
+  // Remove pointer-events: none property from iframe to check that it can claim
+  // the input event now.
+  EXPECT_TRUE(
+      ExecuteScript(web_contents(),
+                    "setTimeout(function() {\n"
+                    "  document.getElementsByTagName('iframe')[0].style."
+                    "      pointerEvents = 'auto';\n"
+                    "}, 100);"));
   ASSERT_EQ(2U, root->child_count());
 
-  {
-    MainThreadFrameObserver observer(
-        root->current_frame_host()->GetRenderWidgetHost());
-    observer.Wait();
-  }
-  {
-    MainThreadFrameObserver observer(
-        root->child_at(0)->current_frame_host()->GetRenderWidgetHost());
-    observer.Wait();
-  }
-  {
-    MainThreadFrameObserver observer(
-        root->child_at(1)->current_frame_host()->GetRenderWidgetHost());
-    observer.Wait();
-  }
+  MainThreadFrameObserver observer(
+      root->current_frame_host()->GetRenderWidgetHost());
+  observer.Wait();
 
-  WaitForHitTestDataOrChildSurfaceReady(child_node1->current_frame_host());
-  WaitForHitTestDataOrChildSurfaceReady(child_node2->current_frame_host());
+  hit_test_data_change_observer.WaitForHitTestDataChange();
+
   main_frame_monitor.ResetEventReceived();
   child_frame_monitor.ResetEventReceived();
   InputEventAckWaiter child_waiter(
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc
index 2ccefdd..77c202e 100644
--- a/content/browser/speech/speech_recognition_browsertest.cc
+++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -257,7 +257,8 @@
     audio_bus->FromInterleaved<media::SignedInt16SampleTypeTraits>(
         reinterpret_cast<int16_t*>(&audio_buffer.get()[0]),
         audio_bus->frames());
-    capture_callback->Capture(audio_bus.get(), 0, 0.0, false);
+    capture_callback->Capture(audio_bus.get(), base::TimeTicks::Now(), 0.0,
+                              false);
   }
 
   void FeedAudioCapturerSource(const media::AudioParameters& audio_params,
diff --git a/content/browser/speech/speech_recognizer_impl.cc b/content/browser/speech/speech_recognizer_impl.cc
index 8b28929..bc113e9 100644
--- a/content/browser/speech/speech_recognizer_impl.cc
+++ b/content/browser/speech/speech_recognizer_impl.cc
@@ -271,7 +271,7 @@
 }
 
 void SpeechRecognizerImpl::Capture(const AudioBus* data,
-                                   int audio_delay_milliseconds,
+                                   base::TimeTicks audio_capture_time,
                                    double volume,
                                    bool key_pressed) {
   // Convert audio from native format to fixed format used by WebSpeech.
diff --git a/content/browser/speech/speech_recognizer_impl.h b/content/browser/speech/speech_recognizer_impl.h
index 8b966d992..c3f699b 100644
--- a/content/browser/speech/speech_recognizer_impl.h
+++ b/content/browser/speech/speech_recognizer_impl.h
@@ -143,7 +143,7 @@
   // media::AudioCapturerSource::CaptureCallback methods.
   void OnCaptureStarted() final {}
   void Capture(const media::AudioBus* audio_bus,
-               int audio_delay_milliseconds,
+               base::TimeTicks audio_capture_time,
                double volume,
                bool key_pressed) final;
   void OnCaptureError(const std::string& message) final;
diff --git a/content/browser/speech/speech_recognizer_impl_unittest.cc b/content/browser/speech/speech_recognizer_impl_unittest.cc
index 0c8ae64..e7b1b22f 100644
--- a/content/browser/speech/speech_recognizer_impl_unittest.cc
+++ b/content/browser/speech/speech_recognizer_impl_unittest.cc
@@ -254,7 +254,7 @@
     auto* capture_callback =
         static_cast<media::AudioCapturerSource::CaptureCallback*>(
             recognizer_.get());
-    capture_callback->Capture(data, 0, 0.0, false);
+    capture_callback->Capture(data, base::TimeTicks::Now(), 0.0, false);
   }
 
   void OnCaptureError() {
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 186174c5..9b1d2bcd 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -38,6 +38,7 @@
 #include "content/browser/cookie_store/cookie_store_context.h"
 #include "content/browser/fileapi/browser_file_system_helper.h"
 #include "content/browser/gpu/shader_cache_factory.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/loader/prefetch_url_loader_service.h"
 #include "content/browser/native_file_system/native_file_system_manager_impl.h"
 #include "content/browser/notifications/platform_notification_context_impl.h"
@@ -519,8 +520,9 @@
     : public network::SharedURLLoaderFactory {
  public:
   explicit URLLoaderFactoryForBrowserProcess(
-      StoragePartitionImpl* storage_partition)
-      : storage_partition_(storage_partition) {}
+      StoragePartitionImpl* storage_partition,
+      bool corb_enabled)
+      : storage_partition_(storage_partition), corb_enabled_(corb_enabled) {}
 
   // mojom::URLLoaderFactory implementation:
 
@@ -535,7 +537,8 @@
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     if (!storage_partition_)
       return;
-    storage_partition_->GetURLLoaderFactoryForBrowserProcessInternal()
+    storage_partition_
+        ->GetURLLoaderFactoryForBrowserProcessInternal(corb_enabled_)
         ->CreateLoaderAndStart(std::move(request), routing_id, request_id,
                                options, url_request, std::move(client),
                                traffic_annotation);
@@ -544,8 +547,9 @@
   void Clone(network::mojom::URLLoaderFactoryRequest request) override {
     if (!storage_partition_)
       return;
-    storage_partition_->GetURLLoaderFactoryForBrowserProcessInternal()->Clone(
-        std::move(request));
+    storage_partition_
+        ->GetURLLoaderFactoryForBrowserProcessInternal(corb_enabled_)
+        ->Clone(std::move(request));
   }
 
   // SharedURLLoaderFactory implementation:
@@ -562,6 +566,7 @@
   ~URLLoaderFactoryForBrowserProcess() override {}
 
   StoragePartitionImpl* storage_partition_;
+  const bool corb_enabled_;
 
   DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryForBrowserProcess);
 };
@@ -763,6 +768,9 @@
   if (shared_url_loader_factory_for_browser_process_) {
     shared_url_loader_factory_for_browser_process_->Shutdown();
   }
+  if (shared_url_loader_factory_for_browser_process_with_corb_) {
+    shared_url_loader_factory_for_browser_process_with_corb_->Shutdown();
+  }
 
   if (GetDatabaseTracker()) {
     GetDatabaseTracker()->task_runner()->PostTask(
@@ -801,9 +809,13 @@
     GetContentIndexContext()->Shutdown();
 
   if (GetAppCacheService()) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
-        base::BindOnce(&ChromeAppCacheService::Shutdown, appcache_service_));
+    if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+      GetAppCacheService()->Shutdown();
+    } else {
+      base::PostTaskWithTraits(
+          FROM_HERE, {BrowserThread::IO},
+          base::BindOnce(&ChromeAppCacheService::Shutdown, appcache_service_));
+    }
   }
 
   BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
@@ -873,8 +885,8 @@
   partition->service_worker_context_ = new ServiceWorkerContextWrapper(context);
   partition->service_worker_context_->set_storage_partition(partition.get());
 
-  partition->appcache_service_ =
-      base::MakeRefCounted<ChromeAppCacheService>(quota_manager_proxy.get());
+  partition->appcache_service_ = base::MakeRefCounted<ChromeAppCacheService>(
+      quota_manager_proxy.get(), partition->weak_factory_.GetWeakPtr());
 
   partition->shared_worker_service_ = std::make_unique<SharedWorkerServiceImpl>(
       partition.get(), partition->service_worker_context_,
@@ -1004,11 +1016,20 @@
 StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcess() {
   if (!shared_url_loader_factory_for_browser_process_) {
     shared_url_loader_factory_for_browser_process_ =
-        new URLLoaderFactoryForBrowserProcess(this);
+        new URLLoaderFactoryForBrowserProcess(this, false /* corb_enabled */);
   }
   return shared_url_loader_factory_for_browser_process_;
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcessWithCORBEnabled() {
+  if (!shared_url_loader_factory_for_browser_process_with_corb_) {
+    shared_url_loader_factory_for_browser_process_with_corb_ =
+        new URLLoaderFactoryForBrowserProcess(this, true /* corb_enabled */);
+  }
+  return shared_url_loader_factory_for_browser_process_with_corb_;
+}
+
 std::unique_ptr<network::SharedURLLoaderFactoryInfo>
 StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcessIOThread() {
   return url_loader_factory_getter_->GetNetworkFactoryInfo();
@@ -1630,6 +1651,7 @@
 void StoragePartitionImpl::ResetURLLoaderFactories() {
   GetNetworkContext()->ResetURLLoaderFactories();
   url_loader_factory_for_browser_process_.reset();
+  url_loader_factory_for_browser_process_with_corb_.reset();
   url_loader_factory_getter_->Initialize(this);
 }
 
@@ -1642,6 +1664,8 @@
   network_context_.FlushForTesting();
   if (url_loader_factory_for_browser_process_)
     url_loader_factory_for_browser_process_.FlushForTesting();
+  if (url_loader_factory_for_browser_process_with_corb_)
+    url_loader_factory_for_browser_process_with_corb_.FlushForTesting();
   if (cookie_manager_for_browser_process_)
     cookie_manager_for_browser_process_.FlushForTesting();
   if (origin_policy_manager_for_browser_process_)
@@ -1721,39 +1745,45 @@
 }
 
 network::mojom::URLLoaderFactory*
-StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcessInternal() {
+StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcessInternal(
+    bool corb_enabled) {
+  auto& url_loader_factory =
+      corb_enabled ? url_loader_factory_for_browser_process_with_corb_
+                   : url_loader_factory_for_browser_process_;
+  auto& is_test_url_loader_factory =
+      corb_enabled ? is_test_url_loader_factory_for_browser_process_with_corb_
+                   : is_test_url_loader_factory_for_browser_process_;
+
   // Create the URLLoaderFactory as needed, but make sure not to reuse a
   // previously created one if the test override has changed.
-  if (url_loader_factory_for_browser_process_ &&
-      !url_loader_factory_for_browser_process_.encountered_error() &&
-      is_test_url_loader_factory_for_browser_process_ !=
+  if (url_loader_factory && !url_loader_factory.encountered_error() &&
+      is_test_url_loader_factory !=
           g_url_loader_factory_callback_for_test.Get().is_null()) {
-    return url_loader_factory_for_browser_process_.get();
+    return url_loader_factory.get();
   }
 
   network::mojom::URLLoaderFactoryParamsPtr params =
       network::mojom::URLLoaderFactoryParams::New();
   params->process_id = network::mojom::kBrowserProcessId;
-  params->is_corb_enabled = false;
+  params->is_corb_enabled = corb_enabled;
   params->disable_web_security =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableWebSecurity);
   if (g_url_loader_factory_callback_for_test.Get().is_null()) {
-    auto request = mojo::MakeRequest(&url_loader_factory_for_browser_process_);
+    auto request = mojo::MakeRequest(&url_loader_factory);
     GetNetworkContext()->CreateURLLoaderFactory(std::move(request),
                                                 std::move(params));
-    is_test_url_loader_factory_for_browser_process_ = false;
-    return url_loader_factory_for_browser_process_.get();
+    is_test_url_loader_factory = false;
+    return url_loader_factory.get();
   }
 
   network::mojom::URLLoaderFactoryPtr original_factory;
   GetNetworkContext()->CreateURLLoaderFactory(
       mojo::MakeRequest(&original_factory), std::move(params));
-  url_loader_factory_for_browser_process_ =
-      g_url_loader_factory_callback_for_test.Get().Run(
-          std::move(original_factory));
-  is_test_url_loader_factory_for_browser_process_ = true;
-  return url_loader_factory_for_browser_process_.get();
+  url_loader_factory = g_url_loader_factory_callback_for_test.Get().Run(
+      std::move(original_factory));
+  is_test_url_loader_factory = true;
+  return url_loader_factory.get();
 }
 
 network::mojom::OriginPolicyManager*
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index 3cf2672..79f80ac 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -93,6 +93,8 @@
   network::mojom::NetworkContext* GetNetworkContext() override;
   scoped_refptr<network::SharedURLLoaderFactory>
   GetURLLoaderFactoryForBrowserProcess() override;
+  scoped_refptr<network::SharedURLLoaderFactory>
+  GetURLLoaderFactoryForBrowserProcessWithCORBEnabled() override;
   std::unique_ptr<network::SharedURLLoaderFactoryInfo>
   GetURLLoaderFactoryForBrowserProcessIOThread() override;
   network::mojom::CookieManager* GetCookieManagerForBrowserProcess() override;
@@ -339,7 +341,7 @@
   void InitNetworkContext();
 
   network::mojom::URLLoaderFactory*
-  GetURLLoaderFactoryForBrowserProcessInternal();
+  GetURLLoaderFactoryForBrowserProcessInternal(bool corb_enabled);
 
   // |is_in_memory_| and |relative_partition_path_| are cached from
   // |StoragePartitionImpl::Create()| in order to re-create |NetworkContext|.
@@ -398,6 +400,8 @@
 
   scoped_refptr<URLLoaderFactoryForBrowserProcess>
       shared_url_loader_factory_for_browser_process_;
+  scoped_refptr<URLLoaderFactoryForBrowserProcess>
+      shared_url_loader_factory_for_browser_process_with_corb_;
 
   // URLLoaderFactory/CookieManager for use in the browser process only.
   // See the method comment for
@@ -405,6 +409,9 @@
   // more details
   network::mojom::URLLoaderFactoryPtr url_loader_factory_for_browser_process_;
   bool is_test_url_loader_factory_for_browser_process_ = false;
+  network::mojom::URLLoaderFactoryPtr
+      url_loader_factory_for_browser_process_with_corb_;
+  bool is_test_url_loader_factory_for_browser_process_with_corb_ = false;
   network::mojom::CookieManagerPtr cookie_manager_for_browser_process_;
   network::mojom::OriginPolicyManagerPtr
       origin_policy_manager_for_browser_process_;
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc
index 474c2317..ad221e8 100644
--- a/content/browser/storage_partition_impl_map.cc
+++ b/content/browser/storage_partition_impl_map.cc
@@ -31,6 +31,7 @@
 #include "content/browser/cookie_store/cookie_store_context.h"
 #include "content/browser/devtools/devtools_url_request_interceptor.h"
 #include "content/browser/fileapi/browser_file_system_helper.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/loader/prefetch_url_loader_service.h"
 #include "content/browser/loader/resource_request_info_impl.h"
 #include "content/browser/resource_context_impl.h"
@@ -535,17 +536,28 @@
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     request_context_getter = partition->GetURLRequestContext();
 
+  if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+    partition->GetAppCacheService()->InitializeOnLoaderThread(
+        in_memory ? base::FilePath()
+                  : partition->GetPath().Append(kAppCacheDirname),
+        browser_context_, nullptr /* resource_context */,
+        request_context_getter, browser_context_->GetSpecialStoragePolicy());
+  }
+
   // Check first to avoid memory leak in unittests.
   if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
-        base::BindOnce(
-            &ChromeAppCacheService::InitializeOnIOThread,
-            partition->GetAppCacheService(),
-            in_memory ? base::FilePath()
-                      : partition->GetPath().Append(kAppCacheDirname),
-            browser_context_->GetResourceContext(), request_context_getter,
-            base::RetainedRef(browser_context_->GetSpecialStoragePolicy())));
+    if (!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
+      base::PostTaskWithTraits(
+          FROM_HERE, {BrowserThread::IO},
+          base::BindOnce(
+              &ChromeAppCacheService::InitializeOnLoaderThread,
+              partition->GetAppCacheService(),
+              in_memory ? base::FilePath()
+                        : partition->GetPath().Append(kAppCacheDirname),
+              nullptr /* browser_context */,
+              browser_context_->GetResourceContext(), request_context_getter,
+              base::RetainedRef(browser_context_->GetSpecialStoragePolicy())));
+    }
 
     partition->GetCacheStorageContext()->SetBlobParametersForCache(
         ChromeBlobStorageContext::GetFor(browser_context_));
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index a46080d..c35ea6f 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1769,10 +1769,7 @@
       ui::EventTimeForNow() - last_interactive_input_event_time_;
   // Note: the expectation is that the caller is typically expecting an input
   // event, e.g. validating that a WebUI message that requires a gesture is
-  // actually attached to a gesture. Logging to UMA here should hopefully give
-  // sufficient data if 5 seconds is actually sufficient (or even too high a
-  // threshhold).
-  UMA_HISTOGRAM_TIMES("Tabs.TimeSinceLastInteraction", delta);
+  // actually attached to a gesture.
   return delta <= kMaxInterval;
 }
 
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc
index bc45ff9..40747a1 100644
--- a/content/browser/worker_host/dedicated_worker_host.cc
+++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -223,7 +223,7 @@
     // creating dedicated workers, as there might be no ancestor frame.
     auto* host =
         RenderFrameHostImpl::FromID(process_id_, ancestor_render_frame_id_);
-    base::Optional<url::Origin> top_frame_origin(
+    url::Origin top_frame_origin(
         host->frame_tree_node()->frame_tree()->root()->current_origin());
 
     process->CreateURLLoaderFactory(
diff --git a/content/browser/worker_host/worker_script_loader.cc b/content/browser/worker_host/worker_script_loader.cc
index 29e875c..62899f1 100644
--- a/content/browser/worker_host/worker_script_loader.cc
+++ b/content/browser/worker_host/worker_script_loader.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "content/browser/appcache/appcache_request_handler.h"
 #include "content/browser/loader/navigation_loader_interceptor.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_request_handler.h"
@@ -47,7 +48,9 @@
       interceptors_.push_back(std::move(service_worker_interceptor));
   }
 
-  if (appcache_host) {
+  // TODO(http://crbug.com/824858): Run interceptors on UI thread.
+  if (!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled() &&
+      appcache_host) {
     std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
         AppCacheRequestHandler::InitializeForMainResourceNetworkService(
             resource_request_, appcache_host);
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index 3e3b103..a7d9f79 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -230,7 +230,7 @@
       base::win::ScopedCOMInitializer::kMTA);
 
   if (base::FeatureList::IsEnabled(features::kGpuProcessHighPriorityWin))
-    ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS);
+    ::SetPriorityClass(::GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
 #endif
 
   logging::SetLogMessageHandler(GpuProcessLogMessageHandler);
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index b7f97b9..ccf092b7 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -289,9 +289,15 @@
   return base::FilePath();
 }
 
+bool ContentBrowserClient::AllowAppCacheOnIO(const GURL& manifest_url,
+                                             const GURL& first_party,
+                                             ResourceContext* context) {
+  return true;
+}
+
 bool ContentBrowserClient::AllowAppCache(const GURL& manifest_url,
                                          const GURL& first_party,
-                                         ResourceContext* context) {
+                                         BrowserContext* context) {
   return true;
 }
 
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 8da3e82..ba6f0ac 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -532,9 +532,13 @@
 
   // Allow the embedder to control if an AppCache can be used for the given url.
   // This is called on the IO thread.
+  virtual bool AllowAppCacheOnIO(const GURL& manifest_url,
+                                 const GURL& first_party,
+                                 ResourceContext* context);
+  // Same as above but called on UI thread.
   virtual bool AllowAppCache(const GURL& manifest_url,
                              const GURL& first_party,
-                             ResourceContext* context);
+                             BrowserContext* context);
 
   // Allows the embedder to control if a service worker is allowed at the given
   // |scope| and can be accessed from |first_party|. This function is called
diff --git a/content/public/browser/push_messaging_service.h b/content/public/browser/push_messaging_service.h
index 82d06de..a25408e 100644
--- a/content/public/browser/push_messaging_service.h
+++ b/content/public/browser/push_messaging_service.h
@@ -33,6 +33,7 @@
  public:
   using RegisterCallback =
       base::OnceCallback<void(const std::string& registration_id,
+                              const GURL& endpoint,
                               const std::vector<uint8_t>& p256dh,
                               const std::vector<uint8_t>& auth,
                               blink::mojom::PushRegistrationStatus status)>;
@@ -40,6 +41,7 @@
       base::OnceCallback<void(blink::mojom::PushUnregistrationStatus)>;
   using SubscriptionInfoCallback =
       base::Callback<void(bool is_valid,
+                          const GURL& endpoint,
                           const std::vector<uint8_t>& p256dh,
                           const std::vector<uint8_t>& auth)>;
   using StringCallback = base::Callback<void(const std::string& data,
@@ -48,11 +50,6 @@
 
   virtual ~PushMessagingService() {}
 
-  // Returns the absolute URL to the endpoint of the push service where messages
-  // should be posted to. Should return an endpoint compatible with the Web Push
-  // Protocol when |standard_protocol| is true.
-  virtual GURL GetEndpoint(bool standard_protocol) = 0;
-
   // Subscribes the given |options->sender_info| with the push messaging service
   // in a document context. The frame is known and a permission UI may be
   // displayed to the user. It's safe to call this method multiple times for
diff --git a/content/public/browser/storage_partition.h b/content/public/browser/storage_partition.h
index bff9f38..79a94d1 100644
--- a/content/public/browser/storage_partition.h
+++ b/content/public/browser/storage_partition.h
@@ -98,6 +98,8 @@
   // network process restarts.
   virtual scoped_refptr<network::SharedURLLoaderFactory>
   GetURLLoaderFactoryForBrowserProcess() = 0;
+  virtual scoped_refptr<network::SharedURLLoaderFactory>
+  GetURLLoaderFactoryForBrowserProcessWithCORBEnabled() = 0;
   virtual std::unique_ptr<network::SharedURLLoaderFactoryInfo>
   GetURLLoaderFactoryForBrowserProcessIOThread() = 0;
   virtual network::mojom::CookieManager*
diff --git a/content/public/test/hit_test_region_observer.cc b/content/public/test/hit_test_region_observer.cc
index 8f81ca1..c081030 100644
--- a/content/public/test/hit_test_region_observer.cc
+++ b/content/public/test/hit_test_region_observer.cc
@@ -23,25 +23,6 @@
 
 namespace content {
 
-namespace {
-
-// Returns a transform from root to |frame_sink_id|. If no HitTestQuery contains
-// |frame_sink_id| then this will return an empty optional.
-base::Optional<gfx::Transform> GetRootToTargetTransform(
-    const viz::FrameSinkId& frame_sink_id) {
-  for (auto& it : GetHostFrameSinkManager()->display_hit_test_query()) {
-    if (it.second->ContainsActiveFrameSinkId(frame_sink_id)) {
-      base::Optional<gfx::Transform> transform(base::in_place);
-      it.second->GetTransformToTarget(frame_sink_id, &transform.value());
-      return transform;
-    }
-  }
-
-  return base::nullopt;
-}
-
-}  // namespace
-
 void WaitForHitTestDataOrChildSurfaceReady(RenderFrameHost* child_frame) {
   RenderWidgetHostViewBase* child_view =
       static_cast<RenderFrameHostImpl*>(child_frame)
@@ -136,43 +117,4 @@
   return iter->second.get()->GetHitTestData();
 }
 
-HitTestTransformChangeObserver::HitTestTransformChangeObserver(
-    const viz::FrameSinkId& frame_sink_id)
-    : target_frame_sink_id_(frame_sink_id),
-      cached_transform_(GetRootToTargetTransform(frame_sink_id)) {
-  DCHECK(frame_sink_id.is_valid());
-}
-
-HitTestTransformChangeObserver::~HitTestTransformChangeObserver() = default;
-
-void HitTestTransformChangeObserver::WaitForTransformChangeInHitTestData() {
-  DCHECK(!run_loop_);
-
-  // If the transform has already changed then don't run RunLoop.
-  base::Optional<gfx::Transform> transform =
-      GetRootToTargetTransform(target_frame_sink_id_);
-  if (transform != cached_transform_) {
-    cached_transform_ = transform;
-    return;
-  }
-
-  GetHostFrameSinkManager()->AddHitTestRegionObserver(this);
-  run_loop_ = std::make_unique<base::RunLoop>();
-  run_loop_->Run();
-  run_loop_.reset();
-  GetHostFrameSinkManager()->RemoveHitTestRegionObserver(this);
-}
-
-void HitTestTransformChangeObserver::OnAggregatedHitTestRegionListUpdated(
-    const viz::FrameSinkId& frame_sink_id,
-    const std::vector<viz::AggregatedHitTestRegion>& hit_test_data) {
-  // Check if the transform has changed since it was cached.
-  base::Optional<gfx::Transform> transform =
-      GetRootToTargetTransform(target_frame_sink_id_);
-  if (transform != cached_transform_) {
-    cached_transform_ = transform;
-    run_loop_->Quit();
-  }
-}
-
 }  // namespace content
diff --git a/content/public/test/hit_test_region_observer.h b/content/public/test/hit_test_region_observer.h
index c73b409..ab168b42 100644
--- a/content/public/test/hit_test_region_observer.h
+++ b/content/public/test/hit_test_region_observer.h
@@ -65,33 +65,6 @@
   DISALLOW_COPY_AND_ASSIGN(HitTestRegionObserver);
 };
 
-// Test API which can wait until there is a transform change in hit test data
-// for a particular FrameSinkId. i.e. change in root to target transform.
-class HitTestTransformChangeObserver : public viz::HitTestRegionObserver {
- public:
-  explicit HitTestTransformChangeObserver(
-      const viz::FrameSinkId& frame_sink_id);
-  ~HitTestTransformChangeObserver() override;
-
-  // Waits until transform changes in hit testing data for |frame_sink_id_|. If
-  // hit test data for |frame_sink_id_| has already changed since it was cached
-  // then this will return immediately. The cached transform will be updated
-  // when this returns so it can be called later.
-  void WaitForTransformChangeInHitTestData();
-
- private:
-  // viz::HitTestRegionObserver:
-  void OnAggregatedHitTestRegionListUpdated(
-      const viz::FrameSinkId& frame_sink_id,
-      const std::vector<viz::AggregatedHitTestRegion>& hit_test_data) override;
-
-  const viz::FrameSinkId target_frame_sink_id_;
-  base::Optional<gfx::Transform> cached_transform_;
-  std::unique_ptr<base::RunLoop> run_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(HitTestTransformChangeObserver);
-};
-
 }  // namespace content
 
 #endif  // CONTENT_PUBLIC_TEST_HIT_TEST_REGION_OBSERVER_H_
diff --git a/content/public/test/test_storage_partition.cc b/content/public/test/test_storage_partition.cc
index aaabeeda..e8132ff 100644
--- a/content/public/test/test_storage_partition.cc
+++ b/content/public/test/test_storage_partition.cc
@@ -34,6 +34,11 @@
   return nullptr;
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+TestStoragePartition::GetURLLoaderFactoryForBrowserProcessWithCORBEnabled() {
+  return nullptr;
+}
+
 std::unique_ptr<network::SharedURLLoaderFactoryInfo>
 TestStoragePartition::GetURLLoaderFactoryForBrowserProcessIOThread() {
   return nullptr;
diff --git a/content/public/test/test_storage_partition.h b/content/public/test/test_storage_partition.h
index 32a03cae..bb938a385 100644
--- a/content/public/test/test_storage_partition.h
+++ b/content/public/test/test_storage_partition.h
@@ -62,6 +62,9 @@
   scoped_refptr<network::SharedURLLoaderFactory>
   GetURLLoaderFactoryForBrowserProcess() override;
 
+  scoped_refptr<network::SharedURLLoaderFactory>
+  GetURLLoaderFactoryForBrowserProcessWithCORBEnabled() override;
+
   std::unique_ptr<network::SharedURLLoaderFactoryInfo>
   GetURLLoaderFactoryForBrowserProcessIOThread() override;
 
diff --git a/content/renderer/media/stream/processed_local_audio_source.cc b/content/renderer/media/stream/processed_local_audio_source.cc
index 56a74de..1e41bd5 100644
--- a/content/renderer/media/stream/processed_local_audio_source.cc
+++ b/content/renderer/media/stream/processed_local_audio_source.cc
@@ -363,19 +363,16 @@
 }
 
 void ProcessedLocalAudioSource::Capture(const media::AudioBus* audio_bus,
-                                        int audio_delay_milliseconds,
+                                        base::TimeTicks audio_capture_time,
                                         double volume,
                                         bool key_pressed) {
   if (audio_processor_) {
     // The data must be processed here.
-    CaptureUsingProcessor(audio_bus, audio_delay_milliseconds, volume,
-                          key_pressed);
+    CaptureUsingProcessor(audio_bus, audio_capture_time, volume, key_pressed);
   } else {
     // The audio is already processed in the audio service, just send it along.
     level_calculator_.Calculate(*audio_bus, false);
-    DeliverDataToTracks(
-        *audio_bus, base::TimeTicks::Now() - base::TimeDelta::FromMilliseconds(
-                                                 audio_delay_milliseconds));
+    DeliverDataToTracks(*audio_bus, audio_capture_time);
   }
 }
 
@@ -404,7 +401,7 @@
 
 void ProcessedLocalAudioSource::CaptureUsingProcessor(
     const media::AudioBus* audio_bus,
-    int audio_delay_milliseconds,
+    base::TimeTicks audio_capture_time,
     double volume,
     bool key_pressed) {
 #if defined(OS_WIN) || defined(OS_MACOSX)
@@ -418,13 +415,8 @@
   DCHECK_LE(volume, 1.6);
 #endif
 
-  // TODO(miu): Plumbing is needed to determine the actual capture timestamp
-  // of the audio, instead of just snapshotting TimeTicks::Now(), for proper
-  // audio/video sync.  https://crbug.com/335335
-  const base::TimeTicks reference_clock_snapshot = base::TimeTicks::Now();
-  TRACE_EVENT2("audio", "ProcessedLocalAudioSource::Capture", "now (ms)",
-               (reference_clock_snapshot - base::TimeTicks()).InMillisecondsF(),
-               "delay (ms)", audio_delay_milliseconds);
+  TRACE_EVENT1("audio", "ProcessedLocalAudioSource::Capture", "capture-time",
+               audio_capture_time);
 
   // Map internal volume range of [0.0, 1.0] into [0, 255] used by AGC.
   // The volume can be higher than 255 on Linux, and it will be cropped to
@@ -453,8 +445,7 @@
 
   // Push the data to the processor for processing.
   audio_processor_->PushCaptureData(
-      *audio_bus,
-      base::TimeDelta::FromMilliseconds(audio_delay_milliseconds));
+      *audio_bus, base::TimeTicks::Now() - audio_capture_time);
 
   // Process and consume the data in the processor until there is not enough
   // data in the processor.
@@ -468,8 +459,7 @@
 
     level_calculator_.Calculate(*processed_data, force_report_nonzero_energy);
 
-    DeliverDataToTracks(*processed_data,
-                        reference_clock_snapshot - processed_data_audio_delay);
+    DeliverDataToTracks(*processed_data, audio_capture_time);
 
     if (new_volume) {
       GetTaskRunner()->PostTask(
diff --git a/content/renderer/media/stream/processed_local_audio_source.h b/content/renderer/media/stream/processed_local_audio_source.h
index 09ba7de1..3ee16e6 100644
--- a/content/renderer/media/stream/processed_local_audio_source.h
+++ b/content/renderer/media/stream/processed_local_audio_source.h
@@ -105,7 +105,7 @@
   // Called on the AudioCapturerSource audio thread.
   void OnCaptureStarted() override;
   void Capture(const media::AudioBus* audio_source,
-               int audio_delay_milliseconds,
+               base::TimeTicks audio_capture_time,
                double volume,
                bool key_pressed) override;
   void OnCaptureError(const std::string& message) override;
@@ -116,7 +116,7 @@
  private:
   // Runs the audio through |audio_processor_| before sending it along.
   void CaptureUsingProcessor(const media::AudioBus* audio_source,
-                             int audio_delay_milliseconds,
+                             base::TimeTicks audio_capture_time,
                              double volume,
                              bool key_pressed);
 
diff --git a/content/renderer/media/stream/processed_local_audio_source_unittest.cc b/content/renderer/media/stream/processed_local_audio_source_unittest.cc
index 66c52b6..519c16e 100644
--- a/content/renderer/media/stream/processed_local_audio_source_unittest.cc
+++ b/content/renderer/media/stream/processed_local_audio_source_unittest.cc
@@ -192,11 +192,13 @@
   int delay_ms = 65;
   bool key_pressed = true;
   double volume = 0.9;
+  const base::TimeTicks capture_time =
+      base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(delay_ms);
   std::unique_ptr<media::AudioBus> audio_bus =
       media::AudioBus::Create(2, kExpectedSourceBufferSize);
   audio_bus->Zero();
   EXPECT_CALL(*sink, OnDataCallback()).Times(AtLeast(1));
-  capture_source_callback()->Capture(audio_bus.get(), delay_ms, volume,
+  capture_source_callback()->Capture(audio_bus.get(), capture_time, volume,
                                      key_pressed);
 
   // Expect the ProcessedLocalAudioSource to auto-stop the MockCapturerSource
diff --git a/content/shell/browser/web_test/web_test_push_messaging_service.cc b/content/shell/browser/web_test/web_test_push_messaging_service.cc
index 12bec8f..b33e05a 100644
--- a/content/shell/browser/web_test/web_test_push_messaging_service.cc
+++ b/content/shell/browser/web_test/web_test_push_messaging_service.cc
@@ -47,11 +47,6 @@
 
 WebTestPushMessagingService::~WebTestPushMessagingService() {}
 
-GURL WebTestPushMessagingService::GetEndpoint(bool standard_protocol) {
-  return GURL(standard_protocol ? "https://example.com/StandardizedEndpoint/"
-                                : "https://example.com/LayoutTestEndpoint/");
-}
-
 void WebTestPushMessagingService::SubscribeFromDocument(
     const GURL& requesting_origin,
     int64_t service_worker_registration_id,
@@ -86,14 +81,17 @@
     std::vector<uint8_t> auth(kAuthentication,
                               kAuthentication + base::size(kAuthentication));
 
+    const std::string subscription_id = "layoutTestRegistrationId";
+    const GURL endpoint = CreateEndpoint(subscription_id);
+
     subscribed_service_worker_registration_ = service_worker_registration_id;
     std::move(callback).Run(
-        "layoutTestRegistrationId", p256dh, auth,
+        subscription_id, endpoint, p256dh, auth,
         blink::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE);
   } else {
     std::move(callback).Run(
-        "registration_id", std::vector<uint8_t>() /* p256dh */,
-        std::vector<uint8_t>() /* auth */,
+        "registration_id", GURL::EmptyGURL() /* endpoint */,
+        std::vector<uint8_t>() /* p256dh */, std::vector<uint8_t>() /* auth */,
         blink::mojom::PushRegistrationStatus::PERMISSION_DENIED);
   }
 }
@@ -109,7 +107,8 @@
   std::vector<uint8_t> auth(kAuthentication,
                             kAuthentication + base::size(kAuthentication));
 
-  callback.Run(true /* is_valid */, p256dh, auth);
+  const GURL endpoint = CreateEndpoint(subscription_id);
+  callback.Run(true /* is_valid */, endpoint, p256dh, auth);
 }
 
 bool WebTestPushMessagingService::SupportNonVisibleMessages() {
@@ -154,4 +153,9 @@
       blink::mojom::kInvalidServiceWorkerRegistrationId;
 }
 
+GURL WebTestPushMessagingService::CreateEndpoint(
+    const std::string& subscription_id) const {
+  return GURL("https://example.com/StandardizedEndpoint/" + subscription_id);
+}
+
 }  // namespace content
diff --git a/content/shell/browser/web_test/web_test_push_messaging_service.h b/content/shell/browser/web_test/web_test_push_messaging_service.h
index 2c2baca..6988df08 100644
--- a/content/shell/browser/web_test/web_test_push_messaging_service.h
+++ b/content/shell/browser/web_test/web_test_push_messaging_service.h
@@ -22,7 +22,6 @@
   ~WebTestPushMessagingService() override;
 
   // PushMessagingService implementation:
-  GURL GetEndpoint(bool standard_protocol) override;
   void SubscribeFromDocument(const GURL& requesting_origin,
                              int64_t service_worker_registration_id,
                              int renderer_id,
@@ -51,6 +50,8 @@
   void DidDeleteServiceWorkerDatabase() override;
 
  private:
+  GURL CreateEndpoint(const std::string& subscription_id) const;
+
   int64_t subscribed_service_worker_registration_;
 
   DISALLOW_COPY_AND_ASSIGN(WebTestPushMessagingService);
diff --git a/content/test/data/gpu/pixel_video_context_loss.html b/content/test/data/gpu/pixel_video_context_loss.html
index 4bd294d..92e2b0f5 100644
--- a/content/test/data/gpu/pixel_video_context_loss.html
+++ b/content/test/data/gpu/pixel_video_context_loss.html
@@ -8,6 +8,7 @@
 
 <html>
 <head>
+<meta name="viewport" content="initial-scale=1">
 <title>Video Context Loss Test</title>
 <style type="text/css">
 .nomargin {
diff --git a/content/test/data/gpu/pixel_video_mp4.html b/content/test/data/gpu/pixel_video_mp4.html
index fd842a2..574158f3 100644
--- a/content/test/data/gpu/pixel_video_mp4.html
+++ b/content/test/data/gpu/pixel_video_mp4.html
@@ -8,6 +8,7 @@
 
 <html>
 <head>
+<meta name="viewport" content="initial-scale=1">
 <title>MP4 Video test</title>
 <style type="text/css">
 .nomargin {
diff --git a/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html b/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html
index cc624f6..4cba526bb 100644
--- a/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html
+++ b/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html
@@ -8,6 +8,7 @@
 
 <html>
 <head>
+<meta name="viewport" content="initial-scale=1">
 <title>MP4 Video with Aspect 4x3 Test</title>
 <style type="text/css">
 .nomargin {
diff --git a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html
index 37a0f97..eadd247 100644
--- a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html
+++ b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html
@@ -8,6 +8,7 @@
 
 <html>
 <head>
+<meta name="viewport" content="initial-scale=1">
 <title>MP4 Video with 180 Degree Rotation Test</title>
 <style type="text/css">
 .nomargin {
diff --git a/content/test/data/gpu/pixel_video_vp9.html b/content/test/data/gpu/pixel_video_vp9.html
index c08aca2..922ddc9 100644
--- a/content/test/data/gpu/pixel_video_vp9.html
+++ b/content/test/data/gpu/pixel_video_vp9.html
@@ -8,6 +8,7 @@
 
 <html>
 <head>
+<meta name="viewport" content="initial-scale=1">
 <title>VP9 Video test</title>
 <style type="text/css">
 .nomargin {
diff --git a/content/test/fuzzer/fuzzer_support.cc b/content/test/fuzzer/fuzzer_support.cc
index 3224eb0..24cbf73 100644
--- a/content/test/fuzzer/fuzzer_support.cc
+++ b/content/test/fuzzer/fuzzer_support.cc
@@ -28,6 +28,7 @@
 
 void RenderViewTestAdapter::SetUp() {
   RenderViewTest::SetUp();
+  CreateFakeWebURLLoaderFactory();
 }
 
 Env::Env() {
diff --git a/content/test/fuzzer/fuzzer_support.h b/content/test/fuzzer/fuzzer_support.h
index 978a509..fbca508 100644
--- a/content/test/fuzzer/fuzzer_support.h
+++ b/content/test/fuzzer/fuzzer_support.h
@@ -26,6 +26,8 @@
     RenderViewTest::LoadHTMLWithUrlOverride(html.c_str(), url.c_str());
   }
 
+  using RenderViewTest::GetMainFrame;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(RenderViewTestAdapter);
 };
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index 007baf04..3549a78b 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import sys
-
 _FOUR_COLOR_VIDEO_240x135_EXPECTED_COLORS = [
   {
     'comment': 'top left video, yellow',
@@ -132,13 +130,13 @@
   def DefaultPages(base_name):
     sw_compositing_args = ['--disable-gpu-compositing']
 
-    tolerance = 3
-    tolerance_vp9 = 5 # VP9 video requires larger tolerance
-    if sys.platform == 'darwin':
-      # On MacOSX, pixels are slightly off.
-      # https://crbug.com/911895
-      tolerance = 10
-      tolerance_vp9 = 20
+    # Tolerance of 10% is required for all the formats to match gold/pixel
+    # expectations on all the platforms for pixel video tests. Hence setting it
+    # to 20.
+    # Bug filed on MacOSX to investigate the tolerance -
+    # https://crbug.com/911895.
+    tolerance = 20
+    tolerance_vp9 = 20
 
     return [
       PixelTestPage(
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index ff3023f..29c65c2 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -66,10 +66,6 @@
 # expectation below is removed.
 # crbug.com/575305  [ android-webview-instrumentation ] Pixel_WebGLSadCanvas [ Skip ]
 
-# Uncomment this when crbug.com/925744 is fixed and conflicting
-# expectation below is removed.
-# crbug.com/925744  [ android-webview-instrumentation ] Pixel_Video_Context_Loss_VP9 [ Skip ]
-
 crbug.com/521588 [ android ] Pixel_ScissorTestWithPreserveDrawingBuffer [ Failure ]
 
 # TODO(vmiura) check / generate reference images for Android devices
@@ -151,13 +147,8 @@
 crbug.com/927107 [ android no-skia-renderer ] Pixel_CSS3DBlueBox [ Failure ]
 
 # Fail on Nexus 5, 5X, 6, 6P, 9 and Shield TV.
-crbug.com/925744 [ android ] Pixel_Video_MP4 [ Skip ]
-crbug.com/925744 [ android ] Pixel_Video_MP4_FourColors_Aspect_4x3 [ Skip ]
-crbug.com/925744 [ android ] Pixel_Video_MP4_FourColors_Rot_180 [ Skip ]
 crbug.com/925744 [ android ] Pixel_Video_MP4_FourColors_Rot_270 [ Skip ]
 crbug.com/925744 [ android ] Pixel_Video_MP4_FourColors_Rot_90 [ Skip ]
-crbug.com/925744 [ android ] Pixel_Video_VP9 [ Skip ]
-crbug.com/925744 [ android ] Pixel_Video_Context_Loss_VP9 [ Skip ]
 
 # Skip on platforms where DXVA vs D3D11 decoder doesn't matter.
 crbug.com/927901 [ linux ] Pixel_Video_MP4_DXVA [ Skip ]
@@ -175,6 +166,12 @@
 # Mark all webview tests as RetryOnFailure due to Nexus 5x driver bug.
 crbug.com/950932 [ android-webview-instrumentation qualcomm-adreno-(tm)-418 ] * [ RetryOnFailure ]
 
+# Mark 1 webview test as Failure. This test is failing instead of flaking. It
+# might have the same Nexus 5x driver bug as crbug.com/950932 but that
+# should have made this test flaky instead of always failing. Need to
+# investigate later. Filed a bug to track the debug.
+crbug.com/984734 [ android-webview-instrumentation qualcomm-adreno-(tm)-418 ] Pixel_Video_Context_Loss_VP9 [ Failure ]
+
 # Producing black images on Nexus 5Xs in Android Webview.
 crbug.com/984352 [ android android-webview-instrumentation qualcomm-adreno-(tm)-418 ] Pixel_CanvasLowLatency2D [ Failure ]
 
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index d5a1933..70d517f3 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -553,7 +553,6 @@
 
 # Misc failures
 crbug.com/angleproject/2988 [ android opengles ] conformance/context/context-size-change.html [ Failure ]
-crbug.com/angleproject/1552 [ android opengles ] WebglExtension_WEBGL_compressed_texture_etc1 [ Failure ]
 
 ############
 # ChromeOS #
diff --git a/device/fido/fido_device.cc b/device/fido/fido_device.cc
index ff4dc54..1016d43 100644
--- a/device/fido/fido_device.cc
+++ b/device/fido/fido_device.cc
@@ -24,14 +24,17 @@
 }
 
 bool FidoDevice::IsInPairingMode() const {
+  NOTREACHED();
   return false;
 }
 
 bool FidoDevice::IsPaired() const {
+  NOTREACHED();
   return false;
 }
 
 bool FidoDevice::RequiresBlePairingPin() const {
+  NOTREACHED();
   return true;
 }
 
diff --git a/device/fido/fido_device.h b/device/fido/fido_device.h
index 85d9a69..e828410 100644
--- a/device/fido/fido_device.h
+++ b/device/fido/fido_device.h
@@ -77,11 +77,13 @@
   virtual std::string GetId() const = 0;
   virtual base::string16 GetDisplayName() const;
   virtual FidoTransportProtocol DeviceTransport() const = 0;
+
+  // These must only be called on Bluetooth devices.
   virtual bool IsInPairingMode() const;
   virtual bool IsPaired() const;
 
-  // Returns false for FIDO Bluetooth devices that do not have the service bit
-  // set to require a PIN or passkey to pair. Returns true otherwise.
+  // Returns whether the service bit is set to require a PIN or passkey to pair
+  // for a FIDO Bluetooth device.
   virtual bool RequiresBlePairingPin() const;
 
   virtual base::WeakPtr<FidoDevice> GetWeakPtr() = 0;
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index ce883992..4187e85 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1422,6 +1422,7 @@
   ACTION_GETBADGEBACKGROUNDCOLOR = 1359,
   ACTION_SETBADGEBACKGROUNDCOLOR = 1360,
   AUTOTESTPRIVATE_SETARCAPPWINDOWSTATE = 1361,
+  ACCESSIBILITY_PRIVATE_OPENSETTINGSSUBPAGE = 1362,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 6895f25..7ca5cc52 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -1035,14 +1035,9 @@
     validators_.g_l_state.AddValue(GL_TEXTURE_BINDING_EXTERNAL_OES);
   }
 
-  // When running on top of ANGLE, also require the
-  // GL_CHROMIUM_compressed_texture_etc exentsion to expose
-  // GL_OES_compressed_ETC1_RGB8_texture. There is no query for native support
-  // of this texture format so assume that if ANGLE natively supports ETC2, ETC1
-  // is also supported.
-  if (gfx::HasExtension(extensions, "GL_OES_compressed_ETC1_RGB8_texture") &&
-      (!gl_version_info_->is_angle ||
-       gfx::HasExtension(extensions, "GL_CHROMIUM_compressed_texture_etc"))) {
+  // ANGLE only exposes this extension when it has native support of the
+  // GL_ETC1_RGB8 format.
+  if (gfx::HasExtension(extensions, "GL_OES_compressed_ETC1_RGB8_texture")) {
     AddExtensionString("GL_OES_compressed_ETC1_RGB8_texture");
     feature_flags_.oes_compressed_etc1_rgb8_texture = true;
     validators_.compressed_texture_format.AddValue(GL_ETC1_RGB8_OES);
diff --git a/ios/chrome/browser/web/font_size_js_unittest.mm b/ios/chrome/browser/web/font_size_js_unittest.mm
index a87caa3..fa8d8e57 100644
--- a/ios/chrome/browser/web/font_size_js_unittest.mm
+++ b/ios/chrome/browser/web/font_size_js_unittest.mm
@@ -5,6 +5,7 @@
 #import <Foundation/Foundation.h>
 #include <stddef.h>
 
+#include "base/ios/ios_util.h"
 #include "base/macros.h"
 #import "ios/web/public/test/web_js_test.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
@@ -57,6 +58,15 @@
 
 // Tests that __gCrWeb.accessibility.adjustFontSize works for any scale.
 TEST_F(FontSizeJsTest, TestAdjustFontSizeForScale) {
+  // TODO(crbug.com/983776): This test fails when compiled with Xcode 10 and
+  // running on iOS 13 because expected font size and actual font size don't
+  // match. Re-enable this test when Xcode 11 is used for compiling.
+#if !defined(__IPHONE_13_0) || (__IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_13_0)
+  if (base::ios::IsRunningOnIOS13OrLater()) {
+    return;
+  }
+#endif
+
   float original_size = 0;
   float current_size = 0;
 
@@ -171,6 +181,15 @@
 
 // Tests that __gCrWeb.accessibility.adjustFontSize works for any CSS unit.
 TEST_F(FontSizeJsTest, TestAdjustFontSizeForUnit) {
+  // TODO(crbug.com/983776): This test fails when compiled with Xcode 10 and
+  // running on iOS 13 because expected font size and actual font size don't
+  // match. Re-enable this test when Xcode 11 is used for compiling.
+#if !defined(__IPHONE_13_0) || (__IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_13_0)
+  if (base::ios::IsRunningOnIOS13OrLater()) {
+    return;
+  }
+#endif
+
   float original_size = 0;
   float current_size = 0;
 
@@ -237,6 +256,15 @@
 
 // Tests that __gCrWeb.accessibility.adjustFontSize works for nested elements.
 TEST_F(FontSizeJsTest, TestAdjustFontSizeForNestedElements) {
+  // TODO(crbug.com/983776): This test fails when compiled with Xcode 10 and
+  // running on iOS 13 because expected font size and actual font size don't
+  // match. Re-enable this test when Xcode 11 is used for compiling.
+#if !defined(__IPHONE_13_0) || (__IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_13_0)
+  if (base::ios::IsRunningOnIOS13OrLater()) {
+    return;
+  }
+#endif
+
   float original_size_1 = 0;
   float original_size_2 = 0;
   float current_size_1 = 0;
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc
index f2ed25e..1deb93a 100644
--- a/media/audio/audio_input_device.cc
+++ b/media/audio/audio_input_device.cc
@@ -460,9 +460,8 @@
   const base::TimeTicks now_time = base::TimeTicks::Now();
   DCHECK_GE(now_time, capture_time);
 
-  capture_callback_->Capture(audio_bus,
-                             (now_time - capture_time).InMilliseconds(),
-                             buffer->params.volume, buffer->params.key_pressed);
+  capture_callback_->Capture(audio_bus, capture_time, buffer->params.volume,
+                             buffer->params.key_pressed);
 
   if (++current_segment_id_ >= total_segments_)
     current_segment_id_ = 0u;
diff --git a/media/audio/audio_input_device_unittest.cc b/media/audio/audio_input_device_unittest.cc
index 59104cb..01fa2ad 100644
--- a/media/audio/audio_input_device_unittest.cc
+++ b/media/audio/audio_input_device_unittest.cc
@@ -55,7 +55,7 @@
   MOCK_METHOD0(OnCaptureStarted, void());
   MOCK_METHOD4(Capture,
                void(const AudioBus* audio_source,
-                    int audio_delay_milliseconds,
+                    base::TimeTicks audio_capture_time,
                     double volume,
                     bool key_pressed));
 
diff --git a/media/base/audio_capturer_source.h b/media/base/audio_capturer_source.h
index 1b9661a..ca91a598 100644
--- a/media/base/audio_capturer_source.h
+++ b/media/base/audio_capturer_source.h
@@ -7,6 +7,7 @@
 
 #include <string>
 #include <vector>
+
 #include "base/memory/ref_counted.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_parameters.h"
@@ -33,10 +34,8 @@
     virtual void OnCaptureStarted() {}
 
     // Callback to deliver the captured data from the OS.
-    // TODO(chcunningham): Update delay argument to use base::TimeDelta instead
-    // of milliseconds to prevent precision loss. See http://crbug.com/587291.
     virtual void Capture(const AudioBus* audio_source,
-                         int audio_delay_milliseconds,
+                         base::TimeTicks audio_capture_time,
                          double volume,
                          bool key_pressed) = 0;
 
diff --git a/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc b/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc
index 8392596..397f7e2 100644
--- a/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc
+++ b/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc
@@ -148,7 +148,7 @@
                            const scoped_refptr<gl::GLImage>& image,
                            bool can_bind_to_sampler) { return true; })),
         decoder_thread_("VaapiVideoDecodeAcceleratorTestThread"),
-        mock_decoder_(new MockAcceleratedVideoDecoder),
+        mock_decoder_(new ::testing::StrictMock<MockAcceleratedVideoDecoder>),
         mock_vaapi_picture_factory_(new MockVaapiPictureFactory()),
         mock_vaapi_wrapper_(new MockVaapiWrapper()),
         mock_vpp_vaapi_wrapper_(new MockVaapiWrapper()),
@@ -232,6 +232,8 @@
     const size_t kNumReferenceFrames = num_pictures / 2;
     EXPECT_CALL(*mock_decoder_, GetNumReferenceFrames())
         .WillOnce(Return(kNumReferenceFrames));
+    EXPECT_CALL(*mock_decoder_, GetVisibleRect())
+        .WillOnce(Return(gfx::Rect(picture_size)));
     if (vda_.buffer_allocation_mode_ !=
         VaapiVideoDecodeAccelerator::BufferAllocationMode::kNone) {
       EXPECT_CALL(*mock_vaapi_wrapper_, DestroyContextAndSurfaces(_));
diff --git a/net/base/network_isolation_key.cc b/net/base/network_isolation_key.cc
index 39202a82..ffcca034 100644
--- a/net/base/network_isolation_key.cc
+++ b/net/base/network_isolation_key.cc
@@ -17,7 +17,7 @@
 }  // namespace
 
 NetworkIsolationKey::NetworkIsolationKey(
-    const base::Optional<url::Origin>& top_frame_origin,
+    const url::Origin& top_frame_origin,
     const base::Optional<url::Origin>& frame_origin)
     : use_frame_origin_(base::FeatureList::IsEnabled(
           net::features::kAppendFrameOriginToNetworkIsolationKey)),
diff --git a/net/base/network_isolation_key.h b/net/base/network_isolation_key.h
index 92931b0..d4c1d586 100644
--- a/net/base/network_isolation_key.h
+++ b/net/base/network_isolation_key.h
@@ -21,9 +21,9 @@
   // Full constructor.  When a request is initiated by the top frame, it must
   // also populate the |frame_origin| parameter when calling this constructor.
   explicit NetworkIsolationKey(
-      // TODO(crbug.com/950069): Make the arguments non-optional once all call
-      // sites are updated to include the frame_origin.
-      const base::Optional<url::Origin>& top_frame_origin,
+      // TODO(crbug.com/950069): Make the frame_origin argument non-optional
+      // once all call sites are updated to include the frame_origin.
+      const url::Origin& top_frame_origin,
       const base::Optional<url::Origin>& frame_origin = base::nullopt);
 
   // Construct an empty key.
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index 190a2bc..7962b68 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -358,7 +358,12 @@
   HttpRequestInfo request_info;
   request_info.url = url;
   request_info.method = http_method;
-  request_info.network_isolation_key = NetworkIsolationKey(top_frame_origin);
+
+  if (top_frame_origin.has_value()) {
+    request_info.network_isolation_key =
+        NetworkIsolationKey(top_frame_origin.value());
+  }
+
   std::string key = GenerateCacheKey(&request_info);
   disk_cache_->OnExternalCacheHit(key);
 }
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 88c1f52..e207a97 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -279,9 +279,9 @@
   dict->SetInteger("max_server_configs_stored_in_properties",
                    params_.quic_params.max_server_configs_stored_in_properties);
   dict->SetInteger("idle_connection_timeout_seconds",
-                   params_.quic_params.idle_connection_timeout_seconds);
+                   params_.quic_params.idle_connection_timeout.InSeconds());
   dict->SetInteger("reduced_ping_timeout_seconds",
-                   params_.quic_params.reduced_ping_timeout_seconds);
+                   params_.quic_params.reduced_ping_timeout.InSeconds());
   dict->SetBoolean(
       "mark_quic_broken_when_network_blackholes",
       params_.quic_params.mark_quic_broken_when_network_blackholes);
@@ -301,7 +301,7 @@
                    params_.quic_params.migrate_sessions_early_v2);
   dict->SetInteger(
       "retransmittable_on_wire_timeout_milliseconds",
-      params_.quic_params.retransmittable_on_wire_timeout_milliseconds);
+      params_.quic_params.retransmittable_on_wire_timeout.InMilliseconds());
   dict->SetBoolean(
       "retry_on_alternate_network_before_handshake",
       params_.quic_params.retry_on_alternate_network_before_handshake);
@@ -330,8 +330,9 @@
                    params_.quic_params.estimate_initial_rtt);
   dict->SetBoolean("server_push_cancellation",
                    params_.enable_server_push_cancellation);
-  dict->SetInteger("initial_rtt_for_handshake_milliseconds",
-                   params_.quic_params.initial_rtt_for_handshake_milliseconds);
+  dict->SetInteger(
+      "initial_rtt_for_handshake_milliseconds",
+      params_.quic_params.initial_rtt_for_handshake.InMilliseconds());
 
   return std::move(dict);
 }
diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc
index 6143499..6a9e13d 100644
--- a/net/quic/bidirectional_stream_quic_impl_unittest.cc
+++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc
@@ -522,10 +522,9 @@
         /*migrate_session_on_network_change_v2=*/false,
         /*default_network=*/NetworkChangeNotifier::kInvalidNetworkHandle,
         quic::QuicTime::Delta::FromMilliseconds(
-            kDefaultRetransmittableOnWireTimeoutMillisecs),
-        /*migrate_idle_session=*/false,
-        base::TimeDelta::FromSeconds(kDefaultIdleSessionMigrationPeriodSeconds),
-        base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
+            kDefaultRetransmittableOnWireTimeout.InMilliseconds()),
+        /*migrate_idle_session=*/false, kDefaultIdleSessionMigrationPeriod,
+        kMaxTimeOnNonDefaultNetwork,
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
         kMaxMigrationsToNonDefaultNetworkOnPathDegrading,
         kQuicYieldAfterPacketsRead,
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc
index f87bc19..3d0ac35 100644
--- a/net/quic/quic_chromium_client_session_test.cc
+++ b/net/quic/quic_chromium_client_session_test.cc
@@ -154,10 +154,9 @@
         /*migrate_session_on_network_change_v2=*/false,
         /*defaulet_network=*/NetworkChangeNotifier::kInvalidNetworkHandle,
         quic::QuicTime::Delta::FromMilliseconds(
-            kDefaultRetransmittableOnWireTimeoutMillisecs),
-        /*migrate_idle_session=*/false,
-        base::TimeDelta::FromSeconds(kDefaultIdleSessionMigrationPeriodSeconds),
-        base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
+            kDefaultRetransmittableOnWireTimeout.InMilliseconds()),
+        /*migrate_idle_session=*/false, kDefaultIdleSessionMigrationPeriod,
+        kMaxTimeOnNonDefaultNetwork,
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
         kMaxMigrationsToNonDefaultNetworkOnPathDegrading,
         kQuicYieldAfterPacketsRead,
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 0c0ba6c..298cae2 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -330,10 +330,9 @@
         /*migrate_session_on_network_change_v2=*/false,
         /*default_network=*/NetworkChangeNotifier::kInvalidNetworkHandle,
         quic::QuicTime::Delta::FromMilliseconds(
-            kDefaultRetransmittableOnWireTimeoutMillisecs),
-        /*migrate_idle_session=*/false,
-        base::TimeDelta::FromSeconds(kDefaultIdleSessionMigrationPeriodSeconds),
-        base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
+            kDefaultRetransmittableOnWireTimeout.InMilliseconds()),
+        /*migrate_idle_session=*/false, kDefaultIdleSessionMigrationPeriod,
+        kMaxTimeOnNonDefaultNetwork,
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
         kMaxMigrationsToNonDefaultNetworkOnPathDegrading,
         kQuicYieldAfterPacketsRead,
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 04e3b04..7c27d08 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -2554,7 +2554,8 @@
 // return QUIC_PROTOCOL_ERROR.
 TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmed) {
   session_params_.quic_params.retry_without_alt_svc_on_quic_errors = false;
-  session_params_.quic_params.idle_connection_timeout_seconds = 5;
+  session_params_.quic_params.idle_connection_timeout =
+      base::TimeDelta::FromSeconds(5);
 
   // The request will initially go out over QUIC.
   MockQuicData quic_data(version_);
@@ -3001,7 +3002,8 @@
 // retried over TCP.
 TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken) {
   session_params_.quic_params.mark_quic_broken_when_network_blackholes = true;
-  session_params_.quic_params.idle_connection_timeout_seconds = 5;
+  session_params_.quic_params.idle_connection_timeout =
+      base::TimeDelta::FromSeconds(5);
 
   // The request will initially go out over QUIC.
   MockQuicData quic_data(version_);
@@ -3139,7 +3141,8 @@
 // connection times out, then QUIC will be marked as broken and the request
 // retried over TCP.
 TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken2) {
-  session_params_.quic_params.idle_connection_timeout_seconds = 5;
+  session_params_.quic_params.idle_connection_timeout =
+      base::TimeDelta::FromSeconds(5);
 
   // The request will initially go out over QUIC.
   MockQuicData quic_data(version_);
@@ -3281,7 +3284,8 @@
 TEST_P(QuicNetworkTransactionTest,
        TimeoutAfterHandshakeConfirmedAndHeadersThenBrokenNotRetried) {
   session_params_.quic_params.mark_quic_broken_when_network_blackholes = true;
-  session_params_.quic_params.idle_connection_timeout_seconds = 5;
+  session_params_.quic_params.idle_connection_timeout =
+      base::TimeDelta::FromSeconds(5);
 
   // The request will initially go out over QUIC.
   MockQuicData quic_data(version_);
@@ -3721,7 +3725,8 @@
 // retried over TCP and the QUIC will be marked as broken.
 TEST_P(QuicNetworkTransactionTest,
        ProtocolErrorAfterHandshakeConfirmedThenBroken) {
-  session_params_.quic_params.idle_connection_timeout_seconds = 5;
+  session_params_.quic_params.idle_connection_timeout =
+      base::TimeDelta::FromSeconds(5);
 
   // The request will initially go out over QUIC.
   MockQuicData quic_data(version_);
diff --git a/net/quic/quic_proxy_client_socket_unittest.cc b/net/quic/quic_proxy_client_socket_unittest.cc
index c8d235fb..93bf9b3 100644
--- a/net/quic/quic_proxy_client_socket_unittest.cc
+++ b/net/quic/quic_proxy_client_socket_unittest.cc
@@ -224,10 +224,9 @@
         /*migrate_session_on_network_change_v2=*/false,
         /*default_network=*/NetworkChangeNotifier::kInvalidNetworkHandle,
         quic::QuicTime::Delta::FromMilliseconds(
-            kDefaultRetransmittableOnWireTimeoutMillisecs),
-        /*migrate_idle_session=*/true,
-        base::TimeDelta::FromSeconds(kDefaultIdleSessionMigrationPeriodSeconds),
-        base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
+            kDefaultRetransmittableOnWireTimeout.InMilliseconds()),
+        /*migrate_idle_session=*/true, kDefaultIdleSessionMigrationPeriod,
+        kMaxTimeOnNonDefaultNetwork,
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
         kMaxMigrationsToNonDefaultNetworkOnPathDegrading,
         kQuicYieldAfterPacketsRead,
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 7be8413..633d3a30d 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -180,20 +180,21 @@
 quic::QuicConfig InitializeQuicConfig(
     const quic::QuicTagVector& connection_options,
     const quic::QuicTagVector& client_connection_options,
-    int idle_connection_timeout_seconds,
-    int max_time_before_crypto_handshake_seconds,
-    int max_idle_time_before_crypto_handshake_seconds) {
-  DCHECK_GT(idle_connection_timeout_seconds, 0);
+    base::TimeDelta idle_connection_timeout,
+    base::TimeDelta max_time_before_crypto_handshake,
+    base::TimeDelta max_idle_time_before_crypto_handshake) {
+  DCHECK_GT(idle_connection_timeout, base::TimeDelta());
   quic::QuicConfig config;
-  config.SetIdleNetworkTimeout(
-      quic::QuicTime::Delta::FromSeconds(idle_connection_timeout_seconds),
-      quic::QuicTime::Delta::FromSeconds(idle_connection_timeout_seconds));
+  config.SetIdleNetworkTimeout(quic::QuicTime::Delta::FromMicroseconds(
+                                   idle_connection_timeout.InMicroseconds()),
+                               quic::QuicTime::Delta::FromMicroseconds(
+                                   idle_connection_timeout.InMicroseconds()));
   config.set_max_time_before_crypto_handshake(
-      quic::QuicTime::Delta::FromSeconds(
-          max_time_before_crypto_handshake_seconds));
+      quic::QuicTime::Delta::FromMicroseconds(
+          max_time_before_crypto_handshake.InMicroseconds()));
   config.set_max_idle_time_before_crypto_handshake(
-      quic::QuicTime::Delta::FromSeconds(
-          max_idle_time_before_crypto_handshake_seconds));
+      quic::QuicTime::Delta::FromMicroseconds(
+          max_idle_time_before_crypto_handshake.InMicroseconds()));
   config.SetConnectionOptionsToSend(connection_options);
   config.SetClientConnectionOptions(client_connection_options);
   return config;
@@ -227,41 +228,12 @@
 
 QuicParams::QuicParams()
     : max_packet_length(quic::kDefaultMaxPacketSize),
-      max_server_configs_stored_in_properties(0u),
-      enable_socket_recv_optimization(false),
-      mark_quic_broken_when_network_blackholes(false),
-      retry_without_alt_svc_on_quic_errors(true),
-      support_ietf_format_quic_altsvc(false),
-      close_sessions_on_ip_change(false),
-      goaway_sessions_on_ip_change(false),
-      idle_connection_timeout_seconds(kIdleConnectionTimeoutSeconds),
-      reduced_ping_timeout_seconds(quic::kPingTimeoutSecs),
-      retransmittable_on_wire_timeout_milliseconds(0),
-      max_time_before_crypto_handshake_seconds(
-          quic::kMaxTimeForCryptoHandshakeSecs),
-      max_idle_time_before_crypto_handshake_seconds(
-          quic::kInitialIdleTimeoutSecs),
-      migrate_sessions_on_network_change_v2(false),
-      migrate_sessions_early_v2(false),
-      retry_on_alternate_network_before_handshake(false),
-      migrate_idle_sessions(false),
-      idle_session_migration_period(base::TimeDelta::FromSeconds(
-          kDefaultIdleSessionMigrationPeriodSeconds)),
-      max_time_on_non_default_network(
-          base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs)),
-      max_migrations_to_non_default_network_on_write_error(
-          kMaxMigrationsToNonDefaultNetworkOnWriteError),
-      max_migrations_to_non_default_network_on_path_degrading(
-          kMaxMigrationsToNonDefaultNetworkOnPathDegrading),
-      allow_server_migration(false),
-      allow_remote_alt_svc(true),
-      race_stale_dns_on_connection(false),
-      go_away_on_path_degrading(false),
-      disable_bidirectional_streams(false),
-      race_cert_verification(false),
-      estimate_initial_rtt(false),
-      headers_include_h2_stream_dependency(false),
-      initial_rtt_for_handshake_milliseconds(0) {
+      reduced_ping_timeout(
+          base::TimeDelta::FromSeconds(quic::kPingTimeoutSecs)),
+      max_time_before_crypto_handshake(
+          base::TimeDelta::FromSeconds(quic::kMaxTimeForCryptoHandshakeSecs)),
+      max_idle_time_before_crypto_handshake(
+          base::TimeDelta::FromSeconds(quic::kInitialIdleTimeoutSecs)) {
   supported_versions.push_back(quic::ParsedQuicVersion(
       quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_46));
 }
@@ -1112,22 +1084,22 @@
       params_(params),
       clock_skew_detector_(base::TimeTicks::Now(), base::Time::Now()),
       socket_performance_watcher_factory_(socket_performance_watcher_factory),
-      config_(InitializeQuicConfig(
-          params.connection_options,
-          params.client_connection_options,
-          params.idle_connection_timeout_seconds,
-          params.max_time_before_crypto_handshake_seconds,
-          params.max_idle_time_before_crypto_handshake_seconds)),
+      config_(
+          InitializeQuicConfig(params.connection_options,
+                               params.client_connection_options,
+                               params.idle_connection_timeout,
+                               params.max_time_before_crypto_handshake,
+                               params.max_idle_time_before_crypto_handshake)),
       crypto_config_(
           std::make_unique<ProofVerifierChromium>(cert_verifier,
                                                   ct_policy_enforcer,
                                                   transport_security_state,
                                                   cert_transparency_verifier)),
       ping_timeout_(quic::QuicTime::Delta::FromSeconds(quic::kPingTimeoutSecs)),
-      reduced_ping_timeout_(quic::QuicTime::Delta::FromSeconds(
-          params.reduced_ping_timeout_seconds)),
-      retransmittable_on_wire_timeout_(quic::QuicTime::Delta::FromMilliseconds(
-          params.retransmittable_on_wire_timeout_milliseconds)),
+      reduced_ping_timeout_(quic::QuicTime::Delta::FromMicroseconds(
+          params.reduced_ping_timeout.InMicroseconds())),
+      retransmittable_on_wire_timeout_(quic::QuicTime::Delta::FromMicroseconds(
+          params.retransmittable_on_wire_timeout.InMicroseconds())),
       yield_after_packets_(kQuicYieldAfterPacketsRead),
       yield_after_duration_(quic::QuicTime::Delta::FromMilliseconds(
           kQuicYieldAfterDurationMilliseconds)),
@@ -1162,10 +1134,10 @@
       params.retry_on_alternate_network_before_handshake)
     DCHECK(params.migrate_sessions_on_network_change_v2);
 
-  if (params.retransmittable_on_wire_timeout_milliseconds == 0 &&
+  if (params.retransmittable_on_wire_timeout.is_zero() &&
       params.migrate_sessions_early_v2) {
-    retransmittable_on_wire_timeout_ = quic::QuicTime::Delta::FromMilliseconds(
-        kDefaultRetransmittableOnWireTimeoutMillisecs);
+    retransmittable_on_wire_timeout_ = quic::QuicTime::Delta::FromMicroseconds(
+        kDefaultRetransmittableOnWireTimeout.InMicroseconds());
   }
 
   // goaway_sessions_on_ip_change and close_sessions_on_ip_change should never
@@ -1968,10 +1940,11 @@
     return;
   }
 
-  if (params_.initial_rtt_for_handshake_milliseconds > 0) {
-    SetInitialRttEstimate(base::TimeDelta::FromMilliseconds(
-                              params_.initial_rtt_for_handshake_milliseconds),
-                          INITIAL_RTT_DEFAULT, config);
+  if (params_.initial_rtt_for_handshake > base::TimeDelta()) {
+    SetInitialRttEstimate(
+        base::TimeDelta::FromMicroseconds(
+            params_.initial_rtt_for_handshake.InMicroseconds()),
+        INITIAL_RTT_DEFAULT, config);
     return;
   }
 
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 55fca42..f725d49 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -79,20 +79,24 @@
 }  // namespace test
 
 // When a connection is idle for 30 seconds it will be closed.
-const int kIdleConnectionTimeoutSeconds = 30;
+constexpr base::TimeDelta kIdleConnectionTimeout =
+    base::TimeDelta::FromSeconds(30);
 
 // Sessions can migrate if they have been idle for less than this period.
-const int kDefaultIdleSessionMigrationPeriodSeconds = 30;
+constexpr base::TimeDelta kDefaultIdleSessionMigrationPeriod =
+    base::TimeDelta::FromSeconds(30);
 
 // The default maximum time allowed to have no retransmittable packets on the
 // wire (after sending the first retransmittable packet) if
 // |migrate_session_early_v2_| is true. PING frames will be sent as needed to
 // enforce this.
-const int64_t kDefaultRetransmittableOnWireTimeoutMillisecs = 100;
+constexpr base::TimeDelta kDefaultRetransmittableOnWireTimeout =
+    base::TimeDelta::FromMilliseconds(100);
 
 // The default maximum time QUIC session could be on non-default network before
 // migrate back to default network.
-const int64_t kMaxTimeOnNonDefaultNetworkSecs = 128;
+constexpr base::TimeDelta kMaxTimeOnNonDefaultNetwork =
+    base::TimeDelta::FromSeconds(128);
 
 // The default maximum number of migrations to non default network on write
 // error per network.
@@ -118,7 +122,7 @@
   size_t max_packet_length;
   // Maximum number of server configs that are to be stored in
   // HttpServerProperties, instead of the disk cache.
-  size_t max_server_configs_stored_in_properties;
+  size_t max_server_configs_stored_in_properties = 0u;
   // QUIC will be used for all connections in this set.
   std::set<HostPortPair> origins_to_force_quic_on;
   // Set of QUIC tags to send in the handshake's connection options.
@@ -127,86 +131,89 @@
   // affect the client.
   quic::QuicTagVector client_connection_options;
   // Enables experimental optimization for receiving data in UDPSocket.
-  bool enable_socket_recv_optimization;
+  bool enable_socket_recv_optimization = false;
 
   // Active QUIC experiments
 
   // Marks a QUIC server broken when a connection blackholes after the
   // handshake is confirmed.
-  bool mark_quic_broken_when_network_blackholes;
+  bool mark_quic_broken_when_network_blackholes = false;
   // Retry requests which fail with QUIC_PROTOCOL_ERROR, and mark QUIC
   // broken if the retry succeeds.
-  bool retry_without_alt_svc_on_quic_errors;
+  bool retry_without_alt_svc_on_quic_errors = true;
   // If true, alt-svc headers advertising QUIC in IETF format will be
   // supported.
-  bool support_ietf_format_quic_altsvc;
+  bool support_ietf_format_quic_altsvc = false;
   // If true, all QUIC sessions are closed when any local IP address changes.
-  bool close_sessions_on_ip_change;
+  bool close_sessions_on_ip_change = false;
   // If true, all QUIC sessions are marked as goaway when any local IP address
   // changes.
-  bool goaway_sessions_on_ip_change;
+  bool goaway_sessions_on_ip_change = false;
   // Specifies QUIC idle connection state lifetime.
-  int idle_connection_timeout_seconds;
+  base::TimeDelta idle_connection_timeout = kIdleConnectionTimeout;
   // Specifies the reduced ping timeout subsequent connections should use when
   // a connection was timed out with open streams.
-  int reduced_ping_timeout_seconds;
+  base::TimeDelta reduced_ping_timeout;
   // Maximum time that a session can have no retransmittable packets on the
   // wire. Set to zero if not specified and no retransmittable PING will be
   // sent to peer when the wire has no retransmittable packets.
-  int retransmittable_on_wire_timeout_milliseconds;
+  base::TimeDelta retransmittable_on_wire_timeout;
   // Maximum time the session can be alive before crypto handshake is
   // finished.
-  int max_time_before_crypto_handshake_seconds;
+  base::TimeDelta max_time_before_crypto_handshake;
   // Maximum idle time before the crypto handshake has completed.
-  int max_idle_time_before_crypto_handshake_seconds;
+  base::TimeDelta max_idle_time_before_crypto_handshake;
   // If true, connection migration v2 will be used to migrate existing
   // sessions to network when the platform indicates that the default network
   // is changing.
-  bool migrate_sessions_on_network_change_v2;
+  bool migrate_sessions_on_network_change_v2 = false;
   // If true, connection migration v2 may be used to migrate active QUIC
   // sessions to alternative network if current network connectivity is poor.
-  bool migrate_sessions_early_v2;
+  bool migrate_sessions_early_v2 = false;
   // If true, a new connection may be kicked off on an alternate network when
   // a connection fails on the default network before handshake is confirmed.
-  bool retry_on_alternate_network_before_handshake;
+  bool retry_on_alternate_network_before_handshake = false;
   // If true, an idle session will be migrated within the idle migration
   // period.
-  bool migrate_idle_sessions;
+  bool migrate_idle_sessions = false;
   // A session can be migrated if its idle time is within this period.
-  base::TimeDelta idle_session_migration_period;
+  base::TimeDelta idle_session_migration_period =
+      kDefaultIdleSessionMigrationPeriod;
   // Maximum time the session could be on the non-default network before
   // migrates back to default network. Defaults to
   // kMaxTimeOnNonDefaultNetwork.
-  base::TimeDelta max_time_on_non_default_network;
+  base::TimeDelta max_time_on_non_default_network = kMaxTimeOnNonDefaultNetwork;
   // Maximum number of migrations to the non-default network on write error
   // per network for each session.
-  int max_migrations_to_non_default_network_on_write_error;
+  int max_migrations_to_non_default_network_on_write_error =
+      kMaxMigrationsToNonDefaultNetworkOnWriteError;
   // Maximum number of migrations to the non-default network on path
   // degrading per network for each session.
-  int max_migrations_to_non_default_network_on_path_degrading;
+  int max_migrations_to_non_default_network_on_path_degrading =
+      kMaxMigrationsToNonDefaultNetworkOnPathDegrading;
   // If true, allows migration of QUIC connections to a server-specified
   // alternate server address.
-  bool allow_server_migration;
+  bool allow_server_migration = false;
   // If true, allows QUIC to use alternative services with a different
   // hostname from the origin.
-  bool allow_remote_alt_svc;
+  bool allow_remote_alt_svc = true;
   // If true, the quic stream factory may race connection from stale dns
   // result with the original dns resolution
-  bool race_stale_dns_on_connection;
+  bool race_stale_dns_on_connection = false;
   // If true, the quic session may mark itself as GOAWAY on path degrading.
-  bool go_away_on_path_degrading;
+  bool go_away_on_path_degrading = false;
   // If true, bidirectional streams over QUIC will be disabled.
-  bool disable_bidirectional_streams;
+  bool disable_bidirectional_streams = false;
   // If true, race cert verification with host resolution.
-  bool race_cert_verification;
+  bool race_cert_verification = false;
   // If true, estimate the initial RTT for QUIC connections based on network.
-  bool estimate_initial_rtt;
+  bool estimate_initial_rtt = false;
   // If true, client headers will include HTTP/2 stream dependency info
   // derived from the request priority.
-  bool headers_include_h2_stream_dependency;
+  bool headers_include_h2_stream_dependency = false;
   // The initial rtt that will be used in crypto handshake if no cached
   // smoothed rtt is present.
-  int initial_rtt_for_handshake_milliseconds;
+  base::TimeDelta initial_rtt_for_handshake;
 };
 
 enum QuicPlatformNotification {
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 388e824..870cd39 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -559,7 +559,8 @@
   // Verifies that the QUIC stream factory is initialized correctly.
   void VerifyInitialization() {
     test_params_.quic_params.max_server_configs_stored_in_properties = 1;
-    test_params_.quic_params.idle_connection_timeout_seconds = 500;
+    test_params_.quic_params.idle_connection_timeout =
+        base::TimeDelta::FromSeconds(500);
     Initialize();
     factory_->set_require_confirmation(false);
     ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
@@ -7260,17 +7261,18 @@
   base::RunLoop().RunUntilIdle();
 
   // Ack delay time.
-  int delay = task_runner->NextPendingTaskDelay().InMilliseconds();
-  EXPECT_GT(kDefaultRetransmittableOnWireTimeoutMillisecs, delay);
+  base::TimeDelta delay = task_runner->NextPendingTaskDelay();
+  EXPECT_GT(kDefaultRetransmittableOnWireTimeout, delay);
   // Fire the ack alarm, since ack has been sent, no ack will be sent.
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   // Fire the ping alarm with retransmittable-on-wire timeout, send PING.
-  delay = kDefaultRetransmittableOnWireTimeoutMillisecs - delay;
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(delay),
-            task_runner->NextPendingTaskDelay());
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  delay = kDefaultRetransmittableOnWireTimeout - delay;
+  EXPECT_EQ(delay, task_runner->NextPendingTaskDelay());
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   socket_data1.Resume();
@@ -7298,8 +7300,9 @@
 // enabled, and a custom retransmittable on wire timeout is specified, the
 // custom value is used.
 TEST_P(QuicStreamFactoryTest, CustomRetransmittableOnWireTimeoutForMigration) {
-  int custom_timeout_value = 200;
-  test_params_.quic_params.retransmittable_on_wire_timeout_milliseconds =
+  constexpr base::TimeDelta custom_timeout_value =
+      base::TimeDelta::FromMilliseconds(200);
+  test_params_.quic_params.retransmittable_on_wire_timeout =
       custom_timeout_value;
   InitializeConnectionMigrationV2Test(
       {kDefaultNetworkForTests, kNewNetworkForTests});
@@ -7405,17 +7408,18 @@
   base::RunLoop().RunUntilIdle();
 
   // Ack delay time.
-  int delay = task_runner->NextPendingTaskDelay().InMilliseconds();
+  base::TimeDelta delay = task_runner->NextPendingTaskDelay();
   EXPECT_GT(custom_timeout_value, delay);
   // Fire the ack alarm, since ack has been sent, no ack will be sent.
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   // Fire the ping alarm with retransmittable-on-wire timeout, send PING.
   delay = custom_timeout_value - delay;
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(delay),
-            task_runner->NextPendingTaskDelay());
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  EXPECT_EQ(delay, task_runner->NextPendingTaskDelay());
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   socket_data1.Resume();
@@ -7443,8 +7447,9 @@
 // retransmittable-on-wire timeout is specified, the ping alarm is set up to
 // send retransmittable pings with the custom value.
 TEST_P(QuicStreamFactoryTest, CustomRetransmittableOnWireTimeout) {
-  int custom_timeout_value = 200;
-  test_params_.quic_params.retransmittable_on_wire_timeout_milliseconds =
+  constexpr base::TimeDelta custom_timeout_value =
+      base::TimeDelta::FromMilliseconds(200);
+  test_params_.quic_params.retransmittable_on_wire_timeout =
       custom_timeout_value;
   Initialize();
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
@@ -7534,17 +7539,18 @@
   base::RunLoop().RunUntilIdle();
 
   // Ack delay time.
-  int delay = task_runner->NextPendingTaskDelay().InMilliseconds();
+  base::TimeDelta delay = task_runner->NextPendingTaskDelay();
   EXPECT_GT(custom_timeout_value, delay);
   // Fire the ack alarm, since ack has been sent, no ack will be sent.
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   // Fire the ping alarm with retransmittable-on-wire timeout, send PING.
   delay = custom_timeout_value - delay;
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(delay),
-            task_runner->NextPendingTaskDelay());
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  EXPECT_EQ(delay, task_runner->NextPendingTaskDelay());
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   socket_data1.Resume();
@@ -7654,17 +7660,19 @@
   base::RunLoop().RunUntilIdle();
 
   // Ack delay time.
-  int delay = task_runner->NextPendingTaskDelay().InMilliseconds();
-  EXPECT_GT(kDefaultRetransmittableOnWireTimeoutMillisecs, delay);
+  base::TimeDelta delay = task_runner->NextPendingTaskDelay();
+  EXPECT_GT(kDefaultRetransmittableOnWireTimeout, delay);
   // Fire the ack alarm, since ack has been sent, no ack will be sent.
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   // Verify that the ping alarm is not set with any default value.
-  int wrong_delay = kDefaultRetransmittableOnWireTimeoutMillisecs - delay;
-  delay = task_runner->NextPendingTaskDelay().InMilliseconds();
+  base::TimeDelta wrong_delay = kDefaultRetransmittableOnWireTimeout - delay;
+  delay = task_runner->NextPendingTaskDelay();
   EXPECT_NE(wrong_delay, delay);
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   // Verify that response headers on the migrated socket were delivered to the
@@ -7688,8 +7696,9 @@
 // send retransmittable pings to the peer with custom value.
 TEST_P(QuicStreamFactoryTest,
        CustomeRetransmittableOnWireTimeoutWithMigrationOnNetworkChangeOnly) {
-  int custom_timeout_value = 200;
-  test_params_.quic_params.retransmittable_on_wire_timeout_milliseconds =
+  constexpr base::TimeDelta custom_timeout_value =
+      base::TimeDelta::FromMilliseconds(200);
+  test_params_.quic_params.retransmittable_on_wire_timeout =
       custom_timeout_value;
   test_params_.quic_params.migrate_sessions_on_network_change_v2 = true;
   Initialize();
@@ -7780,17 +7789,18 @@
   base::RunLoop().RunUntilIdle();
 
   // Ack delay time.
-  int delay = task_runner->NextPendingTaskDelay().InMilliseconds();
+  base::TimeDelta delay = task_runner->NextPendingTaskDelay();
   EXPECT_GT(custom_timeout_value, delay);
   // Fire the ack alarm, since ack has been sent, no ack will be sent.
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   // Fire the ping alarm with retransmittable-on-wire timeout, send PING.
   delay = custom_timeout_value - delay;
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(delay),
-            task_runner->NextPendingTaskDelay());
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  EXPECT_EQ(delay, task_runner->NextPendingTaskDelay());
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   socket_data1.Resume();
@@ -7902,17 +7912,19 @@
   base::RunLoop().RunUntilIdle();
 
   // Ack delay time.
-  int delay = task_runner->NextPendingTaskDelay().InMilliseconds();
-  EXPECT_GT(kDefaultRetransmittableOnWireTimeoutMillisecs, delay);
+  base::TimeDelta delay = task_runner->NextPendingTaskDelay();
+  EXPECT_GT(kDefaultRetransmittableOnWireTimeout, delay);
   // Fire the ack alarm, since ack has been sent, no ack will be sent.
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   // Verify ping alarm is not set with default value.
-  int wrong_delay = kDefaultRetransmittableOnWireTimeoutMillisecs - delay;
-  delay = task_runner->NextPendingTaskDelay().InMilliseconds();
+  base::TimeDelta wrong_delay = kDefaultRetransmittableOnWireTimeout - delay;
+  delay = task_runner->NextPendingTaskDelay();
   EXPECT_NE(wrong_delay, delay);
-  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(delay));
+  clock_.AdvanceTime(
+      quic::QuicTime::Delta::FromMilliseconds(delay.InMilliseconds()));
   task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
 
   // Verify that response headers on the migrated socket were delivered to the
@@ -8843,7 +8855,8 @@
 }
 
 TEST_P(QuicStreamFactoryTest, ReducePingTimeoutOnConnectionTimeOutOpenStreams) {
-  test_params_.quic_params.reduced_ping_timeout_seconds = 10;
+  test_params_.quic_params.reduced_ping_timeout =
+      base::TimeDelta::FromSeconds(10);
   Initialize();
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
@@ -9747,12 +9760,14 @@
   EXPECT_EQ(DEFAULT_PRIORITY, host_resolver_->request_priority(2));
 }
 
-// Passes |quic_max_time_before_crypto_handshake_seconds| and
-// |quic_max_idle_time_before_crypto_handshake_seconds| to QuicStreamFactory,
+// Passes |quic_max_time_before_crypto_handshake| and
+// |quic_max_idle_time_before_crypto_handshake| to QuicStreamFactory,
 // checks that its internal quic::QuicConfig is correct.
 TEST_P(QuicStreamFactoryTest, ConfigMaxTimeBeforeCryptoHandshake) {
-  test_params_.quic_params.max_time_before_crypto_handshake_seconds = 11;
-  test_params_.quic_params.max_idle_time_before_crypto_handshake_seconds = 13;
+  test_params_.quic_params.max_time_before_crypto_handshake =
+      base::TimeDelta::FromSeconds(11);
+  test_params_.quic_params.max_idle_time_before_crypto_handshake =
+      base::TimeDelta::FromSeconds(13);
   Initialize();
 
   const quic::QuicConfig* config =
@@ -11070,8 +11085,9 @@
 }
 
 TEST_P(QuicStreamFactoryTest, ConfigInitialRttForHandshake) {
-  int kInitialRtt = 400;
-  test_params_.quic_params.initial_rtt_for_handshake_milliseconds = kInitialRtt;
+  constexpr base::TimeDelta kInitialRtt =
+      base::TimeDelta::FromMilliseconds(400);
+  test_params_.quic_params.initial_rtt_for_handshake = kInitialRtt;
   crypto_client_stream_factory_.set_handshake_mode(
       MockCryptoClientStream::COLD_START_WITH_CHLO_SENT);
   Initialize();
@@ -11110,19 +11126,17 @@
 
   // The pending task is scheduled for handshake timeout retransmission,
   // which is 2 * 400ms with crypto frames and 1.5 * 400ms otherwise.
-  int handshake_timeout =
+  base::TimeDelta handshake_timeout =
       QuicVersionUsesCryptoFrames(version_.transport_version)
           ? 2 * kInitialRtt
           : 1.5 * kInitialRtt;
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(handshake_timeout),
-            task_runner->NextPendingTaskDelay());
+  EXPECT_EQ(handshake_timeout, task_runner->NextPendingTaskDelay());
 
   // The alarm factory dependes on |clock_|, so clock is advanced to trigger
   // retransmission alarm.
-  clock_.AdvanceTime(
-      quic::QuicTime::Delta::FromMilliseconds(handshake_timeout));
-  task_runner->FastForwardBy(
-      base::TimeDelta::FromMilliseconds(handshake_timeout));
+  clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(
+      handshake_timeout.InMilliseconds()));
+  task_runner->FastForwardBy(handshake_timeout);
 
   crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
       quic::QuicSession::HANDSHAKE_CONFIRMED);
diff --git a/services/device/generic_sensor/BUILD.gn b/services/device/generic_sensor/BUILD.gn
index 9caa1e58..3fea2ec2 100644
--- a/services/device/generic_sensor/BUILD.gn
+++ b/services/device/generic_sensor/BUILD.gn
@@ -54,6 +54,7 @@
     "platform_sensor_reader_linux.h",
     "platform_sensor_reader_win.cc",
     "platform_sensor_reader_win.h",
+    "platform_sensor_reader_win_base.h",
     "platform_sensor_win.cc",
     "platform_sensor_win.h",
     "relative_orientation_euler_angles_fusion_algorithm_using_accelerometer.cc",
@@ -107,6 +108,8 @@
     sources += [
       "platform_sensor_provider_winrt.cc",
       "platform_sensor_provider_winrt.h",
+      "platform_sensor_reader_winrt.cc",
+      "platform_sensor_reader_winrt.h",
     ]
 
     libs = [
diff --git a/services/device/generic_sensor/platform_sensor_provider_win.cc b/services/device/generic_sensor/platform_sensor_provider_win.cc
index 56ade2ba..5d7af8d1d 100644
--- a/services/device/generic_sensor/platform_sensor_provider_win.cc
+++ b/services/device/generic_sensor/platform_sensor_provider_win.cc
@@ -108,7 +108,7 @@
     mojom::SensorType type,
     SensorReadingSharedBuffer* reading_buffer,
     const CreateSensorCallback& callback,
-    std::unique_ptr<PlatformSensorReaderWin> sensor_reader) {
+    std::unique_ptr<PlatformSensorReaderWinBase> sensor_reader) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (!sensor_reader) {
     // Fallback options for sensors that can be implemented using sensor
@@ -135,12 +135,12 @@
   callback.Run(sensor);
 }
 
-std::unique_ptr<PlatformSensorReaderWin>
+std::unique_ptr<PlatformSensorReaderWinBase>
 PlatformSensorProviderWin::CreateSensorReader(mojom::SensorType type) {
   DCHECK(com_sta_task_runner_->RunsTasksInCurrentSequence());
   if (!sensor_manager_)
     return nullptr;
-  return PlatformSensorReaderWin::Create(type, sensor_manager_);
+  return PlatformSensorReaderWin32::Create(type, sensor_manager_);
 }
 
 }  // namespace device
diff --git a/services/device/generic_sensor/platform_sensor_provider_win.h b/services/device/generic_sensor/platform_sensor_provider_win.h
index 9054d892..c75568f3 100644
--- a/services/device/generic_sensor/platform_sensor_provider_win.h
+++ b/services/device/generic_sensor/platform_sensor_provider_win.h
@@ -12,7 +12,7 @@
 
 namespace device {
 
-class PlatformSensorReaderWin;
+class PlatformSensorReaderWinBase;
 
 // Implementation of PlatformSensorProvider for Windows platform.
 // PlatformSensorProviderWin is responsible for following tasks:
@@ -40,13 +40,13 @@
   void OnInitSensorManager(mojom::SensorType type,
                            SensorReadingSharedBuffer* reading_buffer,
                            const CreateSensorCallback& callback);
-  std::unique_ptr<PlatformSensorReaderWin> CreateSensorReader(
+  std::unique_ptr<PlatformSensorReaderWinBase> CreateSensorReader(
       mojom::SensorType type);
   void SensorReaderCreated(
       mojom::SensorType type,
       SensorReadingSharedBuffer* reading_buffer,
       const CreateSensorCallback& callback,
-      std::unique_ptr<PlatformSensorReaderWin> sensor_reader);
+      std::unique_ptr<PlatformSensorReaderWinBase> sensor_reader);
 
   scoped_refptr<base::SingleThreadTaskRunner> com_sta_task_runner_;
   Microsoft::WRL::ComPtr<ISensorManager> sensor_manager_;
diff --git a/services/device/generic_sensor/platform_sensor_provider_winrt.cc b/services/device/generic_sensor/platform_sensor_provider_winrt.cc
index c2b0981..b7919c9 100644
--- a/services/device/generic_sensor/platform_sensor_provider_winrt.cc
+++ b/services/device/generic_sensor/platform_sensor_provider_winrt.cc
@@ -4,17 +4,102 @@
 
 #include "services/device/generic_sensor/platform_sensor_provider_winrt.h"
 
+#include <comdef.h>
+
+#include "base/task/post_task.h"
+#include "base/task_runner_util.h"
+#include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h"
+#include "services/device/generic_sensor/orientation_euler_angles_fusion_algorithm_using_quaternion.h"
+#include "services/device/generic_sensor/platform_sensor_fusion.h"
+#include "services/device/generic_sensor/platform_sensor_reader_winrt.h"
+#include "services/device/generic_sensor/platform_sensor_win.h"
+
 namespace device {
 
-PlatformSensorProviderWinrt::PlatformSensorProviderWinrt() = default;
+std::unique_ptr<PlatformSensorReaderWinBase>
+SensorReaderFactory::CreateSensorReader(mojom::SensorType type) {
+  return PlatformSensorReaderWinrtFactory::Create(type);
+}
+
+PlatformSensorProviderWinrt::PlatformSensorProviderWinrt()
+    : com_sta_task_runner_(base::CreateCOMSTATaskRunnerWithTraits(
+          base::TaskPriority::USER_VISIBLE)),
+      sensor_reader_factory_(std::make_unique<SensorReaderFactory>()) {}
 
 PlatformSensorProviderWinrt::~PlatformSensorProviderWinrt() = default;
 
+void PlatformSensorProviderWinrt::SetSensorReaderFactoryForTesting(
+    std::unique_ptr<SensorReaderFactory> sensor_reader_factory) {
+  sensor_reader_factory_ = std::move(sensor_reader_factory);
+}
+
 void PlatformSensorProviderWinrt::CreateSensorInternal(
     mojom::SensorType type,
     SensorReadingSharedBuffer* reading_buffer,
     const CreateSensorCallback& callback) {
-  callback.Run(nullptr);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  switch (type) {
+    // Fusion sensor.
+    case mojom::SensorType::LINEAR_ACCELERATION: {
+      auto linear_acceleration_fusion_algorithm = std::make_unique<
+          LinearAccelerationFusionAlgorithmUsingAccelerometer>();
+      // If this PlatformSensorFusion object is successfully initialized,
+      // |callback| will be run with a reference to this object.
+      PlatformSensorFusion::Create(
+          reading_buffer, this, std::move(linear_acceleration_fusion_algorithm),
+          callback);
+      break;
+    }
+
+    // Try to create low-level sensors by default.
+    default: {
+      base::PostTaskAndReplyWithResult(
+          com_sta_task_runner_.get(), FROM_HERE,
+          base::Bind(&PlatformSensorProviderWinrt::CreateSensorReader,
+                     base::Unretained(this), type),
+          base::Bind(&PlatformSensorProviderWinrt::SensorReaderCreated,
+                     base::Unretained(this), type, reading_buffer, callback));
+      break;
+    }
+  }
 }
 
-}  // namespace device
+void PlatformSensorProviderWinrt::SensorReaderCreated(
+    mojom::SensorType type,
+    SensorReadingSharedBuffer* reading_buffer,
+    const CreateSensorCallback& callback,
+    std::unique_ptr<PlatformSensorReaderWinBase> sensor_reader) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (!sensor_reader) {
+    // Fallback options for sensors that can be implemented using sensor
+    // fusion. Note that it is important not to generate a cycle by adding a
+    // fallback here that depends on one of the other fallbacks provided.
+    switch (type) {
+      case mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES: {
+        auto algorithm = std::make_unique<
+            OrientationEulerAnglesFusionAlgorithmUsingQuaternion>(
+            /*absolute=*/true);
+        PlatformSensorFusion::Create(reading_buffer, this, std::move(algorithm),
+                                     std::move(callback));
+        return;
+      }
+      default:
+        callback.Run(nullptr);
+        return;
+    }
+  }
+  scoped_refptr<PlatformSensor> sensor =
+      base::MakeRefCounted<PlatformSensorWin>(type, reading_buffer, this,
+                                              com_sta_task_runner_,
+                                              std::move(sensor_reader));
+  callback.Run(std::move(sensor));
+}
+
+std::unique_ptr<PlatformSensorReaderWinBase>
+PlatformSensorProviderWinrt::CreateSensorReader(mojom::SensorType type) {
+  DCHECK(com_sta_task_runner_->RunsTasksInCurrentSequence());
+  return sensor_reader_factory_->CreateSensorReader(type);
+}
+
+}  // namespace device
\ No newline at end of file
diff --git a/services/device/generic_sensor/platform_sensor_provider_winrt.h b/services/device/generic_sensor/platform_sensor_provider_winrt.h
index 2486595..79512718 100644
--- a/services/device/generic_sensor/platform_sensor_provider_winrt.h
+++ b/services/device/generic_sensor/platform_sensor_provider_winrt.h
@@ -9,7 +9,15 @@
 
 namespace device {
 
-class PlatformSensorReaderWin;
+class PlatformSensorReaderWinBase;
+
+// Helper class used to instantiate new PlatformSensorReaderWinBase instances.
+class SensorReaderFactory {
+ public:
+  virtual ~SensorReaderFactory() = default;
+  virtual std::unique_ptr<PlatformSensorReaderWinBase> CreateSensorReader(
+      mojom::SensorType type);
+};
 
 // Implementation of PlatformSensorProvider for Windows platform using the
 // Windows.Devices.Sensors WinRT API. PlatformSensorProviderWinrt is
@@ -22,6 +30,9 @@
   PlatformSensorProviderWinrt();
   ~PlatformSensorProviderWinrt() override;
 
+  void SetSensorReaderFactoryForTesting(
+      std::unique_ptr<SensorReaderFactory> sensor_reader_factory);
+
  protected:
   // PlatformSensorProvider interface implementation.
   void CreateSensorInternal(mojom::SensorType type,
@@ -29,11 +40,20 @@
                             const CreateSensorCallback& callback) override;
 
  private:
+  std::unique_ptr<PlatformSensorReaderWinBase> CreateSensorReader(
+      mojom::SensorType type);
+
   void SensorReaderCreated(
       mojom::SensorType type,
       SensorReadingSharedBuffer* reading_buffer,
       const CreateSensorCallback& callback,
-      std::unique_ptr<PlatformSensorReaderWin> sensor_reader);
+      std::unique_ptr<PlatformSensorReaderWinBase> sensor_reader);
+
+  // The Windows.Devices.Sensors WinRT API supports both STA and MTA
+  // threads. STA was chosen as PlatformSensorWin can only handle STA.
+  scoped_refptr<base::SingleThreadTaskRunner> com_sta_task_runner_;
+
+  std::unique_ptr<SensorReaderFactory> sensor_reader_factory_;
 
   PlatformSensorProviderWinrt(const PlatformSensorProviderWinrt&) = delete;
   PlatformSensorProviderWinrt& operator=(const PlatformSensorProviderWinrt&) =
@@ -42,4 +62,4 @@
 
 }  // namespace device
 
-#endif  // SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_PROVIDER_WINRT_H_
+#endif  // SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_PROVIDER_WINRT_H_
\ No newline at end of file
diff --git a/services/device/generic_sensor/platform_sensor_provider_winrt_unittest.cc b/services/device/generic_sensor/platform_sensor_provider_winrt_unittest.cc
index 27a79470..bdda78f 100644
--- a/services/device/generic_sensor/platform_sensor_provider_winrt_unittest.cc
+++ b/services/device/generic_sensor/platform_sensor_provider_winrt_unittest.cc
@@ -7,32 +7,100 @@
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
+#include "services/device/generic_sensor/platform_sensor_reader_win_base.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace device {
 
+// Mock for PlatformSensorReaderWinBase, used to ensure the actual
+// Windows.Devices.Sensor API isn't called.
+class MockSensorReader : public PlatformSensorReaderWinBase {
+ public:
+  MockSensorReader() = default;
+  ~MockSensorReader() override = default;
+
+  MOCK_METHOD1(SetClient, void(Client* client));
+  MOCK_CONST_METHOD0(GetMinimalReportingInterval, base::TimeDelta());
+  MOCK_METHOD1(StartSensor,
+               bool(const PlatformSensorConfiguration& configuration));
+  MOCK_METHOD0(StopSensor, void());
+};
+
+// Mock for SensorReaderFactory, injected into
+// PlatformSensorProviderWinrt so it will create MockSensorReaders instead
+// of the real PlatformSensorReaderWinBase which calls into the WinRT APIs.
+class MockSensorReaderFactory : public SensorReaderFactory {
+ public:
+  MockSensorReaderFactory() = default;
+  ~MockSensorReaderFactory() override = default;
+
+  MOCK_METHOD1(
+      CreateSensorReader,
+      std::unique_ptr<PlatformSensorReaderWinBase>(mojom::SensorType type));
+};
+
 // Tests that PlatformSensorProviderWinrt can successfully be instantiated
 // and passes the correct result to the CreateSensor callback.
 TEST(PlatformSensorProviderTestWinrt, SensorCreationReturnCheck) {
   base::test::ScopedTaskEnvironment scoped_task_environment;
 
+  auto mock_sensor_reader_factory =
+      std::make_unique<testing::NiceMock<MockSensorReaderFactory>>();
+
+  // Return valid PlatformSensorReaderWinBase instances for gyroscope and
+  // accelerometer to represent them as supported/present. Return nullptr
+  // for ambient light to represent it as not present/supported.
+  EXPECT_CALL(*mock_sensor_reader_factory.get(),
+              CreateSensorReader(mojom::SensorType::AMBIENT_LIGHT))
+      .WillOnce(testing::Invoke([](mojom::SensorType) { return nullptr; }));
+  EXPECT_CALL(*mock_sensor_reader_factory.get(),
+              CreateSensorReader(mojom::SensorType::GYROSCOPE))
+      .WillOnce(testing::Invoke([](mojom::SensorType) {
+        return std::make_unique<testing::NiceMock<MockSensorReader>>();
+      }));
+  EXPECT_CALL(*mock_sensor_reader_factory.get(),
+              CreateSensorReader(mojom::SensorType::ACCELEROMETER))
+      .WillOnce(testing::Invoke([](mojom::SensorType) {
+        return std::make_unique<testing::NiceMock<MockSensorReader>>();
+      }));
+
   auto provider = std::make_unique<PlatformSensorProviderWinrt>();
 
-  // CreateSensor is async so create a RunLoop to wait for completion.
-  base::RunLoop run_loop;
+  provider->SetSensorReaderFactoryForTesting(
+      std::move(mock_sensor_reader_factory));
+
+  // CreateSensor is async so use a RunLoop to wait for completion.
+  base::Optional<base::RunLoop> run_loop;
+  bool expect_sensor_valid = false;
 
   base::Callback<void(scoped_refptr<PlatformSensor> sensor)>
-      CreateSensorCallback =
+      create_sensor_callback =
           base::BindLambdaForTesting([&](scoped_refptr<PlatformSensor> sensor) {
-            EXPECT_FALSE(sensor);
-            run_loop.Quit();
+            if (expect_sensor_valid)
+              EXPECT_TRUE(sensor);
+            else
+              EXPECT_FALSE(sensor);
+            run_loop->Quit();
           });
 
-  // PlatformSensorProviderWinrt is not implemented so it should always
-  // return nullptr.
+  run_loop.emplace();
   provider->CreateSensor(mojom::SensorType::AMBIENT_LIGHT,
-                         CreateSensorCallback);
-  run_loop.Run();
+                         create_sensor_callback);
+  run_loop->Run();
+
+  expect_sensor_valid = true;
+  run_loop.emplace();
+  provider->CreateSensor(mojom::SensorType::GYROSCOPE, create_sensor_callback);
+  run_loop->Run();
+
+  // Linear acceleration is a fusion sensor built on top of accelerometer,
+  // this should trigger the CreateSensorReader(ACCELEROMETER) call.
+  expect_sensor_valid = true;
+  run_loop.emplace();
+  provider->CreateSensor(mojom::SensorType::LINEAR_ACCELERATION,
+                         create_sensor_callback);
+  run_loop->Run();
 }
 
 }  // namespace device
\ No newline at end of file
diff --git a/services/device/generic_sensor/platform_sensor_reader_win.cc b/services/device/generic_sensor/platform_sensor_reader_win.cc
index 86a0da5a..1fbf3232 100644
--- a/services/device/generic_sensor/platform_sensor_reader_win.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_win.cc
@@ -24,7 +24,7 @@
 
 namespace device {
 
-// Init params for the PlatformSensorReaderWin.
+// Init params for the PlatformSensorReaderWin32.
 struct ReaderInitParams {
   // ISensorDataReport::GetSensorValue is not const, therefore, report
   // cannot be passed as const ref.
@@ -35,7 +35,7 @@
                                     SensorReading* reading);
   SENSOR_TYPE_ID sensor_type_id;
   ReaderFunctor reader_func;
-  unsigned long min_reporting_interval_ms = 0;
+  base::TimeDelta min_reporting_interval;
 };
 
 namespace {
@@ -252,7 +252,7 @@
 // by ISensor interface to dispatch state and data change events.
 class EventListener : public ISensorEvents, public base::win::IUnknownImpl {
  public:
-  explicit EventListener(PlatformSensorReaderWin* platform_sensor_reader)
+  explicit EventListener(PlatformSensorReaderWin32* platform_sensor_reader)
       : platform_sensor_reader_(platform_sensor_reader) {
     DCHECK(platform_sensor_reader_);
   }
@@ -345,14 +345,14 @@
   }
 
  private:
-  PlatformSensorReaderWin* const platform_sensor_reader_;
+  PlatformSensorReaderWin32* const platform_sensor_reader_;
   SensorReading last_sensor_reading_;
 
   DISALLOW_COPY_AND_ASSIGN(EventListener);
 };
 
 // static
-std::unique_ptr<PlatformSensorReaderWin> PlatformSensorReaderWin::Create(
+std::unique_ptr<PlatformSensorReaderWinBase> PlatformSensorReaderWin32::Create(
     mojom::SensorType type,
     Microsoft::WRL::ComPtr<ISensorManager> sensor_manager) {
   DCHECK(sensor_manager);
@@ -368,8 +368,10 @@
   base::win::ScopedPropVariant min_interval;
   HRESULT hr = sensor->GetProperty(SENSOR_PROPERTY_MIN_REPORT_INTERVAL,
                                    min_interval.Receive());
-  if (SUCCEEDED(hr) && min_interval.get().vt == VT_UI4)
-    params->min_reporting_interval_ms = min_interval.get().ulVal;
+  if (SUCCEEDED(hr) && min_interval.get().vt == VT_UI4) {
+    params->min_reporting_interval =
+        base::TimeDelta::FromMilliseconds(min_interval.get().ulVal);
+  }
 
   GUID interests[] = {SENSOR_EVENT_STATE_CHANGED, SENSOR_EVENT_DATA_UPDATED};
   hr = sensor->SetEventInterest(interests, base::size(interests));
@@ -377,11 +379,11 @@
     return nullptr;
 
   return base::WrapUnique(
-      new PlatformSensorReaderWin(sensor, std::move(params)));
+      new PlatformSensorReaderWin32(sensor, std::move(params)));
 }
 
 // static
-Microsoft::WRL::ComPtr<ISensor> PlatformSensorReaderWin::GetSensorForType(
+Microsoft::WRL::ComPtr<ISensor> PlatformSensorReaderWin32::GetSensorForType(
     REFSENSOR_TYPE_ID sensor_type,
     Microsoft::WRL::ComPtr<ISensorManager> sensor_manager) {
   Microsoft::WRL::ComPtr<ISensor> sensor;
@@ -398,7 +400,7 @@
   return sensor;
 }
 
-PlatformSensorReaderWin::PlatformSensorReaderWin(
+PlatformSensorReaderWin32::PlatformSensorReaderWin32(
     Microsoft::WRL::ComPtr<ISensor> sensor,
     std::unique_ptr<ReaderInitParams> params)
     : init_params_(std::move(params)),
@@ -413,13 +415,13 @@
   DCHECK(sensor_);
 }
 
-void PlatformSensorReaderWin::SetClient(Client* client) {
+void PlatformSensorReaderWin32::SetClient(Client* client) {
   base::AutoLock autolock(lock_);
   // Can be null.
   client_ = client;
 }
 
-void PlatformSensorReaderWin::StopSensor() {
+void PlatformSensorReaderWin32::StopSensor() {
   base::AutoLock autolock(lock_);
   if (sensor_active_) {
     sensor_->SetEventSink(nullptr);
@@ -427,11 +429,11 @@
   }
 }
 
-PlatformSensorReaderWin::~PlatformSensorReaderWin() {
+PlatformSensorReaderWin32::~PlatformSensorReaderWin32() {
   DCHECK(task_runner_->BelongsToCurrentThread());
 }
 
-bool PlatformSensorReaderWin::StartSensor(
+bool PlatformSensorReaderWin32::StartSensor(
     const PlatformSensorConfiguration& configuration) {
   base::AutoLock autolock(lock_);
 
@@ -440,7 +442,7 @@
 
   if (!sensor_active_) {
     task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&PlatformSensorReaderWin::ListenSensorEvent,
+        FROM_HERE, base::BindOnce(&PlatformSensorReaderWin32::ListenSensorEvent,
                                   weak_factory_.GetWeakPtr()));
     sensor_active_ = true;
   }
@@ -448,7 +450,7 @@
   return true;
 }
 
-void PlatformSensorReaderWin::ListenSensorEvent() {
+void PlatformSensorReaderWin32::ListenSensorEvent() {
   // Set event listener.
   if (FAILED(sensor_->SetEventSink(event_listener_.get()))) {
     SensorError();
@@ -456,7 +458,7 @@
   }
 }
 
-bool PlatformSensorReaderWin::SetReportingInterval(
+bool PlatformSensorReaderWin32::SetReportingInterval(
     const PlatformSensorConfiguration& configuration) {
   Microsoft::WRL::ComPtr<IPortableDeviceValues> props;
   HRESULT hr = ::CoCreateInstance(CLSID_PortableDeviceValues, nullptr,
@@ -485,7 +487,7 @@
   return SUCCEEDED(hr);
 }
 
-HRESULT PlatformSensorReaderWin::SensorReadingChanged(
+HRESULT PlatformSensorReaderWin32::SensorReadingChanged(
     ISensorDataReport* report,
     SensorReading* reading) const {
   if (!client_)
@@ -497,13 +499,13 @@
   return hr;
 }
 
-void PlatformSensorReaderWin::SensorError() {
+void PlatformSensorReaderWin32::SensorError() {
   if (client_)
     client_->OnSensorError();
 }
 
-unsigned long PlatformSensorReaderWin::GetMinimalReportingIntervalMs() const {
-  return init_params_->min_reporting_interval_ms;
+base::TimeDelta PlatformSensorReaderWin32::GetMinimalReportingInterval() const {
+  return init_params_->min_reporting_interval;
 }
 
 }  // namespace device
diff --git a/services/device/generic_sensor/platform_sensor_reader_win.h b/services/device/generic_sensor/platform_sensor_reader_win.h
index 8b31ae2f..3864c51 100644
--- a/services/device/generic_sensor/platform_sensor_reader_win.h
+++ b/services/device/generic_sensor/platform_sensor_reader_win.h
@@ -8,8 +8,13 @@
 #include <SensorsApi.h>
 #include <wrl/client.h>
 
+#include "services/device/generic_sensor/platform_sensor_reader_win_base.h"
 #include "services/device/public/mojom/sensor.mojom.h"
 
+namespace base {
+class TimeDelta;
+}
+
 namespace device {
 
 class PlatformSensorConfiguration;
@@ -19,44 +24,35 @@
 // Generic class that uses ISensor interface to fetch sensor data. Used
 // by PlatformSensorWin and delivers notifications via Client interface.
 // Instances of this class must be created and destructed on the same thread.
-class PlatformSensorReaderWin {
+class PlatformSensorReaderWin32 final : public PlatformSensorReaderWinBase {
  public:
-  // Client interface that can be used to receive notifications about sensor
-  // error or data change events.
-  class Client {
-   public:
-    virtual void OnReadingUpdated(const SensorReading& reading) = 0;
-    virtual void OnSensorError() = 0;
-
-   protected:
-    virtual ~Client() {}
-  };
-
-  static std::unique_ptr<PlatformSensorReaderWin> Create(
+  static std::unique_ptr<PlatformSensorReaderWinBase> Create(
       mojom::SensorType type,
       Microsoft::WRL::ComPtr<ISensorManager> sensor_manager);
 
   // Following methods are thread safe.
-  void SetClient(Client* client);
-  unsigned long GetMinimalReportingIntervalMs() const;
-  bool StartSensor(const PlatformSensorConfiguration& configuration);
-  void StopSensor();
+  void SetClient(Client* client) override;
+  base::TimeDelta GetMinimalReportingInterval() const override;
+  bool StartSensor(const PlatformSensorConfiguration& configuration) override
+      WARN_UNUSED_RESULT;
+  void StopSensor() override;
 
   // Must be destructed on the same thread that was used during construction.
-  ~PlatformSensorReaderWin();
+  ~PlatformSensorReaderWin32() override;
 
  private:
-  PlatformSensorReaderWin(Microsoft::WRL::ComPtr<ISensor> sensor,
-                          std::unique_ptr<ReaderInitParams> params);
+  PlatformSensorReaderWin32(Microsoft::WRL::ComPtr<ISensor> sensor,
+                            std::unique_ptr<ReaderInitParams> params);
 
   static Microsoft::WRL::ComPtr<ISensor> GetSensorForType(
       REFSENSOR_TYPE_ID sensor_type,
       Microsoft::WRL::ComPtr<ISensorManager> sensor_manager);
 
-  bool SetReportingInterval(const PlatformSensorConfiguration& configuration);
+  bool SetReportingInterval(const PlatformSensorConfiguration& configuration)
+      WARN_UNUSED_RESULT;
   void ListenSensorEvent();
   HRESULT SensorReadingChanged(ISensorDataReport* report,
-                               SensorReading* reading) const;
+                               SensorReading* reading) const WARN_UNUSED_RESULT;
   void SensorError();
 
  private:
@@ -72,9 +68,9 @@
   Client* client_;
   Microsoft::WRL::ComPtr<ISensor> sensor_;
   scoped_refptr<EventListener> event_listener_;
-  base::WeakPtrFactory<PlatformSensorReaderWin> weak_factory_;
+  base::WeakPtrFactory<PlatformSensorReaderWin32> weak_factory_;
 
-  DISALLOW_COPY_AND_ASSIGN(PlatformSensorReaderWin);
+  DISALLOW_COPY_AND_ASSIGN(PlatformSensorReaderWin32);
 };
 
 }  // namespace device
diff --git a/services/device/generic_sensor/platform_sensor_reader_win_base.h b/services/device/generic_sensor/platform_sensor_reader_win_base.h
new file mode 100644
index 0000000..8b77bc1
--- /dev/null
+++ b/services/device/generic_sensor/platform_sensor_reader_win_base.h
@@ -0,0 +1,46 @@
+// Copyright 2019 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 SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_WIN_BASE_H_
+#define SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_WIN_BASE_H_
+
+namespace base {
+class TimeDelta;
+}
+
+namespace device {
+
+class PlatformSensorConfiguration;
+union SensorReading;
+
+class PlatformSensorReaderWinBase {
+ public:
+  // Client interface that can be used to receive notifications about sensor
+  // error or data change events.
+  class Client {
+   public:
+    virtual void OnReadingUpdated(const SensorReading& reading) = 0;
+    virtual void OnSensorError() = 0;
+
+   protected:
+    virtual ~Client() = default;
+  };
+
+  // Following methods must be thread safe.
+  // Sets the client PlatformSensorReaderWinBase will use to notify
+  // about errors or data change events. Only one client can be registered
+  // at a time (last client to register wins) and can be removed by
+  // setting the client to nullptr.
+  virtual void SetClient(Client* client) = 0;
+  virtual base::TimeDelta GetMinimalReportingInterval() const = 0;
+  virtual bool StartSensor(
+      const PlatformSensorConfiguration& configuration) = 0;
+  virtual void StopSensor() = 0;
+
+  virtual ~PlatformSensorReaderWinBase() = default;
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_WIN_BASE_H_
\ No newline at end of file
diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt.cc b/services/device/generic_sensor/platform_sensor_reader_winrt.cc
new file mode 100644
index 0000000..d14d5d74
--- /dev/null
+++ b/services/device/generic_sensor/platform_sensor_reader_winrt.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 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 "services/device/generic_sensor/platform_sensor_reader_winrt.h"
+
+#include "services/device/public/mojom/sensor.mojom.h"
+
+namespace device {
+
+// static
+std::unique_ptr<PlatformSensorReaderWinBase>
+PlatformSensorReaderWinrtFactory::Create(mojom::SensorType) {
+  return nullptr;
+}
+
+}  // namespace device
\ No newline at end of file
diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt.h b/services/device/generic_sensor/platform_sensor_reader_winrt.h
new file mode 100644
index 0000000..7712917
--- /dev/null
+++ b/services/device/generic_sensor/platform_sensor_reader_winrt.h
@@ -0,0 +1,27 @@
+// Copyright 2019 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 SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_WINRT_H_
+#define SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_WINRT_H_
+
+#include <memory>
+
+#include "services/device/generic_sensor/platform_sensor_reader_win_base.h"
+
+namespace device {
+
+namespace mojom {
+enum class SensorType;
+}
+
+// Helper class used to create PlatformSensorReaderWinBasert instances
+class PlatformSensorReaderWinrtFactory {
+ public:
+  static std::unique_ptr<PlatformSensorReaderWinBase> Create(
+      mojom::SensorType type);
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_WINRT_H_
\ No newline at end of file
diff --git a/services/device/generic_sensor/platform_sensor_win.cc b/services/device/generic_sensor/platform_sensor_win.cc
index 32ded5f1..89dfd746 100644
--- a/services/device/generic_sensor/platform_sensor_win.cc
+++ b/services/device/generic_sensor/platform_sensor_win.cc
@@ -18,7 +18,7 @@
     SensorReadingSharedBuffer* reading_buffer,
     PlatformSensorProvider* provider,
     scoped_refptr<base::SingleThreadTaskRunner> sensor_thread_runner,
-    std::unique_ptr<PlatformSensorReaderWin> sensor_reader)
+    std::unique_ptr<PlatformSensorReaderWinBase> sensor_reader)
     : PlatformSensor(type, reading_buffer, provider),
       sensor_thread_runner_(sensor_thread_runner),
       sensor_reader_(sensor_reader.release()),
@@ -38,11 +38,11 @@
 }
 
 double PlatformSensorWin::GetMaximumSupportedFrequency() {
-  double minimal_reporting_interval_ms =
-      sensor_reader_->GetMinimalReportingIntervalMs();
-  if (!minimal_reporting_interval_ms)
+  base::TimeDelta minimal_reporting_interval_ms =
+      sensor_reader_->GetMinimalReportingInterval();
+  if (minimal_reporting_interval_ms.is_zero())
     return kDefaultSensorReportingFrequency;
-  return base::Time::kMillisecondsPerSecond / minimal_reporting_interval_ms;
+  return 1.0 / minimal_reporting_interval_ms.InSecondsF();
 }
 
 void PlatformSensorWin::OnReadingUpdated(const SensorReading& reading) {
@@ -69,12 +69,11 @@
 bool PlatformSensorWin::CheckSensorConfiguration(
     const PlatformSensorConfiguration& configuration) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  double minimal_reporting_interval_ms =
-      sensor_reader_->GetMinimalReportingIntervalMs();
-  if (minimal_reporting_interval_ms == 0)
+  base::TimeDelta minimal_reporting_interval_ms =
+      sensor_reader_->GetMinimalReportingInterval();
+  if (minimal_reporting_interval_ms.is_zero())
     return true;
-  double max_frequency =
-      base::Time::kMillisecondsPerSecond / minimal_reporting_interval_ms;
+  double max_frequency = 1.0 / minimal_reporting_interval_ms.InSecondsF();
   return configuration.frequency() <= max_frequency;
 }
 
diff --git a/services/device/generic_sensor/platform_sensor_win.h b/services/device/generic_sensor/platform_sensor_win.h
index bae519df..1f44265 100644
--- a/services/device/generic_sensor/platform_sensor_win.h
+++ b/services/device/generic_sensor/platform_sensor_win.h
@@ -18,25 +18,25 @@
 // Implementation of PlatformSensor interface for Windows platform. Instance
 // of PlatformSensorWin is bound to IPC thread where PlatformSensorProvider is
 // running and communication with Windows platform sensor is done through
-// PlatformSensorReaderWin |sensor_reader_| interface which is bound to sensor
-// thread and communicates with PlatformSensorWin using
-// PlatformSensorReaderWin::Client interface. The error and data change events
-// are forwarded to IPC task runner.
+// PlatformSensorReaderWinBase |sensor_reader_| interface which is bound to
+// sensor thread and communicates with PlatformSensorWin using
+// PlatformSensorReaderWinBase::Client interface. The error and data change
+// events are forwarded to IPC task runner.
 class PlatformSensorWin final : public PlatformSensor,
-                                public PlatformSensorReaderWin::Client {
+                                public PlatformSensorReaderWinBase::Client {
  public:
   PlatformSensorWin(
       mojom::SensorType type,
       SensorReadingSharedBuffer* reading_buffer,
       PlatformSensorProvider* provider,
       scoped_refptr<base::SingleThreadTaskRunner> sensor_thread_runner,
-      std::unique_ptr<PlatformSensorReaderWin> sensor_reader);
+      std::unique_ptr<PlatformSensorReaderWinBase> sensor_reader);
 
   PlatformSensorConfiguration GetDefaultConfiguration() override;
   mojom::ReportingMode GetReportingMode() override;
   double GetMaximumSupportedFrequency() override;
 
-  // PlatformSensorReaderWin::Client interface implementation.
+  // PlatformSensorReaderWinBase::Client interface implementation.
   void OnReadingUpdated(const SensorReading& reading) override;
   void OnSensorError() override;
 
@@ -51,7 +51,7 @@
 
  private:
   scoped_refptr<base::SingleThreadTaskRunner> sensor_thread_runner_;
-  PlatformSensorReaderWin* const sensor_reader_;
+  PlatformSensorReaderWinBase* const sensor_reader_;
   base::WeakPtrFactory<PlatformSensorWin> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PlatformSensorWin);
diff --git a/services/device/generic_sensor/windows/README.md b/services/device/generic_sensor/windows/README.md
index b8013b7..6fed3d1 100644
--- a/services/device/generic_sensor/windows/README.md
+++ b/services/device/generic_sensor/windows/README.md
@@ -140,64 +140,7 @@
   - Wrapper class around the actual Windows.Devices.Sensors APIs, functional
     equivalent of PlatformSensorReaderWin.
 
-#### 4.2.1 PlatformSensorProviderWinrt
-
-Similar to PlatformSensorProviderWin, but with the ISensorManager
-references removed. This is the header for the class:
-
-```cpp
-class PlatformSensorProviderWinrt final : public PlatformSensorProvider {
- public:
-  static PlatformSensorProviderWinrt* GetInstance();
-
-  void SetSensorReaderCreatorForTesting(
-      std::unique_ptr<SensorReaderCreator> sensor_reader_creator);
-
- protected:
-  ~PlatformSensorProviderWinrt() override;
-
-  // Base class calls this function to create sensor instances.
-  void CreateSensorInternal(mojom::SensorType type,
-                            SensorReadingSharedBuffer* reading_buffer,
-                            const CreateSensorCallback& callback) override;
-
- private:
-  PlatformSensorProviderWinrt();
-
-  std::unique_ptr<PlatformSensorReaderWin> CreateSensorReader(
-      mojom::SensorType type);
-  void SensorReaderCreated(
-      mojom::SensorType type,
-      SensorReadingSharedBuffer* reading_buffer,
-      const CreateSensorCallback& callback,
-      std::unique_ptr<PlatformSensorReaderWin> sensor_reader);
-
-  scoped_refptr<base::SingleThreadTaskRunner> com_sta_task_runner_;
-
-  std::unique_ptr<SensorReaderCreator> sensor_reader_creator_;
-
-  DISALLOW_COPY_AND_ASSIGN(PlatformSensorProviderWinrt);
-};
-```
-
-The `SensorReaderCreator` interface is simply a wrapper around the
-`PlatformSensorReaderWinrt::Create(type)` call and allows unit tests
-to mock it out.
-
-For brevity, the implementation has been deferred to section 8.1 in
-the appendix.
-
-Required mocks for unit testing:
-
-- Create a mock PlatformSensorReaderWinrt class.
-- Mock `PlatformSensorReaderWinrt::Create()` by injecting a
-  `MockSensorReaderCreator` so when PlatformSensorProviderWinrt
-  attempts to create a sensor reader, it returns a mocked instance
-  instead of one that calls into the Windows.Devices.Sensors APIs.
-
-Unit test cases for this class are detailed in section 7.
-
-#### 4.2.2 PlatformSensorReaderWinrt
+#### 4.2.1 PlatformSensorReaderWinrt
 
 The existing PlatformSensorReaderWin class will be pulled out into
 its own interface:
@@ -326,8 +269,8 @@
 ```
 
 The implementation for PlatformSensorReaderWinrtBase and
-PlatformSensorReaderWinrtLightSensor have been deferred to section 8.2
-and 8.3 of the appendix for brevity.
+PlatformSensorReaderWinrtLightSensor have been deferred to section 8.1
+and 8.2 of the appendix for brevity.
 
 Lastly, PlatformSensorReaderWinrt::Create will choose which derived
 PlatformSensorReaderWin class to instantiate based on the requested
@@ -413,24 +356,6 @@
 The modernization changes will be broken down into several incremental
 changes to keep change lists to a reviewable size:
 
-#### Change list 2: Implement PlatformSensorProviderWinrt
-
-- Feature Work:
-  - Fill in the implementation for PlatformSensorProviderWinrt as
-    defined in section 8.1.
-- Testing:
-  - Add unit tests for PlatformSensorProviderWinrt:
-    - Validate `CreateSensorCallback()` is given null if the sensor
-      type does not exist on system. This involves mocking
-      `PlatformSensorReaderWinrt::Create()` so it returns null.
-    - Validate `CreateSensorCallback()` is given non-null if the
-      sensor does exist on system. This involves mocking
-      `PlatformSensorReaderWinrt::Create()` so it returns a non-null
-      PlatformSensorReaderWinrt.
-    - Validate `CreateSensorCallback()` is given null if the sensor
-      type is not supported (e.g. SensorType::PRESSURE). This involves
-      mocking `PlatformSensorReaderWinrt::Create()` so it returns null.
-
 #### Change list 3: Define the interface for PlatformSensorReaderWinBase and implement PlatformSensorReaderWinrtBase
 
 - Feature Work:
@@ -500,101 +425,7 @@
 
 ## 8. Appendix
 
-### 8.1 PlatformSensorProviderWinrt Implementation
-
-`platform_sensor_provider_winrt.h`
-
-Located in section 4.2.1 above.
-
-`platform_sensor_provider_winrt.cc`
-
-```cpp
-std::unique_ptr<PlatformSensorReaderWin>
-SensorReaderCreator::CreateSensorReader(mojom::SensorType type) {
-  return PlatformSensorReaderWinrt::Create(type);
-}
-
-PlatformSensorProviderWinrt::PlatformSensorProviderWinrt() = default;
-
-PlatformSensorProviderWinrt::~PlatformSensorProviderWinrt() = default;
-
-void PlatformSensorProviderWinrt::SetSensorReaderCreatorForTesting(
-    std::unique_ptr<SensorReaderCreator> sensor_reader_creator) {
-  sensor_reader_creator_ = std::move(sensor_reader_creator);
-}
-
-void PlatformSensorProviderWinrt::CreateSensorInternal(
-    mojom::SensorType type,
-    SensorReadingSharedBuffer* reading_buffer,
-    const CreateSensorCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  switch (type) {
-    // Fusion sensor.
-    case mojom::SensorType::LINEAR_ACCELERATION: {
-      auto linear_acceleration_fusion_algorithm = std::make_unique<
-          LinearAccelerationFusionAlgorithmUsingAccelerometer>();
-      // If this PlatformSensorFusion object is successfully initialized,
-      // |callback| will be run with a reference to this object.
-      PlatformSensorFusion::Create(
-          reading_buffer, this, std::move(linear_acceleration_fusion_algorithm),
-          callback);
-      break;
-    }
-
-    // Try to create low-level sensors by default.
-    default: {
-      base::PostTaskAndReplyWithResult(
-          com_sta_task_runner_.get(), FROM_HERE,
-          base::Bind(&PlatformSensorProviderWinrt::CreateSensorReader,
-                     base::Unretained(this), type),
-          base::Bind(&PlatformSensorProviderWinrt::SensorReaderCreated,
-                     base::Unretained(this), type, reading_buffer, callback));
-      break;
-    }
-  }
-}
-
-void PlatformSensorProviderWinrt::SensorReaderCreated(
-    mojom::SensorType type,
-    SensorReadingSharedBuffer* reading_buffer,
-    const CreateSensorCallback& callback,
-    std::unique_ptr<PlatformSensorReaderWin> sensor_reader) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!sensor_reader) {
-    // Fallback options for sensors that can be implemented using sensor
-    // fusion. Note that it is important not to generate a cycle by adding a
-    // fallback here that depends on one of the other fallbacks provided.
-    switch (type) {
-      case mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES: {
-        auto algorithm = std::make_unique<
-            OrientationEulerAnglesFusionAlgorithmUsingQuaternion>(
-            true /* absolute */);
-        PlatformSensorFusion::Create(reading_buffer, this, std::move(algorithm),
-                                     std::move(callback));
-        return;
-      }
-      default:
-        callback.Run(nullptr);
-        return;
-    }
-  }
-
-  scoped_refptr<PlatformSensor> sensor =
-      new PlatformSensorWin(type, reading_buffer, this, com_sta_task_runner_,
-                            std::move(sensor_reader));
-  callback.Run(sensor);
-}
-
-std::unique_ptr<PlatformSensorReaderWin>
-PlatformSensorProviderWinrt::CreateSensorReader(mojom::SensorType type) {
-  DCHECK(com_sta_task_runner_->RunsTasksInCurrentSequence());
-
-  return sensor_reader_creator_->CreateSensorReader(type);
-}
-```
-
-### 8.2 PlatformSensorReaderWinrtBase Implementation
+### 8.1 PlatformSensorReaderWinrtBase Implementation
 
 `platform_sensor_reader_winrt.h`:
 
@@ -799,7 +630,7 @@
 }
 ```
 
-### 8.3 PlatformSensorReaderWinrtLightSensor Implementation
+### 8.2 PlatformSensorReaderWinrtLightSensor Implementation
 
 `platform_sensor_reader_winrt.h`:
 
diff --git a/services/device/serial/serial_port_impl.cc b/services/device/serial/serial_port_impl.cc
index febf68c7..520989d3 100644
--- a/services/device/serial/serial_port_impl.cc
+++ b/services/device/serial/serial_port_impl.cc
@@ -46,7 +46,11 @@
   }
 }
 
-SerialPortImpl::~SerialPortImpl() = default;
+SerialPortImpl::~SerialPortImpl() {
+  // Cancel I/O operations so that |io_handler_| drops its self-reference.
+  io_handler_->CancelRead(mojom::SerialReceiveError::DISCONNECTED);
+  io_handler_->CancelWrite(mojom::SerialSendError::DISCONNECTED);
+}
 
 void SerialPortImpl::Open(mojom::SerialConnectionOptionsPtr options,
                           mojo::ScopedDataPipeConsumerHandle in_stream,
diff --git a/services/media_session/public/cpp/BUILD.gn b/services/media_session/public/cpp/BUILD.gn
index 205447c7..fbfd9576c 100644
--- a/services/media_session/public/cpp/BUILD.gn
+++ b/services/media_session/public/cpp/BUILD.gn
@@ -11,6 +11,8 @@
     "media_image.h",
     "media_metadata.cc",
     "media_metadata.h",
+    "media_position.cc",
+    "media_position.h",
   ]
 
   deps = [
@@ -19,6 +21,7 @@
     "//url",
   ]
 
+  # TODO: Remove this (http://crbug.com/101600).
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
   if (is_android) {
@@ -56,6 +59,7 @@
     "//url",
   ]
 
+  # TODO: Remove this (http://crbug.com/101600).
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
   defines = [ "IS_MEDIA_SESSION_CPP_IMPL" ]
@@ -66,6 +70,7 @@
 
   sources = [
     "media_image_manager_unittest.cc",
+    "media_position_unittest.cc",
   ]
 
   deps = [
diff --git a/services/media_session/public/cpp/media_position.cc b/services/media_session/public/cpp/media_position.cc
new file mode 100644
index 0000000..035dad38
--- /dev/null
+++ b/services/media_session/public/cpp/media_position.cc
@@ -0,0 +1,49 @@
+// Copyright 2019 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 "services/media_session/public/cpp/media_position.h"
+
+namespace media_session {
+
+MediaPosition::MediaPosition() = default;
+
+MediaPosition::MediaPosition(double playback_rate,
+                             base::TimeDelta duration,
+                             base::TimeDelta position)
+    : playback_rate_(playback_rate),
+      duration_(duration),
+      position_(position),
+      last_updated_time_(base::Time::Now()) {
+  DCHECK(duration_ >= base::TimeDelta::FromSeconds(0));
+  DCHECK(position_ >= base::TimeDelta::FromSeconds(0));
+  DCHECK(position_ <= duration_);
+}
+
+MediaPosition::~MediaPosition() = default;
+
+base::TimeDelta MediaPosition::duration() const {
+  return duration_;
+}
+
+base::TimeDelta MediaPosition::GetPosition() const {
+  return GetPositionAtTime(base::Time::Now());
+}
+
+base::TimeDelta MediaPosition::GetPositionAtTime(base::Time time) const {
+  DCHECK(time >= last_updated_time_);
+
+  base::TimeDelta elapsed_time = playback_rate_ * (time - last_updated_time_);
+  base::TimeDelta updated_position = position_ + elapsed_time;
+
+  base::TimeDelta start = base::TimeDelta::FromSeconds(0);
+
+  if (updated_position <= start)
+    return start;
+  else if (updated_position >= duration_)
+    return duration_;
+  else
+    return updated_position;
+}
+
+}  // namespace media_session
diff --git a/services/media_session/public/cpp/media_position.h b/services/media_session/public/cpp/media_position.h
new file mode 100644
index 0000000..548586b
--- /dev/null
+++ b/services/media_session/public/cpp/media_position.h
@@ -0,0 +1,68 @@
+// Copyright 2019 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 SERVICES_MEDIA_SESSION_PUBLIC_CPP_MEDIA_POSITION_H_
+#define SERVICES_MEDIA_SESSION_PUBLIC_CPP_MEDIA_POSITION_H_
+
+#include "base/component_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/time/time.h"
+
+namespace mojo {
+template <typename DataViewType, typename T>
+struct StructTraits;
+}
+
+namespace media_session {
+
+namespace mojom {
+class MediaPositionDataView;
+}
+
+struct COMPONENT_EXPORT(MEDIA_SESSION_BASE_CPP) MediaPosition {
+ public:
+  MediaPosition();
+  MediaPosition(double playback_rate,
+                base::TimeDelta duration,
+                base::TimeDelta position);
+  ~MediaPosition();
+
+  // Return the duration of the media.
+  base::TimeDelta duration() const;
+
+  // Return the current position of the media.
+  base::TimeDelta GetPosition() const;
+
+ private:
+  friend struct mojo::StructTraits<mojom::MediaPositionDataView, MediaPosition>;
+  friend class MediaPositionTest;
+  FRIEND_TEST_ALL_PREFIXES(MediaPositionTest, TestPositionUpdated);
+  FRIEND_TEST_ALL_PREFIXES(MediaPositionTest, TestPositionUpdatedTwice);
+  FRIEND_TEST_ALL_PREFIXES(MediaPositionTest, TestPositionUpdatedPastDuration);
+  FRIEND_TEST_ALL_PREFIXES(MediaPositionTest, TestNegativePosition);
+  FRIEND_TEST_ALL_PREFIXES(MediaPositionTest,
+                           TestPositionUpdatedFasterPlayback);
+  FRIEND_TEST_ALL_PREFIXES(MediaPositionTest,
+                           TestPositionUpdatedSlowerPlayback);
+
+  // Return the updated position of the media, assuming current time is
+  // |time|.
+  base::TimeDelta GetPositionAtTime(base::Time time) const;
+
+  // Playback rate of the media.
+  double playback_rate_;
+
+  // Duration of the media.
+  base::TimeDelta duration_;
+
+  // Last updated position of the media.
+  base::TimeDelta position_;
+
+  // Last time |position_| was updated.
+  base::Time last_updated_time_;
+};
+
+}  // namespace media_session
+
+#endif  // SERVICES_MEDIA_SESSION_PUBLIC_CPP_MEDIA_POSITION_H_
diff --git a/services/media_session/public/cpp/media_position_unittest.cc b/services/media_session/public/cpp/media_position_unittest.cc
new file mode 100644
index 0000000..e7e7192f
--- /dev/null
+++ b/services/media_session/public/cpp/media_position_unittest.cc
@@ -0,0 +1,107 @@
+// Copyright 2019 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 "services/media_session/public/cpp/media_position.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media_session {
+
+class MediaPositionTest : public testing::Test {};
+
+TEST_F(MediaPositionTest, TestPositionUpdated) {
+  MediaPosition media_position(
+      1 /* playback_rate */, base::TimeDelta::FromSeconds(600) /* duration */,
+      base::TimeDelta::FromSeconds(300) /* position */);
+
+  base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(100);
+  base::TimeDelta updated_position = media_position.GetPositionAtTime(now);
+
+  EXPECT_EQ(updated_position.InSeconds(), 400);
+}
+
+TEST_F(MediaPositionTest, TestPositionUpdatedTwice) {
+  MediaPosition media_position(
+      1 /* playback_rate */, base::TimeDelta::FromSeconds(600) /* duration */,
+      base::TimeDelta::FromSeconds(200) /* position */);
+
+  base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(100);
+  base::TimeDelta updated_position = media_position.GetPositionAtTime(now);
+
+  EXPECT_EQ(updated_position.InSeconds(), 300);
+
+  now += base::TimeDelta::FromSeconds(100);
+  updated_position = media_position.GetPositionAtTime(now);
+
+  EXPECT_EQ(updated_position.InSeconds(), 400);
+}
+
+TEST_F(MediaPositionTest, TestPositionUpdatedPastDuration) {
+  MediaPosition media_position(
+      1 /* playback_rate */, base::TimeDelta::FromSeconds(600) /* duration */,
+      base::TimeDelta::FromSeconds(300) /* position */);
+
+  base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(400);
+  base::TimeDelta updated_position = media_position.GetPositionAtTime(now);
+
+  // Verify that the position has been updated to the end of the total duration.
+  EXPECT_EQ(updated_position.InSeconds(), 600);
+}
+
+TEST_F(MediaPositionTest, TestPositionAtStart) {
+  MediaPosition media_position(1 /* playback_rate */,
+                               base::TimeDelta::FromSeconds(600) /* duration */,
+                               base::TimeDelta::FromSeconds(0) /* position */);
+
+  base::TimeDelta updated_position = media_position.GetPosition();
+
+  EXPECT_EQ(updated_position.InSeconds(), 0);
+}
+
+TEST_F(MediaPositionTest, TestNegativePosition) {
+  MediaPosition media_position(
+      -1 /* playback_rate */, base::TimeDelta::FromSeconds(600) /* duration */,
+      base::TimeDelta::FromSeconds(300) /* position */);
+
+  base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(400);
+  base::TimeDelta updated_position = media_position.GetPositionAtTime(now);
+
+  // Verify that the position does not go below 0.
+  EXPECT_EQ(updated_position.InSeconds(), 0);
+}
+
+TEST_F(MediaPositionTest, TestPositionUpdatedNoChange) {
+  MediaPosition media_position(
+      1 /* playback_rate */, base::TimeDelta::FromSeconds(600) /* duration */,
+      base::TimeDelta::FromSeconds(300) /* position */);
+
+  // Get the updated position without moving forward in time.
+  base::TimeDelta updated_position = media_position.GetPosition();
+
+  // Verify that the updated position has not changed.
+  EXPECT_EQ(updated_position.InSeconds(), 300);
+}
+
+TEST_F(MediaPositionTest, TestPositionUpdatedFasterPlayback) {
+  MediaPosition media_position(
+      2 /* playback_rate */, base::TimeDelta::FromSeconds(600) /* duration */,
+      base::TimeDelta::FromSeconds(300) /* position */);
+
+  base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(100);
+  base::TimeDelta updated_position = media_position.GetPositionAtTime(now);
+
+  EXPECT_EQ(updated_position.InSeconds(), 500);
+}
+
+TEST_F(MediaPositionTest, TestPositionUpdatedSlowerPlayback) {
+  MediaPosition media_position(
+      .5 /* playback_rate */, base::TimeDelta::FromSeconds(600) /* duration */,
+      base::TimeDelta::FromSeconds(300) /* position */);
+
+  base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(200);
+  base::TimeDelta updated_position = media_position.GetPositionAtTime(now);
+
+  EXPECT_EQ(updated_position.InSeconds(), 400);
+}
+}  // namespace media_session
\ No newline at end of file
diff --git a/services/media_session/public/cpp/media_session.typemap b/services/media_session/public/cpp/media_session.typemap
index ca4ad18..30e168dc 100644
--- a/services/media_session/public/cpp/media_session.typemap
+++ b/services/media_session/public/cpp/media_session.typemap
@@ -6,6 +6,7 @@
 public_headers = [
   "//services/media_session/public/cpp/media_image.h",
   "//services/media_session/public/cpp/media_metadata.h",
+  "//services/media_session/public/cpp/media_position.h",
   "//third_party/skia/include/core/SkBitmap.h",
 ]
 traits_headers =
@@ -21,6 +22,7 @@
   "media_session.mojom.MediaImage=media_session::MediaImage",
   "media_session.mojom.MediaImageBitmap=SkBitmap[nullable_is_same_type]",
   "media_session.mojom.MediaMetadata=media_session::MediaMetadata",
+  "media_session.mojom.MediaPosition=media_session::MediaPosition",
 ]
 sources = [
   "//services/media_session/public/cpp/media_session_mojom_traits.cc",
diff --git a/services/media_session/public/cpp/media_session_mojom_traits.cc b/services/media_session/public/cpp/media_session_mojom_traits.cc
index baf2208..fe165ff 100644
--- a/services/media_session/public/cpp/media_session_mojom_traits.cc
+++ b/services/media_session/public/cpp/media_session_mojom_traits.cc
@@ -5,6 +5,7 @@
 #include "services/media_session/public/cpp/media_session_mojom_traits.h"
 
 #include "mojo/public/cpp/base/string16_mojom_traits.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
 #include "url/mojom/url_gurl_mojom_traits.h"
@@ -90,4 +91,23 @@
   out->reset();
 }
 
+// static
+bool StructTraits<media_session::mojom::MediaPositionDataView,
+                  media_session::MediaPosition>::
+    Read(media_session::mojom::MediaPositionDataView data,
+         media_session::MediaPosition* out) {
+  if (!data.ReadDuration(&out->duration_))
+    return false;
+
+  if (!data.ReadPosition(&out->position_))
+    return false;
+
+  if (!data.ReadLastUpdatedTime(&out->last_updated_time_))
+    return false;
+
+  out->playback_rate_ = data.playback_rate();
+
+  return true;
+}
+
 }  // namespace mojo
diff --git a/services/media_session/public/cpp/media_session_mojom_traits.h b/services/media_session/public/cpp/media_session_mojom_traits.h
index 8dd53c50..4fc5673 100644
--- a/services/media_session/public/cpp/media_session_mojom_traits.h
+++ b/services/media_session/public/cpp/media_session_mojom_traits.h
@@ -73,6 +73,33 @@
   static void SetToNull(SkBitmap* out);
 };
 
+template <>
+struct StructTraits<media_session::mojom::MediaPositionDataView,
+                    media_session::MediaPosition> {
+  static double playback_rate(
+      const media_session::MediaPosition& media_position) {
+    return media_position.playback_rate_;
+  }
+
+  static base::TimeDelta duration(
+      const media_session::MediaPosition& media_position) {
+    return media_position.duration_;
+  }
+
+  static base::TimeDelta position(
+      const media_session::MediaPosition& media_position) {
+    return media_position.position_;
+  }
+
+  static base::Time last_updated_time(
+      const media_session::MediaPosition& media_position) {
+    return media_position.last_updated_time_;
+  }
+
+  static bool Read(media_session::mojom::MediaPositionDataView data,
+                   media_session::MediaPosition* out);
+};
+
 }  // namespace mojo
 
 #endif  // SERVICES_MEDIA_SESSION_PUBLIC_CPP_MEDIA_SESSION_MOJOM_TRAITS_H_
diff --git a/services/media_session/public/mojom/media_session.mojom b/services/media_session/public/mojom/media_session.mojom
index 32477dac..d7b254c 100644
--- a/services/media_session/public/mojom/media_session.mojom
+++ b/services/media_session/public/mojom/media_session.mojom
@@ -70,6 +70,13 @@
   array<uint8> pixel_data;  // Must be ARGB_8888
 };
 
+struct MediaPosition {
+  double playback_rate;
+  mojo_base.mojom.TimeDelta duration;
+  mojo_base.mojom.TimeDelta position;
+  mojo_base.mojom.Time last_updated_time;
+};
+
 // Contains state information about a MediaSession.
 struct MediaSessionInfo {
   [Extensible]
diff --git a/services/network/public/cpp/network_isolation_key_mojom_traits.cc b/services/network/public/cpp/network_isolation_key_mojom_traits.cc
index 077c5bd8..707762a 100644
--- a/services/network/public/cpp/network_isolation_key_mojom_traits.cc
+++ b/services/network/public/cpp/network_isolation_key_mojom_traits.cc
@@ -19,7 +19,7 @@
   // given the flags set).  The constructor verifies this, so if the top-frame
   // origin is populated, we call the full constructor, otherwise, the empty.
   if (top_frame_origin.has_value()) {
-    *out = net::NetworkIsolationKey(top_frame_origin, frame_origin);
+    *out = net::NetworkIsolationKey(top_frame_origin.value(), frame_origin);
   } else {
     *out = net::NetworkIsolationKey();
   }
diff --git a/services/viz/privileged/interfaces/compositing/renderer_settings.mojom b/services/viz/privileged/interfaces/compositing/renderer_settings.mojom
index 2296f9a..dc958b91 100644
--- a/services/viz/privileged/interfaces/compositing/renderer_settings.mojom
+++ b/services/viz/privileged/interfaces/compositing/renderer_settings.mojom
@@ -20,7 +20,6 @@
   bool show_overdraw_feedback;
   int32 slow_down_compositing_scale_factor;
   bool use_skia_renderer;
-  bool use_skia_renderer_non_ddl;
   bool record_sk_picture;
   bool allow_overlays;
   bool requires_alpha_channel;
diff --git a/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc b/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc
index d835807..e4dea1fa 100644
--- a/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc
+++ b/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc
@@ -29,7 +29,6 @@
   out->slow_down_compositing_scale_factor =
       data.slow_down_compositing_scale_factor();
   out->use_skia_renderer = data.use_skia_renderer();
-  out->use_skia_renderer_non_ddl = data.use_skia_renderer_non_ddl();
   out->record_sk_picture = data.record_sk_picture();
   out->allow_overlays = data.allow_overlays();
   out->requires_alpha_channel = data.requires_alpha_channel();
diff --git a/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h b/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h
index 50cfa55..a26c961 100644
--- a/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h
+++ b/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h
@@ -67,10 +67,6 @@
     return input.use_skia_renderer;
   }
 
-  static bool use_skia_renderer_non_ddl(const viz::RendererSettings& input) {
-    return input.use_skia_renderer_non_ddl;
-  }
-
   static bool record_sk_picture(const viz::RendererSettings& input) {
     return input.record_sk_picture;
   }
diff --git a/services/viz/privileged/interfaces/struct_traits_unittest.cc b/services/viz/privileged/interfaces/struct_traits_unittest.cc
index cdd68da..adf8ce1 100644
--- a/services/viz/privileged/interfaces/struct_traits_unittest.cc
+++ b/services/viz/privileged/interfaces/struct_traits_unittest.cc
@@ -29,7 +29,6 @@
   input.show_overdraw_feedback = true;
   input.highp_threshold_min = -1;
   input.use_skia_renderer = true;
-  input.use_skia_renderer_non_ddl = true;
 
   RendererSettings output;
   mojom::RendererSettings::Deserialize(
@@ -48,7 +47,6 @@
   EXPECT_EQ(input.show_overdraw_feedback, output.show_overdraw_feedback);
   EXPECT_EQ(input.highp_threshold_min, output.highp_threshold_min);
   EXPECT_EQ(input.use_skia_renderer, output.use_skia_renderer);
-  EXPECT_EQ(input.use_skia_renderer_non_ddl, output.use_skia_renderer_non_ddl);
 }
 
 }  // namespace
diff --git a/testing/buildbot/filters/navigation_loader_on_ui_browser_tests.filter b/testing/buildbot/filters/navigation_loader_on_ui_browser_tests.filter
index aff1fc06..a2622d1 100644
--- a/testing/buildbot/filters/navigation_loader_on_ui_browser_tests.filter
+++ b/testing/buildbot/filters/navigation_loader_on_ui_browser_tests.filter
@@ -41,10 +41,6 @@
 -DiceBrowserTest.SignoutMainAccount
 -DiceBrowserTest.SignoutSecondaryAccount
 
-# http://crbug.com/824856
--NoStatePrefetchBrowserTest.AppCacheHtmlInitialized
--NoStatePrefetchBrowserTest.AppCacheRegistered
-
 # http://crbug.com/824854
 -ChromeAcceptHeaderTest.Check
 -SignedExchangePageLoadMetricsBrowserTest.UkmSignedExchangeMetric
diff --git a/testing/buildbot/filters/navigation_loader_on_ui_content_browsertests.filter b/testing/buildbot/filters/navigation_loader_on_ui_content_browsertests.filter
index 7365533..af346360 100644
--- a/testing/buildbot/filters/navigation_loader_on_ui_content_browsertests.filter
+++ b/testing/buildbot/filters/navigation_loader_on_ui_content_browsertests.filter
@@ -1,17 +1,5 @@
 # These tests currently fail when run with --enable-features=NavigationLoaderOnUI
 
-# http://crbug.com/824856
--AppCacheNetworkServiceBrowserTest.CacheableResourcesReuse
--WithOutOfBlinkCors/CrossSiteDocumentBlockingTest.AppCache_InitiatorEnforcement/0
--WithOutOfBlinkCors/CrossSiteDocumentBlockingTest.AppCache_NetworkFallback/0
--WithOutOfBlinkCors/CrossSiteDocumentBlockingTest.AppCache_NoNavigationsEnforcement/0
--WithoutCORBProtectionSniffing/CrossSiteDocumentBlockingTest.AppCache_InitiatorEnforcement/0
--WithoutCORBProtectionSniffing/CrossSiteDocumentBlockingTest.AppCache_NetworkFallback/0
--WithoutCORBProtectionSniffing/CrossSiteDocumentBlockingTest.AppCache_NoNavigationsEnforcement/0
--WithoutOutOfBlinkCors/CrossSiteDocumentBlockingTest.AppCache_InitiatorEnforcement/0
--WithoutOutOfBlinkCors/CrossSiteDocumentBlockingTest.AppCache_NetworkFallback/0
--WithoutOutOfBlinkCors/CrossSiteDocumentBlockingTest.AppCache_NoNavigationsEnforcement/0
-
 # http://crbug.com/824858
 -AcceptHeaderTest.Check
 -ReloadCacheControlBrowserTest.BypassingReload_ControlledByServiceWorker
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 1ee1037..6ce01b2 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -330,7 +330,7 @@
     "BlinkHeapConcurrentMarking", base::FEATURE_DISABLED_BY_DEFAULT};
 // Enables concurrently sweeping Blink's heap.
 const base::Feature kBlinkHeapConcurrentSweeping{
-    "BlinkHeapConcurrentSweeping", base::FEATURE_DISABLED_BY_DEFAULT};
+    "BlinkHeapConcurrentSweeping", base::FEATURE_ENABLED_BY_DEFAULT};
 // Enables incrementally marking Blink's heap.
 const base::Feature kBlinkHeapIncrementalMarking{
     "BlinkHeapIncrementalMarking", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/mojom/contacts/contacts_manager.mojom b/third_party/blink/public/mojom/contacts/contacts_manager.mojom
index d0bd9eb..37fdadeb 100644
--- a/third_party/blink/public/mojom/contacts/contacts_manager.mojom
+++ b/third_party/blink/public/mojom/contacts/contacts_manager.mojom
@@ -4,7 +4,7 @@
 
 module blink.mojom;
 
-// As per https://github.com/beverloo/contact-api.
+// As per https://wicg.github.io/contact-api/spec/.
 struct ContactInfo {
   array<string>? name;
   array<string>? email;
diff --git a/third_party/blink/public/mojom/frame/find_in_page.mojom b/third_party/blink/public/mojom/frame/find_in_page.mojom
index 72a2000b..096495d 100644
--- a/third_party/blink/public/mojom/frame/find_in_page.mojom
+++ b/third_party/blink/public/mojom/frame/find_in_page.mojom
@@ -40,7 +40,7 @@
   // Sets the client for this FindInPage instance. Should be called before
   // calling ActivateNearestFindResult.
   // TODO(rakina): Remove the need for this?
-  SetClient(FindInPageClient client);
+  SetClient(pending_remote<FindInPageClient> client);
 
   // Returns the bounding boxes of the find-in-page match markers from the
   // frame. The bounding boxes are returned in find-in-page coordinates.
diff --git a/third_party/blink/public/web/modules/mediastream/local_media_stream_audio_source.h b/third_party/blink/public/web/modules/mediastream/local_media_stream_audio_source.h
index e1c9761..7ed542d 100644
--- a/third_party/blink/public/web/modules/mediastream/local_media_stream_audio_source.h
+++ b/third_party/blink/public/web/modules/mediastream/local_media_stream_audio_source.h
@@ -52,7 +52,7 @@
   // media::AudioCapturerSource::CaptureCallback implementation.
   void OnCaptureStarted() final;
   void Capture(const media::AudioBus* audio_bus,
-               int audio_delay_milliseconds,
+               base::TimeTicks audio_capture_time,
                double volume,
                bool key_pressed) final;
   void OnCaptureError(const std::string& message) final;
diff --git a/third_party/blink/renderer/core/display_lock/BUILD.gn b/third_party/blink/renderer/core/display_lock/BUILD.gn
index db3d6ed0..9d286cf 100644
--- a/third_party/blink/renderer/core/display_lock/BUILD.gn
+++ b/third_party/blink/renderer/core/display_lock/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//testing/libfuzzer/fuzzer_test.gni")
 import("//third_party/blink/renderer/core/core.gni")
 
 blink_core_sources("display_lock") {
@@ -26,3 +27,15 @@
     "//third_party/blink/renderer/bindings/core/v8:bindings_core_v8_generated",
   ]
 }
+
+fuzzer_test("display_lock_fuzzer") {
+  sources = [
+    "display_lock_fuzzer.cc",
+  ]
+  deps = [
+    "//content/test/fuzzer:fuzzer_support",
+  ]
+
+  seed_corpus = "//third_party/blink/web_tests/wpt_internal/display-lock"
+  dict = "display_lock.dict"
+}
diff --git a/third_party/blink/renderer/core/display_lock/DEPS b/third_party/blink/renderer/core/display_lock/DEPS
new file mode 100644
index 0000000..df774af
--- /dev/null
+++ b/third_party/blink/renderer/core/display_lock/DEPS
@@ -0,0 +1,3 @@
+specific_include_rules = {
+  "display_lock_fuzzer.cc" : [ "+content/test/fuzzer/fuzzer_support.h" ],
+}
diff --git a/third_party/blink/renderer/core/display_lock/display_lock.dict b/third_party/blink/renderer/core/display_lock/display_lock.dict
new file mode 100644
index 0000000..e8d5357
--- /dev/null
+++ b/third_party/blink/renderer/core/display_lock/display_lock.dict
@@ -0,0 +1,11 @@
+"displayLock.acquire"
+"displayLock.commit()"
+"displayLock.update()"
+"displayLock.updateAndCommit()"
+"activatable: true"
+"activatable: false"
+"timeout: Infinity"
+"timeout: 0"
+"timeout: 17"
+"size: [100, 100]"
+"contain: style layout"
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index 36e04a0..31d52cb 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -4,6 +4,11 @@
 
 #include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
 
+#include <memory>
+#include <utility>
+
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/display_lock/display_lock_options.h"
@@ -27,17 +32,12 @@
 class DisplayLockTestFindInPageClient : public mojom::blink::FindInPageClient {
  public:
   DisplayLockTestFindInPageClient()
-      : find_results_are_ready_(false),
-        active_index_(-1),
-        count_(-1),
-        binding_(this) {}
+      : find_results_are_ready_(false), active_index_(-1), count_(-1) {}
 
   ~DisplayLockTestFindInPageClient() override = default;
 
   void SetFrame(WebLocalFrameImpl* frame) {
-    mojom::blink::FindInPageClientPtr client;
-    binding_.Bind(MakeRequest(&client));
-    frame->GetFindInPage()->SetClient(std::move(client));
+    frame->GetFindInPage()->SetClient(receiver_.BindNewPipeAndPassRemote());
   }
 
   void SetNumberOfMatches(
@@ -77,7 +77,7 @@
   int active_index_;
 
   int count_;
-  mojo::Binding<mojom::blink::FindInPageClient> binding_;
+  mojo::Receiver<mojom::blink::FindInPageClient> receiver_{this};
 };
 
 class DisplayLockEmptyEventListener final : public NativeEventListener {
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_fuzzer.cc b/third_party/blink/renderer/core/display_lock/display_lock_fuzzer.cc
new file mode 100644
index 0000000..03ab9065
--- /dev/null
+++ b/third_party/blink/renderer/core/display_lock/display_lock_fuzzer.cc
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/test/fuzzer/fuzzer_support.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_view.h"
+#include "third_party/blink/public/web/web_widget.h"
+
+static content::Env* env;
+
+bool Initialize() {
+  blink::WebRuntimeFeatures::EnableDisplayLocking(true);
+  env = new content::Env();
+  return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  static bool initialized = Initialize();
+  // Suppress unused variable warning.
+  (void)initialized;
+
+  // Only handle reasonable size inputs.
+  if (size < 1 || size > 10000)
+    return 0;
+
+  std::string data_as_string(reinterpret_cast<const char*>(data), size);
+  int num_rafs = std::hash<std::string>()(data_as_string) % 10;
+  env->adapter->LoadHTML(data_as_string, "");
+
+  // Delay each frame 17ms which is roughly the length of a frame when running
+  // at 60fps.
+  auto frame_delay = base::TimeDelta::FromMillisecondsD(17);
+
+  for (int i = 0; i < num_rafs; ++i) {
+    base::RunLoop run_loop;
+    blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(), frame_delay);
+    run_loop.Run();
+
+    env->adapter->GetMainFrame()
+        ->View()
+        ->MainFrameWidget()
+        ->UpdateAllLifecyclePhases(
+            blink::WebWidget::LifecycleUpdateReason::kTest);
+  }
+  return 0;
+}
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index 534d545..d151d4d 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -40,6 +40,8 @@
 #include "cc/input/overscroll_behavior.h"
 #include "cc/layers/picture_layer.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
@@ -4802,17 +4804,12 @@
 class TestFindInPageClient : public mojom::blink::FindInPageClient {
  public:
   TestFindInPageClient()
-      : find_results_are_ready_(false),
-        count_(-1),
-        active_index_(-1),
-        binding_(this) {}
+      : find_results_are_ready_(false), count_(-1), active_index_(-1) {}
 
   ~TestFindInPageClient() override = default;
 
   void SetFrame(WebLocalFrameImpl* frame) {
-    mojom::blink::FindInPageClientPtr client;
-    binding_.Bind(MakeRequest(&client));
-    frame->GetFindInPage()->SetClient(std::move(client));
+    frame->GetFindInPage()->SetClient(receiver_.BindNewPipeAndPassRemote());
   }
 
   void SetNumberOfMatches(
@@ -4841,7 +4838,7 @@
   bool find_results_are_ready_;
   int count_;
   int active_index_;
-  mojo::Binding<mojom::blink::FindInPageClient> binding_;
+  mojo::Receiver<mojom::blink::FindInPageClient> receiver_{this};
 };
 
 TEST_F(WebFrameTest, FindInPageMatchRects) {
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index 75f104d..72411b5 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -571,6 +571,14 @@
               ReplacedWillBeRemoved("Atomics.wake", "Atomics.notify", kM76,
                                     "6228189936353280")};
 
+    case WebFeature::kVRGetDisplays:
+      return {"WebVR", kM79,
+              String::Format("WebVR is deprecated and will be removed as soon "
+                             "as %s. Please use WebXR instead.  See "
+                             "https://www.chromestatus.com/feature/"
+                             "4532810371039232 for details.",
+                             MilestoneString(kM79))};
+
     // Features that aren't deprecated don't have a deprecation message.
     default:
       return {"NotDeprecated", kUnknown, ""};
diff --git a/third_party/blink/renderer/core/frame/find_in_page.cc b/third_party/blink/renderer/core/frame/find_in_page.cc
index 654049c..ddbbb1c3 100644
--- a/third_party/blink/renderer/core/frame/find_in_page.cc
+++ b/third_party/blink/renderer/core/frame/find_in_page.cc
@@ -30,6 +30,8 @@
 
 #include "third_party/blink/renderer/core/frame/find_in_page.h"
 
+#include <utility>
+
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_local_frame_client.h"
 #include "third_party/blink/public/web/web_plugin.h"
@@ -45,15 +47,15 @@
 
 FindInPage::FindInPage(WebLocalFrameImpl& frame,
                        InterfaceRegistry* interface_registry)
-    : frame_(&frame), binding_(this) {
+    : frame_(&frame) {
   // TODO(rakina): Use InterfaceRegistry of |frame| directly rather than passing
   // both of them.
   if (!interface_registry)
     return;
   // TODO(crbug.com/800641): Use InterfaceValidator when it works for associated
   // interfaces.
-  interface_registry->AddAssociatedInterface(
-      WTF::BindRepeating(&FindInPage::BindToRequest, WrapWeakPersistent(this)));
+  interface_registry->AddAssociatedInterface(WTF::BindRepeating(
+      &FindInPage::BindToReceiver, WrapWeakPersistent(this)));
 }
 
 void FindInPage::Find(int request_id,
@@ -229,8 +231,12 @@
                             true /* final_update */);
 }
 
-void FindInPage::SetClient(mojom::blink::FindInPageClientPtr client) {
-  client_ = std::move(client);
+void FindInPage::SetClient(
+    mojo::PendingRemote<mojom::blink::FindInPageClient> remote) {
+  // TODO(crbug.com/984878): Having to call reset() to try to bind a remote that
+  // might be bound is questionable behavior and suggests code may be buggy.
+  client_.reset();
+  client_.Bind(std::move(remote));
 }
 
 void FindInPage::GetNearestFindResult(const WebFloatPoint& point,
@@ -303,14 +309,14 @@
   return nullptr;
 }
 
-void FindInPage::BindToRequest(
-    mojom::blink::FindInPageAssociatedRequest request) {
-  binding_.Bind(std::move(request),
-                frame_->GetTaskRunner(blink::TaskType::kInternalDefault));
+void FindInPage::BindToReceiver(
+    mojo::PendingAssociatedReceiver<mojom::blink::FindInPage> receiver) {
+  receiver_.Bind(std::move(receiver),
+                 frame_->GetTaskRunner(blink::TaskType::kInternalDefault));
 }
 
 void FindInPage::Dispose() {
-  binding_.Close();
+  receiver_.reset();
 }
 
 void FindInPage::ReportFindInPageMatchCount(int request_id,
diff --git a/third_party/blink/renderer/core/frame/find_in_page.h b/third_party/blink/renderer/core/frame/find_in_page.h
index 5ed7226..d1cac5d9 100644
--- a/third_party/blink/renderer/core/frame/find_in_page.h
+++ b/third_party/blink/renderer/core/frame/find_in_page.h
@@ -5,7 +5,10 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FIND_IN_PAGE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FIND_IN_PAGE_H_
 
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/frame/find_in_page.mojom-blink.h"
 #include "third_party/blink/public/platform/interface_registry.h"
 #include "third_party/blink/public/platform/web_common.h"
@@ -57,7 +60,7 @@
             const String& search_text,
             mojom::blink::FindOptionsPtr) final;
 
-  void SetClient(mojom::blink::FindInPageClientPtr) final;
+  void SetClient(mojo::PendingRemote<mojom::blink::FindInPageClient>) final;
 
   void ActivateNearestFindResult(int request_id, const WebFloatPoint&) final;
 
@@ -88,7 +91,8 @@
 
   WebPlugin* GetWebPluginForFind();
 
-  void BindToRequest(mojom::blink::FindInPageAssociatedRequest request);
+  void BindToReceiver(
+      mojo::PendingAssociatedReceiver<mojom::blink::FindInPage> receiver);
 
   void Dispose();
 
@@ -105,13 +109,13 @@
 
   const Member<WebLocalFrameImpl> frame_;
 
-  mojom::blink::FindInPageClientPtr client_;
+  mojo::Remote<mojom::blink::FindInPageClient> client_;
 
-  mojo::AssociatedBinding<mojom::blink::FindInPage> binding_;
+  mojo::AssociatedReceiver<mojom::blink::FindInPage> receiver_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FindInPage);
 };
 
 }  // namespace blink
 
-#endif
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FIND_IN_PAGE_H_
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index 10a49c1..d0d9c8a 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -487,10 +487,11 @@
 
   // TODO(crbug.com/927066): We calculate an incorrect intrinsic logical height
   // when percentages are involved, so for now don't apply min-height: auto
-  // in such cases.
+  // in such cases. (This is only a problem if the child has a definite height)
   const LayoutBlock* child_block = DynamicTo<LayoutBlock>(child);
   if (IsColumnFlow() && child_block &&
-      child_block->HasPercentHeightDescendants())
+      child_block->HasPercentHeightDescendants() &&
+      child_block->HasDefiniteLogicalHeight())
     return false;
 
   return !child.ShouldApplySizeContainment() &&
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
index b661a5b7..c23878d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
@@ -69,6 +69,7 @@
       bidi_level_(UBIDI_LTR),
       shape_options_(kPreContext | kPostContext),
       is_empty_item_(false),
+      is_block_level_(false),
       style_variant_(static_cast<unsigned>(NGStyleVariant::kStandard)),
       end_collapse_type_(kNotCollapsible),
       is_end_collapsible_newline_(false),
@@ -91,6 +92,7 @@
       bidi_level_(other.bidi_level_),
       shape_options_(other.shape_options_),
       is_empty_item_(other.is_empty_item_),
+      is_block_level_(other.is_block_level_),
       style_variant_(other.style_variant_),
       end_collapse_type_(other.end_collapse_type_),
       is_end_collapsible_newline_(other.is_end_collapsible_newline_),
@@ -125,6 +127,9 @@
     return;
   }
 
+  if (type_ == kOutOfFlowPositioned || type_ == kFloating)
+    is_block_level_ = true;
+
   is_empty_item_ = true;
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
index 3ef55a46..fa176d1 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
@@ -87,6 +87,13 @@
   bool IsEmptyItem() const { return is_empty_item_; }
   void SetIsEmptyItem(bool value) { is_empty_item_ = value; }
 
+  // If this item is either a float or OOF-positioned node. If an inline
+  // formatting-context *only* contains these types of nodes we consider it
+  // block-level, and run the |NGBlockLayoutAlgorithm| instead of the
+  // |NGInlineLayoutAlgorithm|.
+  bool IsBlockLevel() const { return is_block_level_; }
+  void SetIsBlockLevel(bool value) { is_block_level_ = value; }
+
   // If this item should create a box fragment. Box fragments can be omitted for
   // optimization if this is false.
   bool ShouldCreateBoxFragment() const {
@@ -239,6 +246,7 @@
   unsigned bidi_level_ : 8;              // UBiDiLevel is defined as uint8_t.
   unsigned shape_options_ : 2;
   unsigned is_empty_item_ : 1;
+  unsigned is_block_level_ : 1;
   unsigned style_variant_ : 2;
   unsigned end_collapse_type_ : 2;  // NGCollapseType
   unsigned is_end_collapsible_newline_ : 1;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
index eb15ec9..01e2633 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -245,7 +245,9 @@
   mapping_builder_.AppendIdentityMapping(string.length());
   AppendItem(items_, type, start_offset, text_.length(), layout_object);
   DCHECK(!items_->back().IsEmptyItem());
-  is_empty_inline_ = false;  // text item is not empty.
+  // text item is not empty.
+  is_empty_inline_ = false;
+  is_block_level_ = false;
 }
 
 // Empty text items are not needed for the layout purposes, but all LayoutObject
@@ -260,6 +262,7 @@
   NGInlineItem& item = items_->back();
   item.SetEndCollapseType(NGInlineItem::kOpaqueToCollapsing);
   item.SetIsEmptyItem(true);
+  item.SetIsBlockLevel(true);
 }
 
 // Same as AppendBreakOpportunity, but mark the item as IsGenerated().
@@ -390,6 +393,7 @@
     if (item.StartOffset() == start) {
       items_->push_back(item);
       is_empty_inline_ &= item.IsEmptyItem();
+      is_block_level_ &= item.IsBlockLevel();
       continue;
     }
 
@@ -420,6 +424,7 @@
 
     items_->push_back(adjusted_item);
     is_empty_inline_ &= adjusted_item.IsEmptyItem();
+    is_block_level_ &= adjusted_item.IsBlockLevel();
   }
   return true;
 }
@@ -677,7 +682,9 @@
   NGInlineItem& item = items_->back();
   item.SetEndCollapseType(end_collapse, space_run_has_newline);
   DCHECK(!item.IsEmptyItem());
-  is_empty_inline_ = false;  // text item is not empty.
+  // text item is not empty.
+  is_empty_inline_ = false;
+  is_block_level_ = false;
 }
 
 template <typename OffsetMappingBuilder>
@@ -857,6 +864,7 @@
   AppendItem(items_, type, end_offset - 1, end_offset, layout_object);
 
   is_empty_inline_ &= items_->back().IsEmptyItem();
+  is_block_level_ &= items_->back().IsBlockLevel();
 }
 
 template <typename OffsetMappingBuilder>
@@ -922,6 +930,7 @@
   NGInlineItem& item = items_->back();
   item.SetEndCollapseType(NGInlineItem::kOpaqueToCollapsing);
   is_empty_inline_ &= item.IsEmptyItem();
+  is_block_level_ &= item.IsBlockLevel();
 }
 
 template <typename OffsetMappingBuilder>
@@ -934,6 +943,7 @@
   NGInlineItem& item = items_->back();
   item.SetEndCollapseType(NGInlineItem::kOpaqueToCollapsing);
   is_empty_inline_ &= item.IsEmptyItem();
+  is_block_level_ &= item.IsBlockLevel();
 }
 
 // Removes the collapsible space at the end of |text_| if exists.
@@ -1084,8 +1094,10 @@
   }
 
   if (style->Display() == EDisplay::kListItem &&
-      style->ListStyleType() != EListStyleType::kNone)
+      style->ListStyleType() != EListStyleType::kNone) {
     is_empty_inline_ = false;
+    is_block_level_ = false;
+  }
 }
 
 template <typename OffsetMappingBuilder>
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
index 9645ee7..07abca2 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
@@ -62,6 +62,8 @@
   // <span></span> or <span><float></float></span>.
   bool IsEmptyInline() const { return is_empty_inline_; }
 
+  bool IsBlockLevel() const { return is_block_level_; }
+
   // True if changes to an item may affect different layout of earlier lines.
   // May not be able to use line caches even when the line or earlier lines are
   // not dirty.
@@ -178,6 +180,7 @@
 
   bool has_bidi_controls_ = false;
   bool is_empty_inline_ = true;
+  bool is_block_level_ = true;
   bool changes_may_affect_earlier_lines_ = false;
 
   // Append a character.
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 17cb272..d82beb0f 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
@@ -591,19 +591,16 @@
   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().ForcedBfcBlockOffset())
-    bfc_block_offset = *ConstraintSpace().ForcedBfcBlockOffset();
-
   LayoutUnit bfc_line_offset = container_builder_.BfcLineOffset();
+  LayoutUnit bfc_block_offset = Node().IsEmptyInline()
+                                    ? ConstraintSpace().ExpectedBfcBlockOffset()
+                                    : line_info.BfcOffset().block_offset;
 
   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) {
+    if (child.unpositioned_float) {
       NGPositionedFloat positioned_float = PositionFloat(
           origin_bfc_block_offset, child.unpositioned_float, exclusion_space);
 
@@ -817,8 +814,8 @@
   const LayoutOpportunityVector opportunities =
       initial_exclusion_space.AllLayoutOpportunities(
           {ConstraintSpace().BfcOffset().line_offset,
-           ConstraintSpace().ForcedBfcBlockOffset().value_or(
-               ConstraintSpace().BfcOffset().block_offset)},
+           is_empty_inline ? ConstraintSpace().ExpectedBfcBlockOffset()
+                           : ConstraintSpace().BfcOffset().block_offset},
           ConstraintSpace().AvailableSize().inline_size);
 
   NGExclusionSpace exclusion_space;
@@ -995,13 +992,10 @@
             ? kAdjoiningFloatLeft
             : kAdjoiningFloatRight);
 
-    // If we are an empty inline, and don't have the special forced BFC
-    // block-offset yet, there is no way to position any floats.
-    if (is_empty_inline && !ConstraintSpace().ForcedBfcBlockOffset())
-      continue;
-
+    // Place any floats at the "expected" BFC block-offset, this may be an
+    // optimistic guess.
     LayoutUnit origin_bfc_block_offset =
-        is_empty_inline ? *ConstraintSpace().ForcedBfcBlockOffset()
+        is_empty_inline ? ConstraintSpace().ExpectedBfcBlockOffset()
                         : ConstraintSpace().BfcOffset().block_offset;
 
     NGPositionedFloat positioned_float = PositionFloat(
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 322c77e..4c5014bc 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
@@ -491,6 +491,7 @@
   // doesn't contain any RTL characters.
   data->is_bidi_enabled_ = MayBeBidiEnabled(data->text_content, builder);
   data->is_empty_inline_ = builder.IsEmptyInline();
+  data->is_block_level_ = builder.IsBlockLevel();
   data->changes_may_affect_earlier_lines_ =
       builder.ChangesMayAffectEarlierLines();
 }
@@ -885,13 +886,8 @@
   auto* block_flow = To<LayoutBlockFlow>(fragment.GetMutableLayoutObject());
   if (!block_flow->ChildrenInline())
     return;
+  DCHECK(AreNGBlockFlowChildrenInline(block_flow));
   NGInlineNode node = NGInlineNode(block_flow);
-#if DCHECK_IS_ON()
-  // We assume this function is called for the LayoutObject of an NGInlineNode.
-  NGLayoutInputNode first_child = NGBlockNode(block_flow).FirstChild();
-  DCHECK(first_child && first_child.IsInline());
-  DCHECK(first_child == node);
-#endif
 
   DCHECK(node.IsPrepareLayoutFinished());
   const Vector<NGInlineItem>& items = node.MaybeDirtyData().items;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
index a3bcb07a..e9f6f10 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
@@ -93,6 +93,8 @@
 
   bool IsEmptyInline() { return EnsureData().is_empty_inline_; }
 
+  bool IsBlockLevel() { return EnsureData().is_block_level_; }
+
   // @return if this node can contain the "first formatted line".
   // https://www.w3.org/TR/CSS22/selector.html#first-formatted-line
   bool CanContainFirstFormattedLine() const {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
index 833d639..b7c04d4 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
@@ -21,6 +21,8 @@
 
   bool IsEmptyInline() const { return is_empty_inline_; }
 
+  bool IsBlockLevel() const { return is_block_level_; }
+
  private:
   const NGInlineItemsData& ItemsData(bool is_first_line) const {
     return !is_first_line || !first_line_items_
@@ -52,6 +54,12 @@
   // inlines, open/close tags with margins/border/padding this will be false.
   unsigned is_empty_inline_ : 1;
 
+  // We use this flag to determine if we have *only* floats, and OOF-positioned
+  // children. If so we consider them block-level, and run the
+  // |NGBlockLayoutAlgorithm| instead of the |NGInlineLayoutAlgorithm|. This is
+  // done to pick up block-level static-position behaviour.
+  unsigned is_block_level_ : 1;
+
   // True if changes to an item may affect different layout of earlier lines.
   // May not be able to use line caches even when the line or earlier lines are
   // not dirty.
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 b06be8be..65fa098 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
@@ -167,7 +167,7 @@
         LayoutUnit(Base::StyleRef().BorderBeforeWidth());
     for (const auto& child : physical_fragment->Children()) {
       PhysicalRect child_scrollable_overflow;
-      if (child->IsOutOfFlowPositioned()) {
+      if (child->IsFloatingOrOutOfFlowPositioned()) {
         child_scrollable_overflow =
             child->ScrollableOverflowForPropagation(this);
       } else if (children_inline && child->IsLineBox()) {
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 731fce0e..12e37f57 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
@@ -676,7 +676,6 @@
     // clearance past adjoining floats, or a re-layout), we can safely set our
     // BFC block-offset now.
     if (ConstraintSpace().ForcedBfcBlockOffset()) {
-      DCHECK(unpositioned_floats_.IsEmpty());
       container_builder_.SetBfcBlockOffset(
           *ConstraintSpace().ForcedBfcBlockOffset());
     }
@@ -689,26 +688,13 @@
       ConstraintSpace().HasBlockFragmentation())
     FinalizeForFragmentation();
 
-  // Only layout absolute and fixed children if we aren't going to revisit this
-  // layout.
-  if (!container_builder_.AdjoiningObjectTypes() ||
-      ConstraintSpace().ForcedBfcBlockOffset()) {
-    NGBoxStrut borders_and_scrollbars =
-        container_builder_.Borders() + container_builder_.Scrollbar();
-    NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), borders_and_scrollbars,
-                          &container_builder_)
-        .Run();
-  }
+  NGOutOfFlowLayoutPart(
+      Node(), ConstraintSpace(),
+      container_builder_.Borders() + container_builder_.Scrollbar(),
+      &container_builder_)
+      .Run();
 
 #if DCHECK_IS_ON()
-  // If we have any unpositioned floats at this stage, our parent will pick up
-  // this by examining adjoining object types returned, so that we get relayout
-  // with a forced BFC block-offset once it's known.
-  if (!unpositioned_floats_.IsEmpty()) {
-    DCHECK(!container_builder_.BfcBlockOffset());
-    DCHECK(container_builder_.AdjoiningObjectTypes());
-  }
-
   // If we're not participating in a fragmentation context, no block
   // fragmentation related fields should have been set.
   if (!ConstraintSpace().HasBlockFragmentation())
@@ -738,7 +724,7 @@
     return nullptr;
 
   // If floats are intruding into this node, re-layout may be needed.
-  if (!exclusion_space_.IsEmpty() || !unpositioned_floats_.IsEmpty())
+  if (!exclusion_space_.IsEmpty())
     return nullptr;
 
   // Laying out from a break token is not supported yet, because this logic
@@ -834,8 +820,7 @@
 
     LayoutUnit origin_bfc_block_offset =
         container_builder_.BfcBlockOffset().value_or(
-            ConstraintSpace().ForcedBfcBlockOffset().value_or(
-                ConstraintSpace().BfcOffset().block_offset)) +
+            ConstraintSpace().ExpectedBfcBlockOffset()) +
         static_offset.block_offset;
 
     NGBfcOffset origin_bfc_offset = {
@@ -861,29 +846,47 @@
 
   NGUnpositionedFloat unpositioned_float(child, child_break_token);
 
-  // We shouldn't have seen this float yet.
-  DCHECK(!unpositioned_floats_.Contains(unpositioned_float));
-
   if (!container_builder_.BfcBlockOffset()) {
     container_builder_.AddAdjoiningObjectTypes(
         unpositioned_float.IsLineLeft(ConstraintSpace().Direction())
             ? kAdjoiningFloatLeft
             : kAdjoiningFloatRight);
+    // If we don't have a forced BFC block-offset yet, we'll optimistically
+    // place floats at the "expected" BFC block-offset. If this differs from
+    // our final BFC block-offset we'll need to re-layout.
+    if (!ConstraintSpace().ForcedBfcBlockOffset())
+      abort_when_bfc_block_offset_updated_ = true;
   }
-  unpositioned_floats_.push_back(std::move(unpositioned_float));
 
-  // No need to postpone the positioning if we know the correct offset.
-  if (container_builder_.BfcBlockOffset() ||
-      ConstraintSpace().ForcedBfcBlockOffset()) {
-    // Adjust origin point to the margins of the last child.
-    // Example: <div style="margin-bottom: 20px"><float></div>
-    //          <div style="margin-bottom: 30px"></div>
-    LayoutUnit origin_block_offset =
-        container_builder_.BfcBlockOffset()
-            ? NextBorderEdge(previous_inflow_position)
-            : *ConstraintSpace().ForcedBfcBlockOffset();
-    PositionPendingFloats(origin_block_offset);
-  }
+  // If we don't have a BFC block-offset yet, the "expected" BFC block-offset
+  // is used to optimistically place floats.
+  NGBfcOffset origin_bfc_offset = {
+      ConstraintSpace().BfcOffset().line_offset +
+          border_scrollbar_padding_.LineLeft(ConstraintSpace().Direction()),
+      container_builder_.BfcBlockOffset()
+          ? NextBorderEdge(previous_inflow_position)
+          : ConstraintSpace().ExpectedBfcBlockOffset()};
+
+  NGPositionedFloat positioned_float = PositionFloat(
+      child_available_size_, child_percentage_size_,
+      replaced_child_percentage_size_, origin_bfc_offset, &unpositioned_float,
+      ConstraintSpace(), Style(), &exclusion_space_);
+
+  const auto& physical_fragment =
+      positioned_float.layout_result->PhysicalFragment();
+  LayoutUnit float_inline_size =
+      NGFragment(ConstraintSpace().GetWritingMode(), physical_fragment)
+          .InlineSize();
+
+  NGBfcOffset bfc_offset = {ConstraintSpace().BfcOffset().line_offset,
+                            container_builder_.BfcBlockOffset().value_or(
+                                ConstraintSpace().ExpectedBfcBlockOffset())};
+
+  LogicalOffset logical_offset = LogicalFromBfcOffsets(
+      positioned_float.bfc_offset, bfc_offset, float_inline_size,
+      container_builder_.Size().inline_size, ConstraintSpace().Direction());
+
+  container_builder_.AddResult(*positioned_float.layout_result, logical_offset);
 }
 
 bool NGBlockLayoutAlgorithm::HandleNewFormattingContext(
@@ -929,10 +932,11 @@
   bool bfc_offset_already_resolved = false;
   bool child_determined_bfc_offset = false;
   bool child_margin_got_separated = false;
-  bool had_pending_floats = false;
+  bool has_adjoining_floats = false;
 
   if (!container_builder_.BfcBlockOffset()) {
-    had_pending_floats = !unpositioned_floats_.IsEmpty();
+    has_adjoining_floats =
+        container_builder_.AdjoiningObjectTypes() & kAdjoiningFloatBoth;
 
     // If this node, or an arbitrary ancestor had clearance past adjoining
     // floats, we consider the margin "separated". We should *never* attempt to
@@ -1018,7 +1022,7 @@
                             non_adjoining_bfc_offset_estimate,
                             /* forced_bfc_block_offset */ base::nullopt);
 
-      if ((bfc_offset_already_resolved || had_pending_floats) &&
+      if ((bfc_offset_already_resolved || has_adjoining_floats) &&
           old_offset != *container_builder_.BfcBlockOffset()) {
         // The first BFC block offset resolution turned out to be wrong, and we
         // positioned preceding adjacent floats based on that. Now we have to
@@ -1427,22 +1431,17 @@
           !child_space.ForcedBfcBlockOffset())
         self_collapsing_child_needs_relayout = true;
     }
-  } else if (!child_had_clearance) {
-    // We shouldn't have any pending floats here, since an in-flow child found
-    // its BFC block offset.
-    DCHECK(unpositioned_floats_.IsEmpty());
-
-    // Only non self-collapsing children are allowed resolve the BFC
+  } else if (!child_had_clearance && !is_self_collapsing) {
+    // Only non self-collapsing children are allowed resolve their parent's BFC
     // block-offset. We check the BFC block-offset at the end of layout
     // determine if this fragment is self-collapsing.
-    if (!is_self_collapsing) {
-      // The child's BFC block offset is known, and since there's no clearance,
-      // this container will get the same offset, unless it has already been
-      // resolved.
-      if (!ResolveBfcBlockOffset(previous_inflow_position,
-                                 *child_bfc_block_offset))
-        return false;
-    }
+    //
+    // The child's BFC block-offset is known, and since there's no clearance,
+    // this container will get the same offset, unless it has already been
+    // resolved.
+    if (!ResolveBfcBlockOffset(previous_inflow_position,
+                               *child_bfc_block_offset))
+      return false;
   }
 
   // We need to re-layout a self-collapsing child if it was affected by
@@ -2191,7 +2190,38 @@
   if (!has_bfc_block_offset && ConstraintSpace().ForcedBfcBlockOffset())
     builder.SetForcedBfcBlockOffset(*ConstraintSpace().ForcedBfcBlockOffset());
   if (forced_bfc_block_offset)
-    builder.SetForcedBfcBlockOffset(forced_bfc_block_offset);
+    builder.SetForcedBfcBlockOffset(*forced_bfc_block_offset);
+
+  if (has_bfc_block_offset && child.IsBlock()) {
+    // Typically we aren't allowed to look at the previous layout result within
+    // a layout algorithm. However this is fine (honest), as it is just a hint
+    // to the child algorithm for where floats should be placed. If it doesn't
+    // have this flag, or gets this estimate wrong, it'll relayout with the
+    // appropriate "forced" BFC block-offset.
+    if (const NGLayoutResult* previous_result =
+            child.GetLayoutBox()->GetCachedLayoutResult()) {
+      const NGConstraintSpace& prev_space =
+          previous_result->GetConstraintSpaceForCaching();
+
+      // To increase the hit-rate we adjust the previous "optimistic"/"forced"
+      // BFC block-offset by how much the child has shifted from the previous
+      // layout.
+      LayoutUnit bfc_block_delta = child_data.bfc_offset_estimate.block_offset -
+                                   prev_space.BfcOffset().block_offset;
+      if (prev_space.ForcedBfcBlockOffset()) {
+        builder.SetOptimisticBfcBlockOffset(*prev_space.ForcedBfcBlockOffset() +
+                                            bfc_block_delta);
+      } else if (prev_space.OptimisticBfcBlockOffset()) {
+        builder.SetOptimisticBfcBlockOffset(
+            *prev_space.OptimisticBfcBlockOffset() + bfc_block_delta);
+      }
+    }
+  } else if (ConstraintSpace().OptimisticBfcBlockOffset()) {
+    // Propagate the |NGConstraintSpace::OptimisticBfcBlockOffset| down to our
+    // children.
+    builder.SetOptimisticBfcBlockOffset(
+        *ConstraintSpace().OptimisticBfcBlockOffset());
+  }
 
   // Propagate the |NGConstraintSpace::AncestorHasClearancePastAdjoiningFloats|
   // flag down to our children.
@@ -2342,10 +2372,8 @@
     NGPreviousInflowPosition* previous_inflow_position,
     LayoutUnit bfc_block_offset,
     base::Optional<LayoutUnit> forced_bfc_block_offset) {
-  if (container_builder_.BfcBlockOffset()) {
-    DCHECK(unpositioned_floats_.IsEmpty());
+  if (container_builder_.BfcBlockOffset())
     return true;
-  }
 
   bfc_block_offset = forced_bfc_block_offset.value_or(bfc_block_offset);
 
@@ -2357,11 +2385,6 @@
   if (NeedsAbortOnBfcBlockOffsetChange())
     return false;
 
-  // If our BFC block offset was updated, we may have been affected by
-  // clearance ourselves. We need to adjust the origin point to accomodate
-  // this.
-  PositionPendingFloats(bfc_block_offset);
-
   // Reset the previous inflow position. Clear the margin strut and set the
   // offset to our block-start border edge.
   //
@@ -2381,55 +2404,10 @@
   DCHECK(container_builder_.BfcBlockOffset());
   if (!abort_when_bfc_block_offset_updated_)
     return false;
-  // If no previous BFC block offset was set, we need to abort.
-  if (!ConstraintSpace().ForcedBfcBlockOffset())
-    return true;
 
-  // If the previous BFC block offset matches the new one, we can continue.
-  // Otherwise, we need to abort.
+  // If our position differs from our (potentially optimistic) estimate, abort.
   return *container_builder_.BfcBlockOffset() !=
-         *ConstraintSpace().ForcedBfcBlockOffset();
-}
-
-void NGBlockLayoutAlgorithm::PositionPendingFloats(
-    LayoutUnit origin_block_offset) {
-  DCHECK(container_builder_.BfcBlockOffset() ||
-         ConstraintSpace().ForcedBfcBlockOffset())
-      << "The parent BFC block offset should be known here.";
-
-  NGBfcOffset origin_bfc_offset = {
-      ConstraintSpace().BfcOffset().line_offset +
-          border_scrollbar_padding_.LineLeft(ConstraintSpace().Direction()),
-      origin_block_offset};
-
-  LayoutUnit bfc_block_offset = container_builder_.BfcBlockOffset()
-                                    ? *container_builder_.BfcBlockOffset()
-                                    : *ConstraintSpace().ForcedBfcBlockOffset();
-
-  NGBfcOffset bfc_offset = {ConstraintSpace().BfcOffset().line_offset,
-                            bfc_block_offset};
-
-  for (auto& unpositioned_float : unpositioned_floats_) {
-    NGPositionedFloat positioned_float = PositionFloat(
-        child_available_size_, child_percentage_size_,
-        replaced_child_percentage_size_, origin_bfc_offset, &unpositioned_float,
-        ConstraintSpace(), Style(), &exclusion_space_);
-
-    const auto& physical_fragment =
-        positioned_float.layout_result->PhysicalFragment();
-    LayoutUnit float_inline_size =
-        NGFragment(ConstraintSpace().GetWritingMode(), physical_fragment)
-            .InlineSize();
-
-    LogicalOffset logical_offset = LogicalFromBfcOffsets(
-        positioned_float.bfc_offset, bfc_offset, float_inline_size,
-        container_builder_.Size().inline_size, ConstraintSpace().Direction());
-
-    container_builder_.AddResult(*positioned_float.layout_result,
-                                 logical_offset);
-  }
-
-  unpositioned_floats_.Shrink(0);
+         ConstraintSpace().ExpectedBfcBlockOffset();
 }
 
 LayoutUnit NGBlockLayoutAlgorithm::CalculateMinimumBlockSize(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
index f5fdabef..12ab493 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -284,9 +284,6 @@
   // need to abort layout.
   bool NeedsAbortOnBfcBlockOffsetChange() const;
 
-  // Positions pending floats starting from {@origin_block_offset}.
-  void PositionPendingFloats(LayoutUnit origin_block_offset);
-
   // Positions a list marker for the specified block content.
   // Return false if it aborts when resolving BFC block offset for LI.
   bool PositionOrPropagateListMarker(const NGLayoutResult&,
@@ -344,7 +341,6 @@
   bool has_processed_first_child_ = false;
 
   NGExclusionSpace exclusion_space_;
-  Vector<NGUnpositionedFloat, 1> unpositioned_floats_;
 };
 
 }  // namespace blink
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 986c3484..52f95e1 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
@@ -1361,21 +1361,15 @@
   // 35 = empty1's padding(20) + empty2's padding(15)
   EXPECT_THAT(offset.left, LayoutUnit(35));
 
-  const auto* linebox_fragment = empty2_fragment->Children()[0].fragment;
-
-  offset =
-      To<NGPhysicalLineBoxFragment>(linebox_fragment)->Children()[0].offset;
-  // The floats are positioned outside the line-box as the line-box is
-  // "avoiding" these floats.
-  // inline -35 = inline-size of left-float (including margins).
+  offset = empty2_fragment->Children()[0].offset;
+  // inline 25 = left float's margin(10) + empty2's padding(15).
   // block 10 = left float's margin
-  EXPECT_THAT(offset, PhysicalOffset(-35, 10));
+  EXPECT_THAT(offset, PhysicalOffset(25, 10));
 
-  offset =
-      To<NGPhysicalLineBoxFragment>(linebox_fragment)->Children()[1].offset;
-  // inline offset 90 = right float's margin(10) + right float offset(80)
+  offset = empty2_fragment->Children()[1].offset;
+  // inline offset 140 = right float's margin(10) + right float offset(140)
   // block offset 15 = right float's margin
-  LayoutUnit right_float_offset = LayoutUnit(80);
+  LayoutUnit right_float_offset = LayoutUnit(140);
   EXPECT_THAT(offset, PhysicalOffset(LayoutUnit(10) + right_float_offset,
                                      LayoutUnit(15)));
 
@@ -2275,10 +2269,7 @@
   EXPECT_EQ(PhysicalSize(150, 60), fragment->Size());
   ASSERT_TRUE(!fragment->BreakToken() || fragment->BreakToken()->IsFinished());
 
-  const auto* linebox =
-      To<NGPhysicalBoxFragment>(fragment.get())->Children()[0].fragment;
-  const auto* float2 =
-      To<NGPhysicalLineBoxFragment>(linebox)->Children()[1].fragment;
+  const auto* float2 = fragment->Children()[1].fragment;
 
   // float2 should only have one fragment.
   EXPECT_EQ(PhysicalSize(60, 200), float2->Size());
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 9e7ef41..200a46e0 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
@@ -424,8 +424,9 @@
 
   box_->SetCachedLayoutResult(*layout_result, break_token);
   if (block_flow) {
-    NGLayoutInputNode first_child = FirstChild();
-    bool has_inline_children = first_child && first_child.IsInline();
+    auto* child = GetLayoutObjectForFirstChildNode(block_flow);
+    bool has_inline_children =
+        child && AreNGBlockFlowChildrenInline(block_flow);
 
     // Don't consider display-locked objects as having any children.
     if (has_inline_children &&
@@ -595,11 +596,23 @@
 
 NGLayoutInputNode NGBlockNode::NextSibling() const {
   LayoutObject* next_sibling = GetLayoutObjectForNextSiblingNode(box_);
-  if (next_sibling) {
-    DCHECK(!next_sibling->IsInline());
-    return NGBlockNode(ToLayoutBox(next_sibling));
+
+  // We may have some LayoutInline(s) still within the tree (due to treating
+  // inline-level floats and/or OOF-positioned nodes as block-level), we need
+  // to skip them and clear layout.
+  while (next_sibling && next_sibling->IsInline()) {
+    // TODO(layout-dev): Clearing needs-layout within this accessor is an
+    // unexpected side-effect. There may be additional invalidations that need
+    // to be performed.
+    DCHECK(next_sibling->IsText());
+    next_sibling->ClearNeedsLayout();
+    next_sibling = next_sibling->NextSibling();
   }
-  return nullptr;
+
+  if (!next_sibling)
+    return nullptr;
+
+  return NGBlockNode(ToLayoutBox(next_sibling));
 }
 
 NGLayoutInputNode NGBlockNode::FirstChild() const {
@@ -607,8 +620,33 @@
   auto* child = GetLayoutObjectForFirstChildNode(block);
   if (!child)
     return nullptr;
-  if (AreNGBlockFlowChildrenInline(block))
-    return NGInlineNode(To<LayoutBlockFlow>(block));
+  if (!AreNGBlockFlowChildrenInline(block))
+    return NGBlockNode(ToLayoutBox(child));
+
+  NGInlineNode inline_node(To<LayoutBlockFlow>(block));
+  if (!inline_node.IsBlockLevel())
+    return inline_node;
+
+  // At this point we have a node which is empty or only has floats and
+  // OOF-positioned nodes. We treat all children as block-level, even though
+  // they are within a inline-level LayoutBlockFlow.
+
+  // We may have some LayoutInline(s) still within the tree (due to treating
+  // inline-level floats and/or OOF-positioned nodes as block-level), we need
+  // to skip them and clear layout.
+  while (child && child->IsInline()) {
+    // TODO(layout-dev): Clearing needs-layout within this accessor is an
+    // unexpected side-effect. There may be additional invalidations that need
+    // to be performed.
+    DCHECK(child->IsText());
+    child->ClearNeedsLayout();
+    child = child->NextSibling();
+  }
+
+  if (!child)
+    return nullptr;
+
+  DCHECK(child->IsFloatingOrOutOfFlowPositioned());
   return NGBlockNode(ToLayoutBox(child));
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc
index c368ceb..8190b80 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc
@@ -112,7 +112,7 @@
   )HTML");
   NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
   NGLayoutInputNode child1 = container.FirstChild();
-  EXPECT_TRUE(child1 && child1.IsInline());
+  EXPECT_TRUE(child1 && child1.IsBlock());
   NGLayoutInputNode child2 = child1.NextSibling();
   EXPECT_EQ(child2, nullptr);
 }
@@ -129,7 +129,7 @@
   )HTML");
   NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
   NGLayoutInputNode child1 = container.FirstChild();
-  EXPECT_TRUE(child1 && child1.IsInline());
+  EXPECT_TRUE(child1 && child1.IsBlock());
   NGLayoutInputNode child2 = child1.NextSibling();
   EXPECT_EQ(child2, nullptr);
 }
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 877ec83..c91c05b 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
@@ -2937,7 +2937,6 @@
     offset:0,0 size:320x100
       offset:0,0 size:100x100
         offset:0,0 size:222x100
-          offset:0,0 size:0x0
           offset:0,0 size:111x50
       offset:110,0 size:100x100
         offset:0,0 size:222x100
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index c0910ac..965a32b 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -374,13 +374,13 @@
   }
 
   // If present, and the current layout hasn't resolved its BFC block-offset
-  // yet (see BfcOffset), the layout should position all of its unpositioned
-  // floats at this offset.
+  // yet (see BfcOffset), the layout should position all of its floats at this
+  // offset.
   //
   // This value is present if:
   //   - An ancestor had clearance past adjoining floats. In this case this
   //     value is calculated ahead of time.
-  //   - A second layout pass is required as there were unpositioned floats
+  //   - A second layout pass is required as there were adjoining-floats
   //     within the tree, and an arbitrary sibling determined their BFC
   //     block-offset.
   //
@@ -390,6 +390,33 @@
     return HasRareData() ? rare_data_->forced_bfc_block_offset : base::nullopt;
   }
 
+  // If present, this is a hint as to where place any adjoining objects. This
+  // isn't necessarily the final position, just where they ended up in a
+  // previous layout pass.
+  base::Optional<LayoutUnit> OptimisticBfcBlockOffset() const {
+    return HasRareData() ? rare_data_->optimistic_bfc_block_offset
+                         : base::nullopt;
+  }
+
+  // The "expected" BFC block-offset is:
+  //  - The |ForcedBfcBlockOffset| if set.
+  //  - The |OptimisticBfcBlockOffset| if set.
+  //  - Otherwise the |BfcOffset|.
+  //
+  // This represents where any adjoining-objects should be placed (potentially
+  // optimistically)
+  LayoutUnit ExpectedBfcBlockOffset() const {
+    // A short-circuit optimization (must equivalent to below).
+    if (!HasRareData()) {
+      DCHECK(!ForcedBfcBlockOffset());
+      DCHECK(!OptimisticBfcBlockOffset());
+      return bfc_offset_.block_offset;
+    }
+
+    return ForcedBfcBlockOffset().value_or(
+        OptimisticBfcBlockOffset().value_or(BfcOffset().block_offset));
+  }
+
   // Returns the types of preceding adjoining objects.
   // See |NGAdjoiningObjectTypes|.
   //
@@ -525,6 +552,7 @@
     NGBfcOffset bfc_offset;
     NGMarginStrut margin_strut;
 
+    base::Optional<LayoutUnit> optimistic_bfc_block_offset;
     base::Optional<LayoutUnit> forced_bfc_block_offset;
     LayoutUnit clearance_offset = LayoutUnit::Min();
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index 02e2e7d..06ede82 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -233,13 +233,28 @@
 
     return *this;
   }
+
+  NGConstraintSpaceBuilder& SetOptimisticBfcBlockOffset(
+      LayoutUnit optimistic_bfc_block_offset) {
+#if DCHECK_IS_ON()
+    DCHECK(!is_optimistic_bfc_block_offset_set_);
+    is_optimistic_bfc_block_offset_set_ = true;
+#endif
+    if (LIKELY(!is_new_fc_)) {
+      space_.EnsureRareData()->optimistic_bfc_block_offset =
+          optimistic_bfc_block_offset;
+    }
+
+    return *this;
+  }
+
   NGConstraintSpaceBuilder& SetForcedBfcBlockOffset(
-      const base::Optional<LayoutUnit>& forced_bfc_block_offset) {
+      LayoutUnit forced_bfc_block_offset) {
 #if DCHECK_IS_ON()
     DCHECK(!is_forced_bfc_block_offset_set_);
     is_forced_bfc_block_offset_set_ = true;
 #endif
-    if (LIKELY(!is_new_fc_ && forced_bfc_block_offset != base::nullopt)) {
+    if (LIKELY(!is_new_fc_)) {
       space_.EnsureRareData()->forced_bfc_block_offset =
           forced_bfc_block_offset;
     }
@@ -334,6 +349,7 @@
   bool is_fragmentainer_space_at_bfc_start_set_ = false;
   bool is_block_direction_fragmentation_type_set_ = false;
   bool is_margin_strut_set_ = false;
+  bool is_optimistic_bfc_block_offset_set_ = false;
   bool is_forced_bfc_block_offset_set_ = false;
   bool is_clearance_offset_set_ = false;
 
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 1eb6c26b..ab1718d 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
@@ -262,9 +262,8 @@
   offset:unplaced size:1000x323
     offset:0,0 size:126x323
       offset:13,0 size:50x200
-        offset:50,0 size:0x0
-          offset:-50,0 size:25x200
-          offset:-25,0 size:25x200
+        offset:0,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_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
index 71a78085..885a1b3 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
@@ -516,8 +516,7 @@
     return false;
   if (space.IsIntermediateLayout())
     return false;
-  // Check that we're done positioning any adjoining objects.
-  return !result.AdjoiningObjectTypes() || result.BfcBlockOffset();
+  return true;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
index bc7dc26c..662e76a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
@@ -187,8 +187,7 @@
         container_builder_.BfcLineOffset() +
             border_scrollbar_padding_.LineLeft(direction_),
         container_builder_.BfcBlockOffset().value_or(
-            ConstraintSpace().ForcedBfcBlockOffset().value_or(
-                ConstraintSpace().BfcOffset().block_offset)) +
+            ConstraintSpace().ExpectedBfcBlockOffset()) +
             static_block_offset_};
 
     static_offset.inline_offset += CalculateOutOfFlowStaticInlineLevelOffset(
@@ -236,8 +235,7 @@
     NGBfcOffset container_bfc_offset = {
         container_builder_.BfcLineOffset(),
         container_builder_.BfcBlockOffset().value_or(
-            ConstraintSpace().ForcedBfcBlockOffset().value_or(
-                ConstraintSpace().BfcOffset().block_offset))};
+            ConstraintSpace().ExpectedBfcBlockOffset())};
 
     // Determine the offsets for the exclusion (the margin-box of the float).
     NGBfcOffset start_offset = {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
index fcbd0e1..fbbb45c 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
@@ -94,8 +94,8 @@
 }
 
 Path PathFromElement(const SVGElement& element) {
-  if (IsSVGGeometryElement(element))
-    return ToSVGGeometryElement(element).ToClipPath();
+  if (auto* svg_geometry_element = DynamicTo<SVGGeometryElement>(element))
+    return svg_geometry_element->ToClipPath();
 
   // Guaranteed by DetermineClipStrategy() above, only <use> element and
   // SVGGraphicsElement that has a LayoutSVGShape can reach here.
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
index a9e2489..32bd806 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -78,13 +78,13 @@
 void LayoutSVGShape::CreatePath() {
   if (!path_)
     path_ = std::make_unique<Path>();
-  *path_ = ToSVGGeometryElement(GetElement())->AsPath();
+  *path_ = To<SVGGeometryElement>(GetElement())->AsPath();
 }
 
 float LayoutSVGShape::DashScaleFactor() const {
   if (StyleRef().SvgStyle().StrokeDashArray()->data.IsEmpty())
     return 1;
-  return ToSVGGeometryElement(*GetElement()).PathLengthScaleFactor();
+  return To<SVGGeometryElement>(*GetElement()).PathLengthScaleFactor();
 }
 
 void LayoutSVGShape::UpdateShapeFromElement() {
diff --git a/third_party/blink/renderer/core/svg/svg_geometry_element.h b/third_party/blink/renderer/core/svg/svg_geometry_element.h
index cff2850..774a5c9 100644
--- a/third_party/blink/renderer/core/svg/svg_geometry_element.h
+++ b/third_party/blink/renderer/core/svg/svg_geometry_element.h
@@ -83,7 +83,13 @@
   return element.IsSVGGeometryElement();
 }
 
-DEFINE_SVGELEMENT_TYPE_CASTS_WITH_FUNCTION(SVGGeometryElement);
+template <>
+struct DowncastTraits<SVGGeometryElement> {
+  static bool AllowFrom(const Node& node) {
+    auto* element = DynamicTo<SVGElement>(node);
+    return element && element->IsSVGGeometryElement();
+  }
+};
 
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.cc b/third_party/blink/renderer/core/svg/svg_use_element.cc
index 86b6df14..c49bce3b9 100644
--- a/third_party/blink/renderer/core/svg/svg_use_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_use_element.cc
@@ -485,12 +485,13 @@
 }
 
 Path SVGUseElement::ToClipPath() const {
-  const SVGGraphicsElement* element = VisibleTargetGraphicsElementForClipping();
-  if (!element || !element->IsSVGGeometryElement())
+  auto* svg_geometry_element =
+      DynamicTo<SVGGeometryElement>(VisibleTargetGraphicsElementForClipping());
+  if (!svg_geometry_element)
     return Path();
 
   DCHECK(GetLayoutObject());
-  Path path = ToSVGGeometryElement(*element).ToClipPath();
+  Path path = svg_geometry_element->ToClipPath();
   AffineTransform transform = GetLayoutObject()->LocalSVGTransform();
   if (!transform.IsIdentity())
     path.Transform(transform);
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
index f365ea3b..a694aaf 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
@@ -92,9 +92,18 @@
 
 ClipboardPromise::~ClipboardPromise() = default;
 
-void ClipboardPromise::WriteNextRepresentation() {
+void ClipboardPromise::CompleteWriteRepresentation() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   clipboard_writer_.reset();  // The previous write is done.
+  ++clipboard_representation_index_;
+  StartWriteRepresentation();
+}
+
+void ClipboardPromise::StartWriteRepresentation() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Commit to system clipboard when all representations are written.
+  // This is in the start flow so that a |clipboard_item_data_| with 0 items
+  // will still commit gracefully.
   if (clipboard_representation_index_ == clipboard_item_data_.size()) {
     SystemClipboard::GetInstance().CommitWrite();
     script_promise_resolver_->Resolve();
@@ -104,7 +113,6 @@
       clipboard_item_data_[clipboard_representation_index_].first;
   const Member<Blob>& blob =
       clipboard_item_data_[clipboard_representation_index_].second;
-  clipboard_representation_index_++;
 
   DCHECK(!clipboard_writer_);
   clipboard_writer_ = ClipboardWriter::Create(type, this);
@@ -113,12 +121,10 @@
 
 void ClipboardPromise::RejectFromReadOrDecodeFailure() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK_GE(clipboard_representation_index_, static_cast<wtf_size_t>(1));
   script_promise_resolver_->Reject(MakeGarbageCollected<DOMException>(
       DOMExceptionCode::kDataError,
       "Failed to read or decode Blob for clipboard item type " +
-          clipboard_item_data_[clipboard_representation_index_ - 1].first +
-          "."));
+          clipboard_item_data_[clipboard_representation_index_].first + "."));
 }
 
 void ClipboardPromise::HandleRead() {
@@ -238,7 +244,7 @@
   }
 
   DCHECK(!clipboard_representation_index_);
-  WriteNextRepresentation();
+  StartWriteRepresentation();
 }
 
 void ClipboardPromise::HandleWriteTextWithPermission(PermissionStatus status) {
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
index f2b693c..ab4c4b76 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
@@ -36,14 +36,17 @@
   explicit ClipboardPromise(ScriptState*);
   virtual ~ClipboardPromise();
 
-  // Called to begin writing a type, or after writing each type.
-  void WriteNextRepresentation();
+  // Completes current write and starts next write.
+  void CompleteWriteRepresentation();
   // For rejections originating from ClipboardWriter.
   void RejectFromReadOrDecodeFailure();
 
   void Trace(blink::Visitor*) override;
 
  private:
+  // Called to begin writing a type.
+  void StartWriteRepresentation();
+
   // Checks Read/Write permission (interacting with PermissionService).
   void HandleRead();
   void HandleReadText();
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
index 065321c..9591363 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
@@ -59,7 +59,7 @@
     SkBitmap bitmap;
     image->asLegacyBitmap(&bitmap);
     SystemClipboard::GetInstance().WriteImage(std::move(bitmap));
-    promise_->WriteNextRepresentation();
+    promise_->CompleteWriteRepresentation();
   }
 };
 
@@ -91,7 +91,7 @@
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     SystemClipboard::GetInstance().WritePlainText(text);
 
-    promise_->WriteNextRepresentation();
+    promise_->CompleteWriteRepresentation();
   }
 };
 
diff --git a/third_party/blink/renderer/modules/contacts_picker/README.md b/third_party/blink/renderer/modules/contacts_picker/README.md
index 5afd8bf..9ee1d82 100644
--- a/third_party/blink/renderer/modules/contacts_picker/README.md
+++ b/third_party/blink/renderer/modules/contacts_picker/README.md
@@ -1,3 +1,4 @@
 # Contacts Picker
 
-This directory contains the implementation of [the Contacts Picker API](https://github.com/beverloo/contact-api).
+This directory contains the implementation of
+[the Contacts Picker API](https://wicg.github.io/contact-api/spec/).
diff --git a/third_party/blink/renderer/modules/contacts_picker/contact_info.idl b/third_party/blink/renderer/modules/contacts_picker/contact_info.idl
index 82f06c5..c3444d43 100644
--- a/third_party/blink/renderer/modules/contacts_picker/contact_info.idl
+++ b/third_party/blink/renderer/modules/contacts_picker/contact_info.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://github.com/beverloo/contact-api
+// https://wicg.github.io/contact-api/spec/#contacts-manager
 
 dictionary ContactInfo {
     sequence<USVString> name;
diff --git a/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl b/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl
index a208a78..23d943b 100644
--- a/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl
+++ b/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://github.com/beverloo/contact-api
+// https://wicg.github.io/contact-api/spec/#contacts-manager
 
 [
     Exposed=Window,
diff --git a/third_party/blink/renderer/modules/contacts_picker/contacts_select_options.idl b/third_party/blink/renderer/modules/contacts_picker/contacts_select_options.idl
index 4cab707d..f532941 100644
--- a/third_party/blink/renderer/modules/contacts_picker/contacts_select_options.idl
+++ b/third_party/blink/renderer/modules/contacts_picker/contacts_select_options.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://github.com/beverloo/contact-api
+// https://wicg.github.io/contact-api/spec/#contacts-manager
 
 enum ContactProperty { "email", "name", "tel" };
 
diff --git a/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.idl b/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.idl
index 65bed25..ae89a87 100644
--- a/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.idl
+++ b/third_party/blink/renderer/modules/contacts_picker/navigator_contacts.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://github.com/beverloo/contact-api
+// https://wicg.github.io/contact-api/spec/#extensions-to-navigator
 
 [
     Exposed=Window,
diff --git a/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.cc b/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.cc
index 4a066985..09c2c6b 100644
--- a/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/local_media_stream_audio_source.cc
@@ -113,16 +113,11 @@
 }
 
 void LocalMediaStreamAudioSource::Capture(const media::AudioBus* audio_bus,
-                                          int audio_delay_milliseconds,
+                                          base::TimeTicks audio_capture_time,
                                           double volume,
                                           bool key_pressed) {
   DCHECK(audio_bus);
-  // TODO(miu): Plumbing is needed to determine the actual capture timestamp
-  // of the audio, instead of just snapshotting TimeTicks::Now(), for proper
-  // audio/video sync. https://crbug.com/335335
-  DeliverDataToTracks(
-      *audio_bus, base::TimeTicks::Now() - base::TimeDelta::FromMilliseconds(
-                                               audio_delay_milliseconds));
+  DeliverDataToTracks(*audio_bus, audio_capture_time);
 }
 
 void LocalMediaStreamAudioSource::OnCaptureError(const std::string& why) {
diff --git a/third_party/blink/renderer/modules/vr/navigator_vr.cc b/third_party/blink/renderer/modules/vr/navigator_vr.cc
index b2fcaae..44a63ee 100644
--- a/third_party/blink/renderer/modules/vr/navigator_vr.cc
+++ b/third_party/blink/renderer/modules/vr/navigator_vr.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/modules/vr/vr_controller.h"
 #include "third_party/blink/renderer/modules/vr/vr_pose.h"
@@ -109,7 +110,7 @@
                                            kCannotUseBothNewAndOldAPIMessage));
   }
 
-  UseCounter::Count(*document, WebFeature::kVRGetDisplays);
+  Deprecation::CountDeprecation(*document, WebFeature::kVRGetDisplays);
   ExecutionContext* execution_context = ExecutionContext::From(script_state);
   if (!execution_context->IsSecureContext())
     UseCounter::Count(*document, WebFeature::kVRGetDisplaysInsecureOrigin);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.cc b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.cc
index f74c2967..dc3d856 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.cc
@@ -29,6 +29,9 @@
 WebGLCompressedTextureASTC::WebGLCompressedTextureASTC(
     WebGLRenderingContextBase* context)
     : WebGLExtension(context) {
+  context->ExtensionsUtil()->EnsureExtensionEnabled(
+      "GL_KHR_texture_compression_astc_ldr");
+
   const int kAlphaFormatGap =
       GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR - GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.cc b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.cc
index c8c15b06..0558499 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.cc
@@ -11,6 +11,9 @@
 WebGLCompressedTextureETC1::WebGLCompressedTextureETC1(
     WebGLRenderingContextBase* context)
     : WebGLExtension(context) {
+  context->ExtensionsUtil()->EnsureExtensionEnabled(
+      "GL_OES_compressed_ETC1_RGB8_texture");
+
   context->AddCompressedTextureFormat(GL_ETC1_RGB8_OES);
 }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.cc b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.cc
index 2f59530..b6d88b8 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.cc
@@ -32,6 +32,9 @@
 WebGLCompressedTexturePVRTC::WebGLCompressedTexturePVRTC(
     WebGLRenderingContextBase* context)
     : WebGLExtension(context) {
+  context->ExtensionsUtil()->EnsureExtensionEnabled(
+      "GL_IMG_texture_compression_pvrtc");
+
   context->AddCompressedTextureFormat(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG);
   context->AddCompressedTextureFormat(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG);
   context->AddCompressedTextureFormat(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.cc b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.cc
index b29a0d29..3fd2628 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.cc
@@ -32,6 +32,15 @@
 WebGLCompressedTextureS3TC::WebGLCompressedTextureS3TC(
     WebGLRenderingContextBase* context)
     : WebGLExtension(context) {
+  context->ExtensionsUtil()->EnsureExtensionEnabled(
+      "GL_EXT_texture_compression_s3tc");
+  context->ExtensionsUtil()->EnsureExtensionEnabled(
+      "GL_ANGLE_texture_compression_dxt1");
+  context->ExtensionsUtil()->EnsureExtensionEnabled(
+      "GL_ANGLE_texture_compression_dxt3");
+  context->ExtensionsUtil()->EnsureExtensionEnabled(
+      "GL_ANGLE_texture_compression_dxt5");
+
   context->AddCompressedTextureFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
   context->AddCompressedTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
   context->AddCompressedTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.cc b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.cc
index 634f4a65..9d417dd 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.cc
@@ -11,6 +11,9 @@
 WebGLCompressedTextureS3TCsRGB::WebGLCompressedTextureS3TCsRGB(
     WebGLRenderingContextBase* context)
     : WebGLExtension(context) {
+  context->ExtensionsUtil()->EnsureExtensionEnabled(
+      "GL_EXT_texture_compression_s3tc_srgb");
+
   // TODO(kainino): update these with _EXT versions once
   // GL_EXT_compressed_texture_s3tc_srgb is ratified
   context->AddCompressedTextureFormat(GL_COMPRESSED_SRGB_S3TC_DXT1_NV);
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index 1b50eca..18cd92e 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -235,7 +235,7 @@
   DCHECK(queue);
 
   queue->DetachFromMainThreadScheduler();
-  queue->DetachFromFrameScheduler();
+  DCHECK(!queue->GetFrameScheduler());
   queue->SetBlameContext(nullptr);
 }
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
index fbc2b9ed..173cf5a 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -300,10 +300,10 @@
   // |frame_task_queue_controller_| via CreateResourceLoadingTaskRunnerHandle.
   ResourceLoadingTaskQueuePriorityMap resource_loading_task_queue_priorities_;
 
-  MainThreadSchedulerImpl* main_thread_scheduler_;  // NOT OWNED
-  PageSchedulerImpl* parent_page_scheduler_;        // NOT OWNED
-  FrameScheduler::Delegate* delegate_;              // NOT OWNED
-  base::trace_event::BlameContext* blame_context_;  // NOT OWNED
+  MainThreadSchedulerImpl* const main_thread_scheduler_;  // NOT OWNED
+  PageSchedulerImpl* parent_page_scheduler_;              // NOT OWNED
+  FrameScheduler::Delegate* delegate_;                    // NOT OWNED
+  base::trace_event::BlameContext* blame_context_;        // NOT OWNED
   SchedulingLifecycleState throttling_state_;
   TraceableState<bool, TracingCategoryName::kInfo> frame_visible_;
   TraceableState<bool, TracingCategoryName::kInfo> frame_paused_;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
index fd145d4..7c574ea 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
@@ -177,10 +177,6 @@
   return frame_scheduler_;
 }
 
-void MainThreadTaskQueue::DetachFromFrameScheduler() {
-  frame_scheduler_ = nullptr;
-}
-
 void MainThreadTaskQueue::SetFrameSchedulerForTest(
     FrameSchedulerImpl* frame_scheduler) {
   frame_scheduler_ = frame_scheduler;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
index bbf4964..37aae0e 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -313,7 +313,6 @@
   void ShutdownTaskQueue() override;
 
   FrameSchedulerImpl* GetFrameScheduler() const;
-  void DetachFromFrameScheduler();
 
   scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner(
       TaskType task_type) {
diff --git a/third_party/blink/tools/BUILD.gn b/third_party/blink/tools/BUILD.gn
index 785b96d..4bb5a01f 100644
--- a/third_party/blink/tools/BUILD.gn
+++ b/third_party/blink/tools/BUILD.gn
@@ -47,12 +47,9 @@
     "//third_party/blink/tools/update_wpt_output.py",
     "//third_party/blink/tools/blinkpy/",
 
-    # The WPT root directory contains both the test runner codebase
-    # and the tests themselves.
-    "//third_party/blink/web_tests/external/wpt/",
-
-    # Include the checked-in WPT manifest.
-    "//third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json",
+    # The web_tests/external directory contains all WPT components including
+    # the test runner codebase, manifest file, and the tests themselves.
+    "//third_party/blink/web_tests/external/",
 
     # Include the various Test Expectations files.
     "//third_party/blink/web_tests/ASANExpectations",
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 09c359a1..8a72ecbfa 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -943,7 +943,7 @@
     # Because Windows.
     path = path.replace('\\', '/')
     basename, ext = os.path.splitext(path)
-    # Only check code. Ignore tests.
+    # Only check code. Ignore tests and fuzzers.
     # TODO(tkent): Remove 'Test' after the great mv.
     if (ext not in ('.cc', '.cpp', '.h', '.mm')
             or path.find('/testing/') >= 0
@@ -951,7 +951,8 @@
             or basename.endswith('Test')
             or basename.endswith('_test')
             or basename.endswith('_test_helpers')
-            or basename.endswith('_unittest')):
+            or basename.endswith('_unittest')
+            or basename.endswith('_fuzzer')):
         return results
     entries = _find_matching_entries(path)
     if not entries:
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-features=NavigationLoaderOnUI b/third_party/blink/web_tests/FlagExpectations/enable-features=NavigationLoaderOnUI
index 70c4a73..d4e54b5 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-features=NavigationLoaderOnUI
+++ b/third_party/blink/web_tests/FlagExpectations/enable-features=NavigationLoaderOnUI
@@ -2,15 +2,18 @@
 # See https://crbug.com/824840
 
 # service worker
+Bug(none) external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Timeout ]
 Bug(none) external/wpt/service-workers/service-worker/appcache-ordering-main.https.html [ Failure ]
 Bug(none) external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html [ Failure ]
+Bug(none) http/tests/devtools/service-workers/service-workers-bypass-for-network-navigation.js [ Failure ]
 Bug(none) virtual/blink-cors/external/wpt/service-workers/service-worker/appcache-ordering-main.https.html [ Failure ]
 Bug(none) virtual/blink-cors/external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html [ Failure ]
 Bug(none) virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/appcache-ordering-main.https.html [ Failure ]
 Bug(none) virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html [ Failure ]
+Bug(none) virtual/not-omt-sw-fetch/external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Timeout ]
 Bug(none) virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/appcache-ordering-main.https.html [ Failure ]
 Bug(none) virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html [ Failure ]
-Bug(none) http/tests/devtools/service-workers/service-workers-bypass-for-network-navigation.js [ Failure ]
+Bug(none) virtual/omt-worker-fetch/external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Timeout ]
 Bug(none) virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/appcache-ordering-main.https.html [ Failure ]
 Bug(none) virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/claim-fetch-with-appcache.https.html [ Failure ]
 
@@ -21,14 +24,4 @@
 Bug(none) http/tests/devtools/sxg [ Skip ]
 Bug(none) http/tests/loading/sxg [ Skip ]
 
-# appcache
-Bug(none) external/wpt/html/browsers/offline/appcache/appcache-iframe.https.html [ Timeout ]
-Bug(none) http/tests/appcache/fallback.html [ Timeout ]
-Bug(none) http/tests/appcache/main-resource-hash.html [ Timeout ]
-Bug(none) http/tests/appcache/main-resource-redirect.html [ Timeout ]
-Bug(none) http/tests/appcache/offline-access.html [ Timeout ]
-Bug(none) http/tests/appcache/remove-cache.html [ Timeout ]
-Bug(none) http/tests/appcache/top-frame-2.html [ Timeout ]
-Bug(none) virtual/conditional-appcache-delay/http/tests/loading/appcache-delay/appcache-loads-subresource.html [ Failure ]
-
 Bug(none) http/tests/misc/xhtml.php [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 0dc10262..0c6545c3 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -366,8 +366,6 @@
 
 # ====== Layout team owned tests from here ======
 
-crbug.com/980908 wpt_internal/css/css-position/static-position/inline-level-absolute-float-quirk.html [ Failure ]
-
 crbug.com/974853 external/wpt/css/CSS2/abspos/hypothetical-box-dynamic.html [ Failure ]
 
 crbug.com/711704 external/wpt/css/CSS2/floats/floats-rule3-outside-left-002.xht [ Failure ]
@@ -1845,7 +1843,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/829028 virtual/layout_ng_experimental/fragmentation/forced-break-inside-float.html [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fragmentation/image-block-as-first-child.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fragmentation/overflow-crossing-boundary.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/fragmentation/relayout-abspos.html [ Failure ]
@@ -2013,6 +2011,7 @@
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-008.xht [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-012.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-014.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-015.html [ Failure ]
 crbug.com/249112 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-005.xht [ Failure ]
 crbug.com/249112 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-007.xht [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-order.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index b9bff578..2d49074 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -6487,30 +6487,6 @@
      {}
     ]
    ],
-   "pointerevents/extension/pointerevent_touch-action-pan-down-css_touch-manual.html": [
-    [
-     "pointerevents/extension/pointerevent_touch-action-pan-down-css_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/extension/pointerevent_touch-action-pan-left-css_touch-manual.html": [
-    [
-     "pointerevents/extension/pointerevent_touch-action-pan-left-css_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/extension/pointerevent_touch-action-pan-right-css_touch-manual.html": [
-    [
-     "pointerevents/extension/pointerevent_touch-action-pan-right-css_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/extension/pointerevent_touch-action-pan-up-css_touch-manual.html": [
-    [
-     "pointerevents/extension/pointerevent_touch-action-pan-up-css_touch-manual.html",
-     {}
-    ]
-   ],
    "pointerevents/html/pointerevent_drag_interaction-manual.html": [
     [
      "pointerevents/html/pointerevent_drag_interaction-manual.html",
@@ -31309,6 +31285,18 @@
      {}
     ]
    ],
+   "css/css-animations/animation-pseudo-dynamic-001.html": [
+    [
+     "css/css-animations/animation-pseudo-dynamic-001.html",
+     [
+      [
+       "/css/css-animations/animation-pseudo-dynamic-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-animations/animation-transform-pause-and-set-time.html": [
     [
      "css/css-animations/animation-transform-pause-and-set-time.html",
@@ -129885,6 +129873,9 @@
    "css/css-animations/animation-opacity-pause-and-set-time-ref.html": [
     []
    ],
+   "css/css-animations/animation-pseudo-dynamic-001-ref.html": [
+    []
+   ],
    "css/css-animations/animation-transform-pause-and-set-time-ref.html": [
     []
    ],
@@ -163275,9 +163266,6 @@
    "push-api/META.yml": [
     []
    ],
-   "push-api/idlharness.https.any.serviceworker-expected.txt": [
-    []
-   ],
    "quirks/META.yml": [
     []
    ],
@@ -165438,6 +165426,9 @@
    "resources/webidl2/.travis.yml": [
     []
    ],
+   "resources/webidl2/lib/README.md": [
+    []
+   ],
    "resources/webidl2/lib/webidl2.js": [
     []
    ],
@@ -172779,18 +172770,12 @@
    "wake-lock/OWNERS": [
     []
    ],
-   "wake-lock/idlharness.https.any.worker-expected.txt": [
-    []
-   ],
    "wake-lock/resources/page1.html": [
     []
    ],
    "wake-lock/resources/page2.html": [
     []
    ],
-   "wake-lock/wakelock-abortsignal.https.any.worker-expected.txt": [
-    []
-   ],
    "wake-lock/wakelock-disabled-by-feature-policy.https.sub.html.headers": [
     []
    ],
@@ -172800,12 +172785,6 @@
    "wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html.headers": [
     []
    ],
-   "wake-lock/wakelock-screen-type-on-worker.https.worker-expected.txt": [
-    []
-   ],
-   "wake-lock/wakelock-type.https.any.worker-expected.txt": [
-    []
-   ],
    "wasm/META.yml": [
     []
    ],
@@ -232109,6 +232088,12 @@
      {}
     ]
    ],
+   "fetch/sec-metadata/fetch-preflight.tentative.https.sub.html": [
+    [
+     "fetch/sec-metadata/fetch-preflight.tentative.https.sub.html",
+     {}
+    ]
+   ],
    "fetch/sec-metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html": [
     [
      "fetch/sec-metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html",
@@ -263897,6 +263882,38 @@
      }
     ]
    ],
+   "pointerevents/extension/pointerevent_touch-action-pan-down-css_touch.html": [
+    [
+     "pointerevents/extension/pointerevent_touch-action-pan-down-css_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerevents/extension/pointerevent_touch-action-pan-left-css_touch.html": [
+    [
+     "pointerevents/extension/pointerevent_touch-action-pan-left-css_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerevents/extension/pointerevent_touch-action-pan-right-css_touch.html": [
+    [
+     "pointerevents/extension/pointerevent_touch-action-pan-right-css_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerevents/extension/pointerevent_touch-action-pan-up-css_touch.html": [
+    [
+     "pointerevents/extension/pointerevent_touch-action-pan-up-css_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "pointerevents/extension/pointerevent_touch-action-verification.html": [
     [
      "pointerevents/extension/pointerevent_touch-action-verification.html",
@@ -340688,6 +340705,14 @@
    "27ca389decab5bff949166314f41c50d2b60da95",
    "manual"
   ],
+  "css/css-animations/animation-pseudo-dynamic-001-ref.html": [
+   "30d70aadc1ea7943c8e0d1f84cc2c6323654784c",
+   "support"
+  ],
+  "css/css-animations/animation-pseudo-dynamic-001.html": [
+   "e141b62149d3b37b5d23f25ba28397228f336d67",
+   "reftest"
+  ],
   "css/css-animations/animation-shorthand-001-manual.html": [
    "0a947efe84e238d33d79bc9caf59e1d0ee608e30",
    "manual"
@@ -400749,11 +400774,11 @@
    "testharness"
   ],
   "css/geometry/DOMMatrix2DInit-validate-fixup-expected.txt": [
-   "0ffad3ab9e98977ae67972b02426fb53d960822c",
+   "9e2cb2476754c1776ab4d86893f35777440588fb",
    "support"
   ],
   "css/geometry/DOMMatrix2DInit-validate-fixup.html": [
-   "5fb7e7d271bd95992c5b6d4a8de256c165074596",
+   "7ef4ca8b0605f794c1d2eeec019afdedba29cb1f",
    "testharness"
   ],
   "css/geometry/DOMMatrixInit-validate-fixup.html": [
@@ -416676,6 +416701,10 @@
    "c46765b37c6325260882751e9e592c2b55d8b128",
    "testharness"
   ],
+  "fetch/sec-metadata/fetch-preflight.tentative.https.sub.html": [
+   "a4e2125bc10d38a69cb9518aec11b947f95f5ba1",
+   "testharness"
+  ],
   "fetch/sec-metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html": [
    "e8ec11ec8c1d09b72cf5eee722c1ceab4c3aa6d6",
    "testharness"
@@ -416773,7 +416802,7 @@
    "support"
   ],
   "fetch/sec-metadata/resources/echo-as-json.py": [
-   "ce5a2d925d171fe4af88f299ee77322d9e54266e",
+   "7644a8507d97f9f4d30106dc38fd22cfc6b10796",
    "support"
   ],
   "fetch/sec-metadata/resources/echo-as-script.py": [
@@ -429429,7 +429458,7 @@
    "testharness"
   ],
   "html/semantics/embedded-content/media-elements/track/track-element/track-mode.html": [
-   "97df7efa2ec60f591c351b3a45195a22e57f4cbd",
+   "2474a11fb1adb0ccd2a4f7a5b82098fa7ea04e57",
    "testharness"
   ],
   "html/semantics/embedded-content/media-elements/track/track-element/track-node-add-remove.html": [
@@ -453084,21 +453113,21 @@
    "220a4b82850598c404699e4cf1a1c5a10738b137",
    "manual"
   ],
-  "pointerevents/extension/pointerevent_touch-action-pan-down-css_touch-manual.html": [
-   "592139f9f41abb2a3fe6bf1b99af87d1c5e651f3",
-   "manual"
+  "pointerevents/extension/pointerevent_touch-action-pan-down-css_touch.html": [
+   "7b713f9e5c44055a933a230a0108963db3d2f805",
+   "testharness"
   ],
-  "pointerevents/extension/pointerevent_touch-action-pan-left-css_touch-manual.html": [
-   "7030d5e487ce3cbf94a2d7004562b518af56f8f0",
-   "manual"
+  "pointerevents/extension/pointerevent_touch-action-pan-left-css_touch.html": [
+   "f1becf3e7dbad8ae972cae1dcf2306ce663a0256",
+   "testharness"
   ],
-  "pointerevents/extension/pointerevent_touch-action-pan-right-css_touch-manual.html": [
-   "e711236a37059523b1d8122e30f8ff37ba2b385c",
-   "manual"
+  "pointerevents/extension/pointerevent_touch-action-pan-right-css_touch.html": [
+   "2c93b5505aea7848c8bae9f8e79050937b30d3b9",
+   "testharness"
   ],
-  "pointerevents/extension/pointerevent_touch-action-pan-up-css_touch-manual.html": [
-   "46ddaa26031d98fee8ec797171e4690f56f1198b",
-   "manual"
+  "pointerevents/extension/pointerevent_touch-action-pan-up-css_touch.html": [
+   "30fb3bdfd03ca9e1c7dad346e126292924fd9cf4",
+   "testharness"
   ],
   "pointerevents/extension/pointerevent_touch-action-verification.html": [
    "178f7a68a58e45c510ad2723e634d30996e90fb9",
@@ -454252,10 +454281,6 @@
    "16c0826a7592a4636caa70c53ec7a6bfb0f7b1c3",
    "testharness"
   ],
-  "push-api/idlharness.https.any.serviceworker-expected.txt": [
-   "572742c5657cdaac6eedabf3762985535ace0f68",
-   "support"
-  ],
   "quirks/META.yml": [
    "29f19c5c6af481344376795a8b37d474d23be41d",
    "support"
@@ -464144,8 +464169,12 @@
    "6e5919de39a312330fd1abf64237c4b6ad10c56b",
    "support"
   ],
+  "resources/webidl2/lib/README.md": [
+   "3f9d75f57ba8506537f75ae2958df6a74abcba3d",
+   "support"
+  ],
   "resources/webidl2/lib/webidl2.js": [
-   "d909c30ff07eda519f969a22a0bae6836550c2d8",
+   "9cb975a8bb30075e7ab377bc95b69ecc4f7e77f6",
    "support"
   ],
   "resources/webidl2/lib/webidl2.js.headers": [
@@ -478752,10 +478781,6 @@
    "2ad9980dae53727ea328e942dead029a936875cc",
    "testharness"
   ],
-  "wake-lock/idlharness.https.any.worker-expected.txt": [
-   "481f78d4911ffa78f727f18bc03134e61ba969ff",
-   "support"
-  ],
   "wake-lock/resources/page1.html": [
    "7fc080d380c4bd46dfb011910e570ee412561b92",
    "support"
@@ -478768,10 +478793,6 @@
    "671852f3c946716cf6cfb6dac6249a30bec1f701",
    "testharness"
   ],
-  "wake-lock/wakelock-abortsignal.https.any.worker-expected.txt": [
-   "c75b5871b2c7798083e191558d9887503c7ca637",
-   "support"
-  ],
   "wake-lock/wakelock-active-document.https.window.js": [
    "f0f1e38ddf9defaf4a484ee5db39ec37e561ade5",
    "testharness"
@@ -478816,10 +478837,6 @@
    "f32cc3c354354f99852bb198760cdbd9229355a4",
    "testharness"
   ],
-  "wake-lock/wakelock-screen-type-on-worker.https.worker-expected.txt": [
-   "7019eb31819a0309d864b0bae9112977e6bbe04b",
-   "support"
-  ],
   "wake-lock/wakelock-screen-type-on-worker.https.worker.js": [
    "28e3394279c0b4311a80aad43ced0f9ea79e029f",
    "testharness"
@@ -478832,10 +478849,6 @@
    "cc37c768272512ec412fb749cebd77afa8662ac3",
    "testharness"
   ],
-  "wake-lock/wakelock-type.https.any.worker-expected.txt": [
-   "9d738db325137ae52ec28c20e296b2ece04fede7",
-   "support"
-  ],
   "wasm/META.yml": [
    "3ea02ee7c9e41831aafbd37436f59b51244b142e",
    "support"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/animation-pseudo-dynamic-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-animations/animation-pseudo-dynamic-001-ref.html
new file mode 100644
index 0000000..30d70aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/animation-pseudo-dynamic-001-ref.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>CSS test reference</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<style>
+.test {
+  display: flex;
+}
+.test::before {
+  content: "";
+  display: block;
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+<div class="test"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/animation-pseudo-dynamic-001.html b/third_party/blink/web_tests/external/wpt/css/css-animations/animation-pseudo-dynamic-001.html
new file mode 100644
index 0000000..e141b62
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/animation-pseudo-dynamic-001.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Animation of pseudo-element is stopped properly in presence of dynamic DOM change that reconstructs the layout tree</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-animations/">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1564366">
+<link rel="match" href="animation-pseudo-dynamic-001-ref.html">
+<style>
+@keyframes anim {
+  from { background-color: red }
+  to { background-color: red }
+}
+.test {
+  display: flex;
+}
+.test::before {
+  content: "";
+  display: block;
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+.tweak::before {
+  animation: anim 2s linear infinite;
+}
+</style>
+<div class="test tweak">foo</div>
+<script>
+onload = function() {
+  const div = document.querySelector(".test");
+  const pseudoStyle = getComputedStyle(div, "::before");
+  div.getBoundingClientRect(); // update layout
+  div.classList.remove("tweak");
+  div.innerHTML = ""; // This is necessary to trigger the bug.
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-016.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-016.html
new file mode 100644
index 0000000..a5dc8763
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-016.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>CSS Flexbox: min-height: auto with flex items containing percentage-sized children</title>
+<link rel="author" title="Google LLC" href="https://www.google.com/" />
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#min-size-auto" />
+<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=981481" />
+<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=984606" />
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
+
+<style>
+.flexbox {
+  display: flex;
+  width: 100px;
+  flex-direction: column;
+}
+.item {
+  flex-basis: 0;
+  background: green;
+}
+.percentage {
+  height: 100%;
+}
+.fixed {
+  height: 100px;
+}
+
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div class="flexbox">
+    <div class="item">
+        <div class="percentage"></div>
+        <div class="fixed"></div>
+    </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/geometry/DOMMatrix2DInit-validate-fixup-expected.txt b/third_party/blink/web_tests/external/wpt/css/geometry/DOMMatrix2DInit-validate-fixup-expected.txt
index 0ffad3a..9e2cb247 100644
--- a/third_party/blink/web_tests/external/wpt/css/geometry/DOMMatrix2DInit-validate-fixup-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/geometry/DOMMatrix2DInit-validate-fixup-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 184 tests; 178 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 184 tests; 175 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS setTransform({a: 1, m11: 2}) (invalid)
 PASS addPath({a: 1, m11: 2}) (invalid)
 PASS setTransform({b: 0, m12: -1}) (invalid)
@@ -57,11 +57,11 @@
 PASS setTransform({d: Infinity, m22: Infinity})
 PASS addPath({d: Infinity, m22: Infinity})
 PASS setTransform({e: -Infinity, m41: -Infinity})
-PASS addPath({e: -Infinity, m41: -Infinity})
+FAIL addPath({e: -Infinity, m41: -Infinity}) assert_equals: expected "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEYklEQVR4Xu3UAQkAAAwCwdm/9HI83BLIOdw5AgQIRAQWySkmAQIEzmB5AgIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlACBB1YxAJfjJb2jAAAAAElFTkSuQmCC" but got "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEoklEQVR4Xu3UwQ3DMAwEQav/ou0G/D0IC0wKUJghs+fxIUCAQETgROY0JgECBB7BcgQECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSILAI1nuJdfFbLv0UX0uAwJ/A4k8uWG6NAIGJgGBNWD1KgMBCQLAWqt4kQGAiIFgTVo8SILAQEKyFqjcJEJgICNaE1aMECCwEBGuh6k0CBCYCgjVh9SgBAgsBwVqoepMAgYmAYE1YPUqAwEJAsBaq3iRAYCIgWBNWjxIgsBAQrIWqNwkQmAgI1oTVowQILAQEa6HqTQIEJgKCNWH1KAECCwHBWqh6kwCBiYBgTVg9SoDAQkCwFqreJEBgIiBYE1aPEiCwEBCshao3CRCYCAjWhNWjBAgsBARroepNAgQmAoI1YfUoAQILAcFaqHqTAIGJgGBNWD1KgMBCQLAWqt4kQGAiIFgTVo8SILAQEKyFqjcJEJgILII1GdSjBAgQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICHzhOB6X+LLhOgAAAABJRU5ErkJggg=="
 PASS setTransform({f: NaN, m42: NaN})
-PASS addPath({f: NaN, m42: NaN})
+FAIL addPath({f: NaN, m42: NaN}) assert_equals: expected "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEYklEQVR4Xu3UAQkAAAwCwdm/9HI83BLIOdw5AgQIRAQWySkmAQIEzmB5AgIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlACBB1YxAJfjJb2jAAAAAElFTkSuQmCC" but got "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEoklEQVR4Xu3UwQ3DMAwEQav/ou0G/D0IC0wKUJghs+fxIUCAQETgROY0JgECBB7BcgQECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSILAI1nuJdfFbLv0UX0uAwJ/A4k8uWG6NAIGJgGBNWD1KgMBCQLAWqt4kQGAiIFgTVo8SILAQEKyFqjcJEJgICNaE1aMECCwEBGuh6k0CBCYCgjVh9SgBAgsBwVqoepMAgYmAYE1YPUqAwEJAsBaq3iRAYCIgWBNWjxIgsBAQrIWqNwkQmAgI1oTVowQILAQEa6HqTQIEJgKCNWH1KAECCwHBWqh6kwCBiYBgTVg9SoDAQkCwFqreJEBgIiBYE1aPEiCwEBCshao3CRCYCAjWhNWjBAgsBARroepNAgQmAoI1YfUoAQILAcFaqHqTAIGJgGBNWD1KgMBCQLAWqt4kQGAiIFgTVo8SILAQEKyFqjcJEJgILII1GdSjBAgQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICHzhOB6X+LLhOgAAAABJRU5ErkJggg=="
 PASS setTransform({f: NaN, m42: NaN, is2D: true})
-PASS addPath({f: NaN, m42: NaN, is2D: true})
+FAIL addPath({f: NaN, m42: NaN, is2D: true}) assert_equals: expected "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEYklEQVR4Xu3UAQkAAAwCwdm/9HI83BLIOdw5AgQIRAQWySkmAQIEzmB5AgIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlACBB1YxAJfjJb2jAAAAAElFTkSuQmCC" but got "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEoklEQVR4Xu3UwQ3DMAwEQav/ou0G/D0IC0wKUJghs+fxIUCAQETgROY0JgECBB7BcgQECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSILAI1nuJdfFbLv0UX0uAwJ/A4k8uWG6NAIGJgGBNWD1KgMBCQLAWqt4kQGAiIFgTVo8SILAQEKyFqjcJEJgICNaE1aMECCwEBGuh6k0CBCYCgjVh9SgBAgsBwVqoepMAgYmAYE1YPUqAwEJAsBaq3iRAYCIgWBNWjxIgsBAQrIWqNwkQmAgI1oTVowQILAQEa6HqTQIEJgKCNWH1KAECCwHBWqh6kwCBiYBgTVg9SoDAQkCwFqreJEBgIiBYE1aPEiCwEBCshao3CRCYCAjWhNWjBAgsBARroepNAgQmAoI1YfUoAQILAcFaqHqTAIGJgGBNWD1KgMBCQLAWqt4kQGAiIFgTVo8SILAQEKyFqjcJEJgILII1GdSjBAgQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICAhWZlUGJUBAsNwAAQIZAcHKrMqgBAgIlhsgQCAjIFiZVRmUAAHBcgMECGQEBCuzKoMSICBYboAAgYyAYGVWZVACBATLDRAgkBEQrMyqDEqAgGC5AQIEMgKClVmVQQkQECw3QIBARkCwMqsyKAECguUGCBDICHzhOB6X+LLhOgAAAABJRU5ErkJggg=="
 PASS setTransform({f: 0, m42: null})
 PASS addPath({f: 0, m42: null})
 PASS setTransform({f: -0, m42: null})
diff --git a/third_party/blink/web_tests/external/wpt/css/geometry/DOMMatrix2DInit-validate-fixup.html b/third_party/blink/web_tests/external/wpt/css/geometry/DOMMatrix2DInit-validate-fixup.html
index 5fb7e7d2..7ef4ca8 100644
--- a/third_party/blink/web_tests/external/wpt/css/geometry/DOMMatrix2DInit-validate-fixup.html
+++ b/third_party/blink/web_tests/external/wpt/css/geometry/DOMMatrix2DInit-validate-fixup.html
@@ -39,6 +39,8 @@
   return window.canvas.toDataURL();
 }
 
+var emptyCanvasURL = window.canvas.toDataURL();
+
 [
   {a: 1, m11: 2},
   {b: 0, m12: -1},
@@ -95,10 +97,10 @@
   [{c: 0, m21: -0},                matrix2D({m21: -0})],
   [{c: -0, m21: 0},                matrix2D({m21: 0})],
   [{c: -0, m21: -0},               matrix2D({m21: -0})],
-  [{d: Infinity, m22: Infinity},   matrix2D({})], // should be silently ignored
-  [{e: -Infinity, m41: -Infinity}, matrix2D({})], // should be silently ignored
-  [{f: NaN, m42: NaN},             matrix2D({})], // should be silently ignored
-  [{f: NaN, m42: NaN, is2D: true}, matrix2D({})], // should be silently ignored
+  [{d: Infinity, m22: Infinity},   null], // setTransform: silently ignore / addPath: silently halt
+  [{e: -Infinity, m41: -Infinity}, null], // setTransform: silently ignore / addPath: silently halt
+  [{f: NaN, m42: NaN},             null], // setTransform: silently ignore / addPath: silently halt
+  [{f: NaN, m42: NaN, is2D: true}, null], // setTransform: silently ignore / addPath: silently halt
   [{f: 0, m42: null},              matrix2D({m42: 0})], // null is converted to 0
   [{f: -0, m42: null},             matrix2D({m42: 0})], // null is converted to 0
   [{a: 2},                         matrix2D({m11: 2})],
@@ -171,12 +173,14 @@
     ctx.resetTransform();
     ctx.setTransform(dict);
     const matrix = ctx.getTransform();
-    checkMatrix(matrix, expected);
+    checkMatrix(matrix, expected || matrix2D({}));
   }, `setTransform(${format_dict(dict)})`);
 
   test(() => {
-    var expectedResultURL = drawRectWithSetTransform(ctx, expected);
-    var actualResultURL = drawRectWithAddPathTransform(ctx, expected);
+    var expectedResultURL = expected ?
+      drawRectWithSetTransform(ctx, expected) :
+      emptyCanvasURL;
+    var actualResultURL = drawRectWithAddPathTransform(ctx, dict);
     assert_equals(actualResultURL, expectedResultURL);
   }, `addPath(${format_dict(dict)})`);
  });
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html
index 97df7ef..2474a11f 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html
@@ -9,7 +9,13 @@
     async_test(function(t) {
         var video = document.querySelector("video");
         var track = document.querySelector("track");
-        track.onload = t.step_func(trackLoaded);
+        if (track.readyState != HTMLTrackElement.LOADED) {
+            assert_not_equals(track.readyState, HTMLTrackElement.ERROR,
+                              "track failed to load resource.");
+            track.onload = t.step_func(trackLoaded);
+        } else {
+            trackLoaded();
+        }
 
         var cueCount = 0;
         var textTrack;
diff --git a/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/README.md b/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/README.md
new file mode 100644
index 0000000..3f9d75f5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/README.md
@@ -0,0 +1,4 @@
+This directory contains a built version of the [webidl2.js library](https://github.com/w3c/webidl2.js).
+It is built by running `npx webpack --mode none` at the root of that repository.
+
+The `webidl2.js.headers` file is a local addition to ensure the script is interpreted as UTF-8.
diff --git a/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/webidl2.js b/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/webidl2.js
index d909c30..9cb975a 100644
--- a/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/webidl2.js
+++ b/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/webidl2.js
@@ -103,10 +103,10 @@
 /* harmony import */ var _lib_webidl2_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "parse", function() { return _lib_webidl2_js__WEBPACK_IMPORTED_MODULE_0__["parse"]; });
 
-/* harmony import */ var _lib_writer_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
+/* harmony import */ var _lib_writer_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(14);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "write", function() { return _lib_writer_js__WEBPACK_IMPORTED_MODULE_1__["write"]; });
 
-/* harmony import */ var _lib_validator_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(12);
+/* harmony import */ var _lib_validator_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(15);
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "validate", function() { return _lib_validator_js__WEBPACK_IMPORTED_MODULE_2__["validate"]; });
 
 
@@ -122,13 +122,13 @@
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parse", function() { return parse; });
 /* harmony import */ var _productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
-/* harmony import */ var _productions_array_base_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
-/* harmony import */ var _productions_base_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6);
-/* harmony import */ var _productions_token_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(7);
-/* harmony import */ var _productions_default_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(8);
-/* harmony import */ var _productions_enum_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(9);
-/* harmony import */ var _productions_includes_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(10);
+/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
+/* harmony import */ var _productions_base_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
+/* harmony import */ var _productions_default_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
+/* harmony import */ var _productions_enum_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(12);
+/* harmony import */ var _productions_includes_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(13);
+/* harmony import */ var _productions_type_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(3);
+/* harmony import */ var _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(9);
 
 
 
@@ -148,10 +148,7 @@
 function parseByTokens(tokeniser, options) {
   const source = tokeniser.source;
 
-  const DECIMAL = "decimal";
-  const INT = "integer";
   const ID = "identifier";
-  const STR = "string";
 
   function error(str) {
     tokeniser.error(str);
@@ -169,320 +166,17 @@
     return tokeniser.unconsume(position);
   }
 
-  function integer_type() {
-    const prefix = consume("unsigned");
-    const base = consume("short", "long");
-    if (base) {
-      const postfix = consume("long");
-      return new Type({ source, tokens: { prefix, base, postfix } });
-    }
-    if (prefix) error("Failed to parse integer type");
-  }
-
-  function float_type() {
-    const prefix = consume("unrestricted");
-    const base = consume("float", "double");
-    if (base) {
-      return new Type({ source, tokens: { prefix, base } });
-    }
-    if (prefix) error("Failed to parse float type");
-  }
-
-  function primitive_type() {
-    const num_type = integer_type() || float_type();
-    if (num_type) return num_type;
-    const base = consume("boolean", "byte", "octet");
-    if (base) {
-      return new Type({ source, tokens: { base } });
-    }
-  }
-
-  function type_suffix(obj) {
-    const nullable = consume("?");
-    if (nullable) {
-      obj.tokens.nullable = nullable;
-    }
-    if (probe("?")) error("Can't nullable more than once");
-  }
-
-  class Type extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
-    constructor({ source, tokens }) {
-      super({ source, tokens });
-      Object.defineProperty(this, "subtype", { value: [] });
-      this.extAttrs = [];
-    }
-
-    get generic() {
-      return "";
-    }
-    get nullable() {
-      return !!this.tokens.nullable;
-    }
-    get union() {
-      return false;
-    }
-    get idlType() {
-      if (this.subtype.length) {
-        return this.subtype;
-      }
-      // Adding prefixes/postfixes for "unrestricted float", etc.
-      const name = [
-        this.tokens.prefix,
-        this.tokens.base,
-        this.tokens.postfix
-      ].filter(t => t).map(t => t.value).join(" ");
-      return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(name);
-    }
-  }
-
-  class GenericType extends Type {
-    static parse(typeName) {
-      const base = consume("FrozenArray", "Promise", "sequence", "record");
-      if (!base) {
-        return;
-      }
-      const ret = new GenericType({ source, tokens: { base } });
-      ret.tokens.open = consume("<") || error(`No opening bracket after ${base.type}`);
-      switch (base.type) {
-        case "Promise": {
-          if (probe("[")) error("Promise type cannot have extended attribute");
-          const subtype = return_type(typeName) || error("Missing Promise subtype");
-          ret.subtype.push(subtype);
-          break;
-        }
-        case "sequence":
-        case "FrozenArray": {
-          const subtype = type_with_extended_attributes(typeName) || error(`Missing ${base.type} subtype`);
-          ret.subtype.push(subtype);
-          break;
-        }
-        case "record": {
-          if (probe("[")) error("Record key cannot have extended attribute");
-          const keyType = consume(..._tokeniser_js__WEBPACK_IMPORTED_MODULE_1__["stringTypes"]) || error(`Record key must be one of: ${_tokeniser_js__WEBPACK_IMPORTED_MODULE_1__["stringTypes"].join(", ")}`);
-          const keyIdlType = new Type({ source, tokens: { base: keyType }});
-          keyIdlType.tokens.separator = consume(",") || error("Missing comma after record key type");
-          keyIdlType.type = typeName;
-          const valueType = type_with_extended_attributes(typeName) || error("Error parsing generic type record");
-          ret.subtype.push(keyIdlType, valueType);
-          break;
-        }
-      }
-      if (!ret.idlType) error(`Error parsing generic type ${base.type}`);
-      ret.tokens.close = consume(">") || error(`Missing closing bracket after ${base.type}`);
-      return ret;
-    }
-
-    get generic() {
-      return this.tokens.base.value;
-    }
-  }
-
-  function single_type(typeName) {
-    let ret = GenericType.parse(typeName) || primitive_type();
-    if (!ret) {
-      const base = consume(ID, ..._tokeniser_js__WEBPACK_IMPORTED_MODULE_1__["stringTypes"]);
-      if (!base) {
-        return;
-      }
-      ret = new Type({ source, tokens: { base } });
-      if (probe("<")) error(`Unsupported generic type ${base.value}`);
-    }
-    if (ret.generic === "Promise" && probe("?")) {
-      error("Promise type cannot be nullable");
-    }
-    ret.type = typeName || null;
-    type_suffix(ret);
-    if (ret.nullable && ret.idlType === "any") error("Type `any` cannot be made nullable");
-    return ret;
-  }
-
-  class UnionType extends Type {
-    static parse(type) {
-      const tokens = {};
-      tokens.open = consume("(");
-      if (!tokens.open) return;
-      const ret = new UnionType({ source, tokens });
-      ret.type = type || null;
-      while (true) {
-        const typ = type_with_extended_attributes() || error("No type after open parenthesis or 'or' in union type");
-        if (typ.idlType === "any") error("Type `any` cannot be included in a union type");
-        ret.subtype.push(typ);
-        const or = consume("or");
-        if (or) {
-          typ.tokens.separator = or;
-        }
-        else break;
-      }
-      if (ret.idlType.length < 2) {
-        error("At least two types are expected in a union type but found less");
-      }
-      tokens.close = consume(")") || error("Unterminated union type");
-      type_suffix(ret);
-      return ret;
-    }
-
-    get union() {
-      return true;
-    }
-  }
-
-  function type(typeName) {
-    return single_type(typeName) || UnionType.parse(typeName);
-  }
-
-  function type_with_extended_attributes(typeName) {
-    const extAttrs = ExtendedAttributes.parse();
-    const ret = type(typeName);
-    if (ret) ret.extAttrs = extAttrs;
-    return ret;
-  }
-
-  class Argument extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
-    static parse() {
-      const start_position = tokeniser.position;
-      const tokens = {};
-      const ret = new Argument({ source, tokens });
-      ret.extAttrs = ExtendedAttributes.parse();
-      tokens.optional = consume("optional");
-      ret.idlType = type_with_extended_attributes("argument-type");
-      if (!ret.idlType) {
-        return unconsume(start_position);
-      }
-      if (!tokens.optional) {
-        tokens.variadic = consume("...");
-      }
-      tokens.name = consume(ID, ..._tokeniser_js__WEBPACK_IMPORTED_MODULE_1__["argumentNameKeywords"]);
-      if (!tokens.name) {
-        return unconsume(start_position);
-      }
-      ret.default = tokens.optional ? _productions_default_js__WEBPACK_IMPORTED_MODULE_5__["Default"].parse(tokeniser) : null;
-      return ret;
-    }
-
-    get optional() {
-      return !!this.tokens.optional;
-    }
-    get variadic() {
-      return !!this.tokens.variadic;
-    }
-    get name() {
-      return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(this.tokens.name.value);
-    }
-  }
-
-  function argument_list() {
-    return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["list"])(tokeniser, { parser: Argument.parse, listName: "arguments list" });
-  }
-
-  function identifiers() {
-    const ids = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["list"])(tokeniser, { parser: _productions_token_js__WEBPACK_IMPORTED_MODULE_4__["Token"].parser(tokeniser, ID), listName: "identifier list" });
-    if (!ids.length) {
-      error("Expected identifiers but none found");
-    }
-    return ids;
-  }
-
-  class ExtendedAttributeParameters extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
-    static parse() {
-      const tokens = { assign: consume("=") };
-      const ret = new ExtendedAttributeParameters({ source, tokens });
-      if (tokens.assign) {
-        tokens.secondaryName = consume(ID, DECIMAL, INT, STR);
-      }
-      tokens.open = consume("(");
-      if (tokens.open) {
-        ret.list = ret.rhsType === "identifier-list" ?
-          // [Exposed=(Window,Worker)]
-          identifiers() :
-          // [NamedConstructor=Audio(DOMString src)] or [Constructor(DOMString str)]
-          argument_list();
-        tokens.close = consume(")") || error("Unexpected token in extended attribute argument list");
-      } else if (ret.hasRhs && !tokens.secondaryName) {
-        error("No right hand side to extended attribute assignment");
-      }
-      return ret;
-    }
-
-    get rhsType() {
-      return !this.tokens.assign ? null :
-        !this.tokens.secondaryName ? "identifier-list" :
-        this.tokens.secondaryName.type;
-    }
-  }
-
-  class SimpleExtendedAttribute extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
-    static parse() {
-      const name = consume(ID);
-      if (name) {
-        return new SimpleExtendedAttribute({
-          tokens: { name },
-          params: ExtendedAttributeParameters.parse()
-        });
-      }
-    }
-
-    constructor({ source, tokens, params }) {
-      super({ source, tokens });
-      Object.defineProperty(this, "params", { value: params });
-    }
-
-    get type() {
-      return "extended-attribute";
-    }
-    get name() {
-      return this.tokens.name.value;
-    }
-    get rhs() {
-      const { rhsType: type, tokens, list } = this.params;
-      if (!type) {
-        return null;
-      }
-      const value = type === "identifier-list" ? list : tokens.secondaryName.value;
-      return { type, value };
-    }
-    get arguments() {
-      const { rhsType, list } = this.params;
-      if (!list || rhsType === "identifier-list") {
-        return [];
-      }
-      return list;
-    }
-  }
-
-  // Note: we parse something simpler than the official syntax. It's all that ever
-  // seems to be used
-  class ExtendedAttributes extends _productions_array_base_js__WEBPACK_IMPORTED_MODULE_2__["ArrayBase"] {
-    static parse() {
-      const tokens = {};
-      tokens.open = consume("[");
-      if (!tokens.open) return [];
-      const ret = new ExtendedAttributes({ source, tokens });
-      ret.push(...Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["list"])(tokeniser, {
-        parser: SimpleExtendedAttribute.parse,
-        listName: "extended attribute"
-      }));
-      tokens.close = consume("]") || error("Unexpected form of extended attribute");
-      if (!ret.length) {
-        error("Found an empty extended attribute");
-      }
-      if (probe("[")) {
-        error("Illegal double extended attribute lists, consider merging them");
-      }
-      return ret;
-    }
-  }
-
-  class Constant extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
+  class Constant extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] {
     static parse() {
       const tokens = {};
       tokens.base = consume("const");
       if (!tokens.base) {
         return;
       }
-      let idlType = primitive_type();
+      let idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["primitive_type"])(tokeniser);
       if (!idlType) {
         const base = consume(ID) || error("No type for const");
-        idlType = new Type({ source, tokens: { base } });
+        idlType = new _productions_type_js__WEBPACK_IMPORTED_MODULE_6__["Type"]({ source, tokens: { base } });
       }
       if (probe("?")) {
         error("Unexpected nullable constant type");
@@ -508,16 +202,16 @@
     }
   }
 
-  class CallbackFunction extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
+  class CallbackFunction extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] {
     static parse(base) {
       const tokens = { base };
       const ret = new CallbackFunction({ source, tokens });
       tokens.name = consume(ID) || error("No name for callback");
       tokeniser.current = ret;
       tokens.assign = consume("=") || error("No assignment in callback");
-      ret.idlType = return_type() || error("Missing return type");
+      ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["return_type"])(tokeniser) || error("Missing return type");
       tokens.open = consume("(") || error("No arguments in callback");
-      ret.arguments = argument_list();
+      ret.arguments = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["argument_list"])(tokeniser);
       tokens.close = consume(")") || error("Unterminated callback");
       tokens.termination = consume(";") || error("Unterminated callback");
       return ret;
@@ -541,7 +235,7 @@
     return CallbackFunction.parse(callback);
   }
 
-  class Attribute extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
+  class Attribute extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] {
     static parse({ special, noInherit = false, readonly = false } = {}) {
       const start_position = tokeniser.position;
       const tokens = { special };
@@ -561,7 +255,7 @@
         unconsume(start_position);
         return;
       }
-      ret.idlType = type_with_extended_attributes("attribute-type") || error("No type in attribute");
+      ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser, "attribute-type") || error("No type in attribute");
       switch (ret.idlType.generic) {
         case "sequence":
         case "record": error(`Attributes cannot accept ${ret.idlType.generic} types`);
@@ -588,20 +282,7 @@
     }
   }
 
-  function return_type(typeName) {
-    const typ = type(typeName || "return-type");
-    if (typ) {
-      return typ;
-    }
-    const voidToken = consume("void");
-    if (voidToken) {
-      const ret = new Type({ source, tokens: { base: voidToken } });
-      ret.type = "return-type";
-      return ret;
-    }
-  }
-
-  class Operation extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
+  class Operation extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] {
     static parse({ special, regular } = {}) {
       const tokens = { special };
       const ret = new Operation({ source, tokens });
@@ -615,10 +296,10 @@
       if (!special && !regular) {
         tokens.special = consume("getter", "setter", "deleter");
       }
-      ret.idlType = return_type() || error("Missing return type");
+      ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["return_type"])(tokeniser) || error("Missing return type");
       tokens.name = consume(ID);
       tokens.open = consume("(") || error("Invalid operation");
-      ret.arguments = argument_list();
+      ret.arguments = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["argument_list"])(tokeniser);
       tokens.close = consume(")") || error("Unterminated operation");
       tokens.termination = consume(";") || error("Unterminated attribute");
       return ret;
@@ -660,7 +341,7 @@
     return member;
   }
 
-  class IterableLike extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
+  class IterableLike extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] {
     static parse() {
       const start_position = tokeniser.position;
       const tokens = {};
@@ -679,12 +360,12 @@
       const secondTypeAllowed = secondTypeRequired || type === "iterable";
 
       tokens.open = consume("<") || error(`Error parsing ${type} declaration`);
-      const first = type_with_extended_attributes() || error(`Error parsing ${type} declaration`);
+      const first = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser) || error(`Error parsing ${type} declaration`);
       ret.idlType = [first];
       if (secondTypeAllowed) {
         first.tokens.separator = consume(",");
         if (first.tokens.separator) {
-          ret.idlType.push(type_with_extended_attributes());
+          ret.idlType.push(Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser));
         }
         else if (secondTypeRequired)
           error(`Missing second type argument in ${type} declaration`);
@@ -712,7 +393,7 @@
     return { colon, inheritance };
   }
 
-  class Container extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
+  class Container extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] {
     static parse(instance, { type, inheritable, allowedMembers }) {
       const { tokens } = instance;
       tokens.name = consume(ID) || error("No name for interface");
@@ -728,7 +409,7 @@
           tokens.termination = consume(";") || error(`Missing semicolon after ${type}`);
           return instance;
         }
-        const ea = ExtendedAttributes.parse();
+        const ea = _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_7__["ExtendedAttributes"].parse(tokeniser);
         let mem;
         for (const [parser, ...args] of allowedMembers) {
           mem = parser(...args);
@@ -866,15 +547,15 @@
     }
   }
 
-  class Field extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
+  class Field extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] {
     static parse() {
       const tokens = {};
       const ret = new Field({ source, tokens });
-      ret.extAttrs = ExtendedAttributes.parse();
+      ret.extAttrs = _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_7__["ExtendedAttributes"].parse(tokeniser);
       tokens.required = consume("required");
-      ret.idlType = type_with_extended_attributes("dictionary-type") || error("No type for dictionary member");
+      ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser, "dictionary-type") || error("No type for dictionary member");
       tokens.name = consume(ID) || error("No name for dictionary member");
-      ret.default = _productions_default_js__WEBPACK_IMPORTED_MODULE_5__["Default"].parse(tokeniser);
+      ret.default = _productions_default_js__WEBPACK_IMPORTED_MODULE_3__["Default"].parse(tokeniser);
       if (tokens.required && ret.default) error("Required member must not have a default");
       tokens.termination = consume(";") || error("Unterminated dictionary member");
       return ret;
@@ -891,7 +572,7 @@
     }
   }
 
-  class Typedef extends _productions_base_js__WEBPACK_IMPORTED_MODULE_3__["Base"] {
+  class Typedef extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] {
     static parse() {
       const tokens = {};
       const ret = new Typedef({ source, tokens });
@@ -899,7 +580,7 @@
       if (!tokens.base) {
         return;
       }
-      ret.idlType = type_with_extended_attributes("typedef-type") || error("No type in typedef");
+      ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser, "typedef-type") || error("No type in typedef");
       tokens.name = consume(ID) || error("No name in typedef");
       tokeniser.current = ret;
       tokens.termination = consume(";") || error("Unterminated typedef");
@@ -919,9 +600,9 @@
       interface_() ||
       partial() ||
       Dictionary.parse() ||
-      _productions_enum_js__WEBPACK_IMPORTED_MODULE_6__["Enum"].parse(tokeniser) ||
+      _productions_enum_js__WEBPACK_IMPORTED_MODULE_4__["Enum"].parse(tokeniser) ||
       Typedef.parse() ||
-      _productions_includes_js__WEBPACK_IMPORTED_MODULE_7__["Includes"].parse(tokeniser) ||
+      _productions_includes_js__WEBPACK_IMPORTED_MODULE_5__["Includes"].parse(tokeniser) ||
       Namespace.parse();
   }
 
@@ -929,7 +610,7 @@
     if (!source.length) return [];
     const defs = [];
     while (true) {
-      const ea = ExtendedAttributes.parse();
+      const ea = _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_7__["ExtendedAttributes"].parse(tokeniser);
       const def = definition();
       if (!def) {
         if (ea.length) error("Stray extended attributes");
@@ -965,6 +646,20 @@
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "list", function() { return list; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "const_value", function() { return const_value; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "const_data", function() { return const_data; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "primitive_type", function() { return primitive_type; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identifiers", function() { return identifiers; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "argument_list", function() { return argument_list; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "type_with_extended_attributes", function() { return type_with_extended_attributes; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "return_type", function() { return return_type; });
+/* harmony import */ var _type_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
+/* harmony import */ var _argument_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
+/* harmony import */ var _token_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11);
+/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
+
+
+
+
+
 /**
  * @param {string} identifier
  */
@@ -1024,9 +719,11 @@
       return { type: "Infinity", negative: type.startsWith("-") };
     case "[":
       return { type: "sequence", value: [] };
+    case "{":
+      return { type: "dictionary" };
     case "decimal":
     case "integer":
-        return { type: "number", value };
+      return { type: "number", value };
     case "string":
       return { type: "string", value: value.slice(1, -1) };
     default:
@@ -1034,6 +731,84 @@
   }
 }
 
+/**
+ * @param {import("../tokeniser").Tokeniser} tokeniser
+ */
+function primitive_type(tokeniser) {
+  function integer_type() {
+    const prefix = tokeniser.consume("unsigned");
+    const base = tokeniser.consume("short", "long");
+    if (base) {
+      const postfix = tokeniser.consume("long");
+      return new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source, tokens: { prefix, base, postfix } });
+    }
+    if (prefix) tokeniser.error("Failed to parse integer type");
+  }
+
+  function decimal_type() {
+    const prefix = tokeniser.consume("unrestricted");
+    const base = tokeniser.consume("float", "double");
+    if (base) {
+      return new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source, tokens: { prefix, base } });
+    }
+    if (prefix) tokeniser.error("Failed to parse float type");
+  }
+
+  const { source } = tokeniser;
+  const num_type = integer_type(tokeniser) || decimal_type(tokeniser);
+  if (num_type) return num_type;
+  const base = tokeniser.consume("boolean", "byte", "octet");
+  if (base) {
+    return new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source, tokens: { base } });
+  }
+}
+
+/**
+ * @param {import("../tokeniser").Tokeniser} tokeniser
+ */
+function identifiers(tokeniser) {
+  const ids = list(tokeniser, { parser: _token_js__WEBPACK_IMPORTED_MODULE_2__["Token"].parser(tokeniser, "identifier"), listName: "identifier list" });
+  if (!ids.length) {
+    tokeniser.error("Expected identifiers but none found");
+  }
+  return ids;
+}
+
+/**
+ * @param {import("../tokeniser").Tokeniser} tokeniser
+ */
+function argument_list(tokeniser) {
+  return list(tokeniser, { parser: _argument_js__WEBPACK_IMPORTED_MODULE_1__["Argument"].parse, listName: "arguments list" });
+}
+
+/**
+ * @param {import("../tokeniser").Tokeniser} tokeniser
+ * @param {string} typeName
+ */
+function type_with_extended_attributes(tokeniser, typeName) {
+  const extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__["ExtendedAttributes"].parse(tokeniser);
+  const ret = _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"].parse(tokeniser, typeName);
+  if (ret) ret.extAttrs = extAttrs;
+  return ret;
+}
+
+/**
+ * @param {import("../tokeniser").Tokeniser} tokeniser
+ * @param {string} typeName
+ */
+function return_type(tokeniser, typeName) {
+  const typ = _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"].parse(tokeniser, typeName || "return-type");
+  if (typ) {
+    return typ;
+  }
+  const voidToken = tokeniser.consume("void");
+  if (voidToken) {
+    const ret = new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source: tokeniser.source, tokens: { base: voidToken } });
+    ret.type = "return-type";
+    return ret;
+  }
+}
+
 
 /***/ }),
 /* 3 */
@@ -1041,10 +816,200 @@
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Type", function() { return Type; });
+/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
+/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
+/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
+
+
+
+
+/**
+ * @param {import("../tokeniser").Tokeniser} tokeniser
+ * @param {string} typeName
+ */
+function generic_type(tokeniser, typeName) {
+  const base = tokeniser.consume("FrozenArray", "Promise", "sequence", "record");
+  if (!base) {
+    return;
+  }
+  const ret = new Type({ source: tokeniser.source, tokens: { base } });
+  ret.tokens.open = tokeniser.consume("<") || tokeniser.error(`No opening bracket after ${base.type}`);
+  switch (base.type) {
+    case "Promise": {
+      if (tokeniser.probe("[")) tokeniser.error("Promise type cannot have extended attribute");
+      const subtype = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["return_type"])(tokeniser, typeName) || tokeniser.error("Missing Promise subtype");
+      ret.subtype.push(subtype);
+      break;
+    }
+    case "sequence":
+    case "FrozenArray": {
+      const subtype = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser, typeName) || tokeniser.error(`Missing ${base.type} subtype`);
+      ret.subtype.push(subtype);
+      break;
+    }
+    case "record": {
+      if (tokeniser.probe("[")) tokeniser.error("Record key cannot have extended attribute");
+      const keyType = tokeniser.consume(..._tokeniser_js__WEBPACK_IMPORTED_MODULE_2__["stringTypes"]) || tokeniser.error(`Record key must be one of: ${_tokeniser_js__WEBPACK_IMPORTED_MODULE_2__["stringTypes"].join(", ")}`);
+      const keyIdlType = new Type({ source: tokeniser.source, tokens: { base: keyType }});
+      keyIdlType.tokens.separator = tokeniser.consume(",") || tokeniser.error("Missing comma after record key type");
+      keyIdlType.type = typeName;
+      const valueType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser, typeName) || tokeniser.error("Error parsing generic type record");
+      ret.subtype.push(keyIdlType, valueType);
+      break;
+    }
+  }
+  if (!ret.idlType) tokeniser.error(`Error parsing generic type ${base.type}`);
+  ret.tokens.close = tokeniser.consume(">") || tokeniser.error(`Missing closing bracket after ${base.type}`);
+  return ret;
+}
+
+/**
+ * @param {import("../tokeniser").Tokeniser} tokeniser
+ */
+function type_suffix(tokeniser, obj) {
+  const nullable = tokeniser.consume("?");
+  if (nullable) {
+    obj.tokens.nullable = nullable;
+  }
+  if (tokeniser.probe("?")) tokeniser.error("Can't nullable more than once");
+}
+
+/**
+ * @param {import("../tokeniser").Tokeniser} tokeniser
+ * @param {string} typeName
+ */
+function single_type(tokeniser, typeName) {
+  let ret = generic_type(tokeniser, typeName) || Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["primitive_type"])(tokeniser);
+  if (!ret) {
+    const base = tokeniser.consume("identifier", ..._tokeniser_js__WEBPACK_IMPORTED_MODULE_2__["stringTypes"]);
+    if (!base) {
+      return;
+    }
+    ret = new Type({ source: tokeniser.source, tokens: { base } });
+    if (tokeniser.probe("<")) tokeniser.error(`Unsupported generic type ${base.value}`);
+  }
+  if (ret.generic === "Promise" && tokeniser.probe("?")) {
+    tokeniser.error("Promise type cannot be nullable");
+  }
+  ret.type = typeName || null;
+  type_suffix(tokeniser, ret);
+  if (ret.nullable && ret.idlType === "any") tokeniser.error("Type `any` cannot be made nullable");
+  return ret;
+}
+
+/**
+ * @param {import("../tokeniser").Tokeniser} tokeniser
+ * @param {string} type
+ */
+function union_type(tokeniser, type) {
+  const tokens = {};
+  tokens.open = tokeniser.consume("(");
+  if (!tokens.open) return;
+  const ret = new Type({ source: tokeniser.source, tokens });
+  ret.type = type || null;
+  while (true) {
+    const typ = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser) || tokeniser.error("No type after open parenthesis or 'or' in union type");
+    if (typ.idlType === "any") tokeniser.error("Type `any` cannot be included in a union type");
+    ret.subtype.push(typ);
+    const or = tokeniser.consume("or");
+    if (or) {
+      typ.tokens.separator = or;
+    }
+    else break;
+  }
+  if (ret.idlType.length < 2) {
+    tokeniser.error("At least two types are expected in a union type but found less");
+  }
+  tokens.close = tokeniser.consume(")") || tokeniser.error("Unterminated union type");
+  type_suffix(tokeniser, ret);
+  return ret;
+}
+
+class Type extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] {
+  /**
+   * @param {import("../tokeniser").Tokeniser} tokeniser
+   * @param {string} typeName
+   */
+  static parse(tokeniser, typeName) {
+    return single_type(tokeniser, typeName) || union_type(tokeniser, typeName);
+  }
+
+  constructor({ source, tokens }) {
+    super({ source, tokens });
+    Object.defineProperty(this, "subtype", { value: [] });
+    this.extAttrs = [];
+  }
+
+  get generic() {
+    if (this.subtype.length && this.tokens.base) {
+      return this.tokens.base.value;
+    }
+    return "";
+  }
+  get nullable() {
+    return Boolean(this.tokens.nullable);
+  }
+  get union() {
+    return Boolean(this.subtype.length) && !this.tokens.base;
+  }
+  get idlType() {
+    if (this.subtype.length) {
+      return this.subtype;
+    }
+    // Adding prefixes/postfixes for "unrestricted float", etc.
+    const name = [
+      this.tokens.prefix,
+      this.tokens.base,
+      this.tokens.postfix
+    ].filter(t => t).map(t => t.value).join(" ");
+    return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["unescape"])(name);
+  }
+}
+
+
+/***/ }),
+/* 4 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Base", function() { return Base; });
+class Base {
+  constructor({ source, tokens }) {
+    Object.defineProperties(this, {
+      source: { value: source },
+      tokens: { value: tokens }
+    });
+  }
+
+  toJSON() {
+    const json = { type: undefined, name: undefined, inheritance: undefined };
+    let proto = this;
+    while (proto !== Object.prototype) {
+      const descMap = Object.getOwnPropertyDescriptors(proto);
+      for (const [key, value] of Object.entries(descMap)) {
+        if (value.enumerable || value.get) {
+          json[key] = this[key];
+        }
+      }
+      proto = Object.getPrototypeOf(proto);
+    }
+    return json;
+  }
+}
+
+
+/***/ }),
+/* 5 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "stringTypes", function() { return stringTypes; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "argumentNameKeywords", function() { return argumentNameKeywords; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Tokeniser", function() { return Tokeniser; });
-/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
+/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
 
 
 // These regular expressions use the sticky flag so they will only match at
@@ -1281,7 +1246,7 @@
 
 
 /***/ }),
-/* 4 */
+/* 6 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -1365,81 +1330,56 @@
 
 
 /***/ }),
-/* 5 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayBase", function() { return ArrayBase; });
-class ArrayBase extends Array {
-  constructor({ source, tokens }) {
-    super();
-    Object.defineProperties(this, {
-      source: { value: source },
-      tokens: { value: tokens }
-    });
-  }
-}
-
-
-/***/ }),
-/* 6 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Base", function() { return Base; });
-class Base {
-  constructor({ source, tokens }) {
-    Object.defineProperties(this, {
-      source: { value: source },
-      tokens: { value: tokens }
-    });
-  }
-
-  toJSON() {
-    const json = { type: undefined, name: undefined, inheritance: undefined };
-    let proto = this;
-    while (proto !== Object.prototype) {
-      const descMap = Object.getOwnPropertyDescriptors(proto);
-      for (const [key, value] of Object.entries(descMap)) {
-        if (value.enumerable || value.get) {
-          json[key] = this[key];
-        }
-      }
-      proto = Object.getPrototypeOf(proto);
-    }
-    return json;
-  }
-}
-
-
-/***/ }),
 /* 7 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Token", function() { return Token; });
-/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Argument", function() { return Argument; });
+/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
+/* harmony import */ var _default_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
+/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9);
+/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(2);
+/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5);
 
 
-class Token extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] {
+
+
+
+
+class Argument extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] {
   /**
    * @param {import("../tokeniser").Tokeniser} tokeniser
-   * @param {string} type
    */
-  static parser(tokeniser, type) {
-    return () => {
-      const value = tokeniser.consume(type);
-      if (value) {
-        return new Token({ source: tokeniser.source, tokens: { value } });
-      }
-    };
+  static parse(tokeniser) {
+    const start_position = tokeniser.position;
+    const tokens = {};
+    const ret = new Argument({ source: tokeniser.source, tokens });
+    ret.extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__["ExtendedAttributes"].parse(tokeniser);
+    tokens.optional = tokeniser.consume("optional");
+    ret.idlType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_3__["type_with_extended_attributes"])(tokeniser, "argument-type");
+    if (!ret.idlType) {
+      return tokeniser.unconsume(start_position);
+    }
+    if (!tokens.optional) {
+      tokens.variadic = tokeniser.consume("...");
+    }
+    tokens.name = tokeniser.consume("identifier", ..._tokeniser_js__WEBPACK_IMPORTED_MODULE_4__["argumentNameKeywords"]);
+    if (!tokens.name) {
+      return tokeniser.unconsume(start_position);
+    }
+    ret.default = tokens.optional ? _default_js__WEBPACK_IMPORTED_MODULE_1__["Default"].parse(tokeniser) : null;
+    return ret;
   }
 
-  get value() {
-    return this.tokens.value.value;
+  get optional() {
+    return !!this.tokens.optional;
+  }
+  get variadic() {
+    return !!this.tokens.variadic;
+  }
+  get name() {
+    return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_3__["unescape"])(this.tokens.name.value);
   }
 }
 
@@ -1451,7 +1391,7 @@
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Default", function() { return Default; });
-/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
+/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
 /* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
 
 
@@ -1465,11 +1405,14 @@
     if (!assign) {
       return null;
     }
-    const def = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_value"])(tokeniser) || tokeniser.consume("string", "null", "[") || tokeniser.error("No value for default");
+    const def = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_value"])(tokeniser) || tokeniser.consume("string", "null", "[", "{") || tokeniser.error("No value for default");
     const expression = [def];
     if (def.type === "[") {
       const close = tokeniser.consume("]") || tokeniser.error("Default sequence value must be empty");
       expression.push(close);
+    } else if (def.type === "{") {
+      const close = tokeniser.consume("}") || tokeniser.error("Default dictionary value must be empty");
+      expression.push(close);
     }
     return new Default({ source: tokeniser.source, tokens: { assign }, expression });
   }
@@ -1497,10 +1440,172 @@
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtendedAttributes", function() { return ExtendedAttributes; });
+/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
+/* harmony import */ var _array_base_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
+/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
+
+
+
+
+class ExtendedAttributeParameters extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] {
+  /**
+   * @param {import("../tokeniser").Tokeniser} tokeniser
+   */
+  static parse(tokeniser) {
+    const tokens = { assign: tokeniser.consume("=") };
+    const ret = new ExtendedAttributeParameters({ source: tokeniser.source, tokens });
+    if (tokens.assign) {
+      tokens.secondaryName = tokeniser.consume("identifier", "decimal", "integer", "string");
+    }
+    tokens.open = tokeniser.consume("(");
+    if (tokens.open) {
+      ret.list = ret.rhsType === "identifier-list" ?
+        // [Exposed=(Window,Worker)]
+        Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["identifiers"])(tokeniser) :
+        // [NamedConstructor=Audio(DOMString src)] or [Constructor(DOMString str)]
+        Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["argument_list"])(tokeniser);
+      tokens.close = tokeniser.consume(")") || tokeniser.error("Unexpected token in extended attribute argument list");
+    } else if (ret.hasRhs && !tokens.secondaryName) {
+      tokeniser.error("No right hand side to extended attribute assignment");
+    }
+    return ret;
+  }
+
+  get rhsType() {
+    return !this.tokens.assign ? null :
+      !this.tokens.secondaryName ? "identifier-list" :
+        this.tokens.secondaryName.type;
+  }
+}
+
+class SimpleExtendedAttribute extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] {
+  /**
+   * @param {import("../tokeniser").Tokeniser} tokeniser
+   */
+  static parse(tokeniser) {
+    const name = tokeniser.consume("identifier");
+    if (name) {
+      return new SimpleExtendedAttribute({
+        tokens: { name },
+        params: ExtendedAttributeParameters.parse(tokeniser)
+      });
+    }
+  }
+
+  constructor({ source, tokens, params }) {
+    super({ source, tokens });
+    Object.defineProperty(this, "params", { value: params });
+  }
+
+  get type() {
+    return "extended-attribute";
+  }
+  get name() {
+    return this.tokens.name.value;
+  }
+  get rhs() {
+    const { rhsType: type, tokens, list } = this.params;
+    if (!type) {
+      return null;
+    }
+    const value = type === "identifier-list" ? list : tokens.secondaryName.value;
+    return { type, value };
+  }
+  get arguments() {
+    const { rhsType, list } = this.params;
+    if (!list || rhsType === "identifier-list") {
+      return [];
+    }
+    return list;
+  }
+}
+
+// Note: we parse something simpler than the official syntax. It's all that ever
+// seems to be used
+class ExtendedAttributes extends _array_base_js__WEBPACK_IMPORTED_MODULE_1__["ArrayBase"] {
+  /**
+   * @param {import("../tokeniser").Tokeniser} tokeniser
+   */
+  static parse(tokeniser) {
+    const tokens = {};
+    tokens.open = tokeniser.consume("[");
+    if (!tokens.open) return [];
+    const ret = new ExtendedAttributes({ source: tokeniser.source, tokens });
+    ret.push(...Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["list"])(tokeniser, {
+      parser: SimpleExtendedAttribute.parse,
+      listName: "extended attribute"
+    }));
+    tokens.close = tokeniser.consume("]") || tokeniser.error("Unexpected closing token of extended attribute");
+    if (!ret.length) {
+      tokeniser.error("Found an empty extended attribute");
+    }
+    if (tokeniser.probe("[")) {
+      tokeniser.error("Illegal double extended attribute lists, consider merging them");
+    }
+    return ret;
+  }
+}
+
+
+/***/ }),
+/* 10 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayBase", function() { return ArrayBase; });
+class ArrayBase extends Array {
+  constructor({ source, tokens }) {
+    super();
+    Object.defineProperties(this, {
+      source: { value: source },
+      tokens: { value: tokens }
+    });
+  }
+}
+
+
+/***/ }),
+/* 11 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Token", function() { return Token; });
+/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
+
+
+class Token extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] {
+  /**
+   * @param {import("../tokeniser").Tokeniser} tokeniser
+   * @param {string} type
+   */
+  static parser(tokeniser, type) {
+    return () => {
+      const value = tokeniser.consume(type);
+      if (value) {
+        return new Token({ source: tokeniser.source, tokens: { value } });
+      }
+    };
+  }
+
+  get value() {
+    return this.tokens.value.value;
+  }
+}
+
+
+/***/ }),
+/* 12 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Enum", function() { return Enum; });
 /* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var _token_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
-/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
+/* harmony import */ var _token_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
+/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
 
 
 
@@ -1563,13 +1668,13 @@
 
 
 /***/ }),
-/* 10 */
+/* 13 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Includes", function() { return Includes; });
-/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
+/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
 /* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
 
 
@@ -1607,7 +1712,7 @@
 
 
 /***/ }),
-/* 11 */
+/* 14 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -1921,13 +2026,13 @@
 
 
 /***/ }),
-/* 12 */
+/* 15 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "validate", function() { return validate; });
-/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
+/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
 
 
 
diff --git a/third_party/blink/web_tests/http/tests/push_messaging/application-server-key-format-test.html b/third_party/blink/web_tests/http/tests/push_messaging/application-server-key-format-test.html
index 8186db7b..809f0d7 100644
--- a/third_party/blink/web_tests/http/tests/push_messaging/application-server-key-format-test.html
+++ b/third_party/blink/web_tests/http/tests/push_messaging/application-server-key-format-test.html
@@ -31,7 +31,7 @@
         return registerAndSubscribePushWithString(test, '0123456789')
             .then(function(pushSubscription) {
               assert_true(
-                  pushSubscription.endpoint.includes('LayoutTestEndpoint'));
+                  pushSubscription.endpoint.includes('StandardizedEndpoint'));
             });
       }, 'Subscribing with a valid numeric sender ID should succeed');
 
diff --git a/third_party/blink/web_tests/inspector-protocol/layout-fonts/lang-fallback.js b/third_party/blink/web_tests/inspector-protocol/layout-fonts/lang-fallback.js
new file mode 100644
index 0000000..8469190
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/layout-fonts/lang-fallback.js
@@ -0,0 +1,79 @@
+(async function(testRunner) {
+  var page = await testRunner.createPage();
+  await page.loadHTML(`
+    <html>
+    <meta charset="UTF-8">
+    <body>
+        <div class="test">
+            <div lang="ar" id="ar">&#x062A;&#x062D;</div>
+            <div lang="hy-am" id="hy-am">&#x0540;&#x0541;</div>
+            <div lang="bn" id="bn">&#x09B8;&#x09AE;</div>
+            <div lang="en-us-brai" id="en-us-brai">&#x2870;&#x2871;</div>
+            <div lang="bug" id="bug">&#x1A00;&#x1A01;</div>
+            <div lang="cans" id="cans">&#x1410;&#x1411;</div>
+            <div lang="xcr" id="xcr">&#x000102A0;&#x000102A1;</div>
+            <div lang="chr" id="chr">&#x13A1;&#x13A2;</div>
+            <div lang="copt" id="copt">&#x2C81;&#x2C82;</div>
+            <div lang="akk" id="akk">&#x00012000;&#x0001200C;</div>
+            <div lang="ecy" id="ecy">&#x00010800;&#x00010801;</div>
+            <div lang="ru" id="ru">&#x0410;&#x0411;&#x0412;</div>
+            <div lang="en" id="en">&#x00010400;&#x00010401;</div>
+            <div lang="hi" id="hi">&#x0905;&#x0906;</div>
+            <div lang="am" id="am">&#x1201;&#x1202;</div>
+            <div lang="ka" id="ka">&#x10A0;&#x10A1;</div>
+            <div lang="el" id="el">&#x0391;&#x0392;</div>
+            <div lang="pa" id="pa">&#x0A21;&#x0A22;</div>
+            <div lang="zh-CN" id="zh-CN">&#x6211;</div>
+            <div lang="zh-HK" id="zh-HK">&#x6211;</div>
+            <div lang="zh-Hans" id="zh-Hans">&#x6211;</div>
+            <div lang="zh-Hant" id="zh-Hant">&#x6211;</div>
+            <div lang="ja" id="ja">&#x6211;</div>
+            <div lang="ko" id="ko">&#x1100;&#x1101;</div>
+            <div lang="he" id="he">&#x05D1;&#x05D2;</div>
+            <div lang="km" id="km">&#x1780;&#x1781;</div>
+            <div lang="arc" id="arc">&#x00010841;&#x00010842;</div>
+            <div lang="pal" id="pal">&#x00010B61;&#x00010B62;</div>
+            <div lang="xpr" id="xpr">&#x00010B41;&#x00010B42;</div>
+            <div lang="jv" id="jv">&#xA991;&#xA992;</div>
+            <div lang="kn" id="kn">&#x0CA1;&#x0CA2;</div>
+            <div lang="sa" id="sa">&#x00010A10;&#x00010A11;</div>
+            <div lang="lo" id="lo">&#x0ED0;&#x0ED1;</div>
+            <div lang="lis" id="lis">&#xA4D0;&#xA4D1;</div>
+            <div lang="xlc" id="xlc">&#x00010281;&#x00010282;</div>
+            <div lang="xld" id="xld">&#x00010921;&#x00010922;</div>
+            <div lang="ml" id="ml">&#x0D21;&#x0D22;</div>
+            <div lang="" id="script_meroitic">&#x000109A1;&#x000109A2;</div>
+            <div lang="my" id="my">&#x1000;&#x1001;</div>
+            <div lang="" id="script_new_tai_lue">&#x1981;&#x1982;</div>
+            <div lang="nko" id="nko">&#x07C1;&#x07C2;</div>
+            <div lang="" id="script_ogham">&#x1680;&#x1681;</div>
+            <div lang="" id="script_ol_chiki">&#x1C51;&#x1C52;</div>
+            <div lang="" id="script_old_italic">&#x00010301;&#x00010302;</div>
+            <div lang="peo" id="peo">&#x000103A1;&#x000103A2;</div>
+            <div lang="" id="script_old_south_arabian">&#x00010A61;&#x00010A62;</div>
+            <div lang="or" id="or">&#x0B21;&#x0B22;</div>
+            <div lang="" id="script_phags_pa">&#xA841;&#xA842;</div>
+            <div lang="" id="script_runic">&#x16A0;&#x16A1;</div>
+            <div lang="" id="script_shavian">&#x00010451;&#x00010452;</div>
+            <div lang="si" id="si">&#x0D91;&#x0D92;</div>
+            <div lang="" id="script_sora_sompeng">&#x000110D1;&#x000110D2;</div>
+            <div lang="syr" id="syr">&#x0711;&#x0712;</div>
+            <div lang="" id="script_tai_le">&#x1951;&#x1952;</div>
+            <div lang="ta" id="ta">&#x0BB1;&#x0BB2;</div>
+            <div lang="te" id="te">&#x0C21;&#x0C22;</div>
+            <div lang="" id="script_thaana">&#x0781;&#x0782;</div>
+            <div lang="th" id="th">&#x0e01;&#x0e02;</div>
+            <div lang="bo" id="bo">&#x0F01;&#x0F02;</div>
+            <div lang="" id="script_tifinagh">&#x2D31;&#x2D32;</div>
+            <div lang="vai" id="vai">&#xA501;&#xA502;</div>
+            <div lang="yi" id="yi">&#xA000;&#xA001;</div>
+        </div>
+    </body>
+    </html>
+  `);
+  var session = await page.createSession();
+
+  var helper = await testRunner.loadScript('./resources/layout-font-test.js');
+  await helper(testRunner, session);
+  testRunner.completeTest();
+})
diff --git a/third_party/blink/web_tests/platform/linux/inspector-protocol/layout-fonts/lang-fallback-expected.txt b/third_party/blink/web_tests/platform/linux/inspector-protocol/layout-fonts/lang-fallback-expected.txt
new file mode 100644
index 0000000..c720698c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/inspector-protocol/layout-fonts/lang-fallback-expected.txt
@@ -0,0 +1,249 @@
+تح
+#ar:
+"DejaVu Sans" : 2
+
+ՀՁ
+#hy-am:
+"DejaVu Sans" : 2
+
+সম
+#bn:
+"Mukti Narrow" : 2
+
+⡰⡱
+#en-us-brai:
+"DejaVu Sans" : 2
+
+ᨀᨁ
+#bug:
+"DejaVu Sans" : 2
+
+ᐐᐑ
+#cans:
+"DejaVu Sans" : 2
+
+𐊠𐊡
+#xcr:
+"DejaVu Sans" : 2
+
+ᎡᎢ
+#chr:
+"DejaVu Sans" : 2
+
+ⲁⲂ
+#copt:
+"DejaVu Sans" : 2
+
+𒀀𒀌
+#akk:
+"DejaVu Sans" : 2
+
+𐠀𐠁
+#ecy:
+"DejaVu Sans" : 2
+
+АБВ
+#ru:
+"Tinos" : 3
+
+𐐀𐐁
+#en:
+"DejaVu Sans" : 2
+
+अआ
+#hi:
+"Lohit Devanagari" : 2
+
+ሁሂ
+#am:
+"DejaVu Sans" : 2
+
+ႠႡ
+#ka:
+"DejaVu Sans" : 2
+
+ΑΒ
+#el:
+"Tinos" : 2
+
+ਡਢ
+#pa:
+"Lohit Gurmukhi" : 2
+
+我
+#zh-CN:
+"Noto Sans CJK JP Regular" : 1
+
+我
+#zh-HK:
+"Noto Sans CJK JP Regular" : 1
+
+我
+#zh-Hans:
+"Noto Sans CJK JP Regular" : 1
+
+我
+#zh-Hant:
+"Noto Sans CJK JP Regular" : 1
+
+我
+#ja:
+"Noto Sans CJK JP Regular" : 1
+
+ᄀᄁ
+#ko:
+"Noto Sans CJK JP Regular" : 2
+
+בג
+#he:
+"Tinos" : 2
+
+កខ
+#km:
+"Noto Sans Khmer" : 2
+
+𐡁𐡂
+#arc:
+"DejaVu Sans" : 2
+
+𐭡𐭢
+#pal:
+"DejaVu Sans" : 2
+
+𐭁𐭂
+#xpr:
+"DejaVu Sans" : 2
+
+ꦑꦒ
+#jv:
+"DejaVu Sans" : 2
+
+ಡಢ
+#kn:
+"DejaVu Sans" : 2
+
+𐨐𐨑
+#sa:
+"DejaVu Sans" : 2
+
+໐໑
+#lo:
+"DejaVu Sans" : 2
+
+ꓐꓑ
+#lis:
+"DejaVu Sans" : 2
+
+𐊁𐊂
+#xlc:
+"DejaVu Sans" : 2
+
+𐤡𐤢
+#xld:
+"DejaVu Sans" : 2
+
+ഡഢ
+#ml:
+"DejaVu Sans" : 2
+
+𐦡𐦢
+#script_meroitic:
+"DejaVu Sans" : 2
+
+ကခ
+#my:
+"DejaVu Sans" : 2
+
+ᦁᦂ
+#script_new_tai_lue:
+"DejaVu Sans" : 2
+
+߁߂
+#nko:
+"DejaVu Sans" : 2
+
+ᚁ
+#script_ogham:
+"DejaVu Sans" : 2
+
+᱑᱒
+#script_ol_chiki:
+"DejaVu Sans" : 2
+
+𐌁𐌂
+#script_old_italic:
+"DejaVu Sans" : 2
+
+𐎡𐎢
+#peo:
+"DejaVu Sans" : 2
+
+𐩡𐩢
+#script_old_south_arabian:
+"DejaVu Sans" : 2
+
+ଡଢ
+#or:
+"DejaVu Sans" : 2
+
+ꡁꡂ
+#script_phags_pa:
+"DejaVu Sans" : 2
+
+ᚠᚡ
+#script_runic:
+"DejaVu Sans" : 2
+
+𐑑𐑒
+#script_shavian:
+"DejaVu Sans" : 2
+
+එඒ
+#si:
+"DejaVu Sans" : 2
+
+𑃑𑃒
+#script_sora_sompeng:
+"DejaVu Sans" : 2
+
+ܑܒ
+#syr:
+"DejaVu Sans" : 2
+
+ᥑᥒ
+#script_tai_le:
+"DejaVu Sans" : 2
+
+றல
+#ta:
+"Lohit Tamil" : 2
+
+డఢ
+#te:
+"DejaVu Sans" : 2
+
+ށނ
+#script_thaana:
+"DejaVu Sans" : 2
+
+กข
+#th:
+"Garuda" : 2
+
+༁༂
+#bo:
+"DejaVu Sans" : 2
+
+ⴱⴲ
+#script_tifinagh:
+"DejaVu Sans" : 2
+
+ꔁꔂ
+#vai:
+"DejaVu Sans" : 2
+
+ꀀꀁ
+#yi:
+"DejaVu Sans" : 2
+
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/inspector-protocol/layout-fonts/lang-fallback-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/inspector-protocol/layout-fonts/lang-fallback-expected.txt
new file mode 100644
index 0000000..50eb6758
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/inspector-protocol/layout-fonts/lang-fallback-expected.txt
@@ -0,0 +1,249 @@
+تح
+#ar:
+"Geeza Pro" : 2
+
+ՀՁ
+#hy-am:
+"Mshtakan" : 2
+
+সম
+#bn:
+"Bangla MN" : 2
+
+⡰⡱
+#en-us-brai:
+"Apple Braille" : 2
+
+ᨀᨁ
+#bug:
+"Times" : 2
+
+ᐐᐑ
+#cans:
+"Euphemia UCAS" : 2
+
+𐊠𐊡
+#xcr:
+"Geneva" : 2
+
+ᎡᎢ
+#chr:
+"Plantagenet Cherokee" : 2
+
+ⲁⲂ
+#copt:
+"Times" : 2
+
+𒀀𒀌
+#akk:
+"Times" : 2
+
+𐠀𐠁
+#ecy:
+"Times" : 2
+
+АБВ
+#ru:
+"Times" : 3
+
+𐐀𐐁
+#en:
+"Baskerville" : 2
+
+अआ
+#hi:
+"ITF Devanagari" : 2
+
+ሁሂ
+#am:
+"Kefa" : 2
+
+ႠႡ
+#ka:
+"Arial Unicode MS" : 2
+
+ΑΒ
+#el:
+"Times" : 2
+
+ਡਢ
+#pa:
+"Gurmukhi MN" : 2
+
+我
+#zh-CN:
+"Songti SC" : 1
+
+我
+#zh-HK:
+"Songti SC" : 1
+
+我
+#zh-Hans:
+"Songti SC" : 1
+
+我
+#zh-Hant:
+"Songti SC" : 1
+
+我
+#ja:
+"Songti SC" : 1
+
+ᄀᄁ
+#ko:
+"AppleMyungjo" : 2
+
+בג
+#he:
+"Lucida Grande" : 2
+
+កខ
+#km:
+"Khmer MN" : 2
+
+𐡁𐡂
+#arc:
+"Times" : 2
+
+𐭡𐭢
+#pal:
+"Times" : 2
+
+𐭁𐭂
+#xpr:
+"Times" : 2
+
+ꦑꦒ
+#jv:
+"Times" : 2
+
+ಡಢ
+#kn:
+"Kannada MN" : 2
+
+𐨐𐨑
+#sa:
+"Times" : 2
+
+໐໑
+#lo:
+"Lao MN" : 2
+
+ꓐꓑ
+#lis:
+"Geneva" : 2
+
+𐊁𐊂
+#xlc:
+"Geneva" : 2
+
+𐤡𐤢
+#xld:
+"Times" : 2
+
+ഡഢ
+#ml:
+"Malayalam MN" : 2
+
+𐦡𐦢
+#script_meroitic:
+"Times" : 2
+
+ကခ
+#my:
+"Myanmar MN" : 2
+
+ᦁᦂ
+#script_new_tai_lue:
+"Times" : 2
+
+߁߂
+#nko:
+"Times" : 2
+
+ᚁ
+#script_ogham:
+"Geneva" : 2
+
+᱑᱒
+#script_ol_chiki:
+"Times" : 2
+
+𐌁𐌂
+#script_old_italic:
+"Geneva" : 2
+
+𐎡𐎢
+#peo:
+"Times" : 2
+
+𐩡𐩢
+#script_old_south_arabian:
+"Times" : 2
+
+ଡଢ
+#or:
+"Oriya MN" : 2
+
+ꡁꡂ
+#script_phags_pa:
+"Times" : 2
+
+ᚠᚡ
+#script_runic:
+"Geneva" : 2
+
+𐑑𐑒
+#script_shavian:
+"Geneva" : 2
+
+එඒ
+#si:
+"Sinhala MN" : 2
+
+𑃑𑃒
+#script_sora_sompeng:
+"Times" : 2
+
+ܑܒ
+#syr:
+"Times" : 2
+
+ᥑᥒ
+#script_tai_le:
+"Times" : 2
+
+றல
+#ta:
+"Tamil Sangam MN" : 2
+
+డఢ
+#te:
+"Telugu MN" : 2
+
+ށނ
+#script_thaana:
+"Times" : 2
+
+กข
+#th:
+"Thonburi" : 2
+
+༁༂
+#bo:
+"Kokonor" : 2
+
+ⴱⴲ
+#script_tifinagh:
+"Times" : 2
+
+ꔁꔂ
+#vai:
+"Times" : 2
+
+ꀀꀁ
+#yi:
+"Songti SC" : 2
+
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/inspector-protocol/layout-fonts/lang-fallback-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/inspector-protocol/layout-fonts/lang-fallback-expected.txt
new file mode 100644
index 0000000..4740907
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/inspector-protocol/layout-fonts/lang-fallback-expected.txt
@@ -0,0 +1,249 @@
+تح
+#ar:
+"Geeza Pro" : 2
+
+ՀՁ
+#hy-am:
+"Mshtakan" : 2
+
+সম
+#bn:
+"Kohinoor Bangla" : 2
+
+⡰⡱
+#en-us-brai:
+"Apple Braille" : 2
+
+ᨀᨁ
+#bug:
+"Times" : 2
+
+ᐐᐑ
+#cans:
+"Euphemia UCAS" : 2
+
+𐊠𐊡
+#xcr:
+"Geneva" : 2
+
+ᎡᎢ
+#chr:
+"Plantagenet Cherokee" : 2
+
+ⲁⲂ
+#copt:
+"Noto Sans Coptic" : 2
+
+𒀀𒀌
+#akk:
+"Times" : 2
+
+𐠀𐠁
+#ecy:
+"Times" : 2
+
+АБВ
+#ru:
+"Times" : 3
+
+𐐀𐐁
+#en:
+"Baskerville" : 2
+
+अआ
+#hi:
+"ITF Devanagari" : 2
+
+ሁሂ
+#am:
+"Kefa" : 2
+
+ႠႡ
+#ka:
+"Arial Unicode MS" : 2
+
+ΑΒ
+#el:
+"Times" : 2
+
+ਡਢ
+#pa:
+"Gurmukhi MN" : 2
+
+我
+#zh-CN:
+"Songti SC" : 1
+
+我
+#zh-HK:
+"Songti SC" : 1
+
+我
+#zh-Hans:
+"Songti SC" : 1
+
+我
+#zh-Hant:
+"Songti SC" : 1
+
+我
+#ja:
+"Songti SC" : 1
+
+ᄀᄁ
+#ko:
+"AppleMyungjo" : 2
+
+בג
+#he:
+"Lucida Grande" : 2
+
+កខ
+#km:
+"Khmer MN" : 2
+
+𐡁𐡂
+#arc:
+"Times" : 2
+
+𐭡𐭢
+#pal:
+"Times" : 2
+
+𐭁𐭂
+#xpr:
+"Times" : 2
+
+ꦑꦒ
+#jv:
+"Times" : 2
+
+ಡಢ
+#kn:
+"Kannada MN" : 2
+
+𐨐𐨑
+#sa:
+"Times" : 2
+
+໐໑
+#lo:
+"Lao MN" : 2
+
+ꓐꓑ
+#lis:
+"Noto Sans Lisu" : 2
+
+𐊁𐊂
+#xlc:
+"Geneva" : 2
+
+𐤡𐤢
+#xld:
+"Times" : 2
+
+ഡഢ
+#ml:
+"Malayalam MN" : 2
+
+𐦡𐦢
+#script_meroitic:
+"Times" : 2
+
+ကခ
+#my:
+"Myanmar MN" : 2
+
+ᦁᦂ
+#script_new_tai_lue:
+"Noto Sans New Tai Lue" : 2
+
+߁߂
+#nko:
+"Noto Sans NKo" : 2
+
+ᚁ
+#script_ogham:
+"Noto Sans Ogham" : 2
+
+᱑᱒
+#script_ol_chiki:
+"Noto Sans Ol Chiki" : 2
+
+𐌁𐌂
+#script_old_italic:
+"Geneva" : 2
+
+𐎡𐎢
+#peo:
+"Times" : 2
+
+𐩡𐩢
+#script_old_south_arabian:
+"Times" : 2
+
+ଡଢ
+#or:
+"Oriya MN" : 2
+
+ꡁꡂ
+#script_phags_pa:
+"Noto Sans Phags Pa" : 2
+
+ᚠᚡ
+#script_runic:
+"Noto Sans Runic" : 2
+
+𐑑𐑒
+#script_shavian:
+"Geneva" : 2
+
+එඒ
+#si:
+"Sinhala MN" : 2
+
+𑃑𑃒
+#script_sora_sompeng:
+"Times" : 2
+
+ܑܒ
+#syr:
+"Noto Sans Syriac Eastern" : 2
+
+ᥑᥒ
+#script_tai_le:
+"Noto Sans Tai Le" : 2
+
+றல
+#ta:
+"Tamil Sangam MN" : 2
+
+డఢ
+#te:
+"Kohinoor Telugu" : 2
+
+ށނ
+#script_thaana:
+"Times" : 2
+
+กข
+#th:
+"Thonburi" : 2
+
+༁༂
+#bo:
+"Kokonor" : 2
+
+ⴱⴲ
+#script_tifinagh:
+"Noto Sans Tifinagh" : 2
+
+ꔁꔂ
+#vai:
+"Noto Sans Vai" : 2
+
+ꀀꀁ
+#yi:
+"Songti SC" : 2
+
+
diff --git a/third_party/blink/web_tests/platform/mac/inspector-protocol/layout-fonts/lang-fallback-expected.txt b/third_party/blink/web_tests/platform/mac/inspector-protocol/layout-fonts/lang-fallback-expected.txt
new file mode 100644
index 0000000..fb90d4a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/inspector-protocol/layout-fonts/lang-fallback-expected.txt
@@ -0,0 +1,249 @@
+تح
+#ar:
+"Geeza Pro" : 2
+
+ՀՁ
+#hy-am:
+"Mshtakan" : 2
+
+সম
+#bn:
+"Kohinoor Bangla" : 2
+
+⡰⡱
+#en-us-brai:
+"Apple Braille" : 2
+
+ᨀᨁ
+#bug:
+"Times" : 2
+
+ᐐᐑ
+#cans:
+"Euphemia UCAS" : 2
+
+𐊠𐊡
+#xcr:
+"Geneva" : 2
+
+ᎡᎢ
+#chr:
+"Plantagenet Cherokee" : 2
+
+ⲁⲂ
+#copt:
+"Times" : 2
+
+𒀀𒀌
+#akk:
+"Times" : 2
+
+𐠀𐠁
+#ecy:
+"Times" : 2
+
+АБВ
+#ru:
+"Times" : 3
+
+𐐀𐐁
+#en:
+"Baskerville" : 2
+
+अआ
+#hi:
+"ITF Devanagari" : 2
+
+ሁሂ
+#am:
+"Kefa" : 2
+
+ႠႡ
+#ka:
+"Arial Unicode MS" : 2
+
+ΑΒ
+#el:
+"Times" : 2
+
+ਡਢ
+#pa:
+"Gurmukhi MN" : 2
+
+我
+#zh-CN:
+"Songti SC" : 1
+
+我
+#zh-HK:
+"Songti SC" : 1
+
+我
+#zh-Hans:
+"Songti SC" : 1
+
+我
+#zh-Hant:
+"Songti SC" : 1
+
+我
+#ja:
+"Songti SC" : 1
+
+ᄀᄁ
+#ko:
+"AppleMyungjo" : 2
+
+בג
+#he:
+"Lucida Grande" : 2
+
+កខ
+#km:
+"Khmer MN" : 2
+
+𐡁𐡂
+#arc:
+"Times" : 2
+
+𐭡𐭢
+#pal:
+"Times" : 2
+
+𐭁𐭂
+#xpr:
+"Times" : 2
+
+ꦑꦒ
+#jv:
+"Times" : 2
+
+ಡಢ
+#kn:
+"Kannada MN" : 2
+
+𐨐𐨑
+#sa:
+"Times" : 2
+
+໐໑
+#lo:
+"Lao MN" : 2
+
+ꓐꓑ
+#lis:
+"Geneva" : 2
+
+𐊁𐊂
+#xlc:
+"Geneva" : 2
+
+𐤡𐤢
+#xld:
+"Times" : 2
+
+ഡഢ
+#ml:
+"Malayalam MN" : 2
+
+𐦡𐦢
+#script_meroitic:
+"Times" : 2
+
+ကခ
+#my:
+"Myanmar MN" : 2
+
+ᦁᦂ
+#script_new_tai_lue:
+"Times" : 2
+
+߁߂
+#nko:
+"Times" : 2
+
+ᚁ
+#script_ogham:
+"Geneva" : 2
+
+᱑᱒
+#script_ol_chiki:
+"Times" : 2
+
+𐌁𐌂
+#script_old_italic:
+"Geneva" : 2
+
+𐎡𐎢
+#peo:
+"Times" : 2
+
+𐩡𐩢
+#script_old_south_arabian:
+"Times" : 2
+
+ଡଢ
+#or:
+"Oriya MN" : 2
+
+ꡁꡂ
+#script_phags_pa:
+"Times" : 2
+
+ᚠᚡ
+#script_runic:
+"Geneva" : 2
+
+𐑑𐑒
+#script_shavian:
+"Geneva" : 2
+
+එඒ
+#si:
+"Sinhala MN" : 2
+
+𑃑𑃒
+#script_sora_sompeng:
+"Times" : 2
+
+ܑܒ
+#syr:
+"Times" : 2
+
+ᥑᥒ
+#script_tai_le:
+"Times" : 2
+
+றல
+#ta:
+"Tamil Sangam MN" : 2
+
+డఢ
+#te:
+"Kohinoor Telugu" : 2
+
+ށނ
+#script_thaana:
+"Times" : 2
+
+กข
+#th:
+"Thonburi" : 2
+
+༁༂
+#bo:
+"Kokonor" : 2
+
+ⴱⴲ
+#script_tifinagh:
+"Times" : 2
+
+ꔁꔂ
+#vai:
+"Times" : 2
+
+ꀀꀁ
+#yi:
+"Songti SC" : 2
+
+
diff --git a/third_party/blink/web_tests/platform/win/inspector-protocol/layout-fonts/lang-fallback-expected.txt b/third_party/blink/web_tests/platform/win/inspector-protocol/layout-fonts/lang-fallback-expected.txt
new file mode 100644
index 0000000..267de59
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/inspector-protocol/layout-fonts/lang-fallback-expected.txt
@@ -0,0 +1,249 @@
+تح
+#ar:
+"Times New Roman" : 2
+
+ՀՁ
+#hy-am:
+"Times New Roman" : 2
+
+সম
+#bn:
+"Nirmala UI" : 2
+
+⡰⡱
+#en-us-brai:
+"Segoe UI Symbol" : 2
+
+ᨀᨁ
+#bug:
+"Leelawadee UI" : 2
+
+ᐐᐑ
+#cans:
+"Gadugi" : 2
+
+𐊠𐊡
+#xcr:
+"Segoe UI Historic" : 2
+
+ᎡᎢ
+#chr:
+"Gadugi" : 2
+
+ⲁⲂ
+#copt:
+"Segoe UI Symbol" : 2
+
+𒀀𒀌
+#akk:
+"Segoe UI Historic" : 2
+
+𐠀𐠁
+#ecy:
+"Segoe UI Historic" : 2
+
+АБВ
+#ru:
+"Times New Roman" : 3
+
+𐐀𐐁
+#en:
+"Segoe UI Symbol" : 2
+
+अआ
+#hi:
+"Nirmala UI" : 2
+
+ሁሂ
+#am:
+"Ebrima" : 2
+
+ႠႡ
+#ka:
+"Sylfaen" : 2
+
+ΑΒ
+#el:
+"Times New Roman" : 2
+
+ਡਢ
+#pa:
+"Nirmala UI" : 2
+
+我
+#zh-CN:
+"SimSun" : 1
+
+我
+#zh-HK:
+"微軟正黑體" : 1
+
+我
+#zh-Hans:
+"SimSun" : 1
+
+我
+#zh-Hant:
+"微軟正黑體" : 1
+
+我
+#ja:
+"Yu Gothic" : 1
+
+ᄀᄁ
+#ko:
+"Malgun Gothic" : 2
+
+בג
+#he:
+"Times New Roman" : 2
+
+កខ
+#km:
+"Leelawadee UI" : 2
+
+𐡁𐡂
+#arc:
+"Segoe UI Historic" : 2
+
+𐭡𐭢
+#pal:
+"Segoe UI Historic" : 2
+
+𐭁𐭂
+#xpr:
+"Segoe UI Historic" : 2
+
+ꦑꦒ
+#jv:
+"Javanese Text" : 2
+
+ಡಢ
+#kn:
+"Nirmala UI" : 2
+
+𐨐𐨑
+#sa:
+"Segoe UI Historic" : 2
+
+໐໑
+#lo:
+"Leelawadee UI" : 2
+
+ꓐꓑ
+#lis:
+"Segoe UI" : 2
+
+𐊁𐊂
+#xlc:
+"Segoe UI Historic" : 2
+
+𐤡𐤢
+#xld:
+"Segoe UI Historic" : 2
+
+ഡഢ
+#ml:
+"Nirmala UI" : 2
+
+𐦡𐦢
+#script_meroitic:
+"Segoe UI Historic" : 2
+
+ကခ
+#my:
+"Myanmar Text" : 2
+
+ᦁᦂ
+#script_new_tai_lue:
+"Microsoft New Tai Lue" : 2
+
+߁߂
+#nko:
+"Ebrima" : 2
+
+ᚁ
+#script_ogham:
+"Segoe UI Historic" : 2
+
+᱑᱒
+#script_ol_chiki:
+"Nirmala UI" : 2
+
+𐌁𐌂
+#script_old_italic:
+"Segoe UI Historic" : 2
+
+𐎡𐎢
+#peo:
+"Segoe UI Historic" : 2
+
+𐩡𐩢
+#script_old_south_arabian:
+"Segoe UI Historic" : 2
+
+ଡଢ
+#or:
+"Nirmala UI" : 2
+
+ꡁꡂ
+#script_phags_pa:
+"Microsoft PhagsPa" : 2
+
+ᚠᚡ
+#script_runic:
+"Segoe UI Historic" : 2
+
+𐑑𐑒
+#script_shavian:
+"Segoe UI Historic" : 2
+
+එඒ
+#si:
+"Nirmala UI" : 2
+
+𑃑𑃒
+#script_sora_sompeng:
+"Nirmala UI" : 2
+
+ܑܒ
+#syr:
+"Segoe UI Historic" : 2
+
+ᥑᥒ
+#script_tai_le:
+"Microsoft Tai Le" : 2
+
+றல
+#ta:
+"Nirmala UI" : 2
+
+డఢ
+#te:
+"Nirmala UI" : 2
+
+ށނ
+#script_thaana:
+"MV Boli" : 2
+
+กข
+#th:
+"Tahoma" : 2
+
+༁༂
+#bo:
+"Microsoft Himalaya" : 2
+
+ⴱⴲ
+#script_tifinagh:
+"Ebrima" : 2
+
+ꔁꔂ
+#vai:
+"Ebrima" : 2
+
+ꀀꀁ
+#yi:
+"Microsoft Yi Baiti" : 2
+
+
diff --git a/third_party/blink/web_tests/platform/win7/inspector-protocol/layout-fonts/lang-fallback-expected.txt b/third_party/blink/web_tests/platform/win7/inspector-protocol/layout-fonts/lang-fallback-expected.txt
new file mode 100644
index 0000000..498be4d5
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/inspector-protocol/layout-fonts/lang-fallback-expected.txt
@@ -0,0 +1,249 @@
+تح
+#ar:
+"Times New Roman" : 2
+
+ՀՁ
+#hy-am:
+"Tahoma" : 2
+
+সম
+#bn:
+"Vrinda" : 2
+
+⡰⡱
+#en-us-brai:
+"Segoe UI Symbol" : 2
+
+ᨀᨁ
+#bug:
+"Arial" : 2
+
+ᐐᐑ
+#cans:
+"Euphemia" : 2
+
+𐊠𐊡
+#xcr:
+"Arial" : 2
+
+ᎡᎢ
+#chr:
+"Arial" : 2
+
+ⲁⲂ
+#copt:
+"Arial" : 2
+
+𒀀𒀌
+#akk:
+"Arial" : 2
+
+𐠀𐠁
+#ecy:
+"Arial" : 2
+
+АБВ
+#ru:
+"Times New Roman" : 3
+
+𐐀𐐁
+#en:
+"Arial" : 2
+
+अआ
+#hi:
+"Mangal" : 2
+
+ሁሂ
+#am:
+"Nyala" : 2
+
+ႠႡ
+#ka:
+"Arial" : 2
+
+ΑΒ
+#el:
+"Times New Roman" : 2
+
+ਡਢ
+#pa:
+"Raavi" : 2
+
+我
+#zh-CN:
+"SimSun" : 1
+
+我
+#zh-HK:
+"PMingLiU" : 1
+
+我
+#zh-Hans:
+"SimSun" : 1
+
+我
+#zh-Hant:
+"PMingLiU" : 1
+
+我
+#ja:
+"Meiryo" : 1
+
+ᄀᄁ
+#ko:
+"Malgun Gothic" : 2
+
+בג
+#he:
+"Times New Roman" : 2
+
+កខ
+#km:
+"Khmer UI" : 2
+
+𐡁𐡂
+#arc:
+"Arial" : 2
+
+𐭡𐭢
+#pal:
+"Arial" : 2
+
+𐭁𐭂
+#xpr:
+"Arial" : 2
+
+ꦑꦒ
+#jv:
+"Arial" : 2
+
+ಡಢ
+#kn:
+"Tunga" : 2
+
+𐨐𐨑
+#sa:
+"Arial" : 2
+
+໐໑
+#lo:
+"Lao UI" : 2
+
+ꓐꓑ
+#lis:
+"Arial" : 2
+
+𐊁𐊂
+#xlc:
+"Arial" : 2
+
+𐤡𐤢
+#xld:
+"Arial" : 2
+
+ഡഢ
+#ml:
+"Kartika" : 2
+
+𐦡𐦢
+#script_meroitic:
+"Arial" : 2
+
+ကခ
+#my:
+"Arial" : 2
+
+ᦁᦂ
+#script_new_tai_lue:
+"Microsoft New Tai Lue" : 2
+
+߁߂
+#nko:
+"Ebrima" : 2
+
+ᚁ
+#script_ogham:
+"Segoe UI Symbol" : 2
+
+᱑᱒
+#script_ol_chiki:
+"Arial" : 2
+
+𐌁𐌂
+#script_old_italic:
+"Arial" : 2
+
+𐎡𐎢
+#peo:
+"Arial" : 2
+
+𐩡𐩢
+#script_old_south_arabian:
+"Arial" : 2
+
+ଡଢ
+#or:
+"Kalinga" : 2
+
+ꡁꡂ
+#script_phags_pa:
+"Microsoft PhagsPa" : 2
+
+ᚠᚡ
+#script_runic:
+"Segoe UI Symbol" : 2
+
+𐑑𐑒
+#script_shavian:
+"Arial" : 2
+
+එඒ
+#si:
+"Iskoola Pota" : 2
+
+𑃑𑃒
+#script_sora_sompeng:
+"Arial" : 2
+
+ܑܒ
+#syr:
+"Estrangelo Edessa" : 2
+
+ᥑᥒ
+#script_tai_le:
+"Microsoft Tai Le" : 2
+
+றல
+#ta:
+"Latha" : 2
+
+డఢ
+#te:
+"Gautami" : 2
+
+ށނ
+#script_thaana:
+"MV Boli" : 2
+
+กข
+#th:
+"Tahoma" : 2
+
+༁༂
+#bo:
+"Microsoft Himalaya" : 2
+
+ⴱⴲ
+#script_tifinagh:
+"Ebrima" : 2
+
+ꔁꔂ
+#vai:
+"Ebrima" : 2
+
+ꀀꀁ
+#yi:
+"Microsoft Yi Baiti" : 2
+
+
diff --git a/third_party/blink/web_tests/xr/ar_hittest.html b/third_party/blink/web_tests/xr/ar_hittest.html
index 7c58915..884f27e 100644
--- a/third_party/blink/web_tests/xr/ar_hittest.html
+++ b/third_party/blink/web_tests/xr/ar_hittest.html
@@ -24,7 +24,7 @@
                          0, 0, 1, 3,
                          0, 0, 0, 1];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   assert_equals(session.mode, 'immersive-ar');
   assert_not_equals(session.environmentBlendMode, 'opaque');
   return session.requestReferenceSpace('local').then((referenceSpace) => {
@@ -53,6 +53,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/exclusive_requestFrame_nolayer.html b/third_party/blink/web_tests/xr/exclusive_requestFrame_nolayer.html
index 4e505b7d..680a045 100644
--- a/third_party/blink/web_tests/xr/exclusive_requestFrame_nolayer.html
+++ b/third_party/blink/web_tests/xr/exclusive_requestFrame_nolayer.html
@@ -46,6 +46,6 @@
 });
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/render_state_vertical_fov_immersive.html b/third_party/blink/web_tests/xr/render_state_vertical_fov_immersive.html
index 11c54a1..99da03e8 100644
--- a/third_party/blink/web_tests/xr/render_state_vertical_fov_immersive.html
+++ b/third_party/blink/web_tests/xr/render_state_vertical_fov_immersive.html
@@ -16,7 +16,7 @@
 
 let requestSessionModes =  ['immersive-vr'];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
 
   // Session must have a baseLayer or frame requests will be ignored.
   session.updateRenderState({
@@ -50,6 +50,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/render_state_vertical_fov_inline.html b/third_party/blink/web_tests/xr/render_state_vertical_fov_inline.html
index 8882517..4dabcf4b 100644
--- a/third_party/blink/web_tests/xr/render_state_vertical_fov_inline.html
+++ b/third_party/blink/web_tests/xr/render_state_vertical_fov_inline.html
@@ -25,7 +25,7 @@
   assert_less_than(Math.abs(a - b), epsilon, step);
 }
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   // Session must have a baseLayer or frame requests will be ignored.
   session.updateRenderState({
     baseLayer: new XRWebGLLayer(session, gl, { compositionDisabled: true })
@@ -89,6 +89,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/resources/xr-test-utils.js b/third_party/blink/web_tests/xr/resources/xr-test-utils.js
index 195c7fc3..368fd0f 100644
--- a/third_party/blink/web_tests/xr/resources/xr-test-utils.js
+++ b/third_party/blink/web_tests/xr/resources/xr-test-utils.js
@@ -2,7 +2,7 @@
 // performs tests. If func returns a promise, test will only pass if the promise
 // resolves.
 function xr_session_promise_test(
-    func, deviceOptions, sessionModes, name, properties) {
+    name, func, deviceOptions, sessionModes, properties) {
   if (document.getElementById('webgl-canvas') ||
       document.getElementById('webgl2-canvas')) {
     webglCanvasSetup();
@@ -42,7 +42,7 @@
                   .then((session) => {
                     testSession = session;
                     testSession.mode = nextMode;
-                    return func(session, t, fakeDeviceController);
+                    return func(session, fakeDeviceController, t);
                   })
                   .then(() => {
                     // End the session. Silence any errors generated if the
diff --git a/third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html b/third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html
index 0d83ce2b..54a1e5e6 100644
--- a/third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html
+++ b/third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html
@@ -24,7 +24,7 @@
   'immersive-vr',
 ];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   // Session must have a baseLayer or else frame requests will be ignored.
   session.updateRenderState({
     baseLayer: new XRWebGLLayer(session, gl)
@@ -94,6 +94,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrFrame_getPose.html b/third_party/blink/web_tests/xr/xrFrame_getPose.html
index a43739b7..73f060e 100644
--- a/third_party/blink/web_tests/xr/xrFrame_getPose.html
+++ b/third_party/blink/web_tests/xr/xrFrame_getPose.html
@@ -19,7 +19,7 @@
 
 let requestSessionModes = ['immersive-vr'];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   // Session must have a baseLayer or frame requests will be ignored.
   let webglLayer = new XRWebGLLayer(session, gl);
   session.updateRenderState({ baseLayer: webglLayer });
@@ -47,6 +47,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_immersive.html b/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_immersive.html
index 634f439..5b87177 100644
--- a/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_immersive.html
+++ b/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_immersive.html
@@ -16,7 +16,7 @@
 let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
 let requestSessionModes = ['immersive-vr'];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   return new Promise((resolve) => {
     // Session must have a baseLayer or frame requests will be ignored.
     session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
@@ -34,6 +34,6 @@
 }
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_inline.html b/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_inline.html
index c819e84..8f34d0e 100644
--- a/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_inline.html
+++ b/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_inline.html
@@ -16,7 +16,7 @@
 let fakeDeviceInitParams = VALID_NON_IMMERSIVE_DEVICE;
 let requestSessionModes = ['inline'];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   return new Promise((resolve) => {
     // Session must have a baseLayer or frame requests will be ignored.
     session.updateRenderState({
@@ -36,6 +36,6 @@
 }
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrSession_environmentBlendMode.html b/third_party/blink/web_tests/xr/xrSession_environmentBlendMode.html
index e367fb02..cc2ea79 100644
--- a/third_party/blink/web_tests/xr/xrSession_environmentBlendMode.html
+++ b/third_party/blink/web_tests/xr/xrSession_environmentBlendMode.html
@@ -19,23 +19,23 @@
   'immersive-vr',
 ];
 
-let testFunction = function(session, t) {
+let testFunction = function(session, fakeDeviceController, t) {
   t.step(() => {
     assert_equals(session.environmentBlendMode, 'opaque');
   });
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 // TODO(https://crbug.com/828321): Enable once session options for AR are in place.
-/*xr_session_promise_test( (session, t) => {
+/*xr_session_promise_test("environmentBlendMode is correct for an AR device",
+ (session, fakeDeviceController, t) => {
   t.step(() => {
     assert_equals(session.environmentBlendMode, 'alpha-blend');
   });
 }, fakeDevices["FakeARPhone"], [
     { ar: true, outputContext: getOutputContext() }
-],
-"environmentBlendMode is correct for an AR device");*/
+]);*/
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrSession_environmentProviderDisconnect.html b/third_party/blink/web_tests/xr/xrSession_environmentProviderDisconnect.html
index 09e8b4a..f41f21c 100644
--- a/third_party/blink/web_tests/xr/xrSession_environmentProviderDisconnect.html
+++ b/third_party/blink/web_tests/xr/xrSession_environmentProviderDisconnect.html
@@ -39,7 +39,7 @@
   return new Promise((resolve,reject) => { });
 }
 
-let testFunction = function(session, t, controller) {
+let testFunction = function(session, fakeDeviceController, t) {
   return session.requestReferenceSpace('local')
     .then((referenceSpace) => {
       refSpace = referenceSpace;
@@ -51,7 +51,7 @@
     .then(() => {
       immediatelyResolveHitTest = false;
       let hitTestPromise = session.requestHitTest(ray, refSpace);
-      controller.closeEnvironmentIntegrationProvider();
+      fakeDeviceController.closeEnvironmentIntegrationProvider();
       return hitTestPromise;
     })
     .then(() => {
@@ -63,6 +63,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrSession_requestAnimationFrame_timestamp.html b/third_party/blink/web_tests/xr/xrSession_requestAnimationFrame_timestamp.html
index 3729ee3..c2ea022 100644
--- a/third_party/blink/web_tests/xr/xrSession_requestAnimationFrame_timestamp.html
+++ b/third_party/blink/web_tests/xr/xrSession_requestAnimationFrame_timestamp.html
@@ -21,7 +21,7 @@
   'immersive-vr',
 ];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   // Session must have a baseLayer or else frame requests will be ignored.
   session.updateRenderState({
     baseLayer: new XRWebGLLayer(session, gl, {
@@ -98,6 +98,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrView_match.html b/third_party/blink/web_tests/xr/xrView_match.html
index a736ad85..9c1bed1 100644
--- a/third_party/blink/web_tests/xr/xrView_match.html
+++ b/third_party/blink/web_tests/xr/xrView_match.html
@@ -33,7 +33,7 @@
 
 let requestSessionModes = ['immersive-vr'];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   // Session must have a baseLayer or frame requests will be ignored.
   let webglLayer = new XRWebGLLayer(session, gl);
   session.updateRenderState({ baseLayer: webglLayer });
@@ -89,6 +89,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrView_oneframeupdate.html b/third_party/blink/web_tests/xr/xrView_oneframeupdate.html
index 491422f..94e75b95 100644
--- a/third_party/blink/web_tests/xr/xrView_oneframeupdate.html
+++ b/third_party/blink/web_tests/xr/xrView_oneframeupdate.html
@@ -34,7 +34,7 @@
 
 let requestSessionModes = ['immersive-vr'];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   // Session must have a baseLayer or frame requests will be ignored.
   session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
 
@@ -81,6 +81,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrViewport_valid.html b/third_party/blink/web_tests/xr/xrViewport_valid.html
index 3d3e7ba..2b491a8 100644
--- a/third_party/blink/web_tests/xr/xrViewport_valid.html
+++ b/third_party/blink/web_tests/xr/xrViewport_valid.html
@@ -15,7 +15,7 @@
 
 let requestSessionModes = ['immersive-vr'];
 
-let testFunction = function(session, t, fakeDeviceController) {
+let testFunction = function(session, fakeDeviceController, t) {
   // Session must have a baseLayer or frame requests will be ignored.
   let webglLayer = new XRWebGLLayer(session, gl);
   session.updateRenderState({ baseLayer: webglLayer });
@@ -79,6 +79,6 @@
 };
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrWebGLLayer_constructor.html b/third_party/blink/web_tests/xr/xrWebGLLayer_constructor.html
index 2a61f47..226a26e 100644
--- a/third_party/blink/web_tests/xr/xrWebGLLayer_constructor.html
+++ b/third_party/blink/web_tests/xr/xrWebGLLayer_constructor.html
@@ -17,7 +17,7 @@
 let requestSessionModes =  ['immersive-vr'];
 
 let testFunction =
-  (session, t, fakeDeviceController) => new Promise((resolve, reject) => {
+  (session, fakeDeviceController, t) => new Promise((resolve, reject) => {
   try {
     let webglLayerGood = new XRWebGLLayer(session, gl);
   } catch (err) {
@@ -54,6 +54,6 @@
 });
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrWebGLLayer_dirty_framebuffer.html b/third_party/blink/web_tests/xr/xrWebGLLayer_dirty_framebuffer.html
index 53e447e3..04f9c834 100644
--- a/third_party/blink/web_tests/xr/xrWebGLLayer_dirty_framebuffer.html
+++ b/third_party/blink/web_tests/xr/xrWebGLLayer_dirty_framebuffer.html
@@ -19,7 +19,7 @@
 let requestSessionModes =  ['immersive-vr'];
 
 let testFunction =
-  (session, t, fakeDeviceController) => new Promise((resolve, reject) => {
+  (session, fakeDeviceController, t) => new Promise((resolve, reject) => {
   // Session must have a baseLayer or else frame requests will be ignored.
   let webglLayer = new XRWebGLLayer(session, gl);
   session.updateRenderState({ baseLayer: webglLayer });
@@ -63,6 +63,6 @@
 });
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrWebGLLayer_framebuffer_draw.html b/third_party/blink/web_tests/xr/xrWebGLLayer_framebuffer_draw.html
index 61cf697..fe5f8ba 100644
--- a/third_party/blink/web_tests/xr/xrWebGLLayer_framebuffer_draw.html
+++ b/third_party/blink/web_tests/xr/xrWebGLLayer_framebuffer_draw.html
@@ -38,7 +38,7 @@
 }
 
 let testFunction =
-  (session, t, fakeDeviceController) => new Promise((resolve, reject) => {
+  (session, fakeDeviceController, t) => new Promise((resolve, reject) => {
   // Setup simple WebGL geometry to draw with.
   let program = setupProgram(gl,
     "attribute vec4 vPosition; void main() { gl_Position = vPosition; }",
@@ -95,6 +95,6 @@
 });
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrWebGLLayer_framebuffer_scale.html b/third_party/blink/web_tests/xr/xrWebGLLayer_framebuffer_scale.html
index 9526b3c..c6ac8d5 100644
--- a/third_party/blink/web_tests/xr/xrWebGLLayer_framebuffer_scale.html
+++ b/third_party/blink/web_tests/xr/xrWebGLLayer_framebuffer_scale.html
@@ -17,7 +17,7 @@
 let requestSessionModes =  ['immersive-vr'];
 
 let testFunction =
-  (session, t, fakeDeviceController) => new Promise((resolve, reject) => {
+  (session, fakeDeviceController, t) => new Promise((resolve, reject) => {
   // Session must have a baseLayer or else frame requests will be ignored.
   let webglLayer = new XRWebGLLayer(session, gl);
   let defaultFramebufferWidth = webglLayer.framebufferWidth;
@@ -59,6 +59,6 @@
 });
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/blink/web_tests/xr/xrWebGLLayer_opaque_framebuffer.html b/third_party/blink/web_tests/xr/xrWebGLLayer_opaque_framebuffer.html
index d46144b..e25d181 100644
--- a/third_party/blink/web_tests/xr/xrWebGLLayer_opaque_framebuffer.html
+++ b/third_party/blink/web_tests/xr/xrWebGLLayer_opaque_framebuffer.html
@@ -19,7 +19,7 @@
 ];
 
 let testFunction =
-  (session, t, fakeDeviceController) => new Promise((resolve, reject) => {
+  (session, fakeDeviceController, t) => new Promise((resolve, reject) => {
   // Session must have a baseLayer or frame requests will be ignored.
   let webglLayer = new XRWebGLLayer(session, gl, {
       compositionDisabled: session.mode == 'inline' });
@@ -119,6 +119,6 @@
 });
 
 xr_session_promise_test(
-  testFunction, fakeDeviceInitParams, requestSessionModes, testName);
+  testName, testFunction, fakeDeviceInitParams, requestSessionModes);
 
 </script>
diff --git a/third_party/closure_compiler/externs/accessibility_private.js b/third_party/closure_compiler/externs/accessibility_private.js
index 6eee36d..1cdce4d 100644
--- a/third_party/closure_compiler/externs/accessibility_private.js
+++ b/third_party/closure_compiler/externs/accessibility_private.js
@@ -283,6 +283,13 @@
 chrome.accessibilityPrivate.setVirtualKeyboardVisible = function(isVisible) {};
 
 /**
+ * Opens a settings subpage, specified by the portion of the page's URL after
+ * "chrome://settings/"
+ * @param {string} subpage
+ */
+chrome.accessibilityPrivate.openSettingsSubpage = function (subpage) {}
+
+/**
  * Fired whenever ChromeVox should output introduction.
  * @type {!ChromeEvent}
  */
diff --git a/third_party/grpc/BUILD.gn b/third_party/grpc/BUILD.gn
index 47b043fc..f937e23a 100644
--- a/third_party/grpc/BUILD.gn
+++ b/third_party/grpc/BUILD.gn
@@ -33,8 +33,11 @@
 # The gRPC library. Note that server side code will not be built. You probably
 # want to use cc_grpc_library() from grpc_library.gni directly.
 static_library("grpcpp") {
-  # This is currently only used by remoting.
-  visibility = [ "//remoting/*" ]
+  # This is currently only used by remoting and chromecast.
+  visibility = [
+    "//chromecast/*",
+    "//remoting/*",
+  ]
   sources = [
     "src/src/cpp/client/channel_cc.cc",
     "src/src/cpp/client/client_context.cc",
diff --git a/third_party/instrumented_libraries/BUILD.gn b/third_party/instrumented_libraries/BUILD.gn
index 114f8ea4..cd69cf3 100644
--- a/third_party/instrumented_libraries/BUILD.gn
+++ b/third_party/instrumented_libraries/BUILD.gn
@@ -155,8 +155,11 @@
     ]
     if (is_msan) {
       deps += [
+        ":libcgmanager0",
         ":libcups2",
         ":libgnutls26",
+        ":libnih-dbus1",
+        ":libnih1",
       ]
     }
     if (!is_tsan) {
@@ -372,6 +375,13 @@
     build_method = "custom_libcap"
   }
 
+  instrumented_library("libcgmanager0") {
+    extra_configure_flags = [ "--disable-static" ]
+
+    # Required on Trusty due to autoconf version mismatch.
+    pre_build = "scripts/pre-build/autoreconf.sh"
+  }
+
   instrumented_library("libcredentialkit_pkcs11") {
     build_method = "stub"
   }
@@ -594,6 +604,18 @@
     pre_build = "scripts/pre-build/autogen.sh"
   }
 
+  instrumented_library("libnih1") {
+    extra_configure_flags = [ "--disable-static" ]
+
+    pre_build = "scripts/pre-build/libnih1.sh"
+  }
+
+  instrumented_library("libnih-dbus1") {
+    extra_configure_flags = [ "--disable-static" ]
+
+    pre_build = "scripts/pre-build/libnih1.sh"
+  }
+
   instrumented_library("libnspr4") {
     extra_configure_flags = [
       "--enable-64bit",
diff --git a/third_party/instrumented_libraries/OWNERS b/third_party/instrumented_libraries/OWNERS
index 5ab51c29..bde379aea 100644
--- a/third_party/instrumented_libraries/OWNERS
+++ b/third_party/instrumented_libraries/OWNERS
@@ -1,3 +1,3 @@
-glider@chromium.org
 eugenis@chromium.org
-
+glider@chromium.org
+thomasanderson@chromium.org
diff --git a/third_party/instrumented_libraries/binaries/msan-chained-origins-trusty.tgz.sha1 b/third_party/instrumented_libraries/binaries/msan-chained-origins-trusty.tgz.sha1
index bd4ac27..0f37fb8 100644
--- a/third_party/instrumented_libraries/binaries/msan-chained-origins-trusty.tgz.sha1
+++ b/third_party/instrumented_libraries/binaries/msan-chained-origins-trusty.tgz.sha1
@@ -1 +1 @@
-0185d9b6c6fdfbcfffa61d8ac9f19e8879c4dee2
\ No newline at end of file
+8b12274d9abf6245670d4893f6d25aa916b051a1
\ No newline at end of file
diff --git a/third_party/instrumented_libraries/binaries/msan-no-origins-trusty.tgz.sha1 b/third_party/instrumented_libraries/binaries/msan-no-origins-trusty.tgz.sha1
index 7a5de3dd..19b73595 100644
--- a/third_party/instrumented_libraries/binaries/msan-no-origins-trusty.tgz.sha1
+++ b/third_party/instrumented_libraries/binaries/msan-no-origins-trusty.tgz.sha1
@@ -1 +1 @@
-d429da145648e1795ad8b9005b219b8e6888b79f
\ No newline at end of file
+c7a988dae7eb3391e446a932de7f690698cf3a31
\ No newline at end of file
diff --git a/third_party/instrumented_libraries/scripts/pre-build/libnih1.sh b/third_party/instrumented_libraries/scripts/pre-build/libnih1.sh
new file mode 100755
index 0000000..60c48cff
--- /dev/null
+++ b/third_party/instrumented_libraries/scripts/pre-build/libnih1.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+# Copyright 2019 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.
+
+# This script does some preparations before build of instrumented libnih1.
+
+# Use the system-installed nih-dbus-tool during building. Normally a
+# just-built one is used, however in MSan builds it will crash due to
+# uninstrumented dependencies.
+
+sed -i 's|NIH_DBUS_TOOL="\\${top_builddir}/nih-dbus-tool/nih-dbus-tool"|NIH_DBUS_TOOL="/usr/bin/nih-dbus-tool"|g' configure
diff --git a/tools/checkteamtags/checkteamtags.py b/tools/checkteamtags/checkteamtags.py
index c12166fe..2031e69 100755
--- a/tools/checkteamtags/checkteamtags.py
+++ b/tools/checkteamtags/checkteamtags.py
@@ -35,81 +35,81 @@
 def validate_mappings(options, args):
   """Ensure team/component mapping remains consistent after patch.
 
-  The main purpose of this check is to prevent new and edited OWNERS files
-  introduce multiple teams for the same component.
+  The main purpose of this check is to notify the user if any edited (or added)
+  team tag makes a component map to multiple teams.
 
   Args:
     options: Command line options from optparse
     args: List of paths to affected OWNERS files
+  Returns:
+    A string containing the details of any multi-team per component.
   """
   mappings_file = json.load(urllib2.urlopen(options.current_mapping_url))
+  new_dir_to_component = mappings_file.get('dir-to-component', {})
+  new_dir_to_team = mappings_file.get('dir-to-team', {})
 
-  # Convert dir -> component, component -> team to dir -> (team, component)
-  current_mappings = {}
-  for dir_name in mappings_file['dir-to-component'].keys():
-    component = mappings_file['dir-to-component'].get(dir_name)
-    if component:
-      team = mappings_file['component-to-team'].get(component)
-    else:
-      team = None
-    current_mappings[dir_name] = {'team': team, 'component': component}
-
-  # Extract dir -> (team, component) for affected files
   affected = {}
   deleted = []
+  affected_components = set()
+
+  # Parse affected OWNERS files
   for f in args:
     rel, full = rel_and_full_paths(options.root, f)
     if os.path.exists(full):
       affected[os.path.dirname(rel)] = parse(full)
     else:
       deleted.append(os.path.dirname(rel))
-  for d in deleted:
-    current_mappings.pop(d, None)
-  current_mappings.update(affected)
 
-  #Ensure internal consistency of modified mappings.
-  new_dir_to_component = {}
-  new_component_to_team = {}
-  team_to_dir = defaultdict(list)
-  errors = {}
-  for dir_name, tags in current_mappings.iteritems():
-    team = tags.get('team')
+  # Update component mapping with current changes.
+  for rel_path, tags in affected.iteritems():
     component = tags.get('component')
+    team = tags.get('team')
     os_tag = tags.get('os')
-    if os_tag:
-      component = '%s(%s)' % (component, os)
-
     if component:
-      new_dir_to_component[dir_name] = component
+      if os_tag:
+        component = '%s(%s)' % (component, os_tag)
+      new_dir_to_component[rel_path] = component
+      affected_components.add(component)
+    elif rel_path in new_dir_to_component:
+      del new_dir_to_component[rel_path]
     if team:
-      team_to_dir[team].append(dir_name)
-    if component and team:
-      if new_component_to_team.setdefault(component, team) != team:
-        if component not in errors:
-          errors[component] = set([new_component_to_team[component], team])
-        else:
-          errors[component].add(team)
+      new_dir_to_team[rel_path] = team
+    elif rel_path in new_dir_to_team:
+      del new_dir_to_team[rel_path]
+  for deleted_dir in deleted:
+    if deleted_dir in new_dir_to_component:
+      del new_dir_to_component[deleted_dir]
+    if deleted_dir in new_dir_to_team:
+      del new_dir_to_team[deleted_dir]
 
-  result = []
-  for component, teams in errors.iteritems():
-    error_message = 'The component "%s" has more than one team: ' % component
-    team_details = []
-    for team in teams:
-      offending_dirs = [d for d in team_to_dir[team]
-                        if new_dir_to_component.get(d) == component]
-      team_details.append('%(team)s is used in %(paths)s' % {
-          'team': team,
-          'paths': ', '.join(offending_dirs),
-      })
-    error_message += '; '.join(team_details)
-    result.append({
-        'error': error_message,
-        'full_path':
-            ' '.join(['%s/OWNERS' % d
-                      for d, c in new_dir_to_component.iteritems()
-                      if c == component and d in affected.keys()])
-    })
-  return result
+  # For the components affected by this patch, compute the directories that map
+  # to it.
+  affected_component_to_dirs = {}
+  for d, component in new_dir_to_component.iteritems():
+    if component in affected_components:
+      affected_component_to_dirs.setdefault(component, [])
+      affected_component_to_dirs[component].append(d)
+
+  # Convert component->[dirs], dir->team to component->[teams].
+  affected_component_to_teams = {
+      component: list(set([
+          new_dir_to_team[d]
+          for d in dirs
+          if d in new_dir_to_team
+      ])) for component, dirs in affected_component_to_dirs.iteritems()
+  }
+
+  # Perform cardinality check.
+  warnings = ''
+  for component, teams in affected_component_to_teams.iteritems():
+    if len(teams) > 1:
+      warnings += '\nComponent %s will map to %s' % (
+          component, ', '.join(teams))
+  if warnings:
+    warnings = ('Are you sure these are correct? After landing this patch:%s'
+                % warnings)
+
+  return warnings
 
 
 def check_owners(rel_path, full_path):
@@ -196,8 +196,9 @@
   errors = filter(None, [check_owners(*rel_and_full_paths(options.root, f))
                          for f in args])
 
+  warnings = None
   if not errors:
-    errors += validate_mappings(options, args) or []
+    warnings = validate_mappings(options, args)
 
   if options.json:
     with open(options.json, 'w') as f:
@@ -211,7 +212,8 @@
       print '\n'.join('%s: %s' % (e['full_path'], e['error']) for e in errors)
     return 1
   if not options.bare:
-    print '\nSUCCESS\n'
+    if warnings:
+      print warnings
   return 0
 
 
diff --git a/tools/checkteamtags/checkteamtags_test.py b/tools/checkteamtags/checkteamtags_test.py
index 5dc0c4a..1a1dbf30 100644
--- a/tools/checkteamtags/checkteamtags_test.py
+++ b/tools/checkteamtags/checkteamtags_test.py
@@ -171,13 +171,13 @@
           'V8>mock_component': 'some-other-team@chromium.org',
       },
   }))
-  @mock.patch('sys.argv', ['checkteamtags', '--bare', 'fakepath/OWNERS'])
-  def testMappingFail(self):
+  @mock.patch('sys.argv', ['checkteamtags', 'fakepath/OWNERS'])
+  def testMultipleTeams(self):
     with mock.patch(open_name, create=True) as mock_open:
       mock_open.return_value = mock_file(BASIC)
       with mock.patch('owners_file_tags.open', create=True) as mock_open_2:
         mock_open_2.return_value = mock_file(BASIC)
-        self.assertEqual(1, checkteamtags.main())
+        self.assertEqual(0, checkteamtags.main())
 
   @mock.patch('urllib2.urlopen', mock_url_open({
       'dir-to-component': {
diff --git a/tools/checkteamtags/extract_components.py b/tools/checkteamtags/extract_components.py
index 697c8070..62b6908 100755
--- a/tools/checkteamtags/extract_components.py
+++ b/tools/checkteamtags/extract_components.py
@@ -167,8 +167,6 @@
                     help='If no errors occur, write the mappings to disk.')
   parser.add_option('-v', '--verbose', action='store_true',
                     help='Print warnings.')
-  parser.add_option('-f', '--force_print', action='store_true',
-                    help='Print the mappings despite errors.')
   parser.add_option('-o', '--output_file', help='Specify file to write the '
                     'mappings to instead of the default: <CWD>/'
                     'component_map.json (implies -w)')
@@ -189,15 +187,12 @@
     root = _DEFAULT_SRC_LOCATION
 
   scrape_result = scrape_owners(root, include_subdirs=options.include_subdirs)
-  mappings, warnings, errors, stats = aggregate_components_from_owners(
-      scrape_result, root, include_subdirs=options.include_subdirs)
+  mappings, warnings, stats = aggregate_components_from_owners(scrape_result,
+                                                               root)
   if options.verbose:
     for w in warnings:
       print w
 
-  for e in errors:
-    print e
-
   if options.stat_coverage or options.complete_coverage:
     display_stat(stats, root, options)
 
@@ -208,16 +203,11 @@
   mappings['AAA-README']= _README
   mapping_file_contents = json.dumps(mappings, sort_keys=True, indent=2)
   if options.write or options.output_file:
-    if errors:
-      print 'Not writing to file due to errors'
-      if options.force_print:
-        print mapping_file_contents
-    else:
-      write_results(options.output_file, mapping_file_contents)
+    write_results(options.output_file, mapping_file_contents)
   else:
     print mapping_file_contents
 
-  return len(errors)
+  return 0
 
 
 if __name__ == '__main__':
diff --git a/tools/checkteamtags/extract_components_test.py b/tools/checkteamtags/extract_components_test.py
index 27c7921..a9af972 100644
--- a/tools/checkteamtags/extract_components_test.py
+++ b/tools/checkteamtags/extract_components_test.py
@@ -11,7 +11,6 @@
 from StringIO import StringIO
 
 import extract_components
-from owners_file_tags_test import mock_file_tree
 
 SRC = os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir)
 sys.path.append(os.path.join(SRC, 'third_party', 'pymock'))
@@ -57,7 +56,18 @@
               'dummydir1': 'Dummy>Component',
               'dummydir1/innerdir1':
                   'Dummy>Component>Subcomponent',
-              'dummydir2': 'Components>Component2'
+              'dummydir2': 'Components>Component2',
+          },
+          'dir-to-team': {
+              'dummydir1': 'dummy-team@chromium.org',
+              'dummydir1/innerdir1': 'dummy-specialist-team@chromium.org',
+              'dummydir2': 'other-dummy-team@chromium.org',
+          },
+          'teams-per-component': {
+              'Components>Component2': ['other-dummy-team@chromium.org'],
+              'Dummy>Component': ['dummy-team@chromium.org'],
+              'Dummy>Component>Subcomponent':
+                  ['dummy-specialist-team@chromium.org'],
           }})
 
   def testOsTagBreaksDuplication(self):
@@ -94,6 +104,17 @@
               'dummydir1': 'Dummy>Component',
               'dummydir1/innerdir1': 'Dummy>Component>Subcomponent',
               'dummydir2': 'Dummy>Component(Mac)'
+          },
+          'dir-to-team': {
+              'dummydir1': 'dummy-team@chromium.org',
+              'dummydir1/innerdir1': 'dummy-specialist-team@chromium.org',
+              'dummydir2': 'mac-dummy-team@chromium.org',
+          },
+          'teams-per-component': {
+              'Dummy>Component': ['dummy-team@chromium.org'],
+              'Dummy>Component(Mac)': ['mac-dummy-team@chromium.org'],
+              'Dummy>Component>Subcomponent': [
+                  'dummy-specialist-team@chromium.org']
           }})
 
   def testMultipleTeamsOneComponent(self):
@@ -105,20 +126,42 @@
         },
         'dummydir2': {
             'team': 'other-dummy-team@chromium.org',
-            'component': 'Dummy>Component',
+            'component': 'Dummy>Component2',
         },
         'dummydir1/innerdir1': {
             'team': 'dummy-specialist-team@chromium.org',
-            'component': 'Dummy>Component>Subcomponent'
+            'component': 'Dummy>Component'
         }
     }):
       saved_output = StringIO()
       with mock.patch('sys.stdout', saved_output):
-        error_code = extract_components.main(['%prog', '-w', 'src'])
-      self.assertNotEqual(0, error_code)
-      output = saved_output.getvalue()
-      self.assertIn('has more than one team assigned to it', output)
-      self.assertIn('Not writing to file', output)
+        error_code = extract_components.main(['%prog', 'src'])
+      self.assertEqual(0, error_code)
+      result_minus_readme = json.loads(saved_output.getvalue())
+      del result_minus_readme['AAA-README']
+      self.assertEqual(result_minus_readme, {
+          'component-to-team': {
+              'Dummy>Component': 'dummy-team@chromium.org',
+              'Dummy>Component2':
+                  'other-dummy-team@chromium.org'
+          },
+          'dir-to-component': {
+              'dummydir1': 'Dummy>Component',
+              'dummydir1/innerdir1': 'Dummy>Component',
+              'dummydir2': 'Dummy>Component2'
+          },
+          'dir-to-team': {
+              'dummydir1': 'dummy-team@chromium.org',
+              'dummydir1/innerdir1': 'dummy-specialist-team@chromium.org',
+              'dummydir2': 'other-dummy-team@chromium.org',
+          },
+          'teams-per-component': {
+              'Dummy>Component': [
+                  'dummy-specialist-team@chromium.org',
+                  'dummy-team@chromium.org'],
+              'Dummy>Component2': [
+                  'other-dummy-team@chromium.org'],
+          }})
 
   def testVerbose(self):
     with mock.patch('extract_components.scrape_owners', return_value={
@@ -191,53 +234,6 @@
       self.assertIn('2 OWNERS files at depth 1', output)
       self.assertIn('1 OWNERS files at depth 2', output)
 
-  def testIncludesSubdirectoriesWithNoOwnersFileOrNoComponentTag(self):
-    # We use OrderedDict here to guarantee that mocked version of os.walk
-    # returns directories in the specified order (top-down).
-    with mock_file_tree(OrderedDict([
-        ('chromium/src', 'boss@chromium.org\n'),
-        ('chromium/src/dir1', 'dummy@chromium.org\n'
-                              '# TEAM: dummy-team@chromium.org\n'
-                              '# COMPONENT: Dummy>Component'),
-        ('chromium/src/dir2', 'dummy2@chromium.org\n'
-                              '# TEAM: other-dummy-team@chromium.org\n'
-                              '# COMPONENT: Dummy>Component2'),
-        ('chromium/src/dir1/subdir', 'dummy@chromium.org'),
-        ('chromium/src/dir2/subdir', None),
-        ('third_party/blink/web_tests/foo',
-             '# TEAM: dummy-team-3@chromium.org\n'),
-        ('third_party/blink/web_tests/bar',
-             '# TEAM: dummy-team-3@chromium.org\n'
-             '# COMPONENT: Dummy>Component3\n'),
-    ])):
-      # TODO(robertocn): remove this testcase and the auxiliary function
-      # mock_file_tree (that has been moved to owners_file_tags_test) when
-      # sergiyb's scripts are using the data directly from scrape_owners.
-      self.maxDiff = None  # This helps to see assertDictEqual errors in full.
-      saved_output = StringIO()
-      with mock.patch('sys.stdout', saved_output):
-        error_code = extract_components.main(['%prog', '--include-subdirs', ''])
-      self.assertEqual(0, error_code)
-      result_minus_readme = json.loads(saved_output.getvalue())
-      del result_minus_readme['AAA-README']
-      self.assertDictEqual(result_minus_readme, {
-          u'component-to-team': {
-              u'Dummy>Component': u'dummy-team@chromium.org',
-              u'Dummy>Component2': u'other-dummy-team@chromium.org',
-              u'Dummy>Component3': u'dummy-team-3@chromium.org',
-          },
-          u'dir-to-component': {
-              u'chromium/src/dir1': u'Dummy>Component',
-              u'chromium/src/dir1/subdir': u'Dummy>Component',
-              u'chromium/src/dir2': u'Dummy>Component2',
-              u'chromium/src/dir2/subdir': u'Dummy>Component2',
-              u'third_party/blink/web_tests/bar': u'Dummy>Component3',
-          },
-          u'dir-to-team': {
-              u'third_party/blink/web_tests/foo':
-                  u'dummy-team-3@chromium.org',
-          }})
-
   def testDisplayFile(self):
     with mock.patch('extract_components.scrape_owners', return_value={
         '.': {},
diff --git a/tools/checkteamtags/owners_file_tags.py b/tools/checkteamtags/owners_file_tags.py
index 5cf6937..68fe8ca 100644
--- a/tools/checkteamtags/owners_file_tags.py
+++ b/tools/checkteamtags/owners_file_tags.py
@@ -39,22 +39,20 @@
   return result
 
 
-def aggregate_components_from_owners(all_owners_data, root,
-                                     include_subdirs=False):
+def aggregate_components_from_owners(all_owners_data, root):
   """Converts the team/component/os tags parsed from OWNERS into mappings.
 
   Args:
     all_owners_data (dict): A mapping from relative path to a dir to a dict
         mapping the tag names to their values. See docstring for scrape_owners.
     root (str): the path to the src directory.
-    include_subdirs (bool): Deprecated, whether to generate the additional
-        dir-to-team mapping. This mapping is being replaced by the result of
-        scrape_owners below.
 
   Returns:
-    A tuple (data, warnings, errors, stats) where data is a dict of the form
+    A tuple (data, warnings, stats) where data is a dict of the form
       {'component-to-team': {'Component1': 'team1@chr...', ...},
+       'teams-per-component': {'Component1': ['team1@chr...', 'team2@chr...]},
        'dir-to-component': {'/path/to/1': 'Component1', ...}}
+       'dir-to-team': {'/path/to/1': 'team1@', ...}}
       , warnings is a list of strings, stats is a dict of form
       {'OWNERS-count': total number of OWNERS files,
        'OWNERS-with-component-only-count': number of OWNERS have # COMPONENT,
@@ -73,11 +71,10 @@
   num_with_component_by_depth = defaultdict(int)
   num_with_team_component_by_depth = defaultdict(int)
   warnings = []
-  component_to_team = defaultdict(set)
+  teams_per_component = defaultdict(set)
+  topmost_team = {}
   dir_to_component = {}
   dir_missing_info_by_depth = defaultdict(list)
-  # TODO(sergiyb): Remove this mapping. Please do not use it as it is going to
-  # be removed in the future. See http://crbug.com/702202.
   dir_to_team = {}
   for rel_dirname, owners_data in all_owners_data.iteritems():
     # We apply relpath to remove any possible `.` and `..` chunks and make
@@ -91,6 +88,8 @@
     os_tag = owners_data.get('os')
     if os_tag and component:
       component = '%s(%s)' % (component, os_tag)
+    if team:
+      dir_to_team[rel_dirname] = team
     if component:
       num_with_component += 1
       num_with_component_by_depth[file_depth] += 1
@@ -98,32 +97,27 @@
       if team:
         num_with_team_component += 1
         num_with_team_component_by_depth[file_depth] += 1
-        component_to_team[component].add(team)
+        teams_per_component[component].add(team)
+        if component not in topmost_team or file_depth < topmost_team[
+            component]['depth']:
+          topmost_team[component] = {'depth': file_depth, 'team': team}
     else:
       rel_owners_path = os.path.join(rel_dirname, 'OWNERS')
       warnings.append('%s has no COMPONENT tag' % rel_owners_path)
       if not team and not os_tag:
         dir_missing_info_by_depth[file_depth].append(rel_owners_path)
 
-    # TODO(robertocn): Remove the dir-to-team mapping once the raw owners data
-    # is being exported in its own file and being used by sergiyb's scripts.
-    # Add dir-to-team mapping unless there is also dir-to-component mapping.
-    if (include_subdirs and team and not component and
-        rel_dirname.startswith('third_party/blink/web_tests')):
-      dir_to_team[rel_dirname] = team
-
-    if include_subdirs and rel_dirname not in dir_to_component:
-      rel_parent_dirname = os.path.relpath(rel_dirname, root)
-      if rel_parent_dirname in dir_to_component:
-        dir_to_component[rel_dirname] = dir_to_component[rel_parent_dirname]
-      if rel_parent_dirname in dir_to_team:
-        dir_to_team[rel_dirname] = dir_to_team[rel_parent_dirname]
-
-  mappings = {'component-to-team': component_to_team,
-              'dir-to-component': dir_to_component}
-  if include_subdirs:
-    mappings['dir-to-team'] = dir_to_team
-  errors = validate_one_team_per_component(mappings)
+  mappings = {
+      'component-to-team': {
+          k: v['team'] for k, v in topmost_team.iteritems()
+      },
+      'teams-per-component': {
+          k: sorted(list(v)) for k, v in teams_per_component.iteritems()
+      },
+      'dir-to-component': dir_to_component,
+      'dir-to-team': dir_to_team,
+  }
+  warnings += validate_one_team_per_component(mappings)
   stats = {'OWNERS-count': num_total,
            'OWNERS-with-component-only-count': num_with_component,
            'OWNERS-with-team-and-component-count': num_with_team_component,
@@ -134,27 +128,27 @@
            num_with_team_component_by_depth,
            'OWNERS-missing-info-by-depth':
            dir_missing_info_by_depth}
-  return unwrap(mappings), warnings, errors, stats
+  return mappings, warnings, stats
 
 
 def validate_one_team_per_component(m):
   """Validates that each component is associated with at most 1 team."""
-  errors = []
+  warnings = []
   # TODO(robertocn): Validate the component names: crbug.com/679540
-  component_to_team = m['component-to-team']
-  for c in component_to_team:
-    if len(component_to_team[c]) > 1:
-      errors.append('Component %s has more than one team assigned to it: %s' % (
-          c, ', '.join(list(component_to_team[c]))))
-  return errors
+  teams_per_component = m['teams-per-component']
+  for c in teams_per_component:
+    if len(teams_per_component[c]) > 1:
+      warnings.append('Component %s has the following teams assigned: %s.\n'
+                      'Team %s is being used, as it is defined at the OWNERS '
+                      'file at the topmost dir'
+                      % (
+                          c,
+                          ', '.join(teams_per_component[c]),
+                          m['component-to-team'][c]
+                      ))
+  return warnings
 
 
-def unwrap(mappings):
-  """Remove the set() wrapper around values in component-to-team mapping."""
-  for c in mappings['component-to-team']:
-    mappings['component-to-team'][c] = mappings['component-to-team'][c].pop()
-  return mappings
-
 def scrape_owners(root, include_subdirs):
   """Recursively parse OWNERS files for tags.
 
@@ -176,19 +170,32 @@
   }
   """
   data = {}
+
+  def nearest_ancestor_tag(dirname, tag):
+    """ Find the value of tag in the nearest ancestor that defines it."""
+    ancestor = os.path.dirname(dirname)
+    while ancestor:
+      rel_ancestor = os.path.relpath(ancestor, root)
+      if rel_ancestor in data and data[rel_ancestor].get(tag):
+        return data[rel_ancestor][tag]
+      if rel_ancestor == '.':
+        break
+      ancestor = os.path.dirname(ancestor)
+    return
+
   for dirname, _, files in os.walk(root):
     # Proofing against windows casing oddities.
     owners_file_names = [f for f in files if f.upper() == 'OWNERS']
     rel_dirname = os.path.relpath(dirname, root)
-    if owners_file_names:
-      owners_full_path = os.path.join(dirname, owners_file_names[0])
-      data[rel_dirname] = parse(owners_full_path)
-    if include_subdirs and not data.get(rel_dirname):
-      parent_dirname = os.path.dirname(dirname)
-      # In the case where the root doesn't have an OWNERS file, don't try to
-      # check its parent.
-      if parent_dirname:
-        rel_parent_dirname = os.path.relpath(parent_dirname , root)
-        if rel_parent_dirname in data:
-          data[rel_dirname] = data[rel_parent_dirname]
+    if owners_file_names or include_subdirs:
+      if owners_file_names:
+        owners_full_path = os.path.join(dirname, owners_file_names[0])
+        data[rel_dirname] = parse(owners_full_path)
+      else:
+        data[rel_dirname] = {}
+      for tag in ('component', 'os', 'team'):
+        if not tag in data[rel_dirname]:
+          ancestor_tag = nearest_ancestor_tag(dirname, tag)
+          if ancestor_tag:
+            data[rel_dirname][tag] = ancestor_tag
   return data
diff --git a/tools/checkteamtags/owners_file_tags_test.py b/tools/checkteamtags/owners_file_tags_test.py
index 4218b76..2de932d3 100644
--- a/tools/checkteamtags/owners_file_tags_test.py
+++ b/tools/checkteamtags/owners_file_tags_test.py
@@ -85,16 +85,20 @@
       self.assertEqual({
           '.': {},
           'dummydir1': {
-              'team': 'dummy-team@chromium.org',
               'component': 'Dummy>Component',
+              'team': 'dummy-team@chromium.org',
           },
           'dummydir1/innerdir1': {
+              'component': 'Dummy>Component',
               'team': 'dummy-specialist-team@chromium.org',
           },
           'dummydir1/innerdir2': {
-              'component': 'Dummy>Component>Subcomponent'
+              'component': 'Dummy>Component>Subcomponent',
+              'team': 'dummy-team@chromium.org',
           },
           'dummydir1/innerdir3': {
+              'component': 'Dummy>Component',
+              'team': 'dummy-team@chromium.org',
               'os': 'Mac'
           }
       }, scraped_data)
@@ -120,20 +124,24 @@
       self.assertEqual({
           '.': {},
           'dummydir1': {
-              'team': 'dummy-team@chromium.org',
               'component': 'Dummy>Component',
+              'team': 'dummy-team@chromium.org',
           },
           'dummydir1/innerdir1': {
+              'component': 'Dummy>Component',
               'team': 'dummy-specialist-team@chromium.org',
           },
           'dummydir1/innerdir2': {
-              'component': 'Dummy>Component>Subcomponent'
+              'component': 'Dummy>Component>Subcomponent',
+              'team': 'dummy-team@chromium.org',
           },
           'dummydir1/innerdir3': {
+              'component': 'Dummy>Component',
+              'team': 'dummy-team@chromium.org',
               'os': 'Mac'
           },
           'dummydir1/innerdir4': {
-              'team': 'dummy-team@chromium.org',
               'component': 'Dummy>Component',
+              'team': 'dummy-team@chromium.org',
           },
-      }, scraped_data )
+      }, scraped_data)
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 0182eedb..c403608c 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -217,6 +217,9 @@
   "components/embedder_suppport/android/java/strings/web_contents_delegate_android_strings.grd": {
     "messages": [17600],
   },
+  "components/autofill/core/browser/autofill_address_rewriter_resources.grd":{
+    "includes": [18000]
+  },
   # END components/ section.
 
   # START content/ section.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index fbf6488..7b3eb4e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -19927,6 +19927,7 @@
   <int value="1359" label="ACTION_GETBADGEBACKGROUNDCOLOR"/>
   <int value="1360" label="ACTION_SETBADGEBACKGROUNDCOLOR"/>
   <int value="1361" label="AUTOTESTPRIVATE_SETARCAPPWINDOWSTATE"/>
+  <int value="1362" label="ACCESSIBILITY_PRIVATE_OPENSETTINGSSUBPAGE"/>
 </enum>
 
 <enum name="ExtensionIconState">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cdd8fc4..e130a3e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -5930,6 +5930,33 @@
   </summary>
 </histogram>
 
+<histogram name="Arc.Runtime.Performance.CommitDeviation" units="microseconds"
+    expires_after="2020-07-01">
+<!-- Name completed by histogram_suffixes name="ArcPerformanceAppCategories" -->
+
+  <owner>khmel@google.com</owner>
+  <owner>skuhne@google.com</owner>
+  <summary>Standard deviation for commit time delta from ideal time.</summary>
+</histogram>
+
+<histogram name="Arc.Runtime.Performance.FPS" units="fps"
+    expires_after="2020-07-01">
+<!-- Name completed by histogram_suffixes name="ArcPerformanceAppCategories" -->
+
+  <owner>khmel@google.com</owner>
+  <owner>skuhne@google.com</owner>
+  <summary>Render frames per second.</summary>
+</histogram>
+
+<histogram name="Arc.Runtime.Performance.RenderQuality" units="%"
+    expires_after="2020-07-01">
+<!-- Name completed by histogram_suffixes name="ArcPerformanceAppCategories" -->
+
+  <owner>khmel@google.com</owner>
+  <owner>skuhne@google.com</owner>
+  <summary>Render quality with maximum 100%.</summary>
+</histogram>
+
 <histogram name="Arc.SdkVersionUpgradeType" enum="ArcSdkVersionUpgradeType">
   <owner>niwa@google.com</owner>
   <owner>yusukes@google.com</owner>
@@ -19958,6 +19985,20 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Compositing.Renderer.PercentPictureLayersWithTextButLCDTextDisabled"
+    units="%" expires_after="2019-12-01">
+<!-- Name completed by histogram_suffixes name="CompositingLCDTextDisabledCountSuffixes" -->
+
+  <owner>paint-dev@chromium.org</owner>
+  <summary>
+    The number of PictureLayers in the active tree for each compositor frame
+    that have both text drawing operations and do not permit lcd text. This is
+    logged once per frame, before the frame is drawn (in a renderer process).
+    Suffixed with the count of number of picture layers with text.
+  </summary>
+</histogram>
+
 <histogram name="Compositing.Renderer.PictureMemoryUsageKb" units="KB">
   <owner>paint-dev@chromium.org</owner>
   <summary>
@@ -33540,7 +33581,7 @@
 </histogram>
 
 <histogram name="Enterprise.Policies.IgnoredByPolicyGroup"
-    enum="EnterprisePolicies" expires_after="M78">
+    enum="EnterprisePolicies" expires_after="2020-07-01">
   <owner>ydago@chromium.org</owner>
   <summary>
     A set of enterprise policy rules that are ignored because they do not share
@@ -33563,7 +33604,7 @@
 </histogram>
 
 <histogram name="Enterprise.PolicyAtomicGroup.SourceConflicts"
-    enum="PolicyAtomicGroups" expires_after="M78">
+    enum="PolicyAtomicGroups" expires_after="2020-07-01">
   <owner>ydago@chromium.org</owner>
   <summary>
     A set of policy atomic groups that have at least one policy disabled because
@@ -125955,7 +125996,7 @@
 </histogram>
 
 <histogram name="SingleWebsitePreferences.NavigatedFromToReset"
-    enum="SettingsNavigationSources" expires_after="M78">
+    enum="SettingsNavigationSources" expires_after="M83">
   <owner>pshmakov@chromium.org</owner>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -137340,7 +137381,10 @@
   </summary>
 </histogram>
 
-<histogram name="Tabs.TimeSinceLastInteraction" units="ms" expires_after="M77">
+<histogram name="Tabs.TimeSinceLastInteraction" units="ms">
+  <obsolete>
+    Removed 2019-07.
+  </obsolete>
   <owner>alexmos@chromium.org</owner>
   <owner>dcheng@chromium.org</owner>
   <summary>
@@ -139414,7 +139458,7 @@
 </histogram>
 
 <histogram name="TrustedWebActivity.ClearDataDialogOnClearAppDataAccepted"
-    enum="Boolean" expires_after="M78">
+    enum="Boolean" expires_after="M83">
   <owner>pshmakov@chromium.org</owner>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -139425,7 +139469,7 @@
 </histogram>
 
 <histogram name="TrustedWebActivity.ClearDataDialogOnUninstallAccepted"
-    enum="Boolean" expires_after="M78">
+    enum="Boolean" expires_after="M83">
   <owner>pshmakov@chromium.org</owner>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -139437,7 +139481,7 @@
 
 <histogram name="TrustedWebActivity.DelegatedNotificationSmallIconFallback"
     enum="TrustedWebActivityDelegatedNotificationSmallIconFallback"
-    expires_after="M78">
+    expires_after="M83">
   <owner>pshmakov@chromium.org</owner>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -139448,7 +139492,7 @@
 </histogram>
 
 <histogram name="TrustedWebActivity.SplashScreenShown" enum="Boolean"
-    expires_after="M80">
+    expires_after="M83">
   <owner>pshmakov@chromium.org</owner>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -139474,7 +139518,7 @@
 </histogram>
 
 <histogram name="TrustedWebActivity.TimeInVerifiedOrigin.V2" units="ms"
-    expires_after="M78">
+    expires_after="M83">
   <owner>pshmakov@chromium.org</owner>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -139500,7 +139544,7 @@
 </histogram>
 
 <histogram name="TrustedWebActivity.TimeOutOfVerifiedOrigin.V2" units="ms"
-    expires_after="M78">
+    expires_after="M83">
   <owner>pshmakov@chromium.org</owner>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -139511,7 +139555,7 @@
 </histogram>
 
 <histogram name="TrustedWebActivity.TranslucencyRemovalFailed" enum="Boolean"
-    expires_after="M76">
+    expires_after="M83">
   <owner>pshmakov@chromium.org</owner>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -153176,6 +153220,16 @@
   <affected-histogram name="Apps.ContextMenuUserJourneyTime"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="ArcPerformanceAppCategories" separator=".">
+  <suffix name="CasualGame" label="Casual game."/>
+  <suffix name="OnlineGame" label="Online game."/>
+  <suffix name="ShooterGame" label="Shooter game."/>
+  <suffix name="Video" label="Video playback app."/>
+  <affected-histogram name="Arc.Runtime.Performance.CommitDeviation"/>
+  <affected-histogram name="Arc.Runtime.Performance.FPS"/>
+  <affected-histogram name="Arc.Runtime.Performance.RenderQuality"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="ArcUserTypes" separator=".">
   <suffix name="ActiveDirectory" label="User with active directory account"/>
   <suffix name="Child" label="User with child accounts."/>
@@ -154435,6 +154489,19 @@
   <affected-histogram name="CloudPrint.UrlFetcherUploadSize"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="CompositingLCDTextDisabledCountSuffixes"
+    separator=".">
+  <suffix name="10To30"
+      label="Percentage when number of picture layers with text is 10 thru 30"/>
+  <suffix name="LessThan10"
+      label="Percentage when number of picture layers with text is 1 thru 9"/>
+  <suffix name="MoreThan30"
+      label="Percentage when number of picture layers with text is greater
+             than 30"/>
+  <affected-histogram
+      name="Compositing.Renderer.PercentPictureLayersWithTextButLCDTextDisabled"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="CompositorLatencyStages" separator=".">
   <suffix name="Activation" label="The duration of the activation stage."/>
   <suffix name="BeginImplFrameToSendBeginMainFrame"
diff --git a/tools/metrics/histograms/pretty_print.py b/tools/metrics/histograms/pretty_print.py
index a72d2c5..0ea2e84 100755
--- a/tools/metrics/histograms/pretty_print.py
+++ b/tools/metrics/histograms/pretty_print.py
@@ -30,6 +30,7 @@
   pass
 
 UNIT_REWRITES = {
+  'mcs': 'microseconds',
   'microsecond': 'microseconds',
   'us': 'microseconds',
   'millisecond': 'ms',
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index 0a271d5..7046e0d 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -50,87 +50,34 @@
     ui::ViewAndroid* view,
     viz::HostFrameSinkManager* host_frame_sink_manager,
     Client* client,
-    const viz::FrameSinkId& frame_sink_id,
-    bool enable_surface_synchronization)
+    const viz::FrameSinkId& frame_sink_id)
     : frame_sink_id_(frame_sink_id),
       view_(view),
       host_frame_sink_manager_(host_frame_sink_manager),
       client_(client),
-      begin_frame_source_(this),
-      enable_surface_synchronization_(enable_surface_synchronization),
-      enable_viz_(features::IsVizDisplayCompositorEnabled()),
       frame_evictor_(std::make_unique<viz::FrameEvictor>(this)) {
   DCHECK(view_);
   DCHECK(client_);
+  DCHECK(features::IsVizDisplayCompositorEnabled());
 
-  if (enable_surface_synchronization_) {
-    constexpr bool is_transparent = false;
-    content_layer_ = CreateSurfaceLayer(
-        viz::SurfaceId(), viz::SurfaceId(), gfx::Size(),
-        cc::DeadlinePolicy::UseDefaultDeadline(), is_transparent);
-    view_->GetLayer()->AddChild(content_layer_);
-  }
+  constexpr bool is_transparent = false;
+  content_layer_ = CreateSurfaceLayer(
+      viz::SurfaceId(), viz::SurfaceId(), gfx::Size(),
+      cc::DeadlinePolicy::UseDefaultDeadline(), is_transparent);
+  view_->GetLayer()->AddChild(content_layer_);
 
   host_frame_sink_manager_->RegisterFrameSinkId(
       frame_sink_id_, this, viz::ReportFirstSurfaceActivation::kNo);
   host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_,
                                                    "DelegatedFrameHostAndroid");
-  CreateCompositorFrameSinkSupport();
 }
 
 DelegatedFrameHostAndroid::~DelegatedFrameHostAndroid() {
   EvictDelegatedFrame();
   DetachFromCompositor();
-  support_.reset();
   host_frame_sink_manager_->InvalidateFrameSinkId(frame_sink_id_);
 }
 
-void DelegatedFrameHostAndroid::SubmitCompositorFrame(
-    const viz::LocalSurfaceId& local_surface_id,
-    viz::CompositorFrame frame,
-    base::Optional<viz::HitTestRegionList> hit_test_region_list) {
-  DCHECK(!enable_viz_);
-
-  bool id_changed = (local_surface_id_ != local_surface_id);
-  viz::RenderPass* root_pass = frame.render_pass_list.back().get();
-  const bool has_transparent_background = root_pass->has_transparent_background;
-  const gfx::Size surface_size_in_pixels = frame.size_in_pixels();
-  // Reset |content_layer_| only if surface-sync is not used. When surface-sync
-  // is turned on, |content_layer_| is updated with the appropriate states (see
-  // in EmbedSurface()) instead of being recreated.
-  if (!enable_surface_synchronization_ && content_layer_ && id_changed) {
-    EvictDelegatedFrame();
-  }
-  support_->SubmitCompositorFrame(local_surface_id, std::move(frame),
-                                  std::move(hit_test_region_list));
-  if (enable_surface_synchronization_) {
-    DCHECK(content_layer_);
-    return;
-  }
-
-  if (!content_layer_) {
-    local_surface_id_ = local_surface_id;
-    surface_size_in_pixels_ = surface_size_in_pixels;
-    has_transparent_background_ = has_transparent_background;
-    content_layer_ = CreateSurfaceLayer(
-        viz::SurfaceId(frame_sink_id_, local_surface_id_),
-        viz::SurfaceId(frame_sink_id_, local_surface_id_),
-        surface_size_in_pixels_, cc::DeadlinePolicy::UseDefaultDeadline(),
-        !has_transparent_background_);
-    view_->GetLayer()->AddChild(content_layer_);
-  }
-  content_layer_->SetContentsOpaque(!has_transparent_background_);
-
-  if (id_changed)
-    frame_evictor_->OnNewSurfaceEmbedded();
-}
-
-void DelegatedFrameHostAndroid::DidNotProduceFrame(
-    const viz::BeginFrameAck& ack) {
-  DCHECK(!enable_viz_);
-  support_->DidNotProduceFrame(ack);
-}
-
 const viz::FrameSinkId& DelegatedFrameHostAndroid::GetFrameSinkId() const {
   return frame_sink_id_;
 }
@@ -183,10 +130,6 @@
   if (content_layer_) {
     content_layer_->SetSurfaceId(viz::SurfaceId(),
                                  cc::DeadlinePolicy::UseDefaultDeadline());
-    if (!enable_surface_synchronization_) {
-      content_layer_->RemoveFromParent();
-      content_layer_ = nullptr;
-    }
   }
   if (!HasSavedFrame() || frame_evictor_->visible())
     return;
@@ -225,7 +168,6 @@
 
 void DelegatedFrameHostAndroid::CompositorFrameSinkChanged() {
   EvictDelegatedFrame();
-  CreateCompositorFrameSinkSupport();
   if (registered_parent_compositor_)
     AttachToCompositor(registered_parent_compositor_);
 }
@@ -235,18 +177,12 @@
   if (registered_parent_compositor_)
     DetachFromCompositor();
   compositor->AddChildFrameSink(frame_sink_id_);
-  if (!enable_viz_)
-    client_->SetBeginFrameSource(&begin_frame_source_);
   registered_parent_compositor_ = compositor;
 }
 
 void DelegatedFrameHostAndroid::DetachFromCompositor() {
   if (!registered_parent_compositor_)
     return;
-  if (!enable_viz_) {
-    client_->SetBeginFrameSource(nullptr);
-    support_->SetNeedsBeginFrame(false);
-  }
   registered_parent_compositor_->RemoveChildFrameSink(frame_sink_id_);
   registered_parent_compositor_ = nullptr;
 }
@@ -268,9 +204,6 @@
     const gfx::Size& new_size_in_pixels) {
   frame_evictor_->SetVisible(true);
 
-  if (!enable_surface_synchronization_)
-    return;
-
   EmbedSurface(
       new_local_surface_id, new_size_in_pixels,
       cc::DeadlinePolicy::UseSpecifiedDeadline(FirstFrameTimeoutFrames()));
@@ -280,9 +213,6 @@
     const viz::LocalSurfaceId& new_local_surface_id,
     const gfx::Size& new_size_in_pixels,
     cc::DeadlinePolicy deadline_policy) {
-  if (!enable_surface_synchronization_)
-    return;
-
   // We should never attempt to embed an invalid surface. Catch this here to
   // track down the root cause. Otherwise we will have vague crashes later on
   // at serialization time.
@@ -333,36 +263,6 @@
   }
 }
 
-void DelegatedFrameHostAndroid::DidReceiveCompositorFrameAck(
-    const std::vector<viz::ReturnedResource>& resources) {
-  client_->DidReceiveCompositorFrameAck(resources);
-}
-
-void DelegatedFrameHostAndroid::OnBeginFrame(
-    const viz::BeginFrameArgs& args,
-    const viz::FrameTimingDetailsMap& timing_details) {
-  client_->DidPresentCompositorFrames(timing_details);
-  if (enable_viz_) {
-    NOTREACHED();
-    return;
-  }
-  begin_frame_source_.OnBeginFrame(args);
-}
-
-void DelegatedFrameHostAndroid::ReclaimResources(
-    const std::vector<viz::ReturnedResource>& resources) {
-  client_->ReclaimResources(resources);
-}
-
-void DelegatedFrameHostAndroid::OnBeginFramePausedChanged(bool paused) {
-  begin_frame_source_.OnSetBeginFrameSourcePaused(paused);
-}
-
-void DelegatedFrameHostAndroid::OnNeedsBeginFrames(bool needs_begin_frames) {
-  DCHECK(!enable_viz_);
-  support_->SetNeedsBeginFrame(needs_begin_frames);
-}
-
 void DelegatedFrameHostAndroid::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
   NOTREACHED();
@@ -372,17 +272,6 @@
   client_->OnFrameTokenChanged(frame_token);
 }
 
-void DelegatedFrameHostAndroid::CreateCompositorFrameSinkSupport() {
-  if (enable_viz_)
-    return;
-
-  constexpr bool is_root = false;
-  constexpr bool needs_sync_points = true;
-  support_.reset();
-  support_ = host_frame_sink_manager_->CreateCompositorFrameSinkSupport(
-      this, frame_sink_id_, is_root, needs_sync_points);
-}
-
 viz::SurfaceId DelegatedFrameHostAndroid::SurfaceId() const {
   return viz::SurfaceId(frame_sink_id_, local_surface_id_);
 }
@@ -401,45 +290,21 @@
   if (HasFallbackSurface() || !other->HasPrimarySurface())
     return;
 
-  if (enable_surface_synchronization_) {
-    const viz::SurfaceId& other_primary = other->content_layer_->surface_id();
-    const base::Optional<viz::SurfaceId>& other_fallback =
-        other->content_layer_->oldest_acceptable_fallback();
-    viz::SurfaceId desired_fallback;
-    if (!other->HasFallbackSurface() ||
-        !other_primary.IsSameOrNewerThan(*other_fallback)) {
-      desired_fallback = other_primary.ToSmallestId();
-    } else {
-      desired_fallback = *other_fallback;
-    }
-    content_layer_->SetOldestAcceptableFallback(
-        other->content_layer_->surface_id().ToSmallestId());
-    return;
-  }
-
-  if (content_layer_) {
-    content_layer_->SetSurfaceId(
-        *other->content_layer_->oldest_acceptable_fallback(),
-        cc::DeadlinePolicy::UseDefaultDeadline());
+  const viz::SurfaceId& other_primary = other->content_layer_->surface_id();
+  const base::Optional<viz::SurfaceId>& other_fallback =
+      other->content_layer_->oldest_acceptable_fallback();
+  viz::SurfaceId desired_fallback;
+  if (!other->HasFallbackSurface() ||
+      !other_primary.IsSameOrNewerThan(*other_fallback)) {
+    desired_fallback = other_primary.ToSmallestId();
   } else {
-    const auto& surface_id = other->SurfaceId();
-    local_surface_id_ = surface_id.local_surface_id();
-    surface_size_in_pixels_ = other->surface_size_in_pixels_;
-    has_transparent_background_ = other->has_transparent_background_;
-    content_layer_ = CreateSurfaceLayer(
-        surface_id, surface_id, other->content_layer_->bounds(),
-        cc::DeadlinePolicy::UseDefaultDeadline(),
-        other->content_layer_->contents_opaque());
-    view_->GetLayer()->AddChild(content_layer_);
+    desired_fallback = *other_fallback;
   }
   content_layer_->SetOldestAcceptableFallback(
-      *other->content_layer_->oldest_acceptable_fallback());
+      other->content_layer_->surface_id().ToSmallestId());
 }
 
 void DelegatedFrameHostAndroid::DidNavigate() {
-  if (!enable_surface_synchronization_)
-    return;
-
   first_local_surface_id_after_navigation_ = local_surface_id_;
 }
 
diff --git a/ui/android/delegated_frame_host_android.h b/ui/android/delegated_frame_host_android.h
index cea3be3..f9afdb75 100644
--- a/ui/android/delegated_frame_host_android.h
+++ b/ui/android/delegated_frame_host_android.h
@@ -9,13 +9,12 @@
 #include "base/memory/ref_counted.h"
 #include "cc/layers/deadline_policy.h"
 #include "components/viz/client/frame_evictor.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "components/viz/common/frame_timing_details_map.h"
 #include "components/viz/common/resources/returned_resource.h"
 #include "components/viz/common/surfaces/surface_info.h"
 #include "components/viz/host/host_frame_sink_client.h"
-#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
-#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
 #include "ui/android/ui_android_export.h"
 
 namespace cc {
@@ -24,7 +23,6 @@
 }  // namespace cc
 
 namespace viz {
-class CompositorFrame;
 class HostFrameSinkManager;
 }  // namespace viz
 
@@ -33,22 +31,12 @@
 class WindowAndroidCompositor;
 
 class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
-    : public viz::mojom::CompositorFrameSinkClient,
-      public viz::ExternalBeginFrameSourceClient,
-      public viz::HostFrameSinkClient,
+    : public viz::HostFrameSinkClient,
       public viz::FrameEvictorClient {
  public:
   class Client {
    public:
     virtual ~Client() {}
-    virtual void SetBeginFrameSource(
-        viz::BeginFrameSource* begin_frame_source) = 0;
-    virtual void DidPresentCompositorFrames(
-        const viz::FrameTimingDetailsMap& timing_details) = 0;
-    virtual void DidReceiveCompositorFrameAck(
-        const std::vector<viz::ReturnedResource>& resources) = 0;
-    virtual void ReclaimResources(
-        const std::vector<viz::ReturnedResource>& resources) = 0;
     virtual void OnFrameTokenChanged(uint32_t frame_token) = 0;
     virtual void WasEvicted() = 0;
   };
@@ -56,8 +44,7 @@
   DelegatedFrameHostAndroid(ViewAndroid* view,
                             viz::HostFrameSinkManager* host_frame_sink_manager,
                             Client* client,
-                            const viz::FrameSinkId& frame_sink_id,
-                            bool enable_surface_synchronization);
+                            const viz::FrameSinkId& frame_sink_id);
 
   ~DelegatedFrameHostAndroid() override;
 
@@ -81,12 +68,6 @@
     return ResizeTimeout() / viz::BeginFrameArgs::DefaultInterval();
   }
 
-  void SubmitCompositorFrame(
-      const viz::LocalSurfaceId& local_surface_id,
-      viz::CompositorFrame frame,
-      base::Optional<viz::HitTestRegionList> hit_test_region_list);
-  void DidNotProduceFrame(const viz::BeginFrameAck& ack);
-
   // FrameEvictorClient implementation.
   void EvictDelegatedFrame() override;
 
@@ -138,24 +119,10 @@
   void DidNavigate();
 
  private:
-  // viz::mojom::CompositorFrameSinkClient implementation.
-  void DidReceiveCompositorFrameAck(
-      const std::vector<viz::ReturnedResource>& resources) override;
-  void OnBeginFrame(const viz::BeginFrameArgs& args,
-                    const viz::FrameTimingDetailsMap& timing_details) override;
-  void ReclaimResources(
-      const std::vector<viz::ReturnedResource>& resources) override;
-  void OnBeginFramePausedChanged(bool paused) override;
-
-  // viz::ExternalBeginFrameSourceClient implementation.
-  void OnNeedsBeginFrames(bool needs_begin_frames) override;
-
   // viz::HostFrameSinkClient implementation.
   void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
   void OnFrameTokenChanged(uint32_t frame_token) override;
 
-  void CreateCompositorFrameSinkSupport();
-
   void ProcessCopyOutputRequest(
       std::unique_ptr<viz::CopyOutputRequest> request);
 
@@ -167,16 +134,8 @@
   WindowAndroidCompositor* registered_parent_compositor_ = nullptr;
   Client* client_;
 
-  std::unique_ptr<viz::CompositorFrameSinkSupport> support_;
-  viz::ExternalBeginFrameSource begin_frame_source_;
-
-  bool has_transparent_background_ = false;
-
   scoped_refptr<cc::SurfaceLayer> content_layer_;
 
-  const bool enable_surface_synchronization_;
-  const bool enable_viz_;
-
   // Whether we've received a frame from the renderer since navigating.
   // Only used when surface synchronization is on.
   viz::LocalSurfaceId first_local_surface_id_after_navigation_;
diff --git a/ui/file_manager/file_manager/foreground/elements/files_format_dialog.html b/ui/file_manager/file_manager/foreground/elements/files_format_dialog.html
index 0c45c30..bbd3967 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_format_dialog.html
+++ b/ui/file_manager/file_manager/foreground/elements/files_format_dialog.html
@@ -11,20 +11,17 @@
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 
 <dom-module id="files-format-dialog">
   <template>
-    <style include="md-select">
+    <style include="cr-shared-style md-select">
       .md-select {
         width: 100%;
       }
 
-      .label {
-        @apply --cr-form-field-label;
-      }
-
       [slot='body'] > div {
         margin-bottom: var(--cr-form-field-bottom-spacing);
       }
@@ -57,9 +54,9 @@
             id="label" value="{{label_}}" auto-validate="true">
         </cr-input>
         <div id="disk-format">
-          <div id="format-type-label" class="label">
+          <label id="format-type-label" class="cr-form-field-label">
             [[i18n('FORMAT_DIALOG_FORMAT_LABEL')]]
-          </div>
+          </label>
           <select class="md-select" aria-labelledby="format-type-label"
               value="{{formatType_::change}}">
             <option value="vfat">FAT32</option>
diff --git a/ui/gl/init/create_gr_gl_interface.cc b/ui/gl/init/create_gr_gl_interface.cc
index 4f2a7ac..a099355e 100644
--- a/ui/gl/init/create_gr_gl_interface.cc
+++ b/ui/gl/init/create_gr_gl_interface.cc
@@ -73,10 +73,14 @@
   };
 }
 
-const GLubyte* GetStringHook(const char* version_string, GLenum name) {
+const GLubyte* GetStringHook(const char* gl_version_string,
+                             const char* glsl_version_string,
+                             GLenum name) {
   switch (name) {
     case GL_VERSION:
-      return reinterpret_cast<const GLubyte*>(version_string);
+      return reinterpret_cast<const GLubyte*>(gl_version_string);
+    case GL_SHADING_LANGUAGE_VERSION:
+      return reinterpret_cast<const GLubyte*>(glsl_version_string);
     default:
       return glGetString(name);
   }
@@ -125,14 +129,17 @@
                                       version_info.IsAtLeastGL(4, 2) ||
                                       version_info.IsAtLeastGLES(3, 1);
   if (apply_version_override) {
-    const char* fake_version = nullptr;
+    const char* fake_gl_version = nullptr;
+    const char* fake_glsl_version = nullptr;
     if (use_version_es2) {
-      fake_version = "OpenGL ES 2.0";
+      fake_gl_version = "OpenGL ES 2.0";
+      fake_glsl_version = "OpenGL ES GLSL ES 1.00";
     } else {
-      fake_version = version_info.is_es ? "OpenGL ES 3.0" : "4.1";
+      fake_gl_version = version_info.is_es ? "OpenGL ES 3.0" : "4.1";
+      fake_glsl_version = version_info.is_es ? "OpenGL ES GLSL ES 3.00" : "4.10";
     }
-    get_string = [fake_version](GLenum name) {
-      return GetStringHook(fake_version, name);
+    get_string = [fake_gl_version, fake_glsl_version](GLenum name) {
+      return GetStringHook(fake_gl_version, fake_glsl_version, name);
     };
   } else {
     get_string = bind(&gl::GLApi::glGetStringFn, api);
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config_select.html b/ui/webui/resources/cr_components/chromeos/network/network_config_select.html
index 3600cff..261b505a 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config_select.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config_select.html
@@ -4,22 +4,19 @@
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_tooltip_icon.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
 <link rel="import" href="network_config_element_behavior.html">
 <link rel="import" href="network_shared_css.html">
 
 <dom-module id="network-config-select">
   <template>
-    <style include="network-shared md-select">
+    <style include="cr-shared-style network-shared md-select">
       .md-select {
         color: var(--cr-primary-text-color);
         width: 100%;
       }
 
-      #label {
-        @apply --cr-form-field-label;
-      }
-
       #outer {
         align-items: stretch;
         display: flex;
@@ -41,7 +38,7 @@
     </style>
 
     <div id="outer">
-      <div id="label">[[label]]</div>
+      <div id="label" class="cr-form-field-label">[[label]]</div>
       <div id="inner">
         <select class="md-select"
             disabled="[[getDisabled_(disabled, property)]]"
diff --git a/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.html b/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.html
index e298093..4c5405df 100644
--- a/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.html
+++ b/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.html
@@ -6,6 +6,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
@@ -15,7 +16,7 @@
 
 <dom-module id="add-smb-share-dialog">
   <template>
-    <style include="md-select">
+    <style include="cr-shared-style md-select">
       #dialog [slot=body] {
         height: 440px;
       }
@@ -24,10 +25,6 @@
         width: 100%;
       }
 
-      .label {
-        @apply --cr-form-field-label;
-      }
-
       cr-searchable-drop-down {
         display: block;
       }
@@ -86,9 +83,9 @@
             value="{{mountName_}}" maxlength="64">
         </cr-input>
         <div id="authentication-method" hidden="[[!isActiveDirectory_]]">
-          <div id="authentication-label" class="label">
+          <label id="authentication-label" class="cr-form-field-label">
             [[i18n('smbShareAuthenticationMethod')]]
-          </div>
+          </label>
           <select class="md-select" aria-labelledby="authentication-label"
               value="{{authenticationMethod_::change}}">
             <option value="kerberos">
diff --git a/ui/webui/resources/cr_elements/action_link_css.html b/ui/webui/resources/cr_elements/action_link_css.html
index 06448aac..b9400c4 100644
--- a/ui/webui/resources/cr_elements/action_link_css.html
+++ b/ui/webui/resources/cr_elements/action_link_css.html
@@ -6,7 +6,7 @@
   <template>
     <style>
       [is='action-link'] {
-        @apply --cr-actionable;
+        cursor: pointer;
         display: inline-block;
         text-decoration: none;
       }
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
index cd1a0eb..2693b84 100644
--- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
+++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
@@ -49,7 +49,7 @@
       }
 
       :host ::slotted(.dropdown-item:not([disabled])) {
-        @apply --cr-actionable;
+        cursor: pointer;
       }
 
       :host ::slotted(.dropdown-item:focus) {
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input.html b/ui/webui/resources/cr_elements/cr_input/cr_input.html
index bb39b3e..3ff417ad 100644
--- a/ui/webui/resources/cr_elements/cr_input/cr_input.html
+++ b/ui/webui/resources/cr_elements/cr_input/cr_input.html
@@ -3,12 +3,13 @@
 <link rel="import" href="../../html/assert.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
 <link rel="import" href="../hidden_style_css.html">
+<link rel="import" href="../shared_style_css.html">
 <link rel="import" href="../shared_vars_css.html">
 <link rel="import" href="cr_input_style_css.html">
 
 <dom-module id="cr-input">
   <template>
-    <style include="cr-hidden-style cr-input-style">
+    <style include="cr-hidden-style cr-input-style cr-shared-style">
       /*
         A 'suffix' element will be outside the underlined space, while a
         'prefix' element will be inside the underlined space by default.
@@ -103,7 +104,10 @@
         -webkit-appearance: none;
       }
     </style>
-    <div id="label" hidden="[[!label]]" aria-hidden="true">[[label]]</div>
+    <div id="label" class="cr-form-field-label" hidden="[[!label]]"
+        aria-hidden="true">
+      [[label]]
+    </div>
     <div id="row-container" part="row-container">
       <div id="input-container">
         <div id="inner-input-container">
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html b/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
index 0e8d7c9..f357cb0f 100644
--- a/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
+++ b/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
@@ -27,11 +27,6 @@
         }
       }
 
-      /* Label styling below. */
-      #label {
-        @apply --cr-form-field-label;
-      }
-
       :host([focused_]:not([readonly]):not([invalid])) #label {
         color: var(--cr-input-focus-color);
       }
diff --git a/ui/webui/resources/cr_elements/shared_style_css.html b/ui/webui/resources/cr_elements/shared_style_css.html
index 8e9a990..1784513 100644
--- a/ui/webui/resources/cr_elements/shared_style_css.html
+++ b/ui/webui/resources/cr_elements/shared_style_css.html
@@ -22,7 +22,7 @@
       }
 
       [actionable] {
-        @apply --cr-actionable;
+        cursor: pointer;
       }
 
       .subpage-arrow,
@@ -72,7 +72,7 @@
         @apply --cr-selectable-focus;
       }
       [selectable]:not(cr-radio-group) > * {
-        @apply --cr-actionable;
+        cursor: pointer;
       }
 
       .cr-container-shadow {
@@ -100,6 +100,16 @@
       #cr-container-shadow-bottom.has-shadow {
         opacity: var(--cr-container-shadow-max-opacity);
       }
+
+      .cr-form-field-label {
+        color: var(--cr-form-field-label-color);
+        display: block;
+        font-size: var(--cr-form-field-label-font-size);
+        font-weight: 500;
+        letter-spacing: .4px;
+        line-height: var(--cr-form-field-label-line-height);
+        margin-bottom: 8px;
+      }
     </style>
   </template>
 </dom-module>
diff --git a/ui/webui/resources/cr_elements/shared_vars_css.html b/ui/webui/resources/cr_elements/shared_vars_css.html
index 3b87af2..901b087 100644
--- a/ui/webui/resources/cr_elements/shared_vars_css.html
+++ b/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -112,10 +112,6 @@
    * set for both light and dark modes and use a single variable below. */
 
   html {
-    --cr-actionable: {
-      cursor: pointer;
-    }
-
     --cr-button-edge-spacing: 12px;
     --cr-button-height: 32px;
 
@@ -249,15 +245,6 @@
     --cr-form-field-label-font-size: .625rem;
     --cr-form-field-label-height: 1em;
     --cr-form-field-label-line-height: 1em;
-    --cr-form-field-label: {
-      color: var(--cr-form-field-label-color);
-      display: block;
-      font-size: var(--cr-form-field-label-font-size);
-      font-weight: 500;
-      letter-spacing: .4px;
-      line-height: var(--cr-form-field-label-line-height);
-      margin-bottom: 8px;
-    }
   }
 </style>
 </custom-style>
diff --git a/ui/webui/resources/js/util.js b/ui/webui/resources/js/util.js
index 1711039..fd2bb59 100644
--- a/ui/webui/resources/js/util.js
+++ b/ui/webui/resources/js/util.js
@@ -144,17 +144,6 @@
   return last ? node : null;
 }
 
-function swapDomNodes(a, b) {
-  const afterA = a.nextSibling;
-  if (afterA == b) {
-    swapDomNodes(b, a);
-    return;
-  }
-  const aParent = a.parentNode;
-  b.parentNode.replaceChild(a, b);
-  aParent.insertBefore(b, afterA);
-}
-
 /**
  * Disables text selection and dragging, with optional whitelist callbacks.
  * @param {function(Event):boolean=} opt_allowSelectStart Unless this function