diff --git a/BUILD.gn b/BUILD.gn
index a0f5f57e..6c85e57f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -104,7 +104,6 @@
       "//chrome/test:sync_integration_tests",
       "//chrome/test/chromedriver:chromedriver_unittests",
       "//components/subresource_filter/tools:subresource_filter_tools",
-      "//components/sync/tools:sync_client",
       "//components/sync/tools:sync_listen_notifications",
       "//components/zucchini:zucchini",
       "//components/zucchini:zucchini_unittests",
@@ -144,6 +143,8 @@
       "//third_party/SPIRV-Tools/src:SPIRV-Tools",
       "//third_party/SPIRV-Tools/src/test/fuzzers",
       "//third_party/cacheinvalidation:cacheinvalidation_unittests",
+      "//third_party/dawn:dawn_end2end_tests",
+      "//third_party/dawn:dawn_unittests",
       "//third_party/pdfium/samples:pdfium_test",
       "//third_party/webrtc/rtc_tools:frame_analyzer",
       "//tools/perf/clear_system_cache",
diff --git a/DEPS b/DEPS
index 2add96c..89bf9a9 100644
--- a/DEPS
+++ b/DEPS
@@ -111,11 +111,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': '69a72945dcdd4c96094a23be950b7f552d97fb89',
+  'skia_revision': '73329c8df9d59691a8be642f7b07a93ae92b9962',
   # 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': '600998aa2d5e92302fc8974ee10f7b53c80d23b8',
+  'v8_revision': '0ccf17e9a990361055b824b75cde457bf5e490f0',
   # 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.
@@ -171,7 +171,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '9662809abb166ca5fdf84fa640e4eccdb65b53d3',
+  'catapult_revision': 'e3f4b1f5ee138aee4cb0bbaf95dd949811b58bd7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -219,7 +219,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '6647884a130d026294bad97d2575ff21560d74ec',
+  'spv_tools_revision': 'fb996dce752507132c40c255898154cce6c072c5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -235,7 +235,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '16092faa163b20f6b85ff407b1ec1d61cb9d7f2a',
+  'dawn_revision': '61791eae36b8155219f6217b64b28eb4f54e3396',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -665,7 +665,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'c270bd3daa83f820140656925dbe507f3af988f3',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '46e2b4be31c717db64047079cce5c52cbda197ff',
       'condition': 'checkout_linux',
   },
 
@@ -737,7 +737,7 @@
   },
 
   'src/third_party/glslang/src':
-    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'a08f465d5398518e9a6aeebd4775604a4c10e381',
+    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '0ac199df32687fe17b38cd2d0da64c3742e24fef',
 
   'src/third_party/google_toolbox_for_mac/src': {
       'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'),
@@ -1004,7 +1004,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '76eeb8565846fe0d2abc19e25c6c8f525114ff83',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'fa909263570ecd945717205a6b16ad6b47d23923',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1060,7 +1060,7 @@
   },
 
   'src/third_party/re2/src':
-    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '22caec62055a7707cf5801bebb6028d06220f2b6',
+    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '46155299edb9b30a44cfad233592a24c7d6a905d',
 
   'src/third_party/r8': {
       'packages': [
@@ -1156,7 +1156,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '0d55c887e92b645f6effe753528323ab2ffd94c2',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'b00b28ee5067a45bb5804047bf78c0515c680e1e',
+    Var('webrtc_git') + '/src.git' + '@' + 'ed45c57d9818fe8bcb91f15cfa53568ee35f0bf3',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1187,7 +1187,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d54a42bd9174cf56cdc3ee2531bac8cb1425d0b9',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2e039e9c4069f47e5a5c84d519323fa69660ba7c',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 42b1a41..ae51b1c9 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -371,7 +371,6 @@
 
 bool AwContentBrowserClient::AllowWorkerIndexedDB(
     const GURL& url,
-    const base::string16& name,
     content::ResourceContext* context,
     const std::vector<content::GlobalFrameRoutingId>& render_frames) {
   return true;
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index bb9aacc..3205b38 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -93,7 +93,6 @@
       base::Callback<void(bool)> callback) override;
   bool AllowWorkerIndexedDB(
       const GURL& url,
-      const base::string16& name,
       content::ResourceContext* context,
       const std::vector<content::GlobalFrameRoutingId>& render_frames) override;
   content::QuotaPermissionContext* CreateQuotaPermissionContext() override;
diff --git a/android_webview/browser/aw_settings.cc b/android_webview/browser/aw_settings.cc
index fdd0bce..e9aa707 100644
--- a/android_webview/browser/aw_settings.cc
+++ b/android_webview/browser/aw_settings.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "android_webview/browser/aw_browser_context.h"
 #include "android_webview/browser/aw_content_browser_client.h"
 #include "android_webview/browser/aw_contents.h"
 #include "android_webview/browser/renderer_host/aw_render_view_host_ext.h"
@@ -18,10 +19,12 @@
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/web_preferences.h"
 #include "jni/AwSettings_jni.h"
+#include "services/network/public/cpp/features.h"
 #include "ui/gfx/font_render_params.h"
 
 using base::android::ConvertJavaStringToUTF16;
@@ -243,6 +246,18 @@
   content::RenderViewHost* host = web_contents()->GetRenderViewHost();
   if (update_prefs && host)
     host->SyncRendererPrefs();
+
+  if (update_prefs &&
+      base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    // make sure to update accept languages when the network service is enabled
+    AwBrowserContext* aw_browser_context =
+        AwBrowserContext::FromWebContents(web_contents());
+    // AndroidWebview does not use per-site storage partitions.
+    content::StoragePartition* storage_partition =
+        content::BrowserContext::GetDefaultStoragePartition(aw_browser_context);
+    storage_partition->GetNetworkContext()->SetAcceptLanguage(
+        prefs->accept_languages);
+  }
 }
 
 void AwSettings::UpdateOffscreenPreRasterLocked(
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index d4c6ba97..12a46f20 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -554,6 +554,9 @@
       <message name="IDS_ASH_CHILD_USER_IS_MANAGED_BY_TWO_PARENTS_NOTICE" desc="Text for notifications showing that this user is managed by two parents' accounts.">
         Account managed by <ph name="FIRST_PARENT_EMAIL">$1<ex>first@example.com</ex></ph> and <ph name="SECOND_PARENT_EMAIL">$2<ex>second@example.com</ex></ph>
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_FAMILY_LINK_LABEL" desc="Tooltip of the status area icon indicating that the session is managed by Family Link.">
+         This account is managed by Family Link
+      </message>
 
       <message name="IDS_ASH_STATUS_TRAY_PREVIOUS_MENU" desc="The accessible text for header entries for detailed versions of status tray items.">
         Previous menu
diff --git a/ash/system/power/power_status.cc b/ash/system/power/power_status.cc
index 0926b16..f29c2ab 100644
--- a/ash/system/power/power_status.cc
+++ b/ash/system/power/power_status.cc
@@ -451,6 +451,23 @@
   return std::make_pair(percentage, status);
 }
 
+base::string16 PowerStatus::GetInlinedStatusString() const {
+  base::string16 percentage_text;
+  base::string16 status_text;
+  std::tie(percentage_text, status_text) = GetStatusStrings();
+
+  if (!percentage_text.empty() && !status_text.empty()) {
+    return percentage_text +
+           l10n_util::GetStringUTF16(
+               IDS_ASH_STATUS_TRAY_BATTERY_STATUS_SEPARATOR) +
+           status_text;
+  } else if (!percentage_text.empty()) {
+    return percentage_text;
+  } else {
+    return status_text;
+  }
+}
+
 PowerStatus::PowerStatus() {
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
       this);
diff --git a/ash/system/power/power_status.h b/ash/system/power/power_status.h
index acf01e0c..47dfe30 100644
--- a/ash/system/power/power_status.h
+++ b/ash/system/power/power_status.h
@@ -197,6 +197,10 @@
   // empty string.
   std::pair<base::string16, base::string16> GetStatusStrings() const;
 
+  // Returns status strings that are generated by current PowerStatus.
+  // For example, "53% - 5:00 left".
+  base::string16 GetInlinedStatusString() const;
+
   // Updates |proto_|. Does not notify observers.
   void SetProtoForTesting(const power_manager::PowerSupplyProperties& proto);
 
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc
index dbf9c31f..22dc7cb 100644
--- a/ash/system/power/tray_power.cc
+++ b/ash/system/power/tray_power.cc
@@ -57,6 +57,18 @@
   node_data->role = ax::mojom::Role::kButton;
 }
 
+views::View* PowerTrayView::GetTooltipHandlerForPoint(const gfx::Point& point) {
+  return GetLocalBounds().Contains(point) ? this : nullptr;
+}
+
+bool PowerTrayView::GetTooltipText(const gfx::Point& p,
+                                   base::string16* tooltip) const {
+  if (tooltip_.empty())
+    return false;
+  *tooltip = tooltip_;
+  return true;
+}
+
 void PowerTrayView::OnPowerStatusChanged() {
   UpdateStatus();
 }
@@ -69,6 +81,10 @@
   UpdateImage();
   SetVisible(PowerStatus::Get()->IsBatteryPresent());
   accessible_name_ = PowerStatus::Get()->GetAccessibleNameString(true);
+  tooltip_ = PowerStatus::Get()->GetInlinedStatusString();
+  // Currently ChromeVox only reads the inner view when touching the icon.
+  // As a result this node's accessible node data will not be read.
+  image_view()->SetAccessibleName(accessible_name_);
 }
 
 void PowerTrayView::UpdateImage() {
diff --git a/ash/system/power/tray_power.h b/ash/system/power/tray_power.h
index 8c8d70d9..1a62590 100644
--- a/ash/system/power/tray_power.h
+++ b/ash/system/power/tray_power.h
@@ -27,6 +27,9 @@
 
   // views::View:
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
+  bool GetTooltipText(const gfx::Point& p,
+                      base::string16* tooltip) const override;
 
   // PowerStatus::Observer:
   void OnPowerStatusChanged() override;
@@ -39,6 +42,7 @@
   void UpdateImage();
 
   base::string16 accessible_name_;
+  base::string16 tooltip_;
   base::Optional<PowerStatus::BatteryImageInfo> info_;
   session_manager::SessionState icon_session_state_color_ =
       session_manager::SessionState::UNKNOWN;
diff --git a/ash/system/unified/managed_device_view.cc b/ash/system/unified/managed_device_view.cc
index 241bc16..4fdf44c1 100644
--- a/ash/system/unified/managed_device_view.cc
+++ b/ash/system/unified/managed_device_view.cc
@@ -7,10 +7,15 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/system/enterprise/enterprise_domain_observer.h"
 #include "ash/system/model/enterprise_domain_model.h"
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_utils.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chromeos/strings/grit/chromeos_strings.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/image_view.h"
 
@@ -18,25 +23,50 @@
 
 ManagedDeviceView::ManagedDeviceView(Shelf* shelf) : TrayItemView(shelf) {
   Shell::Get()->session_controller()->AddObserver(this);
+  Shell::Get()->system_tray_model()->enterprise_domain()->AddObserver(this);
   CreateImageView();
-  OnLoginStatusChanged(Shell::Get()->session_controller()->login_status());
+  Update();
 }
 
 ManagedDeviceView::~ManagedDeviceView() {
+  Shell::Get()->system_tray_model()->enterprise_domain()->RemoveObserver(this);
   Shell::Get()->session_controller()->RemoveObserver(this);
 }
 
 void ManagedDeviceView::OnLoginStatusChanged(LoginStatus status) {
+  Update();
+}
+
+void ManagedDeviceView::OnEnterpriseDomainChanged() {
+  Update();
+}
+
+void ManagedDeviceView::Update() {
   SessionController* session = Shell::Get()->session_controller();
   if (session->IsUserPublicAccount()) {
     image_view()->SetImage(gfx::CreateVectorIcon(
         kSystemTrayManagedIcon,
         TrayIconColor(Shell::Get()->session_controller()->GetSessionState())));
+    std::string enterprise_domain_name = Shell::Get()
+                                             ->system_tray_model()
+                                             ->enterprise_domain()
+                                             ->enterprise_display_domain();
     SetVisible(true);
+    if (!enterprise_domain_name.empty()) {
+      image_view()->set_tooltip_text(l10n_util::GetStringFUTF16(
+          IDS_ASH_ENTERPRISE_DEVICE_MANAGED_BY,
+          base::UTF8ToUTF16(enterprise_domain_name)));
+    } else {
+      image_view()->set_tooltip_text(base::string16());
+      LOG(WARNING)
+          << "Public account user, but device not enterprise-enrolled.";
+    }
   } else if (session->IsUserChild()) {
     image_view()->SetImage(gfx::CreateVectorIcon(
         kSystemTrayFamilyLinkIcon,
         TrayIconColor(Shell::Get()->session_controller()->GetSessionState())));
+    image_view()->set_tooltip_text(
+        l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_FAMILY_LINK_LABEL));
     SetVisible(true);
   } else {
     SetVisible(false);
diff --git a/ash/system/unified/managed_device_view.h b/ash/system/unified/managed_device_view.h
index 89f27dad..eb82471d 100644
--- a/ash/system/unified/managed_device_view.h
+++ b/ash/system/unified/managed_device_view.h
@@ -6,6 +6,7 @@
 #define ASH_SYSTEM_UNIFIED_MANAGED_DEVICE_VIEW_H_
 
 #include "ash/session/session_observer.h"
+#include "ash/system/enterprise/enterprise_domain_observer.h"
 #include "ash/system/tray/tray_item_view.h"
 #include "base/macros.h"
 
@@ -15,7 +16,8 @@
 // an organization admin. Observes login status in order to show/hide the
 // icon reflecting the latest status.
 class ManagedDeviceView : public TrayItemView,
-                          public SessionObserver {
+                          public SessionObserver,
+                          public EnterpriseDomainObserver {
  public:
   explicit ManagedDeviceView(Shelf* shelf);
   ~ManagedDeviceView() override;
@@ -23,7 +25,11 @@
   // SessionObserver:
   void OnLoginStatusChanged(LoginStatus status) override;
 
+  // EnterpriseDomainObserver:
+  void OnEnterpriseDomainChanged() override;
+
  private:
+  void Update();
 
   DISALLOW_COPY_AND_ASSIGN(ManagedDeviceView);
 };
diff --git a/ash/wm/client_controlled_state.cc b/ash/wm/client_controlled_state.cc
index fceceff3..d681cd8 100644
--- a/ash/wm/client_controlled_state.cc
+++ b/ash/wm/client_controlled_state.cc
@@ -260,8 +260,6 @@
         window_state->window());
   }
 
-  window_state->UpdatePipState();
-
   return true;
 }
 
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc
index 69094d0..c4cbb6f7 100644
--- a/ash/wm/default_state.cc
+++ b/ash/wm/default_state.cc
@@ -460,8 +460,6 @@
     Shell::Get()->screen_pinning_controller()->SetPinnedWindow(
         window_state->window());
   }
-
-  window_state->UpdatePipState();
 }
 
 void DefaultState::ReenterToCurrentState(
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc
index 98c24877..24ada41 100644
--- a/ash/wm/overview/overview_utils.cc
+++ b/ash/wm/overview/overview_utils.cc
@@ -13,6 +13,7 @@
 #include "ash/shell.h"
 #include "ash/wm/overview/cleanup_animation_observer.h"
 #include "ash/wm/overview/scoped_overview_animation_settings.h"
+#include "ash/wm/overview/start_animation_observer.h"
 #include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/window_state.h"
@@ -139,8 +140,14 @@
   ScopedOverviewAnimationSettings scoped_overview_animation_settings(
       animation_type, window);
   window->layer()->SetOpacity(1.0f);
-  if (slide)
+  if (slide) {
     window->SetTransform(original_transform);
+
+    auto start_observer = std::make_unique<StartAnimationObserver>();
+    scoped_overview_animation_settings.AddObserver(start_observer.get());
+    Shell::Get()->window_selector_controller()->AddStartAnimationObserver(
+        std::move(start_observer));
+  }
 }
 
 void FadeOutWidgetAndMaybeSlideOnExit(std::unique_ptr<views::Widget> widget,
diff --git a/ash/wm/overview/window_grid.cc b/ash/wm/overview/window_grid.cc
index cda09cc..2496dd3 100644
--- a/ash/wm/overview/window_grid.cc
+++ b/ash/wm/overview/window_grid.cc
@@ -1104,7 +1104,6 @@
   aura::Window* parent_window = widget_window->parent();
   const gfx::Rect bounds = ash::screen_util::SnapBoundsToDisplayEdge(
       parent_window->bounds(), parent_window);
-  parent_window->SetBounds(bounds);
   widget_window->SetBounds(bounds);
   widget_window->SetName("OverviewModeShield");
 
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index 8201488..9a6f250 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -50,6 +50,7 @@
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/widget/widget_delegate.h"
 #include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/core/window_util.h"
 #include "ui/wm/public/activation_client.h"
@@ -104,6 +105,27 @@
   const aura::Window* root_window;
 };
 
+// A WidgetDelegate to specify the initialy focused view.
+class TextFilterWidgetDelegate : public views::WidgetDelegate {
+ public:
+  TextFilterWidgetDelegate(views::Widget* widget, views::View* initial_focus)
+      : widget_(widget), initial_focus_(initial_focus) {}
+  ~TextFilterWidgetDelegate() override = default;
+
+  // WidgetDelegate:
+  void DeleteDelegate() override { delete this; }
+  views::Widget* GetWidget() override { return widget_; }
+  const views::Widget* GetWidget() const override { return widget_; }
+  bool ShouldAdvanceFocusToTopLevelWidget() const override { return true; }
+  views::View* GetInitiallyFocusedView() override { return initial_focus_; }
+
+ private:
+  views::Widget* widget_;
+  views::View* initial_focus_;
+
+  DISALLOW_COPY_AND_ASSIGN(TextFilterWidgetDelegate);
+};
+
 // Triggers a shelf visibility update on all root window controllers.
 void UpdateShelfVisibility() {
   for (aura::Window* root : Shell::GetAllRootWindows())
@@ -202,6 +224,9 @@
   params.name = "OverviewModeTextFilter";
   *text_filter_bottom = params.bounds.bottom() + kTextFieldBottomMargin;
   params.parent = root_window->GetChildById(kShellWindowId_StatusContainer);
+
+  views::Textfield* textfield = new views::Textfield();
+  params.delegate = new TextFilterWidgetDelegate(widget, textfield);
   widget->Init(params);
 
   // Use |container| to specify the padding surrounding the text and to give
@@ -221,7 +246,6 @@
                   vertical_padding, kTextFilterCornerRadius),
       kTextFilterHorizontalPadding));
 
-  views::Textfield* textfield = new views::Textfield();
   textfield->set_controller(controller);
   textfield->SetBorder(views::NullBorder());
   textfield->SetBackgroundColor(kTextFilterBackgroundColor);
@@ -245,8 +269,6 @@
   aura::Window* text_filter_widget_window = widget->GetNativeWindow();
   text_filter_widget_window->layer()->SetOpacity(0);
   text_filter_widget_window->SetTransform(transform);
-  widget->Show();
-  textfield->RequestFocus();
 
   return widget;
 }
@@ -747,6 +769,14 @@
   }
 }
 
+void WindowSelector::OnStartingAnimationComplete(bool canceled) {
+  if (!canceled) {
+    UpdateMaskAndShadow(!canceled);
+    if (text_filter_widget_)
+      text_filter_widget_->Show();
+  }
+}
+
 void WindowSelector::OnDisplayRemoved(const display::Display& display) {
   // TODO(flackr): Keep window selection active on remaining displays.
   CancelSelection();
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index 9c3b7af..0b10878 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -217,6 +217,9 @@
   // Shows or hides all the window selector items' mask and shadow.
   void UpdateMaskAndShadow(bool show);
 
+  // Called when the overview mode starting animation completes.
+  void OnStartingAnimationComplete(bool canceled);
+
   WindowSelectorDelegate* delegate() { return delegate_; }
 
   SplitViewDragIndicators* split_view_drag_indicators() {
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
index 8125ca6..7e5b245 100644
--- a/ash/wm/overview/window_selector_controller.cc
+++ b/ash/wm/overview/window_selector_controller.cc
@@ -298,6 +298,11 @@
       return true;
     }
 
+    // Suspend occlusion tracker until the enter animation is complete.
+    occlusion_tracker_pauser_ =
+        std::make_unique<aura::WindowOcclusionTracker::ScopedPause>(
+            Shell::Get()->aura_env());
+
     window_selector_->set_enter_exit_overview_type(new_type);
     if (type == WindowSelector::EnterExitOverviewType::kWindowsMinimized ||
         type == WindowSelector::EnterExitOverviewType::kSwipeFromShelf) {
@@ -325,23 +330,39 @@
     // Clear any animations that may be running from last overview end.
     for (const auto& animation : delayed_animations_)
       animation->Shutdown();
-    if (!delayed_animations_.empty()) {
-      Shell::Get()->NotifyOverviewModeStartingAnimationComplete(
-          /*canceled=*/true);
-    }
+    if (!delayed_animations_.empty())
+      OnStartingAnimationComplete(/*canceled=*/true);
     delayed_animations_.clear();
 
+    // Suspend occlusion tracker until the exit animation is complete.
+    occlusion_tracker_pauser_ =
+        std::make_unique<aura::WindowOcclusionTracker::ScopedPause>(
+            Shell::Get()->aura_env());
+
     window_selector_ = std::make_unique<WindowSelector>(this);
     window_selector_->set_enter_exit_overview_type(new_type);
     Shell::Get()->NotifyOverviewModeStarting();
     window_selector_->Init(windows, hide_windows);
     if (IsBlurAllowed())
       overview_blur_controller_->Blur();
+    if (start_animations_.empty())
+      OnStartingAnimationComplete(/*canceled=*/false);
     OnSelectionStarted();
   }
   return true;
 }
 
+void WindowSelectorController::OnStartingAnimationComplete(bool canceled) {
+  Shell::Get()->NotifyOverviewModeStartingAnimationComplete(canceled);
+  window_selector_->OnStartingAnimationComplete(canceled);
+  occlusion_tracker_pauser_.reset();
+}
+
+void WindowSelectorController::OnEndingAnimationComplete(bool canceled) {
+  Shell::Get()->NotifyOverviewModeEndingAnimationComplete(canceled);
+  occlusion_tracker_pauser_.reset();
+}
+
 bool WindowSelectorController::IsSelecting() const {
   return window_selector_ != nullptr;
 }
@@ -480,15 +501,14 @@
   if (is_shutting_down_)
     return;
 
-  if (!start_animations_.empty()) {
-    Shell::Get()->NotifyOverviewModeEndingAnimationComplete(
-        /*canceled=*/true);
-  }
+  if (!start_animations_.empty())
+    OnEndingAnimationComplete(/*canceled=*/true);
   start_animations_.clear();
+
+  window_selector_->UpdateMaskAndShadow(/*show=*/false);
   is_shutting_down_ = true;
   Shell::Get()->NotifyOverviewModeEnding();
   auto* window_selector = window_selector_.release();
-  window_selector->UpdateMaskAndShadow(/*show=*/false);
   window_selector->Shutdown();
   // There may be no delayed animations in tests, so unblur right away.
   if (delayed_animations_.empty() && IsBlurAllowed())
@@ -519,7 +539,8 @@
   if (!window_selector_ && !previous_empty && delayed_animations_.empty()) {
     if (IsBlurAllowed())
       overview_blur_controller_->Unblur();
-    Shell::Get()->NotifyOverviewModeEndingAnimationComplete(/*canceled=*/false);
+
+    OnEndingAnimationComplete(/*canceled=*/false);
   }
 }
 
@@ -534,11 +555,8 @@
   const bool previous_empty = start_animations_.empty();
   base::EraseIf(start_animations_, base::MatchesUniquePtr(animation_observer));
 
-  if (!previous_empty && start_animations_.empty()) {
-    Shell::Get()->NotifyOverviewModeStartingAnimationComplete(
-        /*canceled=*/false);
-    window_selector_->UpdateMaskAndShadow(/*show=*/true);
-  }
+  if (!previous_empty && start_animations_.empty())
+    OnStartingAnimationComplete(/*canceled=*/false);
 }
 
 // static
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/window_selector_controller.h
index 72491bd..2792dde 100644
--- a/ash/wm/overview/window_selector_controller.h
+++ b/ash/wm/overview/window_selector_controller.h
@@ -13,6 +13,7 @@
 #include "ash/wm/overview/window_selector_delegate.h"
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "ui/aura/window_occlusion_tracker.h"
 
 namespace ash {
 class WindowSelector;
@@ -97,6 +98,9 @@
   // Dispatched when window selection begins.
   void OnSelectionStarted();
 
+  void OnStartingAnimationComplete(bool canceled);
+  void OnEndingAnimationComplete(bool canceled);
+
   // Collection of DelayedAnimationObserver objects that own widgets that may be
   // still animating after overview mode ends. If shell needs to shut down while
   // those animations are in progress, the animations are shut down and the
@@ -106,6 +110,9 @@
   // notify shell that the starting animations have been completed.
   std::vector<std::unique_ptr<DelayedAnimationObserver>> start_animations_;
 
+  std::unique_ptr<aura::WindowOcclusionTracker::ScopedPause>
+      occlusion_tracker_pauser_;
+
   std::unique_ptr<WindowSelector> window_selector_;
   base::Time last_selection_time_;
 
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index df0a86c..e930e5a 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -514,7 +514,7 @@
       ignore_property_change_(false),
       current_state_(new DefaultState(ToWindowStateType(GetShowState()))) {
   window_->AddObserver(this);
-  UpdatePipState();
+  UpdatePipState(/*was_pip=*/false);
 }
 
 bool WindowState::GetAlwaysOnTop() const {
@@ -587,6 +587,7 @@
     mojom::WindowStateType old_window_state_type) {
   for (auto& observer : observer_list_)
     observer.OnPreWindowStateTypeChange(this, old_window_state_type);
+  UpdatePipState(old_window_state_type == mojom::WindowStateType::PIP);
 }
 
 void WindowState::NotifyPostStateTypeChange(
@@ -689,10 +690,14 @@
   }
 }
 
-void WindowState::UpdatePipState() {
-  ::wm::SetWindowVisibilityAnimationType(
-      window(), IsPip() ? WINDOW_VISIBILITY_ANIMATION_TYPE_SLIDE_OUT
-                        : ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
+void WindowState::UpdatePipState(bool was_pip) {
+  if (IsPip()) {
+    ::wm::SetWindowVisibilityAnimationType(
+        window(), WINDOW_VISIBILITY_ANIMATION_TYPE_SLIDE_OUT);
+  } else if (was_pip) {
+    ::wm::SetWindowVisibilityAnimationType(
+        window(), ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
+  }
 }
 
 void WindowState::UpdatePipBounds() {
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index 5e95404..f64e64b 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -415,7 +415,7 @@
 
   // Update PIP related state, such as next window animation type, upon
   // state change.
-  void UpdatePipState();
+  void UpdatePipState(bool was_pip);
 
   // Update the PIP bounds if necessary. This may need to happen when the
   // display work area changes, or if system ui regions like the virtual
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc
index a4b4166..3835b58 100644
--- a/ash/wm/workspace/backdrop_controller.cc
+++ b/ash/wm/workspace/backdrop_controller.cc
@@ -15,9 +15,11 @@
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
+#include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/wallpaper/wallpaper_controller.h"
 #include "ash/wm/overview/window_selector_controller.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/workspace/backdrop_delegate.h"
 #include "base/auto_reset.h"
@@ -68,7 +70,7 @@
 }  // namespace
 
 BackdropController::BackdropController(aura::Window* container)
-    : container_(container), in_restacking_(false) {
+    : container_(container) {
   DCHECK(container_);
   Shell::Get()->AddShellObserver(this);
   Shell::Get()->accessibility_controller()->AddObserver(this);
@@ -101,6 +103,10 @@
   UpdateBackdrop();
 }
 
+void BackdropController::OnDisplayMetricsChanged() {
+  UpdateBackdrop();
+}
+
 void BackdropController::OnPostWindowStateTypeChange(
     wm::WindowState* window_state,
     mojom::WindowStateType old_type) {
@@ -117,8 +123,8 @@
   // No need to continue update for recursive calls or in overview mode.
   WindowSelectorController* window_selector_controller =
       Shell::Get()->window_selector_controller();
-  if (in_restacking_ || (window_selector_controller &&
-                         window_selector_controller->IsSelecting())) {
+  if (pause_update_ || (window_selector_controller &&
+                        window_selector_controller->IsSelecting())) {
     return;
   }
 
@@ -129,12 +135,14 @@
     return;
   }
   // We are changing the order of windows which will cause recursion.
-  base::AutoReset<bool> lock(&in_restacking_, true);
+  base::AutoReset<bool> lock(&pause_update_, true);
   EnsureBackdropWidget();
   UpdateAccessibilityMode();
 
-  if (window == backdrop_window_ && backdrop_->IsVisible())
+  if (window == backdrop_window_ && backdrop_->IsVisible()) {
+    Layout();
     return;
+  }
   if (window->GetRootWindow() != backdrop_window_->GetRootWindow())
     return;
 
@@ -148,11 +156,20 @@
 }
 
 void BackdropController::OnOverviewModeStarting() {
+  if (backdrop_window_)
+    backdrop_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
   Hide();
 }
 
-void BackdropController::OnOverviewModeEnded() {
+void BackdropController::OnOverviewModeEnding() {
+  pause_update_ = true;
+}
+
+void BackdropController::OnOverviewModeEndingAnimationComplete(bool canceled) {
+  pause_update_ = false;
   UpdateBackdrop();
+  if (backdrop_window_)
+    backdrop_window_->ClearProperty(aura::client::kAnimationsDisabledKey);
 }
 
 void BackdropController::OnAppListVisibilityChanged(bool shown,
@@ -209,6 +226,8 @@
   ::wm::SetWindowVisibilityAnimationType(
       backdrop_window_, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
   backdrop_window_->layer()->SetColor(SK_ColorBLACK);
+
+  wm::GetWindowState(backdrop_window_)->set_allow_set_bounds_direct(true);
 }
 
 void BackdropController::UpdateAccessibilityMode() {
@@ -265,11 +284,7 @@
 }
 
 void BackdropController::Show() {
-  // Makes sure that the backdrop has the correct bounds if it should not be
-  // fullscreen size.
-  backdrop_->SetFullscreen(BackdropShouldFullscreen());
-  if (!BackdropShouldFullscreen())
-    backdrop_->SetBounds(GetBackdropBounds());
+  Layout();
   backdrop_->Show();
 }
 
@@ -315,4 +330,21 @@
       snapped_window, snap_position);
 }
 
+void BackdropController::Layout() {
+  // Makes sure that the backdrop has the correct bounds if it should not be
+  // fullscreen size.
+  backdrop_->SetFullscreen(BackdropShouldFullscreen());
+  if (backdrop_->IsFullscreen()) {
+    // TODO(oshima): The size of solid color layer can be smaller than texture's
+    // layer with fractional scale (crbug.com/9000220). Use adjusted bounds so
+    // that it can cover texture layer. Fix the bug and remove this.
+    auto* window = backdrop_window_;
+    gfx::Rect bounds = screen_util::GetDisplayBoundsInParent(window);
+    backdrop_window_->SetBounds(
+        screen_util::SnapBoundsToDisplayEdge(bounds, window));
+  } else {
+    backdrop_->SetBounds(GetBackdropBounds());
+  }
+}
+
 }  // namespace ash
diff --git a/ash/wm/workspace/backdrop_controller.h b/ash/wm/workspace/backdrop_controller.h
index e7562c3..150f709 100644
--- a/ash/wm/workspace/backdrop_controller.h
+++ b/ash/wm/workspace/backdrop_controller.h
@@ -57,6 +57,7 @@
   void OnWindowStackingChanged(aura::Window* window);
   void OnPostWindowStateTypeChange(wm::WindowState* window_state,
                                    mojom::WindowStateType old_type);
+  void OnDisplayMetricsChanged();
 
   void SetBackdropDelegate(std::unique_ptr<BackdropDelegate> delegate);
 
@@ -68,7 +69,8 @@
 
   // ShellObserver:
   void OnOverviewModeStarting() override;
-  void OnOverviewModeEnded() override;
+  void OnOverviewModeEnding() override;
+  void OnOverviewModeEndingAnimationComplete(bool canceled) override;
   void OnAppListVisibilityChanged(bool shown,
                                   aura::Window* root_window) override;
   void OnSplitViewModeStarting() override;
@@ -92,6 +94,8 @@
 
   void UpdateAccessibilityMode();
 
+  void Layout();
+
   // Returns the current visible top level window in the container.
   aura::Window* GetTopmostWindowWithBackdrop();
 
@@ -130,8 +134,10 @@
   std::unique_ptr<ui::EventHandler> backdrop_event_handler_;
   ui::EventHandler* original_event_handler_ = nullptr;
 
-  // If true, the |RestackOrHideWindow| might recurse.
-  bool in_restacking_ = false;
+  // If true, skip updating background. Used to avoid recursive update
+  // when updating the window stack, or delay hiding the backdrop
+  // in overview mode.
+  bool pause_update_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(BackdropController);
 };
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index e5e0739..744d2da 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -387,6 +387,7 @@
     const wm::WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED);
     AdjustAllWindowsBoundsForWorkAreaChange(&event);
   }
+  backdrop_controller_->OnDisplayMetricsChanged();
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/base/strings/string_split_unittest.cc b/base/strings/string_split_unittest.cc
index 022ec17..089398a 100644
--- a/base/strings/string_split_unittest.cc
+++ b/base/strings/string_split_unittest.cc
@@ -91,6 +91,18 @@
   EXPECT_TRUE(kv_pairs.empty());
 }
 
+TEST_F(SplitStringIntoKeyValuePairsTest, MissingKeyValueDelimiter) {
+  EXPECT_FALSE(SplitStringIntoKeyValuePairs("key1,key2:value2",
+                                            ':',  // Key-value delimiter
+                                            ',',  // Key-value pair delimiter
+                                            &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_TRUE(kv_pairs[0].first.empty());
+  EXPECT_TRUE(kv_pairs[0].second.empty());
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
 TEST_F(SplitStringIntoKeyValuePairsTest, EmptyKeyWithKeyValueDelimiter) {
   EXPECT_TRUE(SplitStringIntoKeyValuePairs(":value1,key2:value2",
                                            ':',  // Key-value delimiter
diff --git a/base/task/sequence_manager/sequence_manager_perftest.cc b/base/task/sequence_manager/sequence_manager_perftest.cc
index 66056a9..a83e659 100644
--- a/base/task/sequence_manager/sequence_manager_perftest.cc
+++ b/base/task/sequence_manager/sequence_manager_perftest.cc
@@ -73,192 +73,233 @@
   kUseSingleThreadInWorkerPool = 9,
 };
 
-class SequenceManagerPerfTest : public testing::TestWithParam<PerfTestType> {
+// Customization point for SequenceManagerPerfTest which allows us to test
+// various implementations.
+class PerfTestDelegate {
  public:
-  SequenceManagerPerfTest()
-      : num_queues_(0),
-        max_tasks_in_flight_(0),
-        num_tasks_in_flight_(0),
-        num_tasks_to_post_(0),
-        num_tasks_to_run_(0),
-        done_cond_(&done_lock_) {}
+  virtual ~PerfTestDelegate() = default;
 
-  void SetUp() override {
-    if (ThreadTicks::IsSupported())
-      ThreadTicks::WaitUntilInitialized();
+  virtual const char* GetName() const = 0;
 
-    delayed_task_closure_ = BindRepeating(
-        &SequenceManagerPerfTest::TestDelayedTask, Unretained(this));
+  virtual bool VirtualTimeIsSupported() const = 0;
 
-    immediate_task_closure_ = BindRepeating(
-        &SequenceManagerPerfTest::TestImmediateTask, Unretained(this));
+  virtual bool MultipleQueuesSupported() const = 0;
 
-    switch (GetParam()) {
-      case PerfTestType::kUseSequenceManagerWithMessageLoop:
-        CreateSequenceManagerWithMessageLoop(std::make_unique<MessageLoop>());
-        break;
-      case PerfTestType::kUseSequenceManagerWithMessagePump:
-        CreateSequenceManagerWithMessagePump(
-            std::make_unique<MessagePumpDefault>());
-        break;
-      case PerfTestType::kUseSequenceManagerWithUIMessageLoop:
-        CreateSequenceManagerWithMessageLoop(
-            std::make_unique<MessageLoopForUI>());
-        break;
-      case PerfTestType::kUseSequenceManagerWithUIMessagePump:
-#if !defined(OS_IOS) && !defined(OS_MACOSX)
-        CreateSequenceManagerWithMessagePump(
-            std::make_unique<MessagePumpForUI>());
-#endif
-        break;
-      case PerfTestType::kUseSequenceManagerWithIOMessageLoop:
-        CreateSequenceManagerWithMessageLoop(
-            std::make_unique<MessageLoopForIO>());
-        break;
-      case PerfTestType::kUseSequenceManagerWithIOMessagePump:
-        CreateSequenceManagerWithMessagePump(
-            std::make_unique<MessagePumpForIO>());
-        break;
-      case PerfTestType::kUseMessageLoop:
-        CreateMessageLoop(std::make_unique<MessageLoop>());
-        break;
-      case PerfTestType::kUseUIMessageLoop:
-        CreateMessageLoop(std::make_unique<MessageLoopForUI>());
-        break;
-      case PerfTestType::kUseIOMessageLoop:
-        CreateMessageLoop(std::make_unique<MessageLoopForIO>());
-        break;
-      case PerfTestType::kUseSingleThreadInWorkerPool:
-        CreateTaskScheduler();
-        break;
-    }
+  virtual scoped_refptr<TaskRunner> CreateTaskRunner() = 0;
 
-    if (manager_) {
-      time_domain_ = std::make_unique<PerfTestTimeDomain>();
-      manager_->RegisterTimeDomain(time_domain_.get());
-    }
+  virtual void WaitUntilDone() = 0;
+
+  virtual void SignalDone() = 0;
+};
+
+class BaseSequenceManagerPerfTestDelegate : public PerfTestDelegate {
+ public:
+  BaseSequenceManagerPerfTestDelegate() {}
+
+  ~BaseSequenceManagerPerfTestDelegate() override = default;
+
+  bool VirtualTimeIsSupported() const override { return true; }
+
+  bool MultipleQueuesSupported() const override { return true; }
+
+  scoped_refptr<TaskRunner> CreateTaskRunner() override {
+    scoped_refptr<TestTaskQueue> task_queue =
+        manager_->CreateTaskQueue<TestTaskQueue>(
+            TaskQueue::Spec("test").SetTimeDomain(time_domain_.get()));
+    owned_task_queues_.push_back(task_queue);
+    return task_queue->task_runner();
   }
 
-  void CreateSequenceManagerWithMessageLoop(
-      std::unique_ptr<MessageLoop> message_loop) {
-    message_loop_ = std::move(message_loop);
-    manager_ = SequenceManagerForTest::Create(message_loop_.get(),
-                                              message_loop_->task_runner(),
-                                              DefaultTickClock::GetInstance());
+  void WaitUntilDone() override {
+    run_loop_.reset(new RunLoop());
+    run_loop_->Run();
   }
 
-  void CreateSequenceManagerWithMessagePump(
-      std::unique_ptr<MessagePump> message_pump) {
-    manager_ = SequenceManagerForTest::Create(
+  void SignalDone() override { run_loop_->Quit(); }
+
+  SequenceManager* GetManager() const { return manager_.get(); }
+
+  void SetSequenceManager(std::unique_ptr<SequenceManager> manager) {
+    manager_ = std::move(manager);
+    time_domain_ = std::make_unique<PerfTestTimeDomain>();
+    manager_->RegisterTimeDomain(time_domain_.get());
+  }
+
+  void ShutDown() {
+    owned_task_queues_.clear();
+    manager_->UnregisterTimeDomain(time_domain_.get());
+    manager_.reset();
+  }
+
+ private:
+  std::unique_ptr<SequenceManager> manager_;
+  std::unique_ptr<TimeDomain> time_domain_;
+  std::unique_ptr<RunLoop> run_loop_;
+  std::vector<scoped_refptr<TestTaskQueue>> owned_task_queues_;
+};
+
+template <class MessageLoopType>
+class SequenceManagerWithMessageLoopPerfTestDelegate
+    : public BaseSequenceManagerPerfTestDelegate {
+ public:
+  explicit SequenceManagerWithMessageLoopPerfTestDelegate(const char* name)
+      : name_(name), message_loop_(new MessageLoopType()) {
+    SetSequenceManager(SequenceManagerForTest::Create(
+        message_loop_.get(), message_loop_->task_runner(),
+        DefaultTickClock::GetInstance()));
+  }
+
+  ~SequenceManagerWithMessageLoopPerfTestDelegate() override { ShutDown(); }
+
+  const char* GetName() const override { return name_; }
+
+ private:
+  const char* const name_;
+  std::unique_ptr<MessageLoop> message_loop_;
+};
+
+class SequenceManagerWithMessagePumpPerfTestDelegate
+    : public BaseSequenceManagerPerfTestDelegate {
+ public:
+  SequenceManagerWithMessagePumpPerfTestDelegate(const char* name,
+                                                 MessageLoop::Type type)
+      : name_(name) {
+    SetSequenceManager(SequenceManagerForTest::Create(
         std::make_unique<internal::ThreadControllerWithMessagePumpImpl>(
-            std::move(message_pump), DefaultTickClock::GetInstance()));
+            MessageLoop ::CreateMessagePumpForType(type),
+            DefaultTickClock::GetInstance())));
+
     // ThreadControllerWithMessagePumpImpl doesn't provide a default task
     // runner.
     scoped_refptr<TaskQueue> default_task_queue =
-        manager_->CreateTaskQueue<TestTaskQueue>(TaskQueue::Spec("default"));
-    manager_->SetDefaultTaskRunner(default_task_queue->task_runner());
+        GetManager()->template CreateTaskQueue<TestTaskQueue>(
+            TaskQueue::Spec("default"));
+    GetManager()->SetDefaultTaskRunner(default_task_queue->task_runner());
   }
 
-  void CreateMessageLoop(std::unique_ptr<MessageLoop> message_loop) {
-    message_loop_ = std::move(message_loop);
+  ~SequenceManagerWithMessagePumpPerfTestDelegate() override { ShutDown(); }
+
+  const char* GetName() const override { return name_; }
+
+ private:
+  const char* const name_;
+};
+
+class MessageLoopPerfTestDelegate : public PerfTestDelegate {
+ public:
+  MessageLoopPerfTestDelegate(const char* name,
+                              std::unique_ptr<MessageLoop> message_loop)
+      : name_(name), message_loop_(std::move(message_loop)) {}
+
+  ~MessageLoopPerfTestDelegate() override = default;
+
+  const char* GetName() const override { return name_; }
+
+  bool VirtualTimeIsSupported() const override { return false; }
+
+  bool MultipleQueuesSupported() const override { return false; }
+
+  scoped_refptr<TaskRunner> CreateTaskRunner() override {
+    return message_loop_->task_runner();
   }
 
-  void CreateTaskScheduler() {
+  void WaitUntilDone() override {
+    run_loop_.reset(new RunLoop());
+    run_loop_->Run();
+  }
+
+  void SignalDone() override { run_loop_->Quit(); }
+
+ private:
+  const char* const name_;
+  std::unique_ptr<MessageLoop> message_loop_;
+  std::unique_ptr<RunLoop> run_loop_;
+};
+
+class SingleThreadInWorkerPoolPerfTestDelegate : public PerfTestDelegate {
+ public:
+  SingleThreadInWorkerPoolPerfTestDelegate() : done_cond_(&done_lock_) {
     TaskScheduler::SetInstance(
         std::make_unique<::base::internal::TaskSchedulerImpl>("Test"));
     TaskScheduler::GetInstance()->StartWithDefaultParams();
   }
 
-  void TearDown() override {
-    task_runners_.clear();
-    if (manager_) {
-      manager_->UnregisterTimeDomain(time_domain_.get());
-      manager_.reset();
-    }
-    if (GetParam() == PerfTestType::kUseSingleThreadInWorkerPool) {
-      TaskScheduler::GetInstance()->JoinForTesting();
-      TaskScheduler::SetInstance(nullptr);
-    }
+  ~SingleThreadInWorkerPoolPerfTestDelegate() override {
+    TaskScheduler::GetInstance()->JoinForTesting();
+    TaskScheduler::SetInstance(nullptr);
   }
 
-  scoped_refptr<TaskRunner> CreateTaskRunner() {
-    switch (GetParam()) {
-      case PerfTestType::kUseSequenceManagerWithMessageLoop:
-      case PerfTestType::kUseSequenceManagerWithMessagePump:
-      case PerfTestType::kUseSequenceManagerWithUIMessageLoop:
-      case PerfTestType::kUseSequenceManagerWithUIMessagePump:
-      case PerfTestType::kUseSequenceManagerWithIOMessageLoop:
-      case PerfTestType::kUseSequenceManagerWithIOMessagePump: {
-        scoped_refptr<TestTaskQueue> task_queue =
-            manager_->CreateTaskQueue<TestTaskQueue>(
-                TaskQueue::Spec("test").SetTimeDomain(time_domain_.get()));
-        owning_task_queues_.push_back(task_queue);
-        return task_queue->task_runner();
-      }
-
-      case PerfTestType::kUseMessageLoop:
-      case PerfTestType::kUseUIMessageLoop:
-      case PerfTestType::kUseIOMessageLoop:
-        return message_loop_->task_runner();
-
-      case PerfTestType::kUseSingleThreadInWorkerPool:
-        return CreateSingleThreadTaskRunnerWithTraits(
-            {TaskPriority::USER_BLOCKING});
-    };
+  const char* GetName() const override {
+    return " single thread in WorkerPool ";
   }
 
-  void Initialize(size_t num_queues) {
-    owning_task_queues_.clear();
-    num_queues_ = num_queues;
-    for (size_t i = 0; i < num_queues; i++) {
-      task_runners_.push_back(CreateTaskRunner());
-    }
+  bool VirtualTimeIsSupported() const override { return false; }
+
+  bool MultipleQueuesSupported() const override { return false; }
+
+  scoped_refptr<TaskRunner> CreateTaskRunner() override {
+    return CreateSingleThreadTaskRunnerWithTraits(
+        {TaskPriority::USER_BLOCKING});
   }
 
-  void WaitUntilDone() {
-    switch (GetParam()) {
-      case PerfTestType::kUseSequenceManagerWithMessageLoop:
-      case PerfTestType::kUseSequenceManagerWithMessagePump:
-      case PerfTestType::kUseSequenceManagerWithUIMessageLoop:
-      case PerfTestType::kUseSequenceManagerWithUIMessagePump:
-      case PerfTestType::kUseSequenceManagerWithIOMessageLoop:
-      case PerfTestType::kUseSequenceManagerWithIOMessagePump:
-      case PerfTestType::kUseMessageLoop:
-      case PerfTestType::kUseUIMessageLoop:
-      case PerfTestType::kUseIOMessageLoop:
-        run_loop_.reset(new RunLoop());
-        run_loop_->Run();
-        break;
-      case PerfTestType::kUseSingleThreadInWorkerPool: {
-        AutoLock auto_lock(done_lock_);
-        done_cond_.Wait();
-        break;
-      }
-    }
+  void WaitUntilDone() override {
+    AutoLock auto_lock(done_lock_);
+    done_cond_.Wait();
   }
 
-  void SignalDone() {
-    switch (GetParam()) {
-      case PerfTestType::kUseSequenceManagerWithMessageLoop:
-      case PerfTestType::kUseSequenceManagerWithMessagePump:
-      case PerfTestType::kUseSequenceManagerWithUIMessageLoop:
-      case PerfTestType::kUseSequenceManagerWithUIMessagePump:
-      case PerfTestType::kUseSequenceManagerWithIOMessageLoop:
-      case PerfTestType::kUseSequenceManagerWithIOMessagePump:
-      case PerfTestType::kUseMessageLoop:
-      case PerfTestType::kUseUIMessageLoop:
-      case PerfTestType::kUseIOMessageLoop:
-        run_loop_->Quit();
-        break;
-      case PerfTestType::kUseSingleThreadInWorkerPool: {
-        AutoLock auto_lock(done_lock_);
-        done_cond_.Signal();
-        break;
-      }
-    }
+  void SignalDone() override {
+    AutoLock auto_lock(done_lock_);
+    done_cond_.Signal();
   }
 
-  void TestDelayedTask() {
+ private:
+  Lock done_lock_;
+  ConditionVariable done_cond_;
+};
+
+class TestCase {
+ public:
+  // |delegate| is assumed to outlive TestCase.
+  explicit TestCase(PerfTestDelegate* delegate) : delegate_(delegate) {}
+
+  virtual ~TestCase() = default;
+
+  virtual void Start() = 0;
+
+ protected:
+  PerfTestDelegate* const delegate_;  // NOT OWNED
+};
+
+class TaskSource {
+ public:
+  virtual ~TaskSource() = default;
+
+  virtual void Start() = 0;
+};
+
+class SameThreadTaskSource : public TaskSource {
+ public:
+  SameThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
+                       size_t num_tasks)
+      : num_queues_(task_runners.size()),
+        num_tasks_(num_tasks),
+        task_closure_(
+            BindRepeating(&SameThreadTaskSource::TestTask, Unretained(this))),
+        task_runners_(std::move(task_runners)) {}
+
+  void Start() override {
+    num_tasks_in_flight_ = 1;
+    num_tasks_to_post_ = num_tasks_;
+    num_tasks_to_run_ = num_tasks_;
+    TestTask();
+  }
+
+ protected:
+  virtual void PostTask(unsigned int queue) = 0;
+
+  virtual void SignalDone() = 0;
+
+  void TestTask() {
     if (--num_tasks_to_run_ == 0) {
       SignalDone();
       return;
@@ -282,130 +323,331 @@
       if (queue == num_queues_) {
         queue = 0;
       }
-      // Simulate a mix of short and longer delays.
+      PostTask(queue);
+      num_tasks_in_flight_++;
+      num_tasks_to_post_--;
+    }
+  }
+
+  const size_t num_queues_;
+  const size_t num_tasks_;
+  const RepeatingClosure task_closure_;
+  const std::vector<scoped_refptr<TaskRunner>> task_runners_;
+  const unsigned int max_tasks_in_flight_ = 200;
+  unsigned int num_tasks_in_flight_;
+  unsigned int num_tasks_to_post_;
+  unsigned int num_tasks_to_run_;
+};
+
+class CrossThreadTaskSource : public TaskSource {
+ public:
+  CrossThreadTaskSource(std::vector<scoped_refptr<TaskRunner>> task_runners,
+                        size_t num_tasks)
+      : num_queues_(task_runners.size()),
+        num_tasks_(num_tasks),
+        task_closure_(
+            BindRepeating(&CrossThreadTaskSource::TestTask, Unretained(this))),
+        task_runners_(std::move(task_runners)) {}
+
+  void Start() override {
+    num_tasks_in_flight_ = 0;
+    num_tasks_to_run_ = num_tasks_;
+
+    for (size_t i = 0; i < num_tasks_; i++) {
+      while (num_tasks_in_flight_.load(std::memory_order_acquire) >
+             max_tasks_in_flight_) {
+      }
+      // Choose a queue weighted towards queue 0.
+      unsigned int queue = i % (num_queues_ + 1);
+      if (queue == num_queues_) {
+        queue = 0;
+      }
+      PostTask(queue);
+      num_tasks_in_flight_++;
+    }
+  }
+
+ protected:
+  virtual void PostTask(unsigned int queue) = 0;
+
+  // Will be called on the main thread.
+  virtual void SignalDone() = 0;
+
+  void TestTask() {
+    if (num_tasks_to_run_.fetch_sub(1) == 1) {
+      SignalDone();
+      return;
+    }
+    num_tasks_in_flight_--;
+  }
+
+  const size_t num_queues_;
+  const size_t num_tasks_;
+  const RepeatingClosure task_closure_;
+  const std::vector<scoped_refptr<TaskRunner>> task_runners_;
+  const unsigned int max_tasks_in_flight_ = 200;
+  std::atomic<unsigned int> num_tasks_in_flight_;
+  std::atomic<unsigned int> num_tasks_to_run_;
+};
+
+class SingleThreadImmediateTestCase : public TestCase {
+ public:
+  SingleThreadImmediateTestCase(
+      PerfTestDelegate* delegate,
+      std::vector<scoped_refptr<TaskRunner>> task_runners,
+      size_t num_tasks)
+      : TestCase(delegate),
+        task_source_(std::make_unique<SingleThreadImmediateTaskSource>(
+            delegate,
+            std::move(task_runners),
+            num_tasks)) {}
+
+  void Start() override { task_source_->Start(); }
+
+ private:
+  class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
+   public:
+    SingleThreadImmediateTaskSource(
+        PerfTestDelegate* delegate,
+        std::vector<scoped_refptr<TaskRunner>> task_runners,
+        size_t num_tasks)
+        : SameThreadTaskSource(std::move(task_runners), num_tasks),
+          delegate_(delegate) {}
+
+    ~SingleThreadImmediateTaskSource() override = default;
+
+    void PostTask(unsigned int queue) override {
+      task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
+    }
+
+    void SignalDone() override { delegate_->SignalDone(); }
+
+    PerfTestDelegate* delegate_;  // NOT OWNED.
+  };
+
+  const std::unique_ptr<TaskSource> task_source_;
+};
+
+class SingleThreadDelayedTestCase : public TestCase {
+ public:
+  SingleThreadDelayedTestCase(
+      PerfTestDelegate* delegate,
+      std::vector<scoped_refptr<TaskRunner>> task_runners,
+      size_t num_tasks)
+      : TestCase(delegate),
+        task_source_(std::make_unique<SingleThreadDelayedTaskSource>(
+            delegate,
+            std::move(task_runners),
+            num_tasks)) {}
+
+  void Start() override { task_source_->Start(); }
+
+ private:
+  class SingleThreadDelayedTaskSource : public SameThreadTaskSource {
+   public:
+    explicit SingleThreadDelayedTaskSource(
+        PerfTestDelegate* delegate,
+        std::vector<scoped_refptr<TaskRunner>> task_runners,
+        size_t num_tasks)
+        : SameThreadTaskSource(std::move(task_runners), num_tasks),
+          delegate_(delegate) {}
+
+    ~SingleThreadDelayedTaskSource() override = default;
+
+    void PostTask(unsigned int queue) override {
       unsigned int delay =
           num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10);
-      task_runners_[queue]->PostDelayedTask(FROM_HERE, delayed_task_closure_,
+      task_runners_[queue]->PostDelayedTask(FROM_HERE, task_closure_,
                                             TimeDelta::FromMilliseconds(delay));
-      num_tasks_in_flight_++;
-      num_tasks_to_post_--;
+    }
+
+    void SignalDone() override { delegate_->SignalDone(); }
+
+    PerfTestDelegate* delegate_;  // NOT OWNED.
+  };
+
+  const std::unique_ptr<TaskSource> task_source_;
+};
+
+class TwoThreadTestCase : public TestCase {
+ public:
+  TwoThreadTestCase(PerfTestDelegate* delegate,
+                    std::vector<scoped_refptr<TaskRunner>> task_runners,
+                    size_t num_tasks)
+      : TestCase(delegate),
+        task_runners_(std::move(task_runners)),
+        num_tasks_(num_tasks),
+        auxiliary_thread_("auxillary thread") {
+    auxiliary_thread_.Start();
+  }
+
+  ~TwoThreadTestCase() override { auxiliary_thread_.Stop(); }
+
+ protected:
+  void Start() override {
+    done_count_ = 0;
+    same_thread_task_source_ =
+        std::make_unique<SingleThreadImmediateTaskSource>(this, task_runners_,
+                                                          num_tasks_ / 2);
+    cross_thread_task_scorce_ =
+        std::make_unique<CrossThreadImmediateTaskSource>(this, task_runners_,
+                                                         num_tasks_ / 2);
+
+    auxiliary_thread_.task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(&CrossThreadImmediateTaskSource::Start,
+                                  Unretained(cross_thread_task_scorce_.get())));
+    same_thread_task_source_->Start();
+  }
+
+  class SingleThreadImmediateTaskSource : public SameThreadTaskSource {
+   public:
+    SingleThreadImmediateTaskSource(
+        TwoThreadTestCase* two_thread_test_case,
+        std::vector<scoped_refptr<TaskRunner>> task_runners,
+        size_t num_tasks)
+        : SameThreadTaskSource(std::move(task_runners), num_tasks),
+          two_thread_test_case_(two_thread_test_case) {}
+
+    ~SingleThreadImmediateTaskSource() override = default;
+
+    void PostTask(unsigned int queue) override {
+      task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
+    }
+
+    // Will be called on the main thread.
+    void SignalDone() override { two_thread_test_case_->SignalDone(); }
+
+    TwoThreadTestCase* two_thread_test_case_;  // NOT OWNED.
+  };
+
+  class CrossThreadImmediateTaskSource : public CrossThreadTaskSource {
+   public:
+    CrossThreadImmediateTaskSource(
+        TwoThreadTestCase* two_thread_test_case,
+        std::vector<scoped_refptr<TaskRunner>> task_runners,
+        size_t num_tasks)
+        : CrossThreadTaskSource(std::move(task_runners), num_tasks),
+          two_thread_test_case_(two_thread_test_case) {}
+
+    ~CrossThreadImmediateTaskSource() override = default;
+
+    void PostTask(unsigned int queue) override {
+      task_runners_[queue]->PostTask(FROM_HERE, task_closure_);
+    }
+
+    // Will be called on the main thread.
+    void SignalDone() override { two_thread_test_case_->SignalDone(); }
+
+    TwoThreadTestCase* two_thread_test_case_;  // NOT OWNED.
+  };
+
+  void SignalDone() {
+    if (++done_count_ == 2)
+      delegate_->SignalDone();
+  }
+
+ private:
+  const std::vector<scoped_refptr<TaskRunner>> task_runners_;
+  const size_t num_tasks_;
+  Thread auxiliary_thread_;
+  std::unique_ptr<SingleThreadImmediateTaskSource> same_thread_task_source_;
+  std::unique_ptr<CrossThreadImmediateTaskSource> cross_thread_task_scorce_;
+  int done_count_ = 0;
+};
+
+class SequenceManagerPerfTest : public testing::TestWithParam<PerfTestType> {
+ public:
+  void SetUp() override {
+    if (ThreadTicks::IsSupported())
+      ThreadTicks::WaitUntilInitialized();
+
+    delegate_ = CreateDelegate();
+  }
+
+  void TearDown() override { delegate_.reset(); }
+
+  std::unique_ptr<PerfTestDelegate> CreateDelegate() {
+    switch (GetParam()) {
+      case PerfTestType::kUseSequenceManagerWithMessageLoop:
+        return std::make_unique<
+            SequenceManagerWithMessageLoopPerfTestDelegate<MessageLoop>>(
+            " SequenceManager with MessageLoop ");
+
+      case PerfTestType::kUseSequenceManagerWithMessagePump:
+        return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
+            " SequenceManager with MessagePumpDefault ",
+            MessageLoop::TYPE_DEFAULT);
+
+      case PerfTestType::kUseSequenceManagerWithUIMessageLoop:
+        return std::make_unique<
+            SequenceManagerWithMessageLoopPerfTestDelegate<MessageLoopForUI>>(
+            " SequenceManager with MessageLoopForUI ");
+
+      case PerfTestType::kUseSequenceManagerWithUIMessagePump:
+        return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
+            " SequenceManager with MessagePumpForUI ", MessageLoop::TYPE_UI);
+
+      case PerfTestType::kUseSequenceManagerWithIOMessageLoop:
+        return std::make_unique<
+            SequenceManagerWithMessageLoopPerfTestDelegate<MessageLoopForIO>>(
+            " SequenceManager with MessageLoopForIO ");
+
+      case PerfTestType::kUseSequenceManagerWithIOMessagePump:
+        return std::make_unique<SequenceManagerWithMessagePumpPerfTestDelegate>(
+            " SequenceManager with MessagePumpForIO ", MessageLoop::TYPE_IO);
+
+      case PerfTestType::kUseMessageLoop:
+        return std::make_unique<MessageLoopPerfTestDelegate>(
+            " MessageLoop ", std::make_unique<MessageLoop>());
+
+      case PerfTestType::kUseUIMessageLoop:
+        return std::make_unique<MessageLoopPerfTestDelegate>(
+            " MessageLoopForUI ", std::make_unique<MessageLoopForUI>());
+
+      case PerfTestType::kUseIOMessageLoop:
+        return std::make_unique<MessageLoopPerfTestDelegate>(
+            " MessageLoopForIO ", std::make_unique<MessageLoopForIO>());
+
+      case PerfTestType::kUseSingleThreadInWorkerPool:
+        return std::make_unique<SingleThreadInWorkerPoolPerfTestDelegate>();
+
+      default:
+        NOTREACHED();
+        return nullptr;
     }
   }
 
-  void TestImmediateTask() {
-    if (--num_tasks_to_run_ == 0) {
-      SignalDone();
-      return;
+  std::vector<scoped_refptr<TaskRunner>> CreateTaskRunners(int num) {
+    std::vector<scoped_refptr<TaskRunner>> task_runners;
+    for (int i = 0; i < num; i++) {
+      task_runners.push_back(delegate_->CreateTaskRunner());
     }
-
-    num_tasks_in_flight_--;
-    // NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at
-    // any one time.  Thanks to the lower_num_tasks_to_post going to zero if
-    // there are a lot of tasks in flight, the total number of task in flight at
-    // any one time is very variable.
-    unsigned int lower_num_tasks_to_post =
-        num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0;
-    unsigned int max_tasks_to_post =
-        num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10;
-    for (unsigned int i = 0;
-         i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ &&
-         num_tasks_to_post_ > 0;
-         i++) {
-      // Choose a queue weighted towards queue 0.
-      unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1);
-      if (queue == num_queues_) {
-        queue = 0;
-      }
-      task_runners_[queue]->PostTask(FROM_HERE, immediate_task_closure_);
-      num_tasks_in_flight_++;
-      num_tasks_to_post_--;
-    }
+    return task_runners;
   }
 
-  void ResetAndCallTestDelayedTask(unsigned int num_tasks_to_run) {
-    num_tasks_in_flight_ = 1;
-    num_tasks_to_post_ = num_tasks_to_run;
-    num_tasks_to_run_ = num_tasks_to_run;
-    TestDelayedTask();
-  }
-
-  void ResetAndCallTestImmediateTask(unsigned int num_tasks_to_run) {
-    num_tasks_in_flight_ = 1;
-    num_tasks_to_post_ = num_tasks_to_run;
-    num_tasks_to_run_ = num_tasks_to_run;
-    TestImmediateTask();
-  }
-
-  void Benchmark(const std::string& trace, const RepeatingClosure& test_task) {
+  void Benchmark(const std::string& trace, TestCase* TestCase) {
     TimeTicks start = TimeTicks::Now();
     TimeTicks now;
     unsigned long long num_iterations = 0;
     do {
-      test_task.Run();
-      WaitUntilDone();
+      TestCase->Start();
+      delegate_->WaitUntilDone();
       now = TimeTicks::Now();
       num_iterations++;
     } while (now - start < TimeDelta::FromSeconds(5));
 
-    std::string trace_suffix;
-    switch (GetParam()) {
-      case PerfTestType::kUseSequenceManagerWithMessageLoop:
-        trace_suffix = " SequenceManager with message loop ";
-        break;
-      case PerfTestType::kUseSequenceManagerWithMessagePump:
-        trace_suffix = " SequenceManager with message pump ";
-        break;
-      case PerfTestType::kUseSequenceManagerWithUIMessageLoop:
-        trace_suffix = " SequenceManager with UI message loop ";
-        break;
-      case PerfTestType::kUseSequenceManagerWithUIMessagePump:
-        trace_suffix = " SequenceManager with UI message pump ";
-        break;
-      case PerfTestType::kUseSequenceManagerWithIOMessageLoop:
-        trace_suffix = " SequenceManager with IO message loop ";
-        break;
-      case PerfTestType::kUseSequenceManagerWithIOMessagePump:
-        trace_suffix = " SequenceManager with IO message pump ";
-        break;
-      case PerfTestType::kUseMessageLoop:
-        trace_suffix = " message loop ";
-        break;
-      case PerfTestType::kUseUIMessageLoop:
-        trace_suffix = " message loop for UI ";
-        break;
-      case PerfTestType::kUseIOMessageLoop:
-        trace_suffix = " message loop for IO ";
-        break;
-      case PerfTestType::kUseSingleThreadInWorkerPool:
-        trace_suffix = " single thread in WorkerPool ";
-        break;
-    }
-
     perf_test::PrintResult(
-        "task", "", trace + trace_suffix,
+        "task", "", trace + delegate_->GetName(),
         (now - start).InMicroseconds() / static_cast<double>(num_iterations),
         "us/run", true);
+
+    LOG(ERROR) << "task " << trace << delegate_->GetName()
+               << ((now - start).InMicroseconds() /
+                   static_cast<double>(num_iterations))
+               << " us/run";
   }
 
-  size_t num_queues_;
-  unsigned int max_tasks_in_flight_;
-  unsigned int num_tasks_in_flight_;
-  unsigned int num_tasks_to_post_;
-  unsigned int num_tasks_to_run_;
-  std::unique_ptr<MessageLoop> message_loop_;
-  std::unique_ptr<SequenceManager> manager_;
-  std::unique_ptr<TimeDomain> time_domain_;
-  std::vector<scoped_refptr<TaskRunner>> task_runners_;
-
-  Lock done_lock_;
-  ConditionVariable done_cond_;
-  std::unique_ptr<RunLoop> run_loop_;
-
-  // May own |task_runners_|.
-  std::vector<scoped_refptr<TestTaskQueue>> owning_task_queues_;
-
-  RepeatingClosure delayed_task_closure_;
-  RepeatingClosure immediate_task_closure_;
+  std::unique_ptr<PerfTestDelegate> delegate_;
 };
 
 INSTANTIATE_TEST_CASE_P(
@@ -414,9 +656,7 @@
     testing::Values(PerfTestType::kUseSequenceManagerWithMessageLoop,
                     PerfTestType::kUseSequenceManagerWithMessagePump,
                     PerfTestType::kUseSequenceManagerWithUIMessageLoop,
-#if !defined(OS_IOS) && !defined(OS_MACOSX)
                     PerfTestType::kUseSequenceManagerWithUIMessagePump,
-#endif
                     PerfTestType::kUseSequenceManagerWithIOMessageLoop,
                     PerfTestType::kUseSequenceManagerWithIOMessagePump,
                     PerfTestType::kUseMessageLoop,
@@ -428,184 +668,161 @@
   if (!ThreadTicks::IsSupported())
     return;
 
-  switch (GetParam()) {
-    // Virtual time is not supported for MessageLoop or WorkerPool.
-    case PerfTestType::kUseMessageLoop:
-    case PerfTestType::kUseUIMessageLoop:
-    case PerfTestType::kUseIOMessageLoop:
-    case PerfTestType::kUseSingleThreadInWorkerPool:
-      LOG(INFO) << "Unsupported";
-      return;
-
-    default:
-      break;
+  if (!delegate_->VirtualTimeIsSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
   }
 
-  Initialize(1u);
-
-  max_tasks_in_flight_ = 200;
-  Benchmark("run 10000 delayed tasks with one queue",
-            BindRepeating(&SequenceManagerPerfTest::ResetAndCallTestDelayedTask,
-                          Unretained(this), 10000));
+  SingleThreadDelayedTestCase task_source(delegate_.get(), CreateTaskRunners(1),
+                                          10000u);
+  Benchmark("run 10000 delayed tasks with one queue", &task_source);
 }
 
 TEST_P(SequenceManagerPerfTest, RunTenThousandDelayedTasks_FourQueues) {
   if (!ThreadTicks::IsSupported())
     return;
 
-  switch (GetParam()) {
-    // Virtual time is not supported for MessageLoop or WorkerPool.
-    case PerfTestType::kUseMessageLoop:
-    case PerfTestType::kUseUIMessageLoop:
-    case PerfTestType::kUseIOMessageLoop:
-    case PerfTestType::kUseSingleThreadInWorkerPool:
-      LOG(INFO) << "Unsupported";
-      return;
-
-    default:
-      break;
+  if (!delegate_->VirtualTimeIsSupported() ||
+      !delegate_->MultipleQueuesSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
   }
 
-  Initialize(4u);
-
-  max_tasks_in_flight_ = 200;
-  Benchmark("run 10000 delayed tasks with four queues",
-            BindRepeating(&SequenceManagerPerfTest::ResetAndCallTestDelayedTask,
-                          Unretained(this), 10000));
+  SingleThreadDelayedTestCase task_source(delegate_.get(), CreateTaskRunners(4),
+                                          10000u);
+  Benchmark("run 10000 delayed tasks with four queues", &task_source);
 }
 
 TEST_P(SequenceManagerPerfTest, RunTenThousandDelayedTasks_EightQueues) {
   if (!ThreadTicks::IsSupported())
     return;
 
-  switch (GetParam()) {
-    // Virtual time is not supported for MessageLoop or WorkerPool.
-    case PerfTestType::kUseMessageLoop:
-    case PerfTestType::kUseUIMessageLoop:
-    case PerfTestType::kUseIOMessageLoop:
-    case PerfTestType::kUseSingleThreadInWorkerPool:
-      LOG(INFO) << "Unsupported";
-      return;
-
-    default:
-      break;
+  if (!delegate_->VirtualTimeIsSupported() ||
+      !delegate_->MultipleQueuesSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
   }
 
-  Initialize(8u);
-
-  max_tasks_in_flight_ = 200;
-  Benchmark("run 10000 delayed tasks with eight queues",
-            BindRepeating(&SequenceManagerPerfTest::ResetAndCallTestDelayedTask,
-                          Unretained(this), 10000));
+  SingleThreadDelayedTestCase task_source(delegate_.get(), CreateTaskRunners(8),
+                                          10000u);
+  Benchmark("run 10000 delayed tasks with eight queues", &task_source);
 }
 
 TEST_P(SequenceManagerPerfTest, RunTenThousandDelayedTasks_ThirtyTwoQueues) {
   if (!ThreadTicks::IsSupported())
     return;
 
-  switch (GetParam()) {
-    case PerfTestType::kUseMessageLoop:
-    case PerfTestType::kUseUIMessageLoop:
-    case PerfTestType::kUseIOMessageLoop:
-    case PerfTestType::kUseSingleThreadInWorkerPool:
-      LOG(INFO) << "Unsupported";
-      return;
-
-    default:
-      break;
+  if (!delegate_->VirtualTimeIsSupported() ||
+      !delegate_->MultipleQueuesSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
   }
 
-  Initialize(32u);
-
-  max_tasks_in_flight_ = 200;
-  Benchmark("run 10000 delayed tasks with thirty two queues",
-            BindRepeating(&SequenceManagerPerfTest::ResetAndCallTestDelayedTask,
-                          Unretained(this), 10000));
+  SingleThreadDelayedTestCase task_source(delegate_.get(),
+                                          CreateTaskRunners(32), 10000u);
+  Benchmark("run 10000 delayed tasks with thirty two queues", &task_source);
 }
 
 TEST_P(SequenceManagerPerfTest, RunTenThousandImmediateTasks_OneQueue) {
   if (!ThreadTicks::IsSupported())
     return;
-  Initialize(1u);
 
-  max_tasks_in_flight_ = 200;
-  Benchmark(
-      "run 10000 immediate tasks with one queue",
-      BindRepeating(&SequenceManagerPerfTest::ResetAndCallTestImmediateTask,
-                    Unretained(this), 10000));
+  SingleThreadImmediateTestCase task_source(delegate_.get(),
+                                            CreateTaskRunners(1), 10000u);
+  Benchmark("run 10000 immediate tasks with one queue", &task_source);
 }
 
 TEST_P(SequenceManagerPerfTest, RunTenThousandImmediateTasks_FourQueues) {
   if (!ThreadTicks::IsSupported())
     return;
 
-  switch (GetParam()) {
-    // We only support a single queue on the MessageLoop.
-    case PerfTestType::kUseMessageLoop:
-    case PerfTestType::kUseUIMessageLoop:
-    case PerfTestType::kUseIOMessageLoop:
-      LOG(INFO) << "Unsupported";
-      return;
-
-    default:
-      break;
+  if (!delegate_->MultipleQueuesSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
   }
 
-  Initialize(4u);
-
-  max_tasks_in_flight_ = 200;
-  Benchmark(
-      "run 10000 immediate tasks with four queues",
-      BindRepeating(&SequenceManagerPerfTest::ResetAndCallTestImmediateTask,
-                    Unretained(this), 10000));
+  SingleThreadImmediateTestCase task_source(delegate_.get(),
+                                            CreateTaskRunners(4), 10000u);
+  Benchmark("run 10000 immediate tasks with four queues", &task_source);
 }
 
 TEST_P(SequenceManagerPerfTest, RunTenThousandImmediateTasks_EightQueues) {
   if (!ThreadTicks::IsSupported())
     return;
 
-  switch (GetParam()) {
-    // We only support a single queue on the MessageLoop.
-    case PerfTestType::kUseMessageLoop:
-    case PerfTestType::kUseUIMessageLoop:
-    case PerfTestType::kUseIOMessageLoop:
-      LOG(INFO) << "Unsupported";
-      return;
-
-    default:
-      break;
+  if (!delegate_->MultipleQueuesSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
   }
-  Initialize(8u);
 
-  max_tasks_in_flight_ = 200;
-  Benchmark(
-      "run 10000 immediate tasks with eight queues",
-      BindRepeating(&SequenceManagerPerfTest::ResetAndCallTestImmediateTask,
-                    Unretained(this), 10000));
+  SingleThreadImmediateTestCase task_source(delegate_.get(),
+                                            CreateTaskRunners(8), 10000u);
+  Benchmark("run 10000 immediate tasks with eight queues", &task_source);
 }
 
 TEST_P(SequenceManagerPerfTest, RunTenThousandImmediateTasks_ThirtyTwoQueues) {
   if (!ThreadTicks::IsSupported())
     return;
 
-  switch (GetParam()) {
-    // We only support a single queue on the MessageLoop.
-    case PerfTestType::kUseMessageLoop:
-    case PerfTestType::kUseUIMessageLoop:
-    case PerfTestType::kUseIOMessageLoop:
-      LOG(INFO) << "Unsupported";
-      return;
-
-    default:
-      break;
+  if (!delegate_->MultipleQueuesSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
   }
-  Initialize(32u);
 
-  max_tasks_in_flight_ = 200;
-  Benchmark(
-      "run 10000 immediate tasks with thirty two queues",
-      BindRepeating(&SequenceManagerPerfTest::ResetAndCallTestImmediateTask,
-                    Unretained(this), 10000));
+  SingleThreadImmediateTestCase task_source(delegate_.get(),
+                                            CreateTaskRunners(32), 10000u);
+  Benchmark("run 10000 immediate tasks with thirty two queues", &task_source);
+}
+
+TEST_P(SequenceManagerPerfTest,
+       RunTenThousandImmediateTasksFromTwoThreads_OneQueue) {
+  if (!ThreadTicks::IsSupported())
+    return;
+
+  TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(1), 10000u);
+  Benchmark("run 10000 immediate tasks with one queue", &task_source);
+}
+
+TEST_P(SequenceManagerPerfTest,
+       RunTenThousandImmediateTasksFromTwoThreads_FourQueues) {
+  if (!ThreadTicks::IsSupported())
+    return;
+
+  if (!delegate_->MultipleQueuesSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
+  }
+
+  TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(4), 10000u);
+  Benchmark("run 10000 immediate tasks with four queues", &task_source);
+}
+
+TEST_P(SequenceManagerPerfTest,
+       RunTenThousandImmediateTasksFromTwoThreads_EightQueues) {
+  if (!ThreadTicks::IsSupported())
+    return;
+
+  if (!delegate_->MultipleQueuesSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
+  }
+
+  TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(8), 10000u);
+  Benchmark("run 10000 immediate tasks with eight queues", &task_source);
+}
+
+TEST_P(SequenceManagerPerfTest,
+       RunTenThousandImmediateTasksFromTwoThreads_ThirtyTwoQueues) {
+  if (!ThreadTicks::IsSupported())
+    return;
+
+  if (!delegate_->MultipleQueuesSupported()) {
+    LOG(INFO) << "Unsupported";
+    return;
+  }
+
+  TwoThreadTestCase task_source(delegate_.get(), CreateTaskRunners(32), 10000u);
+  Benchmark("run 10000 immediate tasks with thirty two queues", &task_source);
 }
 
 // TODO(alexclarke): Add additional tests with different mixes of non-delayed vs
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index c8c88518..4c94ecfe75 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -325,8 +325,11 @@
   #     external_attr = (os.stat(src_path)[0] & 0xFFFF) << 16L
   # but we want to use _HERMETIC_FILE_ATTR, so manually set
   # the few attr bits we care about.
-  if src_path and os.access(src_path, os.X_OK):
-    zipinfo.external_attr |= stat.S_IXUSR << 16L
+  if src_path:
+    st = os.stat(src_path)
+    for mode in (stat.S_IXUSR, stat.S_IXGRP, stat.S_IXOTH):
+      if st.st_mode & mode:
+        zipinfo.external_attr |= mode << 16L
 
   if src_path:
     with open(src_path, 'rb') as f:
diff --git a/chrome/android/java/res/layout/contact_view.xml b/chrome/android/java/res/layout/contact_view.xml
index 5572ede7..d2e0a9a 100644
--- a/chrome/android/java/res/layout/contact_view.xml
+++ b/chrome/android/java/res/layout/contact_view.xml
@@ -21,8 +21,8 @@
 
         <ImageView
             android:id="@+id/image"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
             android:layout_alignParentStart="true"
             android:paddingBottom="10dp"
             android:paddingEnd="10dp"
diff --git a/chrome/android/java/res/xml/main_preferences.xml b/chrome/android/java/res/xml/main_preferences.xml
index 8e6a4b28..09cdef8 100644
--- a/chrome/android/java/res/xml/main_preferences.xml
+++ b/chrome/android/java/res/xml/main_preferences.xml
@@ -44,65 +44,70 @@
         android:key="autofill_addresses"
         android:order="7"
         android:title="@string/autofill_addresses_settings_title"/>
+    <org.chromium.chrome.browser.preferences.ChromeBasePreference
+        android:fragment="org.chromium.chrome.browser.preferences.autofill_assistant.AutofillAssistantPreferences"
+        android:key="autofill_assistant"
+        android:order="8"
+        android:title="@string/prefs_autofill_assistant_title"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.NotificationsPreferences"
         android:key="notifications"
-        android:order="8"
+        android:order="9"
         android:title="@string/prefs_notifications"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.ContextualSuggestionsPreference"
         android:key="contextual_suggestions"
-        android:order="9"
+        android:order="10"
         android:title="@string/prefs_contextual_suggestions"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.HomepagePreferences"
         android:key="homepage"
-        android:order="10"
+        android:order="11"
         android:title="@string/options_homepage_title"/>
 
     <PreferenceCategory
         android:key="advanced_section"
-        android:order="11"
+        android:order="12"
         android:title="@string/prefs_section_advanced"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.privacy.PrivacyPreferences"
         android:key="privacy"
-        android:order="12"
+        android:order="13"
         android:title="@string/prefs_privacy"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.AccessibilityPreferences"
         android:key="accessibility"
-        android:order="13"
+        android:order="14"
         android:title="@string/prefs_accessibility"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.website.SiteSettingsPreferences"
         android:key="content_settings"
-        android:order="14"
+        android:order="15"
         android:title="@string/prefs_site_settings"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.languages.LanguagesPreferences"
         android:key="languages"
-        android:order="15"
+        android:order="16"
         android:title="@string/prefs_languages"/>
     <org.chromium.chrome.browser.preferences.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.preferences.datareduction.DataReductionPreferences"
         android:key="data_reduction"
-        android:order="16"
+        android:order="17"
         android:title="@string/data_reduction_title"/>
     <org.chromium.chrome.browser.preferences.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.preferences.download.DownloadPreferences"
         android:key="downloads"
-        android:order="17"
+        android:order="18"
         android:title="@string/menu_downloads"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.developer.DeveloperPreferences"
         android:key="developer"
-        android:order="18"
+        android:order="19"
         android:title="@string/prefs_developer"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.AboutChromePreferences"
         android:key="about_chrome"
-        android:order="19"
+        android:order="20"
         android:title="@string/prefs_about_chrome"/>
 
 </PreferenceScreen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
index 21ca9c3..6d603be1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -9,11 +9,13 @@
 import android.support.annotation.Nullable;
 
 import org.chromium.base.Callback;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.payments.AutofillAssistantPaymentRequest;
+import org.chromium.chrome.browser.preferences.autofill_assistant.AutofillAssistantPreferences;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
@@ -82,7 +84,9 @@
     public static boolean isConfigured(Bundle intentExtras) {
         return getBooleanParameter(intentExtras, PARAMETER_ENABLED)
                 && !VariationsAssociatedData.getVariationParamValue(STUDY_NAME, URL_PARAMETER_NAME)
-                            .isEmpty();
+                            .isEmpty()
+                && ContextUtils.getAppSharedPreferences().getBoolean(
+                           AutofillAssistantPreferences.PREF_AUTOFILL_ASSISTANT_SWITCH, false);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
index d625927d..997ab8c6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
@@ -132,7 +132,7 @@
         mDetailsView.setText(contactDetails.getContactDetailsAsString());
         if (icon == null) {
             icon = mCategoryView.getIconGenerator().generateIconForText(
-                    contactDetails.getDisplayNameAbbreviation(), 2);
+                    contactDetails.getDisplayNameAbbreviation());
             mImage.setImageBitmap(icon);
         } else {
             setIconBitmap(icon);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactsFetcherWorkerTask.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactsFetcherWorkerTask.java
index e232aa6..d8412a9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactsFetcherWorkerTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactsFetcherWorkerTask.java
@@ -126,10 +126,10 @@
 
         // A cursor containing the raw contacts data.
         Cursor cursor = mContentResolver.query(ContactsContract.Contacts.CONTENT_URI, PROJECTION,
-                null, null, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC");
+                null, null, ContactsContract.Contacts.SORT_KEY_PRIMARY + " ASC");
+        if (!cursor.moveToFirst()) return new ArrayList<ContactDetails>();
 
         ArrayList<ContactDetails> contacts = new ArrayList<ContactDetails>(cursor.getCount());
-        if (!cursor.moveToFirst()) return contacts;
         do {
             String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
             String name = cursor.getString(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
index db02385..045f114e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
@@ -45,6 +45,7 @@
     public static final String PREF_LANGUAGES = "languages";
     public static final String PREF_DOWNLOADS = "downloads";
     public static final String PREF_DEVELOPER = "developer";
+    public static final String PREF_AUTOFILL_ASSISTANT = "autofill_assistant";
 
     public static final String AUTOFILL_GUID = "guid";
     // Needs to be in sync with kSettingsOrigin[] in
@@ -158,6 +159,11 @@
         if (!ChromeFeatureList.isEnabled(ChromeFeatureList.DEVELOPER_PREFERENCES)) {
             getPreferenceScreen().removePreference(findPreference(PREF_DEVELOPER));
         }
+
+        // This checks whether Autofill Assistant is enabled.
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ASSISTANT)) {
+            getPreferenceScreen().removePreference(findPreference(PREF_AUTOFILL_ASSISTANT));
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferences.java
new file mode 100644
index 0000000..7313d77
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferences.java
@@ -0,0 +1,60 @@
+// 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.
+
+package org.chromium.chrome.browser.preferences.autofill_assistant;
+
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceFragment;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
+
+/** The "Autofill Assistant" preferences screen in Settings. */
+public class AutofillAssistantPreferences extends PreferenceFragment {
+    /** Autofill Assistant switch preference key name. */
+    public static final String PREF_AUTOFILL_ASSISTANT_SWITCH = "autofill_assistant_switch";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getActivity().setTitle(R.string.prefs_autofill_assistant_title);
+        setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity()));
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        createAutofillAssistantSwitch();
+    }
+
+    private void createAutofillAssistantSwitch() {
+        ChromeSwitchPreference autofillAssistantSwitch =
+                new ChromeSwitchPreference(getActivity(), null);
+        autofillAssistantSwitch.setKey(PREF_AUTOFILL_ASSISTANT_SWITCH);
+        autofillAssistantSwitch.setTitle(R.string.prefs_autofill_assistant_switch);
+        autofillAssistantSwitch.setSummaryOn(R.string.text_on);
+        autofillAssistantSwitch.setSummaryOff(R.string.text_off);
+        autofillAssistantSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+            @Override
+            public boolean onPreferenceChange(Preference preference, Object newValue) {
+                ContextUtils.getAppSharedPreferences()
+                        .edit()
+                        .putBoolean(PREF_AUTOFILL_ASSISTANT_SWITCH, (boolean) newValue)
+                        .apply();
+                return true;
+            }
+        });
+        getPreferenceScreen().addPreference(autofillAssistantSwitch);
+
+        // Note: setting the switch state before the preference is added to the screen results in
+        // some odd behavior where the switch state doesn't always match the internal enabled state
+        // (e.g. the switch will say "On" when it is really turned off), so .setChecked() should be
+        // called after .addPreference()
+        autofillAssistantSwitch.setChecked(ContextUtils.getAppSharedPreferences().getBoolean(
+                PREF_AUTOFILL_ASSISTANT_SWITCH, false));
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/OWNERS
new file mode 100644
index 0000000..829eb83
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/OWNERS
@@ -0,0 +1 @@
+file://components/autofill_assistant/OWNERS
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/RoundedIconGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/RoundedIconGenerator.java
index 1e972f6..91b1d0e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/RoundedIconGenerator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/RoundedIconGenerator.java
@@ -105,23 +105,12 @@
      * @return The generated icon.
      */
     public Bitmap generateIconForText(String text) {
-        return generateIconForText(text, 1);
-    }
-
-    /**
-     * Generates an icon based on |text|.
-     *
-     * @param text The text to render on the icon.
-     * @param numChars The maximum number of characters to return.
-     * @return The generated icon.
-     */
-    public Bitmap generateIconForText(String text, int numChars) {
         Bitmap icon = Bitmap.createBitmap(mIconWidthPx, mIconHeightPx, Bitmap.Config.ARGB_8888);
         Canvas canvas = new Canvas(icon);
 
         canvas.drawRoundRect(mBackgroundRect, mCornerRadiusPx, mCornerRadiusPx, mBackgroundPaint);
 
-        int length = Math.min(numChars, text.length());
+        int length = Math.min(1, text.length());
         String displayText = text.substring(0, length).toUpperCase(Locale.getDefault());
         float textWidth = mTextPaint.measureText(displayText);
 
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index d7a99e7..7529f31 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3926,6 +3926,14 @@
       <message name="IDS_AUTOFILL_ASSISTANT_STOPPED" desc="Text label that is shown when stopping the Autofill Assistant. DURATION_SECONDS is a number representing a duration in seconds, which is why it is appended with 's'.">
         Autofill Assistant will stop in <ph name="DURATION_SECONDS">%1$s<ex>3</ex></ph>s…
       </message>
+      <!-- Autofill Assistant preferences -->
+      <message name="IDS_PREFS_AUTOFILL_ASSISTANT_TITLE" desc="Title for the Autofill Assistant preferences screen. [CHAR-LIMIT=32]">
+        Autofill Assistant
+      </message>
+      <message name="IDS_PREFS_AUTOFILL_ASSISTANT_SWITCH" desc="Title for the switch toggling whether Autofill Assistant is enabled. [CHAR-LIMIT=32]">
+        Automate
+      </message>
+
     </messages>
   </release>
 </grit>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 610bed7..65a7a5e 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1262,6 +1262,7 @@
   "java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditorPreference.java",
   "java/src/org/chromium/chrome/browser/preferences/autofill/AutofillServerProfilePreferences.java",
   "java/src/org/chromium/chrome/browser/preferences/autofill/CreditCardNumberFormattingTextWatcher.java",
+  "java/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferences.java",
   "java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionMainMenuItem.java",
   "java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionSiteBreakdownView.java",
   "java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java",
@@ -2093,6 +2094,7 @@
   "javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragmentTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillTestRule.java",
+  "javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferencesTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoUtilsTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreferenceTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SubresourceFilterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SubresourceFilterTest.java
index 854a9ca..c590f063 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/SubresourceFilterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SubresourceFilterTest.java
@@ -17,6 +17,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.infobar.AdsBlockedInfoBar;
 import org.chromium.chrome.browser.infobar.InfoBar;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
@@ -103,6 +104,7 @@
 
     @Test
     @MediumTest
+    @DisabledTest(message = "crbug.com/899903")
     public void resourceFilteredClose() throws Exception {
         String url = mTestServer.getURL(PAGE_WITH_JPG);
         MockSafeBrowsingApiHandler.addMockResponse(url, METADATA_FOR_ENFORCEMENT);
@@ -130,6 +132,7 @@
 
     @Test
     @MediumTest
+    @DisabledTest(message = "crbug.com/899903")
     public void resourceFilteredClickLearnMore() throws Exception {
         String url = mTestServer.getURL(PAGE_WITH_JPG);
         MockSafeBrowsingApiHandler.addMockResponse(url, METADATA_FOR_ENFORCEMENT);
@@ -170,6 +173,7 @@
 
     @Test
     @MediumTest
+    @DisabledTest(message = "crbug.com/899903")
     public void resourceFilteredReload() throws Exception {
         String url = mTestServer.getURL(PAGE_WITH_JPG);
         MockSafeBrowsingApiHandler.addMockResponse(url, METADATA_FOR_ENFORCEMENT);
@@ -201,6 +205,7 @@
     }
 
     @Test
+    @DisabledTest(message = "crbug.com/899903")
     @MediumTest
     public void resourceNotFilteredWithWarning() throws Exception {
         String url = mTestServer.getURL(PAGE_WITH_JPG);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferencesTest.java
new file mode 100644
index 0000000..642f581
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferencesTest.java
@@ -0,0 +1,168 @@
+// 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.
+
+package org.chromium.chrome.browser.preferences.autofill_assistant;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.intent.rule.IntentsTestRule;
+import android.support.test.filters.SmallTest;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.history.HistoryActivity;
+import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
+import org.chromium.chrome.browser.preferences.MainPreferences;
+import org.chromium.chrome.browser.preferences.Preferences;
+import org.chromium.chrome.browser.preferences.PreferencesTest;
+import org.chromium.chrome.browser.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
+import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+
+/**
+ * Tests for the "Autofill Assisatnt" settings screen.
+ */
+@RunWith(BaseJUnit4ClassRunner.class)
+public class AutofillAssistantPreferencesTest {
+    @Rule
+    public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+
+    @Rule
+    public TestRule mProcessor = new Features.InstrumentationProcessor();
+
+    @Rule
+    public IntentsTestRule<HistoryActivity> mHistoryActivityTestRule =
+            new IntentsTestRule<>(HistoryActivity.class, false, false);
+
+    /**
+     * Set the |PREF_AUTOFILL_ASSISTANT_SWITCH| shared preference to the given |value|.
+     * @param value The value to set the preference to.
+     */
+    private void setAutofillAssistantSwitch(boolean value) {
+        ContextUtils.getAppSharedPreferences()
+                .edit()
+                .putBoolean(AutofillAssistantPreferences.PREF_AUTOFILL_ASSISTANT_SWITCH, value)
+                .apply();
+    }
+
+    /**
+     * Get the |PREF_AUTOFILL_ASSISTANT_SWITCH| shared preference.
+     * @param defaultValue The default value to use if the preference does not exist.
+     * @return The value of the shared preference.
+     */
+    private boolean getAutofillAssistantSwitch(boolean defaultValue) {
+        return ContextUtils.getAppSharedPreferences().getBoolean(
+                AutofillAssistantPreferences.PREF_AUTOFILL_ASSISTANT_SWITCH, defaultValue);
+    }
+
+    /**
+     * Ensure that the on/off switch in "Autofill Assistant" settings works.
+     */
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    @EnableFeatures(ChromeFeatureList.AUTOFILL_ASSISTANT)
+    public void testAutofillAssistantSwitch() throws Exception {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                setAutofillAssistantSwitch(true);
+            }
+        });
+
+        final Preferences preferences =
+                PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
+                        AutofillAssistantPreferences.class.getName());
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                AutofillAssistantPreferences autofillAssistantPrefs =
+                        (AutofillAssistantPreferences) preferences.getFragmentForTest();
+                ChromeSwitchPreference onOffSwitch =
+                        (ChromeSwitchPreference) autofillAssistantPrefs.findPreference(
+                                AutofillAssistantPreferences.PREF_AUTOFILL_ASSISTANT_SWITCH);
+                Assert.assertTrue(onOffSwitch.isChecked());
+
+                PreferencesTest.clickPreference(autofillAssistantPrefs, onOffSwitch);
+                Assert.assertFalse(getAutofillAssistantSwitch(true));
+                PreferencesTest.clickPreference(autofillAssistantPrefs, onOffSwitch);
+                Assert.assertTrue(getAutofillAssistantSwitch(false));
+
+                preferences.finish();
+                setAutofillAssistantSwitch(false);
+            }
+        });
+
+        final Preferences preferences2 =
+                PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
+                        AutofillAssistantPreferences.class.getName());
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                AutofillAssistantPreferences autofillAssistantPrefs =
+                        (AutofillAssistantPreferences) preferences2.getFragmentForTest();
+                ChromeSwitchPreference onOffSwitch =
+                        (ChromeSwitchPreference) autofillAssistantPrefs.findPreference(
+                                AutofillAssistantPreferences.PREF_AUTOFILL_ASSISTANT_SWITCH);
+                Assert.assertFalse(onOffSwitch.isChecked());
+            }
+        });
+    }
+
+    /**
+     * Ensure that the "Autofill Assistant" setting is shown when the feature is enabled.
+     */
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    @EnableFeatures(ChromeFeatureList.AUTOFILL_ASSISTANT)
+    public void testAutofillAssistantPreferenceEnabled() throws Exception {
+        final Preferences preferences = PreferencesTest.startPreferences(
+                InstrumentationRegistry.getInstrumentation(), MainPreferences.class.getName());
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                MainPreferences mainPrefs = (MainPreferences) preferences.getFragmentForTest();
+                Assert.assertThat(mainPrefs.findPreference(MainPreferences.PREF_AUTOFILL_ASSISTANT),
+                        is(not(nullValue())));
+            }
+        });
+    }
+
+    /**
+     * Ensure that the "Autofill Assistant" setting is not shown when the feature is disabled.
+     */
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    @DisableFeatures(ChromeFeatureList.AUTOFILL_ASSISTANT)
+    public void testAutofillAssistantPreferenceDisabled() throws Exception {
+        final Preferences preferences = PreferencesTest.startPreferences(
+                InstrumentationRegistry.getInstrumentation(), MainPreferences.class.getName());
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                MainPreferences mainPrefs = (MainPreferences) preferences.getFragmentForTest();
+                Assert.assertThat(mainPrefs.findPreference(MainPreferences.PREF_AUTOFILL_ASSISTANT),
+                        is(nullValue()));
+            }
+        });
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/OWNERS
new file mode 100644
index 0000000..829eb83
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/OWNERS
@@ -0,0 +1 @@
+file://components/autofill_assistant/OWNERS
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/RoundedIconGeneratorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/RoundedIconGeneratorTest.java
index f3edd91..2dbdb3b0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/RoundedIconGeneratorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/RoundedIconGeneratorTest.java
@@ -87,10 +87,7 @@
         RoundedIconGenerator generator = new RoundedIconGenerator(mContext.getResources(),
                 iconSizeDp, iconSizeDp, iconCornerRadiusDp, iconColor, iconTextSizeDp);
 
-        Assert.assertTrue(generator.generateIconForText("", 0) != null);
-        Assert.assertTrue(generator.generateIconForText("", 1) != null);
-        Assert.assertTrue(generator.generateIconForText("A", 0) != null);
-        Assert.assertTrue(generator.generateIconForText("A", 1) != null);
-        Assert.assertTrue(generator.generateIconForText("A", 2) != null);
+        Assert.assertTrue(generator.generateIconForText("") != null);
+        Assert.assertTrue(generator.generateIconForText("A") != null);
     }
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 2a13db8dd..649cf146 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4090,6 +4090,10 @@
       "offline_pages/fresh_offline_content_observer.h",
       "offline_pages/offline_page_auto_fetcher.cc",
       "offline_pages/offline_page_auto_fetcher.h",
+      "offline_pages/offline_page_auto_fetcher_service.cc",
+      "offline_pages/offline_page_auto_fetcher_service.h",
+      "offline_pages/offline_page_auto_fetcher_service_factory.cc",
+      "offline_pages/offline_page_auto_fetcher_service_factory.h",
       "offline_pages/offline_page_bookmark_observer.cc",
       "offline_pages/offline_page_bookmark_observer.h",
       "offline_pages/offline_page_info_handler.cc",
@@ -5004,6 +5008,7 @@
 
   if (is_win || is_mac || is_desktop_linux || is_chromeos) {
     deps += [
+      "//chrome/browser/resources/discards:discards_resources_gen",
       "//chrome/browser/ui/webui/discards:mojo_bindings_js",
       "//services/resource_coordinator/public/mojom:mojom_js",
     ]
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 33151fd..989ea07 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -77,6 +77,8 @@
         <include name="IDR_DISCARDS_DISCARDS_MAIN_JS" file="resources\discards\discards_main.js" type="BINDATA" />
         <include name="IDR_DISCARDS_DISCARDS_TAB_HTML" file="resources\discards\discards_tab.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
         <include name="IDR_DISCARDS_DISCARDS_TAB_JS" file="resources\discards\discards_tab.js" type="BINDATA" />
+        <include name="IDR_DISCARDS_GRAPH_TAB_HTML" file="${root_gen_dir}\chrome\browser\resources\discards\graph_tab.html" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+        <include name="IDR_DISCARDS_GRAPH_TAB_JS" file="resources\discards\graph_tab.js" type="BINDATA" />
         <include name="IDR_DISCARDS_HTML" file="resources\discards\discards.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
         <include name="IDR_DISCARDS_JS" file="resources\discards\discards.js" type="BINDATA" />
         <include name="IDR_DISCARDS_LIFECYCLE_UNIT_STATE_MOJO_JS" file="${root_gen_dir}\chrome\browser\resource_coordinator\lifecycle_unit_state.mojom.js" use_base_dir="false" type="BINDATA" />
diff --git a/chrome/browser/browser_switcher/OWNERS b/chrome/browser/browser_switcher/OWNERS
index cd9c4a5..2278c01a 100644
--- a/chrome/browser/browser_switcher/OWNERS
+++ b/chrome/browser/browser_switcher/OWNERS
@@ -1 +1,2 @@
+nicolaso@chromium.org
 pastarmovj@chromium.org
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
index 40c27cf..309a079 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
@@ -69,12 +69,9 @@
   indexed_db_context_->DeleteForOrigin(origin);
 }
 
-CannedBrowsingDataIndexedDBHelper::
-PendingIndexedDBInfo::PendingIndexedDBInfo(const GURL& origin,
-                                           const base::string16& name)
-    : origin(origin),
-      name(name) {
-}
+CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo::PendingIndexedDBInfo(
+    const GURL& origin)
+    : origin(origin) {}
 
 CannedBrowsingDataIndexedDBHelper::
 PendingIndexedDBInfo::~PendingIndexedDBInfo() {
@@ -82,7 +79,7 @@
 
 bool CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo::operator<(
     const PendingIndexedDBInfo& other) const {
-  return std::tie(origin, name) < std::tie(other.origin, other.name);
+  return origin < other.origin;
 }
 
 CannedBrowsingDataIndexedDBHelper::CannedBrowsingDataIndexedDBHelper(
@@ -92,12 +89,11 @@
 
 CannedBrowsingDataIndexedDBHelper::~CannedBrowsingDataIndexedDBHelper() {}
 
-void CannedBrowsingDataIndexedDBHelper::AddIndexedDB(
-    const GURL& origin, const base::string16& name) {
+void CannedBrowsingDataIndexedDBHelper::AddIndexedDB(const GURL& origin) {
   if (!BrowsingDataHelper::HasWebScheme(origin))
     return;  // Non-websafe state is not considered browsing data.
 
-  pending_indexed_db_info_.insert(PendingIndexedDBInfo(origin, name));
+  pending_indexed_db_info_.insert(PendingIndexedDBInfo(origin));
 }
 
 void CannedBrowsingDataIndexedDBHelper::Reset() {
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h
index a24848a4..f81ee17 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h
@@ -63,13 +63,12 @@
  public:
   // Contains information about an indexed database.
   struct PendingIndexedDBInfo {
-    PendingIndexedDBInfo(const GURL& origin, const base::string16& name);
+    explicit PendingIndexedDBInfo(const GURL& origin);
     ~PendingIndexedDBInfo();
 
     bool operator<(const PendingIndexedDBInfo& other) const;
 
     GURL origin;
-    base::string16 name;
   };
 
   explicit CannedBrowsingDataIndexedDBHelper(
@@ -77,8 +76,7 @@
 
   // Add a indexed database to the set of canned indexed databases that is
   // returned by this helper.
-  void AddIndexedDB(const GURL& origin,
-                    const base::string16& name);
+  void AddIndexedDB(const GURL& origin);
 
   // Clear the list of canned indexed databases.
   void Reset();
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc
index 4f456c5..088c2bc 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc
@@ -32,12 +32,11 @@
 IN_PROC_BROWSER_TEST_F(BrowsingDataIndexedDBHelperTest, CannedAddIndexedDB) {
   const GURL origin1("http://host1:1/");
   const GURL origin2("http://host2:1/");
-  const base::string16 description(base::ASCIIToUTF16("description"));
 
   scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
-  helper->AddIndexedDB(origin1, description);
-  helper->AddIndexedDB(origin2, description);
+  helper->AddIndexedDB(origin1);
+  helper->AddIndexedDB(origin2);
 
   TestCompletionCallback callback;
   helper->StartFetching(
@@ -56,12 +55,11 @@
 
 IN_PROC_BROWSER_TEST_F(BrowsingDataIndexedDBHelperTest, CannedUnique) {
   const GURL origin("http://host1:1/");
-  const base::string16 description(base::ASCIIToUTF16("description"));
 
   scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
-  helper->AddIndexedDB(origin, description);
-  helper->AddIndexedDB(origin, description);
+  helper->AddIndexedDB(origin);
+  helper->AddIndexedDB(origin);
 
   TestCompletionCallback callback;
   helper->StartFetching(
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc
index af65c46..e6b49282 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc
@@ -28,13 +28,11 @@
 
 TEST_F(CannedBrowsingDataIndexedDBHelperTest, Empty) {
   const GURL origin("http://host1:1/");
-  const base::string16 description(base::ASCIIToUTF16("description"));
-
   scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddIndexedDB(origin, description);
+  helper->AddIndexedDB(origin);
   ASSERT_FALSE(helper->empty());
   helper->Reset();
   ASSERT_TRUE(helper->empty());
@@ -42,20 +40,15 @@
 
 TEST_F(CannedBrowsingDataIndexedDBHelperTest, Delete) {
   const GURL origin1("http://host1:9000");
-  const base::string16 db1(base::ASCIIToUTF16("db1"));
-
   const GURL origin2("http://example.com");
-  const base::string16 db2(base::ASCIIToUTF16("db2"));
-  const base::string16 db3(base::ASCIIToUTF16("db3"));
 
   scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
 
   EXPECT_TRUE(helper->empty());
-  helper->AddIndexedDB(origin1, db1);
-  helper->AddIndexedDB(origin2, db2);
-  helper->AddIndexedDB(origin2, db3);
-  EXPECT_EQ(3u, helper->GetIndexedDBCount());
+  helper->AddIndexedDB(origin1);
+  helper->AddIndexedDB(origin2);
+  EXPECT_EQ(2u, helper->GetIndexedDBCount());
   helper->DeleteIndexedDB(origin2);
   EXPECT_EQ(1u, helper->GetIndexedDBCount());
 }
@@ -63,15 +56,14 @@
 TEST_F(CannedBrowsingDataIndexedDBHelperTest, IgnoreExtensionsAndDevTools) {
   const GURL origin1("chrome-extension://abcdefghijklmnopqrstuvwxyz/");
   const GURL origin2("chrome-devtools://abcdefghijklmnopqrstuvwxyz/");
-  const base::string16 description(base::ASCIIToUTF16("description"));
 
   scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddIndexedDB(origin1, description);
+  helper->AddIndexedDB(origin1);
   ASSERT_TRUE(helper->empty());
-  helper->AddIndexedDB(origin2, description);
+  helper->AddIndexedDB(origin2);
   ASSERT_TRUE(helper->empty());
 }
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 9376b8d..478c9bb 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -381,6 +381,7 @@
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h"
 #include "chrome/browser/chrome_browser_main_android.h"
+#include "chrome/browser/offline_pages/offline_page_auto_fetcher.h"
 #include "chrome/common/descriptors_android.h"
 #include "chrome/services/media_gallery_util/public/mojom/constants.mojom.h"
 #include "components/crash/content/browser/child_exit_observer_android.h"
@@ -2519,7 +2520,6 @@
 
 bool ChromeContentBrowserClient::AllowWorkerIndexedDB(
     const GURL& url,
-    const base::string16& name,
     content::ResourceContext* context,
     const std::vector<content::GlobalFrameRoutingId>& render_frames) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -2533,7 +2533,7 @@
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::UI},
         base::BindOnce(&TabSpecificContentSettings::IndexedDBAccessed,
-                       it.child_id, it.frame_routing_id, url, name, !allow));
+                       it.child_id, it.frame_routing_id, url, !allow));
   }
 
   return allow;
@@ -4301,6 +4301,12 @@
 
   frame_interfaces_parameterized_->AddInterface(
       base::BindRepeating(&NavigationPredictor::Create));
+
+#if defined(OS_ANDROID)
+  frame_interfaces_parameterized_->AddInterface(
+      base::BindRepeating(&offline_pages::OfflinePageAutoFetcher::Create),
+      base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}));
+#endif
 }
 
 void ChromeContentBrowserClient::MaybeCopyDisableWebRtcEncryptionSwitch(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index cfea18f..628f66a 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -248,7 +248,6 @@
       base::Callback<void(bool)> callback) override;
   bool AllowWorkerIndexedDB(
       const GURL& url,
-      const base::string16& name,
       content::ResourceContext* context,
       const std::vector<content::GlobalFrameRoutingId>& render_frames) override;
   AllowWebBluetoothResult AllowWebBluetooth(
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index f8444d6..4eec74cbd 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -88,6 +88,7 @@
           "blink.mojom.MediaDownloadInProductHelp",
           "blink.mojom.ShareService",
           "blink.mojom.TextSuggestionHost",
+          "chrome.mojom.OfflinePageAutoFetcher",
           "chrome.mojom.OpenSearchDocumentDescriptionHandler",
           "chrome.mojom.PrerenderCanceler",
           "chromeos.ime.mojom.InputEngineManager",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index b31f515..cdde7cb 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1045,8 +1045,6 @@
     "login/easy_unlock/easy_unlock_types.h",
     "login/easy_unlock/easy_unlock_user_login_flow.cc",
     "login/easy_unlock/easy_unlock_user_login_flow.h",
-    "login/easy_unlock/short_lived_user_context.cc",
-    "login/easy_unlock/short_lived_user_context.h",
     "login/enrollment/auto_enrollment_check_screen.cc",
     "login/enrollment/auto_enrollment_check_screen.h",
     "login/enrollment/auto_enrollment_check_screen_view.h",
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index dfe4470..96739ed 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -839,9 +839,6 @@
                    chromeos::DemoSession::IsDeviceInDemoMode());
   dict->SetBoolean("DRIVE_FS_ENABLED",
                    base::FeatureList::IsEnabled(chromeos::features::kDriveFs));
-  dict->SetBoolean(
-      "MY_FILES_VOLUME_ENABLED",
-      base::FeatureList::IsEnabled(chromeos::features::kMyFilesVolume));
   dict->SetString("CHROMEOS_RELEASE_BOARD",
                   base::SysInfo::GetLsbReleaseBoard());
   dict->SetString(
diff --git a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.cc b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.cc
index 7c69ca680..0e61ada 100644
--- a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.cc
+++ b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.cc
@@ -11,7 +11,6 @@
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/stl_util.h"
 #include "base/task/post_task.h"
-#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h"
 #include "chrome/browser/chromeos/login/quick_unlock/auth_token.h"
 #include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
@@ -579,8 +578,6 @@
       chromeos::ProfileHelper::Get()->GetUserByProfile(
           GetActiveProfile(browser_context()));
   const chromeos::UserContext user_context(*user);
-  chromeos::EasyUnlockService::Get(GetActiveProfile(browser_context()))
-      ->HandleUserReauth(user_context);
 
   Respond(ArgumentList(SetModes::Results::Create()));
 }
diff --git a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc
index 38e71be..28e0015 100644
--- a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc
+++ b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc
@@ -77,24 +77,14 @@
       : EasyUnlockServiceRegular(profile,
                                  fake_secure_channel_client,
                                  fake_device_sync_client,
-                                 fake_multidevice_setup_client),
-        reauth_count_(0) {}
+                                 fake_multidevice_setup_client) {}
   ~FakeEasyUnlockService() override {}
 
   // EasyUnlockServiceRegular:
   void InitializeInternal() override {}
   void ShutdownInternal() override {}
-  void HandleUserReauth(const chromeos::UserContext& user_context) override {
-    ++reauth_count_;
-  }
-
-  void ResetReauthCount() { reauth_count_ = 0; }
-
-  int reauth_count() const { return reauth_count_; }
 
  private:
-  int reauth_count_;
-
   DISALLOW_COPY_AND_ASSIGN(FakeEasyUnlockService);
 };
 
@@ -586,14 +576,8 @@
   // Verify there is no active mode.
   EXPECT_EQ(GetActiveModes(), QuickUnlockModeList{});
 
-  FakeEasyUnlockService* easy_unlock_service =
-      static_cast<FakeEasyUnlockService*>(EasyUnlockService::Get(profile()));
-  easy_unlock_service->ResetReauthCount();
-  EXPECT_EQ(0, easy_unlock_service->reauth_count());
-
   RunSetModes(QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN},
               {"111111"});
-  EXPECT_EQ(1, easy_unlock_service->reauth_count());
   EXPECT_EQ(GetActiveModes(),
             QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN});
 }
@@ -603,17 +587,11 @@
   // Verify there is no active mode.
   EXPECT_EQ(GetActiveModes(), QuickUnlockModeList{});
 
-  FakeEasyUnlockService* easy_unlock_service =
-      static_cast<FakeEasyUnlockService*>(EasyUnlockService::Get(profile()));
-  easy_unlock_service->ResetReauthCount();
-  EXPECT_EQ(0, easy_unlock_service->reauth_count());
-
   // Try to enable PIN, but use an invalid password. Verify that no event is
   // raised and GetActiveModes still returns an empty set.
   FailIfModesChanged();
   std::string error = RunSetModesWithInvalidToken();
   EXPECT_FALSE(error.empty());
-  EXPECT_EQ(0, easy_unlock_service->reauth_count());
   EXPECT_EQ(GetActiveModes(), QuickUnlockModeList{});
 }
 
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index 1087127..aaa1005 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -416,13 +416,14 @@
     return;
   }
 
-  const base::FilePath localVolume =
-      file_manager::util::GetMyFilesFolderForProfile(profile_);
-  const bool success = RegisterDownloadsMountPoint(profile_, localVolume);
+  // Register 'Downloads' folder for the profile to the file system.
+  const base::FilePath downloads =
+      file_manager::util::GetDownloadsFolderForProfile(profile_);
+  const bool success = RegisterDownloadsMountPoint(profile_, downloads);
   DCHECK(success);
 
   DoMountEvent(chromeos::MOUNT_ERROR_NONE,
-               Volume::CreateForDownloads(localVolume));
+               Volume::CreateForDownloads(downloads));
 
   // Subscribe to DriveIntegrationService.
   drive_integration_service_->AddObserver(this);
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
index 2147cb9..45fc50c 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
@@ -14,17 +14,14 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/file_manager/fake_disk_mount_manager.h"
 #include "chrome/browser/chromeos/file_manager/volume_manager_observer.h"
 #include "chrome/browser/chromeos/file_system_provider/fake_extension_provider.h"
 #include "chrome/browser/chromeos/file_system_provider/service.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/chromeos_features.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/suspend.pb.h"
 #include "chromeos/disks/disk.h"
@@ -44,9 +41,6 @@
 
 namespace file_manager {
 namespace {
-const char kLsbRelease[] =
-    "CHROMEOS_RELEASE_NAME=Chrome OS\n"
-    "CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
 
 class LoggingObserver : public VolumeManagerObserver {
  public:
@@ -854,21 +848,6 @@
   EXPECT_EQ(VOLUME_TYPE_DOWNLOADS_DIRECTORY, volume_list[0]->type());
 }
 
-TEST_F(VolumeManagerTest, VolumeManagerInitializeMyFilesVolume) {
-  // Emulate running inside ChromeOS.
-  chromeos::ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease,
-                                                              base::Time());
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(chromeos::features::kMyFilesVolume);
-  volume_manager()->Initialize();  // Adds "Downloads"
-  std::vector<base::WeakPtr<Volume>> volume_list =
-      volume_manager()->GetVolumeList();
-  ASSERT_EQ(1u, volume_list.size());
-  auto volume = volume_list[0];
-  EXPECT_EQ("downloads:MyFiles", volume->volume_id());
-  EXPECT_EQ(VOLUME_TYPE_DOWNLOADS_DIRECTORY, volume->type());
-}
-
 TEST_F(VolumeManagerTest, FindVolumeById) {
   volume_manager()->Initialize();  // Adds "Downloads"
   base::WeakPtr<Volume> bad_volume =
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
index 5c9d1b6..8e7e20d4 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_app_manager.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_factory.h"
-#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
@@ -372,8 +371,6 @@
       HandleAuthFailure(GetAccountId());
   }
 
-  for (EasyUnlockServiceObserver& observer : observers_)
-    observer.OnScreenlockStateChanged(state);
   return true;
 }
 
@@ -707,8 +704,6 @@
   }
 }
 
-void EasyUnlockService::HandleUserReauth(const UserContext& user_context) {}
-
 void EasyUnlockService::PrepareForSuspend() {
   app_manager_->DisableAppIfLoaded();
   if (screenlock_state_handler_ && screenlock_state_handler_->IsActive())
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h
index 1efa6dc..ee9007f 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h
@@ -53,7 +53,6 @@
 
 class EasyUnlockAppManager;
 class EasyUnlockServiceObserver;
-class UserContext;
 
 class EasyUnlockService : public KeyedService {
  public:
@@ -165,10 +164,6 @@
   // hardlock state if the two do not match.
   void CheckCryptohomeKeysAndMaybeHardlock();
 
-  // Called when the user reauths (e.g. in chrome://settings) so we can cache
-  // the user context for the setup flow.
-  virtual void HandleUserReauth(const UserContext& user_context);
-
   void AddObserver(EasyUnlockServiceObserver* observer);
   void RemoveObserver(EasyUnlockServiceObserver* observer);
 
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h
deleted file mode 100644
index b793221..0000000
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_OBSERVER_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_OBSERVER_H_
-
-#include "chromeos/components/proximity_auth/screenlock_state.h"
-
-namespace chromeos {
-
-class EasyUnlockServiceObserver {
- public:
-  // Invoked when screenlock state changes.
-  virtual void OnScreenlockStateChanged(proximity_auth::ScreenlockState state) {
-  }
-
- protected:
-  virtual ~EasyUnlockServiceObserver() {}
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_OBSERVER_H_
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
index 4d32c60..1c40b40 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
@@ -360,16 +360,6 @@
                    account_info.gaia);
 }
 
-void EasyUnlockServiceRegular::HandleUserReauth(
-    const UserContext& user_context) {
-  // Cache the user context for the next X minutes, so the user doesn't have to
-  // reauth again.
-  short_lived_user_context_.reset(new ShortLivedUserContext(
-      user_context,
-      apps::AppLifetimeMonitorFactory::GetForBrowserContext(profile()),
-      base::ThreadTaskRunnerHandle::Get().get()));
-}
-
 void EasyUnlockServiceRegular::SetHardlockAfterKeyOperation(
     EasyUnlockScreenlockStateHandler::HardlockState state_on_success,
     bool success) {
@@ -463,7 +453,6 @@
 }
 
 void EasyUnlockServiceRegular::ShutdownInternal() {
-  short_lived_user_context_.reset();
   pref_manager_.reset();
 
   proximity_auth::ScreenlockBridge::Get()->RemoveObserver(this);
@@ -697,10 +686,7 @@
   // changes an existing key.
   // Note: We do not show a notification when EasyUnlock is disabled by sync nor
   // if EasyUnlock was enabled through the setup app.
-  bool is_setup_fresh =
-      short_lived_user_context_ && short_lived_user_context_->user_context();
-
-  if (!public_keys_after_sync.empty() && !is_setup_fresh) {
+  if (!public_keys_after_sync.empty()) {
     if (public_keys_before_sync.empty()) {
       if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi) &&
           base::FeatureList::IsEnabled(
@@ -814,25 +800,7 @@
 }
 
 void EasyUnlockServiceRegular::RefreshCryptohomeKeysIfPossible() {
-  // If the user reauthed on the settings page, then the UserContext will be
-  // cached.
-  if (short_lived_user_context_ && short_lived_user_context_->user_context()) {
-    // We only sync the remote devices to cryptohome if the user has enabled
-    // EasyUnlock on the login screen.
-    base::ListValue empty_list;
-    const base::ListValue* remote_devices_list = GetRemoteDevices();
-    if (!IsChromeOSLoginEnabled() || !remote_devices_list)
-      remote_devices_list = &empty_list;
-
-    UserSessionManager::GetInstance()->GetEasyUnlockKeyManager()->RefreshKeys(
-        *short_lived_user_context_->user_context(),
-        base::ListValue(remote_devices_list->GetList()),
-        base::Bind(&EasyUnlockServiceRegular::SetHardlockAfterKeyOperation,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   EasyUnlockScreenlockStateHandler::NO_HARDLOCK));
-  } else {
-    CheckCryptohomeKeysAndMaybeHardlock();
-  }
+  CheckCryptohomeKeysAndMaybeHardlock();
 }
 
 cryptauth::RemoteDeviceRefList EasyUnlockServiceRegular::GetUnlockKeys() {
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.h
index 27d21bb4..633e869 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.h
@@ -15,7 +15,6 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h"
-#include "chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.h"
 #include "chromeos/components/proximity_auth/screenlock_bridge.h"
 #include "chromeos/services/device_sync/public/cpp/device_sync_client.h"
 #include "chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client.h"
@@ -111,7 +110,6 @@
 
   void OnWillFinalizeUnlock(bool success) override;
   void OnSuspendDoneInternal() override;
-  void HandleUserReauth(const UserContext& user_context) override;
 
   // CryptAuthDeviceManager::Observer:
   void OnSyncStarted() override;
@@ -151,8 +149,6 @@
       EasyUnlockScreenlockStateHandler::HardlockState state_on_success,
       bool success);
 
-  std::unique_ptr<ShortLivedUserContext> short_lived_user_context_;
-
   // Returns the CryptAuthEnrollmentManager, which manages the profile's
   // CryptAuth enrollment.
   cryptauth::CryptAuthEnrollmentManager* GetCryptAuthEnrollmentManager();
diff --git a/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc b/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc
deleted file mode 100644
index 10b3dfb6..0000000
--- a/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.h"
-
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/task_runner.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chromeos/login/auth/user_context.h"
-
-namespace chromeos {
-
-namespace {
-
-// The number of minutes that the user context will be stored.
-const int64_t kUserContextTimeToLiveMinutes = 10;
-
-}  // namespace
-
-ShortLivedUserContext::ShortLivedUserContext(
-    const UserContext& user_context,
-    apps::AppLifetimeMonitor* app_lifetime_monitor,
-    base::TaskRunner* task_runner)
-    : user_context_(new UserContext(user_context)),
-      app_lifetime_monitor_(app_lifetime_monitor),
-      weak_ptr_factory_(this) {
-  app_lifetime_monitor_->AddObserver(this);
-
-  task_runner->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&ShortLivedUserContext::Reset,
-                     weak_ptr_factory_.GetWeakPtr()),
-      base::TimeDelta::FromMinutes(kUserContextTimeToLiveMinutes));
-}
-
-ShortLivedUserContext::~ShortLivedUserContext() {
-  Reset();
-}
-
-void ShortLivedUserContext::Reset() {
-  if (user_context_.get()) {
-    user_context_->ClearSecrets();
-    user_context_.reset();
-    app_lifetime_monitor_->RemoveObserver(this);
-  }
-}
-
-void ShortLivedUserContext::OnAppDeactivated(content::BrowserContext* context,
-                                             const std::string& app_id) {
-  if (app_id == extension_misc::kEasyUnlockAppId)
-    Reset();
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.h b/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.h
deleted file mode 100644
index 774f9bc..0000000
--- a/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_SHORT_LIVED_USER_CONTEXT_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_SHORT_LIVED_USER_CONTEXT_H_
-
-#include <memory>
-
-#include "apps/app_lifetime_monitor.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-
-namespace base {
-class TaskRunner;
-}
-
-namespace chromeos {
-
-class UserContext;
-
-// Stores the UserContext of an authentication operation on the sign-in/lock
-// screen, which is used to generate the keys for Easy Sign-in.
-// The lifetime of the user context is bound the the setup app window. As a
-// fail-safe, the user context will also be deleted after a set period of time
-// in case the app is left open indefintely.
-class ShortLivedUserContext : public apps::AppLifetimeMonitor::Observer {
- public:
-  ShortLivedUserContext(const UserContext& user_context,
-                        apps::AppLifetimeMonitor* app_lifetime_monitor,
-                        base::TaskRunner* task_runner);
-  ~ShortLivedUserContext() override;
-
-  // The UserContext returned here can be NULL if its time-to-live has expired.
-  UserContext* user_context() { return user_context_.get(); }
-
- private:
-  void Reset();
-
-  // apps::AppLifetimeMonitor::Observer:
-  void OnAppDeactivated(content::BrowserContext* context,
-                        const std::string& app_id) override;
-
-  std::unique_ptr<UserContext> user_context_;
-
-  apps::AppLifetimeMonitor* app_lifetime_monitor_;
-
-  base::WeakPtrFactory<ShortLivedUserContext> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShortLivedUserContext);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_SHORT_LIVED_USER_CONTEXT_H_
diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc
index cc9c50f..feb98e9 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector.cc
@@ -550,6 +550,7 @@
   // be stored.
   void AddActivityPeriod(Time start,
                          Time end,
+                         Time now,
                          const std::string& active_user_email);
 
   // Clears stored activity periods outside of storage range defined by
@@ -585,7 +586,9 @@
   void ProcessActivityPeriods(const base::DictionaryValue& activity_times,
                               const std::vector<std::string>& reporting_users,
                               base::DictionaryValue* const filtered_times);
-  void StoreChildScreenTime(Time activity_day_start, TimeDelta activity);
+  void StoreChildScreenTime(Time activity_day_start,
+                            TimeDelta activity,
+                            Time now);
 
   // Determine the day key (milliseconds since epoch for corresponding
   // |day_start_| in UTC) for a given |timestamp|.
@@ -651,6 +654,7 @@
 void DeviceStatusCollector::ActivityStorage::AddActivityPeriod(
     Time start,
     Time end,
+    Time now,
     const std::string& active_user_email) {
   DCHECK(start <= end);
 
@@ -676,7 +680,7 @@
     if (user_manager::UserManager::Get()->IsLoggedInAsChildUser() &&
         !is_enterprise_reporting_) {
       StoreChildScreenTime(day_start - TimeDelta::FromDays(1),
-                           TimeDelta::FromMilliseconds(activity));
+                           TimeDelta::FromMilliseconds(activity), now);
     }
 
     start = day_start;
@@ -832,22 +836,30 @@
 
 void DeviceStatusCollector::ActivityStorage::StoreChildScreenTime(
     Time activity_day_start,
-    TimeDelta activity) {
+    TimeDelta activity,
+    Time now) {
   DCHECK(user_manager::UserManager::Get()->IsLoggedInAsChildUser() &&
          !is_enterprise_reporting_);
 
   // Today's start time.
-  Time today_start = Time::Now().LocalMidnight() + day_start_;
+  Time today_start = now.LocalMidnight() + day_start_;
+  if (today_start > now)
+    today_start -= TimeDelta::FromDays(1);
+
+  // The activity windows always start and end on the reset time of two
+  // consecutive days, so it is not possible to have a window starting after
+  // the current day's reset time.
+  DCHECK(activity_day_start <= today_start);
 
   TimeDelta previous_activity = TimeDelta::FromMilliseconds(
       pref_service_->GetInteger(prefs::kChildScreenTimeMilliseconds));
 
   // If this activity window belongs to the current day, the screen time pref
   // should be updated.
-  if (activity_day_start >= today_start) {
+  if (activity_day_start == today_start) {
     pref_service_->SetInteger(prefs::kChildScreenTimeMilliseconds,
                               (previous_activity + activity).InMilliseconds());
-    pref_service_->SetTime(prefs::kLastChildScreenTimeSaved, Time::Now());
+    pref_service_->SetTime(prefs::kLastChildScreenTimeSaved, now);
   }
   pref_service_->CommitPendingWrite();
 }
@@ -1112,10 +1124,11 @@
     if (active_seconds < 0 ||
         active_seconds >= static_cast<int>((2 * kIdlePollIntervalSeconds))) {
       activity_storage_->AddActivityPeriod(
-          now - TimeDelta::FromSeconds(kIdlePollIntervalSeconds), now,
+          now - TimeDelta::FromSeconds(kIdlePollIntervalSeconds), now, now,
           user_email);
     } else {
-      activity_storage_->AddActivityPeriod(last_idle_check_, now, user_email);
+      activity_storage_->AddActivityPeriod(last_idle_check_, now, now,
+                                           user_email);
     }
 
     activity_storage_->PruneActivityPeriods(
@@ -1162,16 +1175,13 @@
     return;
   }
 
-  if (last_active_check_.is_null()) {
-    last_active_check_ = GetCurrentTime();
-    return;
-  }
-
   // Only child accounts should be using this method.
   CHECK(user_manager::UserManager::Get()->IsLoggedInAsChildUser());
 
   Time now = GetCurrentTime();
   Time reset_time = now.LocalMidnight() + activity_day_start_;
+  if (reset_time > now)
+    reset_time -= TimeDelta::FromDays(1);
   // Reset screen time if it has not been reset today.
   if (reset_time > pref_service_->GetTime(prefs::kLastChildScreenTimeReset)) {
     pref_service_->SetTime(prefs::kLastChildScreenTimeReset, now);
@@ -1179,8 +1189,8 @@
     pref_service_->CommitPendingWrite();
   }
 
-  if (last_state_active_) {
-    activity_storage_->AddActivityPeriod(last_active_check_, now,
+  if (!last_active_check_.is_null() && last_state_active_) {
+    activity_storage_->AddActivityPeriod(last_active_check_, now, now,
                                          GetUserForActivityReporting());
 
     activity_storage_->PruneActivityPeriods(
diff --git a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
index ae4f546..fa348c4 100644
--- a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
@@ -94,6 +94,9 @@
 // Time delta representing midnight 00:00.
 constexpr TimeDelta kMidnight;
 
+// Time delta representing 06:00AM.
+constexpr TimeDelta kSixAm = TimeDelta::FromHours(6);
+
 // Time delta representing 1 hour time interval.
 constexpr TimeDelta kHour = TimeDelta::FromHours(1);
 
@@ -496,13 +499,13 @@
       const policy::DeviceStatusCollector::CPUTempFetcher& cpu_temp_fetcher,
       const policy::DeviceStatusCollector::AndroidStatusFetcher&
           android_status_fetcher,
-      const policy::DeviceStatusCollector::TpmStatusFetcher&
-          tpm_status_fetcher) {
+      const policy::DeviceStatusCollector::TpmStatusFetcher& tpm_status_fetcher,
+      const TimeDelta activity_day_start = kMidnight) {
     std::vector<em::VolumeInfo> expected_volume_info;
     status_collector_.reset(new TestingDeviceStatusCollector(
         &local_state_, &fake_statistics_provider_, volume_info, cpu_stats,
-        cpu_temp_fetcher, android_status_fetcher, tpm_status_fetcher, kMidnight,
-        true /* is_enterprise_device */));
+        cpu_temp_fetcher, android_status_fetcher, tpm_status_fetcher,
+        activity_day_start, true /* is_enterprise_device */));
   }
 
   void GetStatus() {
@@ -2371,30 +2374,41 @@
       const policy::DeviceStatusCollector::CPUTempFetcher& cpu_temp_fetcher,
       const policy::DeviceStatusCollector::AndroidStatusFetcher&
           android_status_fetcher,
-      const policy::DeviceStatusCollector::TpmStatusFetcher& tpm_status_fetcher)
-      override {
+      const policy::DeviceStatusCollector::TpmStatusFetcher& tpm_status_fetcher,
+      const TimeDelta activity_day_start = kMidnight) override {
     status_collector_ = std::make_unique<TestingDeviceStatusCollector>(
         &profile_pref_service_, &fake_statistics_provider_, volume_info,
         cpu_stats, cpu_temp_fetcher, android_status_fetcher, tpm_status_fetcher,
-        kMidnight, false /* is_enterprise_reporting */);
+        activity_day_start, false /* is_enterprise_reporting */);
+  }
+
+  void ExpectChildScreenTimeMilliseconds(int64_t duration) {
+    profile_pref_service_.CommitPendingWrite(
+        base::OnceClosure(),
+        base::BindOnce(
+            [](int64_t duration,
+               TestingPrefServiceSimple* profile_pref_service_) {
+              EXPECT_EQ(duration, profile_pref_service_->GetInteger(
+                                      prefs::kChildScreenTimeMilliseconds));
+            },
+            duration, &profile_pref_service_));
+  }
+
+  void ExpectLastChildScreenTimeReset(Time time) {
+    profile_pref_service_.CommitPendingWrite(
+        base::OnceClosure(),
+        base::BindOnce(
+            [](Time time, TestingPrefServiceSimple* profile_pref_service_) {
+              EXPECT_EQ(time, profile_pref_service_->GetTime(
+                                  prefs::kLastChildScreenTimeReset));
+            },
+            time, &profile_pref_service_));
   }
 
   AccountId user_account_id_;
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-void expectChildScreenTimeMilliseconds(int64_t duration,
-                                       TestingPrefServiceSimple* pref_service) {
-  pref_service->CommitPendingWrite(
-      base::OnceClosure(),
-      base::BindOnce(
-          [](int64_t duration, TestingPrefServiceSimple* pref_service) {
-            EXPECT_EQ(duration, pref_service->GetInteger(
-                                    prefs::kChildScreenTimeMilliseconds));
-          },
-          duration, pref_service));
-}
-
 TEST_F(ConsumerDeviceStatusCollectorTimeLimitDisabledTest, ReportingBootMode) {
   fake_statistics_provider_.SetMachineStatistic(
       chromeos::system::kDevSwitchBootKey,
@@ -2594,8 +2608,7 @@
   ASSERT_EQ(1, device_status_.active_period_size());
   EXPECT_EQ(5 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
-  expectChildScreenTimeMilliseconds(5 * ActivePeriodMilliseconds(),
-                                    &profile_pref_service_);
+  ExpectChildScreenTimeMilliseconds(5 * ActivePeriodMilliseconds());
   EXPECT_EQ(user_account_id_.GetUserEmail(),
             device_status_.active_period(0).user_email());
 }
@@ -2619,8 +2632,7 @@
   ASSERT_EQ(1, device_status_.active_period_size());
   EXPECT_EQ(4 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
-  expectChildScreenTimeMilliseconds(4 * ActivePeriodMilliseconds(),
-                                    &profile_pref_service_);
+  ExpectChildScreenTimeMilliseconds(4 * ActivePeriodMilliseconds());
   EXPECT_EQ(user_account_id_.GetUserEmail(),
             device_status_.active_period(0).user_email());
 }
@@ -2646,8 +2658,7 @@
   ASSERT_EQ(1, device_status_.active_period_size());
   EXPECT_EQ(5 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
-  expectChildScreenTimeMilliseconds(5 * ActivePeriodMilliseconds(),
-                                    &profile_pref_service_);
+  ExpectChildScreenTimeMilliseconds(5 * ActivePeriodMilliseconds());
   EXPECT_EQ(user_account_id_.GetUserEmail(),
             device_status_.active_period(0).user_email());
 }
@@ -2688,8 +2699,7 @@
   GetStatus();
   EXPECT_EQ(12 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
-  expectChildScreenTimeMilliseconds(12 * ActivePeriodMilliseconds(),
-                                    &profile_pref_service_);
+  ExpectChildScreenTimeMilliseconds(12 * ActivePeriodMilliseconds());
 }
 
 // Fails on all chromeos builders https://crbug.com/891573
@@ -2715,13 +2725,42 @@
   EXPECT_EQ(1, device_status_.active_period_size());
   EXPECT_EQ(5 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
-  expectChildScreenTimeMilliseconds(5 * ActivePeriodMilliseconds(),
-                                    &profile_pref_service_);
+  ExpectChildScreenTimeMilliseconds(5 * ActivePeriodMilliseconds());
   // Nothing should be written to local state, because it is only used for
   // enterprise reporting.
   EXPECT_TRUE(local_state_.GetDictionary(prefs::kDeviceActivityTimes)->empty());
 }
 
+TEST_F(ConsumerDeviceStatusCollectorTimeLimitEnabledTest, BeforeDayStart) {
+  RestartStatusCollector(base::BindRepeating(&GetEmptyVolumeInfo),
+                         base::BindRepeating(&GetEmptyCPUStatistics),
+                         base::BindRepeating(&GetEmptyCPUTempInfo),
+                         base::BindRepeating(&GetEmptyAndroidStatus),
+                         base::BindRepeating(&GetEmptyTpmStatus), kSixAm);
+  // 04:00 AM
+  Time initial_time = Time::Now().LocalMidnight() + TimeDelta::FromHours(4);
+  status_collector_->SetBaselineTime(initial_time);
+  EXPECT_TRUE(
+      profile_pref_service_.GetDictionary(prefs::kUserActivityTimes)->empty());
+
+  DeviceStateTransitions test_states[] = {
+      DeviceStateTransitions::kEnterSessionActive,
+      DeviceStateTransitions::kLeaveSessionActive,
+      DeviceStateTransitions::kEnterSessionActive,
+      DeviceStateTransitions::kPeriodicCheckTriggered,
+      DeviceStateTransitions::kPeriodicCheckTriggered,
+      DeviceStateTransitions::kLeaveSessionActive};
+  SimulateStateChanges(test_states,
+                       sizeof(test_states) / sizeof(DeviceStateTransitions));
+  GetStatus();
+  // 4 is the number of states yielding an active period with duration of
+  // ActivePeriodMilliseconds
+  EXPECT_EQ(4 * ActivePeriodMilliseconds(),
+            GetActiveMilliseconds(device_status_));
+  ExpectChildScreenTimeMilliseconds(4 * ActivePeriodMilliseconds());
+  ExpectLastChildScreenTimeReset(initial_time);
+}
+
 TEST_F(ConsumerDeviceStatusCollectorTimeLimitEnabledTest,
        ActivityCrossingMidnight) {
   DeviceStateTransitions test_states[] = {
@@ -2732,7 +2771,6 @@
   // split between two days.
   status_collector_->SetBaselineTime(Time::Now().LocalMidnight() -
                                      TimeDelta::FromSeconds(15));
-
   SimulateStateChanges(test_states,
                        sizeof(test_states) / sizeof(DeviceStateTransitions));
   GetStatus();
@@ -2753,8 +2791,7 @@
             kMillisecondsPerDay);
   EXPECT_EQ(time_period1.end_timestamp() - time_period1.start_timestamp(),
             kMillisecondsPerDay);
-  expectChildScreenTimeMilliseconds(0.5 * ActivePeriodMilliseconds(),
-                                    &profile_pref_service_);
+  ExpectChildScreenTimeMilliseconds(0.5 * ActivePeriodMilliseconds());
 }
 
 }  // namespace policy
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc
index 68e0838..aa43289 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings.cc
@@ -201,13 +201,12 @@
     int render_process_id,
     int render_frame_id,
     const GURL& url,
-    const base::string16& description,
     bool blocked_by_policy) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   TabSpecificContentSettings* settings = GetForFrame(
       render_process_id, render_frame_id);
   if (settings)
-    settings->OnIndexedDBAccessed(url, description, blocked_by_policy);
+    settings->OnIndexedDBAccessed(url, blocked_by_policy);
 }
 
 // static
@@ -440,17 +439,13 @@
   NotifySiteDataObservers();
 }
 
-void TabSpecificContentSettings::OnIndexedDBAccessed(
-    const GURL& url,
-    const base::string16& description,
-    bool blocked_by_policy) {
+void TabSpecificContentSettings::OnIndexedDBAccessed(const GURL& url,
+                                                     bool blocked_by_policy) {
   if (blocked_by_policy) {
-    blocked_local_shared_objects_.indexed_dbs()->AddIndexedDB(
-        url, description);
+    blocked_local_shared_objects_.indexed_dbs()->AddIndexedDB(url);
     OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
   } else {
-    allowed_local_shared_objects_.indexed_dbs()->AddIndexedDB(
-        url, description);
+    allowed_local_shared_objects_.indexed_dbs()->AddIndexedDB(url);
     OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
   }
 
@@ -730,24 +725,6 @@
   OnContentBlocked(CONTENT_SETTINGS_TYPE_SOUND);
 }
 
-void TabSpecificContentSettings::OnFramebustBlocked(
-    const GURL& blocked_url,
-    FramebustBlockTabHelper::ClickCallback click_callback) {
-#if !defined(OS_ANDROID)
-  FramebustBlockTabHelper* framebust_block_tab_helper =
-      FramebustBlockTabHelper::FromWebContents(web_contents());
-  if (!framebust_block_tab_helper)
-    return;
-
-  framebust_block_tab_helper->AddBlockedUrl(blocked_url,
-                                            std::move(click_callback));
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      content::Source<WebContents>(web_contents()),
-      content::NotificationService::NoDetails());
-#endif  // !defined(OS_ANDROID)
-}
-
 void TabSpecificContentSettings::SetPepperBrokerAllowed(bool allowed) {
   if (allowed) {
     OnContentAllowed(CONTENT_SETTINGS_TYPE_PPAPI_BROKER);
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.h b/chrome/browser/content_settings/tab_specific_content_settings.h
index b1b7759..a89e258 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.h
+++ b/chrome/browser/content_settings/tab_specific_content_settings.h
@@ -17,7 +17,6 @@
 #include "base/scoped_observer.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/local_shared_objects_container.h"
-#include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h"
 #include "chrome/common/custom_handlers/protocol_handler.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/browser/content_settings_usages_state.h"
@@ -147,7 +146,6 @@
   static void IndexedDBAccessed(int render_process_id,
                                 int render_frame_id,
                                 const GURL& url,
-                                const base::string16& description,
                                 bool blocked_by_policy);
 
   // Called when a specific file system in the current page was accessed.
@@ -199,13 +197,6 @@
   // Called when audio has been blocked on the page.
   void OnAudioBlocked();
 
-  // Updates the blocked framebust icon in the location bar. The
-  // |click_callback| will be called (if it is non-null) if the blocked URL is
-  // ever clicked on in the resulting UI.
-  void OnFramebustBlocked(
-      const GURL& blocked_url,
-      FramebustBlockTabHelper::ClickCallback click_callback);
-
   // Returns whether a particular kind of content has been blocked for this
   // page.
   bool IsContentBlocked(ContentSettingsType content_type) const;
@@ -334,9 +325,7 @@
                       bool blocked_by_policy);
   void OnFileSystemAccessed(const GURL& url,
                             bool blocked_by_policy);
-  void OnIndexedDBAccessed(const GURL& url,
-                           const base::string16& description,
-                           bool blocked_by_policy);
+  void OnIndexedDBAccessed(const GURL& url, bool blocked_by_policy);
   void OnLocalStorageAccessed(const GURL& url,
                               bool local,
                               bool blocked_by_policy);
diff --git a/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc b/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc
index 61acd0301..e7a337a 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc
@@ -264,7 +264,6 @@
   content_settings->OnFileSystemAccessed(GURL("http://google.com"),
                                               blocked_by_policy);
   content_settings->OnIndexedDBAccessed(GURL("http://google.com"),
-                                        base::UTF8ToUTF16("text"),
                                         blocked_by_policy);
   content_settings->OnLocalStorageAccessed(GURL("http://google.com"),
                                            true,
diff --git a/chrome/browser/no_best_effort_tasks_browsertest.cc b/chrome/browser/no_best_effort_tasks_browsertest.cc
index 41fc615..ef89781 100644
--- a/chrome/browser/no_best_effort_tasks_browsertest.cc
+++ b/chrome/browser/no_best_effort_tasks_browsertest.cc
@@ -12,32 +12,47 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
-class RunLoopUntilNonEmptyPaint : public content::WebContentsObserver {
+class RunLoopUntilLoadedAndPainted : public content::WebContentsObserver {
  public:
-  explicit RunLoopUntilNonEmptyPaint(content::WebContents* web_contents)
+  explicit RunLoopUntilLoadedAndPainted(content::WebContents* web_contents)
       : content::WebContentsObserver(web_contents) {}
 
-  ~RunLoopUntilNonEmptyPaint() override = default;
+  ~RunLoopUntilLoadedAndPainted() override = default;
 
   // Runs a RunLoop on the main thread until the first non-empty frame is
-  // painted for the WebContents provided to the constructor.
-  void RunUntilNonEmptyPaint() {
-    if (web_contents()->CompletedFirstVisuallyNonEmptyPaint())
+  // painted and the load is complete for the WebContents provided to the
+  // constructor.
+  void Run() {
+    if (LoadedAndPainted())
       return;
+
     run_loop_.Run();
   }
 
  private:
+  bool LoadedAndPainted() {
+    return web_contents()->CompletedFirstVisuallyNonEmptyPaint() &&
+           !web_contents()->IsLoading();
+  }
+
   // content::WebContentsObserver:
-  void DidFirstVisuallyNonEmptyPaint() override { run_loop_.Quit(); }
+  void DidFirstVisuallyNonEmptyPaint() override {
+    if (LoadedAndPainted())
+      run_loop_.Quit();
+  }
+  void DidStopLoading() override {
+    if (LoadedAndPainted())
+      run_loop_.Quit();
+  }
 
   base::RunLoop run_loop_;
 
-  DISALLOW_COPY_AND_ASSIGN(RunLoopUntilNonEmptyPaint);
+  DISALLOW_COPY_AND_ASSIGN(RunLoopUntilLoadedAndPainted);
 };
 
 class NoBestEffortTasksTest : public InProcessBrowserTest {
@@ -55,22 +70,39 @@
 
 }  // namespace
 
-// Verify that it is possible to get the first non-empty paint without running
-// BEST_EFFORT tasks.
+// Verify that it is possible to load and paint the initial about:blank page
+// without running BEST_EFFORT tasks.
 //
-// TODO(fdoray) https://crbug.com/833989:
-// - Flaky timeout on ChromeOS ASAN
-// - Consistent timeout on Win ASAN
+// TODO(fdoray) https://crbug.com/833989: Times out on Win and ChromeOS ASAN.
 #if defined(ADDRESS_SANITIZER) && (defined(OS_CHROMEOS) || defined(OS_WIN))
-#define MAYBE_FirstNonEmptyPaintWithoutBestEffortTasks \
-  DISABLED_FirstNonEmptyPaintWithoutBestEffortTasks
+#define MAYBE_LoadAndPaintAboutBlank DISABLED_LoadAndPaintAboutBlank
 #else
-#define MAYBE_FirstNonEmptyPaintWithoutBestEffortTasks \
-  FirstNonEmptyPaintWithoutBestEffortTasks
+#define MAYBE_LoadAndPaintAboutBlank LoadAndPaintAboutBlank
 #endif
-IN_PROC_BROWSER_TEST_F(NoBestEffortTasksTest,
-                       MAYBE_FirstNonEmptyPaintWithoutBestEffortTasks) {
-  RunLoopUntilNonEmptyPaint run_loop_until_non_empty_paint(
-      browser()->tab_strip_model()->GetActiveWebContents());
-  run_loop_until_non_empty_paint.RunUntilNonEmptyPaint();
+IN_PROC_BROWSER_TEST_F(NoBestEffortTasksTest, MAYBE_LoadAndPaintAboutBlank) {
+  content::WebContents* const web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(web_contents->GetLastCommittedURL().IsAboutBlank());
+
+  RunLoopUntilLoadedAndPainted run_until_loaded_and_painted(web_contents);
+  run_until_loaded_and_painted.Run();
+}
+
+// Verify that it is possible to load and paint a page from the network without
+// running BEST_EFFORT tasks.
+//
+// This test has more dependencies than LoadAndPaintAboutBlank, including
+// loading cookies.
+IN_PROC_BROWSER_TEST_F(NoBestEffortTasksTest, LoadAndPaintFromNetwork) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  content::OpenURLParams open(
+      embedded_test_server()->GetURL("a.com", "/empty.html"),
+      content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui::PAGE_TRANSITION_TYPED, false);
+  content::WebContents* const web_contents = browser()->OpenURL(open);
+  EXPECT_TRUE(web_contents->IsLoading());
+
+  RunLoopUntilLoadedAndPainted run_until_loaded_and_painted(web_contents);
+  run_until_loaded_and_painted.Run();
 }
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher.cc b/chrome/browser/offline_pages/offline_page_auto_fetcher.cc
index d580da4..b58a9cb 100644
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher.cc
+++ b/chrome/browser/offline_pages/offline_page_auto_fetcher.cc
@@ -4,211 +4,46 @@
 
 #include "chrome/browser/offline_pages/offline_page_auto_fetcher.h"
 
-#include "base/time/time.h"
-#include "chrome/browser/offline_pages/request_coordinator_factory.h"
-#include "components/offline_pages/core/background/request_coordinator.h"
-#include "components/offline_pages/core/background/save_page_request.h"
-#include "components/offline_pages/core/client_id.h"
-#include "components/offline_pages/core/client_namespace_constants.h"
-#include "components/offline_pages/core/offline_page_model.h"
-#include "components/offline_pages/core/offline_store_utils.h"
+#include <utility>
+
+#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service.h"
+#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "url/gurl.h"
 
 namespace offline_pages {
-namespace {
-
-constexpr int kMaximumInFlight = 3;
-
-ClientId URLToClientId(const GURL& url) {
-  // By using namespace.URL as the client ID, we ensure that only a single
-  // request for a page can be in flight.
-
-  // We strip the fragment, because when loading an offline page, only the most
-  // recent page saved with the URL (fragment stripped) can be loaded.
-  GURL::Replacements remove_fragment;
-  remove_fragment.ClearRef();
-  GURL url_to_match = url.ReplaceComponents(remove_fragment);
-
-  return ClientId(kAutoAsyncNamespace, url_to_match.spec());
-}
-
-}  // namespace
-
-// This is an attempt to verify that a task callback eventually calls
-// TaskComplete exactly once. If the token is never std::move'd, it will DCHECK
-// when it is destroyed.
-class OfflinePageAutoFetcher::TaskToken {
- public:
-  // The static methods should only be called by StartOrEnqueue or TaskComplete.
-  static TaskToken NewToken() { return TaskToken(); }
-  static void Finalize(TaskToken& token) { token.alive_ = false; }
-
-  TaskToken(TaskToken&& other) : alive_(other.alive_) {
-    DCHECK(other.alive_);
-    other.alive_ = false;
-  }
-  ~TaskToken() { DCHECK(!alive_); }
-
- private:
-  TaskToken() {}
-
-  bool alive_ = true;
-  DISALLOW_COPY_AND_ASSIGN(TaskToken);
-};
 
 OfflinePageAutoFetcher::OfflinePageAutoFetcher(
-    content::BrowserContext* browser_context)
-    : browser_context_(browser_context) {}
+    content::RenderFrameHost* render_frame_host)
+    : render_frame_host_(render_frame_host) {}
 
 OfflinePageAutoFetcher::~OfflinePageAutoFetcher() = default;
 
 void OfflinePageAutoFetcher::TrySchedule(bool user_requested,
-                                         const GURL& url,
                                          TryScheduleCallback callback) {
-  StartOrEnqueue(base::BindOnce(&OfflinePageAutoFetcher::TryScheduleStep1,
-                                GetWeakPtr(), user_requested, url,
-                                std::move(callback)));
+  GetService()->TrySchedule(user_requested,
+                            render_frame_host_->GetLastCommittedURL(),
+                            std::move(callback));
 }
 
-void OfflinePageAutoFetcher::CancelSchedule(const GURL& url) {
-  StartOrEnqueue(base::BindOnce(&OfflinePageAutoFetcher::CancelScheduleStep1,
-                                GetWeakPtr(), url));
+void OfflinePageAutoFetcher::CancelSchedule() {
+  GetService()->CancelSchedule(render_frame_host_->GetLastCommittedURL());
 }
 
-void OfflinePageAutoFetcher::TryScheduleStep1(bool user_requested,
-                                              const GURL& url,
-                                              TryScheduleCallback callback,
-                                              TaskToken token) {
-  // Return an early failure if the URL is not suitable.
-  if (!OfflinePageModel::CanSaveURL(url)) {
-    std::move(callback).Run(OfflinePageAutoFetcherScheduleResult::kOtherError);
-    TaskComplete(std::move(token));
-    return;
-  }
-
-  // We need to do some checks on in-flight requests before scheduling the
-  // fetch. So first, get the list of all requests, and proceed to step 2.
-  RequestCoordinator* coordinator =
-      RequestCoordinatorFactory::GetForBrowserContext(browser_context_);
-
-  coordinator->GetAllRequests(
-      base::BindOnce(&OfflinePageAutoFetcher::TryScheduleStep2, GetWeakPtr(),
-                     std::move(token), user_requested, url, std::move(callback),
-                     // Unretained is OK because coordinator is calling us back.
-                     base::Unretained(coordinator)));
+// static
+void OfflinePageAutoFetcher::Create(
+    chrome::mojom::OfflinePageAutoFetcherRequest request,
+    content::RenderFrameHost* render_frame_host) {
+  mojo::MakeStrongBinding(
+      std::make_unique<OfflinePageAutoFetcher>(render_frame_host),
+      std::move(request));
 }
 
-void OfflinePageAutoFetcher::TryScheduleStep2(
-    TaskToken token,
-    bool user_requested,
-    const GURL& url,
-    TryScheduleCallback callback,
-    RequestCoordinator* coordinator,
-    std::vector<std::unique_ptr<SavePageRequest>> all_requests) {
-  // If a request for this page is already scheduled, report scheduling as
-  // successful without doing anything.
-  const ClientId url_client_id = URLToClientId(url);
-  for (const auto& request : all_requests) {
-    if (url_client_id == request->client_id()) {
-      std::move(callback).Run(
-          OfflinePageAutoFetcherScheduleResult::kAlreadyScheduled);
-      TaskComplete(std::move(token));
-      return;
-    }
-  }
-
-  // Respect kMaximumInFlight.
-  if (!user_requested) {
-    int in_flight_count = 0;
-    for (const auto& request : all_requests) {
-      if (request->client_id().name_space == kAutoAsyncNamespace) {
-        ++in_flight_count;
-      }
-    }
-    if (in_flight_count >= kMaximumInFlight) {
-      std::move(callback).Run(
-          OfflinePageAutoFetcherScheduleResult::kNotEnoughQuota);
-      TaskComplete(std::move(token));
-      return;
-    }
-  }
-
-  // Finally, schedule a new request, and proceed to step 3.
-  RequestCoordinator::SavePageLaterParams params;
-  params.url = url;
-  params.client_id = url_client_id;
-  params.user_requested = false;
-  params.availability =
-      RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER;
-  coordinator->SavePageLater(
-      params,
-      base::BindOnce(&OfflinePageAutoFetcher::TryScheduleStep3, GetWeakPtr(),
-                     std::move(token), std::move(callback)));
-}
-
-void OfflinePageAutoFetcher::TryScheduleStep3(TaskToken token,
-                                              TryScheduleCallback callback,
-                                              AddRequestResult result) {
-  // Just forward the response to the mojo caller.
-  std::move(callback).Run(
-      result == AddRequestResult::SUCCESS
-          ? OfflinePageAutoFetcherScheduleResult::kScheduled
-          : OfflinePageAutoFetcherScheduleResult::kOtherError);
-  TaskComplete(std::move(token));
-}
-
-void OfflinePageAutoFetcher::CancelScheduleStep1(const GURL& url,
-                                                 TaskToken token) {
-  // Get all requests, and proceed to step 2.
-  RequestCoordinator* coordinator =
-      RequestCoordinatorFactory::GetForBrowserContext(browser_context_);
-  coordinator->GetAllRequests(
-      base::BindOnce(&OfflinePageAutoFetcher::CancelScheduleStep2, GetWeakPtr(),
-                     std::move(token), url, coordinator));
-}
-
-void OfflinePageAutoFetcher::CancelScheduleStep2(
-    TaskToken token,
-    const GURL& url,
-    RequestCoordinator* coordinator,
-    std::vector<std::unique_ptr<SavePageRequest>> requests) {
-  // Cancel the request if it's found in the list of all requests.
-  const ClientId url_client_id = URLToClientId(url);
-  for (const auto& request : requests) {
-    if (url_client_id == request->client_id()) {
-      coordinator->RemoveRequests(
-          {request->request_id()},
-          base::BindOnce(&OfflinePageAutoFetcher::CancelScheduleStep3,
-                         GetWeakPtr(), std::move(token)));
-      return;
-    }
-  }
-  TaskComplete(std::move(token));
-}
-
-void OfflinePageAutoFetcher::CancelScheduleStep3(TaskToken token,
-                                                 const MultipleItemStatuses&) {
-  TaskComplete(std::move(token));
-}
-
-void OfflinePageAutoFetcher::StartOrEnqueue(TaskCallback task) {
-  bool can_run = task_queue_.empty();
-  task_queue_.push(std::move(task));
-  if (can_run)
-    std::move(task_queue_.front()).Run(TaskToken::NewToken());
-}
-
-void OfflinePageAutoFetcher::TaskComplete(TaskToken token) {
-  TaskToken::Finalize(token);
-  DCHECK(!task_queue_.empty());
-  DCHECK(!task_queue_.front());
-  task_queue_.pop();
-  if (!task_queue_.empty())
-    std::move(task_queue_.front()).Run(TaskToken::NewToken());
-}
-
-bool OfflinePageAutoFetcher::IsTaskQueueEmptyForTesting() {
-  return task_queue_.empty();
+OfflinePageAutoFetcherService* OfflinePageAutoFetcher::GetService() {
+  return OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(
+      render_frame_host_->GetProcess()->GetBrowserContext());
 }
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher.h b/chrome/browser/offline_pages/offline_page_auto_fetcher.h
index b24bf735..0f05c5f 100644
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher.h
+++ b/chrome/browser/offline_pages/offline_page_auto_fetcher.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_H_
 
 #include <memory>
+#include <queue>
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
@@ -14,73 +15,31 @@
 #include "components/offline_pages/core/background/save_page_request.h"
 
 namespace content {
-class BrowserContext;
+class RenderFrameHost;
 }
 
 namespace offline_pages {
-class RequestCoordinator;
+class OfflinePageAutoFetcherService;
 
 // Provides control of fetching pages for later in an automatic / quiet way.
-// TODO(crbug.com/883486): This class is not yet used.
 class OfflinePageAutoFetcher : public chrome::mojom::OfflinePageAutoFetcher {
  public:
-  explicit OfflinePageAutoFetcher(content::BrowserContext* browser_context);
+  explicit OfflinePageAutoFetcher(content::RenderFrameHost* render_frame_host);
   ~OfflinePageAutoFetcher() override;
   void TrySchedule(bool user_requested,
-                   const GURL& url,
                    TryScheduleCallback callback) override;
-  void CancelSchedule(const GURL& url) override;
+  void CancelSchedule() override;
 
-  bool IsTaskQueueEmptyForTesting();
+  static void Create(chrome::mojom::OfflinePageAutoFetcherRequest request,
+                     content::RenderFrameHost* render_frame_host);
 
  private:
-  class TaskToken;
-  using TaskCallback = base::OnceCallback<void(TaskToken)>;
+  OfflinePageAutoFetcherService* GetService();
+
   using OfflinePageAutoFetcherScheduleResult =
       chrome::mojom::OfflinePageAutoFetcherScheduleResult;
-  // Task management methods. Each request made to this class is serialized by
-  // appending the tasks as callbacks to task_queue_.
 
-  // Starts or enqueues a new task.
-  void StartOrEnqueue(TaskCallback task);
-  // Reports a task complete. Must be called when the task is completely
-  // finished.
-  void TaskComplete(TaskToken token);
-
-  base::WeakPtr<OfflinePageAutoFetcher> GetWeakPtr() {
-    return weak_ptr_factory_.GetWeakPtr();
-  }
-
-  // Implementation details for public methods.
-
-  void TryScheduleStep1(bool user_requested,
-                        const GURL& url,
-                        TryScheduleCallback callback,
-                        TaskToken token);
-  void TryScheduleStep2(
-      TaskToken token,
-      bool user_requested,
-      const GURL& url,
-      TryScheduleCallback callback,
-      RequestCoordinator* coordinator,
-      std::vector<std::unique_ptr<SavePageRequest>> all_requests);
-  void TryScheduleStep3(TaskToken token,
-                        TryScheduleCallback callback,
-                        AddRequestResult result);
-
-  void CancelScheduleStep1(const GURL& url, TaskToken token);
-  void CancelScheduleStep2(
-      TaskToken token,
-      const GURL& url,
-      RequestCoordinator* coordinator,
-      std::vector<std::unique_ptr<SavePageRequest>> requests);
-  void CancelScheduleStep3(TaskToken token, const MultipleItemStatuses&);
-
-  content::BrowserContext* browser_context_;
-  // TODO(harringtond): Pull out task management into another class, or use
-  // offline_pages::TaskQueue.
-  std::queue<TaskCallback> task_queue_;
-  base::WeakPtrFactory<OfflinePageAutoFetcher> weak_ptr_factory_{this};
+  content::RenderFrameHost* render_frame_host_;
 };
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_service.cc b/chrome/browser/offline_pages/offline_page_auto_fetcher_service.cc
new file mode 100644
index 0000000..4414cc5
--- /dev/null
+++ b/chrome/browser/offline_pages/offline_page_auto_fetcher_service.cc
@@ -0,0 +1,210 @@
+// 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/offline_pages/offline_page_auto_fetcher_service.h"
+
+#include "base/time/time.h"
+#include "chrome/browser/offline_pages/request_coordinator_factory.h"
+#include "components/offline_pages/core/background/request_coordinator.h"
+#include "components/offline_pages/core/background/save_page_request.h"
+#include "components/offline_pages/core/client_id.h"
+#include "components/offline_pages/core/client_namespace_constants.h"
+#include "components/offline_pages/core/offline_page_model.h"
+#include "components/offline_pages/core/offline_store_utils.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+namespace {
+constexpr int kMaximumInFlight = 3;
+
+ClientId URLToClientId(const GURL& url) {
+  // By using namespace.URL as the client ID, we ensure that only a single
+  // request for a page can be in flight.
+
+  // We strip the fragment, because when loading an offline page, only the most
+  // recent page saved with the URL (fragment stripped) can be loaded.
+  GURL::Replacements remove_fragment;
+  remove_fragment.ClearRef();
+  GURL url_to_match = url.ReplaceComponents(remove_fragment);
+
+  return ClientId(kAutoAsyncNamespace, url_to_match.spec());
+}
+}  // namespace
+
+// This is an attempt to verify that a task callback eventually calls
+// TaskComplete exactly once. If the token is never std::move'd, it will DCHECK
+// when it is destroyed.
+class OfflinePageAutoFetcherService::TaskToken {
+ public:
+  // The static methods should only be called by StartOrEnqueue or TaskComplete.
+  static TaskToken NewToken() { return TaskToken(); }
+  static void Finalize(TaskToken& token) { token.alive_ = false; }
+
+  TaskToken(TaskToken&& other) : alive_(other.alive_) {
+    DCHECK(other.alive_);
+    other.alive_ = false;
+  }
+  ~TaskToken() { DCHECK(!alive_); }
+
+ private:
+  TaskToken() {}
+
+  bool alive_ = true;
+  DISALLOW_COPY_AND_ASSIGN(TaskToken);
+};
+
+OfflinePageAutoFetcherService::OfflinePageAutoFetcherService(
+    RequestCoordinator* request_coordinator)
+    : request_coordinator_(request_coordinator) {}
+OfflinePageAutoFetcherService::~OfflinePageAutoFetcherService() {}
+
+void OfflinePageAutoFetcherService::TrySchedule(bool user_requested,
+                                                const GURL& url,
+                                                TryScheduleCallback callback) {
+  StartOrEnqueue(
+      base::BindOnce(&OfflinePageAutoFetcherService::TryScheduleStep1,
+                     GetWeakPtr(), user_requested, url, std::move(callback)));
+}
+
+void OfflinePageAutoFetcherService::CancelSchedule(const GURL& url) {
+  StartOrEnqueue(base::BindOnce(
+      &OfflinePageAutoFetcherService::CancelScheduleStep1, GetWeakPtr(), url));
+}
+
+void OfflinePageAutoFetcherService::TryScheduleStep1(
+    bool user_requested,
+    const GURL& url,
+    TryScheduleCallback callback,
+    TaskToken token) {
+  // Return an early failure if the URL is not suitable.
+  if (!OfflinePageModel::CanSaveURL(url)) {
+    std::move(callback).Run(OfflinePageAutoFetcherScheduleResult::kOtherError);
+    TaskComplete(std::move(token));
+    return;
+  }
+
+  // We need to do some checks on in-flight requests before scheduling the
+  // fetch. So first, get the list of all requests, and proceed to step 2.
+  request_coordinator_->GetAllRequests(base::BindOnce(
+      &OfflinePageAutoFetcherService::TryScheduleStep2, GetWeakPtr(),
+      std::move(token), user_requested, url, std::move(callback),
+      // Unretained is OK because coordinator is calling us back.
+      base::Unretained(request_coordinator_)));
+}
+
+void OfflinePageAutoFetcherService::TryScheduleStep2(
+    TaskToken token,
+    bool user_requested,
+    const GURL& url,
+    TryScheduleCallback callback,
+    RequestCoordinator* coordinator,
+    std::vector<std::unique_ptr<SavePageRequest>> all_requests) {
+  // If a request for this page is already scheduled, report scheduling as
+  // successful without doing anything.
+  const ClientId url_client_id = URLToClientId(url);
+  for (const auto& request : all_requests) {
+    if (url_client_id == request->client_id()) {
+      std::move(callback).Run(
+          OfflinePageAutoFetcherScheduleResult::kAlreadyScheduled);
+      TaskComplete(std::move(token));
+      return;
+    }
+  }
+
+  // Respect kMaximumInFlight.
+  if (!user_requested) {
+    int in_flight_count = 0;
+    for (const auto& request : all_requests) {
+      if (request->client_id().name_space == kAutoAsyncNamespace) {
+        ++in_flight_count;
+      }
+    }
+    if (in_flight_count >= kMaximumInFlight) {
+      std::move(callback).Run(
+          OfflinePageAutoFetcherScheduleResult::kNotEnoughQuota);
+      TaskComplete(std::move(token));
+      return;
+    }
+  }
+
+  // Finally, schedule a new request, and proceed to step 3.
+  RequestCoordinator::SavePageLaterParams params;
+  params.url = url;
+  params.client_id = url_client_id;
+  params.user_requested = false;
+  params.availability =
+      RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER;
+  coordinator->SavePageLater(
+      params,
+      base::BindOnce(&OfflinePageAutoFetcherService::TryScheduleStep3,
+                     GetWeakPtr(), std::move(token), std::move(callback)));
+}
+
+void OfflinePageAutoFetcherService::TryScheduleStep3(
+    TaskToken token,
+    TryScheduleCallback callback,
+    AddRequestResult result) {
+  // Just forward the response to the mojo caller.
+  std::move(callback).Run(
+      result == AddRequestResult::SUCCESS
+          ? OfflinePageAutoFetcherScheduleResult::kScheduled
+          : OfflinePageAutoFetcherScheduleResult::kOtherError);
+  TaskComplete(std::move(token));
+}
+
+void OfflinePageAutoFetcherService::CancelScheduleStep1(const GURL& url,
+                                                        TaskToken token) {
+  // Get all requests, and proceed to step 2.
+  request_coordinator_->GetAllRequests(base::BindOnce(
+      &OfflinePageAutoFetcherService::CancelScheduleStep2, GetWeakPtr(),
+      std::move(token), url, request_coordinator_));
+}
+
+void OfflinePageAutoFetcherService::CancelScheduleStep2(
+    TaskToken token,
+    const GURL& url,
+    RequestCoordinator* coordinator,
+    std::vector<std::unique_ptr<SavePageRequest>> requests) {
+  // Cancel the request if it's found in the list of all requests.
+  const ClientId url_client_id = URLToClientId(url);
+  for (const auto& request : requests) {
+    if (url_client_id == request->client_id()) {
+      coordinator->RemoveRequests(
+          {request->request_id()},
+          base::BindOnce(&OfflinePageAutoFetcherService::CancelScheduleStep3,
+                         GetWeakPtr(), std::move(token)));
+      return;
+    }
+  }
+  TaskComplete(std::move(token));
+}
+
+void OfflinePageAutoFetcherService::CancelScheduleStep3(
+    TaskToken token,
+    const MultipleItemStatuses&) {
+  TaskComplete(std::move(token));
+}
+
+void OfflinePageAutoFetcherService::StartOrEnqueue(TaskCallback task) {
+  bool can_run = task_queue_.empty();
+  task_queue_.push(std::move(task));
+  if (can_run)
+    std::move(task_queue_.front()).Run(TaskToken::NewToken());
+}
+
+void OfflinePageAutoFetcherService::TaskComplete(TaskToken token) {
+  TaskToken::Finalize(token);
+  DCHECK(!task_queue_.empty());
+  DCHECK(!task_queue_.front());
+  task_queue_.pop();
+  if (!task_queue_.empty())
+    std::move(task_queue_.front()).Run(TaskToken::NewToken());
+}
+
+bool OfflinePageAutoFetcherService::IsTaskQueueEmptyForTesting() {
+  return task_queue_.empty();
+}
+
+}  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_service.h b/chrome/browser/offline_pages/offline_page_auto_fetcher_service.h
new file mode 100644
index 0000000..2fb2e95
--- /dev/null
+++ b/chrome/browser/offline_pages/offline_page_auto_fetcher_service.h
@@ -0,0 +1,97 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
+#define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/common/offline_page_auto_fetcher.mojom.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/offline_pages/core/background/request_queue_results.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+class RequestCoordinator;
+class SavePageRequest;
+
+class OfflinePageAutoFetcherService : public KeyedService {
+ public:
+  using OfflinePageAutoFetcherScheduleResult =
+      chrome::mojom::OfflinePageAutoFetcherScheduleResult;
+  using TryScheduleCallback = base::OnceCallback<void(
+      chrome::mojom::OfflinePageAutoFetcherScheduleResult)>;
+
+  explicit OfflinePageAutoFetcherService(
+      RequestCoordinator* request_coordinator);
+  ~OfflinePageAutoFetcherService() override;
+
+  // Auto fetching interface. Schedules and cancels fetch requests.
+
+  void TrySchedule(bool user_requested,
+                   const GURL& url,
+                   TryScheduleCallback callback);
+  void CancelSchedule(const GURL& url);
+
+  // KeyedService implementation.
+
+  void Shutdown() override {}
+
+  // Testing methods.
+  bool IsTaskQueueEmptyForTesting();
+
+ private:
+  class TaskToken;
+  using TaskCallback = base::OnceCallback<void(TaskToken)>;
+
+  base::WeakPtr<OfflinePageAutoFetcherService> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+  // Task management methods. Each request made to this class is serialized by
+  // appending the tasks as callbacks to task_queue_.
+
+  // Starts or enqueues a new task.
+  void StartOrEnqueue(TaskCallback task);
+  // Reports a task complete. Must be called when the task is completely
+  // finished.
+  void TaskComplete(TaskToken token);
+
+  // Implementation details for public methods.
+
+  void TryScheduleStep1(bool user_requested,
+                        const GURL& url,
+                        TryScheduleCallback callback,
+                        TaskToken token);
+  void TryScheduleStep2(
+      TaskToken token,
+      bool user_requested,
+      const GURL& url,
+      TryScheduleCallback callback,
+      RequestCoordinator* coordinator,
+      std::vector<std::unique_ptr<SavePageRequest>> all_requests);
+  void TryScheduleStep3(TaskToken token,
+                        TryScheduleCallback callback,
+                        AddRequestResult result);
+
+  void CancelScheduleStep1(const GURL& url, TaskToken token);
+  void CancelScheduleStep2(
+      TaskToken token,
+      const GURL& url,
+      RequestCoordinator* coordinator,
+      std::vector<std::unique_ptr<SavePageRequest>> requests);
+  void CancelScheduleStep3(TaskToken token, const MultipleItemStatuses&);
+
+  RequestCoordinator* request_coordinator_;
+  // TODO(harringtond): Pull out task management into another class, or use
+  // offline_pages::TaskQueue.
+  std::queue<TaskCallback> task_queue_;
+  base::WeakPtrFactory<OfflinePageAutoFetcherService> weak_ptr_factory_{this};
+};
+
+}  // namespace offline_pages
+#endif  // CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.cc b/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.cc
new file mode 100644
index 0000000..94ca367d
--- /dev/null
+++ b/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.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/offline_pages/offline_page_auto_fetcher_service_factory.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service.h"
+#include "chrome/browser/offline_pages/request_coordinator_factory.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+namespace offline_pages {
+
+// static
+OfflinePageAutoFetcherServiceFactory*
+OfflinePageAutoFetcherServiceFactory::GetInstance() {
+  return base::Singleton<OfflinePageAutoFetcherServiceFactory>::get();
+}
+
+// static
+OfflinePageAutoFetcherService*
+OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return static_cast<OfflinePageAutoFetcherService*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+OfflinePageAutoFetcherServiceFactory::OfflinePageAutoFetcherServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "OfflinePageAutoFetcherService",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(RequestCoordinatorFactory::GetInstance());
+}
+
+OfflinePageAutoFetcherServiceFactory::~OfflinePageAutoFetcherServiceFactory() {}
+
+KeyedService* OfflinePageAutoFetcherServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  RequestCoordinator* coordinator =
+      RequestCoordinatorFactory::GetForBrowserContext(context);
+  return new OfflinePageAutoFetcherService(coordinator);
+}
+
+}  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h b/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h
new file mode 100644
index 0000000..b02ecbd9d
--- /dev/null
+++ b/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h
@@ -0,0 +1,43 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_FACTORY_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "content/public/browser/browser_context.h"
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace offline_pages {
+class OfflinePageAutoFetcherService;
+
+// A factory to create one unique OfflinePageAutoFetcherService.
+class OfflinePageAutoFetcherServiceFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static OfflinePageAutoFetcherServiceFactory* GetInstance();
+  static OfflinePageAutoFetcherService* GetForBrowserContext(
+      content::BrowserContext* context);
+
+ private:
+  friend struct base::DefaultSingletonTraits<
+      OfflinePageAutoFetcherServiceFactory>;
+
+  OfflinePageAutoFetcherServiceFactory();
+  ~OfflinePageAutoFetcherServiceFactory() override;
+
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(OfflinePageAutoFetcherServiceFactory);
+};
+
+}  // namespace offline_pages
+
+#endif  // CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_FACTORY_H_
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_unittest.cc b/chrome/browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc
similarity index 68%
rename from chrome/browser/offline_pages/offline_page_auto_fetcher_unittest.cc
rename to chrome/browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc
index 110190e..d678802 100644
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher_unittest.cc
+++ b/chrome/browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc
@@ -2,16 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher.h"
+#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service.h"
 
 #include "base/bind.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/mock_callback.h"
 #include "chrome/browser/offline_pages/request_coordinator_factory.h"
 #include "chrome/browser/offline_pages/test_request_coordinator_builder.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/offline_pages/core/background/request_coordinator.h"
 #include "components/offline_pages/core/background/test_request_queue_store.h"
+#include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -21,7 +23,7 @@
 using OfflinePageAutoFetcherScheduleResult =
     chrome::mojom::OfflinePageAutoFetcherScheduleResult;
 
-class OfflinePageAutoFetcherTest : public testing::Test {
+class OfflinePageAutoFetcherServiceTest : public testing::Test {
  public:
   void SetUp() override {
     RequestCoordinator* coordinator = static_cast<RequestCoordinator*>(
@@ -29,11 +31,12 @@
             &profile_, base::BindRepeating(&BuildTestRequestCoordinator)));
     queue_store_ = static_cast<TestRequestQueueStore*>(
         coordinator->queue_for_testing()->GetStoreForTesting());
+    service_ = std::make_unique<OfflinePageAutoFetcherService>(coordinator);
   }
 
   void TearDown() override {
     browser_thread_bundle_.RunUntilIdle();
-    ASSERT_TRUE(fetcher_.IsTaskQueueEmptyForTesting());
+    ASSERT_TRUE(service_->IsTaskQueueEmptyForTesting());
   }
 
   TestRequestQueueStore* queue_store() { return queue_store_; }
@@ -59,32 +62,32 @@
   // Owned by the request queue.
   TestRequestQueueStore* queue_store_ = nullptr;
 
-  OfflinePageAutoFetcher fetcher_{&profile_};
+  std::unique_ptr<OfflinePageAutoFetcherService> service_;
 };
 
-TEST_F(OfflinePageAutoFetcherTest, TryScheduleSuccess) {
+TEST_F(OfflinePageAutoFetcherServiceTest, TryScheduleSuccess) {
   base::MockCallback<
       base::OnceCallback<void(OfflinePageAutoFetcherScheduleResult)>>
       result_callback;
   EXPECT_CALL(result_callback,
               Run(OfflinePageAutoFetcherScheduleResult::kScheduled));
-  fetcher_.TrySchedule(false, GURL("http://foo.com"), result_callback.Get());
+  service_->TrySchedule(false, GURL("http://foo.com"), result_callback.Get());
   browser_thread_bundle_.RunUntilIdle();
   EXPECT_EQ(1ul, GetRequestsSync().size());
 }
 
-TEST_F(OfflinePageAutoFetcherTest, AttemptInvalidURL) {
+TEST_F(OfflinePageAutoFetcherServiceTest, AttemptInvalidURL) {
   base::MockCallback<
       base::OnceCallback<void(OfflinePageAutoFetcherScheduleResult)>>
       result_callback;
   EXPECT_CALL(result_callback,
               Run(OfflinePageAutoFetcherScheduleResult::kOtherError));
-  fetcher_.TrySchedule(false, GURL("ftp://foo.com"), result_callback.Get());
+  service_->TrySchedule(false, GURL("ftp://foo.com"), result_callback.Get());
   browser_thread_bundle_.RunUntilIdle();
   EXPECT_EQ(0ul, GetRequestsSync().size());
 }
 
-TEST_F(OfflinePageAutoFetcherTest, TryScheduleDuplicate) {
+TEST_F(OfflinePageAutoFetcherServiceTest, TryScheduleDuplicate) {
   base::MockCallback<
       base::RepeatingCallback<void(OfflinePageAutoFetcherScheduleResult)>>
       result_callback;
@@ -95,13 +98,13 @@
               Run(OfflinePageAutoFetcherScheduleResult::kAlreadyScheduled))
       .Times(1);
   // The page should only be saved once, because the fragment is ignored.
-  fetcher_.TrySchedule(false, GURL("http://foo.com#A"), result_callback.Get());
-  fetcher_.TrySchedule(false, GURL("http://foo.com#Z"), result_callback.Get());
+  service_->TrySchedule(false, GURL("http://foo.com#A"), result_callback.Get());
+  service_->TrySchedule(false, GURL("http://foo.com#Z"), result_callback.Get());
   browser_thread_bundle_.RunUntilIdle();
   EXPECT_EQ(1ul, GetRequestsSync().size());
 }
 
-TEST_F(OfflinePageAutoFetcherTest, AttemptAutoScheduleMoreThanMaximum) {
+TEST_F(OfflinePageAutoFetcherServiceTest, AttemptAutoScheduleMoreThanMaximum) {
   base::MockCallback<
       base::RepeatingCallback<void(OfflinePageAutoFetcherScheduleResult)>>
       result_callback;
@@ -117,51 +120,52 @@
       .Times(1);
 
   // Three requests within quota.
-  fetcher_.TrySchedule(false, GURL("http://foo.com/1"), result_callback.Get());
-  fetcher_.TrySchedule(false, GURL("http://foo.com/2"), result_callback.Get());
-  fetcher_.TrySchedule(false, GURL("http://foo.com/3"), result_callback.Get());
+  service_->TrySchedule(false, GURL("http://foo.com/1"), result_callback.Get());
+  service_->TrySchedule(false, GURL("http://foo.com/2"), result_callback.Get());
+  service_->TrySchedule(false, GURL("http://foo.com/3"), result_callback.Get());
 
   // Quota is exhausted.
-  fetcher_.TrySchedule(false, GURL("http://foo.com/4"), result_callback.Get());
+  service_->TrySchedule(false, GURL("http://foo.com/4"), result_callback.Get());
 
   // User-requested, quota is not enforced.
-  fetcher_.TrySchedule(true, GURL("http://foo.com/5"), result_callback.Get());
+  service_->TrySchedule(true, GURL("http://foo.com/5"), result_callback.Get());
 
   browser_thread_bundle_.RunUntilIdle();
 }
 
-TEST_F(OfflinePageAutoFetcherTest, TryScheduleMoreThanMaximumUserRequested) {
+TEST_F(OfflinePageAutoFetcherServiceTest,
+       TryScheduleMoreThanMaximumUserRequested) {
   base::MockCallback<
       base::RepeatingCallback<void(OfflinePageAutoFetcherScheduleResult)>>
       result_callback;
   EXPECT_CALL(result_callback,
               Run(OfflinePageAutoFetcherScheduleResult::kScheduled))
       .Times(4);
-  fetcher_.TrySchedule(true, GURL("http://foo.com/1"), result_callback.Get());
-  fetcher_.TrySchedule(true, GURL("http://foo.com/2"), result_callback.Get());
-  fetcher_.TrySchedule(true, GURL("http://foo.com/3"), result_callback.Get());
-  fetcher_.TrySchedule(true, GURL("http://foo.com/4"), result_callback.Get());
+  service_->TrySchedule(true, GURL("http://foo.com/1"), result_callback.Get());
+  service_->TrySchedule(true, GURL("http://foo.com/2"), result_callback.Get());
+  service_->TrySchedule(true, GURL("http://foo.com/3"), result_callback.Get());
+  service_->TrySchedule(true, GURL("http://foo.com/4"), result_callback.Get());
   browser_thread_bundle_.RunUntilIdle();
 }
 
-TEST_F(OfflinePageAutoFetcherTest, CancelSuccess) {
-  fetcher_.TrySchedule(false, GURL("http://foo.com"), base::DoNothing());
+TEST_F(OfflinePageAutoFetcherServiceTest, CancelSuccess) {
+  service_->TrySchedule(false, GURL("http://foo.com"), base::DoNothing());
   browser_thread_bundle_.RunUntilIdle();
-  fetcher_.CancelSchedule(GURL("http://foo.com"));
+  service_->CancelSchedule(GURL("http://foo.com"));
   browser_thread_bundle_.RunUntilIdle();
   EXPECT_EQ(0ul, GetRequestsSync().size());
 }
 
-TEST_F(OfflinePageAutoFetcherTest, CancelNotExist) {
-  fetcher_.TrySchedule(false, GURL("http://foo.com"), base::DoNothing());
+TEST_F(OfflinePageAutoFetcherServiceTest, CancelNotExist) {
+  service_->TrySchedule(false, GURL("http://foo.com"), base::DoNothing());
   browser_thread_bundle_.RunUntilIdle();
-  fetcher_.CancelSchedule(GURL("http://NOT-FOO.com"));
+  service_->CancelSchedule(GURL("http://NOT-FOO.com"));
   browser_thread_bundle_.RunUntilIdle();
   EXPECT_EQ(1ul, GetRequestsSync().size());
 }
 
-TEST_F(OfflinePageAutoFetcherTest, CancelQueueEmpty) {
-  fetcher_.CancelSchedule(GURL("http://foo.com"));
+TEST_F(OfflinePageAutoFetcherServiceTest, CancelQueueEmpty) {
+  service_->CancelSchedule(GURL("http://foo.com"));
   browser_thread_bundle_.RunUntilIdle();
 }
 
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index 7452a66..f6a4553 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -284,15 +284,13 @@
 void ChromeRenderMessageFilter::OnAllowIndexedDB(int render_frame_id,
                                                  const GURL& origin_url,
                                                  const GURL& top_origin_url,
-                                                 const base::string16& name,
                                                  bool* allowed) {
   *allowed =
       cookie_settings_->IsCookieAccessAllowed(origin_url, top_origin_url);
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::UI},
       base::Bind(&TabSpecificContentSettings::IndexedDBAccessed,
-                 render_process_id_, render_frame_id, origin_url, name,
-                 !*allowed));
+                 render_process_id_, render_frame_id, origin_url, !*allowed));
 }
 
 #if BUILDFLAG(ENABLE_PLUGINS)
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.h b/chrome/browser/renderer_host/chrome_render_message_filter.h
index e035fe76..9872dcb 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.h
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.h
@@ -94,7 +94,6 @@
   void OnAllowIndexedDB(int render_frame_id,
                         const GURL& origin_url,
                         const GURL& top_origin_url,
-                        const base::string16& name,
                         bool* allowed);
 #if BUILDFLAG(ENABLE_PLUGINS)
   void OnIsCrashReportingEnabled(bool* enabled);
diff --git a/chrome/browser/resource_coordinator/browser_child_process_watcher.cc b/chrome/browser/resource_coordinator/browser_child_process_watcher.cc
index abaca7b..00cf81d09a 100644
--- a/chrome/browser/resource_coordinator/browser_child_process_watcher.cc
+++ b/chrome/browser/resource_coordinator/browser_child_process_watcher.cc
@@ -26,9 +26,7 @@
     gpu_process_resource_coordinator_ =
         std::make_unique<resource_coordinator::ProcessResourceCoordinator>(
             content::ServiceManagerConnection::GetForProcess()->GetConnector());
-
-    gpu_process_resource_coordinator_->SetLaunchTime(base::Time::Now());
-    gpu_process_resource_coordinator_->SetPID(data.GetProcess().Pid());
+    gpu_process_resource_coordinator_->OnProcessLaunched(data.GetProcess());
   }
 }
 
diff --git a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
index 27c18b3..996acee 100644
--- a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
+++ b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
@@ -24,8 +24,7 @@
       std::make_unique<resource_coordinator::ProcessResourceCoordinator>(
           connection->GetConnector());
 
-  process_resource_coordinator_->SetLaunchTime(base::Time::Now());
-  process_resource_coordinator_->SetPID(base::Process::Current().Pid());
+  process_resource_coordinator_->OnProcessLaunched(base::Process::Current());
 
   browser_child_process_watcher_ =
       std::make_unique<resource_coordinator::BrowserChildProcessWatcher>();
diff --git a/chrome/browser/resources/discards/BUILD.gn b/chrome/browser/resources/discards/BUILD.gn
index 78c37d9..82ae6e83 100644
--- a/chrome/browser/resources/discards/BUILD.gn
+++ b/chrome/browser/resources/discards/BUILD.gn
@@ -9,6 +9,8 @@
     ":database_tab",
     ":discards",
     ":discards_tab",
+    ":graph_doc",
+    ":graph_tab",
   ]
 }
 
@@ -50,8 +52,67 @@
   ]
   extra_deps = [ "//chrome/browser/ui/webui/discards:mojo_bindings_js" ]
   externs_list = [
-    "$root_gen_dir/chrome/browser/ui/webui/discards/discards.mojom.externs.js",
-    "$root_gen_dir/chrome/browser/resource_coordinator/lifecycle_unit_state.mojom.externs.js",
     "$externs_path/mojo.js",
+    "$root_gen_dir/chrome/browser/resource_coordinator/lifecycle_unit_state.mojom.externs.js",
+    "$root_gen_dir/chrome/browser/ui/webui/discards/discards.mojom.externs.js",
+  ]
+}
+
+js_library("graph_tab") {
+  deps = [
+    "//ui/webui/resources/js:assert",
+    "//ui/webui/resources/js:cr",
+  ]
+  extra_deps = [
+    "//chrome/browser/ui/webui/discards:mojo_bindings_js",
+    "//mojo/public/mojom/base:base_js",
+    "//services/resource_coordinator/public/mojom:mojom_js",
+  ]
+  externs_list = [
+    "$externs_path/mojo.js",
+    "$root_gen_dir/chrome/browser/resource_coordinator/lifecycle_unit_state.mojom.externs.js",
+    "$root_gen_dir/chrome/browser/ui/webui/discards/discards.mojom.externs.js",
+    "$root_gen_dir/mojo/public/mojom/base/process_id.mojom.externs.js",
+    "$root_gen_dir/mojo/public/mojom/base/time.mojom.externs.js",
+    "$root_gen_dir/services/resource_coordinator/public/mojom/webui_graph_dump.mojom.externs.js",
+  ]
+}
+
+js_library("graph_doc") {
+  extra_deps = [ "//services/resource_coordinator/public/mojom:mojom_js" ]
+
+  externs_list = [
+    "../../../../third_party/d3/src/externs.js",
+    "$root_gen_dir/mojo/public/mojom/base/process_id.mojom.externs.js",
+    "$root_gen_dir/mojo/public/mojom/base/time.mojom.externs.js",
+    "$root_gen_dir/services/resource_coordinator/public/mojom/webui_graph_dump.mojom.externs.js",
+  ]
+}
+
+# This action merges the graph tab script into the graph_doc HTML template.
+# It then base64 encodes the combination, and merges into the graph_tab HTML
+# template to complete the data: URL for the webview therein.
+action("generate_graph_tab") {
+  script = "generate_graph_tab.py"
+  sources = [
+    "graph_doc.js",
+    "graph_doc_template.html",
+    "graph_tab_template.html",
+  ]
+  outputs = [
+    "$target_gen_dir/graph_tab.html",
+  ]
+
+  args = rebase_path(outputs) + rebase_path([
+                                              "graph_doc_template.html",
+                                              "graph_doc.js",
+                                              "graph_tab_template.html",
+                                            ])
+}
+
+# Action with a transparent name.
+group("discards_resources_gen") {
+  deps = [
+    ":generate_graph_tab",
   ]
 }
diff --git a/chrome/browser/resources/discards/discards.html b/chrome/browser/resources/discards/discards.html
index 448866f..9485bfd 100644
--- a/chrome/browser/resources/discards/discards.html
+++ b/chrome/browser/resources/discards/discards.html
@@ -19,6 +19,17 @@
     <script src="mojom/webui_graph_dump.mojom.js"></script>
     <script src="discards.js"></script>
     <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+    <style>
+      html,
+      body {
+        height: 100%;
+        overflow: hidden;
+      }
+
+      body {
+        margin: 0;
+      }
+    </style>
   </head>
   <body>
     <discards-main></discards-main>
diff --git a/chrome/browser/resources/discards/discards_main.html b/chrome/browser/resources/discards/discards_main.html
index 95253c260..2db6164 100644
--- a/chrome/browser/resources/discards/discards_main.html
+++ b/chrome/browser/resources/discards/discards_main.html
@@ -14,18 +14,44 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-tabs/paper-tabs.html">
 <link rel="import" href="database_tab.html">
 <link rel="import" href="discards_tab.html">
+<link rel="import" href="graph_tab.html">
 
 <dom-module id="discards-main">
   <template>
     <style include="paper-tabs-style cr-hidden-style"></style>
+    <style>
+      :host {
+        display: flex;
+        flex-direction: column;
+        height: 100%;
+        overflow: hidden;
+      }
+
+      iron-pages {
+        flex: 1;
+        overflow: hidden;
+      }
+
+      iron-pages > * {
+        display: block;
+        height: 100%;
+        overflow: auto;
+      }
+
+      graph-tab {
+        overflow: hidden;
+      }
+    </style>
     <paper-tabs noink selected="{{selected}}">
       <paper-tab>Discards</paper-tab>
       <paper-tab>Database</paper-tab>
+      <paper-tab>Graph</paper-tab>
     </paper-tabs>
 
     <iron-pages selected="[[selected]]">
       <discards-tab></discards-tab>
       <database-tab></database-tab>
+      <graph-tab></graph-tab>
     </iron-pages>
   </template>
   <script src="discards_main.js"></script>
diff --git a/chrome/browser/resources/discards/generate_graph_tab.py b/chrome/browser/resources/discards/generate_graph_tab.py
new file mode 100644
index 0000000..528e1d8
--- /dev/null
+++ b/chrome/browser/resources/discards/generate_graph_tab.py
@@ -0,0 +1,50 @@
+# 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.
+
+"""Template-combines an HTML and a JSON file and merges them into an output
+file as a data: url."""
+
+import argparse
+import base64
+import os
+import string
+import sys
+
+
+def main():
+  argument_parser = argparse.ArgumentParser()
+  argument_parser.add_argument('output_file', help='The file to write to')
+  argument_parser.add_argument('html_template', help='The HTML template file')
+  argument_parser.add_argument('javascript_file', help='The JS file')
+  argument_parser.add_argument('output_template',
+                               help='The output HTML template file')
+  args = argument_parser.parse_args()
+
+  # Slurp the input files.
+  js_file_contents = open(args.javascript_file, 'r').read();
+  html_template = string.Template(open(args.html_template, 'r').read());
+  output_template = string.Template(open(args.output_template, 'r').read());
+
+  # Stamp the javacript contents into the HTML template.
+  html_doc = html_template.substitute({'javascript_file': js_file_contents});
+
+  # Construct the data: URL that contains the combined doc.
+  data_url = "data:text/html;base64,%s" % base64.b64encode(html_doc);
+
+  # And finally stamp the the data URL into the output template.
+  output = output_template.substitute({'data_url': data_url})
+
+  current_contents = ''
+  if os.path.isfile(args.output_file):
+    with open(args.output_file, 'r') as current_file:
+      current_contents = current_file.read()
+
+  if current_contents != output:
+    with open(args.output_file, 'w') as output_file:
+      output_file.write(output)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/chrome/browser/resources/discards/graph_doc.js b/chrome/browser/resources/discards/graph_doc.js
new file mode 100644
index 0000000..aa34b69
--- /dev/null
+++ b/chrome/browser/resources/discards/graph_doc.js
@@ -0,0 +1,70 @@
+// 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.
+
+class Graph {
+  /**
+   * TODO(siggi): This should be SVGElement, but closure doesn't have externs
+   *    for this yet.
+   * @param {Element} svg
+   */
+  constructor(svg) {
+    /**
+     * TODO(siggi): SVGElement.
+     * @private {Element}
+     */
+    this.svg_ = svg;
+
+    /** @private {number} */
+    this.width_ = 100;
+    /** @private {number} */
+    this.height_ = 100;
+  }
+
+  initialize() {
+    // Set up a message listener to receive the graph data from the WebUI.
+    // This is hosted in a webview that is never navigated anywhere else,
+    // so these event handlers are never removed.
+    window.addEventListener('message', (graph) => {
+      this.onMessage_(graph);
+    }, false);
+
+    // Set up a window resize listener to track the graph on resize.
+    window.addEventListener('resize', () => {
+      this.onResize_();
+    });
+
+    // TODO(siggi): Create the graph.
+  }
+
+  /**
+   * @param {!Event} event A graph update event posted from the WebUI.
+   * @private
+   */
+  onMessage_(event) {
+    this.updateGraph_(event.data);
+  }
+
+  /**
+   * @param {resourceCoordinator.mojom.WebUIGraph} graph An updated graph from
+   *     the WebUI.
+   * @private
+   */
+  updateGraph_(graph) {
+    // TODO(siggi): update the graph
+  }
+
+  /** @private */
+  onResize_() {
+    // TODO(siggi): update the graph.
+  }
+}
+
+let graph = null;
+function onLoad() {
+  graph = new Graph(document.querySelector('svg'));
+
+  graph.initialize();
+}
+
+window.addEventListener('load', onLoad);
diff --git a/chrome/browser/resources/discards/graph_doc_template.html b/chrome/browser/resources/discards/graph_doc_template.html
new file mode 100644
index 0000000..dd29e574
--- /dev/null
+++ b/chrome/browser/resources/discards/graph_doc_template.html
@@ -0,0 +1,38 @@
+<!--
+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.
+
+This document is loaded into a <webview> from the graph_tab element as a data:
+URL. As result, this document needs to be self-contained, hence inline scripts.
+-->
+<html>
+  <head>
+    <style>
+      html,
+      body {
+        height: 100%;
+      }
+
+      body {
+        margin: 0;
+      }
+
+      .links line {
+        stroke: #999;
+        stroke-opacity: 0.6;
+      }
+
+      .nodes circle {
+        stroke: #fff;
+        stroke-width: 1.5px;
+      }
+    </style>
+  <script type="application/javascript">
+${javascript_file}
+  </script>
+  </head>
+  <body>
+    <svg id="graphBody" width="100%" height="100%"></svg>
+  </body>
+</html>
diff --git a/chrome/browser/resources/discards/graph_tab.js b/chrome/browser/resources/discards/graph_tab.js
new file mode 100644
index 0000000..59e1377
--- /dev/null
+++ b/chrome/browser/resources/discards/graph_tab.js
@@ -0,0 +1,49 @@
+// 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.
+
+Polymer({
+  is: 'graph-tab',
+
+  /**
+   * The Mojo graph data source.
+   *
+   * @private {resourceCoordinator.mojom.WebUIGraphDumpPtr}
+   */
+  graphDump_: null,
+
+  /** @private {number} The current update timer if any. */
+  updateTimer_: 0,
+
+  /** @override */
+  ready: function() {
+    this.graphDump_ = new resourceCoordinator.mojom.WebUIGraphDumpPtr;
+    Mojo.bindInterface(
+        resourceCoordinator.mojom.WebUIGraphDump.name,
+        mojo.makeRequest(this.graphDump_).handle);
+  },
+
+  /** @override */
+  detached: function() {
+    // Clear the update timer to avoid memory leaks.
+    if (this.updateTimer_) {
+      clearInterval(this.updateTimer_);
+      this.updateTimer_ = 0;
+    }
+  },
+
+  /** @private */
+  onWebViewReady_: function() {
+    // Set up regular updates.
+    this.updateTimer_ = setInterval(() => {
+      this.graphDump_.getCurrentGraph().then(response => {
+        this.onGraphDump_(response.graph);
+      });
+    }, 1000);
+  },
+
+  /** @private */
+  onGraphDump_: function(graph) {
+    this.$.webView.contentWindow.postMessage(graph, '*');
+  },
+});
diff --git a/chrome/browser/resources/discards/graph_tab_template.html b/chrome/browser/resources/discards/graph_tab_template.html
new file mode 100644
index 0000000..35db8c32
--- /dev/null
+++ b/chrome/browser/resources/discards/graph_tab_template.html
@@ -0,0 +1,18 @@
+<!--
+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.
+
+This is an internal only page meant for debugging. It is not intended for
+general use and is not localized.
+-->
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<dom-module id="graph-tab">
+  <template>
+    <webview id="webView" src="${data_url}" on-contentload="onWebViewReady_"
+        allowscaling>
+    </webview>
+  </template>
+  <script src="graph_tab.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/discards/graph_view.md b/chrome/browser/resources/discards/graph_view.md
new file mode 100644
index 0000000..330e84f6
--- /dev/null
+++ b/chrome/browser/resources/discards/graph_view.md
@@ -0,0 +1,53 @@
+# Graph View
+
+The graph view displays an animated graph of the resource coordinator graph.
+This graph is a course-level overview of the browser's state, broken down
+into pages, each of which has a frame tree. Each frame is then hosted by a
+process.
+
+## Rendering
+To render and animate the graph, the implementation relies on
+[D3.js](https://d3js.org), which transforms the graph to SVG DOM elements.
+The animation is the [D3 force layout](https://github.com/d3/d3-force) using
+X and Y attracting forces to pull pages to the top, processes to the bottom,
+and the graph at large to the center.
+
+Because D3.js is rather large, it was deemed unreasonable to ship it as part of
+Chrome for occasional use by this debug page. For this reason, D3.js is loaded
+from an external, Google controlled page.
+
+## Security concerns
+WebUI runs in privileged renderer processes, each of which has access to the set
+of APIs exposed by their corresponding WebUIController. In the case of the
+discards UI, this includes the DiscardsDetailsProvider interface. This allows
+discarding pages, as well as e.g. querying and manipulating the browser state.
+
+The D3 library is loaded from the web, and it was strongly desired not to load
+it into a WebUI renderer. Instead, the graph rendering takes place in a
+`<webview>`, which is hosted in a second, unprivileged renderer process.
+This limits Chrome's exposure in case of implementation error in the D3 library
+exploitable errors in the renderer.
+
+The main body document of this webview is provided in a data URL.
+To ensure that the D3.js library is not modified in transport it is pinned with
+[subresource integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
+This is mainly to ensure that the graph view is not subverted, as it handles
+potentially sensitive data, like the URLs currently loaded.
+
+Communication to the webview is done with one-way postMessage, from WebUI to
+webview.
+
+## Incidental Detail
+In order to allow type checking the main body javascript code with the closure
+compiler, it is hosted in a separate file named `graph_doc.js`. At build time,
+the javascript is merged into the `graph_doc.html.template` file, and the
+whole lot is encoded in a data URL, which is merged into the `graph_tab.html`
+file.
+While GRIT does have an include (`<include src="">`) and a flattening mechanism,
+which will flatten resources to a data URL, this doesn't at present allow
+flattening HTML.
+
+## How to debug
+To debug the contents in the webview, navigate to the development tools
+page inspector (`chrome://inspect/#pages`), and select the inspect link from the
+subpage you see there under the `chrome://discards` page.
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js
index 92543b7b..07c5429 100644
--- a/chrome/browser/resources/print_preview/data/destination.js
+++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -181,6 +181,8 @@
  * @typedef {{
  *   allowedColorModes: ?print_preview.ColorMode,
  *   allowedDuplexModes: ?print_preview.DuplexModeRestriction,
+ *   defaultColorMode: ?print_preview.ColorMode,
+ *   defaultDuplexMode: ?print_preview.DuplexModeRestriction,
  * }}
  */
 print_preview.Policies;
@@ -796,23 +798,21 @@
 
     /**
      * @return {?print_preview.ColorMode} Color mode set by policy.
-     * @private
      */
-    colorPolicy_() {
+    get colorPolicy() {
       return this.policies && this.policies.allowedColorModes ?
           this.policies.allowedColorModes :
           null;
     }
 
     /**
-     * @return {print_preview.DuplexModeRestriction} Duplex modes allowed by
+     * @return {?print_preview.DuplexModeRestriction} Duplex modes allowed by
      *     policy.
-     * @private
      */
-    duplexPolicy_() {
+    get duplexPolicy() {
       return this.policies && this.policies.allowedDuplexModes ?
           this.policies.allowedDuplexModes :
-          print_preview.DuplexModeRestriction.NONE;
+          null;
     }
 
     /**
@@ -834,33 +834,20 @@
       return hasColor && hasMonochrome;
     }
 
-    /** @return {boolean} Whether the printer color mode is set by policy. */
-    get isColorManaged() {
-      return !!this.colorPolicy_();
+    /**
+     * @return {?print_preview.ColorMode} Value of default color setting given
+     *     by policy.
+     */
+    get defaultColorPolicy() {
+      return this.policies && this.policies.defaultColorMode;
     }
 
-    /** @return {?boolean} Value of color setting given by policy. */
-    get colorPolicyValue() {
-      return this.colorPolicy_() ?
-          this.colorPolicy_() == print_preview.ColorMode.COLOR :
-          null;
-    }
-
-    /** @return {boolean} Whether the printer duplex mode is set by policy. */
-    get isDuplexManaged() {
-      return !!this.duplexPolicy_();
-    }
-
-    /** @return {?boolean} Value for duplex setting given by policy. */
-    get duplexPolicyValue() {
-      switch (this.duplexPolicy_()) {
-        case print_preview.DuplexModeRestriction.NONE:
-          return null;
-        case print_preview.DuplexModeRestriction.SIMPLEX:
-          return false;
-        default:
-          return true;
-      }
+    /**
+     * @return {?print_preview.DuplexModeRestriction} Value of default duplex
+     *     setting given by policy.
+     */
+    get defaultDuplexPolicy() {
+      return this.policies && this.policies.defaultDuplexMode;
     }
 
     /**
diff --git a/chrome/browser/resources/print_preview/new/app.js b/chrome/browser/resources/print_preview/new/app.js
index 943b3ff..c5ea54e 100644
--- a/chrome/browser/resources/print_preview/new/app.js
+++ b/chrome/browser/resources/print_preview/new/app.js
@@ -411,6 +411,9 @@
     if (!this.$.model.initialized())
       this.$.model.applyStickySettings();
 
+    if (this.destination_)
+      this.$.model.applyDestinationSpecificPolicies();
+
     if (this.state == print_preview_new.State.NOT_READY ||
         this.state == print_preview_new.State.INVALID_PRINTER) {
       this.$.state.transitTo(print_preview_new.State.READY);
diff --git a/chrome/browser/resources/print_preview/new/model.js b/chrome/browser/resources/print_preview/new/model.js
index d11dbcc..2b4fd66a 100644
--- a/chrome/browser/resources/print_preview/new/model.js
+++ b/chrome/browser/resources/print_preview/new/model.js
@@ -375,17 +375,6 @@
     this.set('settings.layout.available', this.isLayoutAvailable_(caps));
     this.set('settings.color.available', this.destination.hasColorCapability);
 
-    if (this.destination.isColorManaged) {
-      // |this.setSetting| does nothing if policy is present.
-      // We want to set the value nevertheless so we call |this.set| directly.
-      this.set('settings.color.value', this.destination.colorPolicyValue);
-    }
-    this.set('settings.color.setByPolicy', this.destination.isColorManaged);
-
-    if (this.destination.isDuplexManaged)
-      this.set('settings.duplex.value', this.destination.duplexPolicyValue);
-    this.set('settings.duplex.setByPolicy', this.destination.isDuplexManaged);
-
     this.set(
         'settings.dpi.available',
         !!caps && !!caps.dpi && !!caps.dpi.option &&
@@ -719,6 +708,33 @@
     this.stickySettingsChanged_();
   },
 
+  /**
+   * Restricts settings and applies defaults as defined by policy applicable to
+   * current destination.
+   */
+  applyDestinationSpecificPolicies: function() {
+    const colorPolicy = this.destination.colorPolicy;
+    const colorValue =
+        colorPolicy ? colorPolicy : this.destination.defaultColorPolicy;
+    if (colorValue) {
+      // |this.setSetting| does nothing if policy is present.
+      // We want to set the value nevertheless so we call |this.set| directly.
+      this.set(
+          'settings.color.value', colorValue == print_preview.ColorMode.COLOR);
+    }
+    this.set('settings.color.setByPolicy', !!colorPolicy);
+
+    const duplexPolicy = this.destination.duplexPolicy;
+    const duplexValue =
+        duplexPolicy ? duplexPolicy : this.destination.defaultDuplexPolicy;
+    if (duplexValue) {
+      this.set(
+          'settings.duplex.value',
+          duplexValue != print_preview.DuplexModeRestriction.SIMPLEX);
+    }
+    this.set('settings.duplex.setByPolicy', !!duplexPolicy);
+  },
+
   /** @return {boolean} Whether the model has been initialized. */
   initialized: function() {
     return this.initialized_;
diff --git a/chrome/browser/tab_contents/view_source_browsertest.cc b/chrome/browser/tab_contents/view_source_browsertest.cc
index e5f3a58..8d04c62 100644
--- a/chrome/browser/tab_contents/view_source_browsertest.cc
+++ b/chrome/browser/tab_contents/view_source_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
@@ -19,6 +20,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
@@ -51,6 +53,25 @@
   DISALLOW_COPY_AND_ASSIGN(ViewSourceTest);
 };
 
+class ViewSourceFeaturePolicyTest : public ViewSourceTest {
+ public:
+  ViewSourceFeaturePolicyTest() : ViewSourceTest() {}
+
+ protected:
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    host_resolver()->AddRule("*", "127.0.0.1");
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ViewSourceFeaturePolicyTest);
+};
+
 // This test renders a page in view-source and then checks to see if the title
 // set in the html was set successfully (it shouldn't because we rendered the
 // page in view source).
@@ -513,3 +534,31 @@
       link_href_extraction_script, &link_href));
   EXPECT_EQ("about:blank", link_href);
 }
+
+// This test verifies that 'view-source' documents are not affected by vertical
+// scroll (see https://crbug.com/898688).
+IN_PROC_BROWSER_TEST_F(ViewSourceFeaturePolicyTest,
+                       ViewSourceNotAffectedByHeaderPolicy) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const std::string k_verify_feature = R"(
+      var all_features = document.policy.allowedFeatures();
+      var vs = all_features.find((f) => f === 'vertical-scroll');
+      console.log(vs);
+      domAutomationController.send("" + vs);)";
+  // Sanity-check: 'vertical-scroll' is disabled in the actual page (set by the
+  // mock headers).
+  GURL url(embedded_test_server()->GetURL(kTestHtml));
+  ui_test_utils::NavigateToURL(browser(), url);
+  std::string response;
+  ASSERT_TRUE(ExecuteScriptAndExtractString(
+      browser()->tab_strip_model()->GetActiveWebContents(), k_verify_feature,
+      &response));
+  EXPECT_EQ("undefined", response);
+  // Ensure the policy is enabled in the view-source version.
+  ui_test_utils::NavigateToURL(browser(), GURL(content::kViewSourceScheme +
+                                               std::string(":") + url.spec()));
+  ASSERT_TRUE(ExecuteScriptAndExtractString(
+      browser()->tab_strip_model()->GetActiveWebContents(), k_verify_feature,
+      &response));
+  EXPECT_EQ("vertical-scroll", response);
+}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index bb013a9..e6e5fe00 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1920,8 +1920,8 @@
 
   if (is_mac) {
     sources += [
-      "browser_commands_mac.cc",
       "browser_commands_mac.h",
+      "browser_commands_mac.mm",
       "browser_mac.cc",
       "browser_mac.h",
       "cocoa/accelerator_utils_cocoa.mm",
@@ -3306,6 +3306,8 @@
       "in_product_help/active_tab_tracker.h",
       "in_product_help/reopen_tab_in_product_help.cc",
       "in_product_help/reopen_tab_in_product_help.h",
+      "in_product_help/reopen_tab_in_product_help_factory.cc",
+      "in_product_help/reopen_tab_in_product_help_factory.h",
       "in_product_help/reopen_tab_in_product_help_trigger.cc",
       "in_product_help/reopen_tab_in_product_help_trigger.h",
     ]
diff --git a/chrome/browser/ui/blocked_content/framebust_block_tab_helper.cc b/chrome/browser/ui/blocked_content/framebust_block_tab_helper.cc
index 3c8c0fce..ecc571c4 100644
--- a/chrome/browser/ui/blocked_content/framebust_block_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/framebust_block_tab_helper.cc
@@ -9,6 +9,17 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/notification_service.h"
 
+namespace {
+
+void UpdateLocationBarUI(content::WebContents* contents) {
+  content::NotificationService::current()->Notify(
+      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
+      content::Source<content::WebContents>(contents),
+      content::NotificationService::NoDetails());
+}
+
+}  // namespace
+
 FramebustBlockTabHelper::~FramebustBlockTabHelper() = default;
 
 void FramebustBlockTabHelper::AddBlockedUrl(const GURL& blocked_url,
@@ -20,6 +31,7 @@
   for (Observer& observer : observers_) {
     observer.OnBlockedUrlAdded(blocked_url);
   }
+  UpdateLocationBarUI(web_contents());
 }
 
 bool FramebustBlockTabHelper::HasBlockedUrls() const {
@@ -60,13 +72,5 @@
   callbacks_.clear();
   animation_has_run_ = false;
 
-  // TODO(csharrison): It is a bit ugly that this tab helper has to notify this
-  // change directly. Consider improving this by integrating framebust
-  // information with the TabSpecificContentSetting class. This may be
-  // challenging, since popups and framebusts are controlled by the same content
-  // setting.
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-      content::Source<content::WebContents>(web_contents()),
-      content::NotificationService::NoDetails());
+  UpdateLocationBarUI(web_contents());
 }
diff --git a/chrome/browser/ui/blocked_content/tab_under_navigation_throttle.cc b/chrome/browser/ui/blocked_content/tab_under_navigation_throttle.cc
index 162b04b..e345ae9 100644
--- a/chrome/browser/ui/blocked_content/tab_under_navigation_throttle.cc
+++ b/chrome/browser/ui/blocked_content/tab_under_navigation_throttle.cc
@@ -18,7 +18,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/blocked_content/list_item_position.h"
 #include "chrome/browser/ui/blocked_content/popup_opener_tab_helper.h"
@@ -210,11 +209,11 @@
       std::make_unique<FramebustBlockMessageDelegate>(
           web_contents, url, base::BindOnce(&LogOutcome, off_the_record)));
 #else
-  TabSpecificContentSettings* content_settings =
-      TabSpecificContentSettings::FromWebContents(web_contents);
-  DCHECK(content_settings);
-  content_settings->OnFramebustBlocked(
-      url, base::BindOnce(&OnListItemClicked, off_the_record));
+  if (auto* tab_helper =
+          FramebustBlockTabHelper::FromWebContents(web_contents)) {
+    tab_helper->AddBlockedUrl(
+        url, base::BindOnce(&OnListItemClicked, off_the_record));
+  }
 #endif
 }
 
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 0e2be7d..24bbbd9 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1255,13 +1255,13 @@
 
 void Browser::OnDidBlockFramebust(content::WebContents* web_contents,
                                   const GURL& url) {
-  TabSpecificContentSettings* content_settings =
-      TabSpecificContentSettings::FromWebContents(web_contents);
-  DCHECK(content_settings);
-  // TODO(csharrison): Add a click callback here to collect framebusting
-  // click-through metrics.
-  content_settings->OnFramebustBlocked(
-      url, FramebustBlockTabHelper::ClickCallback());
+  if (auto* framebust_helper =
+          FramebustBlockTabHelper::FromWebContents(web_contents)) {
+    // TODO(csharrison): Add a click callback here to collect framebusting
+    // click-through metrics.
+    framebust_helper->AddBlockedUrl(url,
+                                    FramebustBlockTabHelper::ClickCallback());
+  }
 }
 
 gfx::Size Browser::EnterPictureInPicture(const viz::SurfaceId& surface_id,
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index cb6812d..21a375e 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -442,9 +442,7 @@
       chrome::ToggleFullscreenToolbar(browser_);
       break;
     case IDC_TOGGLE_JAVASCRIPT_APPLE_EVENTS: {
-      PrefService* prefs = profile()->GetPrefs();
-      prefs->SetBoolean(prefs::kAllowJavascriptAppleEvents,
-                        !prefs->GetBoolean(prefs::kAllowJavascriptAppleEvents));
+      chrome::ToggleJavaScriptFromAppleEventsAllowed(browser_);
       break;
     }
 #endif
diff --git a/chrome/browser/ui/browser_commands_mac.cc b/chrome/browser/ui/browser_commands_mac.cc
deleted file mode 100644
index 22be4a7..0000000
--- a/chrome/browser/ui/browser_commands_mac.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/browser_commands_mac.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
-#include "chrome/common/pref_names.h"
-#include "components/prefs/pref_service.h"
-
-namespace chrome {
-
-void ToggleFullscreenToolbar(Browser* browser) {
-  DCHECK(browser);
-
-  // Toggle the value of the preference.
-  PrefService* prefs = browser->profile()->GetPrefs();
-  bool show_toolbar = prefs->GetBoolean(prefs::kShowFullscreenToolbar);
-  prefs->SetBoolean(prefs::kShowFullscreenToolbar, !show_toolbar);
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/ui/browser_commands_mac.h b/chrome/browser/ui/browser_commands_mac.h
index 7e66d7a3..8d7f1dc 100644
--- a/chrome/browser/ui/browser_commands_mac.h
+++ b/chrome/browser/ui/browser_commands_mac.h
@@ -12,6 +12,9 @@
 // Toggles the visibility of the toolbar in fullscreen mode.
 void ToggleFullscreenToolbar(Browser* browser);
 
+// Toggles the "Allow JavaScript from AppleEvents" setting.
+void ToggleJavaScriptFromAppleEventsAllowed(Browser* browser);
+
 }  // namespace chrome
 
 #endif  // CHROME_BROWSER_UI_BROWSER_COMMANDS_MAC_H_
diff --git a/chrome/browser/ui/browser_commands_mac.mm b/chrome/browser/ui/browser_commands_mac.mm
new file mode 100644
index 0000000..9d75502c
--- /dev/null
+++ b/chrome/browser/ui/browser_commands_mac.mm
@@ -0,0 +1,61 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/browser_commands_mac.h"
+
+#include <unistd.h>
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+
+namespace chrome {
+
+void ToggleFullscreenToolbar(Browser* browser) {
+  DCHECK(browser);
+
+  // Toggle the value of the preference.
+  PrefService* prefs = browser->profile()->GetPrefs();
+  bool show_toolbar = prefs->GetBoolean(prefs::kShowFullscreenToolbar);
+  prefs->SetBoolean(prefs::kShowFullscreenToolbar, !show_toolbar);
+}
+
+void ToggleJavaScriptFromAppleEventsAllowed(Browser* browser) {
+  CGEventRef cg_event = [[NSApp currentEvent] CGEvent];
+  if (!cg_event)
+    return;
+
+  // If the event is from another process, do not allow it to toggle this
+  // secure setting.
+  int sender_pid =
+      CGEventGetIntegerValueField(cg_event, kCGEventSourceUnixProcessID);
+  if (sender_pid != 0 && sender_pid != getpid()) {
+    DLOG(ERROR)
+        << "Dropping JS AppleScript toggle, event not from browser, from "
+        << sender_pid;
+    return;
+  }
+
+  // Only allow events generated in the HID system to toggle this setting.
+  int event_source =
+      CGEventGetIntegerValueField(cg_event, kCGEventSourceStateID);
+  if (event_source != kCGEventSourceStateHIDSystemState) {
+    DLOG(ERROR) << "Dropping JS AppleScript toggle, event source state not "
+                   "from HID, from "
+                << event_source;
+    return;
+  }
+
+  PrefService* prefs = browser->profile()->GetPrefs();
+  prefs->SetBoolean(prefs::kAllowJavascriptAppleEvents,
+                    !prefs->GetBoolean(prefs::kAllowJavascriptAppleEvents));
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/ui/in_product_help/reopen_tab_in_product_help_factory.cc b/chrome/browser/ui/in_product_help/reopen_tab_in_product_help_factory.cc
new file mode 100644
index 0000000..1c2b8ba
--- /dev/null
+++ b/chrome/browser/ui/in_product_help/reopen_tab_in_product_help_factory.cc
@@ -0,0 +1,51 @@
+// 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/ui/in_product_help/reopen_tab_in_product_help_factory.h"
+
+#include <memory>
+
+#include "base/memory/singleton.h"
+#include "base/time/default_tick_clock.h"
+#include "chrome/browser/feature_engagement/tracker_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/in_product_help/reopen_tab_in_product_help.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+namespace in_product_help {
+
+ReopenTabInProductHelpFactory::ReopenTabInProductHelpFactory()
+    : BrowserContextKeyedServiceFactory(
+          "ReopenTabInProductHelp",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(feature_engagement::TrackerFactory::GetInstance());
+}
+
+ReopenTabInProductHelpFactory::~ReopenTabInProductHelpFactory() {}
+
+// static
+ReopenTabInProductHelpFactory* ReopenTabInProductHelpFactory::GetInstance() {
+  return base::Singleton<ReopenTabInProductHelpFactory>::get();
+}
+
+// static
+ReopenTabInProductHelp* ReopenTabInProductHelpFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<ReopenTabInProductHelp*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+KeyedService* ReopenTabInProductHelpFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new ReopenTabInProductHelp(Profile::FromBrowserContext(context),
+                                    base::DefaultTickClock::GetInstance());
+}
+
+content::BrowserContext* ReopenTabInProductHelpFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+}  // namespace in_product_help
diff --git a/chrome/browser/ui/in_product_help/reopen_tab_in_product_help_factory.h b/chrome/browser/ui/in_product_help/reopen_tab_in_product_help_factory.h
new file mode 100644
index 0000000..fd23c744
--- /dev/null
+++ b/chrome/browser/ui/in_product_help/reopen_tab_in_product_help_factory.h
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_IN_PRODUCT_HELP_REOPEN_TAB_IN_PRODUCT_HELP_FACTORY_H_
+#define CHROME_BROWSER_UI_IN_PRODUCT_HELP_REOPEN_TAB_IN_PRODUCT_HELP_FACTORY_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class Profile;
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace in_product_help {
+
+class ReopenTabInProductHelp;
+
+class ReopenTabInProductHelpFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static ReopenTabInProductHelpFactory* GetInstance();
+
+  static ReopenTabInProductHelp* GetForProfile(Profile* profile);
+
+ private:
+  ReopenTabInProductHelpFactory();
+  ~ReopenTabInProductHelpFactory() override;
+
+  // BrowserContextKeyedServiceFactory overrides:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+
+  friend struct base::DefaultSingletonTraits<ReopenTabInProductHelpFactory>;
+
+  DISALLOW_COPY_AND_ASSIGN(ReopenTabInProductHelpFactory);
+};
+
+}  // namespace in_product_help
+
+#endif  // CHROME_BROWSER_UI_IN_PRODUCT_HELP_REOPEN_TAB_IN_PRODUCT_HELP_FACTORY_H_
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index aa8cb90..fc1a0378 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -79,6 +79,7 @@
 #include "content/public/common/url_constants.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/feature_switch.h"
+#include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/ime/input_method.h"
@@ -122,6 +123,7 @@
 }  // namespace
 
 using content::WebContents;
+using metrics::OmniboxEventProto;
 using views::View;
 
 // LocationBarView -----------------------------------------------------------
@@ -809,8 +811,8 @@
   DCHECK(event.IsMouseEvent() || event.IsGestureEvent());
   if (keyword_hint_view_ == sender) {
     omnibox_view_->model()->AcceptKeyword(
-        event.IsMouseEvent() ? KeywordModeEntryMethod::CLICK_ON_VIEW
-                             : KeywordModeEntryMethod::TAP_ON_VIEW);
+        event.IsMouseEvent() ? OmniboxEventProto::CLICK_HINT_VIEW
+                             : OmniboxEventProto::TAP_HINT_VIEW);
   } else {
     DCHECK_EQ(clear_all_button_, sender);
     omnibox_view_->SetUserText(base::string16());
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 5d9fc013..e10da6a 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -38,6 +38,7 @@
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/escape.h"
+#include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_node_data.h"
@@ -74,6 +75,8 @@
 #include "chrome/browser/feature_engagement/new_tab/new_tab_tracker_factory.h"
 #endif
 
+using metrics::OmniboxEventProto;
+
 namespace {
 
 // OmniboxState ---------------------------------------------------------------
@@ -293,7 +296,7 @@
 void OmniboxViewViews::EnterKeywordModeForDefaultSearchProvider() {
   // Transition the user into keyword mode using their default search provider.
   model()->EnterKeywordModeForDefaultSearchProvider(
-      KeywordModeEntryMethod::KEYBOARD_SHORTCUT);
+      OmniboxEventProto::KEYBOARD_SHORTCUT);
 }
 
 void OmniboxViewViews::GetSelectionBounds(
@@ -485,7 +488,7 @@
     return false;
 
   if (model()->is_keyword_hint() && !event.IsShiftDown())
-    return model()->AcceptKeyword(KeywordModeEntryMethod::TAB);
+    return model()->AcceptKeyword(OmniboxEventProto::TAB);
 
   if (!model()->popup_model()->IsOpen())
     return false;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index eabe3f1..c19d844 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -30,6 +30,7 @@
 #include "components/omnibox/browser/test_location_bar_model.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/text_edit_commands.h"
 #include "ui/events/event_utils.h"
@@ -45,6 +46,7 @@
 #endif
 
 using gfx::Range;
+using metrics::OmniboxEventProto;
 
 namespace {
 
@@ -512,7 +514,7 @@
 TEST_F(OmniboxViewViewsTest, BackspaceExitsKeywordMode) {
   omnibox_view()->SetUserText(base::UTF8ToUTF16("user text"));
   omnibox_view()->model()->EnterKeywordModeForDefaultSearchProvider(
-      KeywordModeEntryMethod::KEYBOARD_SHORTCUT);
+      OmniboxEventProto::KEYBOARD_SHORTCUT);
 
   ASSERT_EQ(base::UTF8ToUTF16("user text"), omnibox_view()->GetText());
   ASSERT_TRUE(omnibox_view()->IsSelectAll());
diff --git a/chrome/browser/ui/webui/discards/discards_ui.cc b/chrome/browser/ui/webui/discards/discards_ui.cc
index 8717e81..d5d9ac6 100644
--- a/chrome/browser/ui/webui/discards/discards_ui.cc
+++ b/chrome/browser/ui/webui/discards/discards_ui.cc
@@ -407,6 +407,9 @@
   source->AddResourcePath("sorted_table_behavior.js",
                           IDR_DISCARDS_SORTED_TABLE_BEHAVIOR_JS);
 
+  source->AddResourcePath("graph_tab.html", IDR_DISCARDS_GRAPH_TAB_HTML);
+  source->AddResourcePath("graph_tab.js", IDR_DISCARDS_GRAPH_TAB_JS);
+
   // Full paths (relative to src) are important for Mojom generated files.
   source->AddResourcePath("chrome/browser/ui/webui/discards/discards.mojom.js",
                           IDR_DISCARDS_MOJO_JS);
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
index c8fbaecf..e64492f 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
@@ -190,6 +190,12 @@
       policies.SetInteger(
           printing::kAllowedDuplexModes,
           profile_->GetPrefs()->GetInteger(prefs::kPrintingAllowedDuplexModes));
+      policies.SetInteger(
+          printing::kDefaultColorMode,
+          profile_->GetPrefs()->GetInteger(prefs::kPrintingColorDefault));
+      policies.SetInteger(
+          printing::kDefaultDuplexMode,
+          profile_->GetPrefs()->GetInteger(prefs::kPrintingDuplexDefault));
       // fetch settings on the blocking pool and invoke callback.
       FetchCapabilities(std::move(printer), std::move(policies), std::move(cb));
       return;
diff --git a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h
index 3323704..2f5b303b 100644
--- a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_EASY_UNLOCK_SETTINGS_HANDLER_H_
 
 #include "base/macros.h"
-#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "components/prefs/pref_change_registrar.h"
 
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
index 035f5a5..d77fc7e6 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
@@ -6,17 +6,29 @@
 
 #include <string>
 
+#include "base/logging.h"
 #include "base/macros.h"
 #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
 #include "chrome/common/webui_url_constants.h"
+#include "ui/aura/window.h"
 
 namespace chromeos {
 
+namespace {
+
+InlineLoginHandlerDialogChromeOS* dialog = nullptr;
+
+}  // namespace
+
 // static
 void InlineLoginHandlerDialogChromeOS::Show() {
+  if (dialog) {
+    dialog->dialog_window()->Focus();
+    return;
+  }
+
   // Will be deleted by |SystemWebDialogDelegate::OnDialogClosed|.
-  InlineLoginHandlerDialogChromeOS* dialog =
-      new InlineLoginHandlerDialogChromeOS();
+  dialog = new InlineLoginHandlerDialogChromeOS();
   dialog->ShowSystemDialog(false /* is_minimal_style */);
 }
 
@@ -24,7 +36,10 @@
     : SystemWebDialogDelegate(GURL(chrome::kChromeUIChromeSigninURL),
                               base::string16() /* title */) {}
 
-InlineLoginHandlerDialogChromeOS::~InlineLoginHandlerDialogChromeOS() = default;
+InlineLoginHandlerDialogChromeOS::~InlineLoginHandlerDialogChromeOS() {
+  DCHECK_EQ(this, dialog);
+  dialog = nullptr;
+}
 
 std::string InlineLoginHandlerDialogChromeOS::GetDialogArgs() const {
   return std::string();
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index ab6675fd..1c396a6 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -251,6 +251,7 @@
     "contexts": ["webui"],
     "matches": [
       "chrome://chrome-signin/*",
+      "chrome://discards/*",
       "chrome://media-router/*",
       "chrome://mobilesetup/*",
       "chrome://oobe/*",
diff --git a/chrome/common/offline_page_auto_fetcher.mojom b/chrome/common/offline_page_auto_fetcher.mojom
index 77ecdca..9c1f319 100644
--- a/chrome/common/offline_page_auto_fetcher.mojom
+++ b/chrome/common/offline_page_auto_fetcher.mojom
@@ -22,12 +22,12 @@
 // Provides controls for fetching offline pages automatically and quietly in
 // the background.
 interface OfflinePageAutoFetcher {
-  // Attempts to schedule an auto fetch for this URL, and returns the result.
+  // Attempts to schedule an auto fetch for the URL on the current page.
   // If user_requested is false, only schedules the fetch if there is remaining
   // quota.
-  TrySchedule(bool user_requested, url.mojom.Url url) =>
+  TrySchedule(bool user_requested) =>
     (OfflinePageAutoFetcherScheduleResult out);
 
-  // Cancels a previously scheduled auto fetch.
-  CancelSchedule(url.mojom.Url url);
+  // Cancels a previously scheduled auto fetch for the URL of the current page.
+  CancelSchedule();
 };
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 3c61f8f0..fed196b 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -110,13 +110,12 @@
                     GURL /* origin_url */,
                     GURL /* top origin url */)
 
-// Sent by the renderer process to check whether access to Indexed DBis
+// Sent by the renderer process to check whether access to Indexed DB is
 // granted by content settings.
-IPC_SYNC_MESSAGE_CONTROL4_1(ChromeViewHostMsg_AllowIndexedDB,
+IPC_SYNC_MESSAGE_CONTROL3_1(ChromeViewHostMsg_AllowIndexedDB,
                             int /* render_frame_id */,
                             GURL /* origin_url */,
                             GURL /* top origin url */,
-                            base::string16 /* database name */,
                             bool /* allowed */)
 
 #if BUILDFLAG(ENABLE_PLUGINS)
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index 45e6cbd..aaa5d7f 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -426,6 +426,8 @@
     sources += [
       "net/available_offline_content_helper.cc",
       "net/available_offline_content_helper.h",
+      "net/page_auto_fetcher_helper_android.cc",
+      "net/page_auto_fetcher_helper_android.h",
     ]
   }
 }
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc
index 6901a9d..944f7f4 100644
--- a/chrome/renderer/content_settings_observer.cc
+++ b/chrome/renderer/content_settings_observer.cc
@@ -308,8 +308,7 @@
   return allow;
 }
 
-bool ContentSettingsObserver::AllowIndexedDB(const WebString& name,
-                                             const WebSecurityOrigin& origin) {
+bool ContentSettingsObserver::AllowIndexedDB(const WebSecurityOrigin& origin) {
   WebFrame* frame = render_frame()->GetWebFrame();
   if (IsUniqueFrame(frame))
     return false;
@@ -317,8 +316,7 @@
   bool result = false;
   Send(new ChromeViewHostMsg_AllowIndexedDB(
       routing_id(), url::Origin(frame->GetSecurityOrigin()).GetURL(),
-      url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), name.Utf16(),
-      &result));
+      url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), &result));
   return result;
 }
 
diff --git a/chrome/renderer/content_settings_observer.h b/chrome/renderer/content_settings_observer.h
index 28b8eaf4..b77c34d9 100644
--- a/chrome/renderer/content_settings_observer.h
+++ b/chrome/renderer/content_settings_observer.h
@@ -82,8 +82,7 @@
       const blink::WebContentSettingCallbacks& callbacks) override;
   bool AllowImage(bool enabled_per_settings,
                   const blink::WebURL& image_url) override;
-  bool AllowIndexedDB(const blink::WebString& name,
-                      const blink::WebSecurityOrigin& origin) override;
+  bool AllowIndexedDB(const blink::WebSecurityOrigin& origin) override;
   bool AllowScript(bool enabled_per_settings) override;
   bool AllowScriptFromSource(bool enabled_per_settings,
                              const blink::WebURL& script_url) override;
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc
index 1d681f9..c3475d20 100644
--- a/chrome/renderer/net/net_error_helper.cc
+++ b/chrome/renderer/net/net_error_helper.cc
@@ -61,6 +61,10 @@
 #include "ui/base/webui/jstemplate_builder.h"
 #include "url/gurl.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/common/offline_page_auto_fetcher.mojom.h"
+#endif
+
 using base::JSONWriter;
 using content::DocumentState;
 using content::RenderFrame;
@@ -112,6 +116,16 @@
 }
 #endif  // OS_ANDROID
 
+#if defined(OS_ANDROID)
+bool IsAutoFetchFeatureEnabled() {
+  return base::FeatureList::IsEnabled(features::kAutoFetchOnNetErrorPage);
+}
+#else   // OS_ANDROID
+bool IsAutoFetchFeatureEnabled() {
+  return false;
+}
+#endif  // OS_ANDROID
+
 const net::NetworkTrafficAnnotationTag& GetNetworkTrafficAnnotationTag() {
   static const net::NetworkTrafficAnnotationTag network_traffic_annotation_tag =
       net::DefineNetworkTrafficAnnotation("net_error_helper", R"(
@@ -191,6 +205,10 @@
   core_->LaunchDownloadsPage();
 }
 
+content::RenderFrame* NetErrorHelper::GetRenderFrame() {
+  return render_frame();
+}
+
 void NetErrorHelper::SendCommand(
     security_interstitials::SecurityInterstitialCommand command) {
   security_interstitials::mojom::InterstitialCommandsAssociatedPtr interface;
@@ -352,6 +370,7 @@
     bool* show_cached_copy_button_shown,
     bool* download_button_shown,
     OfflineContentOnNetErrorFeatureState* offline_content_feature_state,
+    bool* auto_fetch_allowed,
     std::string* error_html) const {
   error_html->clear();
 
@@ -367,8 +386,8 @@
         error.reason(), error.domain(), error.url(), is_failed_post,
         error.stale_copy_in_cache(), can_show_network_diagnostics_dialog,
         ChromeRenderThreadObserver::is_incognito_process(),
-        *offline_content_feature_state, RenderThread::Get()->GetLocale(),
-        std::move(params), &error_strings);
+        *offline_content_feature_state, IsAutoFetchFeatureEnabled(),
+        RenderThread::Get()->GetLocale(), std::move(params), &error_strings);
     *reload_button_shown = error_strings.Get("reloadButton", nullptr);
     *show_saved_copy_button_shown =
         error_strings.Get("showSavedCopyButton", nullptr);
@@ -381,7 +400,7 @@
       *offline_content_feature_state =
           OfflineContentOnNetErrorFeatureState::kDisabled;
     }
-
+    *auto_fetch_allowed = error_strings.FindKey("attemptAutoFetch") != nullptr;
     // "t" is the id of the template's root node.
     *error_html = webui::GetTemplatesHtml(template_html, &error_strings, "t");
   }
@@ -422,7 +441,7 @@
       error.reason(), error.domain(), error.url(), is_failed_post,
       error.stale_copy_in_cache(), can_show_network_diagnostics_dialog,
       ChromeRenderThreadObserver::is_incognito_process(),
-      GetOfflineContentOnNetErrorFeatureState(),
+      GetOfflineContentOnNetErrorFeatureState(), IsAutoFetchFeatureEnabled(),
       RenderThread::Get()->GetLocale(), std::unique_ptr<ErrorPageParams>(),
       &error_strings);
 
@@ -538,9 +557,31 @@
         base::UTF8ToUTF16(base::StrCat({"offlineContentSummaryAvailable(",
                                         offline_content_summary_json, ");"})));
   }
-#endif
+#endif  // defined(OS_ANDROID)
 }
 
+#if defined(OS_ANDROID)
+void NetErrorHelper::SetAutoFetchState(
+    chrome::mojom::OfflinePageAutoFetcherScheduleResult result) {
+  const char* scheduled = "false";
+  const char* can_schedule = "false";
+  switch (result) {
+    case chrome::mojom::OfflinePageAutoFetcherScheduleResult::kAlreadyScheduled:
+    case chrome::mojom::OfflinePageAutoFetcherScheduleResult::kScheduled:
+      scheduled = "true";
+      can_schedule = "true";
+      break;
+    case chrome::mojom::OfflinePageAutoFetcherScheduleResult::kOtherError:
+      break;
+    case chrome::mojom::OfflinePageAutoFetcherScheduleResult::kNotEnoughQuota:
+      can_schedule = "true";
+      break;
+  }
+  render_frame()->ExecuteJavaScript(base::UTF8ToUTF16(base::StrCat(
+      {"setAutoFetchState(", scheduled, ", ", can_schedule, ");"})));
+}
+#endif  // defined(OS_ANDROID)
+
 void NetErrorHelper::DNSProbeStatus(int32_t status_num) {
   DCHECK(status_num >= 0 && status_num < error_page::DNS_PROBE_MAX);
 
diff --git a/chrome/renderer/net/net_error_helper.h b/chrome/renderer/net/net_error_helper.h
index 80eb0bff..23177864 100644
--- a/chrome/renderer/net/net_error_helper.h
+++ b/chrome/renderer/net/net_error_helper.h
@@ -120,6 +120,7 @@
       bool* download_button_shown,
       error_page::LocalizedError::OfflineContentOnNetErrorFeatureState*
           offline_content_feature_state,
+      bool* auto_fetch_allowed,
       std::string* html) const override;
   void LoadErrorPage(const std::string& html, const GURL& failed_url) override;
   void EnablePageHelperFunctions(net::Error net_error) override;
@@ -141,6 +142,12 @@
       const std::string& offline_content_json) override;
   void OfflineContentSummaryAvailable(
       const std::string& offline_content_summary_json) override;
+  content::RenderFrame* GetRenderFrame() override;
+
+#if defined(OS_ANDROID)
+  void SetAutoFetchState(
+      chrome::mojom::OfflinePageAutoFetcherScheduleResult state) override;
+#endif
 
   void OnSetNavigationCorrectionInfo(const GURL& navigation_correction_url,
                                      const std::string& language,
diff --git a/chrome/renderer/net/net_error_helper_core.cc b/chrome/renderer/net/net_error_helper_core.cc
index 35ce48e..750dcd1 100644
--- a/chrome/renderer/net/net_error_helper_core.cc
+++ b/chrome/renderer/net/net_error_helper_core.cc
@@ -15,6 +15,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/i18n/rtl.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_value_converter.h"
@@ -28,6 +29,7 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "chrome/common/chrome_features.h"
 #include "components/error_page/common/error_page_params.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_formatter.h"
@@ -430,7 +432,8 @@
         is_finished_loading(false),
         auto_reload_triggered(false),
         offline_content_feature_state(
-            OfflineContentOnNetErrorFeatureState::kDisabled) {}
+            OfflineContentOnNetErrorFeatureState::kDisabled),
+        auto_fetch_allowed(false) {}
 
   // Information about the failed page load.
   error_page::Error error;
@@ -476,6 +479,9 @@
   // State of the offline content on net error page feature. Only enabled if
   // the feature is enabled, and the error page is an offline error.
   OfflineContentOnNetErrorFeatureState offline_content_feature_state;
+
+  // True if auto-fetch-on-dino-page is enabled and allowed for this error page.
+  bool auto_fetch_allowed;
 };
 
 NetErrorHelperCore::NavigationCorrectionParams::NavigationCorrectionParams() {}
@@ -527,7 +533,14 @@
       online_(content::RenderThread::Get()->IsOnline()),
       visible_(is_visible),
       auto_reload_count_(0),
-      navigation_from_button_(NO_BUTTON) {}
+      navigation_from_button_(NO_BUTTON)
+#if defined(OS_ANDROID)
+      ,
+      page_auto_fetcher_helper_(
+          std::make_unique<PageAutoFetcherHelper>(delegate->GetRenderFrame()))
+#endif
+{
+}
 
 NetErrorHelperCore::~NetErrorHelperCore() {
   if (committed_error_page_info_ &&
@@ -691,7 +704,13 @@
         base::BindOnce(&Delegate::OfflineContentSummaryAvailable,
                        base::Unretained(delegate_)));
   }
-#endif
+
+  if (committed_error_page_info_->auto_fetch_allowed) {
+    page_auto_fetcher_helper_->TrySchedule(
+        false, base::BindOnce(&Delegate::SetAutoFetchState,
+                              base::Unretained(delegate_)));
+  }
+#endif  // OS_ANDROID
 
   if (committed_error_page_info_->needs_load_navigation_corrections) {
     // If there is another pending error page load, |fix_url| should have been
@@ -739,13 +758,14 @@
     bool show_cached_copy_button_in_page;
     bool download_button_in_page;
     OfflineContentOnNetErrorFeatureState offline_content_feature_state;
+    bool auto_fetch_allowed;
     if (error_html) {
       delegate_->GenerateLocalizedErrorPage(
           error, is_failed_post,
           false /* No diagnostics dialogs allowed for subframes. */, nullptr,
           &reload_button_in_page, &show_saved_copy_button_in_page,
           &show_cached_copy_button_in_page, &download_button_in_page,
-          &offline_content_feature_state, error_html);
+          &offline_content_feature_state, &auto_fetch_allowed, error_html);
     }
   }
 }
@@ -813,7 +833,8 @@
         &pending_error_page_info->show_saved_copy_button_in_page,
         &pending_error_page_info->show_cached_copy_button_in_page,
         &pending_error_page_info->download_button_in_page,
-        &pending_error_page_info->offline_content_feature_state, error_html);
+        &pending_error_page_info->offline_content_feature_state,
+        &pending_error_page_info->auto_fetch_allowed, error_html);
   }
 }
 
@@ -875,7 +896,8 @@
         &pending_error_page_info_->show_saved_copy_button_in_page,
         &pending_error_page_info_->show_cached_copy_button_in_page,
         &pending_error_page_info_->download_button_in_page,
-        &pending_error_page_info_->offline_content_feature_state, &error_html);
+        &pending_error_page_info_->offline_content_feature_state,
+        &pending_error_page_info_->auto_fetch_allowed, &error_html);
   } else {
     // Since |navigation_correction_params| in |pending_error_page_info_| is
     // NULL, this won't trigger another attempt to load corrections.
@@ -1002,6 +1024,13 @@
   return true;
 }
 
+#if defined(OS_ANDROID)
+void NetErrorHelperCore::SetPageAutoFetcherHelperForTesting(
+    std::unique_ptr<PageAutoFetcherHelper> page_auto_fetcher_helper) {
+  page_auto_fetcher_helper_ = std::move(page_auto_fetcher_helper);
+}
+#endif
+
 void NetErrorHelperCore::ExecuteButtonPress(Button button) {
   // If there's no committed error page, should not be invoked.
   DCHECK(committed_error_page_info_);
diff --git a/chrome/renderer/net/net_error_helper_core.h b/chrome/renderer/net/net_error_helper_core.h
index f7e5a5a0..896a8f4 100644
--- a/chrome/renderer/net/net_error_helper_core.h
+++ b/chrome/renderer/net/net_error_helper_core.h
@@ -20,8 +20,12 @@
 
 #if defined(OS_ANDROID)
 #include "chrome/renderer/net/available_offline_content_helper.h"
+#include "chrome/renderer/net/page_auto_fetcher_helper_android.h"
 #endif
 
+namespace content {
+class RenderFrame;
+}
 namespace error_page {
 struct ErrorPageParams;
 }
@@ -69,6 +73,7 @@
         bool* download_button_shown,
         error_page::LocalizedError::OfflineContentOnNetErrorFeatureState*
             offline_content_feature_state,
+        bool* auto_fetch_allowed,
         std::string* html) const = 0;
 
     // Loads the given HTML in the frame for use as an error page.
@@ -126,6 +131,16 @@
     virtual void OfflineContentSummaryAvailable(
         const std::string& offline_content_summary_json) = 0;
 
+    // Returns the render frame associated with NetErrorHelper.
+    virtual content::RenderFrame* GetRenderFrame() = 0;
+
+#if defined(OS_ANDROID)
+    // Called after an attempt to automatically schedule a background fetch for
+    // a page with a network error.
+    virtual void SetAutoFetchState(
+        chrome::mojom::OfflinePageAutoFetcherScheduleResult result) = 0;
+#endif
+
    protected:
     virtual ~Delegate() {}
   };
@@ -211,6 +226,11 @@
     auto_reload_timer_ = std::move(timer);
   }
 
+#if defined(OS_ANDROID)
+  void SetPageAutoFetcherHelperForTesting(
+      std::unique_ptr<PageAutoFetcherHelper> page_auto_fetcher_helper);
+#endif
+
   // Execute the effect of pressing the specified button.
   // Note that the visual effects of the 'MORE' button are taken
   // care of in JavaScript.
@@ -311,6 +331,7 @@
 
 #if defined(OS_ANDROID)
   AvailableOfflineContentHelper available_content_helper_;
+  std::unique_ptr<PageAutoFetcherHelper> page_auto_fetcher_helper_;
 #endif
 };
 
diff --git a/chrome/renderer/net/net_error_helper_core_unittest.cc b/chrome/renderer/net/net_error_helper_core_unittest.cc
index 0074b33..3ea8f790 100644
--- a/chrome/renderer/net/net_error_helper_core_unittest.cc
+++ b/chrome/renderer/net/net_error_helper_core_unittest.cc
@@ -40,6 +40,10 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/common/offline_page_auto_fetcher.mojom.h"
+#endif
+
 namespace {
 
 using OfflineContentOnNetErrorFeatureState =
@@ -248,6 +252,8 @@
     offline_content_feature_state_ = offline_content_feature_state;
   }
 
+  void set_auto_fetch_allowed(bool allowed) { auto_fetch_allowed_ = allowed; }
+
   const std::string& offline_content_json() const {
     return offline_content_json_;
   }
@@ -256,6 +262,15 @@
     return offline_content_summary_json_;
   }
 
+#if defined(OS_ANDROID)
+  // State of auto fetch, as reported to Delegate. Unset if SetAutoFetchState
+  // was not called.
+  base::Optional<chrome::mojom::OfflinePageAutoFetcherScheduleResult>
+  auto_fetch_state() const {
+    return auto_fetch_state_;
+  }
+#endif
+
   base::MockOneShotTimer* timer() { return timer_; }
 
   base::test::ScopedTaskEnvironment* task_environment() {
@@ -359,6 +374,7 @@
       bool* show_cached_copy_button_shown,
       bool* download_button_shown,
       OfflineContentOnNetErrorFeatureState* offline_content_feature_state,
+      bool* auto_fetch_allowed,
       std::string* html) const override {
     last_can_show_network_diagnostics_dialog_ =
         can_show_network_diagnostics_dialog;
@@ -368,6 +384,7 @@
     *show_cached_copy_button_shown = false;
     *download_button_shown = false;
     *offline_content_feature_state = offline_content_feature_state_;
+    *auto_fetch_allowed = auto_fetch_allowed_;
     *html = ErrorToString(error, is_failed_post);
   }
 
@@ -450,6 +467,13 @@
     offline_content_summary_json_ = offline_content_summary_json;
   }
 
+#if defined(OS_ANDROID)
+  void SetAutoFetchState(
+      chrome::mojom::OfflinePageAutoFetcherScheduleResult result) override {
+    auto_fetch_state_ = result;
+  }
+#endif
+
   void SendTrackingRequest(const GURL& tracking_url,
                            const std::string& tracking_request_body) override {
     last_tracking_url_ = tracking_url;
@@ -472,6 +496,8 @@
     EXPECT_TRUE(StringValueEquals(*dict, "params.key", kApiKey));
   }
 
+  content::RenderFrame* GetRenderFrame() override { return nullptr; }
+
   base::MockOneShotTimer* timer_;
 
   base::test::ScopedTaskEnvironment task_environment_;
@@ -507,8 +533,13 @@
   int download_count_;
   std::string offline_content_json_;
   std::string offline_content_summary_json_;
+#if defined(OS_ANDROID)
+  base::Optional<chrome::mojom::OfflinePageAutoFetcherScheduleResult>
+      auto_fetch_state_;
+#endif
   OfflineContentOnNetErrorFeatureState offline_content_feature_state_ =
       OfflineContentOnNetErrorFeatureState::kDisabled;
+  bool auto_fetch_allowed_ = false;
 
   int enable_page_helper_functions_count_;
 
@@ -2830,6 +2861,112 @@
       error_page::NETWORK_ERROR_PAGE_OFFLINE_SUGGESTIONS_SHOWN, 0);
 }
 
+class FakeOfflinePageAutoFetcher
+    : public chrome::mojom::OfflinePageAutoFetcher {
+ public:
+  FakeOfflinePageAutoFetcher() = default;
+
+  struct TryScheduleParameters {
+    bool user_requested;
+    TryScheduleCallback callback;
+  };
+
+  void TrySchedule(bool user_requested, TryScheduleCallback callback) override {
+    try_schedule_calls_.push_back({user_requested, std::move(callback)});
+  }
+
+  void CancelSchedule() override { cancel_calls_++; }
+
+  void AddBinding(mojo::ScopedMessagePipeHandle handle) {
+    bindings_.AddBinding(
+        this, chrome::mojom::OfflinePageAutoFetcherRequest(std::move(handle)));
+  }
+
+  int cancel_calls() const { return cancel_calls_; }
+  std::vector<TryScheduleParameters> take_try_schedule_calls() {
+    std::vector<TryScheduleParameters> result = std::move(try_schedule_calls_);
+    try_schedule_calls_.clear();
+    return result;
+  }
+
+ private:
+  mojo::BindingSet<chrome::mojom::OfflinePageAutoFetcher> bindings_;
+  int cancel_calls_ = 0;
+  std::vector<TryScheduleParameters> try_schedule_calls_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeOfflinePageAutoFetcher);
+};
+// This uses the real implementation of PageAutoFetcherHelper, but with a
+// substituted fetcher.
+class TestPageAutoFetcherHelper : public PageAutoFetcherHelper {
+ public:
+  explicit TestPageAutoFetcherHelper(
+      chrome::mojom::OfflinePageAutoFetcherPtr fetcher)
+      : PageAutoFetcherHelper(nullptr) {
+    fetcher_ = std::move(fetcher);
+  }
+  bool Bind() override { return true; }
+};
+
+// Provides set up for testing the 'auto fetch on dino' feature.
+class NetErrorHelperCoreAutoFetchTest : public NetErrorHelperCoreTest {
+ public:
+  void SetUp() override {
+    NetErrorHelperCoreTest::SetUp();
+    // Override PageAutoFetcherHelper so that it talks to
+    // FakeOfflinePageAutoFetcher. This is a bit roundabout because
+    // we do not create a RenderFrame in this fixture.
+    test_api_.OverrideBinderForTesting(
+        service_manager::Identity(content::mojom::kBrowserServiceName),
+        chrome::mojom::OfflinePageAutoFetcher::Name_,
+        base::BindRepeating(&FakeOfflinePageAutoFetcher::AddBinding,
+                            base::Unretained(&fake_fetcher_)));
+    chrome::mojom::OfflinePageAutoFetcherPtr fetcher_ptr;
+    render_thread()->GetConnector()->BindInterface(
+        content::mojom::kBrowserServiceName, &fetcher_ptr);
+    ASSERT_TRUE(fetcher_ptr);
+    core()->SetPageAutoFetcherHelperForTesting(
+        std::make_unique<TestPageAutoFetcherHelper>(std::move(fetcher_ptr)));
+  }
+
+ protected:
+  FakeOfflinePageAutoFetcher fake_fetcher_;
+  service_manager::Connector::TestApi test_api_{
+      render_thread()->GetConnector()};
+};
+
+TEST_F(NetErrorHelperCoreAutoFetchTest, NotAllowed) {
+  set_auto_fetch_allowed(false);
+
+  DoErrorLoad(net::ERR_INTERNET_DISCONNECTED);
+  task_environment()->RunUntilIdle();
+
+  // When auto fetch is not allowed, OfflinePageAutoFetcher is not called.
+  std::vector<FakeOfflinePageAutoFetcher::TryScheduleParameters> calls =
+      fake_fetcher_.take_try_schedule_calls();
+  EXPECT_EQ(0ul, calls.size());
+}
+
+TEST_F(NetErrorHelperCoreAutoFetchTest, AutoFetchTriggered) {
+  set_auto_fetch_allowed(true);
+
+  DoErrorLoad(net::ERR_INTERNET_DISCONNECTED);
+  task_environment()->RunUntilIdle();
+
+  // Auto fetch is allowed, so OfflinePageAutoFetcher is called once.
+  std::vector<FakeOfflinePageAutoFetcher::TryScheduleParameters> calls =
+      fake_fetcher_.take_try_schedule_calls();
+  EXPECT_EQ(1ul, calls.size());
+
+  // Finalize the call to TrySchedule, and verify the delegate is called.
+  std::move(calls[0].callback)
+      .Run(chrome::mojom::OfflinePageAutoFetcherScheduleResult::kScheduled);
+  task_environment()->RunUntilIdle();
+
+  EXPECT_EQ(chrome::mojom::OfflinePageAutoFetcherScheduleResult::kScheduled,
+            auto_fetch_state());
+}
+
 #endif  // defined(OS_ANDROID)
 
 }  // namespace
diff --git a/chrome/renderer/net/net_error_page_controller.h b/chrome/renderer/net/net_error_page_controller.h
index 6a0b9d3..6c024b1 100644
--- a/chrome/renderer/net/net_error_page_controller.h
+++ b/chrome/renderer/net/net_error_page_controller.h
@@ -11,7 +11,6 @@
 #include "gin/arguments.h"
 #include "gin/wrappable.h"
 
-
 namespace content {
 class RenderFrame;
 }
diff --git a/chrome/renderer/net/page_auto_fetcher_helper_android.cc b/chrome/renderer/net/page_auto_fetcher_helper_android.cc
new file mode 100644
index 0000000..835c8ed
--- /dev/null
+++ b/chrome/renderer/net/page_auto_fetcher_helper_android.cc
@@ -0,0 +1,53 @@
+// 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/renderer/net/page_auto_fetcher_helper_android.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "content/public/common/service_names.mojom.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+
+PageAutoFetcherHelper::PageAutoFetcherHelper(content::RenderFrame* render_frame)
+    : render_frame_(render_frame) {}
+PageAutoFetcherHelper::~PageAutoFetcherHelper() = default;
+
+void PageAutoFetcherHelper::TrySchedule(
+    bool user_requested,
+    base::OnceCallback<void(FetcherScheduleResult)> complete_callback) {
+  if (!Bind()) {
+    std::move(complete_callback).Run(FetcherScheduleResult::kOtherError);
+    return;
+  }
+
+  fetcher_->TrySchedule(
+      user_requested,
+      base::BindOnce(&PageAutoFetcherHelper::TryScheduleComplete,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(complete_callback)));
+}
+
+void PageAutoFetcherHelper::TryScheduleComplete(
+    base::OnceCallback<void(FetcherScheduleResult)> complete_callback,
+    FetcherScheduleResult result) {
+  std::move(complete_callback).Run(result);
+}
+
+void PageAutoFetcherHelper::CancelSchedule() {
+  if (Bind()) {
+    fetcher_->CancelSchedule();
+  }
+}
+
+bool PageAutoFetcherHelper::Bind() {
+  if (fetcher_)
+    return true;
+  render_frame_->GetRemoteInterfaces()->GetInterface(
+      mojo::MakeRequest(&fetcher_));
+  return fetcher_.is_bound();
+}
diff --git a/chrome/renderer/net/page_auto_fetcher_helper_android.h b/chrome/renderer/net/page_auto_fetcher_helper_android.h
new file mode 100644
index 0000000..0d76567
--- /dev/null
+++ b/chrome/renderer/net/page_auto_fetcher_helper_android.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_NET_PAGE_AUTO_FETCHER_HELPER_ANDROID_H_
+#define CHROME_RENDERER_NET_PAGE_AUTO_FETCHER_HELPER_ANDROID_H_
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/common/offline_page_auto_fetcher.mojom.h"
+
+namespace content {
+class RenderFrame;
+}
+
+// Wraps calls from the renderer thread to the PageAutoFetcher, and records
+// related UMA.
+class PageAutoFetcherHelper {
+ public:
+  using FetcherScheduleResult =
+      chrome::mojom::OfflinePageAutoFetcherScheduleResult;
+  explicit PageAutoFetcherHelper(content::RenderFrame* render_frame);
+  virtual ~PageAutoFetcherHelper();
+  void TrySchedule(
+      bool user_requested,
+      base::OnceCallback<void(FetcherScheduleResult)> complete_callback);
+  void CancelSchedule();
+
+ protected:
+  void TryScheduleComplete(
+      base::OnceCallback<void(FetcherScheduleResult)> complete_callback,
+      FetcherScheduleResult result);
+
+  // Binds |fetcher_| if necessary. Returns true if the fetcher_ is bound.
+  // Virtual for testing only.
+  virtual bool Bind();
+
+  content::RenderFrame* render_frame_;
+  chrome::mojom::OfflinePageAutoFetcherPtr fetcher_;
+
+  base::WeakPtrFactory<PageAutoFetcherHelper> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(PageAutoFetcherHelper);
+};
+
+#endif  // CHROME_RENDERER_NET_PAGE_AUTO_FETCHER_HELPER_ANDROID_H_
diff --git a/chrome/renderer/worker_content_settings_client.cc b/chrome/renderer/worker_content_settings_client.cc
index 2999397..9d5cd2c 100644
--- a/chrome/renderer/worker_content_settings_client.cc
+++ b/chrome/renderer/worker_content_settings_client.cc
@@ -61,15 +61,13 @@
 }
 
 bool WorkerContentSettingsClient::AllowIndexedDB(
-    const blink::WebString& name,
     const blink::WebSecurityOrigin&) {
   if (is_unique_origin_)
     return false;
 
   bool result = false;
   sync_message_filter_->Send(new ChromeViewHostMsg_AllowIndexedDB(
-      routing_id_, document_origin_url_, top_frame_origin_url_, name.Utf16(),
-      &result));
+      routing_id_, document_origin_url_, top_frame_origin_url_, &result));
   return result;
 }
 
diff --git a/chrome/renderer/worker_content_settings_client.h b/chrome/renderer/worker_content_settings_client.h
index a6b093a..b7d0791 100644
--- a/chrome/renderer/worker_content_settings_client.h
+++ b/chrome/renderer/worker_content_settings_client.h
@@ -34,8 +34,7 @@
   // WebContentSettingsClient overrides.
   std::unique_ptr<blink::WebContentSettingsClient> Clone() override;
   bool RequestFileSystemAccessSync() override;
-  bool AllowIndexedDB(const blink::WebString& name,
-                      const blink::WebSecurityOrigin&) override;
+  bool AllowIndexedDB(const blink::WebSecurityOrigin&) override;
   bool AllowRunningInsecureContent(bool allowed_per_settings,
                                    const blink::WebSecurityOrigin& context,
                                    const blink::WebURL& url) override;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 50aa9f1..4f8eb39 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2941,7 +2941,7 @@
     sources += [
       "../browser/offline_pages/background_loader_offliner_unittest.cc",
       "../browser/offline_pages/download_archive_manager_unittest.cc",
-      "../browser/offline_pages/offline_page_auto_fetcher_unittest.cc",
+      "../browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc",
       "../browser/offline_pages/offline_page_mhtml_archiver_unittest.cc",
       "../browser/offline_pages/offline_page_request_handler_unittest.cc",
       "../browser/offline_pages/offline_page_tab_helper_unittest.cc",
diff --git a/chrome/test/chromedriver/cpp_source.py b/chrome/test/chromedriver/cpp_source.py
index dd6114b3..b0f8159 100644
--- a/chrome/test/chromedriver/cpp_source.py
+++ b/chrome/test/chromedriver/cpp_source.py
@@ -1,4 +1,4 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# 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.
 
@@ -24,16 +24,13 @@
           variables will be available as globals.
   """
   copyright_header_template = (
-      '// Copyright %s The Chromium Authors. All rights reserved.\n'
+      '// Copyright 2018 The Chromium Authors. All rights reserved.\n'
       '// Use of this source code is governed by a BSD-style license '
       'that can be\n'
       '// found in the LICENSE file.\n\n'
-      '// This file was generated at (%s) by running:\n'
+      '// This file was generated by running:\n'
       '//     %s')
-  copyright_header = copyright_header_template % (
-      datetime.date.today().year,
-      datetime.datetime.now().isoformat(' '),
-      ' '.join(sys.argv))
+  copyright_header = copyright_header_template % (' '.join(sys.argv))
 
   # Write header file.
   externs = []
diff --git a/chrome/test/data/viewsource/test.html.mock-http-headers b/chrome/test/data/viewsource/test.html.mock-http-headers
new file mode 100644
index 0000000..6d9d2171
--- /dev/null
+++ b/chrome/test/data/viewsource/test.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Feature-Policy: vertical-scroll 'none'
\ No newline at end of file
diff --git a/chrome/test/data/webui/print_preview/settings_section_test.js b/chrome/test/data/webui/print_preview/settings_section_test.js
index fcdc0f67..d7160ae 100644
--- a/chrome/test/data/webui/print_preview/settings_section_test.js
+++ b/chrome/test/data/webui/print_preview/settings_section_test.js
@@ -1157,6 +1157,7 @@
         // observers only check for |capabilities|, so the order is important.
         page.set('destination_.policies', policies);
         page.set('destination_.capabilities', capabilities);
+        page.$$('print-preview-model').applyDestinationSpecificPolicies();
         assertEquals(
             subtestParams.expectedValue, page.getSettingValue('color'));
         assertEquals(subtestParams.expectedHidden, colorElement.hidden);
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index f85b583..0559a40 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -2142,7 +2142,8 @@
 // mac: http://crbug.com/96767
 // aura: http://crbug.com/104384
 // cros: http://crbug.com/396502
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+// windows: http://crbug.com/899893
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_WIN)
 #define MAYBE_FlashFullscreen DISABLED_FlashFullscreen
 #else
 #define MAYBE_FlashFullscreen FlashFullscreen
diff --git a/chromeos/services/ime/public/cpp/BUILD.gn b/chromeos/services/ime/public/cpp/BUILD.gn
index 621a71d..e87c844 100644
--- a/chromeos/services/ime/public/cpp/BUILD.gn
+++ b/chromeos/services/ime/public/cpp/BUILD.gn
@@ -16,21 +16,35 @@
 
 source_set("rulebased") {
   sources = [
+    "rulebased/def/ar.cc",
     "rulebased/def/ar.h",
+    "rulebased/def/ckb_ar.cc",
     "rulebased/def/ckb_ar.h",
+    "rulebased/def/ckb_en.cc",
     "rulebased/def/ckb_en.h",
     "rulebased/def/deva_phone.cc",
     "rulebased/def/deva_phone.h",
+    "rulebased/def/fa.cc",
     "rulebased/def/fa.h",
+    "rulebased/def/km.cc",
     "rulebased/def/km.h",
+    "rulebased/def/lo.cc",
     "rulebased/def/lo.h",
+    "rulebased/def/ne_inscript.cc",
     "rulebased/def/ne_inscript.h",
+    "rulebased/def/ru_phone_aatseel.cc",
     "rulebased/def/ru_phone_aatseel.h",
+    "rulebased/def/ru_phone_yazhert.cc",
     "rulebased/def/ru_phone_yazhert.h",
+    "rulebased/def/ta_inscript.cc",
     "rulebased/def/ta_inscript.h",
+    "rulebased/def/ta_typewriter.cc",
     "rulebased/def/ta_typewriter.h",
+    "rulebased/def/th.cc",
     "rulebased/def/th.h",
+    "rulebased/def/th_pattajoti.cc",
     "rulebased/def/th_pattajoti.h",
+    "rulebased/def/th_tis.cc",
     "rulebased/def/th_tis.h",
     "rulebased/def/us.cc",
     "rulebased/def/us.h",
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ar.cc b/chromeos/services/ime/public/cpp/rulebased/def/ar.cc
new file mode 100644
index 0000000..1a411fa
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ar.cc
@@ -0,0 +1,415 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/ar.h"
+
+namespace ar {
+
+const char* kId = "ar";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u0630",        // BackQuote
+    u8"\u0661",        // Digit1
+    u8"\u0662",        // Digit2
+    u8"\u0663",        // Digit3
+    u8"\u0664",        // Digit4
+    u8"\u0665",        // Digit5
+    u8"\u0666",        // Digit6
+    u8"\u0667",        // Digit7
+    u8"\u0668",        // Digit8
+    u8"\u0669",        // Digit9
+    u8"\u0660",        // Digit0
+    u8"-",             // Minus
+    u8"=",             // Equal
+    u8"\u0636",        // KeyQ
+    u8"\u0635",        // KeyW
+    u8"\u062b",        // KeyE
+    u8"\u0642",        // KeyR
+    u8"\u0641",        // KeyT
+    u8"\u063a",        // KeyY
+    u8"\u0639",        // KeyU
+    u8"\u0647",        // KeyI
+    u8"\u062e",        // KeyO
+    u8"\u062d",        // KeyP
+    u8"\u062c",        // BracketLeft
+    u8"\u062f",        // BracketRight
+    u8"\\",            // Backslash
+    u8"\u0634",        // KeyA
+    u8"\u0633",        // KeyS
+    u8"\u064a",        // KeyD
+    u8"\u0628",        // KeyF
+    u8"\u0644",        // KeyG
+    u8"\u0627",        // KeyH
+    u8"\u062a",        // KeyJ
+    u8"\u0646",        // KeyK
+    u8"\u0645",        // KeyL
+    u8"\u0643",        // Semicolon
+    u8"\u0637",        // Quote
+    u8"\u0626",        // KeyZ
+    u8"\u0621",        // KeyX
+    u8"\u0624",        // KeyC
+    u8"\u0631",        // KeyV
+    u8"\u0644\u0627",  // KeyB
+    u8"\u0649",        // KeyN
+    u8"\u0629",        // KeyM
+    u8"\u0648",        // Comma
+    u8"\u0632",        // Period
+    u8"\u0638",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kShift[] = {
+    u8"\u0651",        // BackQuote
+    u8"!",             // Digit1
+    u8"\"",            // Digit2
+    u8"#",             // Digit3
+    u8"$",             // Digit4
+    u8"%",             // Digit5
+    u8"^",             // Digit6
+    u8"&",             // Digit7
+    u8"*",             // Digit8
+    u8")",             // Digit9
+    u8"(",             // Digit0
+    u8"_",             // Minus
+    u8"+",             // Equal
+    u8"\u064e",        // KeyQ
+    u8"\u064b",        // KeyW
+    u8"\u064f",        // KeyE
+    u8"\u064c",        // KeyR
+    u8"\u0644\u0625",  // KeyT
+    u8"\u0625",        // KeyY
+    u8"\u2018",        // KeyU
+    u8"\u00f7",        // KeyI
+    u8"\u00d7",        // KeyO
+    u8"\u061b",        // KeyP
+    u8"<",             // BracketLeft
+    u8">",             // BracketRight
+    u8"|",             // Backslash
+    u8"\u0650",        // KeyA
+    u8"\u064d",        // KeyS
+    u8"]",             // KeyD
+    u8"[",             // KeyF
+    u8"\u0644\u0623",  // KeyG
+    u8"\u0623",        // KeyH
+    u8"\u0640",        // KeyJ
+    u8"\u060c",        // KeyK
+    u8"/",             // KeyL
+    u8":",             // Semicolon
+    u8"@",             // Quote
+    u8"~",             // KeyZ
+    u8"\u0652",        // KeyX
+    u8"}",             // KeyC
+    u8"{",             // KeyV
+    u8"\u0644\u0622",  // KeyB
+    u8"\u0622",        // KeyN
+    u8"\u2019",        // KeyM
+    u8",",             // Comma
+    u8".",             // Period
+    u8"\u061f",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kAltGr[] = {
+    u8"\u0630",        // BackQuote
+    u8"\u0661",        // Digit1
+    u8"\u0662",        // Digit2
+    u8"\u0663",        // Digit3
+    u8"\u0664",        // Digit4
+    u8"\u0665",        // Digit5
+    u8"\u0666",        // Digit6
+    u8"\u0667",        // Digit7
+    u8"\u0668",        // Digit8
+    u8"\u0669",        // Digit9
+    u8"\u0660",        // Digit0
+    u8"-",             // Minus
+    u8"=",             // Equal
+    u8"\u0636",        // KeyQ
+    u8"\u0635",        // KeyW
+    u8"\u062b",        // KeyE
+    u8"\u0642",        // KeyR
+    u8"\u0641",        // KeyT
+    u8"\u063a",        // KeyY
+    u8"\u0639",        // KeyU
+    u8"\u0647",        // KeyI
+    u8"\u062e",        // KeyO
+    u8"\u062d",        // KeyP
+    u8"\u062c",        // BracketLeft
+    u8"\u062f",        // BracketRight
+    u8"\\",            // Backslash
+    u8"\u0634",        // KeyA
+    u8"\u0633",        // KeyS
+    u8"\u064a",        // KeyD
+    u8"\u0628",        // KeyF
+    u8"\u0644",        // KeyG
+    u8"\u0627",        // KeyH
+    u8"\u062a",        // KeyJ
+    u8"\u0646",        // KeyK
+    u8"\u0645",        // KeyL
+    u8"\u0643",        // Semicolon
+    u8"\u0637",        // Quote
+    u8"\u0626",        // KeyZ
+    u8"\u0621",        // KeyX
+    u8"\u0624",        // KeyC
+    u8"\u0631",        // KeyV
+    u8"\u0644\u0627",  // KeyB
+    u8"\u0649",        // KeyN
+    u8"\u0629",        // KeyM
+    u8"\u0648",        // Comma
+    u8"\u0632",        // Period
+    u8"\u0638",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kCapslock[] = {
+    u8"\u0630",        // BackQuote
+    u8"\u0661",        // Digit1
+    u8"\u0662",        // Digit2
+    u8"\u0663",        // Digit3
+    u8"\u0664",        // Digit4
+    u8"\u0665",        // Digit5
+    u8"\u0666",        // Digit6
+    u8"\u0667",        // Digit7
+    u8"\u0668",        // Digit8
+    u8"\u0669",        // Digit9
+    u8"\u0660",        // Digit0
+    u8"-",             // Minus
+    u8"=",             // Equal
+    u8"\u0636",        // KeyQ
+    u8"\u0635",        // KeyW
+    u8"\u062b",        // KeyE
+    u8"\u0642",        // KeyR
+    u8"\u0641",        // KeyT
+    u8"\u063a",        // KeyY
+    u8"\u0639",        // KeyU
+    u8"\u0647",        // KeyI
+    u8"\u062e",        // KeyO
+    u8"\u062d",        // KeyP
+    u8"\u062c",        // BracketLeft
+    u8"\u062f",        // BracketRight
+    u8"\\",            // Backslash
+    u8"\u0634",        // KeyA
+    u8"\u0633",        // KeyS
+    u8"\u064a",        // KeyD
+    u8"\u0628",        // KeyF
+    u8"\u0644",        // KeyG
+    u8"\u0627",        // KeyH
+    u8"\u062a",        // KeyJ
+    u8"\u0646",        // KeyK
+    u8"\u0645",        // KeyL
+    u8"\u0643",        // Semicolon
+    u8"\u0637",        // Quote
+    u8"\u0626",        // KeyZ
+    u8"\u0621",        // KeyX
+    u8"\u0624",        // KeyC
+    u8"\u0631",        // KeyV
+    u8"\u0644\u0627",  // KeyB
+    u8"\u0649",        // KeyN
+    u8"\u0629",        // KeyM
+    u8"\u0648",        // Comma
+    u8"\u0632",        // Period
+    u8"\u0638",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kShiftAltGr[] = {
+    u8"\u0651",        // BackQuote
+    u8"!",             // Digit1
+    u8"\"",            // Digit2
+    u8"#",             // Digit3
+    u8"$",             // Digit4
+    u8"%",             // Digit5
+    u8"^",             // Digit6
+    u8"&",             // Digit7
+    u8"*",             // Digit8
+    u8")",             // Digit9
+    u8"(",             // Digit0
+    u8"_",             // Minus
+    u8"+",             // Equal
+    u8"\u064e",        // KeyQ
+    u8"\u064b",        // KeyW
+    u8"\u064f",        // KeyE
+    u8"\u064c",        // KeyR
+    u8"\u0644\u0625",  // KeyT
+    u8"\u0625",        // KeyY
+    u8"\u2018",        // KeyU
+    u8"\u00f7",        // KeyI
+    u8"\u00d7",        // KeyO
+    u8"\u061b",        // KeyP
+    u8"<",             // BracketLeft
+    u8">",             // BracketRight
+    u8"|",             // Backslash
+    u8"\u0650",        // KeyA
+    u8"\u064d",        // KeyS
+    u8"]",             // KeyD
+    u8"[",             // KeyF
+    u8"\u0644\u0623",  // KeyG
+    u8"\u0623",        // KeyH
+    u8"\u0640",        // KeyJ
+    u8"\u060c",        // KeyK
+    u8"/",             // KeyL
+    u8":",             // Semicolon
+    u8"@",             // Quote
+    u8"~",             // KeyZ
+    u8"\u0652",        // KeyX
+    u8"}",             // KeyC
+    u8"{",             // KeyV
+    u8"\u0644\u0622",  // KeyB
+    u8"\u0622",        // KeyN
+    u8"\u2019",        // KeyM
+    u8",",             // Comma
+    u8".",             // Period
+    u8"\u061f",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kAltgrCapslock[] = {
+    u8"\u0630",        // BackQuote
+    u8"\u0661",        // Digit1
+    u8"\u0662",        // Digit2
+    u8"\u0663",        // Digit3
+    u8"\u0664",        // Digit4
+    u8"\u0665",        // Digit5
+    u8"\u0666",        // Digit6
+    u8"\u0667",        // Digit7
+    u8"\u0668",        // Digit8
+    u8"\u0669",        // Digit9
+    u8"\u0660",        // Digit0
+    u8"-",             // Minus
+    u8"=",             // Equal
+    u8"\u0636",        // KeyQ
+    u8"\u0635",        // KeyW
+    u8"\u062b",        // KeyE
+    u8"\u0642",        // KeyR
+    u8"\u0641",        // KeyT
+    u8"\u063a",        // KeyY
+    u8"\u0639",        // KeyU
+    u8"\u0647",        // KeyI
+    u8"\u062e",        // KeyO
+    u8"\u062d",        // KeyP
+    u8"\u062c",        // BracketLeft
+    u8"\u062f",        // BracketRight
+    u8"\\",            // Backslash
+    u8"\u0634",        // KeyA
+    u8"\u0633",        // KeyS
+    u8"\u064a",        // KeyD
+    u8"\u0628",        // KeyF
+    u8"\u0644",        // KeyG
+    u8"\u0627",        // KeyH
+    u8"\u062a",        // KeyJ
+    u8"\u0646",        // KeyK
+    u8"\u0645",        // KeyL
+    u8"\u0643",        // Semicolon
+    u8"\u0637",        // Quote
+    u8"\u0626",        // KeyZ
+    u8"\u0621",        // KeyX
+    u8"\u0624",        // KeyC
+    u8"\u0631",        // KeyV
+    u8"\u0644\u0627",  // KeyB
+    u8"\u0649",        // KeyN
+    u8"\u0629",        // KeyM
+    u8"\u0648",        // Comma
+    u8"\u0632",        // Period
+    u8"\u0638",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kShiftCapslock[] = {
+    u8"\u0651",        // BackQuote
+    u8"!",             // Digit1
+    u8"\"",            // Digit2
+    u8"#",             // Digit3
+    u8"$",             // Digit4
+    u8"%",             // Digit5
+    u8"^",             // Digit6
+    u8"&",             // Digit7
+    u8"*",             // Digit8
+    u8")",             // Digit9
+    u8"(",             // Digit0
+    u8"_",             // Minus
+    u8"+",             // Equal
+    u8"\u064e",        // KeyQ
+    u8"\u064b",        // KeyW
+    u8"\u064f",        // KeyE
+    u8"\u064c",        // KeyR
+    u8"\u0644\u0625",  // KeyT
+    u8"\u0625",        // KeyY
+    u8"\u2018",        // KeyU
+    u8"\u00f7",        // KeyI
+    u8"\u00d7",        // KeyO
+    u8"\u061b",        // KeyP
+    u8"<",             // BracketLeft
+    u8">",             // BracketRight
+    u8"|",             // Backslash
+    u8"\u0650",        // KeyA
+    u8"\u064d",        // KeyS
+    u8"]",             // KeyD
+    u8"[",             // KeyF
+    u8"\u0644\u0623",  // KeyG
+    u8"\u0623",        // KeyH
+    u8"\u0640",        // KeyJ
+    u8"\u060c",        // KeyK
+    u8"/",             // KeyL
+    u8":",             // Semicolon
+    u8"@",             // Quote
+    u8"~",             // KeyZ
+    u8"\u0652",        // KeyX
+    u8"}",             // KeyC
+    u8"{",             // KeyV
+    u8"\u0644\u0622",  // KeyB
+    u8"\u0622",        // KeyN
+    u8"\u2019",        // KeyM
+    u8",",             // Comma
+    u8".",             // Period
+    u8"\u061f",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kShiftAltGrCapslock[] = {
+    u8"\u0651",        // BackQuote
+    u8"!",             // Digit1
+    u8"\"",            // Digit2
+    u8"#",             // Digit3
+    u8"$",             // Digit4
+    u8"%",             // Digit5
+    u8"^",             // Digit6
+    u8"&",             // Digit7
+    u8"*",             // Digit8
+    u8")",             // Digit9
+    u8"(",             // Digit0
+    u8"_",             // Minus
+    u8"+",             // Equal
+    u8"\u064e",        // KeyQ
+    u8"\u064b",        // KeyW
+    u8"\u064f",        // KeyE
+    u8"\u064c",        // KeyR
+    u8"\u0644\u0625",  // KeyT
+    u8"\u0625",        // KeyY
+    u8"\u2018",        // KeyU
+    u8"\u00f7",        // KeyI
+    u8"\u00d7",        // KeyO
+    u8"\u061b",        // KeyP
+    u8"<",             // BracketLeft
+    u8">",             // BracketRight
+    u8"|",             // Backslash
+    u8"\u0650",        // KeyA
+    u8"\u064d",        // KeyS
+    u8"]",             // KeyD
+    u8"[",             // KeyF
+    u8"\u0644\u0623",  // KeyG
+    u8"\u0623",        // KeyH
+    u8"\u0640",        // KeyJ
+    u8"\u060c",        // KeyK
+    u8"/",             // KeyL
+    u8":",             // Semicolon
+    u8"@",             // Quote
+    u8"~",             // KeyZ
+    u8"\u0652",        // KeyX
+    u8"}",             // KeyC
+    u8"{",             // KeyV
+    u8"\u0644\u0622",  // KeyB
+    u8"\u0622",        // KeyN
+    u8"\u2019",        // KeyM
+    u8",",             // Comma
+    u8".",             // Period
+    u8"\u061f",        // Slash
+    u8"\u0020",        // Space
+};
+const char** kKeyMap[8] = {
+    kNormal,   kShift,         kAltGr,         kShiftAltGr,
+    kCapslock, kShiftCapslock, kAltgrCapslock, kShiftAltGrCapslock};
+
+}  // namespace ar
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ar.h b/chromeos/services/ime/public/cpp/rulebased/def/ar.h
index 58777bba..b3e2dd4f 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/ar.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ar.h
@@ -5,31 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_AR_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_AR_H_
 
-const wchar_t* key_map_ar[] = {
-    // Row #1
-    L"\u0630\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u0660-="
-    // Row #2
-    L"\u0636\u0635\u062b\u0642\u0641\u063a\u0639\u0647\u062e\u062d\u062c\u062f"
-    L"\\"
-    // Row #3
-    L"\u0634\u0633\u064a\u0628\u0644\u0627\u062a\u0646\u0645\u0643\u0637"
-    // Row #4
-    L"\u0626\u0621\u0624\u0631{{\u0644\u0627}}\u0649\u0629\u0648\u0632\u0638"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u0651!\"#$%^&*)(_+"
-    // Row #2
-    L"\u064e\u064b\u064f\u064c{{\u0644\u0625}}\u0625\u2018\u00f7\u00d7\u061b<>|"
-    // Row #3
-    L"\u0650\u064d][{{\u0644\u0623}}\u0623\u0640\u060c/:@"
-    // Row #4
-    L"~\u0652}{((\u0644\u0622))\u0622\u2019,.\u061f"
-    // Row #5
-    L"\u0020"};
+namespace ar {
 
-const uint8_t key_map_index_ar[8]{0, 1, 0, 1, 0, 1, 0, 1};
-const char* id_ar = "ar";
-const bool is_102_ar = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace ar
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_AR_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ckb_ar.cc b/chromeos/services/ime/public/cpp/rulebased/def/ckb_ar.cc
new file mode 100644
index 0000000..e13d697
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ckb_ar.cc
@@ -0,0 +1,114 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/ckb_ar.h"
+
+namespace ckb_ar {
+
+const char* kId = "ckb_ar";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u0698",        // BackQuote
+    u8"\u0661",        // Digit1
+    u8"\u0662",        // Digit2
+    u8"\u0663",        // Digit3
+    u8"\u0664",        // Digit4
+    u8"\u0665",        // Digit5
+    u8"\u0666",        // Digit6
+    u8"\u0667",        // Digit7
+    u8"\u0668",        // Digit8
+    u8"\u0669",        // Digit9
+    u8"\u0660",        // Digit0
+    u8"-",             // Minus
+    u8"=",             // Equal
+    u8"\u0686",        // KeyQ
+    u8"\u0635",        // KeyW
+    u8"\u067e",        // KeyE
+    u8"\u0642",        // KeyR
+    u8"\u0641",        // KeyT
+    u8"\u063a",        // KeyY
+    u8"\u0639",        // KeyU
+    u8"\u0647",        // KeyI
+    u8"\u062e",        // KeyO
+    u8"\u062d",        // KeyP
+    u8"\u062c",        // BracketLeft
+    u8"\u062f",        // BracketRight
+    u8"\\",            // Backslash
+    u8"\u0634",        // KeyA
+    u8"\u0633",        // KeyS
+    u8"\u06cc",        // KeyD
+    u8"\u0628",        // KeyF
+    u8"\u0644",        // KeyG
+    u8"\u0627",        // KeyH
+    u8"\u062a",        // KeyJ
+    u8"\u0646",        // KeyK
+    u8"\u0645",        // KeyL
+    u8"\u06a9",        // Semicolon
+    u8"\u06af",        // Quote
+    u8"\u0626",        // KeyZ
+    u8"\u0621",        // KeyX
+    u8"\u06c6",        // KeyC
+    u8"\u0631",        // KeyV
+    u8"\u0644\u0627",  // KeyB
+    u8"\u0649",        // KeyN
+    u8"\u0647\u200c",  // KeyM
+    u8"\u0648",        // Comma
+    u8"\u0632",        // Period
+    u8"/",             // Slash
+    u8"\u0020",        // Space
+};
+const char* kShift[] = {
+    u8"~",             // BackQuote
+    u8"!",             // Digit1
+    u8"@",             // Digit2
+    u8"#",             // Digit3
+    u8"$",             // Digit4
+    u8"%",             // Digit5
+    u8"\u00bb",        // Digit6
+    u8"\u00ab",        // Digit7
+    u8"*",             // Digit8
+    u8")",             // Digit9
+    u8"(",             // Digit0
+    u8"_",             // Minus
+    u8"+",             // Equal
+    u8"\u0636",        // KeyQ
+    u8"}",             // KeyW
+    u8"\u062b",        // KeyE
+    u8"{",             // KeyR
+    u8"\u06a4",        // KeyT
+    u8"\u0625",        // KeyY
+    u8"",              // KeyU
+    u8"'",             // KeyI
+    u8"\"",            // KeyO
+    u8"\u061b",        // KeyP
+    u8">",             // BracketLeft
+    u8"<",             // BracketRight
+    u8"|",             // Backslash
+    u8"]",             // KeyA
+    u8"[",             // KeyS
+    u8"\u06ce",        // KeyD
+    u8"",              // KeyF
+    u8"\u06b5",        // KeyG
+    u8"\u0623",        // KeyH
+    u8"\u0640",        // KeyJ
+    u8"\u060c",        // KeyK
+    u8"/",             // KeyL
+    u8":",             // Semicolon
+    u8"\u0637",        // Quote
+    u8"\u2904",        // KeyZ
+    u8"\u0648\u0648",  // KeyX
+    u8"\u0624",        // KeyC
+    u8"\u0695",        // KeyV
+    u8"\u06b5\u0627",  // KeyB
+    u8"\u0622",        // KeyN
+    u8"\u0629",        // KeyM
+    u8",",             // Comma
+    u8".",             // Period
+    u8"\u061f",        // Slash
+    u8"\u200c",        // Space
+};
+const char** kKeyMap[8] = {kNormal, kShift, kNormal, kShift,
+                           kNormal, kShift, kNormal, kShift};
+
+}  // namespace ckb_ar
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ckb_ar.h b/chromeos/services/ime/public/cpp/rulebased/def/ckb_ar.h
index 71dcc7e..14e402a 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/ckb_ar.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ckb_ar.h
@@ -5,32 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_CKB_AR_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_CKB_AR_H_
 
-const wchar_t* key_map_ckb_ar[] = {
-    // Row #1
-    L"\u0698\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u0660-="
-    // Row #2
-    L"\u0686\u0635\u067e\u0642\u0641\u063a\u0639\u0647\u062e\u062d\u062c\u062f"
-    L"\\"
-    // Row #3
-    L"\u0634\u0633\u06cc\u0628\u0644\u0627\u062a\u0646\u0645\u06a9\u06af"
-    // Row #4
-    L"\u0626\u0621\u06c6\u0631{{\u0644\u0627}}\u0649{{\u0647\u200c}}\u0648"
-    L"\u0632/"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"~!@#$%\u00bb\u00ab*)(_+"
-    // Row #2
-    L"\u0636}\u062b{\u06a4\u0625{{}}'\"\u061b><|"
-    // Row #3
-    L"][\u06ce{{}}\u06b5\u0623\u0640\u060c/:\u0637"
-    // Row #4
-    L"\u2904{{\u0648\u0648}}\u0624\u0695{{\u06b5\u0627}}\u0622\u0629,.\u061f"
-    // Row #5
-    L"\u200c"};
+namespace ckb_ar {
 
-const uint8_t key_map_index_ckb_ar[8]{0, 1, 0, 1, 0, 1, 0, 0};
-const char* id_ckb_ar = "ckb_ar";
-const bool is_102_ckb_ar = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace ckb_ar
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_CKB_AR_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ckb_en.cc b/chromeos/services/ime/public/cpp/rulebased/def/ckb_en.cc
new file mode 100644
index 0000000..b8920f3
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ckb_en.cc
@@ -0,0 +1,114 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/ckb_en.h"
+
+namespace ckb_en {
+
+const char* kId = "ckb_en";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u20ac",  // BackQuote
+    u8"\u0661",  // Digit1
+    u8"\u0662",  // Digit2
+    u8"\u0663",  // Digit3
+    u8"\u0664",  // Digit4
+    u8"\u0665",  // Digit5
+    u8"\u0666",  // Digit6
+    u8"\u0667",  // Digit7
+    u8"\u0668",  // Digit8
+    u8"\u0669",  // Digit9
+    u8"\u0660",  // Digit0
+    u8"-",       // Minus
+    u8"=",       // Equal
+    u8"\u0642",  // KeyQ
+    u8"\u0648",  // KeyW
+    u8"\u06d5",  // KeyE
+    u8"\u0631",  // KeyR
+    u8"\u062a",  // KeyT
+    u8"\u06cc",  // KeyY
+    u8"\u0626",  // KeyU
+    u8"\u062d",  // KeyI
+    u8"\u06c6",  // KeyO
+    u8"\u067e",  // KeyP
+    u8"}",       // BracketLeft
+    u8"{",       // BracketRight
+    u8"\\",      // Backslash
+    u8"\u0627",  // KeyA
+    u8"\u0633",  // KeyS
+    u8"\u062f",  // KeyD
+    u8"\u0641",  // KeyF
+    u8"\u06af",  // KeyG
+    u8"\u0647",  // KeyH
+    u8"\u0698",  // KeyJ
+    u8"\u06a9",  // KeyK
+    u8"\u0644",  // KeyL
+    u8"\u061b",  // Semicolon
+    u8"'",       // Quote
+    u8"\u0632",  // KeyZ
+    u8"\u062e",  // KeyX
+    u8"\u062c",  // KeyC
+    u8"\u06a4",  // KeyV
+    u8"\u0628",  // KeyB
+    u8"\u0646",  // KeyN
+    u8"\u0645",  // KeyM
+    u8"\u060c",  // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"~",             // BackQuote
+    u8"!",             // Digit1
+    u8"@",             // Digit2
+    u8"#",             // Digit3
+    u8"$",             // Digit4
+    u8"%",             // Digit5
+    u8"\u00bb",        // Digit6
+    u8"\u00ab",        // Digit7
+    u8"*",             // Digit8
+    u8")",             // Digit9
+    u8"(",             // Digit0
+    u8"_",             // Minus
+    u8"+",             // Equal
+    u8"`",             // KeyQ
+    u8"\u0648\u0648",  // KeyW
+    u8"\u064a",        // KeyE
+    u8"\u0695",        // KeyR
+    u8"\u0637",        // KeyT
+    u8"\u06ce",        // KeyY
+    u8"\u0621",        // KeyU
+    u8"\u0639",        // KeyI
+    u8"\u0624",        // KeyO
+    u8"\u062b",        // KeyP
+    u8"]",             // BracketLeft
+    u8"[",             // BracketRight
+    u8"|",             // Backslash
+    u8"\u0622",        // KeyA
+    u8"\u0634",        // KeyS
+    u8"\u0630",        // KeyD
+    u8"\u0625",        // KeyF
+    u8"\u063a",        // KeyG
+    u8"\u200c",        // KeyH
+    u8"\u0623",        // KeyJ
+    u8"\u0643",        // KeyK
+    u8"\u06b5",        // KeyL
+    u8":",             // Semicolon
+    u8"\"",            // Quote
+    u8"\u0636",        // KeyZ
+    u8"\u0635",        // KeyX
+    u8"\u0686",        // KeyC
+    u8"\u0638",        // KeyV
+    u8"\u0649",        // KeyB
+    u8"\u0629",        // KeyN
+    u8"\u0640",        // KeyM
+    u8">",             // Comma
+    u8"<",             // Period
+    u8"\u061f",        // Slash
+    u8"\u200c",        // Space
+};
+const char** kKeyMap[8] = {kNormal, kShift, kNormal, kShift,
+                           kNormal, kShift, kNormal, kShift};
+
+}  // namespace ckb_en
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ckb_en.h b/chromeos/services/ime/public/cpp/rulebased/def/ckb_en.h
index a7db39d..d73a0790 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/ckb_en.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ckb_en.h
@@ -5,30 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_CKB_EN_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_CKB_EN_H_
 
-const wchar_t* key_map_ckb_en[] = {
-    // Row #1
-    L"\u20ac\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u0660-="
-    // Row #2
-    L"\u0642\u0648\u06d5\u0631\u062a\u06cc\u0626\u062d\u06c6\u067e}{\\"
-    // Row #3
-    L"\u0627\u0633\u062f\u0641\u06af\u0647\u0698\u06a9\u0644\u061b'"
-    // Row #4
-    L"\u0632\u062e\u062c\u06a4\u0628\u0646\u0645\u060c./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"~!@#$%\u00bb\u00ab*)(_+"
-    // Row #2
-    L"`{{\u0648\u0648}}\u064a\u0695\u0637\u06ce\u0621\u0639\u0624\u062b][|"
-    // Row #3
-    L"\u0622\u0634\u0630\u0625\u063a\u200c\u0623\u0643\u06b5:\""
-    // Row #4
-    L"\u0636\u0635\u0686\u0638\u0649\u0629\u0640><\u061f"
-    // Row #5
-    L"\u200c"};
+namespace ckb_en {
 
-const uint8_t key_map_index_ckb_en[8]{0, 1, 0, 1, 0, 1, 0, 0};
-const char* id_ckb_en = "ckb_en";
-const bool is_102_ckb_en = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace ckb_en
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_CKB_EN_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/deva_phone.cc b/chromeos/services/ime/public/cpp/rulebased/def/deva_phone.cc
index e348761..f9aba394 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/deva_phone.cc
+++ b/chromeos/services/ime/public/cpp/rulebased/def/deva_phone.cc
@@ -6,7 +6,9 @@
 
 #include "base/stl_util.h"
 
-const char* kTransformsDevaPhone[] = {
+namespace deva_phone {
+
+const char* kTransforms[] = {
     u8"0",
     u8"\u0966",
     u8"1",
@@ -530,8 +532,10 @@
     u8"\u0964\u001d?\\.",
     u8"\u2026"};
 
-const unsigned int kTransformsDevaPhoneLen = base::size(kTransformsDevaPhone);
+const unsigned int kTransformsLen = base::size(kTransforms);
 
-const char* kHistoryPruneDevaPhone = "n(\\.)?|c|ch|C|nc|nC|nch|\\.|a";
+const char* kHistoryPrune = "n(\\.)?|c|ch|C|nc|nC|nch|\\.|a";
 
-const char* kIdDevaPhone = "deva_phone";
+const char* kId = "deva_phone";
+
+}  // namespace deva_phone
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/deva_phone.h b/chromeos/services/ime/public/cpp/rulebased/def/deva_phone.h
index aca1407..9000b59f 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/deva_phone.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/deva_phone.h
@@ -5,16 +5,20 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_DEVA_PHONE_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_DEVA_PHONE_H_
 
+namespace deva_phone {
+
 // The transform rules for the deva_phone IME.
-extern const char* kTransformsDevaPhone[];
+extern const char* kTransforms[];
 
 // The length of the transform rule for the deva_phone IME.
-extern const unsigned int kTransformsDevaPhoneLen;
+extern const unsigned int kTransformsLen;
 
 // The history prune regexp for the deva_phone IME.
-extern const char* kHistoryPruneDevaPhone;
+extern const char* kHistoryPrune;
 
 // The id of the deva_phone IME.
-extern const char* kIdDevaPhone;
+extern const char* kId;
+
+}  // namespace deva_phone
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_DEVA_PHONE_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/fa.cc b/chromeos/services/ime/public/cpp/rulebased/def/fa.cc
new file mode 100644
index 0000000..464fbbd9
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/fa.cc
@@ -0,0 +1,265 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/fa.h"
+
+namespace fa {
+
+const char* kId = "fa";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u200d",  // BackQuote
+    u8"\u06f1",  // Digit1
+    u8"\u06f2",  // Digit2
+    u8"\u06f3",  // Digit3
+    u8"\u06f4",  // Digit4
+    u8"\u06f5",  // Digit5
+    u8"\u06f6",  // Digit6
+    u8"\u06f7",  // Digit7
+    u8"\u06f8",  // Digit8
+    u8"\u06f9",  // Digit9
+    u8"\u06f0",  // Digit0
+    u8"-",       // Minus
+    u8"=",       // Equal
+    u8"\u0636",  // KeyQ
+    u8"\u0635",  // KeyW
+    u8"\u062b",  // KeyE
+    u8"\u0642",  // KeyR
+    u8"\u0641",  // KeyT
+    u8"\u063a",  // KeyY
+    u8"\u0639",  // KeyU
+    u8"\u0647",  // KeyI
+    u8"\u062e",  // KeyO
+    u8"\u062d",  // KeyP
+    u8"\u062c",  // BracketLeft
+    u8"\u0686",  // BracketRight
+    u8"\\",      // Backslash
+    u8"\u0634",  // KeyA
+    u8"\u0633",  // KeyS
+    u8"\u06cc",  // KeyD
+    u8"\u0628",  // KeyF
+    u8"\u0644",  // KeyG
+    u8"\u0627",  // KeyH
+    u8"\u062a",  // KeyJ
+    u8"\u0646",  // KeyK
+    u8"\u0645",  // KeyL
+    u8"\u06a9",  // Semicolon
+    u8"\u06af",  // Quote
+    u8"\u0638",  // KeyZ
+    u8"\u0637",  // KeyX
+    u8"\u0632",  // KeyC
+    u8"\u0631",  // KeyV
+    u8"\u0630",  // KeyB
+    u8"\u062f",  // KeyN
+    u8"\u067e",  // KeyM
+    u8"\u0648",  // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"",                          // BackQuote
+    u8"!",                         // Digit1
+    u8"\u066c",                    // Digit2
+    u8"\u066b",                    // Digit3
+    u8"\u0631\u06cc\u0627\u0644",  // Digit4
+    u8"\u066a",                    // Digit5
+    u8"\u00d7",                    // Digit6
+    u8"\u060c",                    // Digit7
+    u8"*",                         // Digit8
+    u8")",                         // Digit9
+    u8"(",                         // Digit0
+    u8"\u0640",                    // Minus
+    u8"+",                         // Equal
+    u8"\u0652",                    // KeyQ
+    u8"\u064c",                    // KeyW
+    u8"\u064d",                    // KeyE
+    u8"\u064b",                    // KeyR
+    u8"\u064f",                    // KeyT
+    u8"\u0650",                    // KeyY
+    u8"\u064e",                    // KeyU
+    u8"\u0651",                    // KeyI
+    u8"]",                         // KeyO
+    u8"[",                         // KeyP
+    u8"}",                         // BracketLeft
+    u8"{",                         // BracketRight
+    u8"|",                         // Backslash
+    u8"\u0624",                    // KeyA
+    u8"\u0626",                    // KeyS
+    u8"\u064a",                    // KeyD
+    u8"\u0625",                    // KeyF
+    u8"\u0623",                    // KeyG
+    u8"\u0622",                    // KeyH
+    u8"\u0629",                    // KeyJ
+    u8"\u00bb",                    // KeyK
+    u8"\u00ab",                    // KeyL
+    u8":",                         // Semicolon
+    u8"\u061b",                    // Quote
+    u8"\u0643",                    // KeyZ
+    u8"",                          // KeyX
+    u8"\u0698",                    // KeyC
+    u8"",                          // KeyV
+    u8"\u200c",                    // KeyB
+    u8"",                          // KeyN
+    u8"\u0621",                    // KeyM
+    u8"<",                         // Comma
+    u8">",                         // Period
+    u8"\u061f",                    // Slash
+    u8"\u200c",                    // Space
+};
+const char* kAltGr[] = {
+    u8"~",       // BackQuote
+    u8"`",       // Digit1
+    u8"@",       // Digit2
+    u8"#",       // Digit3
+    u8"$",       // Digit4
+    u8"%",       // Digit5
+    u8"^",       // Digit6
+    u8"&",       // Digit7
+    u8"\u2022",  // Digit8
+    u8"\u200e",  // Digit9
+    u8"\u200f",  // Digit0
+    u8"_",       // Minus
+    u8"\u2212",  // Equal
+    u8"\u00b0",  // KeyQ
+    u8"",        // KeyW
+    u8"\u20ac",  // KeyE
+    u8"",        // KeyR
+    u8"",        // KeyT
+    u8"",        // KeyY
+    u8"",        // KeyU
+    u8"\u202d",  // KeyI
+    u8"\u202e",  // KeyO
+    u8"\u202c",  // KeyP
+    u8"\u202a",  // BracketLeft
+    u8"\u202b",  // BracketRight
+    u8"\u2010",  // Backslash
+    u8"",        // KeyA
+    u8"",        // KeyS
+    u8"\u0649",  // KeyD
+    u8"",        // KeyF
+    u8"",        // KeyG
+    u8"\u0671",  // KeyH
+    u8"",        // KeyJ
+    u8"\ufd3e",  // KeyK
+    u8"\ufd3f",  // KeyL
+    u8";",       // Semicolon
+    u8"\"",      // Quote
+    u8"\u00a0",  // KeyZ
+    u8"",        // KeyX
+    u8"",        // KeyC
+    u8"\u0656",  // KeyV
+    u8"\u200d",  // KeyB
+    u8"\u0655",  // KeyN
+    u8"\u2026",  // KeyM
+    u8",",       // Comma
+    u8"'",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"\u200d",  // BackQuote
+    u8"\u06f1",  // Digit1
+    u8"\u06f2",  // Digit2
+    u8"\u06f3",  // Digit3
+    u8"\u06f4",  // Digit4
+    u8"\u06f5",  // Digit5
+    u8"\u06f6",  // Digit6
+    u8"\u06f7",  // Digit7
+    u8"\u06f8",  // Digit8
+    u8"\u06f9",  // Digit9
+    u8"\u06f0",  // Digit0
+    u8"-",       // Minus
+    u8"=",       // Equal
+    u8"\u0636",  // KeyQ
+    u8"\u0635",  // KeyW
+    u8"\u062b",  // KeyE
+    u8"\u0642",  // KeyR
+    u8"\u0641",  // KeyT
+    u8"\u063a",  // KeyY
+    u8"\u0639",  // KeyU
+    u8"\u0647",  // KeyI
+    u8"\u062e",  // KeyO
+    u8"\u062d",  // KeyP
+    u8"\u062c",  // BracketLeft
+    u8"\u0686",  // BracketRight
+    u8"\\",      // Backslash
+    u8"\u0634",  // KeyA
+    u8"\u0633",  // KeyS
+    u8"\u06cc",  // KeyD
+    u8"\u0628",  // KeyF
+    u8"\u0644",  // KeyG
+    u8"\u0627",  // KeyH
+    u8"\u062a",  // KeyJ
+    u8"\u0646",  // KeyK
+    u8"\u0645",  // KeyL
+    u8"\u06a9",  // Semicolon
+    u8"\u06af",  // Quote
+    u8"\u0638",  // KeyZ
+    u8"\u0637",  // KeyX
+    u8"\u0632",  // KeyC
+    u8"\u0631",  // KeyV
+    u8"\u0630",  // KeyB
+    u8"\u062f",  // KeyN
+    u8"\u067e",  // KeyM
+    u8"\u0648",  // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftCapslock[] = {
+    u8"",                          // BackQuote
+    u8"!",                         // Digit1
+    u8"\u066c",                    // Digit2
+    u8"\u066b",                    // Digit3
+    u8"\u0631\u06cc\u0627\u0644",  // Digit4
+    u8"\u066a",                    // Digit5
+    u8"\u00d7",                    // Digit6
+    u8"\u060c",                    // Digit7
+    u8"*",                         // Digit8
+    u8")",                         // Digit9
+    u8"(",                         // Digit0
+    u8"\u0640",                    // Minus
+    u8"+",                         // Equal
+    u8"\u0652",                    // KeyQ
+    u8"\u064c",                    // KeyW
+    u8"\u064d",                    // KeyE
+    u8"\u064b",                    // KeyR
+    u8"\u064f",                    // KeyT
+    u8"\u0650",                    // KeyY
+    u8"\u064e",                    // KeyU
+    u8"\u0651",                    // KeyI
+    u8"]",                         // KeyO
+    u8"[",                         // KeyP
+    u8"}",                         // BracketLeft
+    u8"{",                         // BracketRight
+    u8"|",                         // Backslash
+    u8"\u0624",                    // KeyA
+    u8"\u0626",                    // KeyS
+    u8"\u064a",                    // KeyD
+    u8"\u0625",                    // KeyF
+    u8"\u0623",                    // KeyG
+    u8"\u0622",                    // KeyH
+    u8"\u0629",                    // KeyJ
+    u8"\u00bb",                    // KeyK
+    u8"\u00ab",                    // KeyL
+    u8":",                         // Semicolon
+    u8"\u061b",                    // Quote
+    u8"\u0643",                    // KeyZ
+    u8"",                          // KeyX
+    u8"\u0698",                    // KeyC
+    u8"",                          // KeyV
+    u8"\u200c",                    // KeyB
+    u8"",                          // KeyN
+    u8"\u0621",                    // KeyM
+    u8"<",                         // Comma
+    u8">",                         // Period
+    u8"\u061f",                    // Slash
+    u8"\u200c",                    // Space
+};
+const char** kKeyMap[8] = {kNormal,   kShift,        kAltGr,
+                           kShift,    kCapslock,     kShiftCapslock,
+                           kCapslock, kShiftCapslock};
+
+}  // namespace fa
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/fa.h b/chromeos/services/ime/public/cpp/rulebased/def/fa.h
index 1f7a4b8d..d63cf449 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/fa.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/fa.h
@@ -5,41 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_FA_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_FA_H_
 
-const wchar_t* key_map_fa[] = {
-    // Row #1
-    L"\u200d\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u06f0-="
-    // Row #2
-    L"\u0636\u0635\u062b\u0642\u0641\u063a\u0639\u0647\u062e\u062d\u062c\u0686"
-    L"\\"
-    // Row #3
-    L"\u0634\u0633\u06cc\u0628\u0644\u0627\u062a\u0646\u0645\u06a9\u06af"
-    // Row #4
-    L"\u0638\u0637\u0632\u0631\u0630\u062f\u067e\u0648./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"{{}}!\u066c\u066b{{\u0631\u06cc\u0627\u0644}}\u066a\u00d7\u060c*)(\u0640+"
-    // Row #2
-    L"\u0652\u064c\u064d\u064b\u064f\u0650\u064e\u0651][}{|"
-    // Row #3
-    L"\u0624\u0626\u064a\u0625\u0623\u0622\u0629\u00bb\u00ab:\u061b"
-    // Row #4
-    L"\u0643{{}}\u0698{{}}\u200c{{}}\u0621<>\u061f"
-    // Row #5
-    L"\u200c",
-    // Row #1
-    L"~`@#$%^&\u2022\u200e\u200f_\u2212"
-    // Row #2
-    L"\u00b0{{}}\u20ac{{}}{{}}{{}}{{}}\u202d\u202e\u202c\u202a\u202b\u2010"
-    // Row #3
-    L"{{}}{{}}\u0649{{}}{{}}\u0671{{}}\ufd3e\ufd3f;\""
-    // Row #4
-    L"\u00a0{{}}{{}}\u0656\u200d\u0655\u2026,'?"
-    // Row #5
-    L"\u0020"};
+namespace fa {
 
-const uint8_t key_map_index_fa[8]{0, 1, 2, 1, 0, 1, 0, 1};
-const char* id_fa = "fa";
-const bool is_102_fa = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace fa
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_FA_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/km.cc b/chromeos/services/ime/public/cpp/rulebased/def/km.cc
new file mode 100644
index 0000000..9d4ce03
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/km.cc
@@ -0,0 +1,415 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/km.h"
+
+namespace km {
+
+const char* kId = "km";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u00ab",        // BackQuote
+    u8"\u17e1",        // Digit1
+    u8"\u17e2",        // Digit2
+    u8"\u17e3",        // Digit3
+    u8"\u17e4",        // Digit4
+    u8"\u17e5",        // Digit5
+    u8"\u17e6",        // Digit6
+    u8"\u17e7",        // Digit7
+    u8"\u17e8",        // Digit8
+    u8"\u17e9",        // Digit9
+    u8"\u17e0",        // Digit0
+    u8"\u17a5",        // Minus
+    u8"\u17b2",        // Equal
+    u8"\u1786",        // KeyQ
+    u8"\u17b9",        // KeyW
+    u8"\u17c1",        // KeyE
+    u8"\u179a",        // KeyR
+    u8"\u178f",        // KeyT
+    u8"\u1799",        // KeyY
+    u8"\u17bb",        // KeyU
+    u8"\u17b7",        // KeyI
+    u8"\u17c4",        // KeyO
+    u8"\u1795",        // KeyP
+    u8"\u17c0",        // BracketLeft
+    u8"\u17aa",        // BracketRight
+    u8"\u17ae",        // Backslash
+    u8"\u17b6",        // KeyA
+    u8"\u179f",        // KeyS
+    u8"\u178a",        // KeyD
+    u8"\u1790",        // KeyF
+    u8"\u1784",        // KeyG
+    u8"\u17a0",        // KeyH
+    u8"\u17d2",        // KeyJ
+    u8"\u1780",        // KeyK
+    u8"\u179b",        // KeyL
+    u8"\u17be",        // Semicolon
+    u8"\u17cb",        // Quote
+    u8"\u178b",        // KeyZ
+    u8"\u1781",        // KeyX
+    u8"\u1785",        // KeyC
+    u8"\u179c",        // KeyV
+    u8"\u1794",        // KeyB
+    u8"\u1793",        // KeyN
+    u8"\u1798",        // KeyM
+    u8"\u17bb\u17c6",  // Comma
+    u8"\u17d4",        // Period
+    u8"\u17ca",        // Slash
+    u8"\u200b",        // Space
+};
+const char* kShift[] = {
+    u8"\u00bb",        // BackQuote
+    u8"!",             // Digit1
+    u8"\u17d7",        // Digit2
+    u8"\"",            // Digit3
+    u8"\u17db",        // Digit4
+    u8"%",             // Digit5
+    u8"\u17cd",        // Digit6
+    u8"\u17d0",        // Digit7
+    u8"\u17cf",        // Digit8
+    u8"(",             // Digit9
+    u8")",             // Digit0
+    u8"\u17cc",        // Minus
+    u8"=",             // Equal
+    u8"\u1788",        // KeyQ
+    u8"\u17ba",        // KeyW
+    u8"\u17c2",        // KeyE
+    u8"\u17ac",        // KeyR
+    u8"\u1791",        // KeyT
+    u8"\u17bd",        // KeyY
+    u8"\u17bc",        // KeyU
+    u8"\u17b8",        // KeyI
+    u8"\u17c5",        // KeyO
+    u8"\u1797",        // KeyP
+    u8"\u17bf",        // BracketLeft
+    u8"\u17a7",        // BracketRight
+    u8"\u17ad",        // Backslash
+    u8"\u17b6\u17c6",  // KeyA
+    u8"\u17c3",        // KeyS
+    u8"\u178c",        // KeyD
+    u8"\u1792",        // KeyF
+    u8"\u17a2",        // KeyG
+    u8"\u17c7",        // KeyH
+    u8"\u1789",        // KeyJ
+    u8"\u1782",        // KeyK
+    u8"\u17a1",        // KeyL
+    u8"\u17c4\u17c7",  // Semicolon
+    u8"\u17c9",        // Quote
+    u8"\u178d",        // KeyZ
+    u8"\u1783",        // KeyX
+    u8"\u1787",        // KeyC
+    u8"\u17c1\u17c7",  // KeyV
+    u8"\u1796",        // KeyB
+    u8"\u178e",        // KeyN
+    u8"\u17c6",        // KeyM
+    u8"\u17bb\u17c7",  // Comma
+    u8"\u17d5",        // Period
+    u8"?",             // Slash
+    u8"\u0020",        // Space
+};
+const char* kAltGr[] = {
+    u8"\u200d",  // BackQuote
+    u8"\u200c",  // Digit1
+    u8"@",       // Digit2
+    u8"\u17d1",  // Digit3
+    u8"$",       // Digit4
+    u8"\u20ac",  // Digit5
+    u8"\u17d9",  // Digit6
+    u8"\u17da",  // Digit7
+    u8"*",       // Digit8
+    u8"{",       // Digit9
+    u8"}",       // Digit0
+    u8"\u00d7",  // Minus
+    u8"\u17ce",  // Equal
+    u8"\u17dc",  // KeyQ
+    u8"\u17dd",  // KeyW
+    u8"\u17af",  // KeyE
+    u8"\u17ab",  // KeyR
+    u8"\u17a8",  // KeyT
+    u8"",        // KeyY
+    u8"",        // KeyU
+    u8"\u17a6",  // KeyI
+    u8"\u17b1",  // KeyO
+    u8"\u17b0",  // KeyP
+    u8"\u17a9",  // BracketLeft
+    u8"\u17b3",  // BracketRight
+    u8"\\",      // Backslash
+    u8"+",       // KeyA
+    u8"-",       // KeyS
+    u8"",        // KeyD
+    u8"",        // KeyF
+    u8"",        // KeyG
+    u8"",        // KeyH
+    u8"",        // KeyJ
+    u8"\u179d",  // KeyK
+    u8"",        // KeyL
+    u8"\u17d6",  // Semicolon
+    u8"\u17c8",  // Quote
+    u8"",        // KeyZ
+    u8"",        // KeyX
+    u8"",        // KeyC
+    u8"",        // KeyV
+    u8"\u179e",  // KeyB
+    u8"",        // KeyN
+    u8"",        // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"\u00bb",        // BackQuote
+    u8"!",             // Digit1
+    u8"\u17d7",        // Digit2
+    u8"\"",            // Digit3
+    u8"\u17db",        // Digit4
+    u8"%",             // Digit5
+    u8"\u17cd",        // Digit6
+    u8"\u17d0",        // Digit7
+    u8"\u17cf",        // Digit8
+    u8"(",             // Digit9
+    u8")",             // Digit0
+    u8"\u17cc",        // Minus
+    u8"=",             // Equal
+    u8"\u1788",        // KeyQ
+    u8"\u17ba",        // KeyW
+    u8"\u17c2",        // KeyE
+    u8"\u17ac",        // KeyR
+    u8"\u1791",        // KeyT
+    u8"\u17bd",        // KeyY
+    u8"\u17bc",        // KeyU
+    u8"\u17b8",        // KeyI
+    u8"\u17c5",        // KeyO
+    u8"\u1797",        // KeyP
+    u8"\u17bf",        // BracketLeft
+    u8"\u17a7",        // BracketRight
+    u8"\u17ad",        // Backslash
+    u8"\u17b6\u17c6",  // KeyA
+    u8"\u17c3",        // KeyS
+    u8"\u178c",        // KeyD
+    u8"\u1792",        // KeyF
+    u8"\u17a2",        // KeyG
+    u8"\u17c7",        // KeyH
+    u8"\u1789",        // KeyJ
+    u8"\u1782",        // KeyK
+    u8"\u17a1",        // KeyL
+    u8"\u17c4\u17c7",  // Semicolon
+    u8"\u17c9",        // Quote
+    u8"\u178d",        // KeyZ
+    u8"\u1783",        // KeyX
+    u8"\u1787",        // KeyC
+    u8"\u17c1\u17c7",  // KeyV
+    u8"\u1796",        // KeyB
+    u8"\u178e",        // KeyN
+    u8"\u17c6",        // KeyM
+    u8"\u17bb\u17c7",  // Comma
+    u8"\u17d5",        // Period
+    u8"?",             // Slash
+    u8"\u0020",        // Space
+};
+const char* kShiftAltGr[] = {
+    u8"",        // BackQuote
+    u8"\u17f1",  // Digit1
+    u8"\u17f2",  // Digit2
+    u8"\u17f3",  // Digit3
+    u8"\u17f4",  // Digit4
+    u8"\u17f5",  // Digit5
+    u8"\u17f6",  // Digit6
+    u8"\u17f7",  // Digit7
+    u8"\u17f8",  // Digit8
+    u8"\u17f9",  // Digit9
+    u8"\u17f0",  // Digit0
+    u8"",        // Minus
+    u8"",        // Equal
+    u8"\u19e0",  // KeyQ
+    u8"\u19e1",  // KeyW
+    u8"\u19e2",  // KeyE
+    u8"\u19e3",  // KeyR
+    u8"\u19e4",  // KeyT
+    u8"\u19e5",  // KeyY
+    u8"\u19e6",  // KeyU
+    u8"\u19e7",  // KeyI
+    u8"\u19e8",  // KeyO
+    u8"\u19e9",  // KeyP
+    u8"\u19ea",  // BracketLeft
+    u8"\u19eb",  // BracketRight
+    u8"",        // Backslash
+    u8"\u19ec",  // KeyA
+    u8"\u19ed",  // KeyS
+    u8"\u19ee",  // KeyD
+    u8"\u19ef",  // KeyF
+    u8"\u19f0",  // KeyG
+    u8"\u19f1",  // KeyH
+    u8"\u19f2",  // KeyJ
+    u8"\u19f3",  // KeyK
+    u8"\u19f4",  // KeyL
+    u8"\u19f5",  // Semicolon
+    u8"\u19f6",  // Quote
+    u8"\u19f7",  // KeyZ
+    u8"\u19f8",  // KeyX
+    u8"\u19f9",  // KeyC
+    u8"\u19fa",  // KeyV
+    u8"\u19fb",  // KeyB
+    u8"\u19fc",  // KeyN
+    u8"\u19fd",  // KeyM
+    u8"\u19fe",  // Comma
+    u8"\u19ff",  // Period
+    u8"",        // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltgrCapslock[] = {
+    u8"",        // BackQuote
+    u8"\u17f1",  // Digit1
+    u8"\u17f2",  // Digit2
+    u8"\u17f3",  // Digit3
+    u8"\u17f4",  // Digit4
+    u8"\u17f5",  // Digit5
+    u8"\u17f6",  // Digit6
+    u8"\u17f7",  // Digit7
+    u8"\u17f8",  // Digit8
+    u8"\u17f9",  // Digit9
+    u8"\u17f0",  // Digit0
+    u8"",        // Minus
+    u8"",        // Equal
+    u8"\u19e0",  // KeyQ
+    u8"\u19e1",  // KeyW
+    u8"\u19e2",  // KeyE
+    u8"\u19e3",  // KeyR
+    u8"\u19e4",  // KeyT
+    u8"\u19e5",  // KeyY
+    u8"\u19e6",  // KeyU
+    u8"\u19e7",  // KeyI
+    u8"\u19e8",  // KeyO
+    u8"\u19e9",  // KeyP
+    u8"\u19ea",  // BracketLeft
+    u8"\u19eb",  // BracketRight
+    u8"",        // Backslash
+    u8"\u19ec",  // KeyA
+    u8"\u19ed",  // KeyS
+    u8"\u19ee",  // KeyD
+    u8"\u19ef",  // KeyF
+    u8"\u19f0",  // KeyG
+    u8"\u19f1",  // KeyH
+    u8"\u19f2",  // KeyJ
+    u8"\u19f3",  // KeyK
+    u8"\u19f4",  // KeyL
+    u8"\u19f5",  // Semicolon
+    u8"\u19f6",  // Quote
+    u8"\u19f7",  // KeyZ
+    u8"\u19f8",  // KeyX
+    u8"\u19f9",  // KeyC
+    u8"\u19fa",  // KeyV
+    u8"\u19fb",  // KeyB
+    u8"\u19fc",  // KeyN
+    u8"\u19fd",  // KeyM
+    u8"\u19fe",  // Comma
+    u8"\u19ff",  // Period
+    u8"",        // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftCapslock[] = {
+    u8"\u00ab",        // BackQuote
+    u8"\u17e1",        // Digit1
+    u8"\u17e2",        // Digit2
+    u8"\u17e3",        // Digit3
+    u8"\u17e4",        // Digit4
+    u8"\u17e5",        // Digit5
+    u8"\u17e6",        // Digit6
+    u8"\u17e7",        // Digit7
+    u8"\u17e8",        // Digit8
+    u8"\u17e9",        // Digit9
+    u8"\u17e0",        // Digit0
+    u8"\u17a5",        // Minus
+    u8"\u17b2",        // Equal
+    u8"\u1786",        // KeyQ
+    u8"\u17b9",        // KeyW
+    u8"\u17c1",        // KeyE
+    u8"\u179a",        // KeyR
+    u8"\u178f",        // KeyT
+    u8"\u1799",        // KeyY
+    u8"\u17bb",        // KeyU
+    u8"\u17b7",        // KeyI
+    u8"\u17c4",        // KeyO
+    u8"\u1795",        // KeyP
+    u8"\u17c0",        // BracketLeft
+    u8"\u17aa",        // BracketRight
+    u8"\u17ae",        // Backslash
+    u8"\u17b6",        // KeyA
+    u8"\u179f",        // KeyS
+    u8"\u178a",        // KeyD
+    u8"\u1790",        // KeyF
+    u8"\u1784",        // KeyG
+    u8"\u17a0",        // KeyH
+    u8"\u17d2",        // KeyJ
+    u8"\u1780",        // KeyK
+    u8"\u179b",        // KeyL
+    u8"\u17be",        // Semicolon
+    u8"\u17cb",        // Quote
+    u8"\u178b",        // KeyZ
+    u8"\u1781",        // KeyX
+    u8"\u1785",        // KeyC
+    u8"\u179c",        // KeyV
+    u8"\u1794",        // KeyB
+    u8"\u1793",        // KeyN
+    u8"\u1798",        // KeyM
+    u8"\u17bb\u17c6",  // Comma
+    u8"\u17d4",        // Period
+    u8"\u17ca",        // Slash
+    u8"\u200b",        // Space
+};
+const char* kShiftAltGrCapslock[] = {
+    u8"\u200d",  // BackQuote
+    u8"\u200c",  // Digit1
+    u8"@",       // Digit2
+    u8"\u17d1",  // Digit3
+    u8"$",       // Digit4
+    u8"\u20ac",  // Digit5
+    u8"\u17d9",  // Digit6
+    u8"\u17da",  // Digit7
+    u8"*",       // Digit8
+    u8"{",       // Digit9
+    u8"}",       // Digit0
+    u8"\u00d7",  // Minus
+    u8"\u17ce",  // Equal
+    u8"\u17dc",  // KeyQ
+    u8"\u17dd",  // KeyW
+    u8"\u17af",  // KeyE
+    u8"\u17ab",  // KeyR
+    u8"\u17a8",  // KeyT
+    u8"",        // KeyY
+    u8"",        // KeyU
+    u8"\u17a6",  // KeyI
+    u8"\u17b1",  // KeyO
+    u8"\u17b0",  // KeyP
+    u8"\u17a9",  // BracketLeft
+    u8"\u17b3",  // BracketRight
+    u8"\\",      // Backslash
+    u8"+",       // KeyA
+    u8"-",       // KeyS
+    u8"",        // KeyD
+    u8"",        // KeyF
+    u8"",        // KeyG
+    u8"",        // KeyH
+    u8"",        // KeyJ
+    u8"\u179d",  // KeyK
+    u8"",        // KeyL
+    u8"\u17d6",  // Semicolon
+    u8"\u17c8",  // Quote
+    u8"",        // KeyZ
+    u8"",        // KeyX
+    u8"",        // KeyC
+    u8"",        // KeyV
+    u8"\u179e",  // KeyB
+    u8"",        // KeyN
+    u8"",        // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char** kKeyMap[8] = {
+    kNormal,   kShift,         kAltGr,         kShiftAltGr,
+    kCapslock, kShiftCapslock, kAltgrCapslock, kShiftAltGrCapslock};
+
+}  // namespace km
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/km.h b/chromeos/services/ime/public/cpp/rulebased/def/km.h
index 5bf6f6a..98872de 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/km.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/km.h
@@ -5,56 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_KM_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_KM_H_
 
-const wchar_t* key_map_km[] = {
-    // Row #1
-    L"\u00ab\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9\u17e0\u17a5"
-    L"\u17b2"
-    // Row #2
-    L"\u1786\u17b9\u17c1\u179a\u178f\u1799\u17bb\u17b7\u17c4\u1795\u17c0\u17aa"
-    L"\u17ae"
-    // Row #3
-    L"\u17b6\u179f\u178a\u1790\u1784\u17a0\u17d2\u1780\u179b\u17be\u17cb"
-    // Row #4
-    L"\u178b\u1781\u1785\u179c\u1794\u1793\u1798{{\u17bb\u17c6}}\u17d4\u17ca"
-    // Row #5
-    L"\u200b",
-    // Row #1
-    L"\u00bb!\u17d7\"\u17db%\u17cd\u17d0\u17cf()\u17cc="
-    // Row #2
-    L"\u1788\u17ba\u17c2\u17ac\u1791\u17bd\u17bc\u17b8\u17c5\u1797\u17bf\u17a7"
-    L"\u17ad"
-    // Row #3
-    L"{{\u17b6\u17c6}}\u17c3\u178c\u1792\u17a2\u17c7\u1789\u1782\u17a1{{\u17c4"
-    L"\u17c7}}\u17c9"
-    // Row #4
-    L"\u178d\u1783\u1787{{\u17c1\u17c7}}\u1796\u178e\u17c6{{\u17bb\u17c7}}"
-    L"\u17d5?"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u200d\u200c@\u17d1$\u20ac\u17d9\u17da*{}\u00d7\u17ce"
-    // Row #2
-    L"\u17dc\u17dd\u17af\u17ab\u17a8{{}}{{}}\u17a6\u17b1\u17b0\u17a9\u17b3\\"
-    // Row #3
-    L"+-{{}}{{}}{{}}{{}}{{}}\u179d{{}}\u17d6\u17c8"
-    // Row #4
-    L"{{}}{{}}{{}}{{}}\u179e{{}}{{}},./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"{{}}\u17f1\u17f2\u17f3\u17f4\u17f5\u17f6\u17f7\u17f8\u17f9\u17f0{{}}{{}}"
-    // Row #2
-    L"\u19e0\u19e1\u19e2\u19e3\u19e4\u19e5\u19e6\u19e7\u19e8\u19e9\u19ea\u19eb{"
-    L"{}}"
-    // Row #3
-    L"\u19ec\u19ed\u19ee\u19ef\u19f0\u19f1\u19f2\u19f3\u19f4\u19f5\u19f6"
-    // Row #4
-    L"\u19f7\u19f8\u19f9\u19fa\u19fb\u19fc\u19fd\u19fe\u19ff{{}}"
-    // Row #5
-    L"\u0020"};
+namespace km {
 
-const uint8_t key_map_index_km[8]{0, 1, 2, 3, 1, 0, 3, 2};
-const char* id_km = "km";
-const bool is_102_km = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace km
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_KM_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/lo.cc b/chromeos/services/ime/public/cpp/rulebased/def/lo.cc
new file mode 100644
index 0000000..c1f5a47e
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/lo.cc
@@ -0,0 +1,315 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/lo.h"
+
+namespace lo {
+
+const char* kId = "lo";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"*",       // BackQuote
+    u8"\u0ea2",  // Digit1
+    u8"\u0e9f",  // Digit2
+    u8"\u0ec2",  // Digit3
+    u8"\u0e96",  // Digit4
+    u8"\u0eb8",  // Digit5
+    u8"\u0eb9",  // Digit6
+    u8"\u0e84",  // Digit7
+    u8"\u0e95",  // Digit8
+    u8"\u0e88",  // Digit9
+    u8"\u0e82",  // Digit0
+    u8"\u0e8a",  // Minus
+    u8"\u0ecd",  // Equal
+    u8"\u0ebb",  // KeyQ
+    u8"\u0ec4",  // KeyW
+    u8"\u0eb3",  // KeyE
+    u8"\u0e9e",  // KeyR
+    u8"\u0eb0",  // KeyT
+    u8"\u0eb4",  // KeyY
+    u8"\u0eb5",  // KeyU
+    u8"\u0eae",  // KeyI
+    u8"\u0e99",  // KeyO
+    u8"\u0e8d",  // KeyP
+    u8"\u0e9a",  // BracketLeft
+    u8"\u0ea5",  // BracketRight
+    u8"\u201c",  // Backslash
+    u8"\u0eb1",  // KeyA
+    u8"\u0eab",  // KeyS
+    u8"\u0e81",  // KeyD
+    u8"\u0e94",  // KeyF
+    u8"\u0ec0",  // KeyG
+    u8"\u0ec9",  // KeyH
+    u8"\u0ec8",  // KeyJ
+    u8"\u0eb2",  // KeyK
+    u8"\u0eaa",  // KeyL
+    u8"\u0ea7",  // Semicolon
+    u8"\u0e87",  // Quote
+    u8"\u0e9c",  // KeyZ
+    u8"\u0e9b",  // KeyX
+    u8"\u0ec1",  // KeyC
+    u8"\u0ead",  // KeyV
+    u8"\u0eb6",  // KeyB
+    u8"\u0eb7",  // KeyN
+    u8"\u0e97",  // KeyM
+    u8"\u0ea1",  // Comma
+    u8"\u0ec3",  // Period
+    u8"\u0e9d",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"/",             // BackQuote
+    u8"1",             // Digit1
+    u8"2",             // Digit2
+    u8"3",             // Digit3
+    u8"4",             // Digit4
+    u8"\u0ecc",        // Digit5
+    u8"\u0ebc",        // Digit6
+    u8"5",             // Digit7
+    u8"6",             // Digit8
+    u8"7",             // Digit9
+    u8"8",             // Digit0
+    u8"9",             // Minus
+    u8"\u0ecd\u0ec8",  // Equal
+    u8"\u0ebb\u0ec9",  // KeyQ
+    u8"0",             // KeyW
+    u8"\u0eb3\u0ec9",  // KeyE
+    u8"_",             // KeyR
+    u8"+",             // KeyT
+    u8"\u0eb4\u0ec9",  // KeyY
+    u8"\u0eb5\u0ec9",  // KeyU
+    u8"\u0ea3",        // KeyI
+    u8"\u0edc",        // KeyO
+    u8"\u0ebd",        // KeyP
+    u8"-",             // BracketLeft
+    u8"\u0eab\u0ebc",  // BracketRight
+    u8"\u201d",        // Backslash
+    u8"\u0eb1\u0ec9",  // KeyA
+    u8";",             // KeyS
+    u8".",             // KeyD
+    u8",",             // KeyF
+    u8":",             // KeyG
+    u8"\u0eca",        // KeyH
+    u8"\u0ecb",        // KeyJ
+    u8"!",             // KeyK
+    u8"?",             // KeyL
+    u8"%",             // Semicolon
+    u8"=",             // Quote
+    u8"\u20ad",        // KeyZ
+    u8"(",             // KeyX
+    u8"\u0eaf",        // KeyC
+    u8"x",             // KeyV
+    u8"\u0eb6\u0ec9",  // KeyB
+    u8"\u0eb7\u0ec9",  // KeyN
+    u8"\u0ec6",        // KeyM
+    u8"\u0edd",        // Comma
+    u8"$",             // Period
+    u8")",             // Slash
+    u8"\u0020",        // Space
+};
+const char* kAltGr[] = {
+    u8"",        // BackQuote
+    u8"\u0ed1",  // Digit1
+    u8"\u0ed2",  // Digit2
+    u8"\u0ed3",  // Digit3
+    u8"\u0ed4",  // Digit4
+    u8"\u0ed5",  // Digit5
+    u8"\u0ed6",  // Digit6
+    u8"\u0ed7",  // Digit7
+    u8"\u0ed8",  // Digit8
+    u8"\u0ed9",  // Digit9
+    u8"\u0ed0",  // Digit0
+    u8"",        // Minus
+    u8"",        // Equal
+    u8"",        // KeyQ
+    u8"",        // KeyW
+    u8"",        // KeyE
+    u8"",        // KeyR
+    u8"",        // KeyT
+    u8"",        // KeyY
+    u8"",        // KeyU
+    u8"",        // KeyI
+    u8"",        // KeyO
+    u8"",        // KeyP
+    u8"",        // BracketLeft
+    u8"",        // BracketRight
+    u8"",        // Backslash
+    u8"",        // KeyA
+    u8"",        // KeyS
+    u8"",        // KeyD
+    u8"",        // KeyF
+    u8"",        // KeyG
+    u8"",        // KeyH
+    u8"",        // KeyJ
+    u8"",        // KeyK
+    u8"",        // KeyL
+    u8"",        // Semicolon
+    u8"",        // Quote
+    u8"",        // KeyZ
+    u8"",        // KeyX
+    u8"",        // KeyC
+    u8"",        // KeyV
+    u8"",        // KeyB
+    u8"",        // KeyN
+    u8"",        // KeyM
+    u8"",        // Comma
+    u8"",        // Period
+    u8"",        // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"*",       // BackQuote
+    u8"\u0ea2",  // Digit1
+    u8"\u0e9f",  // Digit2
+    u8"\u0ec2",  // Digit3
+    u8"\u0e96",  // Digit4
+    u8"\u0eb8",  // Digit5
+    u8"\u0eb9",  // Digit6
+    u8"\u0e84",  // Digit7
+    u8"\u0e95",  // Digit8
+    u8"\u0e88",  // Digit9
+    u8"\u0e82",  // Digit0
+    u8"\u0e8a",  // Minus
+    u8"\u0ecd",  // Equal
+    u8"\u0ebb",  // KeyQ
+    u8"\u0ec4",  // KeyW
+    u8"\u0eb3",  // KeyE
+    u8"\u0e9e",  // KeyR
+    u8"\u0eb0",  // KeyT
+    u8"\u0eb4",  // KeyY
+    u8"\u0eb5",  // KeyU
+    u8"\u0eae",  // KeyI
+    u8"\u0e99",  // KeyO
+    u8"\u0e8d",  // KeyP
+    u8"\u0e9a",  // BracketLeft
+    u8"\u0ea5",  // BracketRight
+    u8"\u201c",  // Backslash
+    u8"\u0eb1",  // KeyA
+    u8"\u0eab",  // KeyS
+    u8"\u0e81",  // KeyD
+    u8"\u0e94",  // KeyF
+    u8"\u0ec0",  // KeyG
+    u8"\u0ec9",  // KeyH
+    u8"\u0ec8",  // KeyJ
+    u8"\u0eb2",  // KeyK
+    u8"\u0eaa",  // KeyL
+    u8"\u0ea7",  // Semicolon
+    u8"\u0e87",  // Quote
+    u8"\u0e9c",  // KeyZ
+    u8"\u0e9b",  // KeyX
+    u8"\u0ec1",  // KeyC
+    u8"\u0ead",  // KeyV
+    u8"\u0eb6",  // KeyB
+    u8"\u0eb7",  // KeyN
+    u8"\u0e97",  // KeyM
+    u8"\u0ea1",  // Comma
+    u8"\u0ec3",  // Period
+    u8"\u0e9d",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltgrCapslock[] = {
+    u8"",        // BackQuote
+    u8"\u0ed1",  // Digit1
+    u8"\u0ed2",  // Digit2
+    u8"\u0ed3",  // Digit3
+    u8"\u0ed4",  // Digit4
+    u8"\u0ed5",  // Digit5
+    u8"\u0ed6",  // Digit6
+    u8"\u0ed7",  // Digit7
+    u8"\u0ed8",  // Digit8
+    u8"\u0ed9",  // Digit9
+    u8"\u0ed0",  // Digit0
+    u8"",        // Minus
+    u8"",        // Equal
+    u8"",        // KeyQ
+    u8"",        // KeyW
+    u8"",        // KeyE
+    u8"",        // KeyR
+    u8"",        // KeyT
+    u8"",        // KeyY
+    u8"",        // KeyU
+    u8"",        // KeyI
+    u8"",        // KeyO
+    u8"",        // KeyP
+    u8"",        // BracketLeft
+    u8"",        // BracketRight
+    u8"",        // Backslash
+    u8"",        // KeyA
+    u8"",        // KeyS
+    u8"",        // KeyD
+    u8"",        // KeyF
+    u8"",        // KeyG
+    u8"",        // KeyH
+    u8"",        // KeyJ
+    u8"",        // KeyK
+    u8"",        // KeyL
+    u8"",        // Semicolon
+    u8"",        // Quote
+    u8"",        // KeyZ
+    u8"",        // KeyX
+    u8"",        // KeyC
+    u8"",        // KeyV
+    u8"",        // KeyB
+    u8"",        // KeyN
+    u8"",        // KeyM
+    u8"",        // Comma
+    u8"",        // Period
+    u8"",        // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftCapslock[] = {
+    u8"/",             // BackQuote
+    u8"1",             // Digit1
+    u8"2",             // Digit2
+    u8"3",             // Digit3
+    u8"4",             // Digit4
+    u8"\u0ecc",        // Digit5
+    u8"\u0ebc",        // Digit6
+    u8"5",             // Digit7
+    u8"6",             // Digit8
+    u8"7",             // Digit9
+    u8"8",             // Digit0
+    u8"9",             // Minus
+    u8"\u0ecd\u0ec8",  // Equal
+    u8"\u0ebb\u0ec9",  // KeyQ
+    u8"0",             // KeyW
+    u8"\u0eb3\u0ec9",  // KeyE
+    u8"_",             // KeyR
+    u8"+",             // KeyT
+    u8"\u0eb4\u0ec9",  // KeyY
+    u8"\u0eb5\u0ec9",  // KeyU
+    u8"\u0ea3",        // KeyI
+    u8"\u0edc",        // KeyO
+    u8"\u0ebd",        // KeyP
+    u8"-",             // BracketLeft
+    u8"\u0eab\u0ebc",  // BracketRight
+    u8"\u201d",        // Backslash
+    u8"\u0eb1\u0ec9",  // KeyA
+    u8";",             // KeyS
+    u8".",             // KeyD
+    u8",",             // KeyF
+    u8":",             // KeyG
+    u8"\u0eca",        // KeyH
+    u8"\u0ecb",        // KeyJ
+    u8"!",             // KeyK
+    u8"?",             // KeyL
+    u8"%",             // Semicolon
+    u8"=",             // Quote
+    u8"\u20ad",        // KeyZ
+    u8"(",             // KeyX
+    u8"\u0eaf",        // KeyC
+    u8"x",             // KeyV
+    u8"\u0eb6\u0ec9",  // KeyB
+    u8"\u0eb7\u0ec9",  // KeyN
+    u8"\u0ec6",        // KeyM
+    u8"\u0edd",        // Comma
+    u8"$",             // Period
+    u8")",             // Slash
+    u8"\u0020",        // Space
+};
+const char** kKeyMap[8] = {kNormal,        kShift,        kAltGr,
+                           kShift,         kCapslock,     kShiftCapslock,
+                           kAltgrCapslock, kShiftCapslock};
+
+}  // namespace lo
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/lo.h b/chromeos/services/ime/public/cpp/rulebased/def/lo.h
index b2a6a43..65b84c8 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/lo.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/lo.h
@@ -5,42 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_LO_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_LO_H_
 
-const wchar_t* key_map_lo[] = {
-    // Row #1
-    L"*\u0ea2\u0e9f\u0ec2\u0e96\u0eb8\u0eb9\u0e84\u0e95\u0e88\u0e82\u0e8a\u0ecd"
-    // Row #2
-    L"\u0ebb\u0ec4\u0eb3\u0e9e\u0eb0\u0eb4\u0eb5\u0eae\u0e99\u0e8d\u0e9a\u0ea5"
-    L"\u201c"
-    // Row #3
-    L"\u0eb1\u0eab\u0e81\u0e94\u0ec0\u0ec9\u0ec8\u0eb2\u0eaa\u0ea7\u0e87"
-    // Row #4
-    L"\u0e9c\u0e9b\u0ec1\u0ead\u0eb6\u0eb7\u0e97\u0ea1\u0ec3\u0e9d"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"/1234\u0ecc\u0ebc56789{{\u0ecd\u0ec8}}"
-    // Row #2
-    L"{{\u0ebb\u0ec9}}0{{\u0eb3\u0ec9}}_+{{\u0eb4\u0ec9}}{{\u0eb5\u0ec9}}\u0ea3"
-    L"\u0edc\u0ebd-{{\u0eab\u0ebc}}\u201d"
-    // Row #3
-    L"{{\u0eb1\u0ec9}};.,:\u0eca\u0ecb!?%="
-    // Row #4
-    L"\u20ad(\u0eafx{{\u0eb6\u0ec9}}{{\u0eb7\u0ec9}}\u0ec6\u0edd$)"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"{{}}\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9\u0ed0{{}}{{}}"
-    // Row #2
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}"
-    // Row #3
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}"
-    // Row #4
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}"
-    // Row #5
-    L"\u0020"};
+namespace lo {
 
-const uint8_t key_map_index_lo[8]{0, 1, 2, 1, 0, 1, 2, 1};
-const char* id_lo = "lo";
-const bool is_102_lo = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace lo
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_LO_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ne_inscript.cc b/chromeos/services/ime/public/cpp/rulebased/def/ne_inscript.cc
new file mode 100644
index 0000000..96fcdb9
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ne_inscript.cc
@@ -0,0 +1,215 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/ne_inscript.h"
+
+namespace ne_inscript {
+
+const char* kId = "ne_inscript";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u091e",              // BackQuote
+    u8"\u0967",              // Digit1
+    u8"\u0968",              // Digit2
+    u8"\u0969",              // Digit3
+    u8"\u096a",              // Digit4
+    u8"\u096b",              // Digit5
+    u8"\u096c",              // Digit6
+    u8"\u096d",              // Digit7
+    u8"\u096e",              // Digit8
+    u8"\u096f",              // Digit9
+    u8"\u0966",              // Digit0
+    u8"\u0914",              // Minus
+    u8"\u200d",              // Equal
+    u8"\u0924\u094d\u0930",  // KeyQ
+    u8"\u0927",              // KeyW
+    u8"\u092d",              // KeyE
+    u8"\u091a",              // KeyR
+    u8"\u0924",              // KeyT
+    u8"\u0925",              // KeyY
+    u8"\u0917",              // KeyU
+    u8"\u0937",              // KeyI
+    u8"\u092f",              // KeyO
+    u8"\u0909",              // KeyP
+    u8"\u0930\u094d",        // BracketLeft
+    u8"\u0947",              // BracketRight
+    u8"\u094d",              // Backslash
+    u8"\u092c",              // KeyA
+    u8"\u0915",              // KeyS
+    u8"\u092e",              // KeyD
+    u8"\u093e",              // KeyF
+    u8"\u0928",              // KeyG
+    u8"\u091c",              // KeyH
+    u8"\u0935",              // KeyJ
+    u8"\u092a",              // KeyK
+    u8"\u093f",              // KeyL
+    u8"\u0938",              // Semicolon
+    u8"\u0941",              // Quote
+    u8"\u0936",              // KeyZ
+    u8"\u0939",              // KeyX
+    u8"\u0905",              // KeyC
+    u8"\u0916",              // KeyV
+    u8"\u0926",              // KeyB
+    u8"\u0932",              // KeyN
+    u8"\u0903",              // KeyM
+    u8"\u093d",              // Comma
+    u8"\u0964",              // Period
+    u8"\u0930",              // Slash
+    u8"\u0020",              // Space
+};
+const char* kShift[] = {
+    u8"\u0965",              // BackQuote
+    u8"\u091c\u094d\u091e",  // Digit1
+    u8"\u0908",              // Digit2
+    u8"\u0918",              // Digit3
+    u8"$",                   // Digit4
+    u8"\u091b",              // Digit5
+    u8"\u091f",              // Digit6
+    u8"\u0920",              // Digit7
+    u8"\u0921",              // Digit8
+    u8"\u0922",              // Digit9
+    u8"\u0923",              // Digit0
+    u8"\u0913",              // Minus
+    u8"\u200c",              // Equal
+    u8"\u0924\u094d\u0924",  // KeyQ
+    u8"\u0921\u094d\u0922",  // KeyW
+    u8"\u0910",              // KeyE
+    u8"\u0926\u094d\u0935",  // KeyR
+    u8"\u091f\u094d\u091f",  // KeyT
+    u8"\u0920\u094d\u0920",  // KeyY
+    u8"\u090a",              // KeyU
+    u8"\u0915\u094d\u0937",  // KeyI
+    u8"\u0907",              // KeyO
+    u8"\u090f",              // KeyP
+    u8"\u0943",              // BracketLeft
+    u8"\u0948",              // BracketRight
+    u8"\u0902",              // Backslash
+    u8"\u0906",              // KeyA
+    u8"\u0919\u094d\u0915",  // KeyS
+    u8"\u0919\u094d\u0917",  // KeyD
+    u8"\u0901",              // KeyF
+    u8"\u0926\u094d\u0926",  // KeyG
+    u8"\u091d",              // KeyH
+    u8"\u094b",              // KeyJ
+    u8"\u092b",              // KeyK
+    u8"\u0940",              // KeyL
+    u8"\u091f\u094d\u0920",  // Semicolon
+    u8"\u0942",              // Quote
+    u8"\u0915\u094d\u0915",  // KeyZ
+    u8"\u0939\u094d\u092e",  // KeyX
+    u8"\u090b",              // KeyC
+    u8"\u0950",              // KeyV
+    u8"\u094c",              // KeyB
+    u8"\u0926\u094d\u092f",  // KeyN
+    u8"\u0921\u094d\u0921",  // KeyM
+    u8"\u0919",              // Comma
+    u8"\u0936\u094d\u0930",  // Period
+    u8"\u0930\u0941",        // Slash
+    u8"\u0020",              // Space
+};
+const char* kCapslock[] = {
+    u8"\u091e",              // BackQuote
+    u8"\u0967",              // Digit1
+    u8"\u0968",              // Digit2
+    u8"\u0969",              // Digit3
+    u8"\u096a",              // Digit4
+    u8"\u096b",              // Digit5
+    u8"\u096c",              // Digit6
+    u8"\u096d",              // Digit7
+    u8"\u096e",              // Digit8
+    u8"\u096f",              // Digit9
+    u8"\u0966",              // Digit0
+    u8"\u0914",              // Minus
+    u8"\u200d",              // Equal
+    u8"\u0924\u094d\u0930",  // KeyQ
+    u8"\u0927",              // KeyW
+    u8"\u092d",              // KeyE
+    u8"\u091a",              // KeyR
+    u8"\u0924",              // KeyT
+    u8"\u0925",              // KeyY
+    u8"\u0917",              // KeyU
+    u8"\u0937",              // KeyI
+    u8"\u092f",              // KeyO
+    u8"\u0909",              // KeyP
+    u8"\u0930\u094d",        // BracketLeft
+    u8"\u0947",              // BracketRight
+    u8"\u094d",              // Backslash
+    u8"\u092c",              // KeyA
+    u8"\u0915",              // KeyS
+    u8"\u092e",              // KeyD
+    u8"\u093e",              // KeyF
+    u8"\u0928",              // KeyG
+    u8"\u091c",              // KeyH
+    u8"\u0935",              // KeyJ
+    u8"\u092a",              // KeyK
+    u8"\u093f",              // KeyL
+    u8"\u0938",              // Semicolon
+    u8"\u0941",              // Quote
+    u8"\u0936",              // KeyZ
+    u8"\u0939",              // KeyX
+    u8"\u0905",              // KeyC
+    u8"\u0916",              // KeyV
+    u8"\u0926",              // KeyB
+    u8"\u0932",              // KeyN
+    u8"\u0903",              // KeyM
+    u8"\u093d",              // Comma
+    u8"\u0964",              // Period
+    u8"\u0930",              // Slash
+    u8"\u0020",              // Space
+};
+const char* kShiftCapslock[] = {
+    u8"\u0965",              // BackQuote
+    u8"\u091c\u094d\u091e",  // Digit1
+    u8"\u0908",              // Digit2
+    u8"\u0918",              // Digit3
+    u8"$",                   // Digit4
+    u8"\u091b",              // Digit5
+    u8"\u091f",              // Digit6
+    u8"\u0920",              // Digit7
+    u8"\u0921",              // Digit8
+    u8"\u0922",              // Digit9
+    u8"\u0923",              // Digit0
+    u8"\u0913",              // Minus
+    u8"\u200c",              // Equal
+    u8"\u0924\u094d\u0924",  // KeyQ
+    u8"\u0921\u094d\u0922",  // KeyW
+    u8"\u0910",              // KeyE
+    u8"\u0926\u094d\u0935",  // KeyR
+    u8"\u091f\u094d\u091f",  // KeyT
+    u8"\u0920\u094d\u0920",  // KeyY
+    u8"\u090a",              // KeyU
+    u8"\u0915\u094d\u0937",  // KeyI
+    u8"\u0907",              // KeyO
+    u8"\u090f",              // KeyP
+    u8"\u0943",              // BracketLeft
+    u8"\u0948",              // BracketRight
+    u8"\u0902",              // Backslash
+    u8"\u0906",              // KeyA
+    u8"\u0919\u094d\u0915",  // KeyS
+    u8"\u0919\u094d\u0917",  // KeyD
+    u8"\u0901",              // KeyF
+    u8"\u0926\u094d\u0926",  // KeyG
+    u8"\u091d",              // KeyH
+    u8"\u094b",              // KeyJ
+    u8"\u092b",              // KeyK
+    u8"\u0940",              // KeyL
+    u8"\u091f\u094d\u0920",  // Semicolon
+    u8"\u0942",              // Quote
+    u8"\u0915\u094d\u0915",  // KeyZ
+    u8"\u0939\u094d\u092e",  // KeyX
+    u8"\u090b",              // KeyC
+    u8"\u0950",              // KeyV
+    u8"\u094c",              // KeyB
+    u8"\u0926\u094d\u092f",  // KeyN
+    u8"\u0921\u094d\u0921",  // KeyM
+    u8"\u0919",              // Comma
+    u8"\u0936\u094d\u0930",  // Period
+    u8"\u0930\u0941",        // Slash
+    u8"\u0020",              // Space
+};
+const char** kKeyMap[8] = {kNormal,   kShift,        kNormal,
+                           kShift,    kCapslock,     kShiftCapslock,
+                           kCapslock, kShiftCapslock};
+
+}  // namespace ne_inscript
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ne_inscript.h b/chromeos/services/ime/public/cpp/rulebased/def/ne_inscript.h
index 6a9b30a..152d13b 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/ne_inscript.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ne_inscript.h
@@ -5,39 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_NE_INSCRIPT_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_NE_INSCRIPT_H_
 
-const wchar_t* key_map_ne_inscript[] = {
-    // Row #1
-    L"\u091e\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u0966\u0914"
-    L"\u200d"
-    // Row #2
-    L"{{\u0924\u094d\u0930}}\u0927\u092d\u091a\u0924\u0925\u0917\u0937\u092f"
-    L"\u0909{{\u0930\u094d}}\u0947\u094d"
-    // Row #3
-    L"\u092c\u0915\u092e\u093e\u0928\u091c\u0935\u092a\u093f\u0938\u0941"
-    // Row #4
-    L"\u0936\u0939\u0905\u0916\u0926\u0932\u0903\u093d\u0964\u0930"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u0965{{\u091c\u094d\u091e}}\u0908\u0918$\u091b\u091f\u0920\u0921\u0922"
-    L"\u0923\u0913\u200c"
-    // Row #2
-    L"{{\u0924\u094d\u0924}}{{\u0921\u094d\u0922}}\u0910{{\u0926\u094d\u0935}}{"
-    L"{\u091f\u094d\u091f}}{{\u0920\u094d\u0920}}\u090a{{\u0915\u094d\u0937}}"
-    L"\u0907"
-    L"\u090f\u0943\u0948\u0902"
-    // Row #3
-    L"\u0906{{\u0919\u094d\u0915}}{{\u0919\u094d\u0917}}\u0901{{\u0926\u094d"
-    L"\u0926}}\u091d\u094b\u092b\u0940{{\u091f\u094d\u0920}}\u0942"
-    // Row #4
-    L"{{\u0915\u094d\u0915}}{{\u0939\u094d\u092e}}\u090b\u0950\u094c{{\u0926"
-    L"\u094d\u092f}}{{\u0921\u094d\u0921}}\u0919{{\u0936\u094d\u0930}}{{"
-    L"\u0930\u0941}}"
-    // Row #5
-    L"\u0020"};
+namespace ne_inscript {
 
-const uint8_t key_map_index_ne_inscript[8]{0, 1, 0, 1, 0, 1, 0, 1};
-const char* id_ne_inscript = "ne_inscript";
-const bool is_102_ne_inscript = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace ne_inscript
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_NE_INSCRIPT_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_aatseel.cc b/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_aatseel.cc
new file mode 100644
index 0000000..d032cdf
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_aatseel.cc
@@ -0,0 +1,415 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/ru_phone_aatseel.h"
+
+namespace ru_phone_aatseel {
+
+const char* kId = "ru_phone_aatseel";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u0451",  // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"\u044a",  // Equal
+    u8"\u044f",  // KeyQ
+    u8"\u0448",  // KeyW
+    u8"\u0435",  // KeyE
+    u8"\u0440",  // KeyR
+    u8"\u0442",  // KeyT
+    u8"\u044b",  // KeyY
+    u8"\u0443",  // KeyU
+    u8"\u0438",  // KeyI
+    u8"\u043e",  // KeyO
+    u8"\u043f",  // KeyP
+    u8"\u044e",  // BracketLeft
+    u8"\u0449",  // BracketRight
+    u8"\u044d",  // Backslash
+    u8"\u0430",  // KeyA
+    u8"\u0441",  // KeyS
+    u8"\u0434",  // KeyD
+    u8"\u0444",  // KeyF
+    u8"\u0433",  // KeyG
+    u8"\u0447",  // KeyH
+    u8"\u0439",  // KeyJ
+    u8"\u043a",  // KeyK
+    u8"\u043b",  // KeyL
+    u8"\u044c",  // Semicolon
+    u8"\u0436",  // Quote
+    u8"\u0437",  // KeyZ
+    u8"\u0445",  // KeyX
+    u8"\u0446",  // KeyC
+    u8"\u0432",  // KeyV
+    u8"\u0431",  // KeyB
+    u8"\u043d",  // KeyN
+    u8"\u043c",  // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"\u0401",  // BackQuote
+    u8"!",       // Digit1
+    u8"@",       // Digit2
+    u8"#",       // Digit3
+    u8"\"",      // Digit4
+    u8":",       // Digit5
+    u8"^",       // Digit6
+    u8"&",       // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"\u042a",  // Equal
+    u8"\u042f",  // KeyQ
+    u8"\u0428",  // KeyW
+    u8"\u0415",  // KeyE
+    u8"\u0420",  // KeyR
+    u8"\u0422",  // KeyT
+    u8"\u042b",  // KeyY
+    u8"\u0423",  // KeyU
+    u8"\u0418",  // KeyI
+    u8"\u041e",  // KeyO
+    u8"\u041f",  // KeyP
+    u8"\u042e",  // BracketLeft
+    u8"\u0429",  // BracketRight
+    u8"\u042d",  // Backslash
+    u8"\u0410",  // KeyA
+    u8"\u0421",  // KeyS
+    u8"\u0414",  // KeyD
+    u8"\u0424",  // KeyF
+    u8"\u0413",  // KeyG
+    u8"\u0427",  // KeyH
+    u8"\u0419",  // KeyJ
+    u8"\u041a",  // KeyK
+    u8"\u041b",  // KeyL
+    u8"\u042c",  // Semicolon
+    u8"\u0416",  // Quote
+    u8"\u0417",  // KeyZ
+    u8"\u0425",  // KeyX
+    u8"\u0426",  // KeyC
+    u8"\u0412",  // KeyV
+    u8"\u0411",  // KeyB
+    u8"\u041d",  // KeyN
+    u8"\u041c",  // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltGr[] = {
+    u8"`",       // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"=",       // Equal
+    u8"q",       // KeyQ
+    u8"w",       // KeyW
+    u8"e",       // KeyE
+    u8"r",       // KeyR
+    u8"t",       // KeyT
+    u8"y",       // KeyY
+    u8"u",       // KeyU
+    u8"i",       // KeyI
+    u8"o",       // KeyO
+    u8"p",       // KeyP
+    u8"[",       // BracketLeft
+    u8"]",       // BracketRight
+    u8"\\",      // Backslash
+    u8"a",       // KeyA
+    u8"s",       // KeyS
+    u8"d",       // KeyD
+    u8"f",       // KeyF
+    u8"g",       // KeyG
+    u8"h",       // KeyH
+    u8"j",       // KeyJ
+    u8"k",       // KeyK
+    u8"l",       // KeyL
+    u8";",       // Semicolon
+    u8"'",       // Quote
+    u8"z",       // KeyZ
+    u8"x",       // KeyX
+    u8"c",       // KeyC
+    u8"v",       // KeyV
+    u8"b",       // KeyB
+    u8"n",       // KeyN
+    u8"m",       // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"\u0401",  // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"\u042a",  // Equal
+    u8"\u042f",  // KeyQ
+    u8"\u0428",  // KeyW
+    u8"\u0415",  // KeyE
+    u8"\u0420",  // KeyR
+    u8"\u0422",  // KeyT
+    u8"\u042b",  // KeyY
+    u8"\u0423",  // KeyU
+    u8"\u0418",  // KeyI
+    u8"\u041e",  // KeyO
+    u8"\u041f",  // KeyP
+    u8"\u042e",  // BracketLeft
+    u8"\u0429",  // BracketRight
+    u8"\u042d",  // Backslash
+    u8"\u0410",  // KeyA
+    u8"\u0421",  // KeyS
+    u8"\u0414",  // KeyD
+    u8"\u0424",  // KeyF
+    u8"\u0413",  // KeyG
+    u8"\u0427",  // KeyH
+    u8"\u0419",  // KeyJ
+    u8"\u041a",  // KeyK
+    u8"\u041b",  // KeyL
+    u8"\u042c",  // Semicolon
+    u8"\u0416",  // Quote
+    u8"\u0417",  // KeyZ
+    u8"\u0425",  // KeyX
+    u8"\u0426",  // KeyC
+    u8"\u0412",  // KeyV
+    u8"\u0411",  // KeyB
+    u8"\u041d",  // KeyN
+    u8"\u041c",  // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftAltGr[] = {
+    u8"~",       // BackQuote
+    u8"!",       // Digit1
+    u8"@",       // Digit2
+    u8"#",       // Digit3
+    u8"$",       // Digit4
+    u8"%",       // Digit5
+    u8"^",       // Digit6
+    u8"&",       // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"+",       // Equal
+    u8"Q",       // KeyQ
+    u8"W",       // KeyW
+    u8"E",       // KeyE
+    u8"R",       // KeyR
+    u8"T",       // KeyT
+    u8"Y",       // KeyY
+    u8"U",       // KeyU
+    u8"I",       // KeyI
+    u8"O",       // KeyO
+    u8"P",       // KeyP
+    u8"{",       // BracketLeft
+    u8"}",       // BracketRight
+    u8"|",       // Backslash
+    u8"A",       // KeyA
+    u8"S",       // KeyS
+    u8"D",       // KeyD
+    u8"F",       // KeyF
+    u8"G",       // KeyG
+    u8"H",       // KeyH
+    u8"J",       // KeyJ
+    u8"K",       // KeyK
+    u8"L",       // KeyL
+    u8":",       // Semicolon
+    u8"\"",      // Quote
+    u8"Z",       // KeyZ
+    u8"X",       // KeyX
+    u8"C",       // KeyC
+    u8"V",       // KeyV
+    u8"B",       // KeyB
+    u8"N",       // KeyN
+    u8"M",       // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltgrCapslock[] = {
+    u8"`",       // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"=",       // Equal
+    u8"Q",       // KeyQ
+    u8"W",       // KeyW
+    u8"E",       // KeyE
+    u8"R",       // KeyR
+    u8"T",       // KeyT
+    u8"Y",       // KeyY
+    u8"U",       // KeyU
+    u8"I",       // KeyI
+    u8"O",       // KeyO
+    u8"P",       // KeyP
+    u8"[",       // BracketLeft
+    u8"]",       // BracketRight
+    u8"\\",      // Backslash
+    u8"A",       // KeyA
+    u8"S",       // KeyS
+    u8"D",       // KeyD
+    u8"F",       // KeyF
+    u8"G",       // KeyG
+    u8"H",       // KeyH
+    u8"J",       // KeyJ
+    u8"K",       // KeyK
+    u8"L",       // KeyL
+    u8";",       // Semicolon
+    u8"'",       // Quote
+    u8"Z",       // KeyZ
+    u8"X",       // KeyX
+    u8"C",       // KeyC
+    u8"V",       // KeyV
+    u8"B",       // KeyB
+    u8"N",       // KeyN
+    u8"M",       // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftCapslock[] = {
+    u8"\u0451",  // BackQuote
+    u8"!",       // Digit1
+    u8"@",       // Digit2
+    u8"#",       // Digit3
+    u8"\"",      // Digit4
+    u8":",       // Digit5
+    u8"^",       // Digit6
+    u8"&",       // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"\u044a",  // Equal
+    u8"\u044f",  // KeyQ
+    u8"\u0448",  // KeyW
+    u8"\u0435",  // KeyE
+    u8"\u0440",  // KeyR
+    u8"\u0442",  // KeyT
+    u8"\u044b",  // KeyY
+    u8"\u0443",  // KeyU
+    u8"\u0438",  // KeyI
+    u8"\u043e",  // KeyO
+    u8"\u043f",  // KeyP
+    u8"\u044e",  // BracketLeft
+    u8"\u0449",  // BracketRight
+    u8"\u044d",  // Backslash
+    u8"\u0430",  // KeyA
+    u8"\u0441",  // KeyS
+    u8"\u0434",  // KeyD
+    u8"\u0444",  // KeyF
+    u8"\u0433",  // KeyG
+    u8"\u0447",  // KeyH
+    u8"\u0439",  // KeyJ
+    u8"\u043a",  // KeyK
+    u8"\u043b",  // KeyL
+    u8"\u044c",  // Semicolon
+    u8"\u0436",  // Quote
+    u8"\u0437",  // KeyZ
+    u8"\u0445",  // KeyX
+    u8"\u0446",  // KeyC
+    u8"\u0432",  // KeyV
+    u8"\u0431",  // KeyB
+    u8"\u043d",  // KeyN
+    u8"\u043c",  // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftAltGrCapslock[] = {
+    u8"~",       // BackQuote
+    u8"!",       // Digit1
+    u8"@",       // Digit2
+    u8"#",       // Digit3
+    u8"$",       // Digit4
+    u8"%",       // Digit5
+    u8"^",       // Digit6
+    u8"&",       // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"+",       // Equal
+    u8"q",       // KeyQ
+    u8"w",       // KeyW
+    u8"e",       // KeyE
+    u8"r",       // KeyR
+    u8"t",       // KeyT
+    u8"y",       // KeyY
+    u8"u",       // KeyU
+    u8"i",       // KeyI
+    u8"o",       // KeyO
+    u8"p",       // KeyP
+    u8"{",       // BracketLeft
+    u8"}",       // BracketRight
+    u8"|",       // Backslash
+    u8"a",       // KeyA
+    u8"s",       // KeyS
+    u8"d",       // KeyD
+    u8"f",       // KeyF
+    u8"g",       // KeyG
+    u8"h",       // KeyH
+    u8"j",       // KeyJ
+    u8"k",       // KeyK
+    u8"l",       // KeyL
+    u8":",       // Semicolon
+    u8"\"",      // Quote
+    u8"z",       // KeyZ
+    u8"x",       // KeyX
+    u8"c",       // KeyC
+    u8"v",       // KeyV
+    u8"b",       // KeyB
+    u8"n",       // KeyN
+    u8"m",       // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char** kKeyMap[8] = {
+    kNormal,   kShift,         kAltGr,         kShiftAltGr,
+    kCapslock, kShiftCapslock, kAltgrCapslock, kShiftAltGrCapslock};
+
+}  // namespace ru_phone_aatseel
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_aatseel.h b/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_aatseel.h
index 52e5dfd..0483536e 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_aatseel.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_aatseel.h
@@ -5,94 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_RU_PHONE_AATSEEL_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_RU_PHONE_AATSEEL_H_
 
-const wchar_t* key_map_ru_phone_aatseel[] = {
-    // Row #1
-    L"\u04511234567890-\u044a"
-    // Row #2
-    L"\u044f\u0448\u0435\u0440\u0442\u044b\u0443\u0438\u043e\u043f\u044e\u0449"
-    L"\u044d"
-    // Row #3
-    L"\u0430\u0441\u0434\u0444\u0433\u0447\u0439\u043a\u043b\u044c\u0436"
-    // Row #4
-    L"\u0437\u0445\u0446\u0432\u0431\u043d\u043c,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u0401!@#\":^&*()_\u042a"
-    // Row #2
-    L"\u042f\u0428\u0415\u0420\u0422\u042b\u0423\u0418\u041e\u041f\u042e\u0429"
-    L"\u042d"
-    // Row #3
-    L"\u0410\u0421\u0414\u0424\u0413\u0427\u0419\u041a\u041b\u042c\u0416"
-    // Row #4
-    L"\u0417\u0425\u0426\u0412\u0411\u041d\u041c<>?"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"`1234567890-="
-    // Row #2
-    L"qwertyuiop[]\\"
-    // Row #3
-    L"asdfghjkl;'"
-    // Row #4
-    L"zxcvbnm,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u04011234567890-\u042a"
-    // Row #2
-    L"\u042f\u0428\u0415\u0420\u0422\u042b\u0423\u0418\u041e\u041f\u042e\u0429"
-    L"\u042d"
-    // Row #3
-    L"\u0410\u0421\u0414\u0424\u0413\u0427\u0419\u041a\u041b\u042c\u0416"
-    // Row #4
-    L"\u0417\u0425\u0426\u0412\u0411\u041d\u041c,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"~!@#$%^&*()_+"
-    // Row #2
-    L"QWERTYUIOP{}|"
-    // Row #3
-    L"ASDFGHJKL:\""
-    // Row #4
-    L"ZXCVBNM<>?"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"`1234567890-="
-    // Row #2
-    L"QWERTYUIOP[]\\"
-    // Row #3
-    L"ASDFGHJKL;'"
-    // Row #4
-    L"ZXCVBNM,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u0451!@#\":^&*()_\u044a"
-    // Row #2
-    L"\u044f\u0448\u0435\u0440\u0442\u044b\u0443\u0438\u043e\u043f\u044e\u0449"
-    L"\u044d"
-    // Row #3
-    L"\u0430\u0441\u0434\u0444\u0433\u0447\u0439\u043a\u043b\u044c\u0436"
-    // Row #4
-    L"\u0437\u0445\u0446\u0432\u0431\u043d\u043c<>?"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"~!@#$%^&*()_+"
-    // Row #2
-    L"qwertyuiop{}|"
-    // Row #3
-    L"asdfghjkl:\""
-    // Row #4
-    L"zxcvbnm<>?"
-    // Row #5
-    L"\u0020"};
+namespace ru_phone_aatseel {
 
-const uint8_t key_map_index_ru_phone_aatseel[8]{0, 1, 2, 4, 3, 6, 5, 7};
-const char* id_ru_phone_aatseel = "ru_phone_aatseel";
-const bool is_102_ru_phone_aatseel = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace ru_phone_aatseel
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_RU_PHONE_AATSEEL_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_yazhert.cc b/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_yazhert.cc
new file mode 100644
index 0000000..fc05f3ad
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_yazhert.cc
@@ -0,0 +1,415 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/ru_phone_yazhert.h"
+
+namespace ru_phone_yazhert {
+
+const char* kId = "ru_phone_yazhert";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u044e",  // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"\u044c",  // Equal
+    u8"\u044f",  // KeyQ
+    u8"\u0436",  // KeyW
+    u8"\u0435",  // KeyE
+    u8"\u0440",  // KeyR
+    u8"\u0442",  // KeyT
+    u8"\u044b",  // KeyY
+    u8"\u0443",  // KeyU
+    u8"\u0438",  // KeyI
+    u8"\u043e",  // KeyO
+    u8"\u043f",  // KeyP
+    u8"\u0448",  // BracketLeft
+    u8"\u0449",  // BracketRight
+    u8"\u044d",  // Backslash
+    u8"\u0430",  // KeyA
+    u8"\u0441",  // KeyS
+    u8"\u0434",  // KeyD
+    u8"\u0444",  // KeyF
+    u8"\u0433",  // KeyG
+    u8"\u0447",  // KeyH
+    u8"\u0439",  // KeyJ
+    u8"\u043a",  // KeyK
+    u8"\u043b",  // KeyL
+    u8";",       // Semicolon
+    u8"'",       // Quote
+    u8"\u0437",  // KeyZ
+    u8"\u0445",  // KeyX
+    u8"\u0446",  // KeyC
+    u8"\u0432",  // KeyV
+    u8"\u0431",  // KeyB
+    u8"\u043d",  // KeyN
+    u8"\u043c",  // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"\u042e",  // BackQuote
+    u8"!",       // Digit1
+    u8"\u044a",  // Digit2
+    u8"\u042a",  // Digit3
+    u8"$",       // Digit4
+    u8"%",       // Digit5
+    u8"\u0451",  // Digit6
+    u8"\u0401",  // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"\u042c",  // Equal
+    u8"\u042f",  // KeyQ
+    u8"\u0416",  // KeyW
+    u8"\u0415",  // KeyE
+    u8"\u0420",  // KeyR
+    u8"\u0422",  // KeyT
+    u8"\u042b",  // KeyY
+    u8"\u0423",  // KeyU
+    u8"\u0418",  // KeyI
+    u8"\u041e",  // KeyO
+    u8"\u041f",  // KeyP
+    u8"\u0428",  // BracketLeft
+    u8"\u0429",  // BracketRight
+    u8"\u042d",  // Backslash
+    u8"\u0410",  // KeyA
+    u8"\u0421",  // KeyS
+    u8"\u0414",  // KeyD
+    u8"\u0424",  // KeyF
+    u8"\u0413",  // KeyG
+    u8"\u0427",  // KeyH
+    u8"\u0419",  // KeyJ
+    u8"\u041a",  // KeyK
+    u8"\u041b",  // KeyL
+    u8":",       // Semicolon
+    u8"\"",      // Quote
+    u8"\u0417",  // KeyZ
+    u8"\u0425",  // KeyX
+    u8"\u0426",  // KeyC
+    u8"\u0412",  // KeyV
+    u8"\u0411",  // KeyB
+    u8"\u041d",  // KeyN
+    u8"\u041c",  // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltGr[] = {
+    u8"`",       // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"=",       // Equal
+    u8"q",       // KeyQ
+    u8"w",       // KeyW
+    u8"e",       // KeyE
+    u8"r",       // KeyR
+    u8"t",       // KeyT
+    u8"y",       // KeyY
+    u8"u",       // KeyU
+    u8"i",       // KeyI
+    u8"o",       // KeyO
+    u8"p",       // KeyP
+    u8"[",       // BracketLeft
+    u8"]",       // BracketRight
+    u8"\\",      // Backslash
+    u8"a",       // KeyA
+    u8"s",       // KeyS
+    u8"d",       // KeyD
+    u8"f",       // KeyF
+    u8"g",       // KeyG
+    u8"h",       // KeyH
+    u8"j",       // KeyJ
+    u8"k",       // KeyK
+    u8"l",       // KeyL
+    u8";",       // Semicolon
+    u8"'",       // Quote
+    u8"z",       // KeyZ
+    u8"x",       // KeyX
+    u8"c",       // KeyC
+    u8"v",       // KeyV
+    u8"b",       // KeyB
+    u8"n",       // KeyN
+    u8"m",       // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"\u042e",  // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"\u042c",  // Equal
+    u8"\u042f",  // KeyQ
+    u8"\u0416",  // KeyW
+    u8"\u0415",  // KeyE
+    u8"\u0420",  // KeyR
+    u8"\u0422",  // KeyT
+    u8"\u042b",  // KeyY
+    u8"\u0423",  // KeyU
+    u8"\u0418",  // KeyI
+    u8"\u041e",  // KeyO
+    u8"\u041f",  // KeyP
+    u8"\u0428",  // BracketLeft
+    u8"\u0429",  // BracketRight
+    u8"\u042d",  // Backslash
+    u8"\u0410",  // KeyA
+    u8"\u0421",  // KeyS
+    u8"\u0414",  // KeyD
+    u8"\u0424",  // KeyF
+    u8"\u0413",  // KeyG
+    u8"\u0427",  // KeyH
+    u8"\u0419",  // KeyJ
+    u8"\u041a",  // KeyK
+    u8"\u041b",  // KeyL
+    u8";",       // Semicolon
+    u8"'",       // Quote
+    u8"\u0417",  // KeyZ
+    u8"\u0425",  // KeyX
+    u8"\u0426",  // KeyC
+    u8"\u0412",  // KeyV
+    u8"\u0411",  // KeyB
+    u8"\u041d",  // KeyN
+    u8"\u041c",  // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftAltGr[] = {
+    u8"~",       // BackQuote
+    u8"!",       // Digit1
+    u8"@",       // Digit2
+    u8"#",       // Digit3
+    u8"$",       // Digit4
+    u8"%",       // Digit5
+    u8"^",       // Digit6
+    u8"&",       // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"+",       // Equal
+    u8"Q",       // KeyQ
+    u8"W",       // KeyW
+    u8"E",       // KeyE
+    u8"R",       // KeyR
+    u8"T",       // KeyT
+    u8"Y",       // KeyY
+    u8"U",       // KeyU
+    u8"I",       // KeyI
+    u8"O",       // KeyO
+    u8"P",       // KeyP
+    u8"{",       // BracketLeft
+    u8"}",       // BracketRight
+    u8"|",       // Backslash
+    u8"A",       // KeyA
+    u8"S",       // KeyS
+    u8"D",       // KeyD
+    u8"F",       // KeyF
+    u8"G",       // KeyG
+    u8"H",       // KeyH
+    u8"J",       // KeyJ
+    u8"K",       // KeyK
+    u8"L",       // KeyL
+    u8":",       // Semicolon
+    u8"\"",      // Quote
+    u8"Z",       // KeyZ
+    u8"X",       // KeyX
+    u8"C",       // KeyC
+    u8"V",       // KeyV
+    u8"B",       // KeyB
+    u8"N",       // KeyN
+    u8"M",       // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltgrCapslock[] = {
+    u8"`",       // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"=",       // Equal
+    u8"Q",       // KeyQ
+    u8"W",       // KeyW
+    u8"E",       // KeyE
+    u8"R",       // KeyR
+    u8"T",       // KeyT
+    u8"Y",       // KeyY
+    u8"U",       // KeyU
+    u8"I",       // KeyI
+    u8"O",       // KeyO
+    u8"P",       // KeyP
+    u8"[",       // BracketLeft
+    u8"]",       // BracketRight
+    u8"\\",      // Backslash
+    u8"A",       // KeyA
+    u8"S",       // KeyS
+    u8"D",       // KeyD
+    u8"F",       // KeyF
+    u8"G",       // KeyG
+    u8"H",       // KeyH
+    u8"J",       // KeyJ
+    u8"K",       // KeyK
+    u8"L",       // KeyL
+    u8";",       // Semicolon
+    u8"'",       // Quote
+    u8"Z",       // KeyZ
+    u8"X",       // KeyX
+    u8"C",       // KeyC
+    u8"V",       // KeyV
+    u8"B",       // KeyB
+    u8"N",       // KeyN
+    u8"M",       // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftCapslock[] = {
+    u8"\u044e",  // BackQuote
+    u8"!",       // Digit1
+    u8"\u044a",  // Digit2
+    u8"\u042a",  // Digit3
+    u8"$",       // Digit4
+    u8"%",       // Digit5
+    u8"\u0451",  // Digit6
+    u8"\u0401",  // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"\u044c",  // Equal
+    u8"\u044f",  // KeyQ
+    u8"\u0436",  // KeyW
+    u8"\u0435",  // KeyE
+    u8"\u0440",  // KeyR
+    u8"\u0442",  // KeyT
+    u8"\u044b",  // KeyY
+    u8"\u0443",  // KeyU
+    u8"\u0438",  // KeyI
+    u8"\u043e",  // KeyO
+    u8"\u043f",  // KeyP
+    u8"\u0448",  // BracketLeft
+    u8"\u0449",  // BracketRight
+    u8"\u044d",  // Backslash
+    u8"\u0430",  // KeyA
+    u8"\u0441",  // KeyS
+    u8"\u0434",  // KeyD
+    u8"\u0444",  // KeyF
+    u8"\u0433",  // KeyG
+    u8"\u0447",  // KeyH
+    u8"\u0439",  // KeyJ
+    u8"\u043a",  // KeyK
+    u8"\u043b",  // KeyL
+    u8":",       // Semicolon
+    u8"\"",      // Quote
+    u8"\u0437",  // KeyZ
+    u8"\u0445",  // KeyX
+    u8"\u0446",  // KeyC
+    u8"\u0432",  // KeyV
+    u8"\u0431",  // KeyB
+    u8"\u043d",  // KeyN
+    u8"\u043c",  // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftAltGrCapslock[] = {
+    u8"~",       // BackQuote
+    u8"!",       // Digit1
+    u8"@",       // Digit2
+    u8"#",       // Digit3
+    u8"$",       // Digit4
+    u8"%",       // Digit5
+    u8"^",       // Digit6
+    u8"&",       // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"+",       // Equal
+    u8"q",       // KeyQ
+    u8"w",       // KeyW
+    u8"e",       // KeyE
+    u8"r",       // KeyR
+    u8"t",       // KeyT
+    u8"y",       // KeyY
+    u8"u",       // KeyU
+    u8"i",       // KeyI
+    u8"o",       // KeyO
+    u8"p",       // KeyP
+    u8"{",       // BracketLeft
+    u8"}",       // BracketRight
+    u8"|",       // Backslash
+    u8"a",       // KeyA
+    u8"s",       // KeyS
+    u8"d",       // KeyD
+    u8"f",       // KeyF
+    u8"g",       // KeyG
+    u8"h",       // KeyH
+    u8"j",       // KeyJ
+    u8"k",       // KeyK
+    u8"l",       // KeyL
+    u8":",       // Semicolon
+    u8"\"",      // Quote
+    u8"z",       // KeyZ
+    u8"x",       // KeyX
+    u8"c",       // KeyC
+    u8"v",       // KeyV
+    u8"b",       // KeyB
+    u8"n",       // KeyN
+    u8"m",       // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char** kKeyMap[8] = {
+    kNormal,   kShift,         kAltGr,         kShiftAltGr,
+    kCapslock, kShiftCapslock, kAltgrCapslock, kShiftAltGrCapslock};
+
+}  // namespace ru_phone_yazhert
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_yazhert.h b/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_yazhert.h
index 5c9b3fd..0f336f6 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_yazhert.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ru_phone_yazhert.h
@@ -5,94 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_RU_PHONE_YAZHERT_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_RU_PHONE_YAZHERT_H_
 
-const wchar_t* key_map_ru_phone_yazhert[] = {
-    // Row #1
-    L"\u044e1234567890-\u044c"
-    // Row #2
-    L"\u044f\u0436\u0435\u0440\u0442\u044b\u0443\u0438\u043e\u043f\u0448\u0449"
-    L"\u044d"
-    // Row #3
-    L"\u0430\u0441\u0434\u0444\u0433\u0447\u0439\u043a\u043b;'"
-    // Row #4
-    L"\u0437\u0445\u0446\u0432\u0431\u043d\u043c,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u042e!\u044a\u042a$%\u0451\u0401*()_\u042c"
-    // Row #2
-    L"\u042f\u0416\u0415\u0420\u0422\u042b\u0423\u0418\u041e\u041f\u0428\u0429"
-    L"\u042d"
-    // Row #3
-    L"\u0410\u0421\u0414\u0424\u0413\u0427\u0419\u041a\u041b:\""
-    // Row #4
-    L"\u0417\u0425\u0426\u0412\u0411\u041d\u041c<>?"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"`1234567890-="
-    // Row #2
-    L"qwertyuiop[]\\"
-    // Row #3
-    L"asdfghjkl;'"
-    // Row #4
-    L"zxcvbnm,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u042e1234567890-\u042c"
-    // Row #2
-    L"\u042f\u0416\u0415\u0420\u0422\u042b\u0423\u0418\u041e\u041f\u0428\u0429"
-    L"\u042d"
-    // Row #3
-    L"\u0410\u0421\u0414\u0424\u0413\u0427\u0419\u041a\u041b;'"
-    // Row #4
-    L"\u0417\u0425\u0426\u0412\u0411\u041d\u041c,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"~!@#$%^&*()_+"
-    // Row #2
-    L"QWERTYUIOP{}|"
-    // Row #3
-    L"ASDFGHJKL:\""
-    // Row #4
-    L"ZXCVBNM<>?"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"`1234567890-="
-    // Row #2
-    L"QWERTYUIOP[]\\"
-    // Row #3
-    L"ASDFGHJKL;'"
-    // Row #4
-    L"ZXCVBNM,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u044e!\u044a\u042a$%\u0451\u0401*()_\u044c"
-    // Row #2
-    L"\u044f\u0436\u0435\u0440\u0442\u044b\u0443\u0438\u043e\u043f\u0448\u0449"
-    L"\u044d"
-    // Row #3
-    L"\u0430\u0441\u0434\u0444\u0433\u0447\u0439\u043a\u043b:\""
-    // Row #4
-    L"\u0437\u0445\u0446\u0432\u0431\u043d\u043c<>?"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"~!@#$%^&*()_+"
-    // Row #2
-    L"qwertyuiop{}|"
-    // Row #3
-    L"asdfghjkl:\""
-    // Row #4
-    L"zxcvbnm<>?"
-    // Row #5
-    L"\u0020"};
+namespace ru_phone_yazhert {
 
-const uint8_t key_map_index_ru_phone_yazhert[8]{0, 1, 2, 4, 3, 6, 5, 7};
-const char* id_ru_phone_yazhert = "ru_phone_yazhert";
-const bool is_102_ru_phone_yazhert = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace ru_phone_yazhert
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_RU_PHONE_YAZHERT_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.cc b/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.cc
new file mode 100644
index 0000000..dfcf8eb
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.cc
@@ -0,0 +1,265 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.h"
+
+namespace ta_inscript {
+
+const char* kId = "ta_inscript";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u0bca",  // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"\u0bf2",  // Equal
+    u8"\u0bcc",  // KeyQ
+    u8"\u0bc8",  // KeyW
+    u8"\u0bbe",  // KeyE
+    u8"\u0bc0",  // KeyR
+    u8"\u0bc2",  // KeyT
+    u8"\u0baa",  // KeyY
+    u8"\u0bb9",  // KeyU
+    u8"\u0b95",  // KeyI
+    u8"\u0ba4",  // KeyO
+    u8"\u0b9c",  // KeyP
+    u8"\u0b9f",  // BracketLeft
+    u8"\u0b9e",  // BracketRight
+    u8"\u0b9f",  // Backslash
+    u8"\u0bcb",  // KeyA
+    u8"\u0bc7",  // KeyS
+    u8"\u0bcd",  // KeyD
+    u8"\u0bbf",  // KeyF
+    u8"\u0bc1",  // KeyG
+    u8"\u0baa",  // KeyH
+    u8"\u0bb0",  // KeyJ
+    u8"\u0b95",  // KeyK
+    u8"\u0ba4",  // KeyL
+    u8"\u0b9a",  // Semicolon
+    u8"\u0b9f",  // Quote
+    u8"\u0bc6",  // KeyZ
+    u8"\u0b82",  // KeyX
+    u8"\u0bae",  // KeyC
+    u8"\u0ba8",  // KeyV
+    u8"\u0bb5",  // KeyB
+    u8"\u0bb2",  // KeyN
+    u8"\u0bb8",  // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"\u0baf",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"\u0b92",                    // BackQuote
+    u8"\u0b95",                    // Digit1
+    u8"\u0be8",                    // Digit2
+    u8"\u0bcd\u0bb0",              // Digit3
+    u8"\u0bb0\u0bcd",              // Digit4
+    u8"\u0b9c\u0bcd\u0b9e",        // Digit5
+    u8"\u0ba4\u0bcd\u0bb0",        // Digit6
+    u8"\u0b95\u0bcd\u0bb7",        // Digit7
+    u8"\u0bb6\u0bcd\u0bb0",        // Digit8
+    u8"(",                         // Digit9
+    u8")",                         // Digit0
+    u8"\u0b83",                    // Minus
+    u8"",                          // Equal
+    u8"\u0b94",                    // KeyQ
+    u8"\u0b90",                    // KeyW
+    u8"\u0b86",                    // KeyE
+    u8"\u0b88",                    // KeyR
+    u8"\u0b8a",                    // KeyT
+    u8"",                          // KeyY
+    u8"\u0b99",                    // KeyU
+    u8"",                          // KeyI
+    u8"",                          // KeyO
+    u8"\u0b9a",                    // KeyP
+    u8"",                          // BracketLeft
+    u8"",                          // BracketRight
+    u8"",                          // Backslash
+    u8"\u0b93",                    // KeyA
+    u8"\u0b8f",                    // KeyS
+    u8"\u0b85",                    // KeyD
+    u8"\u0b87",                    // KeyF
+    u8"\u0b89",                    // KeyG
+    u8"",                          // KeyH
+    u8"\u0bb1",                    // KeyJ
+    u8"",                          // KeyK
+    u8"",                          // KeyL
+    u8"",                          // Semicolon
+    u8"",                          // Quote
+    u8"\u0b8e",                    // KeyZ
+    u8"",                          // KeyX
+    u8"\u0ba3",                    // KeyC
+    u8"\u0ba9",                    // KeyV
+    u8"\u0bb4",                    // KeyB
+    u8"\u0bb3",                    // KeyN
+    u8"\u0bb6",                    // KeyM
+    u8"\u0bb7",                    // Comma
+    u8"\u0bb8\u0bcd\u0bb0\u0bc0",  // Period
+    u8"",                          // Slash
+    u8"\u0020",                    // Space
+};
+const char* kAltGr[] = {
+    u8"",        // BackQuote
+    u8"\u0be7",  // Digit1
+    u8"\u0be8",  // Digit2
+    u8"\u0be9",  // Digit3
+    u8"\u0bea",  // Digit4
+    u8"\u0beb",  // Digit5
+    u8"\u0bec",  // Digit6
+    u8"\u0bed",  // Digit7
+    u8"\u0bee",  // Digit8
+    u8"\u0bef",  // Digit9
+    u8"\u0be6",  // Digit0
+    u8"",        // Minus
+    u8"\u0bf2",  // Equal
+    u8"",        // KeyQ
+    u8"",        // KeyW
+    u8"",        // KeyE
+    u8"",        // KeyR
+    u8"",        // KeyT
+    u8"",        // KeyY
+    u8"",        // KeyU
+    u8"",        // KeyI
+    u8"",        // KeyO
+    u8"",        // KeyP
+    u8"",        // BracketLeft
+    u8"",        // BracketRight
+    u8"",        // Backslash
+    u8"",        // KeyA
+    u8"",        // KeyS
+    u8"",        // KeyD
+    u8"",        // KeyF
+    u8"",        // KeyG
+    u8"",        // KeyH
+    u8"",        // KeyJ
+    u8"",        // KeyK
+    u8"",        // KeyL
+    u8"",        // Semicolon
+    u8"",        // Quote
+    u8"",        // KeyZ
+    u8"",        // KeyX
+    u8"",        // KeyC
+    u8"",        // KeyV
+    u8"",        // KeyB
+    u8"",        // KeyN
+    u8"",        // KeyM
+    u8"",        // Comma
+    u8"",        // Period
+    u8"",        // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"\u0bca",  // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"\u0bf2",  // Equal
+    u8"\u0bcc",  // KeyQ
+    u8"\u0bc8",  // KeyW
+    u8"\u0bbe",  // KeyE
+    u8"\u0bc0",  // KeyR
+    u8"\u0bc2",  // KeyT
+    u8"\u0baa",  // KeyY
+    u8"\u0bb9",  // KeyU
+    u8"\u0b95",  // KeyI
+    u8"\u0ba4",  // KeyO
+    u8"\u0b9c",  // KeyP
+    u8"\u0b9f",  // BracketLeft
+    u8"\u0b9e",  // BracketRight
+    u8"\u0b9f",  // Backslash
+    u8"\u0bcb",  // KeyA
+    u8"\u0bc7",  // KeyS
+    u8"\u0bcd",  // KeyD
+    u8"\u0bbf",  // KeyF
+    u8"\u0bc1",  // KeyG
+    u8"\u0baa",  // KeyH
+    u8"\u0bb0",  // KeyJ
+    u8"\u0b95",  // KeyK
+    u8"\u0ba4",  // KeyL
+    u8"\u0b9a",  // Semicolon
+    u8"\u0b9f",  // Quote
+    u8"\u0bc6",  // KeyZ
+    u8"\u0b82",  // KeyX
+    u8"\u0bae",  // KeyC
+    u8"\u0ba8",  // KeyV
+    u8"\u0bb5",  // KeyB
+    u8"\u0bb2",  // KeyN
+    u8"\u0bb8",  // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"\u0baf",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftCapslock[] = {
+    u8"\u0b92",                    // BackQuote
+    u8"\u0b95",                    // Digit1
+    u8"\u0be8",                    // Digit2
+    u8"\u0bcd\u0bb0",              // Digit3
+    u8"\u0bb0\u0bcd",              // Digit4
+    u8"\u0b9c\u0bcd\u0b9e",        // Digit5
+    u8"\u0ba4\u0bcd\u0bb0",        // Digit6
+    u8"\u0b95\u0bcd\u0bb7",        // Digit7
+    u8"\u0bb6\u0bcd\u0bb0",        // Digit8
+    u8"(",                         // Digit9
+    u8")",                         // Digit0
+    u8"\u0b83",                    // Minus
+    u8"",                          // Equal
+    u8"\u0b94",                    // KeyQ
+    u8"\u0b90",                    // KeyW
+    u8"\u0b86",                    // KeyE
+    u8"\u0b88",                    // KeyR
+    u8"\u0b8a",                    // KeyT
+    u8"",                          // KeyY
+    u8"\u0b99",                    // KeyU
+    u8"",                          // KeyI
+    u8"",                          // KeyO
+    u8"\u0b9a",                    // KeyP
+    u8"",                          // BracketLeft
+    u8"",                          // BracketRight
+    u8"",                          // Backslash
+    u8"\u0b93",                    // KeyA
+    u8"\u0b8f",                    // KeyS
+    u8"\u0b85",                    // KeyD
+    u8"\u0b87",                    // KeyF
+    u8"\u0b89",                    // KeyG
+    u8"",                          // KeyH
+    u8"\u0bb1",                    // KeyJ
+    u8"",                          // KeyK
+    u8"",                          // KeyL
+    u8"",                          // Semicolon
+    u8"",                          // Quote
+    u8"\u0b8e",                    // KeyZ
+    u8"",                          // KeyX
+    u8"\u0ba3",                    // KeyC
+    u8"\u0ba9",                    // KeyV
+    u8"\u0bb4",                    // KeyB
+    u8"\u0bb3",                    // KeyN
+    u8"\u0bb6",                    // KeyM
+    u8"\u0bb7",                    // Comma
+    u8"\u0bb8\u0bcd\u0bb0\u0bc0",  // Period
+    u8"",                          // Slash
+    u8"\u0020",                    // Space
+};
+const char** kKeyMap[8] = {kNormal,   kShift,        kAltGr,
+                           kShift,    kCapslock,     kShiftCapslock,
+                           kCapslock, kShiftCapslock};
+
+}  // namespace ta_inscript
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.h b/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.h
index ad8fc7d..4cfb321 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.h
@@ -5,45 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TA_INSCRIPT_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TA_INSCRIPT_H_
 
-const wchar_t* key_map_ta_inscript[] = {
-    // Row #1
-    L"\u0bca1234567890-\u0bf2"
-    // Row #2
-    L"\u0bcc\u0bc8\u0bbe\u0bc0\u0bc2\u0baa\u0bb9\u0b95\u0ba4\u0b9c\u0b9f\u0b9e"
-    L"\u0b9f"
-    // Row #3
-    L"\u0bcb\u0bc7\u0bcd\u0bbf\u0bc1\u0baa\u0bb0\u0b95\u0ba4\u0b9a\u0b9f"
-    // Row #4
-    L"\u0bc6\u0b82\u0bae\u0ba8\u0bb5\u0bb2\u0bb8,.\u0baf"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u0b92\u0b95\u0be8{{\u0bcd\u0bb0}}{{\u0bb0\u0bcd}}{{\u0b9c\u0bcd\u0b9e}}{"
-    L"{\u0ba4\u0bcd\u0bb0}}{{\u0b95\u0bcd\u0bb7}}{{\u0bb6\u0bcd\u0bb0}}()"
-    L"\u0b83{{}}"
-    // Row #2
-    L"\u0b94\u0b90\u0b86\u0b88\u0b8a{{}}\u0b99{{}}{{}}\u0b9a{{}}{{}}{{}}"
-    // Row #3
-    L"\u0b93\u0b8f\u0b85\u0b87\u0b89{{}}\u0bb1{{}}{{}}{{}}{{}}"
-    // Row #4
-    L"\u0b8e{{}}\u0ba3\u0ba9\u0bb4\u0bb3\u0bb6\u0bb7{{\u0bb8\u0bcd\u0bb0\u0bc0}"
-    L"}{{}}"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"{{}}\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0be6{{}}"
-    L"\u0bf2"
-    // Row #2
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}"
-    // Row #3
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}"
-    // Row #4
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}"
-    // Row #5
-    L"\u0020"};
+namespace ta_inscript {
 
-const uint8_t key_map_index_ta_inscript[8]{0, 1, 2, 1, 0, 1, 0, 1};
-const char* id_ta_inscript = "ta_inscript";
-const bool is_102_ta_inscript = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace ta_inscript
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TA_INSCRIPT_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ta_typewriter.cc b/chromeos/services/ime/public/cpp/rulebased/def/ta_typewriter.cc
new file mode 100644
index 0000000..6c62c0c
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ta_typewriter.cc
@@ -0,0 +1,215 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/ta_typewriter.h"
+
+namespace ta_typewriter {
+
+const char* kId = "ta_typewriter";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"\u0b83",              // BackQuote
+    u8"1",                   // Digit1
+    u8"2",                   // Digit2
+    u8"3",                   // Digit3
+    u8"4",                   // Digit4
+    u8"5",                   // Digit5
+    u8"6",                   // Digit6
+    u8"7",                   // Digit7
+    u8"8",                   // Digit8
+    u8"9",                   // Digit9
+    u8"0",                   // Digit0
+    u8"/",                   // Minus
+    u8"=",                   // Equal
+    u8"\u0ba3\u0bc1",        // KeyQ
+    u8"\u0bb1",              // KeyW
+    u8"\u0ba8",              // KeyE
+    u8"\u0b9a",              // KeyR
+    u8"\u0bb5",              // KeyT
+    u8"\u0bb2",              // KeyY
+    u8"\u0bb0",              // KeyU
+    u8"\u0bc8",              // KeyI
+    u8"\u0b9f\u0bbf",        // KeyO
+    u8"\u0bbf",              // KeyP
+    u8"\u0bc1",              // BracketLeft
+    u8"\u0bb9",              // BracketRight
+    u8"\u0b95\u0bcd\u0bb7",  // Backslash
+    u8"\u0baf",              // KeyA
+    u8"\u0bb3",              // KeyS
+    u8"\u0ba9",              // KeyD
+    u8"\u0b95",              // KeyF
+    u8"\u0baa",              // KeyG
+    u8"\u0bbe",              // KeyH
+    u8"\u0ba4",              // KeyJ
+    u8"\u0bae",              // KeyK
+    u8"\u0b9f",              // KeyL
+    u8"\u0bcd",              // Semicolon
+    u8"\u0b99",              // Quote
+    u8"\u0ba3",              // KeyZ
+    u8"\u0b92",              // KeyX
+    u8"\u0b89",              // KeyC
+    u8"\u0b8e",              // KeyV
+    u8"\u0bc6",              // KeyB
+    u8"\u0bc7",              // KeyN
+    u8"\u0b85",              // KeyM
+    u8"\u0b87",              // Comma
+    u8",",                   // Period
+    u8".",                   // Slash
+    u8"\u0020",              // Space
+};
+const char* kShift[] = {
+    u8"'",                         // BackQuote
+    u8"\u0bb8",                    // Digit1
+    u8"\"",                        // Digit2
+    u8"%",                         // Digit3
+    u8"\u0b9c",                    // Digit4
+    u8"\u0bb6",                    // Digit5
+    u8"\u0bb7",                    // Digit6
+    u8"",                          // Digit7
+    u8"",                          // Digit8
+    u8"(",                         // Digit9
+    u8")",                         // Digit0
+    u8"\u0bb8\u0bcd\u0bb0\u0bc0",  // Minus
+    u8"+",                         // Equal
+    u8"",                          // KeyQ
+    u8"\u0bb1\u0bc1",              // KeyW
+    u8"\u0ba8\u0bc1",              // KeyE
+    u8"\u0b9a\u0bc1",              // KeyR
+    u8"\u0b95\u0bc2",              // KeyT
+    u8"\u0bb2\u0bc1",              // KeyY
+    u8"\u0bb0\u0bc1",              // KeyU
+    u8"\u0b90",                    // KeyI
+    u8"\u0b9f\u0bc0",              // KeyO
+    u8"\u0bc0",                    // KeyP
+    u8"\u0bc2",                    // BracketLeft
+    u8"\u0bcc",                    // BracketRight
+    u8"\u0bf8",                    // Backslash
+    u8"",                          // KeyA
+    u8"\u0bb3\u0bc1",              // KeyS
+    u8"\u0ba9\u0bc1",              // KeyD
+    u8"\u0b95\u0bc1",              // KeyF
+    u8"\u0bb4\u0bc1",              // KeyG
+    u8"\u0bb4",                    // KeyH
+    u8"\u0ba4\u0bc1",              // KeyJ
+    u8"\u0bae\u0bc1",              // KeyK
+    u8"\u0b9f\u0bc1",              // KeyL
+    u8"\\",                        // Semicolon
+    u8"\u0b9e",                    // Quote
+    u8"\u0bb7",                    // KeyZ
+    u8"\u0b93",                    // KeyX
+    u8"\u0b8a",                    // KeyC
+    u8"\u0b8f",                    // KeyV
+    u8"\u0b95\u0bcd\u0bb7",        // KeyB
+    u8"\u0b9a\u0bc2",              // KeyN
+    u8"\u0b86",                    // KeyM
+    u8"\u0b88",                    // Comma
+    u8"?",                         // Period
+    u8"-",                         // Slash
+    u8"\u0020",                    // Space
+};
+const char* kCapslock[] = {
+    u8"'",                         // BackQuote
+    u8"\u0bb8",                    // Digit1
+    u8"\"",                        // Digit2
+    u8"%",                         // Digit3
+    u8"\u0b9c",                    // Digit4
+    u8"\u0bb6",                    // Digit5
+    u8"\u0bb7",                    // Digit6
+    u8"",                          // Digit7
+    u8"",                          // Digit8
+    u8"(",                         // Digit9
+    u8")",                         // Digit0
+    u8"\u0bb8\u0bcd\u0bb0\u0bc0",  // Minus
+    u8"+",                         // Equal
+    u8"",                          // KeyQ
+    u8"\u0bb1\u0bc1",              // KeyW
+    u8"\u0ba8\u0bc1",              // KeyE
+    u8"\u0b9a\u0bc1",              // KeyR
+    u8"\u0b95\u0bc2",              // KeyT
+    u8"\u0bb2\u0bc1",              // KeyY
+    u8"\u0bb0\u0bc1",              // KeyU
+    u8"\u0b90",                    // KeyI
+    u8"\u0b9f\u0bc0",              // KeyO
+    u8"\u0bc0",                    // KeyP
+    u8"\u0bc2",                    // BracketLeft
+    u8"\u0bcc",                    // BracketRight
+    u8"\u0bf8",                    // Backslash
+    u8"",                          // KeyA
+    u8"\u0bb3\u0bc1",              // KeyS
+    u8"\u0ba9\u0bc1",              // KeyD
+    u8"\u0b95\u0bc1",              // KeyF
+    u8"\u0bb4\u0bc1",              // KeyG
+    u8"\u0bb4",                    // KeyH
+    u8"\u0ba4\u0bc1",              // KeyJ
+    u8"\u0bae\u0bc1",              // KeyK
+    u8"\u0b9f\u0bc1",              // KeyL
+    u8"\\",                        // Semicolon
+    u8"\u0b9e",                    // Quote
+    u8"\u0bb7",                    // KeyZ
+    u8"\u0b93",                    // KeyX
+    u8"\u0b8a",                    // KeyC
+    u8"\u0b8f",                    // KeyV
+    u8"\u0b95\u0bcd\u0bb7",        // KeyB
+    u8"\u0b9a\u0bc2",              // KeyN
+    u8"\u0b86",                    // KeyM
+    u8"\u0b88",                    // Comma
+    u8"?",                         // Period
+    u8"-",                         // Slash
+    u8"\u0020",                    // Space
+};
+const char* kShiftCapslock[] = {
+    u8"\u0b83",              // BackQuote
+    u8"1",                   // Digit1
+    u8"2",                   // Digit2
+    u8"3",                   // Digit3
+    u8"4",                   // Digit4
+    u8"5",                   // Digit5
+    u8"6",                   // Digit6
+    u8"7",                   // Digit7
+    u8"8",                   // Digit8
+    u8"9",                   // Digit9
+    u8"0",                   // Digit0
+    u8"/",                   // Minus
+    u8"=",                   // Equal
+    u8"\u0ba3\u0bc1",        // KeyQ
+    u8"\u0bb1",              // KeyW
+    u8"\u0ba8",              // KeyE
+    u8"\u0b9a",              // KeyR
+    u8"\u0bb5",              // KeyT
+    u8"\u0bb2",              // KeyY
+    u8"\u0bb0",              // KeyU
+    u8"\u0bc8",              // KeyI
+    u8"\u0b9f\u0bbf",        // KeyO
+    u8"\u0bbf",              // KeyP
+    u8"\u0bc1",              // BracketLeft
+    u8"\u0bb9",              // BracketRight
+    u8"\u0b95\u0bcd\u0bb7",  // Backslash
+    u8"\u0baf",              // KeyA
+    u8"\u0bb3",              // KeyS
+    u8"\u0ba9",              // KeyD
+    u8"\u0b95",              // KeyF
+    u8"\u0baa",              // KeyG
+    u8"\u0bbe",              // KeyH
+    u8"\u0ba4",              // KeyJ
+    u8"\u0bae",              // KeyK
+    u8"\u0b9f",              // KeyL
+    u8"\u0bcd",              // Semicolon
+    u8"\u0b99",              // Quote
+    u8"\u0ba3",              // KeyZ
+    u8"\u0b92",              // KeyX
+    u8"\u0b89",              // KeyC
+    u8"\u0b8e",              // KeyV
+    u8"\u0bc6",              // KeyB
+    u8"\u0bc7",              // KeyN
+    u8"\u0b85",              // KeyM
+    u8"\u0b87",              // Comma
+    u8",",                   // Period
+    u8".",                   // Slash
+    u8"\u0020",              // Space
+};
+const char** kKeyMap[8] = {kNormal,   kShift,        kNormal,
+                           kShift,    kCapslock,     kShiftCapslock,
+                           kCapslock, kShiftCapslock};
+
+}  // namespace ta_typewriter
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ta_typewriter.h b/chromeos/services/ime/public/cpp/rulebased/def/ta_typewriter.h
index 1d21838..02c56bf1 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/ta_typewriter.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ta_typewriter.h
@@ -5,35 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TA_TYPEWRITER_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TA_TYPEWRITER_H_
 
-const wchar_t* key_map_ta_typewriter[] = {
-    // Row #1
-    L"\u0b831234567890/="
-    // Row #2
-    L"{{\u0ba3\u0bc1}}\u0bb1\u0ba8\u0b9a\u0bb5\u0bb2\u0bb0\u0bc8{{\u0b9f\u0bbf}"
-    L"}\u0bbf\u0bc1\u0bb9{{\u0b95\u0bcd\u0bb7}}"
-    // Row #3
-    L"\u0baf\u0bb3\u0ba9\u0b95\u0baa\u0bbe\u0ba4\u0bae\u0b9f\u0bcd\u0b99"
-    // Row #4
-    L"\u0ba3\u0b92\u0b89\u0b8e\u0bc6\u0bc7\u0b85\u0b87,."
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"'\u0bb8\"%\u0b9c\u0bb6\u0bb7{{}}{{}}(){{\u0bb8\u0bcd\u0bb0\u0bc0}}+"
-    // Row #2
-    L"{{}}{{\u0bb1\u0bc1}}{{\u0ba8\u0bc1}}{{\u0b9a\u0bc1}}{{\u0b95\u0bc2}}{{"
-    L"\u0bb2\u0bc1}}{{\u0bb0\u0bc1}}\u0b90{{\u0b9f\u0bc0}}"
-    L"\u0bc0\u0bc2\u0bcc\u0bf8"
-    // Row #3
-    L"{{}}{{\u0bb3\u0bc1}}{{\u0ba9\u0bc1}}{{\u0b95\u0bc1}}{{\u0bb4\u0bc1}}"
-    L"\u0bb4{{\u0ba4\u0bc1}}{{\u0bae\u0bc1}}{{\u0b9f\u0bc1}}\\\u0b9e"
-    // Row #4
-    L"\u0bb7\u0b93\u0b8a\u0b8f{{\u0b95\u0bcd\u0bb7}}{{\u0b9a\u0bc2}}\u0b86"
-    L"\u0b88?-"
-    // Row #5
-    L"\u0020"};
+namespace ta_typewriter {
 
-const uint8_t key_map_index_ta_typewriter[8]{0, 1, 0, 1, 1, 0, 1, 0};
-const char* id_ta_typewriter = "ta_typewriter";
-const bool is_102_ta_typewriter = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace ta_typewriter
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TA_TYPEWRITER_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/th.cc b/chromeos/services/ime/public/cpp/rulebased/def/th.cc
new file mode 100644
index 0000000..bfe8f36
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/th.cc
@@ -0,0 +1,315 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/th.h"
+
+namespace th {
+
+const char* kId = "th";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"_",       // BackQuote
+    u8"\u0e45",  // Digit1
+    u8"/",       // Digit2
+    u8"-",       // Digit3
+    u8"\u0e20",  // Digit4
+    u8"\u0e16",  // Digit5
+    u8"\u0e38",  // Digit6
+    u8"\u0e36",  // Digit7
+    u8"\u0e04",  // Digit8
+    u8"\u0e15",  // Digit9
+    u8"\u0e08",  // Digit0
+    u8"\u0e02",  // Minus
+    u8"\u0e0a",  // Equal
+    u8"\u0e46",  // KeyQ
+    u8"\u0e44",  // KeyW
+    u8"\u0e33",  // KeyE
+    u8"\u0e1e",  // KeyR
+    u8"\u0e30",  // KeyT
+    u8"\u0e31",  // KeyY
+    u8"\u0e35",  // KeyU
+    u8"\u0e23",  // KeyI
+    u8"\u0e19",  // KeyO
+    u8"\u0e22",  // KeyP
+    u8"\u0e1a",  // BracketLeft
+    u8"\u0e25",  // BracketRight
+    u8"\u0e03",  // Backslash
+    u8"\u0e1f",  // KeyA
+    u8"\u0e2b",  // KeyS
+    u8"\u0e01",  // KeyD
+    u8"\u0e14",  // KeyF
+    u8"\u0e40",  // KeyG
+    u8"\u0e49",  // KeyH
+    u8"\u0e48",  // KeyJ
+    u8"\u0e32",  // KeyK
+    u8"\u0e2a",  // KeyL
+    u8"\u0e27",  // Semicolon
+    u8"\u0e07",  // Quote
+    u8"\u0e1c",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e41",  // KeyC
+    u8"\u0e2d",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e37",  // KeyN
+    u8"\u0e17",  // KeyM
+    u8"\u0e21",  // Comma
+    u8"\u0e43",  // Period
+    u8"\u0e1d",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"%",       // BackQuote
+    u8"+",       // Digit1
+    u8"\u0e51",  // Digit2
+    u8"\u0e52",  // Digit3
+    u8"\u0e53",  // Digit4
+    u8"\u0e54",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e3f",  // Digit7
+    u8"\u0e55",  // Digit8
+    u8"\u0e56",  // Digit9
+    u8"\u0e57",  // Digit0
+    u8"\u0e58",  // Minus
+    u8"\u0e59",  // Equal
+    u8"\u0e50",  // KeyQ
+    u8"\"",      // KeyW
+    u8"\u0e0e",  // KeyE
+    u8"\u0e11",  // KeyR
+    u8"\u0e18",  // KeyT
+    u8"\u0e4d",  // KeyY
+    u8"\u0e4a",  // KeyU
+    u8"\u0e13",  // KeyI
+    u8"\u0e2f",  // KeyO
+    u8"\u0e0d",  // KeyP
+    u8"\u0e10",  // BracketLeft
+    u8",",       // BracketRight
+    u8"\u0e05",  // Backslash
+    u8"\u0e24",  // KeyA
+    u8"\u0e06",  // KeyS
+    u8"\u0e0f",  // KeyD
+    u8"\u0e42",  // KeyF
+    u8"\u0e0c",  // KeyG
+    u8"\u0e47",  // KeyH
+    u8"\u0e4b",  // KeyJ
+    u8"\u0e29",  // KeyK
+    u8"\u0e28",  // KeyL
+    u8"\u0e0b",  // Semicolon
+    u8".",       // Quote
+    u8"(",       // KeyZ
+    u8")",       // KeyX
+    u8"\u0e09",  // KeyC
+    u8"\u0e2e",  // KeyV
+    u8"\u0e3a",  // KeyB
+    u8"\u0e4c",  // KeyN
+    u8"?",       // KeyM
+    u8"\u0e12",  // Comma
+    u8"\u0e2c",  // Period
+    u8"\u0e26",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltGr[] = {
+    u8"",        // BackQuote
+    u8"",        // Digit1
+    u8"",        // Digit2
+    u8"",        // Digit3
+    u8"",        // Digit4
+    u8"",        // Digit5
+    u8"",        // Digit6
+    u8"",        // Digit7
+    u8"",        // Digit8
+    u8"",        // Digit9
+    u8"",        // Digit0
+    u8"",        // Minus
+    u8"",        // Equal
+    u8"",        // KeyQ
+    u8"",        // KeyW
+    u8"",        // KeyE
+    u8"",        // KeyR
+    u8"",        // KeyT
+    u8"",        // KeyY
+    u8"",        // KeyU
+    u8"",        // KeyI
+    u8"",        // KeyO
+    u8"",        // KeyP
+    u8"%",       // BracketLeft
+    u8"\u0e51",  // BracketRight
+    u8"+",       // Backslash
+    u8"",        // KeyA
+    u8"",        // KeyS
+    u8"",        // KeyD
+    u8"",        // KeyF
+    u8"",        // KeyG
+    u8"",        // KeyH
+    u8"",        // KeyJ
+    u8"",        // KeyK
+    u8"",        // KeyL
+    u8"",        // Semicolon
+    u8"",        // Quote
+    u8"",        // KeyZ
+    u8"",        // KeyX
+    u8"",        // KeyC
+    u8"",        // KeyV
+    u8"",        // KeyB
+    u8"",        // KeyN
+    u8"",        // KeyM
+    u8"",        // Comma
+    u8"",        // Period
+    u8"",        // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"%",       // BackQuote
+    u8"+",       // Digit1
+    u8"\u0e51",  // Digit2
+    u8"\u0e52",  // Digit3
+    u8"\u0e53",  // Digit4
+    u8"\u0e54",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e3f",  // Digit7
+    u8"\u0e55",  // Digit8
+    u8"\u0e56",  // Digit9
+    u8"\u0e57",  // Digit0
+    u8"\u0e58",  // Minus
+    u8"\u0e59",  // Equal
+    u8"\u0e50",  // KeyQ
+    u8"\"",      // KeyW
+    u8"\u0e0e",  // KeyE
+    u8"\u0e11",  // KeyR
+    u8"\u0e18",  // KeyT
+    u8"\u0e4d",  // KeyY
+    u8"\u0e4a",  // KeyU
+    u8"\u0e13",  // KeyI
+    u8"\u0e2f",  // KeyO
+    u8"\u0e0d",  // KeyP
+    u8"\u0e10",  // BracketLeft
+    u8",",       // BracketRight
+    u8"\u0e05",  // Backslash
+    u8"\u0e24",  // KeyA
+    u8"\u0e06",  // KeyS
+    u8"\u0e0f",  // KeyD
+    u8"\u0e42",  // KeyF
+    u8"\u0e0c",  // KeyG
+    u8"\u0e47",  // KeyH
+    u8"\u0e4b",  // KeyJ
+    u8"\u0e29",  // KeyK
+    u8"\u0e28",  // KeyL
+    u8"\u0e0b",  // Semicolon
+    u8".",       // Quote
+    u8"(",       // KeyZ
+    u8")",       // KeyX
+    u8"\u0e09",  // KeyC
+    u8"\u0e2e",  // KeyV
+    u8"\u0e3a",  // KeyB
+    u8"\u0e4c",  // KeyN
+    u8"?",       // KeyM
+    u8"\u0e12",  // Comma
+    u8"\u0e2c",  // Period
+    u8"\u0e26",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltgrCapslock[] = {
+    u8"",        // BackQuote
+    u8"",        // Digit1
+    u8"",        // Digit2
+    u8"",        // Digit3
+    u8"",        // Digit4
+    u8"",        // Digit5
+    u8"",        // Digit6
+    u8"",        // Digit7
+    u8"",        // Digit8
+    u8"",        // Digit9
+    u8"",        // Digit0
+    u8"",        // Minus
+    u8"",        // Equal
+    u8"",        // KeyQ
+    u8"",        // KeyW
+    u8"",        // KeyE
+    u8"",        // KeyR
+    u8"",        // KeyT
+    u8"",        // KeyY
+    u8"",        // KeyU
+    u8"",        // KeyI
+    u8"",        // KeyO
+    u8"",        // KeyP
+    u8"%",       // BracketLeft
+    u8"\u0e51",  // BracketRight
+    u8"+",       // Backslash
+    u8"",        // KeyA
+    u8"",        // KeyS
+    u8"",        // KeyD
+    u8"",        // KeyF
+    u8"",        // KeyG
+    u8"",        // KeyH
+    u8"",        // KeyJ
+    u8"",        // KeyK
+    u8"",        // KeyL
+    u8"",        // Semicolon
+    u8"",        // Quote
+    u8"",        // KeyZ
+    u8"",        // KeyX
+    u8"",        // KeyC
+    u8"",        // KeyV
+    u8"",        // KeyB
+    u8"",        // KeyN
+    u8"",        // KeyM
+    u8"",        // Comma
+    u8"",        // Period
+    u8"",        // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftCapslock[] = {
+    u8"_",       // BackQuote
+    u8"\u0e45",  // Digit1
+    u8"/",       // Digit2
+    u8"-",       // Digit3
+    u8"\u0e20",  // Digit4
+    u8"\u0e16",  // Digit5
+    u8"\u0e38",  // Digit6
+    u8"\u0e36",  // Digit7
+    u8"\u0e04",  // Digit8
+    u8"\u0e15",  // Digit9
+    u8"\u0e08",  // Digit0
+    u8"\u0e02",  // Minus
+    u8"\u0e0a",  // Equal
+    u8"\u0e46",  // KeyQ
+    u8"\u0e44",  // KeyW
+    u8"\u0e33",  // KeyE
+    u8"\u0e1e",  // KeyR
+    u8"\u0e30",  // KeyT
+    u8"\u0e31",  // KeyY
+    u8"\u0e35",  // KeyU
+    u8"\u0e23",  // KeyI
+    u8"\u0e19",  // KeyO
+    u8"\u0e22",  // KeyP
+    u8"\u0e1a",  // BracketLeft
+    u8"\u0e25",  // BracketRight
+    u8"\u0e03",  // Backslash
+    u8"\u0e1f",  // KeyA
+    u8"\u0e2b",  // KeyS
+    u8"\u0e01",  // KeyD
+    u8"\u0e14",  // KeyF
+    u8"\u0e40",  // KeyG
+    u8"\u0e49",  // KeyH
+    u8"\u0e48",  // KeyJ
+    u8"\u0e32",  // KeyK
+    u8"\u0e2a",  // KeyL
+    u8"\u0e27",  // Semicolon
+    u8"\u0e07",  // Quote
+    u8"\u0e1c",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e41",  // KeyC
+    u8"\u0e2d",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e37",  // KeyN
+    u8"\u0e17",  // KeyM
+    u8"\u0e21",  // Comma
+    u8"\u0e43",  // Period
+    u8"\u0e1d",  // Slash
+    u8"\u0020",  // Space
+};
+const char** kKeyMap[8] = {kNormal,        kShift,        kAltGr,
+                           kShift,         kCapslock,     kShiftCapslock,
+                           kAltgrCapslock, kShiftCapslock};
+
+}  // namespace th
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/th.h b/chromeos/services/ime/public/cpp/rulebased/def/th.h
index da256fb3..6693166 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/th.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/th.h
@@ -5,41 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TH_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TH_H_
 
-const wchar_t* key_map_th[] = {
-    // Row #1
-    L"_\u0e45/-\u0e20\u0e16\u0e38\u0e36\u0e04\u0e15\u0e08\u0e02\u0e0a"
-    // Row #2
-    L"\u0e46\u0e44\u0e33\u0e1e\u0e30\u0e31\u0e35\u0e23\u0e19\u0e22\u0e1a\u0e25"
-    L"\u0e03"
-    // Row #3
-    L"\u0e1f\u0e2b\u0e01\u0e14\u0e40\u0e49\u0e48\u0e32\u0e2a\u0e27\u0e07"
-    // Row #4
-    L"\u0e1c\u0e1b\u0e41\u0e2d\u0e34\u0e37\u0e17\u0e21\u0e43\u0e1d"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"%+\u0e51\u0e52\u0e53\u0e54\u0e39\u0e3f\u0e55\u0e56\u0e57\u0e58\u0e59"
-    // Row #2
-    L"\u0e50\"\u0e0e\u0e11\u0e18\u0e4d\u0e4a\u0e13\u0e2f\u0e0d\u0e10,\u0e05"
-    // Row #3
-    L"\u0e24\u0e06\u0e0f\u0e42\u0e0c\u0e47\u0e4b\u0e29\u0e28\u0e0b."
-    // Row #4
-    L"()\u0e09\u0e2e\u0e3a\u0e4c?\u0e12\u0e2c\u0e26"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}"
-    // Row #2
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}%\u0e51+"
-    // Row #3
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}"
-    // Row #4
-    L"{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}{{}}"
-    // Row #5
-    L"\u0020"};
+namespace th {
 
-const uint8_t key_map_index_th[8]{0, 1, 2, 1, 1, 0, 2, 0};
-const char* id_th = "th";
-const bool is_102_th = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace th
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TH_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/th_pattajoti.cc b/chromeos/services/ime/public/cpp/rulebased/def/th_pattajoti.cc
new file mode 100644
index 0000000..4b26d58
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/th_pattajoti.cc
@@ -0,0 +1,415 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/th_pattajoti.h"
+
+namespace th_pattajoti {
+
+const char* kId = "th_pattajoti";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"_",       // BackQuote
+    u8"=",       // Digit1
+    u8"\u0e52",  // Digit2
+    u8"\u0e53",  // Digit3
+    u8"\u0e54",  // Digit4
+    u8"\u0e55",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e57",  // Digit7
+    u8"\u0e58",  // Digit8
+    u8"\u0e59",  // Digit9
+    u8"\u0e50",  // Digit0
+    u8"\u0e51",  // Minus
+    u8"\u0e56",  // Equal
+    u8"\u0e47",  // KeyQ
+    u8"\u0e15",  // KeyW
+    u8"\u0e22",  // KeyE
+    u8"\u0e2d",  // KeyR
+    u8"\u0e23",  // KeyT
+    u8"\u0e48",  // KeyY
+    u8"\u0e14",  // KeyU
+    u8"\u0e21",  // KeyI
+    u8"\u0e27",  // KeyO
+    u8"\u0e41",  // KeyP
+    u8"\u0e43",  // BracketLeft
+    u8"\u0e0c",  // BracketRight
+    u8"\u0e3a",  // Backslash
+    u8"\u0e49",  // KeyA
+    u8"\u0e17",  // KeyS
+    u8"\u0e07",  // KeyD
+    u8"\u0e01",  // KeyF
+    u8"\u0e31",  // KeyG
+    u8"\u0e35",  // KeyH
+    u8"\u0e32",  // KeyJ
+    u8"\u0e19",  // KeyK
+    u8"\u0e40",  // KeyL
+    u8"\u0e44",  // Semicolon
+    u8"\u0e02",  // Quote
+    u8"\u0e1a",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e25",  // KeyC
+    u8"\u0e2b",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e04",  // KeyN
+    u8"\u0e2a",  // KeyM
+    u8"\u0e30",  // Comma
+    u8"\u0e08",  // Period
+    u8"\u0e1e",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"\u0e3f",        // BackQuote
+    u8"+",             // Digit1
+    u8"\"",            // Digit2
+    u8"/",             // Digit3
+    u8",",             // Digit4
+    u8"?",             // Digit5
+    u8"\u0e38",        // Digit6
+    u8"\u0e45",        // Digit7
+    u8".",             // Digit8
+    u8"(",             // Digit9
+    u8")",             // Digit0
+    u8"-",             // Minus
+    u8"%",             // Equal
+    u8"\u0e4a",        // KeyQ
+    u8"\u0e24",        // KeyW
+    u8"\u0e46",        // KeyE
+    u8"\u0e0d",        // KeyR
+    u8"\u0e29",        // KeyT
+    u8"\u0e36",        // KeyY
+    u8"\u0e1d",        // KeyU
+    u8"\u0e0b",        // KeyI
+    u8"\u0e16",        // KeyO
+    u8"\u0e12",        // KeyP
+    u8"\u0e2f",        // BracketLeft
+    u8"\u0e26",        // BracketRight
+    u8"\u0e4d",        // Backslash
+    u8"\u0e4b",        // KeyA
+    u8"\u0e18",        // KeyS
+    u8"\u0e33",        // KeyD
+    u8"\u0e13",        // KeyF
+    u8"\u0e4c",        // KeyG
+    u8"\u0e37",        // KeyH
+    u8"\u0e1c",        // KeyJ
+    u8"\u0e0a",        // KeyK
+    u8"\u0e42",        // KeyL
+    u8"\u0e06",        // Semicolon
+    u8"\u0e11",        // Quote
+    u8"\u0e0e",        // KeyZ
+    u8"\u0e0f",        // KeyX
+    u8"\u0e10",        // KeyC
+    u8"\u0e20",        // KeyV
+    u8"\u0e31\u0e49",  // KeyB
+    u8"\u0e28",        // KeyN
+    u8"\u0e2e",        // KeyM
+    u8"\u0e1f",        // Comma
+    u8"\u0e09",        // Period
+    u8"\u0e2c",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kAltGr[] = {
+    u8"_",       // BackQuote
+    u8"=",       // Digit1
+    u8"\u0e52",  // Digit2
+    u8"\u0e53",  // Digit3
+    u8"\u0e54",  // Digit4
+    u8"\u0e55",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e57",  // Digit7
+    u8"\u0e58",  // Digit8
+    u8"\u0e59",  // Digit9
+    u8"\u0e50",  // Digit0
+    u8"\u0e51",  // Minus
+    u8"\u0e56",  // Equal
+    u8"\u0e47",  // KeyQ
+    u8"\u0e15",  // KeyW
+    u8"\u0e22",  // KeyE
+    u8"\u0e2d",  // KeyR
+    u8"\u0e23",  // KeyT
+    u8"\u0e48",  // KeyY
+    u8"\u0e14",  // KeyU
+    u8"\u0e21",  // KeyI
+    u8"\u0e27",  // KeyO
+    u8"\u0e41",  // KeyP
+    u8"\u0e43",  // BracketLeft
+    u8"\u0e0c",  // BracketRight
+    u8"\u0e3a",  // Backslash
+    u8"\u0e49",  // KeyA
+    u8"\u0e17",  // KeyS
+    u8"\u0e07",  // KeyD
+    u8"\u0e01",  // KeyF
+    u8"\u0e31",  // KeyG
+    u8"\u0e35",  // KeyH
+    u8"\u0e32",  // KeyJ
+    u8"\u0e19",  // KeyK
+    u8"\u0e40",  // KeyL
+    u8"\u0e44",  // Semicolon
+    u8"\u0e02",  // Quote
+    u8"\u0e1a",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e25",  // KeyC
+    u8"\u0e2b",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e04",  // KeyN
+    u8"\u0e2a",  // KeyM
+    u8"\u0e30",  // Comma
+    u8"\u0e08",  // Period
+    u8"\u0e1e",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"\u0e3f",        // BackQuote
+    u8"+",             // Digit1
+    u8"\"",            // Digit2
+    u8"/",             // Digit3
+    u8",",             // Digit4
+    u8"?",             // Digit5
+    u8"\u0e38",        // Digit6
+    u8"\u0e45",        // Digit7
+    u8".",             // Digit8
+    u8"(",             // Digit9
+    u8")",             // Digit0
+    u8"-",             // Minus
+    u8"%",             // Equal
+    u8"\u0e4a",        // KeyQ
+    u8"\u0e24",        // KeyW
+    u8"\u0e46",        // KeyE
+    u8"\u0e0d",        // KeyR
+    u8"\u0e29",        // KeyT
+    u8"\u0e36",        // KeyY
+    u8"\u0e1d",        // KeyU
+    u8"\u0e0b",        // KeyI
+    u8"\u0e16",        // KeyO
+    u8"\u0e12",        // KeyP
+    u8"\u0e2f",        // BracketLeft
+    u8"\u0e26",        // BracketRight
+    u8"\u0e4d",        // Backslash
+    u8"\u0e4b",        // KeyA
+    u8"\u0e18",        // KeyS
+    u8"\u0e33",        // KeyD
+    u8"\u0e13",        // KeyF
+    u8"\u0e4c",        // KeyG
+    u8"\u0e37",        // KeyH
+    u8"\u0e1c",        // KeyJ
+    u8"\u0e0a",        // KeyK
+    u8"\u0e42",        // KeyL
+    u8"\u0e06",        // Semicolon
+    u8"\u0e11",        // Quote
+    u8"\u0e0e",        // KeyZ
+    u8"\u0e0f",        // KeyX
+    u8"\u0e10",        // KeyC
+    u8"\u0e20",        // KeyV
+    u8"\u0e31\u0e49",  // KeyB
+    u8"\u0e28",        // KeyN
+    u8"\u0e2e",        // KeyM
+    u8"\u0e1f",        // Comma
+    u8"\u0e09",        // Period
+    u8"\u0e2c",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kShiftAltGr[] = {
+    u8"\u0e3f",        // BackQuote
+    u8"+",             // Digit1
+    u8"\"",            // Digit2
+    u8"/",             // Digit3
+    u8",",             // Digit4
+    u8"?",             // Digit5
+    u8"\u0e38",        // Digit6
+    u8"\u0e45",        // Digit7
+    u8".",             // Digit8
+    u8"(",             // Digit9
+    u8")",             // Digit0
+    u8"-",             // Minus
+    u8"%",             // Equal
+    u8"\u0e4a",        // KeyQ
+    u8"\u0e24",        // KeyW
+    u8"\u0e46",        // KeyE
+    u8"\u0e0d",        // KeyR
+    u8"\u0e29",        // KeyT
+    u8"\u0e36",        // KeyY
+    u8"\u0e1d",        // KeyU
+    u8"\u0e0b",        // KeyI
+    u8"\u0e16",        // KeyO
+    u8"\u0e12",        // KeyP
+    u8"\u0e2f",        // BracketLeft
+    u8"\u0e26",        // BracketRight
+    u8"\u0e4d",        // Backslash
+    u8"\u0e4b",        // KeyA
+    u8"\u0e18",        // KeyS
+    u8"\u0e33",        // KeyD
+    u8"\u0e13",        // KeyF
+    u8"\u0e4c",        // KeyG
+    u8"\u0e37",        // KeyH
+    u8"\u0e1c",        // KeyJ
+    u8"\u0e0a",        // KeyK
+    u8"\u0e42",        // KeyL
+    u8"\u0e06",        // Semicolon
+    u8"\u0e11",        // Quote
+    u8"\u0e0e",        // KeyZ
+    u8"\u0e0f",        // KeyX
+    u8"\u0e10",        // KeyC
+    u8"\u0e20",        // KeyV
+    u8"\u0e31\u0e49",  // KeyB
+    u8"\u0e28",        // KeyN
+    u8"\u0e2e",        // KeyM
+    u8"\u0e1f",        // Comma
+    u8"\u0e09",        // Period
+    u8"\u0e2c",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kAltgrCapslock[] = {
+    u8"\u0e3f",        // BackQuote
+    u8"+",             // Digit1
+    u8"\"",            // Digit2
+    u8"/",             // Digit3
+    u8",",             // Digit4
+    u8"?",             // Digit5
+    u8"\u0e38",        // Digit6
+    u8"\u0e45",        // Digit7
+    u8".",             // Digit8
+    u8"(",             // Digit9
+    u8")",             // Digit0
+    u8"-",             // Minus
+    u8"%",             // Equal
+    u8"\u0e4a",        // KeyQ
+    u8"\u0e24",        // KeyW
+    u8"\u0e46",        // KeyE
+    u8"\u0e0d",        // KeyR
+    u8"\u0e29",        // KeyT
+    u8"\u0e36",        // KeyY
+    u8"\u0e1d",        // KeyU
+    u8"\u0e0b",        // KeyI
+    u8"\u0e16",        // KeyO
+    u8"\u0e12",        // KeyP
+    u8"\u0e2f",        // BracketLeft
+    u8"\u0e26",        // BracketRight
+    u8"\u0e4d",        // Backslash
+    u8"\u0e4b",        // KeyA
+    u8"\u0e18",        // KeyS
+    u8"\u0e33",        // KeyD
+    u8"\u0e13",        // KeyF
+    u8"\u0e4c",        // KeyG
+    u8"\u0e37",        // KeyH
+    u8"\u0e1c",        // KeyJ
+    u8"\u0e0a",        // KeyK
+    u8"\u0e42",        // KeyL
+    u8"\u0e06",        // Semicolon
+    u8"\u0e11",        // Quote
+    u8"\u0e0e",        // KeyZ
+    u8"\u0e0f",        // KeyX
+    u8"\u0e10",        // KeyC
+    u8"\u0e20",        // KeyV
+    u8"\u0e31\u0e49",  // KeyB
+    u8"\u0e28",        // KeyN
+    u8"\u0e2e",        // KeyM
+    u8"\u0e1f",        // Comma
+    u8"\u0e09",        // Period
+    u8"\u0e2c",        // Slash
+    u8"\u0020",        // Space
+};
+const char* kShiftCapslock[] = {
+    u8"_",       // BackQuote
+    u8"=",       // Digit1
+    u8"\u0e52",  // Digit2
+    u8"\u0e53",  // Digit3
+    u8"\u0e54",  // Digit4
+    u8"\u0e55",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e57",  // Digit7
+    u8"\u0e58",  // Digit8
+    u8"\u0e59",  // Digit9
+    u8"\u0e50",  // Digit0
+    u8"\u0e51",  // Minus
+    u8"\u0e56",  // Equal
+    u8"\u0e47",  // KeyQ
+    u8"\u0e15",  // KeyW
+    u8"\u0e22",  // KeyE
+    u8"\u0e2d",  // KeyR
+    u8"\u0e23",  // KeyT
+    u8"\u0e48",  // KeyY
+    u8"\u0e14",  // KeyU
+    u8"\u0e21",  // KeyI
+    u8"\u0e27",  // KeyO
+    u8"\u0e41",  // KeyP
+    u8"\u0e43",  // BracketLeft
+    u8"\u0e0c",  // BracketRight
+    u8"\u0e3a",  // Backslash
+    u8"\u0e49",  // KeyA
+    u8"\u0e17",  // KeyS
+    u8"\u0e07",  // KeyD
+    u8"\u0e01",  // KeyF
+    u8"\u0e31",  // KeyG
+    u8"\u0e35",  // KeyH
+    u8"\u0e32",  // KeyJ
+    u8"\u0e19",  // KeyK
+    u8"\u0e40",  // KeyL
+    u8"\u0e44",  // Semicolon
+    u8"\u0e02",  // Quote
+    u8"\u0e1a",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e25",  // KeyC
+    u8"\u0e2b",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e04",  // KeyN
+    u8"\u0e2a",  // KeyM
+    u8"\u0e30",  // Comma
+    u8"\u0e08",  // Period
+    u8"\u0e1e",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftAltGrCapslock[] = {
+    u8"_",       // BackQuote
+    u8"=",       // Digit1
+    u8"\u0e52",  // Digit2
+    u8"\u0e53",  // Digit3
+    u8"\u0e54",  // Digit4
+    u8"\u0e55",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e57",  // Digit7
+    u8"\u0e58",  // Digit8
+    u8"\u0e59",  // Digit9
+    u8"\u0e50",  // Digit0
+    u8"\u0e51",  // Minus
+    u8"\u0e56",  // Equal
+    u8"\u0e47",  // KeyQ
+    u8"\u0e15",  // KeyW
+    u8"\u0e22",  // KeyE
+    u8"\u0e2d",  // KeyR
+    u8"\u0e23",  // KeyT
+    u8"\u0e48",  // KeyY
+    u8"\u0e14",  // KeyU
+    u8"\u0e21",  // KeyI
+    u8"\u0e27",  // KeyO
+    u8"\u0e41",  // KeyP
+    u8"\u0e43",  // BracketLeft
+    u8"\u0e0c",  // BracketRight
+    u8"\u0e3a",  // Backslash
+    u8"\u0e49",  // KeyA
+    u8"\u0e17",  // KeyS
+    u8"\u0e07",  // KeyD
+    u8"\u0e01",  // KeyF
+    u8"\u0e31",  // KeyG
+    u8"\u0e35",  // KeyH
+    u8"\u0e32",  // KeyJ
+    u8"\u0e19",  // KeyK
+    u8"\u0e40",  // KeyL
+    u8"\u0e44",  // Semicolon
+    u8"\u0e02",  // Quote
+    u8"\u0e1a",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e25",  // KeyC
+    u8"\u0e2b",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e04",  // KeyN
+    u8"\u0e2a",  // KeyM
+    u8"\u0e30",  // Comma
+    u8"\u0e08",  // Period
+    u8"\u0e1e",  // Slash
+    u8"\u0020",  // Space
+};
+const char** kKeyMap[8] = {
+    kNormal,   kShift,         kAltGr,         kShiftAltGr,
+    kCapslock, kShiftCapslock, kAltgrCapslock, kShiftAltGrCapslock};
+
+}  // namespace th_pattajoti
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/th_pattajoti.h b/chromeos/services/ime/public/cpp/rulebased/def/th_pattajoti.h
index daf9987..dc20e12 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/th_pattajoti.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/th_pattajoti.h
@@ -5,32 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TH_PATTAJOTI_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TH_PATTAJOTI_H_
 
-const wchar_t* key_map_th_pattajoti[] = {
-    // Row #1
-    L"_=\u0e52\u0e53\u0e54\u0e55\u0e39\u0e57\u0e58\u0e59\u0e50\u0e51\u0e56"
-    // Row #2
-    L"\u0e47\u0e15\u0e22\u0e2d\u0e23\u0e48\u0e14\u0e21\u0e27\u0e41\u0e43\u0e0c"
-    L"\u0e3a"
-    // Row #3
-    L"\u0e49\u0e17\u0e07\u0e01\u0e31\u0e35\u0e32\u0e19\u0e40\u0e44\u0e02"
-    // Row #4
-    L"\u0e1a\u0e1b\u0e25\u0e2b\u0e34\u0e04\u0e2a\u0e30\u0e08\u0e1e"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"\u0e3f+\"/,?\u0e38\u0e45.()-%"
-    // Row #2
-    L"\u0e4a\u0e24\u0e46\u0e0d\u0e29\u0e36\u0e1d\u0e0b\u0e16\u0e12\u0e2f\u0e26"
-    L"\u0e4d"
-    // Row #3
-    L"\u0e4b\u0e18\u0e33\u0e13\u0e4c\u0e37\u0e1c\u0e0a\u0e42\u0e06\u0e11"
-    // Row #4
-    L"\u0e0e\u0e0f\u0e10\u0e20{{\u0e31\u0e49}}\u0e28\u0e2e\u0e1f\u0e09\u0e2c"
-    // Row #5
-    L"\u0020"};
+namespace th_pattajoti {
 
-const uint8_t key_map_index_th_pattajoti[8]{0, 1, 0, 1, 1, 0, 1, 0};
-const char* id_th_pattajoti = "th_pattajoti";
-const bool is_102_th_pattajoti = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace th_pattajoti
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TH_PATTAJOTI_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/th_tis.cc b/chromeos/services/ime/public/cpp/rulebased/def/th_tis.cc
new file mode 100644
index 0000000..b579702
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/def/th_tis.cc
@@ -0,0 +1,415 @@
+// 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 "chromeos/services/ime/public/cpp/rulebased/def/th_tis.h"
+
+namespace th_tis {
+
+const char* kId = "th_tis";
+bool kIs102 = false;
+const char* kNormal[] = {
+    u8"_",       // BackQuote
+    u8"\u0e45",  // Digit1
+    u8"/",       // Digit2
+    u8"-",       // Digit3
+    u8"\u0e20",  // Digit4
+    u8"\u0e16",  // Digit5
+    u8"\u0e38",  // Digit6
+    u8"\u0e36",  // Digit7
+    u8"\u0e04",  // Digit8
+    u8"\u0e15",  // Digit9
+    u8"\u0e08",  // Digit0
+    u8"\u0e02",  // Minus
+    u8"\u0e0a",  // Equal
+    u8"\u0e46",  // KeyQ
+    u8"\u0e44",  // KeyW
+    u8"\u0e33",  // KeyE
+    u8"\u0e1e",  // KeyR
+    u8"\u0e30",  // KeyT
+    u8"\u0e31",  // KeyY
+    u8"\u0e35",  // KeyU
+    u8"\u0e23",  // KeyI
+    u8"\u0e19",  // KeyO
+    u8"\u0e22",  // KeyP
+    u8"\u0e1a",  // BracketLeft
+    u8"\u0e25",  // BracketRight
+    u8"\u0e03",  // Backslash
+    u8"\u0e1f",  // KeyA
+    u8"\u0e2b",  // KeyS
+    u8"\u0e01",  // KeyD
+    u8"\u0e14",  // KeyF
+    u8"\u0e40",  // KeyG
+    u8"\u0e49",  // KeyH
+    u8"\u0e48",  // KeyJ
+    u8"\u0e32",  // KeyK
+    u8"\u0e2a",  // KeyL
+    u8"\u0e27",  // Semicolon
+    u8"\u0e07",  // Quote
+    u8"\u0e1c",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e41",  // KeyC
+    u8"\u0e2d",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e37",  // KeyN
+    u8"\u0e17",  // KeyM
+    u8"\u0e21",  // Comma
+    u8"\u0e43",  // Period
+    u8"\u0e1d",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"%",       // BackQuote
+    u8"+",       // Digit1
+    u8"\u0e51",  // Digit2
+    u8"\u0e52",  // Digit3
+    u8"\u0e53",  // Digit4
+    u8"\u0e54",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e3f",  // Digit7
+    u8"\u0e55",  // Digit8
+    u8"\u0e56",  // Digit9
+    u8"\u0e57",  // Digit0
+    u8"\u0e58",  // Minus
+    u8"\u0e59",  // Equal
+    u8"\u0e50",  // KeyQ
+    u8"\"",      // KeyW
+    u8"\u0e0e",  // KeyE
+    u8"\u0e11",  // KeyR
+    u8"\u0e18",  // KeyT
+    u8"\u0e4d",  // KeyY
+    u8"\u0e4a",  // KeyU
+    u8"\u0e13",  // KeyI
+    u8"\u0e2f",  // KeyO
+    u8"\u0e0d",  // KeyP
+    u8"\u0e10",  // BracketLeft
+    u8",",       // BracketRight
+    u8"\u0e05",  // Backslash
+    u8"\u0e24",  // KeyA
+    u8"\u0e06",  // KeyS
+    u8"\u0e0f",  // KeyD
+    u8"\u0e42",  // KeyF
+    u8"\u0e0c",  // KeyG
+    u8"\u0e47",  // KeyH
+    u8"\u0e4b",  // KeyJ
+    u8"\u0e29",  // KeyK
+    u8"\u0e28",  // KeyL
+    u8"\u0e0b",  // Semicolon
+    u8".",       // Quote
+    u8"(",       // KeyZ
+    u8")",       // KeyX
+    u8"\u0e09",  // KeyC
+    u8"\u0e2e",  // KeyV
+    u8"\u0e3a",  // KeyB
+    u8"\u0e4c",  // KeyN
+    u8"?",       // KeyM
+    u8"\u0e12",  // Comma
+    u8"\u0e2c",  // Period
+    u8"\u0e26",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltGr[] = {
+    u8"_",       // BackQuote
+    u8"\u0e45",  // Digit1
+    u8"/",       // Digit2
+    u8"-",       // Digit3
+    u8"\u0e20",  // Digit4
+    u8"\u0e16",  // Digit5
+    u8"\u0e38",  // Digit6
+    u8"\u0e36",  // Digit7
+    u8"\u0e04",  // Digit8
+    u8"\u0e15",  // Digit9
+    u8"\u0e08",  // Digit0
+    u8"\u0e02",  // Minus
+    u8"\u0e0a",  // Equal
+    u8"\u0e46",  // KeyQ
+    u8"\u0e44",  // KeyW
+    u8"\u0e33",  // KeyE
+    u8"\u0e1e",  // KeyR
+    u8"\u0e30",  // KeyT
+    u8"\u0e31",  // KeyY
+    u8"\u0e35",  // KeyU
+    u8"\u0e23",  // KeyI
+    u8"\u0e19",  // KeyO
+    u8"\u0e22",  // KeyP
+    u8"\u0e1a",  // BracketLeft
+    u8"\u0e25",  // BracketRight
+    u8"\u0e03",  // Backslash
+    u8"\u0e1f",  // KeyA
+    u8"\u0e2b",  // KeyS
+    u8"\u0e01",  // KeyD
+    u8"\u0e14",  // KeyF
+    u8"\u0e40",  // KeyG
+    u8"\u0e49",  // KeyH
+    u8"\u0e48",  // KeyJ
+    u8"\u0e32",  // KeyK
+    u8"\u0e2a",  // KeyL
+    u8"\u0e27",  // Semicolon
+    u8"\u0e07",  // Quote
+    u8"\u0e1c",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e41",  // KeyC
+    u8"\u0e2d",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e37",  // KeyN
+    u8"\u0e17",  // KeyM
+    u8"\u0e21",  // Comma
+    u8"\u0e43",  // Period
+    u8"\u0e1d",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"%",       // BackQuote
+    u8"+",       // Digit1
+    u8"\u0e51",  // Digit2
+    u8"\u0e52",  // Digit3
+    u8"\u0e53",  // Digit4
+    u8"\u0e54",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e3f",  // Digit7
+    u8"\u0e55",  // Digit8
+    u8"\u0e56",  // Digit9
+    u8"\u0e57",  // Digit0
+    u8"\u0e58",  // Minus
+    u8"\u0e59",  // Equal
+    u8"\u0e50",  // KeyQ
+    u8"\"",      // KeyW
+    u8"\u0e0e",  // KeyE
+    u8"\u0e11",  // KeyR
+    u8"\u0e18",  // KeyT
+    u8"\u0e4d",  // KeyY
+    u8"\u0e4a",  // KeyU
+    u8"\u0e13",  // KeyI
+    u8"\u0e2f",  // KeyO
+    u8"\u0e0d",  // KeyP
+    u8"\u0e10",  // BracketLeft
+    u8",",       // BracketRight
+    u8"\u0e05",  // Backslash
+    u8"\u0e24",  // KeyA
+    u8"\u0e06",  // KeyS
+    u8"\u0e0f",  // KeyD
+    u8"\u0e42",  // KeyF
+    u8"\u0e0c",  // KeyG
+    u8"\u0e47",  // KeyH
+    u8"\u0e4b",  // KeyJ
+    u8"\u0e29",  // KeyK
+    u8"\u0e28",  // KeyL
+    u8"\u0e0b",  // Semicolon
+    u8".",       // Quote
+    u8"(",       // KeyZ
+    u8")",       // KeyX
+    u8"\u0e09",  // KeyC
+    u8"\u0e2e",  // KeyV
+    u8"\u0e3a",  // KeyB
+    u8"\u0e4c",  // KeyN
+    u8"?",       // KeyM
+    u8"\u0e12",  // Comma
+    u8"\u0e2c",  // Period
+    u8"\u0e26",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftAltGr[] = {
+    u8"%",       // BackQuote
+    u8"+",       // Digit1
+    u8"\u0e51",  // Digit2
+    u8"\u0e52",  // Digit3
+    u8"\u0e53",  // Digit4
+    u8"\u0e54",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e3f",  // Digit7
+    u8"\u0e55",  // Digit8
+    u8"\u0e56",  // Digit9
+    u8"\u0e57",  // Digit0
+    u8"\u0e58",  // Minus
+    u8"\u0e59",  // Equal
+    u8"\u0e50",  // KeyQ
+    u8"\"",      // KeyW
+    u8"\u0e0e",  // KeyE
+    u8"\u0e11",  // KeyR
+    u8"\u0e18",  // KeyT
+    u8"\u0e4d",  // KeyY
+    u8"\u0e4a",  // KeyU
+    u8"\u0e13",  // KeyI
+    u8"\u0e2f",  // KeyO
+    u8"\u0e0d",  // KeyP
+    u8"\u0e10",  // BracketLeft
+    u8",",       // BracketRight
+    u8"\u0e05",  // Backslash
+    u8"\u0e24",  // KeyA
+    u8"\u0e06",  // KeyS
+    u8"\u0e0f",  // KeyD
+    u8"\u0e42",  // KeyF
+    u8"\u0e0c",  // KeyG
+    u8"\u0e47",  // KeyH
+    u8"\u0e4b",  // KeyJ
+    u8"\u0e29",  // KeyK
+    u8"\u0e28",  // KeyL
+    u8"\u0e0b",  // Semicolon
+    u8".",       // Quote
+    u8"(",       // KeyZ
+    u8")",       // KeyX
+    u8"\u0e09",  // KeyC
+    u8"\u0e2e",  // KeyV
+    u8"\u0e3a",  // KeyB
+    u8"\u0e4c",  // KeyN
+    u8"?",       // KeyM
+    u8"\u0e12",  // Comma
+    u8"\u0e2c",  // Period
+    u8"\u0e26",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kAltgrCapslock[] = {
+    u8"%",       // BackQuote
+    u8"+",       // Digit1
+    u8"\u0e51",  // Digit2
+    u8"\u0e52",  // Digit3
+    u8"\u0e53",  // Digit4
+    u8"\u0e54",  // Digit5
+    u8"\u0e39",  // Digit6
+    u8"\u0e3f",  // Digit7
+    u8"\u0e55",  // Digit8
+    u8"\u0e56",  // Digit9
+    u8"\u0e57",  // Digit0
+    u8"\u0e58",  // Minus
+    u8"\u0e59",  // Equal
+    u8"\u0e50",  // KeyQ
+    u8"\"",      // KeyW
+    u8"\u0e0e",  // KeyE
+    u8"\u0e11",  // KeyR
+    u8"\u0e18",  // KeyT
+    u8"\u0e4d",  // KeyY
+    u8"\u0e4a",  // KeyU
+    u8"\u0e13",  // KeyI
+    u8"\u0e2f",  // KeyO
+    u8"\u0e0d",  // KeyP
+    u8"\u0e10",  // BracketLeft
+    u8",",       // BracketRight
+    u8"\u0e05",  // Backslash
+    u8"\u0e24",  // KeyA
+    u8"\u0e06",  // KeyS
+    u8"\u0e0f",  // KeyD
+    u8"\u0e42",  // KeyF
+    u8"\u0e0c",  // KeyG
+    u8"\u0e47",  // KeyH
+    u8"\u0e4b",  // KeyJ
+    u8"\u0e29",  // KeyK
+    u8"\u0e28",  // KeyL
+    u8"\u0e0b",  // Semicolon
+    u8".",       // Quote
+    u8"(",       // KeyZ
+    u8")",       // KeyX
+    u8"\u0e09",  // KeyC
+    u8"\u0e2e",  // KeyV
+    u8"\u0e3a",  // KeyB
+    u8"\u0e4c",  // KeyN
+    u8"?",       // KeyM
+    u8"\u0e12",  // Comma
+    u8"\u0e2c",  // Period
+    u8"\u0e26",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftCapslock[] = {
+    u8"_",       // BackQuote
+    u8"\u0e45",  // Digit1
+    u8"/",       // Digit2
+    u8"-",       // Digit3
+    u8"\u0e20",  // Digit4
+    u8"\u0e16",  // Digit5
+    u8"\u0e38",  // Digit6
+    u8"\u0e36",  // Digit7
+    u8"\u0e04",  // Digit8
+    u8"\u0e15",  // Digit9
+    u8"\u0e08",  // Digit0
+    u8"\u0e02",  // Minus
+    u8"\u0e0a",  // Equal
+    u8"\u0e46",  // KeyQ
+    u8"\u0e44",  // KeyW
+    u8"\u0e33",  // KeyE
+    u8"\u0e1e",  // KeyR
+    u8"\u0e30",  // KeyT
+    u8"\u0e31",  // KeyY
+    u8"\u0e35",  // KeyU
+    u8"\u0e23",  // KeyI
+    u8"\u0e19",  // KeyO
+    u8"\u0e22",  // KeyP
+    u8"\u0e1a",  // BracketLeft
+    u8"\u0e25",  // BracketRight
+    u8"\u0e03",  // Backslash
+    u8"\u0e1f",  // KeyA
+    u8"\u0e2b",  // KeyS
+    u8"\u0e01",  // KeyD
+    u8"\u0e14",  // KeyF
+    u8"\u0e40",  // KeyG
+    u8"\u0e49",  // KeyH
+    u8"\u0e48",  // KeyJ
+    u8"\u0e32",  // KeyK
+    u8"\u0e2a",  // KeyL
+    u8"\u0e27",  // Semicolon
+    u8"\u0e07",  // Quote
+    u8"\u0e1c",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e41",  // KeyC
+    u8"\u0e2d",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e37",  // KeyN
+    u8"\u0e17",  // KeyM
+    u8"\u0e21",  // Comma
+    u8"\u0e43",  // Period
+    u8"\u0e1d",  // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftAltGrCapslock[] = {
+    u8"_",       // BackQuote
+    u8"\u0e45",  // Digit1
+    u8"/",       // Digit2
+    u8"-",       // Digit3
+    u8"\u0e20",  // Digit4
+    u8"\u0e16",  // Digit5
+    u8"\u0e38",  // Digit6
+    u8"\u0e36",  // Digit7
+    u8"\u0e04",  // Digit8
+    u8"\u0e15",  // Digit9
+    u8"\u0e08",  // Digit0
+    u8"\u0e02",  // Minus
+    u8"\u0e0a",  // Equal
+    u8"\u0e46",  // KeyQ
+    u8"\u0e44",  // KeyW
+    u8"\u0e33",  // KeyE
+    u8"\u0e1e",  // KeyR
+    u8"\u0e30",  // KeyT
+    u8"\u0e31",  // KeyY
+    u8"\u0e35",  // KeyU
+    u8"\u0e23",  // KeyI
+    u8"\u0e19",  // KeyO
+    u8"\u0e22",  // KeyP
+    u8"\u0e1a",  // BracketLeft
+    u8"\u0e25",  // BracketRight
+    u8"\u0e03",  // Backslash
+    u8"\u0e1f",  // KeyA
+    u8"\u0e2b",  // KeyS
+    u8"\u0e01",  // KeyD
+    u8"\u0e14",  // KeyF
+    u8"\u0e40",  // KeyG
+    u8"\u0e49",  // KeyH
+    u8"\u0e48",  // KeyJ
+    u8"\u0e32",  // KeyK
+    u8"\u0e2a",  // KeyL
+    u8"\u0e27",  // Semicolon
+    u8"\u0e07",  // Quote
+    u8"\u0e1c",  // KeyZ
+    u8"\u0e1b",  // KeyX
+    u8"\u0e41",  // KeyC
+    u8"\u0e2d",  // KeyV
+    u8"\u0e34",  // KeyB
+    u8"\u0e37",  // KeyN
+    u8"\u0e17",  // KeyM
+    u8"\u0e21",  // Comma
+    u8"\u0e43",  // Period
+    u8"\u0e1d",  // Slash
+    u8"\u0020",  // Space
+};
+const char** kKeyMap[8] = {
+    kNormal,   kShift,         kAltGr,         kShiftAltGr,
+    kCapslock, kShiftCapslock, kAltgrCapslock, kShiftAltGrCapslock};
+
+}  // namespace th_tis
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/th_tis.h b/chromeos/services/ime/public/cpp/rulebased/def/th_tis.h
index 755b51d..3746458 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/th_tis.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/th_tis.h
@@ -5,31 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TH_TIS_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TH_TIS_H_
 
-const wchar_t* key_map_th_tis[] = {
-    // Row #1
-    L"_\u0e45/-\u0e20\u0e16\u0e38\u0e36\u0e04\u0e15\u0e08\u0e02\u0e0a"
-    // Row #2
-    L"\u0e46\u0e44\u0e33\u0e1e\u0e30\u0e31\u0e35\u0e23\u0e19\u0e22\u0e1a\u0e25"
-    L"\u0e03"
-    // Row #3
-    L"\u0e1f\u0e2b\u0e01\u0e14\u0e40\u0e49\u0e48\u0e32\u0e2a\u0e27\u0e07"
-    // Row #4
-    L"\u0e1c\u0e1b\u0e41\u0e2d\u0e34\u0e37\u0e17\u0e21\u0e43\u0e1d"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"%+\u0e51\u0e52\u0e53\u0e54\u0e39\u0e3f\u0e55\u0e56\u0e57\u0e58\u0e59"
-    // Row #2
-    L"\u0e50\"\u0e0e\u0e11\u0e18\u0e4d\u0e4a\u0e13\u0e2f\u0e0d\u0e10,\u0e05"
-    // Row #3
-    L"\u0e24\u0e06\u0e0f\u0e42\u0e0c\u0e47\u0e4b\u0e29\u0e28\u0e0b."
-    // Row #4
-    L"()\u0e09\u0e2e\u0e3a\u0e4c?\u0e12\u0e2c\u0e26"
-    // Row #5
-    L"\u0020"};
+namespace th_tis {
 
-const uint8_t key_map_index_th_tis[8]{0, 1, 0, 1, 1, 0, 1, 0};
-const char* id_th_tis = "th_tis";
-const bool is_102_th_tis = false;
+// The id of this IME/keyboard.
+extern const char* kId;
+
+// Whether this keyboard layout is a 102 or 101 keyboard.
+extern bool kIs102;
+
+// The key mapping definitions under various modifier states.
+extern const char** kKeyMap[8];
+
+}  // namespace th_tis
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_TH_TIS_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/us.cc b/chromeos/services/ime/public/cpp/rulebased/def/us.cc
index 4ca943b..c3fd481 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/us.cc
+++ b/chromeos/services/ime/public/cpp/rulebased/def/us.cc
@@ -4,50 +4,212 @@
 
 #include "chromeos/services/ime/public/cpp/rulebased/def/us.h"
 
-#include "base/stl_util.h"
+namespace us {
 
-const wchar_t* kKeyMapUs[] = {
-    // Row #1
-    L"`1234567890-="
-    // Row #2
-    L"qwertyuiop[]\\"
-    // Row #3
-    L"asdfghjkl;'"
-    // Row #4
-    L"zxcvbnm,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"~!@#$%^&*()_+"
-    // Row #2
-    L"QWERTYUIOP{}|"
-    // Row #3
-    L"ASDFGHJKL:\""
-    // Row #4
-    L"ZXCVBNM<>?"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"`1234567890-="
-    // Row #2
-    L"QWERTYUIOP[]\\"
-    // Row #3
-    L"ASDFGHJKL;'"
-    // Row #4
-    L"ZXCVBNM,./"
-    // Row #5
-    L"\u0020",
-    // Row #1
-    L"~!@#$%^&*()_+"
-    // Row #2
-    L"qwertyuiop{}|"
-    // Row #3
-    L"asdfghjkl:\""
-    // Row #4
-    L"zxcvbnm<>?"
-    // Row #5
-    L"\u0020"};
-const unsigned int kKeyMapUsLen = base::size(kKeyMapUs);
-const unsigned char kKeyMapIndexUs[8]{0, 1, 0, 1, 2, 3, 2, 3};
-const char* kIdUs = "us";
-const bool kIs102Us = false;
+const char* kNormal[] = {
+    u8"`",       // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"=",       // Equal
+    u8"q",       // KeyQ
+    u8"w",       // KeyW
+    u8"e",       // KeyE
+    u8"r",       // KeyR
+    u8"t",       // KeyT
+    u8"y",       // KeyY
+    u8"u",       // KeyU
+    u8"i",       // KeyI
+    u8"o",       // KeyO
+    u8"p",       // KeyP
+    u8"[",       // BracketLeft
+    u8"]",       // BracketRight
+    u8"\\",      // Backslash
+    u8"a",       // KeyA
+    u8"s",       // KeyS
+    u8"d",       // KeyD
+    u8"f",       // KeyF
+    u8"g",       // KeyG
+    u8"h",       // KeyH
+    u8"j",       // KeyJ
+    u8"k",       // KeyK
+    u8"l",       // KeyL
+    u8";",       // Semicolon
+    u8"'",       // Quote
+    u8"z",       // KeyZ
+    u8"x",       // KeyX
+    u8"c",       // KeyC
+    u8"v",       // KeyV
+    u8"b",       // KeyB
+    u8"n",       // KeyN
+    u8"m",       // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShift[] = {
+    u8"~",       // BackQuote
+    u8"!",       // Digit1
+    u8"@",       // Digit2
+    u8"#",       // Digit3
+    u8"$",       // Digit4
+    u8"%",       // Digit5
+    u8"^",       // Digit6
+    u8"&",       // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"+",       // Equal
+    u8"Q",       // KeyQ
+    u8"W",       // KeyW
+    u8"E",       // KeyE
+    u8"R",       // KeyR
+    u8"T",       // KeyT
+    u8"Y",       // KeyY
+    u8"U",       // KeyU
+    u8"I",       // KeyI
+    u8"O",       // KeyO
+    u8"P",       // KeyP
+    u8"{",       // BracketLeft
+    u8"}",       // BracketRight
+    u8"|",       // Backslash
+    u8"A",       // KeyA
+    u8"S",       // KeyS
+    u8"D",       // KeyD
+    u8"F",       // KeyF
+    u8"G",       // KeyG
+    u8"H",       // KeyH
+    u8"J",       // KeyJ
+    u8"K",       // KeyK
+    u8"L",       // KeyL
+    u8":",       // Semicolon
+    u8"\"",      // Quote
+    u8"Z",       // KeyZ
+    u8"X",       // KeyX
+    u8"C",       // KeyC
+    u8"V",       // KeyV
+    u8"B",       // KeyB
+    u8"N",       // KeyN
+    u8"M",       // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kCapslock[] = {
+    u8"`",       // BackQuote
+    u8"1",       // Digit1
+    u8"2",       // Digit2
+    u8"3",       // Digit3
+    u8"4",       // Digit4
+    u8"5",       // Digit5
+    u8"6",       // Digit6
+    u8"7",       // Digit7
+    u8"8",       // Digit8
+    u8"9",       // Digit9
+    u8"0",       // Digit0
+    u8"-",       // Minus
+    u8"=",       // Equal
+    u8"Q",       // KeyQ
+    u8"W",       // KeyW
+    u8"E",       // KeyE
+    u8"R",       // KeyR
+    u8"T",       // KeyT
+    u8"Y",       // KeyY
+    u8"U",       // KeyU
+    u8"I",       // KeyI
+    u8"O",       // KeyO
+    u8"P",       // KeyP
+    u8"[",       // BracketLeft
+    u8"]",       // BracketRight
+    u8"\\",      // Backslash
+    u8"A",       // KeyA
+    u8"S",       // KeyS
+    u8"D",       // KeyD
+    u8"F",       // KeyF
+    u8"G",       // KeyG
+    u8"H",       // KeyH
+    u8"J",       // KeyJ
+    u8"K",       // KeyK
+    u8"L",       // KeyL
+    u8";",       // Semicolon
+    u8"'",       // Quote
+    u8"Z",       // KeyZ
+    u8"X",       // KeyX
+    u8"C",       // KeyC
+    u8"V",       // KeyV
+    u8"B",       // KeyB
+    u8"N",       // KeyN
+    u8"M",       // KeyM
+    u8",",       // Comma
+    u8".",       // Period
+    u8"/",       // Slash
+    u8"\u0020",  // Space
+};
+const char* kShiftCapslock[] = {
+    u8"~",       // BackQuote
+    u8"!",       // Digit1
+    u8"@",       // Digit2
+    u8"#",       // Digit3
+    u8"$",       // Digit4
+    u8"%",       // Digit5
+    u8"^",       // Digit6
+    u8"&",       // Digit7
+    u8"*",       // Digit8
+    u8"(",       // Digit9
+    u8")",       // Digit0
+    u8"_",       // Minus
+    u8"+",       // Equal
+    u8"q",       // KeyQ
+    u8"w",       // KeyW
+    u8"e",       // KeyE
+    u8"r",       // KeyR
+    u8"t",       // KeyT
+    u8"y",       // KeyY
+    u8"u",       // KeyU
+    u8"i",       // KeyI
+    u8"o",       // KeyO
+    u8"p",       // KeyP
+    u8"{",       // BracketLeft
+    u8"}",       // BracketRight
+    u8"|",       // Backslash
+    u8"a",       // KeyA
+    u8"s",       // KeyS
+    u8"d",       // KeyD
+    u8"f",       // KeyF
+    u8"g",       // KeyG
+    u8"h",       // KeyH
+    u8"j",       // KeyJ
+    u8"k",       // KeyK
+    u8"l",       // KeyL
+    u8":",       // Semicolon
+    u8"\"",      // Quote
+    u8"z",       // KeyZ
+    u8"x",       // KeyX
+    u8"c",       // KeyC
+    u8"v",       // KeyV
+    u8"b",       // KeyB
+    u8"n",       // KeyN
+    u8"m",       // KeyM
+    u8"<",       // Comma
+    u8">",       // Period
+    u8"?",       // Slash
+    u8"\u0020",  // Space
+};
+const char** kKeyMap[8] = {kNormal,   kShift,        kNormal,
+                           kShift,    kCapslock,     kShiftCapslock,
+                           kCapslock, kShiftCapslock};
+const char* kId = "us";
+const bool kIs102 = false;
+
+}  // namespace us
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/us.h b/chromeos/services/ime/public/cpp/rulebased/def/us.h
index 04762f50..aca3eec 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/us.h
+++ b/chromeos/services/ime/public/cpp/rulebased/def/us.h
@@ -5,20 +5,17 @@
 #ifndef CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_US_H_
 #define CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_US_H_
 
+namespace us {
+
 // The key mapping definitions under various modifier states for the US layout.
-extern const wchar_t* kKeyMapUs[];
-
-// The length of the key mapping definitions.
-extern const unsigned int kKeyMapUsLen;
-
-// The indexes pointed to the key mapping definition under certain modifier
-// state.
-extern const unsigned char kKeyMapIndexUs[8];
+extern const char** kKeyMap[8];
 
 // The Id for the US keyboard.
-extern const char* kIdUs;
+extern const char* kId;
 
 // Whether the US keyboard is 102 or 101 keyboard.
-extern const bool kIs102Us;
+extern const bool kIs102;
+
+}  // namespace us
 
 #endif  // CHROMEOS_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_US_H_
diff --git a/chromeos/services/ime/public/cpp/rulebased/rulebased_unittest.cc b/chromeos/services/ime/public/cpp/rulebased/rulebased_unittest.cc
index a13aa6fd..b85fb8e7 100644
--- a/chromeos/services/ime/public/cpp/rulebased/rulebased_unittest.cc
+++ b/chromeos/services/ime/public/cpp/rulebased/rulebased_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/stl_util.h"
-#include "base/strings/utf_string_conversions.h"
+#include "chromeos/services/ime/public/cpp/rulebased/def/us.h"
 #include "chromeos/services/ime/public/cpp/rulebased/engine.h"
 #include "chromeos/services/ime/public/cpp/rulebased/rules_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -16,7 +16,7 @@
 struct KeyVerifyEntry {
   const char* key;
   uint8_t modifiers;
-  const wchar_t* expected_str;
+  const char* expected_str;
 };
 
 }  // namespace
@@ -34,8 +34,7 @@
       rulebased::ProcessKeyResult res =
           engine_->ProcessKey(entry.key, entry.modifiers);
       EXPECT_TRUE(res.key_handled);
-      std::string expected_str = base::WideToUTF8(entry.expected_str);
-      EXPECT_EQ(expected_str, res.commit_text);
+      EXPECT_EQ(entry.expected_str, res.commit_text);
     }
   }
 
@@ -48,54 +47,46 @@
 TEST_F(RulebasedImeTest, Arabic) {
   engine_->Activate("ar");
   std::vector<KeyVerifyEntry> entries;
-  entries.push_back({"KeyA", rulebased::MODIFIER_SHIFT, L"\u0650"});
-  entries.push_back({"KeyB", 0, L"\u0644\u0627"});
-  entries.push_back({"Space", 0, L" "});
+  entries.push_back({"KeyA", rulebased::MODIFIER_SHIFT, u8"\u0650"});
+  entries.push_back({"KeyB", 0, u8"\u0644\u0627"});
+  entries.push_back({"Space", 0, " "});
   VerifyKeys(entries);
 }
 
 TEST_F(RulebasedImeTest, Persian) {
   engine_->Activate("fa");
   std::vector<KeyVerifyEntry> entries;
-  entries.push_back({"KeyA", 0, L"\u0634"});
-  entries.push_back({"KeyV", rulebased::MODIFIER_SHIFT, L""});
-  entries.push_back({"Space", rulebased::MODIFIER_SHIFT, L"\u200c"});
+  entries.push_back({"KeyA", 0, u8"\u0634"});
+  entries.push_back({"KeyV", rulebased::MODIFIER_SHIFT, ""});
+  entries.push_back({"Space", rulebased::MODIFIER_SHIFT, u8"\u200c"});
   VerifyKeys(entries);
 }
 
 TEST_F(RulebasedImeTest, Thai) {
   engine_->Activate("th");
   std::vector<KeyVerifyEntry> entries;
-  entries.push_back({"KeyA", 0, L"\u0e1f"});
-  entries.push_back({"KeyA", rulebased::MODIFIER_ALTGR, L""});
+  entries.push_back({"KeyA", 0, u8"\u0e1f"});
+  entries.push_back({"KeyA", rulebased::MODIFIER_ALTGR, ""});
   VerifyKeys(entries);
 
   engine_->Activate("th_pattajoti");
   entries.clear();
-  entries.push_back({"KeyA", 0, L"\u0e49"});
-  entries.push_back({"KeyB", rulebased::MODIFIER_SHIFT, L"\u0e31\u0e49"});
+  entries.push_back({"KeyA", 0, u8"\u0e49"});
+  entries.push_back({"KeyB", rulebased::MODIFIER_SHIFT, u8"\u0e31\u0e49"});
   VerifyKeys(entries);
 
   engine_->Activate("th_tis");
   entries.clear();
-  entries.push_back({"KeyA", 0, L"\u0e1f"});
-  entries.push_back({"KeyM", rulebased::MODIFIER_SHIFT, L"?"});
+  entries.push_back({"KeyA", 0, u8"\u0e1f"});
+  entries.push_back({"KeyM", rulebased::MODIFIER_SHIFT, u8"?"});
   VerifyKeys(entries);
 }
 
 TEST_F(RulebasedImeTest, Transforms) {
-  const wchar_t* key_map[] = {
-      L"`1234567890-="
-      L"qwertyuiop[]\\"
-      L"asdfghjkl;'"
-      L"zxcvbnm,./"
-      L"\u0020"};
-  const uint8_t key_map_index[8] = {0};
   const char* transforms[] = {
       u8"a", u8"x", u8"x\u001dAA", u8"X", u8"(\\w)(\\w)[<>]", u8"\\2\\1"};
-  auto data =
-      rulebased::RulesData::Create(key_map, 1, key_map_index, false, transforms,
-                                   base::size(transforms), nullptr);
+  auto data = rulebased::RulesData::Create(us::kKeyMap, false, transforms,
+                                           base::size(transforms), nullptr);
   std::string transformed;
   bool res = data->Transform("..", -1, "b", &transformed);
   EXPECT_FALSE(res);
@@ -132,45 +123,5 @@
   EXPECT_EQ(u8"..\u0915\u094c", transformed);
 }
 
-TEST_F(RulebasedImeTest, ParseKeyMap) {
-  // Empty.
-  rulebased::KeyMap key_map = rulebased::ParseKeyMapForTesting(L"", false);
-  EXPECT_TRUE(key_map.empty());
-
-  // Single char mapping.
-  key_map = rulebased::ParseKeyMapForTesting(L"abcde", false);
-  EXPECT_EQ(5UL, key_map.size());
-  EXPECT_EQ("a", key_map["BackQuote"]);
-  EXPECT_EQ("e", key_map["Digit4"]);
-
-  // Brackets for multiple chars.
-  key_map = rulebased::ParseKeyMapForTesting(L"ab{{cc}}de", false);
-  EXPECT_EQ(5UL, key_map.size());
-  EXPECT_EQ("a", key_map["BackQuote"]);
-  EXPECT_EQ("e", key_map["Digit4"]);
-  EXPECT_EQ("cc", key_map["Digit2"]);
-
-  key_map = rulebased::ParseKeyMapForTesting(L"ab((cc))de", false);
-  EXPECT_EQ(5UL, key_map.size());
-  EXPECT_EQ("a", key_map["BackQuote"]);
-  EXPECT_EQ("e", key_map["Digit4"]);
-  EXPECT_EQ("cc", key_map["Digit2"]);
-
-  // Brackets for empty.
-  key_map = rulebased::ParseKeyMapForTesting(L"ab{{}}de", false);
-  EXPECT_EQ(5UL, key_map.size());
-  EXPECT_EQ("a", key_map["BackQuote"]);
-  EXPECT_EQ("e", key_map["Digit4"]);
-  EXPECT_EQ("", key_map["Digit2"]);
-
-  // Incorrect brackets.
-  key_map = rulebased::ParseKeyMapForTesting(L"ab{{cc))de", false);
-  EXPECT_EQ(10UL, key_map.size());
-
-  // End with brackets.
-  key_map = rulebased::ParseKeyMapForTesting(L"abc{{", false);
-  EXPECT_EQ(5UL, key_map.size());
-}
-
 }  // namespace ime
 }  // namespace chromeos
diff --git a/chromeos/services/ime/public/cpp/rulebased/rules_data.cc b/chromeos/services/ime/public/cpp/rulebased/rules_data.cc
index 2d1c542..7473883 100644
--- a/chromeos/services/ime/public/cpp/rulebased/rules_data.cc
+++ b/chromeos/services/ime/public/cpp/rulebased/rules_data.cc
@@ -4,9 +4,7 @@
 
 #include "chromeos/services/ime/public/cpp/rulebased/rules_data.h"
 
-#include "base/logging.h"
 #include "base/stl_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "chromeos/services/ime/public/cpp/rulebased/def/ar.h"
 #include "chromeos/services/ime/public/cpp/rulebased/def/ckb_ar.h"
 #include "chromeos/services/ime/public/cpp/rulebased/def/ckb_en.h"
@@ -32,30 +30,21 @@
 namespace {
 
 struct RawDataEntry {
-  const wchar_t** key_map;
-  const uint8_t key_map_count;
-  const uint8_t* key_map_index;
+  const char*** key_map;
   bool is_102_keyboard;
   const char** transforms;
   const uint16_t transforms_count;
   const char* history_prune;
 
-  RawDataEntry(const wchar_t** map,
-               uint8_t map_count,
-               const uint8_t* map_index,
-               bool is_102)
-      : RawDataEntry(map, map_count, map_index, is_102, nullptr, 0, nullptr) {}
+  RawDataEntry(const char*** map, bool is_102)
+      : RawDataEntry(map, is_102, nullptr, 0, nullptr) {}
 
-  RawDataEntry(const wchar_t** map,
-               uint8_t map_count,
-               const uint8_t* map_index,
+  RawDataEntry(const char*** map,
                bool is_102,
                const char** trans,
                uint16_t trans_count,
                const char* prune)
       : key_map(map),
-        key_map_count(map_count),
-        key_map_index(map_index),
         is_102_keyboard(is_102),
         transforms(trans),
         transforms_count(trans_count),
@@ -63,69 +52,29 @@
 };
 
 static const std::map<std::string, RawDataEntry> kRawData = {
-    {id_ar, RawDataEntry(key_map_ar,
-                         base::size(key_map_ar),
-                         key_map_index_ar,
-                         is_102_ar)},
-    {id_ckb_ar, RawDataEntry(key_map_ckb_ar,
-                             base::size(key_map_ckb_ar),
-                             key_map_index_ckb_ar,
-                             is_102_ckb_ar)},
-    {id_ckb_en, RawDataEntry(key_map_ckb_en,
-                             base::size(key_map_ckb_en),
-                             key_map_index_ckb_en,
-                             is_102_ckb_en)},
-    {kIdDevaPhone, RawDataEntry(kKeyMapUs,
-                                kKeyMapUsLen,
-                                kKeyMapIndexUs,
-                                kIs102Us,
-                                kTransformsDevaPhone,
-                                kTransformsDevaPhoneLen,
-                                kHistoryPruneDevaPhone)},
-    {id_fa, RawDataEntry(key_map_fa,
-                         base::size(key_map_fa),
-                         key_map_index_fa,
-                         is_102_fa)},
-    {id_km, RawDataEntry(key_map_km,
-                         base::size(key_map_km),
-                         key_map_index_km,
-                         is_102_km)},
-    {id_lo, RawDataEntry(key_map_lo,
-                         base::size(key_map_lo),
-                         key_map_index_lo,
-                         is_102_lo)},
-    {id_ne_inscript, RawDataEntry(key_map_ne_inscript,
-                                  base::size(key_map_ne_inscript),
-                                  key_map_index_ne_inscript,
-                                  is_102_ne_inscript)},
-    {id_ru_phone_aatseel, RawDataEntry(key_map_ru_phone_aatseel,
-                                       base::size(key_map_ru_phone_aatseel),
-                                       key_map_index_ru_phone_aatseel,
-                                       is_102_ru_phone_aatseel)},
-    {id_ru_phone_yazhert, RawDataEntry(key_map_ru_phone_yazhert,
-                                       base::size(key_map_ru_phone_yazhert),
-                                       key_map_index_ru_phone_yazhert,
-                                       is_102_ru_phone_yazhert)},
-    {id_ta_inscript, RawDataEntry(key_map_ta_inscript,
-                                  base::size(key_map_ta_inscript),
-                                  key_map_index_ta_inscript,
-                                  is_102_ta_inscript)},
-    {id_ta_typewriter, RawDataEntry(key_map_ta_typewriter,
-                                    base::size(key_map_ta_typewriter),
-                                    key_map_index_ta_typewriter,
-                                    is_102_ta_typewriter)},
-    {id_th, RawDataEntry(key_map_th,
-                         base::size(key_map_th),
-                         key_map_index_th,
-                         is_102_th)},
-    {id_th_pattajoti, RawDataEntry(key_map_th_pattajoti,
-                                   base::size(key_map_th_pattajoti),
-                                   key_map_index_th_pattajoti,
-                                   is_102_th_pattajoti)},
-    {id_th_tis, RawDataEntry(key_map_th_tis,
-                             base::size(key_map_th_tis),
-                             key_map_index_th_tis,
-                             is_102_th_tis)}};
+    {ar::kId, RawDataEntry(ar::kKeyMap, ar::kIs102)},
+    {ckb_ar::kId, RawDataEntry(ckb_ar::kKeyMap, ckb_ar::kIs102)},
+    {ckb_en::kId, RawDataEntry(ckb_en::kKeyMap, ckb_en::kIs102)},
+    {deva_phone::kId, RawDataEntry(us::kKeyMap,
+                                   us::kIs102,
+                                   deva_phone::kTransforms,
+                                   deva_phone::kTransformsLen,
+                                   deva_phone::kHistoryPrune)},
+    {fa::kId, RawDataEntry(fa::kKeyMap, fa::kIs102)},
+    {km::kId, RawDataEntry(km::kKeyMap, km::kIs102)},
+    {lo::kId, RawDataEntry(lo::kKeyMap, lo::kIs102)},
+    {ne_inscript::kId, RawDataEntry(ne_inscript::kKeyMap, ne_inscript::kIs102)},
+    {ru_phone_aatseel::kId,
+     RawDataEntry(ru_phone_aatseel::kKeyMap, ru_phone_aatseel::kIs102)},
+    {ru_phone_yazhert::kId,
+     RawDataEntry(ru_phone_yazhert::kKeyMap, ru_phone_yazhert::kIs102)},
+    {ta_inscript::kId, RawDataEntry(ta_inscript::kKeyMap, ta_inscript::kIs102)},
+    {ta_typewriter::kId,
+     RawDataEntry(ta_typewriter::kKeyMap, ta_typewriter::kIs102)},
+    {th::kId, RawDataEntry(th::kKeyMap, th::kIs102)},
+    {th_pattajoti::kId,
+     RawDataEntry(th_pattajoti::kKeyMap, th_pattajoti::kIs102)},
+    {th_tis::kId, RawDataEntry(th_tis::kKeyMap, th_tis::kIs102)}};
 
 static const char* k101Keys[] = {
     // Row #1
@@ -159,52 +108,15 @@
     // Row #5
     "Space"};
 
-bool ScanBrackets(const wchar_t** pstr,
-                  wchar_t bracket_left,
-                  wchar_t bracket_right,
-                  std::string* str_out) {
-  const wchar_t* p = *pstr;
-  if (*p != bracket_left || *(p + 1) != bracket_left)
-    return false;
-  p += 2;
-  const wchar_t* from = p;
-  while (*p != L'\0') {
-    if (*p == bracket_right && *(p + 1) == bracket_right) {
-      base::WideToUTF8(from, p - from, str_out);
-      *pstr = p + 2;
-      return true;
-    }
-    ++p;
-  }
-  return false;
-}
+const static size_t kKeyMapCount = 8;
 
-// Parses the raw key map string and generate a KeyMap instance.
-// Each character in the raw key map string maps to a key on the keyboard 101 or
-// 102 layout with the same sequence of from top left to bottom right.
-// For example, the 1st character maps to the BackQuote key, the 2nd maps to the
-// Number1 key, and the last character maps to the Space key.
-// Please refer to the sequences defined by |k101Keys| and |k102Keys|.
-// If the definition wants to map multiple characters to one key, the double
-// brackets are used. e.g. "{{abc}}" or "((abc))".
-// The parsing supports both "{{}}" and "(())" to eliminate the ambiguities
-// where it wants to map the character "{", "}", "(", or ")" to a key.
-// e.g. "{{{abc}}..." is ambiguous and should be defined as "{((abc))..".
-KeyMap ParseKeyMap(const wchar_t* raw_key_map, bool is_102) {
+// Parses the raw key mappings and generate a KeyMap instance.
+KeyMap ParseKeyMap(const char** raw_key_map, bool is_102) {
   const char** std_keys = is_102 ? k102Keys : k101Keys;
+  size_t nkeys = is_102 ? base::size(k102Keys) : base::size(k101Keys);
   KeyMap key_map;
-  const wchar_t* p = raw_key_map;
-  uint8_t index = 0;
-  while (*p != L'\0') {
-    std::string str;
-    if (!ScanBrackets(&p, L'{', L'}', &str) &&
-        !ScanBrackets(&p, L'(', L')', &str)) {
-      base::WideToUTF8(p++, 1, &str);
-    }
-
-    DCHECK((is_102 && index < 49) || (!is_102 && index < 48));
-    key_map[std_keys[index++]] = str;
-  }
+  for (size_t i = 0; i < nkeys; ++i)
+    key_map[std_keys[i]] = raw_key_map[i];
   return key_map;
 }
 
@@ -254,32 +166,22 @@
 // The delimit inserted at the position of "transat".
 // The term "transat" means "was transformed at".
 // Please refer to some details in the |Transform| method.
-static const std::string kTransatDelimit = base::WideToUTF8(L"\u001D");
+static const char* kTransatDelimit = u8"\u001D";
 
 }  // namespace
-KeyMap ParseKeyMapForTesting(const wchar_t* raw_key_map, bool is_102) {
-  return ParseKeyMap(raw_key_map, is_102);
-}
 
 RulesData::RulesData() = default;
 RulesData::~RulesData() = default;
 
 // static
-std::unique_ptr<RulesData> RulesData::Create(const wchar_t** key_map,
-                                             const uint8_t key_map_count,
-                                             const uint8_t* key_map_index,
+std::unique_ptr<RulesData> RulesData::Create(const char*** key_map,
                                              bool is_102_keyboard,
                                              const char** transforms,
                                              const uint16_t transforms_count,
                                              const char* history_prune) {
   std::unique_ptr<RulesData> data = std::make_unique<RulesData>();
-  for (uint8_t i = 0; i < key_map_count; ++i)
-    data->key_map_cache_.push_back(ParseKeyMap(key_map[i], is_102_keyboard));
-
-  for (uint8_t i = 0; i < base::size(data->key_maps_); ++i) {
-    uint8_t index = key_map_index[i];
-    DCHECK(index < data->key_map_cache_.size());
-    data->key_maps_[i] = &(data->key_map_cache_[index]);
+  for (uint8_t i = 0; i < kKeyMapCount; ++i) {
+    data->key_maps_[i] = ParseKeyMap(key_map[i], is_102_keyboard);
   }
   data->transform_re_merged_ =
       ParseTransforms(transforms, transforms_count, data->transform_rules_);
@@ -294,9 +196,8 @@
     return nullptr;
 
   const RawDataEntry& entry = it->second;
-  return Create(entry.key_map, entry.key_map_count, entry.key_map_index,
-                entry.is_102_keyboard, entry.transforms, entry.transforms_count,
-                entry.history_prune);
+  return Create(entry.key_map, entry.is_102_keyboard, entry.transforms,
+                entry.transforms_count, entry.history_prune);
 }
 
 // static
@@ -305,7 +206,7 @@
 }
 
 const KeyMap* RulesData::GetKeyMapByModifiers(uint8_t modifiers) const {
-  return modifiers < 8 ? key_maps_[modifiers] : nullptr;
+  return modifiers < 8 ? &key_maps_[modifiers] : nullptr;
 }
 
 bool RulesData::Transform(const std::string& context,
diff --git a/chromeos/services/ime/public/cpp/rulebased/rules_data.h b/chromeos/services/ime/public/cpp/rulebased/rules_data.h
index 8b77975..b898ee3 100644
--- a/chromeos/services/ime/public/cpp/rulebased/rules_data.h
+++ b/chromeos/services/ime/public/cpp/rulebased/rules_data.h
@@ -19,21 +19,17 @@
 namespace ime {
 namespace rulebased {
 
-using KeyMap = std::map<std::string, std::string>;
+using KeyMap = std::map<std::string, const char*>;
 
 using TransformRule = std::pair<std::unique_ptr<re2::RE2>, std::string>;
 
-KeyMap ParseKeyMapForTesting(const wchar_t* raw_key_map, bool is_102);
-
 class RulesData {
  public:
   RulesData();
   ~RulesData();
 
   // Creates the RulesData by the given raw data.
-  static std::unique_ptr<RulesData> Create(const wchar_t** key_map,
-                                           const uint8_t key_map_count,
-                                           const uint8_t* key_map_index,
+  static std::unique_ptr<RulesData> Create(const char*** key_map,
                                            bool is_102_keyboard,
                                            const char** transforms,
                                            const uint16_t transforms_count,
@@ -63,11 +59,8 @@
   const re2::RE2* history_prune_re() const { return history_prune_re_.get(); }
 
  private:
-  // All possible KeyMap instances under various modifier states.
-  std::vector<KeyMap> key_map_cache_;
-
-  // The map from the modifier state to the KeyMap instance.
-  const KeyMap* key_maps_[8] = {0};
+  // The KeyMap instances under all the modifier states.
+  KeyMap key_maps_[8];
 
   // The map from the sub group match index (of the merged regexp) to the
   // transform rule (which is a pair of matching regexp, and replace string).
diff --git a/components/autofill_assistant/browser/actions/focus_element_action.cc b/components/autofill_assistant/browser/actions/focus_element_action.cc
index 593f8dcf..01b4994 100644
--- a/components/autofill_assistant/browser/actions/focus_element_action.cc
+++ b/components/autofill_assistant/browser/actions/focus_element_action.cc
@@ -16,7 +16,6 @@
 FocusElementAction::FocusElementAction(const ActionProto& proto)
     : Action(proto), weak_ptr_factory_(this) {
   DCHECK(proto_.has_focus_element());
-  show_overlay_ = false;
 }
 
 FocusElementAction::~FocusElementAction() {}
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc
index aac823d..9ca1fb80 100644
--- a/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -363,51 +363,5 @@
   executor_->Run(executor_callback_.Get());
 }
 
-TEST_F(ScriptExecutorTest, HideOverlay) {
-  ActionsResponseProto actions_response;
-  actions_response.set_server_payload("payload");
-  actions_response.add_actions()->mutable_tell()->set_message("1");
-  // focus_element hides the overlay
-  actions_response.add_actions()
-      ->mutable_focus_element()
-      ->mutable_element()
-      ->add_selectors("exists");
-
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _))
-      .WillOnce(RunOnceCallback<2>(true, Serialize(actions_response)));
-
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _))
-      .WillOnce(RunOnceCallback<2>(true, ""));
-
-  EXPECT_CALL(executor_callback_, Run(_));
-
-  overlay_ = true;
-  executor_->Run(executor_callback_.Get());
-  ASSERT_FALSE(overlay_);
-}
-
-TEST_F(ScriptExecutorTest, ShowOverlayAgainAfterHiding) {
-  ActionsResponseProto actions_response;
-  actions_response.set_server_payload("payload");
-  actions_response.add_actions()
-      ->mutable_focus_element()
-      ->mutable_element()
-      ->add_selectors("exists");
-  // tell shows the overlay again, after it's been hidden by focus_element
-  actions_response.add_actions()->mutable_tell()->set_message("1");
-
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _))
-      .WillOnce(RunOnceCallback<2>(true, Serialize(actions_response)));
-
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _))
-      .WillOnce(RunOnceCallback<2>(true, ""));
-
-  EXPECT_CALL(executor_callback_, Run(_));
-
-  overlay_ = true;
-  executor_->Run(executor_callback_.Get());
-  ASSERT_TRUE(overlay_);
-}
-
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/browser_sync/profile_sync_service_startup_unittest.cc b/components/browser_sync/profile_sync_service_startup_unittest.cc
index cfc838b1..4948c179 100644
--- a/components/browser_sync/profile_sync_service_startup_unittest.cc
+++ b/components/browser_sync/profile_sync_service_startup_unittest.cc
@@ -15,7 +15,7 @@
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/engine/fake_sync_engine.h"
 #include "components/sync/engine/mock_sync_engine.h"
-#include "services/identity/public/cpp/identity_test_utils.h"
+#include "services/identity/public/cpp/identity_test_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -65,8 +65,8 @@
       : scoped_task_environment_(
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
         sync_prefs_(profile_sync_service_bundle_.pref_service()) {
-    profile_sync_service_bundle_.auth_service()
-        ->set_auto_post_fetch_response_on_message_loop(true);
+    profile_sync_service_bundle_.identity_test_env()
+        ->SetAutomaticIssueOfAccessTokens(true);
   }
 
   ~ProfileSyncServiceStartupTest() override {
@@ -97,23 +97,18 @@
   }
 
   void SimulateTestUserSignin() {
-    identity::MakePrimaryAccountAvailable(
-        profile_sync_service_bundle_.signin_manager(),
-        profile_sync_service_bundle_.auth_service(),
-        profile_sync_service_bundle_.identity_manager(), kEmail);
+    profile_sync_service_bundle_.identity_test_env()
+        ->MakePrimaryAccountAvailable(kEmail);
   }
 
   void SimulateTestUserSigninWithoutRefreshToken() {
     // Set the primary account *without* providing an OAuth token.
-    identity::SetPrimaryAccount(profile_sync_service_bundle_.signin_manager(),
-                                profile_sync_service_bundle_.identity_manager(),
-                                kEmail);
+    profile_sync_service_bundle_.identity_test_env()->SetPrimaryAccount(kEmail);
   }
 
   void UpdateCredentials() {
-    identity::SetRefreshTokenForPrimaryAccount(
-        profile_sync_service_bundle_.auth_service(),
-        profile_sync_service_bundle_.identity_manager());
+    profile_sync_service_bundle_.identity_test_env()
+        ->SetRefreshTokenForPrimaryAccount();
   }
 
   DataTypeManagerMock* SetUpDataTypeManagerMock() {
diff --git a/components/browser_sync/profile_sync_service_unittest.cc b/components/browser_sync/profile_sync_service_unittest.cc
index 17aabef54..e58e6f4a6 100644
--- a/components/browser_sync/profile_sync_service_unittest.cc
+++ b/components/browser_sync/profile_sync_service_unittest.cc
@@ -16,7 +16,6 @@
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/browser_sync/profile_sync_test_util.h"
 #include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/driver/configure_context.h"
 #include "components/sync/driver/fake_data_type_controller.h"
@@ -28,8 +27,7 @@
 #include "components/sync/engine/fake_sync_engine.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/version_info/version_info_values.h"
-#include "google_apis/gaia/oauth2_token_service_delegate.h"
-#include "services/identity/public/cpp/identity_test_utils.h"
+#include "services/identity/public/cpp/identity_test_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -182,9 +180,7 @@
   }
 
   void SignIn() {
-    identity::MakePrimaryAccountAvailable(signin_manager(), auth_service(),
-                                          identity_manager(),
-                                          "test_user@gmail.com");
+    identity_test_env()->MakePrimaryAccountAvailable("test_user@gmail.com");
   }
 
   void CreateService(ProfileSyncService::StartBehavior behavior) {
@@ -300,24 +296,14 @@
     return profile_sync_service_bundle_.account_tracker();
   }
 
-#if defined(OS_CHROMEOS)
-  FakeSigninManagerBase* signin_manager()
-#else
-  FakeSigninManager* signin_manager()
-#endif
-  // Opening brace is outside of macro to avoid confusing lint.
-  {
-    return profile_sync_service_bundle_.signin_manager();
-  }
-
-  FakeProfileOAuth2TokenService* auth_service() {
-    return profile_sync_service_bundle_.auth_service();
-  }
-
   identity::IdentityManager* identity_manager() {
     return profile_sync_service_bundle_.identity_manager();
   }
 
+  identity::IdentityTestEnvironment* identity_test_env() {
+    return profile_sync_service_bundle_.identity_test_env();
+  }
+
   ProfileSyncService* service() { return service_.get(); }
 
   sync_preferences::TestingPrefServiceSyncable* prefs() {
@@ -705,7 +691,7 @@
             service()->GetDisableReasons());
   EXPECT_EQ(syncer::SyncService::TransportState::ACTIVE,
             service()->GetTransportState());
-  EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
+  EXPECT_EQ(identity_manager()->GetPrimaryAccountId(),
             identity_provider()->GetActiveAccountId());
 
   identity_manager()->ClearPrimaryAccount(
@@ -720,10 +706,8 @@
             service()->GetTransportState());
   EXPECT_EQ("", identity_provider()->GetActiveAccountId());
 
-  identity::MakePrimaryAccountAvailable(signin_manager(), auth_service(),
-                                        identity_manager(),
-                                        "new_user@gmail.com");
-  EXPECT_EQ(signin_manager()->GetAuthenticatedAccountId(),
+  identity_test_env()->MakePrimaryAccountAvailable("new_user@gmail.com");
+  EXPECT_EQ(identity_manager()->GetPrimaryAccountId(),
             identity_provider()->GetActiveAccountId());
 }
 #endif  // !defined(OS_CHROMEOS)
@@ -796,12 +780,11 @@
   std::string secondary_account_name = "test_user2@gmail.com";
   std::string secondary_account_id = account_tracker()->SeedAccountInfo(
       secondary_account_gaiaid, secondary_account_name);
-  auth_service()->UpdateCredentials(secondary_account_id,
-                                    "second_account_refresh_token");
-  auth_service()->RevokeCredentials(secondary_account_id);
+  identity_test_env()->SetRefreshTokenForAccount(secondary_account_id);
+  identity_test_env()->RemoveRefreshTokenForAccount(secondary_account_id);
   EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
 
-  auth_service()->RevokeCredentials(primary_account_id);
+  identity_test_env()->RemoveRefreshTokenForPrimaryAccount();
   EXPECT_TRUE(service()->GetAccessTokenForTest().empty());
 }
 
@@ -848,14 +831,15 @@
 
   // Simulate the credentials getting locally rejected by the client by setting
   // the refresh token to a special invalid value.
-  auth_service()->UpdateCredentials(
-      primary_account_id, OAuth2TokenServiceDelegate::kInvalidRefreshToken);
+  identity_test_env()->SetInvalidRefreshTokenForPrimaryAccount();
   GoogleServiceAuthError rejected_by_client =
       GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
           GoogleServiceAuthError::InvalidGaiaCredentialsReason::
               CREDENTIALS_REJECTED_BY_CLIENT);
   ASSERT_EQ(rejected_by_client,
-            auth_service()->GetAuthError(primary_account_id));
+            identity_test_env()
+                ->identity_manager()
+                ->GetErrorStateOfRefreshTokenForAccount(primary_account_id));
   EXPECT_TRUE(service()->GetAccessTokenForTest().empty());
   EXPECT_TRUE(invalidate_credentials_called);
 
@@ -958,7 +942,7 @@
 TEST_F(ProfileSyncServiceTest, CredentialErrorReturned) {
   // This test needs to manually send access tokens (or errors), so disable
   // automatic replies to access token requests.
-  auth_service()->set_auto_post_fetch_response_on_message_loop(false);
+  identity_test_env()->SetAutomaticIssueOfAccessTokens(false);
 
   syncer::SyncCredentials init_credentials;
 
@@ -991,17 +975,17 @@
 
   // Wait for ProfileSyncService to send an access token request.
   base::RunLoop().RunUntilIdle();
-  auth_service()->IssueAllTokensForAccount(primary_account_id, "access token",
-                                           base::Time::Max());
+  identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+      primary_account_id, "access token", base::Time::Max());
   ASSERT_FALSE(service()->GetAccessTokenForTest().empty());
   ASSERT_EQ(GoogleServiceAuthError::NONE, service()->GetAuthError().state());
 
   // Emulate Chrome receiving a new, invalid LST. This happens when the user
   // signs out of the content area.
-  auth_service()->UpdateCredentials(primary_account_id, "not a valid token");
+  identity_test_env()->SetRefreshTokenForPrimaryAccount();
   // Again, wait for ProfileSyncService to be notified.
   base::RunLoop().RunUntilIdle();
-  auth_service()->IssueErrorForAllPendingRequests(
+  identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
       GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
 
   // Check that the invalid token is returned from sync.
@@ -1021,7 +1005,7 @@
 TEST_F(ProfileSyncServiceTest, CredentialErrorClearsOnNewToken) {
   // This test needs to manually send access tokens (or errors), so disable
   // automatic replies to access token requests.
-  auth_service()->set_auto_post_fetch_response_on_message_loop(false);
+  identity_test_env()->SetAutomaticIssueOfAccessTokens(false);
 
   syncer::SyncCredentials init_credentials;
 
@@ -1054,18 +1038,18 @@
 
   // Wait for ProfileSyncService to send an access token request.
   base::RunLoop().RunUntilIdle();
-  auth_service()->IssueAllTokensForAccount(primary_account_id, "access token",
-                                           base::Time::Max());
+  identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+      primary_account_id, "access token", base::Time::Max());
   ASSERT_FALSE(service()->GetAccessTokenForTest().empty());
   ASSERT_EQ(GoogleServiceAuthError::NONE, service()->GetAuthError().state());
 
   // Emulate Chrome receiving a new, invalid LST. This happens when the user
   // signs out of the content area.
-  auth_service()->UpdateCredentials(primary_account_id, "not a valid token");
+  identity_test_env()->SetRefreshTokenForPrimaryAccount();
   // Wait for ProfileSyncService to be notified of the changed credentials and
   // send a new access token request.
   base::RunLoop().RunUntilIdle();
-  auth_service()->IssueErrorForAllPendingRequests(
+  identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
       GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
 
   // Check that the invalid token is returned from sync.
@@ -1076,10 +1060,10 @@
             service()->GetTransportState());
 
   // Now emulate Chrome receiving a new, valid LST.
-  auth_service()->UpdateCredentials(primary_account_id, "totally valid token");
+  identity_test_env()->SetRefreshTokenForPrimaryAccount();
   // Again, wait for ProfileSyncService to be notified.
   base::RunLoop().RunUntilIdle();
-  auth_service()->IssueTokenForAllPendingRequests(
+  identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "this one works", base::Time::Now() + base::TimeDelta::FromDays(10));
 
   // Check that sync auth error state cleared.
diff --git a/components/error_page/common/localized_error.cc b/components/error_page/common/localized_error.cc
index f7b6cd2..8253826 100644
--- a/components/error_page/common/localized_error.cc
+++ b/components/error_page/common/localized_error.cc
@@ -874,6 +874,7 @@
     bool can_show_network_diagnostics_dialog,
     bool is_incognito,
     OfflineContentOnNetErrorFeatureState offline_content_feature_state,
+    bool auto_fetch_feature_enabled,
     const std::string& locale,
     std::unique_ptr<error_page::ErrorPageParams> params,
     base::DictionaryValue* error_strings) {
@@ -1082,6 +1083,11 @@
       "closeDescriptionPopup",
       l10n_util::GetStringUTF16(IDS_ERRORPAGES_SUGGESTION_CLOSE_POPUP_BUTTON));
 
+  if (auto_fetch_feature_enabled && IsOfflineError(error_domain, error_code) &&
+      !is_incognito) {
+    error_strings->SetString("attemptAutoFetch", "true");
+  }
+
   if (IsOfflineError(error_domain, error_code) && !is_incognito) {
     switch (offline_content_feature_state) {
       case OfflineContentOnNetErrorFeatureState::kDisabled:
diff --git a/components/error_page/common/localized_error.h b/components/error_page/common/localized_error.h
index 6639e4477..4ff32316 100644
--- a/components/error_page/common/localized_error.h
+++ b/components/error_page/common/localized_error.h
@@ -39,6 +39,7 @@
       bool can_show_network_diagnostics_dialog,
       bool is_incognito,
       OfflineContentOnNetErrorFeatureState offline_content_feature_state,
+      bool auto_fetch_feature_enabled,
       const std::string& locale,
       std::unique_ptr<error_page::ErrorPageParams> params,
       base::DictionaryValue* strings);
diff --git a/components/invalidation/OWNERS b/components/invalidation/OWNERS
index 7f08e5f..7a57abd 100644
--- a/components/invalidation/OWNERS
+++ b/components/invalidation/OWNERS
@@ -1,5 +1,6 @@
 dcheng@chromium.org
 nyquist@chromium.org
 pavely@chromium.org
+melandory@chromium.org
 
 # COMPONENT: Services>Invalidation
diff --git a/components/neterror/resources/neterror.js b/components/neterror/resources/neterror.js
index 3d7682a3..df76f57 100644
--- a/components/neterror/resources/neterror.js
+++ b/components/neterror/resources/neterror.js
@@ -159,6 +159,10 @@
 primaryControlOnLeft = false;
 // </if>
 
+// TODO(crbug.com/883486): UI not yet implemented.
+function setAutoFetchState(scheduled, can_schedule) {
+}
+
 function toggleErrorInformationPopup() {
   document.getElementById('error-information-popup-container')
       .classList.toggle(HIDDEN_CLASS);
diff --git a/components/offline_pages/core/model/offline_page_model_utils.cc b/components/offline_pages/core/model/offline_page_model_utils.cc
index f6829d14d..6785f1a 100644
--- a/components/offline_pages/core/model/offline_page_model_utils.cc
+++ b/components/offline_pages/core/model/offline_page_model_utils.cc
@@ -43,6 +43,8 @@
     return OfflinePagesNamespaceEnumeration::BROWSER_ACTIONS;
   else if (name_space == kLivePageSharingNamespace)
     return OfflinePagesNamespaceEnumeration::LIVE_PAGE_SHARING;
+  else if (name_space == kAutoAsyncNamespace)
+    return OfflinePagesNamespaceEnumeration::ASYNC_AUTO_LOADING;
 
   NOTREACHED();
   return OfflinePagesNamespaceEnumeration::DEFAULT;
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index b81e20d..667f37e 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -77,8 +77,9 @@
 
 // Histogram name which counts the number of times the user enters
 // keyword hint mode and via what method.  The possible values are listed
-// in the KeywordModeEntryMethod enum which is defined in the .h file.
-const char kEnteredKeywordModeHistogram[] = "Omnibox.EnteredKeywordMode";
+// in the metrics OmniboxEnteredKeywordMode2 enum which is defined in metrics
+// enum XML file.
+const char kEnteredKeywordModeHistogram[] = "Omnibox.EnteredKeywordMode2";
 
 // Histogram name which counts the number of milliseconds a user takes
 // between focusing and editing the omnibox.
@@ -89,19 +90,27 @@
 const char kFocusToOpenTimeHistogram[] =
     "Omnibox.FocusToOpenTimeAnyPopupState3";
 
+void EmitKeywordHistogram(
+    OmniboxEventProto::KeywordModeEntryMethod entry_method) {
+  UMA_HISTOGRAM_ENUMERATION(
+      kEnteredKeywordModeHistogram, static_cast<int>(entry_method),
+      static_cast<int>(OmniboxEventProto::KeywordModeEntryMethod_MAX + 1));
+}
+
 }  // namespace
 
 
 // OmniboxEditModel::State ----------------------------------------------------
 
-OmniboxEditModel::State::State(bool user_input_in_progress,
-                               const base::string16& user_text,
-                               const base::string16& keyword,
-                               bool is_keyword_hint,
-                               KeywordModeEntryMethod keyword_mode_entry_method,
-                               OmniboxFocusState focus_state,
-                               FocusSource focus_source,
-                               const AutocompleteInput& autocomplete_input)
+OmniboxEditModel::State::State(
+    bool user_input_in_progress,
+    const base::string16& user_text,
+    const base::string16& keyword,
+    bool is_keyword_hint,
+    OmniboxEventProto::KeywordModeEntryMethod keyword_mode_entry_method,
+    OmniboxFocusState focus_state,
+    FocusSource focus_source,
+    const AutocompleteInput& autocomplete_input)
     : user_input_in_progress(user_input_in_progress),
       user_text(user_text),
       keyword(keyword),
@@ -109,8 +118,7 @@
       keyword_mode_entry_method(keyword_mode_entry_method),
       focus_state(focus_state),
       focus_source(focus_source),
-      autocomplete_input(autocomplete_input) {
-}
+      autocomplete_input(autocomplete_input) {}
 
 OmniboxEditModel::State::State(const State& other) = default;
 
@@ -135,6 +143,7 @@
       paste_state_(NONE),
       control_key_state_(UP),
       is_keyword_hint_(false),
+      keyword_mode_entry_method_(OmniboxEventProto::INVALID),
       in_revert_(false),
       allow_exact_keyword_match_(false) {
   omnibox_controller_.reset(new OmniboxController(this, client_.get()));
@@ -277,6 +286,7 @@
   SetInputInProgress(true);
   keyword_.clear();
   is_keyword_hint_ = false;
+  keyword_mode_entry_method_ = OmniboxEventProto::INVALID;
   InternalSetUserText(text);
   omnibox_controller_->InvalidateCurrentMatch();
   paste_state_ = NONE;
@@ -441,6 +451,7 @@
   InternalSetUserText(base::string16());
   keyword_.clear();
   is_keyword_hint_ = false;
+  keyword_mode_entry_method_ = OmniboxEventProto::INVALID;
   has_temporary_text_ = false;
   size_t start, end;
   view_->GetSelectionBounds(&start, &end);
@@ -604,7 +615,7 @@
 }
 
 void OmniboxEditModel::EnterKeywordModeForDefaultSearchProvider(
-    KeywordModeEntryMethod entry_method) {
+    OmniboxEventProto::KeywordModeEntryMethod entry_method) {
   if (!client_->IsDefaultSearchProviderEnabled())
     return;
 
@@ -618,19 +629,17 @@
   base::string16 display_text =
       user_input_in_progress_ ? view_->GetText() : base::string16();
   size_t caret_pos = display_text.length();
-  if (entry_method == KeywordModeEntryMethod::QUESTION_MARK) {
+  if (entry_method == OmniboxEventProto::QUESTION_MARK) {
     display_text.erase(0, 1);
     caret_pos = 0;
   }
 
   InternalSetUserText(display_text);
   view_->SetWindowTextAndCaretPos(display_text, caret_pos, true, false);
-  if (entry_method == KeywordModeEntryMethod::KEYBOARD_SHORTCUT)
+  if (entry_method == OmniboxEventProto::KEYBOARD_SHORTCUT)
     view_->SelectAll(false);
 
-  UMA_HISTOGRAM_ENUMERATION(
-      kEnteredKeywordModeHistogram, static_cast<int>(entry_method),
-      static_cast<int>(KeywordModeEntryMethod::NUM_ITEMS));
+  EmitKeywordHistogram(entry_method);
 }
 
 void OmniboxEditModel::OpenMatch(AutocompleteMatch match,
@@ -820,7 +829,7 @@
 }
 
 bool OmniboxEditModel::AcceptKeyword(
-      KeywordModeEntryMethod entry_method) {
+    OmniboxEventProto::KeywordModeEntryMethod entry_method) {
   DCHECK(is_keyword_hint_ && !keyword_.empty());
 
   autocomplete_controller()->Stop(false);
@@ -851,7 +860,7 @@
   // here, may have generated a new match, which the user won't actually see and
   // which we don't want to switch back to when exiting keyword mode; see
   // comments in ClearKeyword().
-  if (entry_method == KeywordModeEntryMethod::TAB) {
+  if (entry_method == OmniboxEventProto::TAB) {
     // Ensure the current selection is saved before showing keyword mode
     // so that moving to another line and then reverting the text will restore
     // the current state properly.
@@ -867,9 +876,7 @@
   }
 
   base::RecordAction(base::UserMetricsAction("AcceptedKeywordHint"));
-  UMA_HISTOGRAM_ENUMERATION(
-      kEnteredKeywordModeHistogram, static_cast<int>(entry_method),
-      static_cast<int>(KeywordModeEntryMethod::NUM_ITEMS));
+  EmitKeywordHistogram(entry_method);
 
   return true;
 }
@@ -937,6 +944,7 @@
   if (was_toggled_into_keyword_mode && has_temporary_text_) {
     // State 4 above.
     is_keyword_hint_ = true;
+    keyword_mode_entry_method_ = OmniboxEventProto::INVALID;
     const base::string16 window_text = keyword_ + view_->GetText();
     view_->SetWindowTextAndCaretPos(window_text, keyword_.length(), false,
                                     true);
@@ -960,14 +968,14 @@
     // keyword.  Instead, restore the question mark iff the user originally
     // typed one.
     base::string16 prefix;
-    if (keyword_mode_entry_method_ == KeywordModeEntryMethod::QUESTION_MARK)
+    if (keyword_mode_entry_method_ == OmniboxEventProto::QUESTION_MARK)
       prefix = base::ASCIIToUTF16("?");
-    else if (keyword_mode_entry_method_ !=
-             KeywordModeEntryMethod::KEYBOARD_SHORTCUT)
+    else if (keyword_mode_entry_method_ != OmniboxEventProto::KEYBOARD_SHORTCUT)
       prefix = keyword_ + base::ASCIIToUTF16(" ");
 
     keyword_.clear();
     is_keyword_hint_ = false;
+    keyword_mode_entry_method_ = OmniboxEventProto::INVALID;
 
     view_->SetWindowTextAndCaretPos(prefix + view_->GetText(), prefix.length(),
                                     false, false);
@@ -1142,6 +1150,13 @@
     if (!keyword_was_selected && is_keyword_selected()) {
       // We just entered keyword mode, so remove the keyword from the input.
       user_text_ = MaybeStripKeyword(user_text_);
+      // Since we entered keyword mode, record the reason. Note that we
+      // don't do this simply because the keyword changes, since the user
+      // never left keyword mode.
+      keyword_mode_entry_method_ = OmniboxEventProto::SELECT_SUGGESTION;
+    } else if (!is_keyword_selected()) {
+      // We've left keyword mode, so align the entry method field with that.
+      keyword_mode_entry_method_ = OmniboxEventProto::INVALID;
     }
 
     // |is_keyword_hint_| should always be false if |keyword_| is empty.
@@ -1299,11 +1314,8 @@
           *state_changes.old_text, user_text_, state_changes.new_sel_start);
   view_->UpdatePopup();
   if (allow_exact_keyword_match_) {
-    keyword_mode_entry_method_ = KeywordModeEntryMethod::SPACE_IN_MIDDLE;
-    UMA_HISTOGRAM_ENUMERATION(
-        kEnteredKeywordModeHistogram,
-        static_cast<int>(KeywordModeEntryMethod::SPACE_IN_MIDDLE),
-        static_cast<int>(KeywordModeEntryMethod::NUM_ITEMS));
+    keyword_mode_entry_method_ = OmniboxEventProto::SPACE_IN_MIDDLE;
+    EmitKeywordHistogram(OmniboxEventProto::SPACE_IN_MIDDLE);
     allow_exact_keyword_match_ = false;
   }
 
@@ -1315,8 +1327,7 @@
   // If the user input a "?" at the beginning of the text, put them into
   // keyword mode for their default search provider.
   if ((state_changes.new_sel_start == 1) && (user_text_[0] == '?')) {
-    EnterKeywordModeForDefaultSearchProvider(
-        KeywordModeEntryMethod::QUESTION_MARK);
+    EnterKeywordModeForDefaultSearchProvider(OmniboxEventProto::QUESTION_MARK);
     return false;
   }
 
@@ -1455,7 +1466,7 @@
   return is_keyword_hint_ && (keyword_.length() == keyword_length) &&
          IsSpaceCharForAcceptingKeyword(new_text[keyword_length]) &&
          !new_text.compare(0, keyword_length, keyword_, 0, keyword_length) &&
-         AcceptKeyword(KeywordModeEntryMethod::SPACE_AT_END);
+         AcceptKeyword(OmniboxEventProto::SPACE_AT_END);
 }
 
 bool OmniboxEditModel::CreatedKeywordSearchByInsertingSpaceInMiddle(
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h
index 2891bbb..9284900 100644
--- a/components/omnibox/browser/omnibox_edit_model.h
+++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -35,19 +35,6 @@
 class Image;
 }
 
-// Reasons why the Omnibox could change into keyword mode.
-// These numeric values are used in UMA logs; do not change them.
-enum class KeywordModeEntryMethod {
-  TAB = 0,
-  SPACE_AT_END = 1,
-  SPACE_IN_MIDDLE = 2,
-  KEYBOARD_SHORTCUT = 3,
-  QUESTION_MARK = 4,
-  CLICK_ON_VIEW = 5,
-  TAP_ON_VIEW = 6,
-  NUM_ITEMS,
-};
-
 class OmniboxEditModel {
  public:
   // Did the Omnibox focus originate via the user clicking on the Omnibox, on
@@ -64,7 +51,8 @@
           const base::string16& user_text,
           const base::string16& keyword,
           bool is_keyword_hint,
-          KeywordModeEntryMethod keyword_mode_entry_method,
+          metrics::OmniboxEventProto::KeywordModeEntryMethod
+              keyword_mode_entry_method,
           OmniboxFocusState focus_state,
           FocusSource focus_source,
           const AutocompleteInput& autocomplete_input);
@@ -75,7 +63,8 @@
     const base::string16 user_text;
     const base::string16 keyword;
     const bool is_keyword_hint;
-    KeywordModeEntryMethod keyword_mode_entry_method;
+    metrics::OmniboxEventProto::KeywordModeEntryMethod
+        keyword_mode_entry_method;
     OmniboxFocusState focus_state;
     FocusSource focus_source;
     const AutocompleteInput autocomplete_input;
@@ -264,16 +253,17 @@
   }
 
   // Accepts the current keyword hint as a keyword. It always returns true for
-  // caller convenience. |entered_method| indicates how the user entered
+  // caller convenience. |entry_method| indicates how the user entered
   // keyword mode.
-  bool AcceptKeyword(KeywordModeEntryMethod entry_method);
+  bool AcceptKeyword(
+      metrics::OmniboxEventProto::KeywordModeEntryMethod entry_method);
 
   // Sets the current keyword to that of the user's default search provider and
   // updates the view so the user sees the keyword chip in the omnibox.  Adjusts
   // user_text_ and the selection based on the display text and the keyword
   // entry method.
   void EnterKeywordModeForDefaultSearchProvider(
-      KeywordModeEntryMethod entry_method);
+      metrics::OmniboxEventProto::KeywordModeEntryMethod entry_method);
 
   // Accepts the current temporary text as the user text.
   void AcceptTemporaryTextAsUserText();
@@ -606,9 +596,9 @@
   bool is_keyword_hint_;
 
   // Indicates how the user entered keyword mode if the user is actually in
-  // keyword mode.  Otherwise, the value of this variable is undefined.  This
+  // keyword mode.  Otherwise, the value of this variable is INVALID.  This
   // is used to restore the user's search terms upon a call to ClearKeyword().
-  KeywordModeEntryMethod keyword_mode_entry_method_;
+  metrics::OmniboxEventProto::KeywordModeEntryMethod keyword_mode_entry_method_;
 
   // This is needed to properly update the SearchModel state when the user
   // presses escape.
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc
index ae7967f..46cd204 100644
--- a/components/omnibox/browser/omnibox_edit_model_unittest.cc
+++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -22,6 +22,9 @@
 #include "components/omnibox/browser/test_omnibox_edit_model.h"
 #include "components/omnibox/browser/test_omnibox_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/metrics_proto/omnibox_event.pb.h"
+
+using metrics::OmniboxEventProto;
 
 class OmniboxEditModelTest : public testing::Test {
  public:
@@ -411,14 +414,13 @@
   // Entering keyword search mode should preserve the full display text as the
   // user text, and select all.
   model()->EnterKeywordModeForDefaultSearchProvider(
-      KeywordModeEntryMethod::KEYBOARD_SHORTCUT);
+      OmniboxEventProto::KEYBOARD_SHORTCUT);
   EXPECT_EQ(base::UTF8ToUTF16("user text"), model()->GetUserTextForTesting());
   EXPECT_EQ(base::UTF8ToUTF16("user text"), view()->GetText());
   EXPECT_TRUE(view()->IsSelectAll());
 
-  // Deleting the user text and exiting keyword mode should clear everything.
+  // Deleting the user text (exiting keyword) mode should clear everything.
   view()->SetUserText(base::string16());
-  model()->ClearKeyword();
   {
     EXPECT_TRUE(view()->GetText().empty());
     EXPECT_TRUE(model()->GetUserTextForTesting().empty());
@@ -441,7 +443,7 @@
   // Entering keyword search mode should preserve temporary text as the user
   // text, and select all.
   model()->EnterKeywordModeForDefaultSearchProvider(
-      KeywordModeEntryMethod::KEYBOARD_SHORTCUT);
+      OmniboxEventProto::KEYBOARD_SHORTCUT);
   EXPECT_EQ(base::UTF8ToUTF16("match text"), model()->GetUserTextForTesting());
   EXPECT_EQ(base::UTF8ToUTF16("match text"), view()->GetText());
   EXPECT_TRUE(view()->IsSelectAll());
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
index 233172a..6db93050 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -251,7 +251,7 @@
       AsWeakPtr()));
   auto filter = std::make_unique<WebDocumentSubresourceFilterImpl>(
       url::Origin::Create(url), activation_state, std::move(ruleset),
-      std::move(first_disallowed_load_callback), IsAdSubframe());
+      std::move(first_disallowed_load_callback));
   filter->set_ad_resource_tracker(ad_resource_tracker_.get());
   filter_for_last_committed_load_ = filter->AsWeakPtr();
   SetSubresourceFilterForCommittedLoad(std::move(filter));
@@ -286,8 +286,7 @@
           std::move(ruleset_file),
           base::BindOnce(&SubresourceFilterAgent::
                              SignalFirstSubresourceDisallowedForCommittedLoad,
-                         AsWeakPtr()),
-          IsAdSubframe()));
+                         AsWeakPtr())));
 }
 
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
index c9dd27c..14de844 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -66,10 +66,6 @@
   bool IsAdSubframe() override { return is_ad_subframe_; }
   void SetIsAdSubframe() override { is_ad_subframe_ = true; }
 
-  bool IsFilterAssociatedWithAdSubframe() {
-    return last_injected_filter_->GetIsAssociatedWithAdSubframe();
-  }
-
   blink::WebDocumentSubresourceFilter* filter() {
     return last_injected_filter_.get();
   }
@@ -508,7 +504,6 @@
   histogram_tester.ExpectTotalCount(kEvaluationTotalWallDuration, 0);
   histogram_tester.ExpectTotalCount(kEvaluationTotalCPUDuration, 0);
 
-  EXPECT_FALSE(agent()->IsFilterAssociatedWithAdSubframe());
   EXPECT_FALSE(agent()->IsAdSubframe());
 }
 
@@ -576,7 +571,6 @@
   // For testing the flag passed to the dedicated worker filter, the unit test
   // is not able to test the implementation of WillCreateWorkerFetchContext as
   // that will require setup of a WebWorkerFetchContextImpl.
-  EXPECT_TRUE(agent()->IsFilterAssociatedWithAdSubframe());
   EXPECT_TRUE(agent()->IsAdSubframe());
 }
 
@@ -589,7 +583,6 @@
                                  false /* is_associated_with_ad_subframe */);
   ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
 
-  EXPECT_TRUE(agent()->IsFilterAssociatedWithAdSubframe());
   EXPECT_TRUE(agent()->IsAdSubframe());
 }
 
diff --git a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
index 451b2bc5..91af3f8 100644
--- a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
+++ b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
@@ -106,13 +106,11 @@
     url::Origin document_origin,
     mojom::ActivationState activation_state,
     scoped_refptr<const MemoryMappedRuleset> ruleset,
-    base::OnceClosure first_disallowed_load_callback,
-    bool is_associated_with_ad_subframe)
+    base::OnceClosure first_disallowed_load_callback)
     : activation_state_(activation_state),
       filter_(std::move(document_origin), activation_state, std::move(ruleset)),
       first_disallowed_load_callback_(
-          std::move(first_disallowed_load_callback)),
-      is_associated_with_ad_subframe_(is_associated_with_ad_subframe) {}
+          std::move(first_disallowed_load_callback)) {}
 
 WebLoadPolicy WebDocumentSubresourceFilterImpl::GetLoadPolicy(
     const blink::WebURL& resourceUrl,
@@ -136,10 +134,6 @@
   return activation_state().enable_logging;
 }
 
-bool WebDocumentSubresourceFilterImpl::GetIsAssociatedWithAdSubframe() const {
-  return is_associated_with_ad_subframe_;
-}
-
 WebLoadPolicy WebDocumentSubresourceFilterImpl::getLoadPolicyImpl(
     const blink::WebURL& url,
     proto::ElementType element_type) {
@@ -157,16 +151,13 @@
     url::Origin document_origin,
     mojom::ActivationState activation_state,
     base::File ruleset_file,
-    base::OnceClosure first_disallowed_load_callback,
-    bool is_associated_with_ad_subframe)
+    base::OnceClosure first_disallowed_load_callback)
     : document_origin_(std::move(document_origin)),
       activation_state_(std::move(activation_state)),
       ruleset_file_(std::move(ruleset_file)),
       first_disallowed_load_callback_(
           std::move(first_disallowed_load_callback)),
-      main_task_runner_(base::MessageLoopCurrent::Get()->task_runner()),
-      is_associated_with_ad_subframe_(is_associated_with_ad_subframe) {}
-
+      main_task_runner_(base::MessageLoopCurrent::Get()->task_runner()) {}
 WebDocumentSubresourceFilterImpl::BuilderImpl::~BuilderImpl() {}
 
 std::unique_ptr<blink::WebDocumentSubresourceFilter>
@@ -180,8 +171,7 @@
   return std::make_unique<WebDocumentSubresourceFilterImpl>(
       document_origin_, activation_state_, std::move(ruleset),
       base::BindOnce(&ProxyToTaskRunner, main_task_runner_,
-                     std::move(first_disallowed_load_callback_)),
-      is_associated_with_ad_subframe_);
+                     std::move(first_disallowed_load_callback_)));
 }
 
 void WebDocumentSubresourceFilterImpl::ReportAdRequestId(int request_id) {
diff --git a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h
index 6bc0c3e..3a26e1c 100644
--- a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h
+++ b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h
@@ -31,8 +31,7 @@
     BuilderImpl(url::Origin document_origin,
                 mojom::ActivationState activation_state,
                 base::File ruleset_file,
-                base::OnceClosure first_disallowed_load_callback,
-                bool is_associated_with_ad_subframe);
+                base::OnceClosure first_disallowed_load_callback);
     ~BuilderImpl() override;
 
     std::unique_ptr<blink::WebDocumentSubresourceFilter> Build() override;
@@ -43,7 +42,6 @@
     base::File ruleset_file_;
     base::OnceClosure first_disallowed_load_callback_;
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
-    bool is_associated_with_ad_subframe_;
 
     DISALLOW_COPY_AND_ASSIGN(BuilderImpl);
   };
@@ -56,8 +54,7 @@
       url::Origin document_origin,
       mojom::ActivationState activation_state,
       scoped_refptr<const MemoryMappedRuleset> ruleset,
-      base::OnceClosure first_disallowed_load_callback,
-      bool is_associated_with_ad_subframe);
+      base::OnceClosure first_disallowed_load_callback);
 
   ~WebDocumentSubresourceFilterImpl() override;
 
@@ -70,7 +67,6 @@
       const blink::WebURL& url) override;
   void ReportDisallowedLoad() override;
   bool ShouldLogToConsole() override;
-  bool GetIsAssociatedWithAdSubframe() const override;
   void ReportAdRequestId(int request_id) override;
 
   const mojom::ActivationState& activation_state() const {
@@ -89,7 +85,6 @@
   mojom::ActivationState activation_state_;
   DocumentSubresourceFilter filter_;
   base::OnceClosure first_disallowed_load_callback_;
-  bool is_associated_with_ad_subframe_;
 
   // Manages all AdResource observers. Only non-null for the
   // WebDocumentSubresourceFilter most recently created by the
diff --git a/components/sync/tools/BUILD.gn b/components/sync/tools/BUILD.gn
index 088de6b..1477f14 100644
--- a/components/sync/tools/BUILD.gn
+++ b/components/sync/tools/BUILD.gn
@@ -36,23 +36,3 @@
     "//net:test_support",
   ]
 }
-
-test("sync_client") {
-  sources = [
-    "sync_client.cc",
-  ]
-
-  defines = [ "SYNC_TEST" ]
-
-  deps = [
-    ":common",
-    "//base",
-    "//components/invalidation/impl",
-    "//components/sync",
-    "//components/sync:test_support_engine",
-    "//jingle:notifier",
-    "//net:test_support",
-    "//services/network:network_service",
-    "//services/network:test_support",
-  ]
-}
diff --git a/components/sync/tools/sync_client.cc b/components/sync/tools/sync_client.cc
deleted file mode 100644
index 5637f62..0000000
--- a/components/sync/tools/sync_client.cc
+++ /dev/null
@@ -1,463 +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 <stdint.h>
-
-#include <cstddef>
-#include <cstdio>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/at_exit.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/debug/stack_trace.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/json/json_writer.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/rand_util.h"
-#include "base/run_loop.h"
-#include "base/task_runner.h"
-#include "base/threading/thread.h"
-#include "build/build_config.h"
-#include "components/invalidation/impl/non_blocking_invalidator.h"
-#include "components/invalidation/public/object_id_invalidation_map.h"
-#include "components/sync/base/cancelation_signal.h"
-#include "components/sync/base/fake_encryptor.h"
-#include "components/sync/base/invalidation_helper.h"
-#include "components/sync/base/model_type.h"
-#include "components/sync/base/unrecoverable_error_handler.h"
-#include "components/sync/base/weak_handle.h"
-#include "components/sync/engine/engine_components_factory_impl.h"
-#include "components/sync/engine/net/http_bridge.h"
-#include "components/sync/engine/net/http_post_provider_factory.h"
-#include "components/sync/engine/passive_model_worker.h"
-#include "components/sync/engine/sync_manager.h"
-#include "components/sync/engine/sync_manager_factory.h"
-#include "components/sync/js/js_event_details.h"
-#include "components/sync/js/js_event_handler.h"
-#include "components/sync/syncable/base_node.h"
-#include "components/sync/syncable/read_node.h"
-#include "components/sync/tools/null_invalidation_state_tracker.h"
-#include "jingle/notifier/base/notification_method.h"
-#include "jingle/notifier/base/notifier_options.h"
-#include "net/base/host_port_pair.h"
-#include "net/dns/host_resolver.h"
-#include "net/http/transport_security_state.h"
-#include "net/url_request/url_request_test_util.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "services/network/test/test_shared_url_loader_factory.h"
-#include "services/network/transitional_url_loader_factory_owner.h"
-#include "url/gurl.h"
-
-#if defined(OS_MACOSX)
-#include "base/mac/scoped_nsautorelease_pool.h"
-#endif
-
-// This is a simple utility that initializes a sync client and
-// prints out any events.
-
-// TODO(akalin): Refactor to combine shared code with
-// sync_listen_notifications.
-namespace syncer {
-namespace {
-
-const char kEmailSwitch[] = "email";
-const char kTokenSwitch[] = "token";
-const char kXmppHostPortSwitch[] = "xmpp-host-port";
-const char kXmppTrySslTcpFirstSwitch[] = "xmpp-try-ssltcp-first";
-const char kXmppAllowInsecureConnectionSwitch[] =
-    "xmpp-allow-insecure-connection";
-const char kSyncServiceURL[] = "https://clients4.google.com/chrome-sync/dev";
-
-// Needed to use a real host resolver.
-class MyTestURLRequestContext : public net::TestURLRequestContext {
- public:
-  MyTestURLRequestContext() : TestURLRequestContext(true) {
-    context_storage_.set_host_resolver(
-        net::HostResolver::CreateDefaultResolver(nullptr));
-    context_storage_.set_transport_security_state(
-        std::make_unique<net::TransportSecurityState>());
-    Init();
-  }
-
-  ~MyTestURLRequestContext() override {}
-};
-
-class MyTestURLRequestContextGetter : public net::TestURLRequestContextGetter {
- public:
-  explicit MyTestURLRequestContextGetter(
-      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
-      : TestURLRequestContextGetter(io_task_runner) {}
-
-  net::TestURLRequestContext* GetURLRequestContext() override {
-    // Construct |context_| lazily so it gets constructed on the right
-    // thread (the IO thread).
-    if (!context_)
-      context_ = std::make_unique<MyTestURLRequestContext>();
-    return context_.get();
-  }
-
- private:
-  ~MyTestURLRequestContextGetter() override {}
-
-  std::unique_ptr<MyTestURLRequestContext> context_;
-};
-
-// TODO(akalin): Use system encryptor once it's moved to sync/.
-class NullEncryptor : public Encryptor {
- public:
-  ~NullEncryptor() override {}
-
-  bool EncryptString(const std::string& plaintext,
-                     std::string* ciphertext) override {
-    *ciphertext = plaintext;
-    return true;
-  }
-
-  bool DecryptString(const std::string& ciphertext,
-                     std::string* plaintext) override {
-    *plaintext = ciphertext;
-    return true;
-  }
-};
-
-std::string ValueToString(const base::Value& value) {
-  std::string str;
-  base::JSONWriter::Write(value, &str);
-  return str;
-}
-
-class LoggingChangeDelegate : public SyncManager::ChangeDelegate {
- public:
-  ~LoggingChangeDelegate() override {}
-
-  void OnChangesApplied(ModelType model_type,
-                        int64_t model_version,
-                        const BaseTransaction* trans,
-                        const ImmutableChangeRecordList& changes) override {
-    LOG(INFO) << "Changes applied for " << ModelTypeToString(model_type);
-    size_t i = 1;
-    size_t change_count = changes.Get().size();
-    for (auto it = changes.Get().begin(); it != changes.Get().end(); ++it) {
-      std::unique_ptr<base::DictionaryValue> change_value(it->ToValue());
-      LOG(INFO) << "Change (" << i << "/" << change_count
-                << "): " << ValueToString(*change_value);
-      if (it->action != ChangeRecord::ACTION_DELETE) {
-        ReadNode node(trans);
-        DCHECK_EQ(node.InitByIdLookup(it->id), BaseNode::INIT_OK);
-        std::unique_ptr<base::DictionaryValue> details(node.ToValue());
-        VLOG(1) << "Details: " << ValueToString(*details);
-      }
-      ++i;
-    }
-  }
-
-  void OnChangesComplete(ModelType model_type) override {
-    LOG(INFO) << "Changes complete for " << ModelTypeToString(model_type);
-  }
-};
-
-class LoggingUnrecoverableErrorHandler : public UnrecoverableErrorHandler {
- public:
-  ~LoggingUnrecoverableErrorHandler() override {}
-
-  void OnUnrecoverableError(const base::Location& from_here,
-                            const std::string& message) override {
-    if (LOG_IS_ON(ERROR)) {
-      logging::LogMessage(from_here.file_name(), from_here.line_number(),
-                          logging::LOG_ERROR)
-              .stream()
-          << message;
-    }
-  }
-};
-
-class LoggingJsEventHandler
-    : public JsEventHandler,
-      public base::SupportsWeakPtr<LoggingJsEventHandler> {
- public:
-  ~LoggingJsEventHandler() override {}
-
-  void HandleJsEvent(const std::string& name,
-                     const JsEventDetails& details) override {
-    VLOG(1) << name << ": " << details.ToString();
-  }
-};
-
-class InvalidationAdapter : public InvalidationInterface {
- public:
-  explicit InvalidationAdapter(const Invalidation& invalidation)
-      : invalidation_(invalidation) {}
-  ~InvalidationAdapter() override {}
-
-  bool IsUnknownVersion() const override {
-    return invalidation_.is_unknown_version();
-  }
-
-  const std::string& GetPayload() const override {
-    return invalidation_.payload();
-  }
-
-  int64_t GetVersion() const override { return invalidation_.version(); }
-
-  void Acknowledge() override { invalidation_.Acknowledge(); }
-
-  void Drop() override { invalidation_.Drop(); }
-
- private:
-  Invalidation invalidation_;
-};
-
-class InvalidatorShim : public InvalidationHandler {
- public:
-  explicit InvalidatorShim(SyncManager* sync_manager)
-      : sync_manager_(sync_manager) {}
-
-  void OnInvalidatorStateChange(InvalidatorState state) override {
-    sync_manager_->SetInvalidatorEnabled(state == INVALIDATIONS_ENABLED);
-  }
-
-  void OnIncomingInvalidation(
-      const ObjectIdInvalidationMap& invalidation_map) override {
-    ObjectIdSet ids = invalidation_map.GetObjectIds();
-    for (auto ids_it = ids.begin(); ids_it != ids.end(); ++ids_it) {
-      ModelType type;
-      if (!NotificationTypeToRealModelType(ids_it->name(), &type)) {
-        DLOG(WARNING) << "Notification has invalid id: "
-                      << ObjectIdToString(*ids_it);
-      } else {
-        SingleObjectInvalidationSet invalidation_set =
-            invalidation_map.ForObject(*ids_it);
-        for (auto inv_it = invalidation_set.begin();
-             inv_it != invalidation_set.end(); ++inv_it) {
-          std::unique_ptr<InvalidationInterface> inv_adapter(
-              new InvalidationAdapter(*inv_it));
-          sync_manager_->OnIncomingInvalidation(type, std::move(inv_adapter));
-        }
-      }
-    }
-  }
-
-  std::string GetOwnerName() const override { return "InvalidatorShim"; }
-
- private:
-  SyncManager* sync_manager_;
-};
-
-void LogUnrecoverableErrorContext() {
-  base::debug::StackTrace().Print();
-}
-
-notifier::NotifierOptions ParseNotifierOptions(
-    const base::CommandLine& command_line,
-    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) {
-  notifier::NotifierOptions notifier_options;
-  notifier_options.request_context_getter = request_context_getter;
-  notifier_options.auth_mechanism = "X-OAUTH2";
-
-  if (command_line.HasSwitch(kXmppHostPortSwitch)) {
-    notifier_options.xmpp_host_port = net::HostPortPair::FromString(
-        command_line.GetSwitchValueASCII(kXmppHostPortSwitch));
-    LOG(INFO) << "Using " << notifier_options.xmpp_host_port.ToString()
-              << " for test sync notification server.";
-  }
-
-  notifier_options.try_ssltcp_first =
-      command_line.HasSwitch(kXmppTrySslTcpFirstSwitch);
-  LOG_IF(INFO, notifier_options.try_ssltcp_first)
-      << "Trying SSL/TCP port before XMPP port for notifications.";
-
-  notifier_options.allow_insecure_connection =
-      command_line.HasSwitch(kXmppAllowInsecureConnectionSwitch);
-  LOG_IF(INFO, notifier_options.allow_insecure_connection)
-      << "Allowing insecure XMPP connections.";
-
-  return notifier_options;
-}
-
-void StubNetworkTimeUpdateCallback(const base::Time&,
-                                   const base::TimeDelta&,
-                                   const base::TimeDelta&) {}
-
-int SyncClientMain(int argc, char* argv[]) {
-#if defined(OS_MACOSX)
-  base::mac::ScopedNSAutoreleasePool pool;
-#endif
-  base::AtExitManager exit_manager;
-  base::CommandLine::Init(argc, argv);
-  logging::LoggingSettings settings;
-  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
-  logging::InitLogging(settings);
-
-  base::MessageLoop sync_loop;
-  base::Thread io_thread("IO thread");
-  base::Thread::Options options;
-  options.message_loop_type = base::MessageLoop::TYPE_IO;
-  io_thread.StartWithOptions(options);
-
-  // Parse command line.
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  SyncCredentials credentials;
-  credentials.account_id = command_line.GetSwitchValueASCII(kEmailSwitch);
-  credentials.email = command_line.GetSwitchValueASCII(kEmailSwitch);
-  credentials.sync_token = command_line.GetSwitchValueASCII(kTokenSwitch);
-  // TODO(akalin): Write a wrapper script that gets a token for an
-  // email and password and passes that in to this utility.
-  if (credentials.email.empty() || credentials.sync_token.empty()) {
-    std::printf(
-        "Usage: %s --%s=foo@bar.com --%s=token\n"
-        "[--%s=host:port] [--%s] [--%s]\n"
-        "Run chrome and set a breakpoint on\n"
-        "SyncManagerImpl::UpdateCredentials() "
-        "after logging into\n"
-        "sync to get the token to pass into this utility.\n",
-        argv[0], kEmailSwitch, kTokenSwitch, kXmppHostPortSwitch,
-        kXmppTrySslTcpFirstSwitch, kXmppAllowInsecureConnectionSwitch);
-    return -1;
-  }
-
-  // Set up sync notifier factory.
-  const scoped_refptr<MyTestURLRequestContextGetter> context_getter =
-      new MyTestURLRequestContextGetter(io_thread.task_runner());
-  const notifier::NotifierOptions& notifier_options =
-      ParseNotifierOptions(command_line, context_getter);
-  NetworkChannelCreator network_channel_creator =
-      NonBlockingInvalidator::MakePushClientChannelCreator(notifier_options);
-  const char kClientInfo[] = "standalone_sync_client";
-  std::string invalidator_id = base::RandBytesAsString(8);
-  NullInvalidationStateTracker null_invalidation_state_tracker;
-  std::unique_ptr<Invalidator> invalidator(new NonBlockingInvalidator(
-      network_channel_creator, invalidator_id,
-      null_invalidation_state_tracker.GetSavedInvalidations(),
-      null_invalidation_state_tracker.GetBootstrapData(),
-      &null_invalidation_state_tracker, kClientInfo,
-      notifier_options.request_context_getter));
-
-  // Set up database directory for the syncer.
-  base::ScopedTempDir database_dir;
-  bool success = database_dir.CreateUniqueTempDir();
-  DCHECK(success);
-
-  // Developers often add types to ModelTypeSet::All() before the server
-  // supports them.  We need to be explicit about which types we want here.
-  ModelTypeSet model_types;
-  model_types.Put(BOOKMARKS);
-  model_types.Put(PREFERENCES);
-  model_types.Put(PASSWORDS);
-  model_types.Put(AUTOFILL);
-  model_types.Put(THEMES);
-  model_types.Put(TYPED_URLS);
-  model_types.Put(EXTENSIONS);
-  model_types.Put(NIGORI);
-  model_types.Put(SEARCH_ENGINES);
-  model_types.Put(SESSIONS);
-  model_types.Put(APPS);
-  model_types.Put(AUTOFILL_PROFILE);
-  model_types.Put(APP_SETTINGS);
-  model_types.Put(EXTENSION_SETTINGS);
-  model_types.Put(APP_NOTIFICATIONS);
-  model_types.Put(HISTORY_DELETE_DIRECTIVES);
-  model_types.Put(SYNCED_NOTIFICATIONS);
-  model_types.Put(SYNCED_NOTIFICATION_APP_INFO);
-  model_types.Put(DEVICE_INFO);
-  model_types.Put(EXPERIMENTS);
-  model_types.Put(PRIORITY_PREFERENCES);
-  model_types.Put(DICTIONARY);
-  model_types.Put(FAVICON_IMAGES);
-  model_types.Put(FAVICON_TRACKING);
-
-  scoped_refptr<PassiveModelWorker> passive_model_safe_worker =
-      new PassiveModelWorker();
-  std::vector<scoped_refptr<ModelSafeWorker>> workers;
-  workers.push_back(passive_model_safe_worker);
-
-  // Set up sync manager.
-  std::unique_ptr<network::NetworkConnectionTracker>
-      network_connection_tracker =
-          network::TestNetworkConnectionTracker::CreateInstance();
-  SyncManagerFactory sync_manager_factory(network_connection_tracker.get());
-  std::unique_ptr<SyncManager> sync_manager =
-      sync_manager_factory.CreateSyncManager("sync_client manager");
-  LoggingJsEventHandler js_event_handler;
-  // Used only by InitialProcessMetadata(), so it's okay to leave this as null.
-  const scoped_refptr<base::TaskRunner> blocking_task_runner = nullptr;
-  const char kUserAgent[] = "sync_client";
-  // TODO(akalin): Replace this with just the context getter once
-  // HttpPostProviderFactory is removed.
-  auto url_loader_factory_owner =
-      std::make_unique<network::TransitionalURLLoaderFactoryOwner>(
-          context_getter);
-  CancelationSignal factory_cancelation_signal;
-  std::unique_ptr<HttpPostProviderFactory> post_factory(new HttpBridgeFactory(
-      url_loader_factory_owner->GetURLLoaderFactory()->Clone(),
-      base::BindRepeating(&StubNetworkTimeUpdateCallback),
-      &factory_cancelation_signal));
-  post_factory->Init(kUserAgent, BindToTrackerCallback());
-  // Used only when committing bookmarks, so it's okay to leave this as null.
-  ExtensionsActivity* extensions_activity = nullptr;
-  LoggingChangeDelegate change_delegate;
-  const char kRestoredKeyForBootstrapping[] = "";
-  const char kRestoredKeystoreKeyForBootstrapping[] = "";
-  NullEncryptor null_encryptor;
-  EngineComponentsFactoryImpl::Switches factory_switches = {
-      EngineComponentsFactory::ENCRYPTION_KEYSTORE,
-      EngineComponentsFactory::BACKOFF_NORMAL};
-  CancelationSignal scm_cancelation_signal;
-
-  SyncManager::InitArgs args;
-  args.database_location = database_dir.GetPath();
-  args.event_handler = WeakHandle<JsEventHandler>(js_event_handler.AsWeakPtr());
-  args.service_url = GURL(kSyncServiceURL);
-  args.post_factory = std::move(post_factory);
-  args.workers = workers;
-  args.extensions_activity = extensions_activity;
-  args.change_delegate = &change_delegate;
-  args.credentials = credentials;
-  args.invalidator_client_id = invalidator_id;
-  args.restored_key_for_bootstrapping = kRestoredKeyForBootstrapping;
-  args.restored_keystore_key_for_bootstrapping =
-      kRestoredKeystoreKeyForBootstrapping;
-  args.engine_components_factory =
-      std::make_unique<EngineComponentsFactoryImpl>(factory_switches);
-  args.encryptor = &null_encryptor;
-  args.unrecoverable_error_handler = WeakHandle<UnrecoverableErrorHandler>();
-  args.report_unrecoverable_error_function =
-      base::BindRepeating(LogUnrecoverableErrorContext);
-  args.cancelation_signal = &scm_cancelation_signal;
-  sync_manager->Init(&args);
-  // TODO(akalin): Avoid passing in model parameters multiple times by
-  // organizing handling of model types.
-  invalidator->UpdateCredentials(credentials.email, credentials.sync_token);
-  std::unique_ptr<InvalidatorShim> shim(
-      new InvalidatorShim(sync_manager.get()));
-  invalidator->RegisterHandler(shim.get());
-  success = invalidator->UpdateRegisteredIds(
-      shim.get(), ModelTypeSetToObjectIdSet(model_types));
-  DCHECK(success);
-  ModelTypeConnector* model_type_connector =
-      sync_manager->GetModelTypeConnector();
-  for (ModelType type : model_types) {
-    model_type_connector->RegisterDirectoryType(type, GROUP_PASSIVE);
-  }
-
-  sync_manager->StartSyncingNormally(base::Time());
-
-  base::RunLoop().Run();
-
-  io_thread.Stop();
-  return 0;
-}
-
-}  // namespace
-}  // namespace syncer
-
-int main(int argc, char* argv[]) {
-  return syncer::SyncClientMain(argc, argv);
-}
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.cc b/content/browser/notifications/notification_event_dispatcher_impl.cc
index db206cc9..1ca3905 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -426,16 +426,6 @@
 void NotificationEventDispatcherImpl::RegisterNonPersistentNotificationListener(
     const std::string& notification_id,
     blink::mojom::NonPersistentNotificationListenerPtr event_listener_ptr) {
-  if (non_persistent_notification_listeners_.count(notification_id)) {
-    // Dispatch the close event for any previously displayed notification with
-    // the same notification id. This happens whenever a non-persistent
-    // notification is replaced (by creating another with the same tag), since
-    // from the JavaScript point of view there will be two notification objects,
-    // and the old one needs to receive a close event before the new one
-    // receives a show event.
-    DispatchNonPersistentCloseEvent(notification_id, base::DoNothing());
-  }
-
   // Observe connection errors, which occur when the JavaScript object or the
   // renderer hosting them goes away. (For example through navigation.) The
   // listener gets freed together with |this|, thus the Unretained is safe.
@@ -444,6 +434,22 @@
           HandleConnectionErrorForNonPersistentNotificationListener,
       base::Unretained(this), notification_id));
 
+  if (non_persistent_notification_listeners_.count(notification_id)) {
+    // Dispatch the close event for any previously displayed notification with
+    // the same notification id. This happens whenever a non-persistent
+    // notification is replaced (by creating another with the same tag), since
+    // from the JavaScript point of view there will be two notification objects,
+    // and the old one needs to receive a close event before the new one
+    // receives a show event.
+    DispatchNonPersistentCloseEvent(
+        notification_id,
+        base::BindOnce(&NotificationEventDispatcherImpl::
+                           ReplaceNonPersistentNotificationListener,
+                       base::Unretained(this), notification_id,
+                       std::move(event_listener_ptr)));
+    return;
+  }
+
   non_persistent_notification_listeners_.emplace(notification_id,
                                                  std::move(event_listener_ptr));
 }
@@ -489,6 +495,13 @@
   std::move(completed_closure).Run();
 }
 
+void NotificationEventDispatcherImpl::ReplaceNonPersistentNotificationListener(
+    const std::string& notification_id,
+    blink::mojom::NonPersistentNotificationListenerPtr event_listener_ptr) {
+  non_persistent_notification_listeners_.emplace(notification_id,
+                                                 std::move(event_listener_ptr));
+}
+
 void NotificationEventDispatcherImpl::
     HandleConnectionErrorForNonPersistentNotificationListener(
         const std::string& notification_id) {
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.h b/content/browser/notifications/notification_event_dispatcher_impl.h
index 230c56df..dd2c10e 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.h
+++ b/content/browser/notifications/notification_event_dispatcher_impl.h
@@ -67,6 +67,13 @@
   void OnNonPersistentCloseComplete(const std::string& notification_id,
                                     base::OnceClosure completed_closure);
 
+  // Replace listener for existing non-persistent notification.
+  // This method is called after a non-persistent notification has
+  // been replaced and |OnNonPersistentCloseComplete| is executed.
+  void ReplaceNonPersistentNotificationListener(
+      const std::string& notification_id,
+      blink::mojom::NonPersistentNotificationListenerPtr event_listener_ptr);
+
   // Removes all references to the listener registered to receive events
   // from the non-persistent notification identified by |notification_id|.
   // Should be called when the connection to this listener goes away.
diff --git a/content/browser/notifications/notification_event_dispatcher_impl_unittest.cc b/content/browser/notifications/notification_event_dispatcher_impl_unittest.cc
index d1bf4fe..e4f4619 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl_unittest.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl_unittest.cc
@@ -119,7 +119,7 @@
 }
 
 TEST_F(NotificationEventDispatcherImplTest,
-       RegisterReplacementNonPersistentListener_FirstListenerGetsOnClose) {
+       RegisterNonPersistentListener_FirstListenerGetsOnClose) {
   auto original_listener = std::make_unique<TestNotificationListener>();
   dispatcher_->RegisterNonPersistentNotificationListener(
       kPrimaryUniqueId, original_listener->GetPtr());
@@ -139,6 +139,31 @@
 }
 
 TEST_F(NotificationEventDispatcherImplTest,
+       RegisterNonPersistentListener_ReplacedListenerGetsOnClick) {
+  auto original_listener = std::make_unique<TestNotificationListener>();
+  dispatcher_->RegisterNonPersistentNotificationListener(
+      kPrimaryUniqueId, original_listener->GetPtr());
+
+  dispatcher_->DispatchNonPersistentShowEvent(kPrimaryUniqueId);
+
+  auto replacement_listener = std::make_unique<TestNotificationListener>();
+  dispatcher_->RegisterNonPersistentNotificationListener(
+      kPrimaryUniqueId, replacement_listener->GetPtr());
+
+  WaitForMojoTasksToComplete();
+
+  dispatcher_->DispatchNonPersistentClickEvent(kPrimaryUniqueId,
+                                               base::DoNothing());
+
+  WaitForMojoTasksToComplete();
+
+  EXPECT_EQ(original_listener->on_click_count(), 0);
+  EXPECT_EQ(original_listener->on_close_count(), 1);
+  EXPECT_EQ(replacement_listener->on_click_count(), 1);
+  EXPECT_EQ(replacement_listener->on_close_count(), 0);
+}
+
+TEST_F(NotificationEventDispatcherImplTest,
        DispatchNonPersistentClickEvent_NotifiesCorrectRegisteredListener) {
   auto listener = std::make_unique<TestNotificationListener>();
   dispatcher_->RegisterNonPersistentNotificationListener(kPrimaryUniqueId,
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc
index 6a55e155..b2cfb7a 100644
--- a/content/browser/renderer_host/input/input_router_impl.cc
+++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -331,7 +331,7 @@
         base::NumberToString(ack_result).c_str());
     touch_action_filter_.AppendToGestureSequenceForDebugging(
         base::NumberToString(event.event.unique_touch_event_id).c_str());
-    touch_action_filter_.IncreaseActiveTouches();
+    touch_action_filter_.SetTouchSequenceInProgress(true);
     // There are some cases the touch action may not have value when receiving
     // the ACK for the touch start, such as input ack state is
     // NO_CONSUMER_EXISTS, or the renderer has swapped out. In these cases, set
@@ -347,7 +347,7 @@
     touch_action_filter_.AppendToGestureSequenceForDebugging("E");
     touch_action_filter_.AppendToGestureSequenceForDebugging(
         base::NumberToString(event.event.unique_touch_event_id).c_str());
-    touch_action_filter_.DecreaseActiveTouches();
+    touch_action_filter_.SetTouchSequenceInProgress(false);
     touch_action_filter_.ReportAndResetTouchAction();
     UpdateTouchAckTimeoutEnabled();
   }
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index 5aa4d444..af5c6266 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -417,7 +417,7 @@
     disposition_handler_->GetAndResetAckCount();
   }
 
-  void ActiveTouchSequenceCountTest(
+  void TouchSequenceInProgressTest(
       const base::Optional<cc::TouchAction>& touch_action,
       InputEventAckState state) {
     PressTouchPoint(1, 1);
@@ -426,11 +426,13 @@
     input_router_->TouchEventHandled(
         TouchEventWithLatencyInfo(touch_event_), InputEventAckSource::BROWSER,
         ui::LatencyInfo(), state, overscroll, touch_action);
-    EXPECT_EQ(input_router_->touch_action_filter_.num_of_active_touches_, 1);
+    EXPECT_TRUE(
+        input_router_->touch_action_filter_.touch_sequence_in_progress_);
     ReleaseTouchPoint(0);
     input_router_->OnTouchEventAck(TouchEventWithLatencyInfo(touch_event_),
                                    InputEventAckSource::BROWSER, state);
-    EXPECT_EQ(input_router_->touch_action_filter_.num_of_active_touches_, 0);
+    EXPECT_FALSE(
+        input_router_->touch_action_filter_.touch_sequence_in_progress_);
   }
 
   void OnTouchEventAckWithAckState(InputEventAckState ack_state) {
@@ -614,31 +616,31 @@
 
 // Test that the active touch sequence count increment when the touch start is
 // not ACKed from the main thread.
-TEST_F(InputRouterImplTest, ActiveTouchSequenceCountWithoutTouchAction) {
+TEST_F(InputRouterImplTest, TouchSequenceInProgressWithoutTouchAction) {
   base::Optional<cc::TouchAction> touch_action;
-  ActiveTouchSequenceCountTest(touch_action,
-                               INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
+  TouchSequenceInProgressTest(touch_action,
+                              INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 }
 
 TEST_F(InputRouterImplTest,
-       ActiveTouchSequenceCountWithoutTouchActionNoConsumer) {
+       TouchSequenceInProgressWithoutTouchActionNoConsumer) {
   base::Optional<cc::TouchAction> touch_action;
-  ActiveTouchSequenceCountTest(touch_action,
-                               INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+  TouchSequenceInProgressTest(touch_action,
+                              INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
 }
 
 // Test that the active touch sequence count increment when the touch start is
 // ACKed from the main thread.
-TEST_F(InputRouterImplTest, ActiveTouchSequenceCountWithTouchAction) {
+TEST_F(InputRouterImplTest, TouchSequenceInProgressWithTouchAction) {
   base::Optional<cc::TouchAction> touch_action(cc::kTouchActionPanY);
-  ActiveTouchSequenceCountTest(touch_action,
-                               INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
+  TouchSequenceInProgressTest(touch_action,
+                              INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 }
 
-TEST_F(InputRouterImplTest, ActiveTouchSequenceCountWithTouchActionNoConsumer) {
+TEST_F(InputRouterImplTest, TouchSequenceInProgressWithTouchActionNoConsumer) {
   base::Optional<cc::TouchAction> touch_action(cc::kTouchActionPanY);
-  ActiveTouchSequenceCountTest(touch_action,
-                               INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+  TouchSequenceInProgressTest(touch_action,
+                              INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
 }
 
 TEST_F(InputRouterImplTest, TouchActionAutoWithAckStateConsumed) {
diff --git a/content/browser/renderer_host/input/touch_action_filter.cc b/content/browser/renderer_host/input/touch_action_filter.cc
index 2010ea3c..15b516f 100644
--- a/content/browser/renderer_host/input/touch_action_filter.cc
+++ b/content/browser/renderer_host/input/touch_action_filter.cc
@@ -188,10 +188,7 @@
       gesture_sequence_in_progress_ = true;
       // If the gesture is hitting a region that has a non-blocking (such as a
       // passive) event listener.
-      // In theory, the num_of_active_touches_ should be > 0 at this point. But
-      // crash reports suggest otherwise.
-      if (gesture_event->is_source_touch_event_set_non_blocking ||
-          num_of_active_touches_ <= 0)
+      if (gesture_event->is_source_touch_event_set_non_blocking)
         SetTouchAction(cc::kTouchActionAuto);
       active_touch_action_ = allowed_touch_action_;
       if (active_touch_action_.has_value())
@@ -269,12 +266,9 @@
   active_touch_action_ = allowed_touch_action_;
 }
 
-void TouchActionFilter::IncreaseActiveTouches() {
-  num_of_active_touches_++;
-}
-
-void TouchActionFilter::DecreaseActiveTouches() {
-  num_of_active_touches_--;
+void TouchActionFilter::SetTouchSequenceInProgress(
+    bool touch_sequence_in_progress) {
+  touch_sequence_in_progress_ = touch_sequence_in_progress;
 }
 
 void TouchActionFilter::ReportAndResetTouchAction() {
@@ -283,8 +277,8 @@
   else
     gesture_sequence_.append("RN");
   ReportTouchAction();
-  if (num_of_active_touches_ <= 0)
-    ResetTouchAction();
+  DCHECK(!touch_sequence_in_progress_);
+  ResetTouchAction();
 }
 
 void TouchActionFilter::ReportTouchAction() {
@@ -396,7 +390,7 @@
   // We have set the associated touch action if the touch start already happened
   // or there is a gesture in progress. In these cases, we should not reset the
   // associated touch action.
-  if (!gesture_sequence_in_progress_ && num_of_active_touches_ <= 0) {
+  if (!gesture_sequence_in_progress_ && !touch_sequence_in_progress_) {
     ResetTouchAction();
     if (has_touch_event_handler_)
       active_touch_action_.reset();
diff --git a/content/browser/renderer_host/input/touch_action_filter.h b/content/browser/renderer_host/input/touch_action_filter.h
index b7a76a5..a7001398 100644
--- a/content/browser/renderer_host/input/touch_action_filter.h
+++ b/content/browser/renderer_host/input/touch_action_filter.h
@@ -60,8 +60,7 @@
 
   void OnHasTouchEventHandlers(bool has_handlers);
 
-  void IncreaseActiveTouches();
-  void DecreaseActiveTouches();
+  void SetTouchSequenceInProgress(bool touch_sequence_in_progress);
 
   void ForceResetTouchActionForTest();
 
@@ -111,8 +110,8 @@
   // before GSE.
   bool gesture_sequence_in_progress_ = false;
 
-  // Increment at receiving ACK for touch start and decrement at touch end.
-  int num_of_active_touches_ = 0;
+  // True at touch sequence start and false at touch sequence end.
+  bool touch_sequence_in_progress_ = false;
 
   // What touch actions are currently permitted.
   base::Optional<cc::TouchAction> allowed_touch_action_;
diff --git a/content/browser/renderer_host/input/touch_action_filter_unittest.cc b/content/browser/renderer_host/input/touch_action_filter_unittest.cc
index a1ba212..6d4bb3aa 100644
--- a/content/browser/renderer_host/input/touch_action_filter_unittest.cc
+++ b/content/browser/renderer_host/input/touch_action_filter_unittest.cc
@@ -46,7 +46,6 @@
       // Scrolls with no direction hint are permitted in the |action| direction.
       ResetTouchAction();
       filter_.OnSetTouchAction(action);
-      filter_.IncreaseActiveTouches();
 
       WebGestureEvent scroll_begin =
           SyntheticWebGestureEventBuilder::BuildScrollBegin(0, 0,
@@ -66,14 +65,12 @@
 
       EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
                 FilterGestureEventResult::kFilterGestureEventAllowed);
-      filter_.DecreaseActiveTouches();
     }
 
     {
       // Scrolls biased towards the touch-action axis are permitted.
       ResetTouchAction();
       filter_.OnSetTouchAction(action);
-      filter_.IncreaseActiveTouches();
       WebGestureEvent scroll_begin =
           SyntheticWebGestureEventBuilder::BuildScrollBegin(scroll_x, scroll_y,
                                                             kSourceDevice);
@@ -104,7 +101,6 @@
 
       EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
                 FilterGestureEventResult::kFilterGestureEventAllowed);
-      filter_.DecreaseActiveTouches();
     }
 
     {
@@ -112,7 +108,6 @@
       // suppressed entirely.
       ResetTouchAction();
       filter_.OnSetTouchAction(action);
-      filter_.IncreaseActiveTouches();
       WebGestureEvent scroll_begin =
           SyntheticWebGestureEventBuilder::BuildScrollBegin(scroll_y, scroll_x,
                                                             kSourceDevice);
@@ -131,7 +126,6 @@
 
       EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
                 FilterGestureEventResult::kFilterGestureEventFiltered);
-      filter_.DecreaseActiveTouches();
     }
   }
 
@@ -147,7 +141,6 @@
       // Scrolls towards the touch-action direction are permitted.
       ResetTouchAction();
       filter_.OnSetTouchAction(action);
-      filter_.IncreaseActiveTouches();
       WebGestureEvent scroll_begin =
           SyntheticWebGestureEventBuilder::BuildScrollBegin(scroll_x, scroll_y,
                                                             kSourceDevice);
@@ -163,7 +156,6 @@
                 FilterGestureEventResult::kFilterGestureEventAllowed);
       EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
                 FilterGestureEventResult::kFilterGestureEventAllowed);
-      filter_.DecreaseActiveTouches();
     }
 
     {
@@ -171,7 +163,6 @@
       // suppressed entirely.
       ResetTouchAction();
       filter_.OnSetTouchAction(action);
-      filter_.IncreaseActiveTouches();
       WebGestureEvent scroll_begin =
           SyntheticWebGestureEventBuilder::BuildScrollBegin(
               -scroll_x, -scroll_y, kSourceDevice);
@@ -187,7 +178,6 @@
                 FilterGestureEventResult::kFilterGestureEventFiltered);
       EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
                 FilterGestureEventResult::kFilterGestureEventFiltered);
-      filter_.DecreaseActiveTouches();
     }
 
     {
@@ -195,7 +185,6 @@
       // suppressed entirely.
       ResetTouchAction();
       filter_.OnSetTouchAction(action);
-      filter_.IncreaseActiveTouches();
       WebGestureEvent scroll_begin =
           SyntheticWebGestureEventBuilder::BuildScrollBegin(
               -scroll_x - scroll_y, -scroll_x - scroll_y, kSourceDevice);
@@ -211,7 +200,6 @@
                 FilterGestureEventResult::kFilterGestureEventFiltered);
       EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
                 FilterGestureEventResult::kFilterGestureEventFiltered);
-      filter_.DecreaseActiveTouches();
     }
   }
   TouchActionFilter filter_;
@@ -233,7 +221,6 @@
   // cc::kTouchActionAuto doesn't cause any filtering.
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionAuto);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -244,12 +231,10 @@
   EXPECT_EQ(kDeltaY, scroll_update.data.scroll_update.delta_y);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  filter_.DecreaseActiveTouches();
 
   // cc::kTouchActionNone filters out all scroll events, but no other events.
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionNone);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -262,12 +247,10 @@
   EXPECT_EQ(kDeltaY, scroll_update.data.scroll_update.delta_y);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventFiltered);
-  filter_.DecreaseActiveTouches();
 
   // When a new touch sequence begins, the state is reset.
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionAuto);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -276,12 +259,10 @@
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  filter_.DecreaseActiveTouches();
 
   // Setting touch action doesn't impact any in-progress gestures.
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionAuto);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -291,24 +272,20 @@
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  filter_.DecreaseActiveTouches();
 
   // And the state is still cleared for the next gesture.
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionAuto);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  filter_.DecreaseActiveTouches();
 
   // Changing the touch action during a gesture has no effect.
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionNone);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -322,7 +299,6 @@
   EXPECT_EQ(kDeltaY, scroll_update.data.scroll_update.delta_y);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventFiltered);
-  filter_.DecreaseActiveTouches();
 }
 
 TEST_F(TouchActionFilterTest, PanLeft) {
@@ -395,7 +371,6 @@
     // Scrolls hinted in the X axis are permitted and unmodified.
     ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionPan);
-    filter_.IncreaseActiveTouches();
     WebGestureEvent scroll_begin =
         SyntheticWebGestureEventBuilder::BuildScrollBegin(-7, 6, kSourceDevice);
     EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
@@ -413,14 +388,12 @@
 
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
               FilterGestureEventResult::kFilterGestureEventAllowed);
-    filter_.DecreaseActiveTouches();
   }
 
   {
     // Scrolls hinted in the Y axis are permitted and unmodified.
     ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionPan);
-    filter_.IncreaseActiveTouches();
     WebGestureEvent scroll_begin =
         SyntheticWebGestureEventBuilder::BuildScrollBegin(-6, 7, kSourceDevice);
     EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
@@ -438,14 +411,12 @@
 
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
               FilterGestureEventResult::kFilterGestureEventAllowed);
-    filter_.DecreaseActiveTouches();
   }
 
   {
     // A two-finger gesture is not allowed.
     ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionPan);
-    filter_.IncreaseActiveTouches();
     WebGestureEvent scroll_begin =
         SyntheticWebGestureEventBuilder::BuildScrollBegin(-6, 7, kSourceDevice,
                                                           2);
@@ -462,7 +433,6 @@
 
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
               FilterGestureEventResult::kFilterGestureEventFiltered);
-    filter_.DecreaseActiveTouches();
   }
 }
 
@@ -497,7 +467,6 @@
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionNone);
   filter_.OnSetTouchAction(cc::kTouchActionAuto);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -510,14 +479,12 @@
   EXPECT_EQ(kDeltaY, scroll_update.data.scroll_update.delta_y);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventFiltered);
-  filter_.DecreaseActiveTouches();
 
   // Intersection of PAN_X and PAN_Y is NONE.
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionPanX);
   filter_.OnSetTouchAction(cc::kTouchActionPanY);
   filter_.OnSetTouchAction(cc::kTouchActionPan);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -526,7 +493,6 @@
             FilterGestureEventResult::kFilterGestureEventFiltered);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventFiltered);
-  filter_.DecreaseActiveTouches();
 }
 
 class TouchActionFilterPinchTest : public testing::Test {
@@ -553,7 +519,6 @@
     // Pinch is allowed with touch-action: auto.
     filter_.ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionAuto);
-    filter_.IncreaseActiveTouches();
     EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -566,12 +531,10 @@
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
               FilterGestureEventResult::kFilterGestureEventAllowed);
-    filter_.DecreaseActiveTouches();
 
     // Pinch is not allowed with touch-action: none.
     filter_.ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionNone);
-    filter_.IncreaseActiveTouches();
     EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -590,13 +553,11 @@
               FilterGestureEventResult::kFilterGestureEventFiltered);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
               FilterGestureEventResult::kFilterGestureEventFiltered);
-    filter_.DecreaseActiveTouches();
 
     // Pinch is not allowed with touch-action: pan-x pan-y except for force
     // enable zoom.
     filter_.ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionPan);
-    filter_.IncreaseActiveTouches();
     EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_NE(filter_.FilterGestureEvent(&scroll_begin),
@@ -619,12 +580,10 @@
               force_enable_zoom
                   ? FilterGestureEventResult::kFilterGestureEventFiltered
                   : FilterGestureEventResult::kFilterGestureEventAllowed);
-    filter_.DecreaseActiveTouches();
 
     // Pinch is allowed with touch-action: manipulation.
     filter_.ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionManipulation);
-    filter_.IncreaseActiveTouches();
     EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -645,12 +604,10 @@
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
               FilterGestureEventResult::kFilterGestureEventAllowed);
-    filter_.DecreaseActiveTouches();
 
     // Pinch state is automatically reset at the end of a scroll.
     filter_.ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionAuto);
-    filter_.IncreaseActiveTouches();
     EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -663,23 +620,19 @@
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
               FilterGestureEventResult::kFilterGestureEventAllowed);
-    filter_.DecreaseActiveTouches();
 
     filter_.ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionAuto);
-    filter_.IncreaseActiveTouches();
     EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&pinch_update),
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&pinch_end),
               FilterGestureEventResult::kFilterGestureEventAllowed);
-    filter_.DecreaseActiveTouches();
 
     // Scrolling is allowed when two fingers are down.
     filter_.ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionPinchZoom);
-    filter_.IncreaseActiveTouches();
     EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -692,7 +645,6 @@
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
               FilterGestureEventResult::kFilterGestureEventAllowed);
-    filter_.DecreaseActiveTouches();
 
     // At double-tap-drag-zoom case, the pointer_count is 1 at GesturePinchBegin
     // and we need to evaluate whether the gesture is allowed or not at that
@@ -700,7 +652,6 @@
     scroll_begin.data.scroll_begin.pointer_count = 1;
     filter_.ResetTouchAction();
     filter_.OnSetTouchAction(cc::kTouchActionPinchZoom);
-    filter_.IncreaseActiveTouches();
     EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -713,7 +664,6 @@
               FilterGestureEventResult::kFilterGestureEventAllowed);
     EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
               FilterGestureEventResult::kFilterGestureEventFiltered);
-    filter_.DecreaseActiveTouches();
   }
 
  private:
@@ -774,7 +724,6 @@
   // Double tap is disabled with any touch action other than auto.
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionManipulation);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&unconfirmed_tap),
@@ -792,7 +741,6 @@
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(WebInputEvent::kGestureTap, double_tap.GetType());
   EXPECT_EQ(2, double_tap.data.tap.tap_count);
-  filter_.DecreaseActiveTouches();
 }
 
 TEST_F(TouchActionFilterTest, SingleTapWithTouchActionAuto) {
@@ -826,7 +774,6 @@
   // With touch action other than auto, tap unconfirmed is turned into tap.
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionNone);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&unconfirmed_tap1),
@@ -834,7 +781,6 @@
   EXPECT_EQ(WebInputEvent::kGestureTap, unconfirmed_tap1.GetType());
   EXPECT_EQ(filter_.FilterGestureEvent(&tap),
             FilterGestureEventResult::kFilterGestureEventFiltered);
-  filter_.DecreaseActiveTouches();
 }
 
 TEST_F(TouchActionFilterTest, TouchActionResetsOnResetTouchAction) {
@@ -849,32 +795,26 @@
 
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionNone);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
             FilterGestureEventResult::kFilterGestureEventFiltered);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventFiltered);
-  filter_.DecreaseActiveTouches();
 
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionNone);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&tap),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  filter_.DecreaseActiveTouches();
 
   ResetTouchAction();
   filter_.OnSetTouchAction(cc::kTouchActionAuto);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  filter_.DecreaseActiveTouches();
 }
 
 TEST_F(TouchActionFilterTest, TouchActionResetMidSequence) {
@@ -894,7 +834,6 @@
       WebInputEvent::kGestureScrollEnd, kSourceDevice);
 
   filter_.OnSetTouchAction(cc::kTouchActionNone);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
@@ -914,11 +853,9 @@
             FilterGestureEventResult::kFilterGestureEventFiltered);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventFiltered);
-  filter_.DecreaseActiveTouches();
 
   // A new scroll and pinch sequence should be allowed.
   filter_.OnSetTouchAction(cc::kTouchActionAuto);
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -935,7 +872,6 @@
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  filter_.DecreaseActiveTouches();
 }
 
 // This test makes sure that we do not reset scrolling touch action in the
@@ -955,7 +891,6 @@
   WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
       WebInputEvent::kGestureScrollEnd, kSourceDevice);
 
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(cc::kTouchActionPanY, ScrollingTouchAction().value());
@@ -965,7 +900,6 @@
   EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   // Simulate a touch sequence end by calling ReportAndResetTouchAction.
-  filter_.DecreaseActiveTouches();
   filter_.ReportAndResetTouchAction();
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
   EXPECT_EQ(cc::kTouchActionPanY, ScrollingTouchAction().value());
@@ -1017,7 +951,6 @@
       WebInputEvent::kGestureDoubleTap, kSourceDevice);
 
   // Simulate a double tap gesture: GTD-->GTC-->GTD-->GTC-->GDT.
-  filter_.IncreaseActiveTouches();
   EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionAuto);
@@ -1033,7 +966,6 @@
             FilterGestureEventResult::kFilterGestureEventAllowed);
   EXPECT_EQ(filter_.FilterGestureEvent(&double_tap),
             FilterGestureEventResult::kFilterGestureEventAllowed);
-  filter_.DecreaseActiveTouches();
 }
 
 TEST_F(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringScroll) {
@@ -1111,9 +1043,9 @@
   EXPECT_FALSE(ScrollingTouchAction().has_value());
   EXPECT_FALSE(filter_.allowed_touch_action().has_value());
 
+  filter_.SetTouchSequenceInProgress(true);
   // Receive a touch start ack, set the touch action.
   filter_.OnSetTouchAction(cc::kTouchActionPanY);
-  filter_.IncreaseActiveTouches();
   filter_.OnHasTouchEventHandlers(false);
   EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionPanY);
   EXPECT_EQ(filter_.allowed_touch_action().value(), cc::kTouchActionPanY);
@@ -1122,33 +1054,6 @@
   EXPECT_EQ(filter_.allowed_touch_action().value(), cc::kTouchActionPanY);
 }
 
-TEST_F(TouchActionFilterTest, ResetTouchActionWithActiveTouch) {
-  filter_.OnHasTouchEventHandlers(true);
-  EXPECT_FALSE(ScrollingTouchAction().has_value());
-  EXPECT_FALSE(filter_.allowed_touch_action().has_value());
-
-  // Receive a touch start ack, set the touch action.
-  filter_.OnSetTouchAction(cc::kTouchActionPanY);
-  filter_.IncreaseActiveTouches();
-
-  // Somehow we get the ACK for the second touch start before the ACK for the
-  // first touch end.
-  filter_.OnSetTouchAction(cc::kTouchActionPan);
-  filter_.IncreaseActiveTouches();
-
-  // The first touch end comes, we report and reset touch action. The touch
-  // actions should still have value.
-  filter_.DecreaseActiveTouches();
-  filter_.ReportAndResetTouchAction();
-  EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionPanY);
-  EXPECT_EQ(filter_.allowed_touch_action().value(), cc::kTouchActionPanY);
-
-  // The ack for the second touch end comes, the touch actions will be reset.
-  filter_.DecreaseActiveTouches();
-  filter_.ReportAndResetTouchAction();
-  EXPECT_FALSE(filter_.allowed_touch_action().has_value());
-}
-
 // If the renderer is busy, the gesture event might have come before the
 // OnHasTouchEventHanlders IPC is received. In this case, we should allow all
 // the gestures.
@@ -1183,20 +1088,6 @@
   EXPECT_EQ(filter_.allowed_touch_action().value(), cc::kTouchActionAuto);
 }
 
-// This tests a gesture tap down with |num_of_active_touches_| == 0
-TEST_F(TouchActionFilterTest, TapDownWithZeroNumOfActiveTouches) {
-  filter_.OnHasTouchEventHandlers(true);
-  EXPECT_FALSE(ScrollingTouchAction().has_value());
-  EXPECT_FALSE(filter_.allowed_touch_action().has_value());
-
-  WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
-      WebInputEvent::kGestureTapDown, kSourceDevice);
-  EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
-            FilterGestureEventResult::kFilterGestureEventAllowed);
-  EXPECT_TRUE(ScrollingTouchAction().has_value());
-  EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionAuto);
-}
-
 // Regression test for crbug.com/771330. One can start one finger panning y, and
 // add another finger to pinch zooming. The pinch zooming should not be allowed
 // if the allowed touch action doesn't allow it.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index dae3544..b80651e3c 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -4477,8 +4477,7 @@
       observer.RenderProcessReady(this);
   }
 
-  GetProcessResourceCoordinator()->SetLaunchTime(base::Time::Now());
-  GetProcessResourceCoordinator()->SetPID(GetProcess().Pid());
+  GetProcessResourceCoordinator()->OnProcessLaunched(GetProcess());
 
   WebRTCInternals* webrtc_internals = WebRTCInternals::GetInstance();
   if (webrtc_internals->IsAudioDebugRecordingsEnabled()) {
diff --git a/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc b/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc
index f7baefc5..f768373 100644
--- a/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc
+++ b/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc
@@ -28,7 +28,6 @@
     ~ServiceWorkerContentSettingsProxyImpl() = default;
 
 void ServiceWorkerContentSettingsProxyImpl::AllowIndexedDB(
-    const base::string16& name,
     AllowIndexedDBCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // May be shutting down.
@@ -46,7 +45,7 @@
   // so just pass an empty |render_frames|.
   std::vector<GlobalFrameRoutingId> render_frames;
   std::move(callback).Run(GetContentClient()->browser()->AllowWorkerIndexedDB(
-      origin_.GetURL(), name, context_->wrapper()->resource_context(),
+      origin_.GetURL(), context_->wrapper()->resource_context(),
       render_frames));
 }
 
diff --git a/content/browser/service_worker/service_worker_content_settings_proxy_impl.h b/content/browser/service_worker/service_worker_content_settings_proxy_impl.h
index d519ce70..c17eb1f 100644
--- a/content/browser/service_worker/service_worker_content_settings_proxy_impl.h
+++ b/content/browser/service_worker/service_worker_content_settings_proxy_impl.h
@@ -33,8 +33,7 @@
   ~ServiceWorkerContentSettingsProxyImpl() override;
 
   // blink::mojom::WorkerContentSettingsProxy implementation
-  void AllowIndexedDB(const base::string16& name,
-                      AllowIndexedDBCallback callback) override;
+  void AllowIndexedDB(AllowIndexedDBCallback callback) override;
   void RequestFileSystemAccessSync(
       RequestFileSystemAccessSyncCallback callback) override;
 
diff --git a/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.cc b/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.cc
index 3626969ae..952ef9ab 100644
--- a/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.cc
+++ b/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.cc
@@ -24,10 +24,9 @@
     default;
 
 void SharedWorkerContentSettingsProxyImpl::AllowIndexedDB(
-    const base::string16& name,
     AllowIndexedDBCallback callback) {
   if (!origin_.opaque()) {
-    owner_->AllowIndexedDB(origin_.GetURL(), name, std::move(callback));
+    owner_->AllowIndexedDB(origin_.GetURL(), std::move(callback));
   } else {
     std::move(callback).Run(false);
   }
diff --git a/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.h b/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.h
index 03ffc05..083ddcb 100644
--- a/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.h
+++ b/content/browser/shared_worker/shared_worker_content_settings_proxy_impl.h
@@ -34,8 +34,7 @@
   ~SharedWorkerContentSettingsProxyImpl() override;
 
   // blink::mojom::WorkerContentSettingsProxy implementation.
-  void AllowIndexedDB(const base::string16& name,
-                      AllowIndexedDBCallback callback) override;
+  void AllowIndexedDB(AllowIndexedDBCallback callback) override;
   void RequestFileSystemAccessSync(
       RequestFileSystemAccessSyncCallback callback) override;
 
diff --git a/content/browser/shared_worker/shared_worker_host.cc b/content/browser/shared_worker/shared_worker_host.cc
index 03f1798..409368d4 100644
--- a/content/browser/shared_worker/shared_worker_host.cc
+++ b/content/browser/shared_worker/shared_worker_host.cc
@@ -55,12 +55,11 @@
 }
 
 bool AllowIndexedDBOnIOThread(const GURL& url,
-                              const base::string16& name,
                               ResourceContext* resource_context,
                               std::vector<GlobalFrameRoutingId> render_frames) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   return GetContentClient()->browser()->AllowWorkerIndexedDB(
-      url, name, resource_context, render_frames);
+      url, resource_context, render_frames);
 }
 
 }  // namespace
@@ -320,11 +319,10 @@
 }
 
 void SharedWorkerHost::AllowIndexedDB(const GURL& url,
-                                      const base::string16& name,
                                       base::OnceCallback<void(bool)> callback) {
   base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&AllowIndexedDBOnIOThread, url, name,
+      base::BindOnce(&AllowIndexedDBOnIOThread, url,
                      RenderProcessHost::FromID(process_id_)
                          ->GetBrowserContext()
                          ->GetResourceContext(),
diff --git a/content/browser/shared_worker/shared_worker_host.h b/content/browser/shared_worker/shared_worker_host.h
index 0bf7bba..bbb2b9df 100644
--- a/content/browser/shared_worker/shared_worker_host.h
+++ b/content/browser/shared_worker/shared_worker_host.h
@@ -101,9 +101,7 @@
 
   void AllowFileSystem(const GURL& url,
                        base::OnceCallback<void(bool)> callback);
-  void AllowIndexedDB(const GURL& url,
-                      const base::string16& name,
-                      base::OnceCallback<void(bool)> callback);
+  void AllowIndexedDB(const GURL& url, base::OnceCallback<void(bool)> callback);
 
   // Terminates the given worker, i.e. based on a UI action.
   void TerminateWorker();
diff --git a/content/browser/webrtc/webrtc_image_capture_browsertest.cc b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
index 183a04f..3dbe27b 100644
--- a/content/browser/webrtc/webrtc_image_capture_browsertest.cc
+++ b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
@@ -34,6 +34,7 @@
 #define MAYBE_GetTrackSettings GetTrackSettings
 #define MAYBE_ManipulateZoom DISABLED_ManipulateZoom
 #define MAYBE_ManipulateExposureTime DISABLED_ManipulateExposureTime
+#define MAYBE_ManipulateFocusDistance DISABLED_ManipulateFocusDistance
 #else
 #define MAYBE_GetPhotoCapabilities GetPhotoCapabilities
 #define MAYBE_GetPhotoSettings GetPhotoSettings
@@ -43,6 +44,7 @@
 #define MAYBE_GetTrackSettings GetTrackSettings
 #define MAYBE_ManipulateZoom ManipulateZoom
 #define MAYBE_ManipulateExposureTime ManipulateExposureTime
+#define MAYBE_ManipulateFocusDistance ManipulateFocusDistance
 #endif
 
 namespace {
@@ -235,6 +237,12 @@
   ASSERT_TRUE(RunImageCaptureTestCase("testManipulateExposureTime()"));
 }
 
+IN_PROC_BROWSER_TEST_P(WebRtcImageCaptureSucceedsBrowserTest,
+                       MAYBE_ManipulateFocusDistance) {
+  embedded_test_server()->StartAcceptingConnections();
+  ASSERT_TRUE(RunImageCaptureTestCase("testManipulateFocusDistance()"));
+}
+
 INSTANTIATE_TEST_CASE_P(
     ,  // Use no prefix, so that these get picked up when using
        // --gtest_filter=WebRtc*
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidImplTest.java
index d6c09a4b..a64517e 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidImplTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidImplTest.java
@@ -19,7 +19,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
-import org.chromium.base.test.util.DisabledTest;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_shell_apk.ContentShellActivity;
@@ -42,7 +42,7 @@
     @Test
     @MediumTest
     @Feature({"GPU"})
-    @DisabledTest(message = "crbug.com/899894")
+    @DisableIf.Build(sdk_is_less_than = 21, message = "crbug.com/899894")
     public void testTraceFileCreation() throws Exception {
         ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl("about:blank");
         mActivityTestRule.waitForActiveShellToBeDoneLoading();
@@ -76,8 +76,8 @@
     private class TestCallback<T> implements Callback<T> {
         @Override
         public void onResult(T result) {
-            mWasCalled.open();
             mResult = result;
+            mWasCalled.open();
         }
 
         public ConditionVariable mWasCalled = new ConditionVariable();
@@ -87,7 +87,6 @@
     @Test
     @MediumTest
     @Feature({"GPU"})
-    @DisabledTest(message = "crbug.com/899894")
     public void testGetKnownCategories() throws Exception {
         ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl("about:blank");
         mActivityTestRule.waitForActiveShellToBeDoneLoading();
@@ -108,7 +107,6 @@
     @Test
     @MediumTest
     @Feature({"GPU"})
-    @DisabledTest(message = "crbug.com/899894")
     public void testBufferUsage() throws Exception {
         ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl("about:blank");
         mActivityTestRule.waitForActiveShellToBeDoneLoading();
@@ -131,7 +129,7 @@
     @Test
     @MediumTest
     @Feature({"GPU"})
-    @DisabledTest(message = "crbug.com/899894")
+    @DisableIf.Build(sdk_is_less_than = 21, message = "crbug.com/899894")
     public void testStopCallbackAndCompression() throws Exception {
         ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl("about:blank");
         mActivityTestRule.waitForActiveShellToBeDoneLoading();
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 8d37f89..ca4b9259 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -346,7 +346,6 @@
 
 bool ContentBrowserClient::AllowWorkerIndexedDB(
     const GURL& url,
-    const base::string16& name,
     ResourceContext* context,
     const std::vector<GlobalFrameRoutingId>& render_frames) {
   return true;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 88dfe1d..14fa589 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -595,7 +595,6 @@
   // This is called on the IO thread.
   virtual bool AllowWorkerIndexedDB(
       const GURL& url,
-      const base::string16& name,
       ResourceContext* context,
       const std::vector<GlobalFrameRoutingId>& render_frames);
 
diff --git a/content/renderer/media/stream/audio_service_audio_processor_proxy.cc b/content/renderer/media/stream/audio_service_audio_processor_proxy.cc
index 2f40b05..584b46b3 100644
--- a/content/renderer/media/stream/audio_service_audio_processor_proxy.cc
+++ b/content/renderer/media/stream/audio_service_audio_processor_proxy.cc
@@ -102,12 +102,6 @@
     aec_dump_message_filter_->AddDelegate(this);
 }
 
-void AudioServiceAudioProcessorProxy::GetStats(AudioProcessorStats* out) {
-  // This is the old GetStats interface from webrtc::AudioProcessorInterface.
-  // It should not be in use by Chrome any longer.
-  NOTREACHED();
-}
-
 webrtc::AudioProcessorInterface::AudioProcessorStatistics
 AudioServiceAudioProcessorProxy::GetStats(bool has_remote_tracks) {
   base::AutoLock lock(stats_lock_);
diff --git a/content/renderer/media/stream/audio_service_audio_processor_proxy.h b/content/renderer/media/stream/audio_service_audio_processor_proxy.h
index 7f11062..29a9082 100644
--- a/content/renderer/media/stream/audio_service_audio_processor_proxy.h
+++ b/content/renderer/media/stream/audio_service_audio_processor_proxy.h
@@ -41,10 +41,6 @@
   // this method.
   void Stop();
 
-  // webrtc::AudioProcessorInterface implementation.
-  // This method is called on the libjingle thread.
-  void GetStats(AudioProcessorStats* stats) override;
-
   // This method is called on the libjingle thread.
   AudioProcessorStatistics GetStats(bool has_remote_tracks) override;
 
diff --git a/content/renderer/media/stream/local_media_stream_audio_source.cc b/content/renderer/media/stream/local_media_stream_audio_source.cc
index 58a617f5..378a97e 100644
--- a/content/renderer/media/stream/local_media_stream_audio_source.cc
+++ b/content/renderer/media/stream/local_media_stream_audio_source.cc
@@ -63,6 +63,16 @@
   if (source_)
     return true;
 
+  std::string str = base::StringPrintf(
+      "LocalMediaStreamAudioSource::EnsureSourceIsStarted. render_frame_id=%d"
+      ", channel_layout=%d, sample_rate=%d, buffer_size=%d"
+      ", session_id=%d, effects=%d. ",
+      consumer_render_frame_id_, device().input.channel_layout(),
+      device().input.sample_rate(), device().input.frames_per_buffer(),
+      device().session_id, device().input.effects());
+  WebRtcLogMessage(str);
+  DVLOG(1) << str;
+
   // Sanity-check that the consuming RenderFrame still exists. This is required
   // by AudioDeviceFactory.
   if (!RenderFrameImpl::FromRoutingID(consumer_render_frame_id_))
diff --git a/content/renderer/media/stream/media_stream_audio_processor.cc b/content/renderer/media/stream/media_stream_audio_processor.cc
index 73b055d..ce56851b 100644
--- a/content/renderer/media/stream/media_stream_audio_processor.cc
+++ b/content/renderer/media/stream/media_stream_audio_processor.cc
@@ -524,12 +524,6 @@
   DCHECK(render_thread_checker_.CalledOnValidThread());
 }
 
-void MediaStreamAudioProcessor::GetStats(AudioProcessorStats* stats) {
-  // This is the old GetStats interface from webrtc::AudioProcessorInterface.
-  // It should not be in use by Chrome any longer.
-  NOTREACHED();
-}
-
 webrtc::AudioProcessorInterface::AudioProcessorStatistics
 MediaStreamAudioProcessor::GetStats(bool has_remote_tracks) {
   AudioProcessorStatistics stats;
diff --git a/content/renderer/media/stream/media_stream_audio_processor.h b/content/renderer/media/stream/media_stream_audio_processor.h
index f105c48..c2f20035 100644
--- a/content/renderer/media/stream/media_stream_audio_processor.h
+++ b/content/renderer/media/stream/media_stream_audio_processor.h
@@ -134,10 +134,6 @@
   void OnPlayoutDataSourceChanged() override;
   void OnRenderThreadChanged() override;
 
-  // webrtc::AudioProcessorInterface implementation.
-  // This method is called on the libjingle thread.
-  void GetStats(AudioProcessorStats* stats) override;
-
   // This method is called on the libjingle thread.
   AudioProcessorStatistics GetStats(bool has_remote_tracks) override;
 
diff --git a/content/renderer/media/stream/media_stream_audio_processor_options.cc b/content/renderer/media/stream/media_stream_audio_processor_options.cc
index 56cc861..1fff770b 100644
--- a/content/renderer/media/stream/media_stream_audio_processor_options.cc
+++ b/content/renderer/media/stream/media_stream_audio_processor_options.cc
@@ -217,22 +217,4 @@
   }
 }
 
-void GetAudioProcessingStats(
-    AudioProcessing* audio_processing,
-    webrtc::AudioProcessorInterface::AudioProcessorStats* stats) {
-  // TODO(ivoc): Change the APM stats to use optional instead of default values.
-  auto apm_stats = audio_processing->GetStatistics();
-  stats->echo_return_loss = apm_stats.echo_return_loss.instant();
-  stats->echo_return_loss_enhancement =
-      apm_stats.echo_return_loss_enhancement.instant();
-  stats->aec_divergent_filter_fraction = apm_stats.divergent_filter_fraction;
-
-  stats->echo_delay_median_ms = apm_stats.delay_median;
-  stats->echo_delay_std_ms = apm_stats.delay_standard_deviation;
-
-  stats->residual_echo_likelihood = apm_stats.residual_echo_likelihood;
-  stats->residual_echo_likelihood_recent_max =
-      apm_stats.residual_echo_likelihood_recent_max;
-}
-
 }  // namespace content
diff --git a/content/renderer/media/stream/media_stream_audio_processor_options.h b/content/renderer/media/stream/media_stream_audio_processor_options.h
index ecaaf33..aee9bf3f 100644
--- a/content/renderer/media/stream/media_stream_audio_processor_options.h
+++ b/content/renderer/media/stream/media_stream_audio_processor_options.h
@@ -131,10 +131,6 @@
 void ConfigPreAmplifier(webrtc::AudioProcessing::Config* apm_config,
                         base::Optional<double> fixed_gain_factor);
 
-void GetAudioProcessingStats(
-    AudioProcessing* audio_processing,
-    webrtc::AudioProcessorInterface::AudioProcessorStats* stats);
-
 }  // namespace content
 
 #endif  // CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_AUDIO_PROCESSOR_OPTIONS_H_
diff --git a/content/renderer/media/stream/processed_local_audio_source.cc b/content/renderer/media/stream/processed_local_audio_source.cc
index 10622251..0bd3f4a 100644
--- a/content/renderer/media/stream/processed_local_audio_source.cc
+++ b/content/renderer/media/stream/processed_local_audio_source.cc
@@ -99,13 +99,15 @@
     return false;
   }
 
-  WebRtcLogMessage(base::StringPrintf(
+  std::string str = base::StringPrintf(
       "ProcessedLocalAudioSource::EnsureSourceIsStarted. render_frame_id=%d"
       ", channel_layout=%d, sample_rate=%d, buffer_size=%d"
       ", session_id=%d, effects=%d. ",
       consumer_render_frame_id_, device().input.channel_layout(),
       device().input.sample_rate(), device().input.frames_per_buffer(),
-      device().session_id, device().input.effects()));
+      device().session_id, device().input.effects());
+  WebRtcLogMessage(str);
+  DVLOG(1) << str;
 
   MediaStreamDevice modified_device(device());
   bool device_is_modified = false;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 226250d..7280b6b 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1298,6 +1298,8 @@
 
   render_frame->render_widget_ = render_widget;
   render_frame->in_frame_tree_ = true;
+  render_frame->Initialize();
+
   return render_frame;
 }
 
@@ -1659,8 +1661,6 @@
       g_routing_id_frame_map.Get().insert(std::make_pair(routing_id_, this));
   CHECK(result.second) << "Inserting a duplicate item.";
 
-  RenderThread::Get()->AddRoute(routing_id_, this);
-
   // Everything below subclasses RenderFrameObserver and is automatically
   // deleted when the RenderFrame gets deleted.
 #if defined(OS_ANDROID)
@@ -1780,6 +1780,10 @@
     enabled_bindings_ |= BINDINGS_POLICY_STATS_COLLECTION;
   if (base::FeatureList::IsEnabled(network::features::kNetworkService))
     frame_request_blocker_ = base::MakeRefCounted<FrameRequestBlocker>();
+
+  // Bind this frame and the message router. This must be called after |frame_|
+  // is set since binding requires a per-frame task runner.
+  RenderThread::Get()->AddRoute(routing_id_, this);
 }
 
 void RenderFrameImpl::InitializeBlameContext(RenderFrameImpl* parent_frame) {
@@ -2141,9 +2145,8 @@
     const service_manager::BindSourceInfo& browser_info,
     mojom::FrameRequest request) {
   browser_info_ = browser_info;
-  frame_binding_.Bind(
-      std::move(request),
-      frame_ ? GetTaskRunner(blink::TaskType::kInternalIPC) : nullptr);
+  frame_binding_.Bind(std::move(request),
+                      GetTaskRunner(blink::TaskType::kInternalIPC));
 }
 
 void RenderFrameImpl::BindFrameBindingsControl(
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index dde4120a..a6894ce 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -541,8 +541,6 @@
         GetWidget()->GetWebScreenInfo(), GetWidget()->compositor_deps(),
         opener_frame, params->devtools_main_frame_token,
         params->replicated_frame_state, params->has_committed_real_load);
-
-    main_render_frame_->Initialize();
   } else {
     CHECK(params->swapped_out);
     RenderFrameProxy::CreateFrameProxy(params->proxy_routing_id, GetRoutingID(),
diff --git a/content/shell/test_runner/mock_web_document_subresource_filter.cc b/content/shell/test_runner/mock_web_document_subresource_filter.cc
index 96fa966..d03f62f5 100644
--- a/content/shell/test_runner/mock_web_document_subresource_filter.cc
+++ b/content/shell/test_runner/mock_web_document_subresource_filter.cc
@@ -50,8 +50,4 @@
   return true;
 }
 
-bool MockWebDocumentSubresourceFilter::GetIsAssociatedWithAdSubframe() const {
-  return false;
-}
-
 }  // namespace test_runner
diff --git a/content/shell/test_runner/mock_web_document_subresource_filter.h b/content/shell/test_runner/mock_web_document_subresource_filter.h
index bd7ec96..6ae65b56 100644
--- a/content/shell/test_runner/mock_web_document_subresource_filter.h
+++ b/content/shell/test_runner/mock_web_document_subresource_filter.h
@@ -32,7 +32,6 @@
       const blink::WebURL& url) override;
   void ReportDisallowedLoad() override;
   bool ShouldLogToConsole() override;
-  bool GetIsAssociatedWithAdSubframe() const override;
 
  private:
   LoadPolicy getLoadPolicyImpl(const blink::WebURL& url);
diff --git a/content/test/data/media/image_capture_test.html b/content/test/data/media/image_capture_test.html
index d73c5aa..23cdff3 100644
--- a/content/test/data/media/image_capture_test.html
+++ b/content/test/data/media/image_capture_test.html
@@ -271,6 +271,68 @@
         });
 }
 
+// Tries to read, set and read back the focusDistance capability if available.
+function testManipulateFocusDistance() {
+    var newFocusDistance = -1;
+    var imageCapturer;
+    var focusDistanceTolerance;
+    navigator.mediaDevices.getUserMedia({"video": CONSTRAINTS})
+        .then(stream => {
+            assertEquals('video', stream.getVideoTracks()[0].kind);
+            return new ImageCapture(stream.getVideoTracks()[0]);
+        })
+        .then(capturer => {
+            imageCapturer = capturer;
+            // TODO(mcasas): Before accesing synchronous track APIs we need a delay,
+            // use instead a round trip of capabilities: https://crbug.com/711524.
+            return capturer.getPhotoCapabilities();
+        })
+        .then(capabilities => {
+            const trackCapabilities = imageCapturer.track.getCapabilities();
+            if (trackCapabilities.focusDistance === undefined) {
+                console.log('focusDistance not supported, skipping test');
+                reportTestSuccess();
+                return;
+            }
+
+            const currentFocusDistance = imageCapturer.track.getSettings().focusDistance;
+            newFocusDistance = currentFocusDistance + trackCapabilities.focusDistance
+                .step;
+            newFocusDistance = Math.min(newFocusDistance, trackCapabilities.focusDistance
+                .max);
+            console.log("Setting focusDistance from " + currentFocusDistance +
+                " to " +
+                newFocusDistance);
+            focusDistanceTolerance = trackCapabilities.focusDistance.step /
+                10;
+
+            currentFocusMode = imageCapturer.track.getSettings().focusMode;
+            console.log(" focusMode == " + currentFocusMode);
+            focusModeCapabilities = trackCapabilities.focusMode;
+            console.log(" focusModeCapabilities == " +
+                focusModeCapabilities);
+
+            return imageCapturer.track.applyConstraints({
+                advanced: [{
+                    focusMode: "manual",
+                    focusDistance: newFocusDistance
+                }]
+            });
+        })
+        .then(() => {
+            assertEquals(newFocusDistance,
+                imageCapturer.track.getConstraints().advanced[0].focusDistance
+            );
+            assertTrue(Math.abs(newFocusDistance - imageCapturer.track.getSettings()
+                    .focusDistance) <
+                focusDistanceTolerance);
+            reportTestSuccess();
+        })
+        .catch(err => {
+            return failTest(err.toString());
+        });
+}
+
 </script>
 </body>
 </html>
diff --git a/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc b/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc
index cbbb54229..11b64de 100644
--- a/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc
+++ b/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc
@@ -49,9 +49,9 @@
 const int kRenderFrameId = 24;
 const float kWaveFrequency = 440.f;
 const int kChannels = 1;
-const int kBuffers = 1000;
-const int kSampleFrequency = 44100;
-const int kSamplesPerBuffer = kSampleFrequency / 100;
+const int kBuffers = 100;
+const int kSampleFrequency = 8000;
+const int kSamplesPerBuffer = kSampleFrequency / 10;
 
 std::unique_ptr<media::AudioOutputStream::AudioSourceCallback>
 GetTestAudioSource() {
@@ -206,8 +206,7 @@
 };
 
 // It's flaky on the buildbot, http://crbug.com/761214.
-TEST_F(RendererAudioOutputStreamFactoryIntegrationTest,
-       DISABLED_StreamIntegrationTest) {
+TEST_F(RendererAudioOutputStreamFactoryIntegrationTest, StreamIntegrationTest) {
   // Sets up the factory on the IO thread and runs client code on the UI thread.
   // Send a sine wave from the client and makes sure it's received by the output
   // stream.
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 61a27d9..6095ed1 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -200,6 +200,7 @@
       "contexts": ["webui"],
       "matches": [
         "chrome://cast/*",
+        "chrome://discards/*",
         "chrome://extensions-frame/*",
         "chrome://extensions/*",
         "chrome://home/*",
@@ -571,6 +572,7 @@
     "contexts": ["webui"],
     "matches": [
       "chrome://chrome-signin/*",
+      "chrome://discards/*",
       "chrome://home/*",
       "chrome://media-router/*",
       "chrome://mobilesetup/*",
@@ -588,6 +590,7 @@
     "contexts": ["webui"],
     "matches": [
       "chrome://chrome-signin/*",
+      "chrome://discards/*",
       "chrome://home/*",
       "chrome://media-router/*",
       "chrome://mobilesetup/*",
@@ -603,6 +606,7 @@
     "contexts": ["webui"],
     "matches": [
       "chrome://chrome-signin/*",
+      "chrome://discards/*",
       "chrome://home/*",
       "chrome://media-router/*",
       "chrome://mobilesetup/*",
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index 80d20165..087f5877 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -1048,6 +1048,13 @@
     gpu_tracer_.reset();
   }
 
+  if (!have_context) {
+    for (auto& fence : deschedule_until_finished_fences_) {
+      fence->Invalidate();
+    }
+  }
+  deschedule_until_finished_fences_.clear();
+
   // Destroy the surface before the context, some surface destructors make GL
   // calls.
   surface_ = nullptr;
@@ -1461,10 +1468,12 @@
 }
 
 bool GLES2DecoderPassthroughImpl::HasPollingWork() const {
-  return false;
+  return deschedule_until_finished_fences_.size() >= 2;
 }
 
-void GLES2DecoderPassthroughImpl::PerformPollingWork() {}
+void GLES2DecoderPassthroughImpl::PerformPollingWork() {
+  ProcessDescheduleUntilFinished();
+}
 
 bool GLES2DecoderPassthroughImpl::GetServiceTextureId(
     uint32_t client_texture_id,
@@ -2239,6 +2248,23 @@
   return error::kNoError;
 }
 
+void GLES2DecoderPassthroughImpl::ProcessDescheduleUntilFinished() {
+  if (deschedule_until_finished_fences_.size() < 2) {
+    return;
+  }
+  DCHECK_EQ(2u, deschedule_until_finished_fences_.size());
+
+  if (!deschedule_until_finished_fences_[0]->HasCompleted()) {
+    return;
+  }
+
+  TRACE_EVENT_ASYNC_END0(
+      "cc", "GLES2DecoderPassthroughImpl::DescheduleUntilFinished", this);
+  deschedule_until_finished_fences_.erase(
+      deschedule_until_finished_fences_.begin());
+  client_->OnRescheduleAfterFinished();
+}
+
 void GLES2DecoderPassthroughImpl::UpdateTextureBinding(
     GLenum target,
     GLuint client_id,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
index 2cd798f..a987f08a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
@@ -435,6 +435,9 @@
 
   error::Error ProcessReadPixels(bool did_finish);
 
+  // Checks to see if the inserted fence has completed.
+  void ProcessDescheduleUntilFinished();
+
   void UpdateTextureBinding(GLenum target,
                             GLuint client_id,
                             TexturePassthrough* texture);
@@ -833,6 +836,11 @@
 
   std::unique_ptr<DCLayerSharedState> dc_layer_shared_state_;
 
+  // After a second fence is inserted, both the GpuChannelMessageQueue and
+  // CommandExecutor are descheduled. Once the first fence has completed, both
+  // get rescheduled.
+  std::vector<std::unique_ptr<gl::GLFence>> deschedule_until_finished_fences_;
+
   base::WeakPtrFactory<GLES2DecoderPassthroughImpl> weak_ptr_factory_;
 
 // Include the prototypes of all the doer functions from a separate header to
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index a77b7d72..146aa75 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -4324,8 +4324,26 @@
 }
 
 error::Error GLES2DecoderPassthroughImpl::DoDescheduleUntilFinishedCHROMIUM() {
-  NOTIMPLEMENTED();
-  return error::kNoError;
+  if (!gl::GLFence::IsSupported()) {
+    return error::kNoError;
+  }
+  deschedule_until_finished_fences_.push_back(gl::GLFence::Create());
+
+  if (deschedule_until_finished_fences_.size() == 1) {
+    return error::kNoError;
+  }
+
+  DCHECK_EQ(2u, deschedule_until_finished_fences_.size());
+  if (deschedule_until_finished_fences_[0]->HasCompleted()) {
+    deschedule_until_finished_fences_.erase(
+        deschedule_until_finished_fences_.begin());
+    return error::kNoError;
+  }
+
+  TRACE_EVENT_ASYNC_BEGIN0(
+      "cc", "GLES2DecoderPassthroughImpl::DescheduleUntilFinished", this);
+  client_->OnDescheduleUntilFinished();
+  return error::kDeferLaterCommands;
 }
 
 error::Error GLES2DecoderPassthroughImpl::DoInsertFenceSyncCHROMIUM(
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 939b5b5..58a5bdb 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -39,7 +39,6 @@
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/gl_context_virtual.h"
-#include "gpu/command_buffer/service/gl_state_restorer_impl.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_command_buffer_memory_tracker.h"
 #include "gpu/command_buffer/service/gpu_fence_manager.h"
@@ -584,9 +583,6 @@
                       "Could not make context current.";
         return gpu::ContextResult::kTransientFailure;
       }
-
-      context_->SetGLStateRestorer(
-          new GLStateRestorerImpl(decoder_->AsWeakPtr()));
     } else {
       context_ = real_context;
       DCHECK(context_->IsCurrent(surface_.get()));
diff --git a/gpu/ipc/service/raster_command_buffer_stub.cc b/gpu/ipc/service/raster_command_buffer_stub.cc
index 5e88dcd..06cdafd 100644
--- a/gpu/ipc/service/raster_command_buffer_stub.cc
+++ b/gpu/ipc/service/raster_command_buffer_stub.cc
@@ -15,7 +15,6 @@
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/service/gl_context_virtual.h"
-#include "gpu/command_buffer/service/gl_state_restorer_impl.h"
 #include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/logger.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
@@ -162,8 +161,6 @@
                     "Failed to initialize virtual GL context.";
       return gpu::ContextResult::kFatalFailure;
     }
-
-    context->SetGLStateRestorer(new GLStateRestorerImpl(decoder->AsWeakPtr()));
   }
 
   if (!context->MakeCurrent(surface_.get())) {
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 8d0fdc47..b938d90 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -1860,15 +1860,10 @@
 
     # Code coverage reports generation bots.
     builders {
-      name: "linux-code-coverage-builder"
+      name: "linux-code-coverage"
       mixins: "code-coverage"
       dimensions: "cores:32"
     }
-    builders {
-      name: "linux-code-coverage-tester"
-      mixins: "code-coverage"
-      dimensions: "cores:8"
-    }
 
     builders {
       name: "mac-code-coverage-generation"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index bbb9c774..65a3fa7 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -2460,14 +2460,9 @@
     category: "closure_compilation"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/linux-code-coverage-builder"
-    category: "code_coverage|linux"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/linux-code-coverage-tester"
-    category: "code_coverage|linux"
-    short_name: "tst"
+    name: "buildbucket/luci.chromium.ci/linux-code-coverage"
+    category: "code_coverage"
+    short_name: "lnx"
   }
   builders {
     name: "buildbucket/luci.chromium.ci/mac-code-coverage-generation"
@@ -2816,14 +2811,9 @@
     category: "closure_compilation"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/linux-code-coverage-builder"
-    category: "code_coverage|linux"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/linux-code-coverage-tester"
-    category: "code_coverage|linux"
-    short_name: "tst"
+    name: "buildbucket/luci.chromium.ci/linux-code-coverage"
+    category: "code_coverage"
+    short_name: "lnx"
   }
   builders {
     name: "buildbucket/luci.chromium.ci/mac-code-coverage-generation"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index cce2ec4..a4a58db 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -310,7 +310,7 @@
   triggers: "linux-chromeos-dbg"
   triggers: "linux-chromeos-rel"
   triggers: "linux-chromium-tests-staging-builder"
-  triggers: "linux-code-coverage-builder"
+  triggers: "linux-code-coverage"
   triggers: "linux-dbg"
   triggers: "linux-gcc-rel"
   triggers: "linux-jumbo-rel"
@@ -1561,23 +1561,12 @@
 }
 
 job {
-  id: "linux-code-coverage-builder"
+  id: "linux-code-coverage"
   acl_sets: "default"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
     bucket: "luci.chromium.ci"
-    builder: "linux-code-coverage-builder"
-  }
-}
-
-job {
-  id: "linux-code-coverage-tester"
-  # Triggered by "linux-code-coverage-buidler".
-  acl_sets: "triggered-by-parent-builders"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "linux-code-coverage-tester"
+    builder: "linux-code-coverage"
   }
 }
 
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index b6f5a5c..d6b1a48 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -120,6 +120,7 @@
     "//ios/chrome/browser/app_launcher:feature_flags",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browsing_data:feature_flags",
+    "//ios/chrome/browser/crash_report:flags",
     "//ios/chrome/browser/download",
     "//ios/chrome/browser/drag_and_drop",
     "//ios/chrome/browser/itunes_urls",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 745e175..02aab7062 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -45,6 +45,7 @@
 #include "ios/chrome/browser/app_launcher/app_launcher_flags.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #include "ios/chrome/browser/chrome_switches.h"
+#include "ios/chrome/browser/crash_report/crash_report_flags.h"
 #include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
 #include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
 #include "ios/chrome/browser/itunes_urls/itunes_urls_flag.h"
@@ -421,6 +422,11 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(kIconForSearchButtonFeature,
                                     kIconForSearchButtonVariations,
                                     "ToggleSearchButtonIcon")},
+    {"enable-breakpad-upload-no-delay",
+     flag_descriptions::kBreakpadNoDelayInitialUploadName,
+     flag_descriptions::kBreakpadNoDelayInitialUploadDescription,
+     flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(crash_report::kBreakpadNoDelayInitialUpload)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/crash_report/BUILD.gn b/ios/chrome/browser/crash_report/BUILD.gn
index 6babb985..261f4fc5 100644
--- a/ios/chrome/browser/crash_report/BUILD.gn
+++ b/ios/chrome/browser/crash_report/BUILD.gn
@@ -17,6 +17,7 @@
   configs += [ "//build/config/compiler:enable_arc" ]
 
   deps = [
+    ":flags",
     "//base",
     "//components/crash/core/common",
     "//components/upload_list",
@@ -26,6 +27,16 @@
   ]
 }
 
+source_set("flags") {
+  sources = [
+    "crash_report_flags.cc",
+    "crash_report_flags.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
 source_set("crash_report_internal") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
diff --git a/ios/chrome/browser/crash_report/breakpad_helper.mm b/ios/chrome/browser/crash_report/breakpad_helper.mm
index bad7d20..ed2a942 100644
--- a/ios/chrome/browser/crash_report/breakpad_helper.mm
+++ b/ios/chrome/browser/crash_report/breakpad_helper.mm
@@ -4,7 +4,7 @@
 
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
 
-#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
 #include <stddef.h>
 
 #include "base/auto_reset.h"
@@ -19,6 +19,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/post_task.h"
 #include "ios/chrome/browser/chrome_paths.h"
+#include "ios/chrome/browser/crash_report/crash_report_flags.h"
 #import "ios/chrome/browser/crash_report/crash_report_user_application_state.h"
 
 // TODO(stuartmorgan): Move this up where it belongs once
@@ -154,6 +155,14 @@
 }
 
 void SetUploadingEnabled(bool enabled) {
+  if (enabled &&
+      [UIApplication sharedApplication].applicationState ==
+          UIApplicationStateInactive &&
+      !base::FeatureList::IsEnabled(
+          crash_report::kBreakpadNoDelayInitialUpload)) {
+    return;
+  }
+
   CacheUploadingEnabled(g_crash_reporter_enabled && enabled);
 
   if (!g_crash_reporter_enabled)
diff --git a/ios/chrome/browser/crash_report/crash_report_flags.cc b/ios/chrome/browser/crash_report/crash_report_flags.cc
new file mode 100644
index 0000000..b30b56cf
--- /dev/null
+++ b/ios/chrome/browser/crash_report/crash_report_flags.cc
@@ -0,0 +1,12 @@
+// 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 "ios/chrome/browser/crash_report/crash_report_flags.h"
+
+namespace crash_report {
+
+const base::Feature kBreakpadNoDelayInitialUpload{
+    "BreakpadNoDelayInitialUpload", base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace crash_report
diff --git a/ios/chrome/browser/crash_report/crash_report_flags.h b/ios/chrome/browser/crash_report/crash_report_flags.h
new file mode 100644
index 0000000..2c95022
--- /dev/null
+++ b/ios/chrome/browser/crash_report/crash_report_flags.h
@@ -0,0 +1,16 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_CRASH_REPORT_CRASH_REPORT_FLAGS_H_
+#define IOS_CHROME_BROWSER_CRASH_REPORT_CRASH_REPORT_FLAGS_H_
+
+#include "base/feature_list.h"
+
+namespace crash_report {
+
+extern const base::Feature kBreakpadNoDelayInitialUpload;
+
+}  // namespace crash_report
+
+#endif  // IOS_CHROME_BROWSER_CRASH_REPORT_CRASH_REPORT_FLAGS_H_
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index d1a6b50..b5d258c 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -34,6 +34,13 @@
     "When enabled, shows the Google Pay logo animation when showing payments"
     "credit card suggestions in downstream keyboard accessory";
 
+extern const char kBreakpadNoDelayInitialUploadName[] =
+    "Remove delay on initial crash upload";
+extern const char kBreakpadNoDelayInitialUploadDescription[] =
+    "When enabled, the initial crash uploading will not be delayed. When "
+    "disabled, initial upload is delayed until deferred initialization. This "
+    "does not affect recovery mode.";
+
 const char kEnableAutofillCreditCardUploadUpdatePromptExplanationName[] =
     "Enable updated prompt explanation when offering credit card upload";
 const char kEnableAutofillCreditCardUploadUpdatePromptExplanationDescription[] =
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 0431b0e..c77f1d7 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -24,6 +24,11 @@
 extern const char kAutofillDownstreamUseGooglePayBrandingOniOSName[];
 extern const char kAutofillDownstreamUseGooglePayBrandingOniOSDescription[];
 
+// Title and description for the flag to control if initial uploading of crash
+// reports is delayed.
+extern const char kBreakpadNoDelayInitialUploadName[];
+extern const char kBreakpadNoDelayInitialUploadDescription[];
+
 // Title and description for the flag to control the updated prompt explanation
 // when offering credit card upload.
 extern const char kEnableAutofillCreditCardUploadUpdatePromptExplanationName[];
diff --git a/ios/chrome/browser/ui/infobars/infobar_egtest.mm b/ios/chrome/browser/ui/infobars/infobar_egtest.mm
index b59d5a2..f5c46353 100644
--- a/ios/chrome/browser/ui/infobars/infobar_egtest.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_egtest.mm
@@ -45,25 +45,21 @@
   return nullptr;
 }
 
-// Adds a TestInfoBar to the current tab.
-bool AddTestInfoBarToCurrentTab() {
+// Adds a TestInfoBar with |message| to the current tab.
+bool AddTestInfoBarToCurrentTabWithMessage(NSString* message) {
   infobars::InfoBarManager* manager = GetCurrentInfoBarManager();
-  return TestInfoBarDelegate::Create(manager);
+  TestInfoBarDelegate* test_infobar_delegate = new TestInfoBarDelegate(message);
+  return test_infobar_delegate->Create(manager);
 }
 
-// Verifies that a single TestInfoBar is either present or absent on the current
-// tab.
-void VerifyTestInfoBarVisibleForCurrentTab(bool visible) {
-  // Expected values.
-  bool expected_count = visible ? 1U : 0U;
+// Verifies that a single TestInfoBar with |message| is either present or absent
+// on the current tab.
+void VerifyTestInfoBarVisibleForCurrentTab(bool visible, NSString* message) {
   id<GREYMatcher> expected_visibility =
       visible ? grey_sufficientlyVisible() : grey_notVisible();
   NSString* condition_name =
       visible ? @"Waiting for infobar to show" : @"Waiting for infobar to hide";
 
-  infobars::InfoBarManager* manager = GetCurrentInfoBarManager();
-  GREYAssertEqual(expected_count, manager->infobar_count(),
-                  @"Incorrect number of infobars.");
   [[GREYCondition
       conditionWithName:condition_name
                   block:^BOOL {
@@ -71,13 +67,20 @@
                     [[EarlGrey
                         selectElementWithMatcher:
                             chrome_test_util::StaticTextWithAccessibilityLabel(
-                                base::SysUTF8ToNSString(kTestInfoBarTitle))]
-                        assertWithMatcher:expected_visibility
-                                    error:&error];
+                                message)] assertWithMatcher:expected_visibility
+                                                      error:&error];
                     return error == nil;
                   }] waitWithTimeout:kTimeout];
 }
 
+// Verifies the number of Infobar currently in the InfobarManager (Thus in the
+// InfobarContainer) is |number_of_infobars|.
+void VerifyNumberOfInfobarsInManager(size_t number_of_infobars) {
+  infobars::InfoBarManager* manager = GetCurrentInfoBarManager();
+  GREYAssertEqual(number_of_infobars, manager->infobar_count(),
+                  @"Incorrect number of infobars.");
+}
+
 }  // namespace
 
 // Tests functionality related to infobars.
@@ -96,16 +99,21 @@
   [ChromeEarlGrey loadURL:testURL];
   [ChromeEarlGrey waitForMainTabCount:1];
 
+  // Infobar Message
+  NSString* infoBarMessage = @"TestInfoBar";
+
   // Add a test infobar to the current tab. Verify that the infobar is present
   // in the model and that the infobar view is visible on screen.
-  GREYAssert(AddTestInfoBarToCurrentTab(),
+  GREYAssert(AddTestInfoBarToCurrentTabWithMessage(infoBarMessage),
              @"Failed to add infobar to test tab.");
-  VerifyTestInfoBarVisibleForCurrentTab(true);
+  VerifyTestInfoBarVisibleForCurrentTab(true, infoBarMessage);
+  VerifyNumberOfInfobarsInManager(1);
 
   // Navigate to a different page.  Verify that the infobar is dismissed and no
   // longer visible on screen.
   [ChromeEarlGrey loadURL:GURL(url::kAboutBlankURL)];
-  VerifyTestInfoBarVisibleForCurrentTab(false);
+  VerifyTestInfoBarVisibleForCurrentTab(false, infoBarMessage);
+  VerifyNumberOfInfobarsInManager(0);
 }
 
 // Tests that page infobars persist only on the tabs they are opened on, and
@@ -121,18 +129,24 @@
   [ChromeEarlGrey loadURL:destinationURL];
   [ChromeEarlGrey waitForMainTabCount:1];
 
+  // Infobar Message
+  NSString* infoBarMessage = @"TestInfoBar";
+
   // Create the second tab, navigate to the test page, and add the test infobar.
   chrome_test_util::OpenNewTab();
   [ChromeEarlGrey loadURL:ponyURL];
   [ChromeEarlGrey waitForMainTabCount:2];
-  VerifyTestInfoBarVisibleForCurrentTab(false);
-  GREYAssert(AddTestInfoBarToCurrentTab(),
+  VerifyTestInfoBarVisibleForCurrentTab(false, infoBarMessage);
+  VerifyNumberOfInfobarsInManager(0);
+  GREYAssert(AddTestInfoBarToCurrentTabWithMessage(infoBarMessage),
              @"Failed to add infobar to second tab.");
-  VerifyTestInfoBarVisibleForCurrentTab(true);
+  VerifyTestInfoBarVisibleForCurrentTab(true, infoBarMessage);
+  VerifyNumberOfInfobarsInManager(1);
 
   // Switch back to the first tab and make sure no infobar is visible.
   chrome_test_util::SelectTabAtIndexInCurrentMode(0U);
-  VerifyTestInfoBarVisibleForCurrentTab(false);
+  VerifyTestInfoBarVisibleForCurrentTab(false, infoBarMessage);
+  VerifyNumberOfInfobarsInManager(0);
 
   // Navigate to a different URL in the first tab, to verify that this
   // navigation does not hide the infobar in the second tab.
@@ -142,7 +156,117 @@
   // infobar is visible.
   chrome_test_util::CloseCurrentTab();
   [ChromeEarlGrey waitForMainTabCount:1];
-  VerifyTestInfoBarVisibleForCurrentTab(true);
+  VerifyTestInfoBarVisibleForCurrentTab(true, infoBarMessage);
+  VerifyNumberOfInfobarsInManager(1);
+}
+
+// Tests that the Infobar dissapears once the "OK" button is tapped.
+- (void)testInfobarButtonDismissal {
+  web::test::SetUpFileBasedHttpServer();
+
+  // Open a new tab and navigate to the test page.
+  const GURL testURL = web::test::HttpServer::MakeUrl(
+      "http://ios/testing/data/http_server_files/pony.html");
+  [ChromeEarlGrey loadURL:testURL];
+  [ChromeEarlGrey waitForMainTabCount:1];
+
+  // Infobar Message
+  NSString* infoBarMessage = @"TestInfoBar";
+
+  // Add a test infobar to the current tab. Verify that the infobar is present
+  // in the model and that the infobar view is visible on screen.
+  GREYAssert(AddTestInfoBarToCurrentTabWithMessage(infoBarMessage),
+             @"Failed to add infobar to test tab.");
+  VerifyTestInfoBarVisibleForCurrentTab(true, infoBarMessage);
+  VerifyNumberOfInfobarsInManager(1);
+
+  // Tap on "OK" which should dismiss the Infobar.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(grey_buttonTitle(@"OK"),
+                                          grey_sufficientlyVisible(), nil)]
+      performAction:grey_tap()];
+  VerifyTestInfoBarVisibleForCurrentTab(false, infoBarMessage);
+  VerifyNumberOfInfobarsInManager(0);
+}
+
+// Tests adding an Infobar on top of an existing one.
+- (void)testInfobarTopMostVisible {
+  web::test::SetUpFileBasedHttpServer();
+
+  // Open a new tab and navigate to the test page.
+  const GURL testURL = web::test::HttpServer::MakeUrl(
+      "http://ios/testing/data/http_server_files/pony.html");
+  [ChromeEarlGrey loadURL:testURL];
+  [ChromeEarlGrey waitForMainTabCount:1];
+
+  // First Infobar Message
+  NSString* firstInfoBarMessage = @"TestFirstInfoBar";
+
+  // Add a test infobar to the current tab. Verify that the infobar is present
+  // in the model and that the infobar view is visible on screen.
+  GREYAssert(AddTestInfoBarToCurrentTabWithMessage(firstInfoBarMessage),
+             @"Failed to add infobar to test tab.");
+  VerifyTestInfoBarVisibleForCurrentTab(true, firstInfoBarMessage);
+  VerifyNumberOfInfobarsInManager(1);
+
+  // Second Infobar Message
+  NSString* secondInfoBarMessage = @"TestSecondInfoBar";
+
+  // Add a second test infobar to the current tab. Verify that the infobar is
+  // present in the model, and that only this second infobar is now visible on
+  // screen.
+  GREYAssert(AddTestInfoBarToCurrentTabWithMessage(secondInfoBarMessage),
+             @"Failed to add infobar to test tab.");
+  VerifyTestInfoBarVisibleForCurrentTab(true, secondInfoBarMessage);
+  VerifyTestInfoBarVisibleForCurrentTab(false, firstInfoBarMessage);
+  VerifyNumberOfInfobarsInManager(2);
+}
+
+// Tests that adding an Infobar of lower height on top of a taller Infobar only
+// displays the top shorter one, and that after dismissing the shorter Infobar
+// the taller infobar is now completely displayed again.
+- (void)testInfobarTopMostVisibleHeight {
+  web::test::SetUpFileBasedHttpServer();
+
+  // Open a new tab and navigate to the test page.
+  const GURL testURL = web::test::HttpServer::MakeUrl(
+      "http://ios/testing/data/http_server_files/pony.html");
+  [ChromeEarlGrey loadURL:testURL];
+  [ChromeEarlGrey waitForMainTabCount:1];
+
+  // First Infobar Message
+  NSString* firstInfoBarMessage =
+      @"This is a really long message that will cause this infobar height to "
+      @"increase since Confirm Infobar heights changes depending on its "
+      @"message.";
+
+  // Add a test infobar to the current tab. Verify that the infobar is present
+  // in the model and that the infobar view is visible on screen.
+  GREYAssert(AddTestInfoBarToCurrentTabWithMessage(firstInfoBarMessage),
+             @"Failed to add infobar to test tab.");
+  VerifyTestInfoBarVisibleForCurrentTab(true, firstInfoBarMessage);
+  VerifyNumberOfInfobarsInManager(1);
+
+  // Second Infobar Message
+  NSString* secondInfoBarMessage = @"TestSecondInfoBar";
+
+  // Add a second test infobar to the current tab. Verify that the infobar is
+  // present in the model, and that only this second infobar is now visible on
+  // screen.
+  GREYAssert(AddTestInfoBarToCurrentTabWithMessage(secondInfoBarMessage),
+             @"Failed to add infobar to test tab.");
+  VerifyTestInfoBarVisibleForCurrentTab(true, secondInfoBarMessage);
+  VerifyTestInfoBarVisibleForCurrentTab(false, firstInfoBarMessage);
+  VerifyNumberOfInfobarsInManager(2);
+
+  // Dismiss the second Infobar.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(grey_buttonTitle(@"OK"),
+                                          grey_sufficientlyVisible(), nil)]
+      performAction:grey_tap()];
+  VerifyTestInfoBarVisibleForCurrentTab(false, secondInfoBarMessage);
+  VerifyTestInfoBarVisibleForCurrentTab(true, firstInfoBarMessage);
+  VerifyNumberOfInfobarsInManager(1);
 }
 
 @end
diff --git a/ios/chrome/browser/ui/infobars/test_infobar_delegate.h b/ios/chrome/browser/ui/infobars/test_infobar_delegate.h
index 7bce9228..023d8e0 100644
--- a/ios/chrome/browser/ui/infobars/test_infobar_delegate.h
+++ b/ios/chrome/browser/ui/infobars/test_infobar_delegate.h
@@ -5,22 +5,23 @@
 #ifndef IOS_CHROME_BROWSER_UI_INFOBARS_TEST_INFOBAR_DELEGATE_H_
 #define IOS_CHROME_BROWSER_UI_INFOBARS_TEST_INFOBAR_DELEGATE_H_
 
-#include "base/strings/utf_string_conversions.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 
-// The title of the test infobar.
-extern const char kTestInfoBarTitle[];
-
-// An infobar that displays a single line of text and no buttons.
+// An infobar that displays |infobar_message| and one button.
 class TestInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  static bool Create(infobars::InfoBarManager* infobar_manager);
+  explicit TestInfoBarDelegate(NSString* infobar_message);
+
+  bool Create(infobars::InfoBarManager* infobar_manager);
 
   // InfoBarDelegate implementation.
   InfoBarIdentifier GetIdentifier() const override;
   // ConfirmInfoBarDelegate implementation.
   base::string16 GetMessageText() const override;
   int GetButtons() const override;
+
+ private:
+  NSString* infobar_message_;
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_INFOBARS_TEST_INFOBAR_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/infobars/test_infobar_delegate.mm b/ios/chrome/browser/ui/infobars/test_infobar_delegate.mm
index 8166f9a..b3ac8034 100644
--- a/ios/chrome/browser/ui/infobars/test_infobar_delegate.mm
+++ b/ios/chrome/browser/ui/infobars/test_infobar_delegate.mm
@@ -4,18 +4,20 @@
 
 #import "ios/chrome/browser/ui/infobars/test_infobar_delegate.h"
 
+#include "base/strings/sys_string_conversions.h"
 #include "components/infobars/core/infobar.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-const char kTestInfoBarTitle[] = "TestInfoBar";
+TestInfoBarDelegate::TestInfoBarDelegate(NSString* infobar_message)
+    : infobar_message_(infobar_message) {}
 
 bool TestInfoBarDelegate::Create(infobars::InfoBarManager* infobar_manager) {
   DCHECK(infobar_manager);
   return !!infobar_manager->AddInfoBar(infobar_manager->CreateConfirmInfoBar(
-      std::unique_ptr<ConfirmInfoBarDelegate>(new TestInfoBarDelegate)));
+      std::unique_ptr<ConfirmInfoBarDelegate>(this)));
 }
 
 TestInfoBarDelegate::InfoBarIdentifier TestInfoBarDelegate::GetIdentifier()
@@ -24,7 +26,7 @@
 }
 
 base::string16 TestInfoBarDelegate::GetMessageText() const {
-  return base::ASCIIToUTF16(kTestInfoBarTitle);
+  return base::SysNSStringToUTF16(infobar_message_);
 }
 
 int TestInfoBarDelegate::GetButtons() const {
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
index 7c11caea..0180c8ec5 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.h"
 
+#include "base/ios/ios_util.h"
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "base/metrics/histogram_macros.h"
@@ -137,7 +138,21 @@
   if (!editing) {
     self.editingWithToolbarButtons = NO;
     if (self.needsSectionCleanupAfterEditing) {
-      [self removeEmptySections];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-variable"
+      // |removedSectionCount| is only used in iOS10, so unused variable
+      // warnings should be ignored in order to allow compilation until the
+      // iOS10 fix is removed.
+      NSUInteger removedSectionCount = [self removeEmptySections];
+#pragma clang diagnostic pop
+#if !defined(__IPHONE_11_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_11_0
+      // The swipe-to-delete gesture on iOS 10 erroneously attempts to reload
+      // deleted row's section upon completion of its animation, regardless of
+      // whether the row was the last in the section.  If the section was
+      // removed force a full table reload so that the updated model is used.
+      if (removedSectionCount && !base::ios::IsRunningOnIOS11OrLater())
+        [self.tableView reloadData];
+#endif
       self.needsSectionCleanupAfterEditing = NO;
     }
   }
@@ -860,10 +875,12 @@
   [self removeEmptySections];
 }
 
-// Removes the empty sections from the table and the model.
-- (void)removeEmptySections {
+// Removes the empty sections from the table and the model.  Returns the number
+// of removed sections.
+- (NSUInteger)removeEmptySections {
   UITableView* tableView = self.tableView;
   TableViewModel* model = self.tableViewModel;
+  __block NSUInteger removedSectionCount = 0;
   void (^updates)(void) = ^{
     SectionIdentifier sections[] = {SectionIdentifierRead,
                                     SectionIdentifierUnread};
@@ -878,6 +895,7 @@
         [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                  withRowAnimation:UITableViewRowAnimationFade];
         [model removeSectionWithIdentifier:section];
+        ++removedSectionCount;
       }
     }
   };
@@ -887,6 +905,8 @@
     [self tableIsEmpty];
   else
     [self updateToolbarItems];
+
+  return removedSectionCount;
 }
 
 // Resets self.editing to NO, optionally with animation.
diff --git a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
index e04e873..bf8d24bd 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
@@ -52,6 +52,9 @@
 const char kTextID[] = "textID";
 const char kPageLoadedString[] = "Page loaded!";
 
+// The title of the test infobar.
+NSString* kTestInfoBarTitle = @"TestInfoBar";
+
 // Defines the visibility of an element, in relation to the toolbar.
 typedef NS_ENUM(NSInteger, ButtonVisibility) {
   ButtonVisibilityNone,
@@ -190,7 +193,9 @@
 bool AddInfobar() {
   infobars::InfoBarManager* manager =
       InfoBarManagerImpl::FromWebState(chrome_test_util::GetCurrentWebState());
-  return TestInfoBarDelegate::Create(manager);
+  TestInfoBarDelegate* test_infobar_delegate =
+      new TestInfoBarDelegate(kTestInfoBarTitle);
+  return test_infobar_delegate->Create(manager);
 }
 
 // Rotate the device if it is an iPhone or change the trait collection to
@@ -577,7 +582,7 @@
                     [[EarlGrey
                         selectElementWithMatcher:
                             chrome_test_util::StaticTextWithAccessibilityLabel(
-                                base::SysUTF8ToNSString(kTestInfoBarTitle))]
+                                kTestInfoBarTitle)]
                         assertWithMatcher:grey_sufficientlyVisible()
                                     error:&error];
                     return error == nil;
diff --git a/ios/chrome/browser/web/error_page_util.mm b/ios/chrome/browser/web/error_page_util.mm
index b3cf9a7..a1b78ac 100644
--- a/ios/chrome/browser/web/error_page_util.mm
+++ b/ios/chrome/browser/web/error_page_util.mm
@@ -49,6 +49,7 @@
       /*can_show_network_diagnostics_dialog=*/false, is_off_the_record,
       error_page::LocalizedError::OfflineContentOnNetErrorFeatureState::
           kDisabled,
+      /*auto_fetch_feature_enabled=*/false,
       GetApplicationContext()->GetApplicationLocale(),
       /*params=*/nullptr, &error_strings);
 
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc
index 45287af..2728f080 100644
--- a/media/audio/android/audio_manager_android.cc
+++ b/media/audio/android/audio_manager_android.cc
@@ -126,6 +126,11 @@
     ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id);
     device_names->push_back(device);
   }
+
+  for (auto d : *device_names) {
+    DVLOG(1) << "device_name: " << d.device_name;
+    DVLOG(1) << "unique_id: " << d.unique_id;
+  }
 }
 
 void AudioManagerAndroid::GetAudioOutputDeviceNames(
@@ -148,8 +153,9 @@
       ChannelLayoutToChannelCount(channel_layout));
   buffer_size = buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size;
   int effects = AudioParameters::NO_EFFECTS;
-  effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ?
-      AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS;
+  effects |= Java_AudioManagerAndroid_acousticEchoCancelerIsAvailable(env)
+                 ? AudioParameters::ECHO_CANCELLER
+                 : AudioParameters::NO_EFFECTS;
 
   int user_buffer_size = GetUserBufferSize();
   if (user_buffer_size)
@@ -158,6 +164,7 @@
   AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
                          GetNativeOutputSampleRate(), buffer_size);
   params.set_effects(effects);
+  DVLOG(1) << params.AsHumanReadableString();
   return params;
 }
 
@@ -186,11 +193,13 @@
   AudioInputStream* stream = AudioManagerBase::MakeAudioInputStream(
       params, device_id, AudioManager::LogCallback());
 
-  // The audio manager for Android creates streams intended for real-time
-  // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION.
-  // If a Bluetooth headset is used, the audio stream will use the SCO
-  // channel and therefore have a limited bandwidth (8kHz).
-  if (stream && has_no_input_streams) {
+  // By default, the audio manager for Android creates streams intended for
+  // real-time VoIP sessions and therefore sets the audio mode to
+  // MODE_IN_COMMUNICATION. However, the user might have asked for a special
+  // mode where all audio input processing is disabled, and if that is the case
+  // we avoid changing the mode.
+  if (stream && has_no_input_streams &&
+      params.effects() != AudioParameters::NO_EFFECTS) {
     communication_mode_is_on_ = true;
     SetCommunicationAudioModeOn(true);
   }
@@ -209,7 +218,7 @@
 
   // Restore the audio mode which was used before the first communication-
   // mode stream was created.
-  if (HasNoAudioInputStreams()) {
+  if (HasNoAudioInputStreams() && communication_mode_is_on_) {
     communication_mode_is_on_ = false;
     SetCommunicationAudioModeOn(false);
   }
@@ -260,6 +269,7 @@
     const AudioParameters& params,
     const std::string& device_id,
     const LogCallback& log_callback) {
+  DVLOG(1) << "MakeLowLatencyInputStream: " << params.effects();
   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
   DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
   DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!";
@@ -273,14 +283,8 @@
     return NULL;
   }
 
-  if (params.effects() != AudioParameters::NO_EFFECTS) {
-    // Platform effects can only be enabled through the AudioRecord path.
-    // An effect should only have been requested here if recommended by
-    // AudioManagerAndroid#shouldUse...().
-    DVLOG(1) << "Creating AudioRecordInputStream";
-    return new AudioRecordInputStream(this, params);
-  }
-  DVLOG(1) << "Creating OpenSLESInputStream";
+  // Create a new audio input stream and enable or disable all audio effects
+  // given |params.effects()|.
   return new OpenSLESInputStream(this, params);
 }
 
@@ -320,6 +324,7 @@
 AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
     const std::string& output_device_id,
     const AudioParameters& input_params) {
+  DVLOG(1) << __FUNCTION__;
   // TODO(tommi): Support |output_device_id|.
   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
   DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
@@ -382,11 +387,13 @@
 }
 
 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) {
+  DVLOG(1) << __FUNCTION__ << ": " << on;
   Java_AudioManagerAndroid_setCommunicationAudioModeOn(
       base::android::AttachCurrentThread(), GetJavaAudioManager(), on);
 }
 
 bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
+  DVLOG(1) << __FUNCTION__ << ": " << device_id;
   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
 
   // Send the unique device ID to the Java audio manager and make the
diff --git a/media/audio/android/audio_record_input.cc b/media/audio/android/audio_record_input.cc
index 79176804..0c85bc4c 100644
--- a/media/audio/android/audio_record_input.cc
+++ b/media/audio/android/audio_record_input.cc
@@ -114,31 +114,25 @@
 }
 
 double AudioRecordInputStream::GetMaxVolume() {
-  NOTIMPLEMENTED();
   return 0.0;
 }
 
 void AudioRecordInputStream::SetVolume(double volume) {
-  NOTIMPLEMENTED();
 }
 
 double AudioRecordInputStream::GetVolume() {
-  NOTIMPLEMENTED();
   return 0.0;
 }
 
 bool AudioRecordInputStream::SetAutomaticGainControl(bool enabled) {
-  NOTIMPLEMENTED();
   return false;
 }
 
 bool AudioRecordInputStream::GetAutomaticGainControl() {
-  NOTIMPLEMENTED();
   return false;
 }
 
 bool AudioRecordInputStream::IsMuted() {
-  NOTIMPLEMENTED();
   return false;
 }
 
diff --git a/media/audio/android/opensles_input.cc b/media/audio/android/opensles_input.cc
index cd26504..5a06fd3 100644
--- a/media/audio/android/opensles_input.cc
+++ b/media/audio/android/opensles_input.cc
@@ -30,8 +30,10 @@
       active_buffer_index_(0),
       buffer_size_bytes_(0),
       started_(false),
-      audio_bus_(media::AudioBus::Create(params)) {
+      audio_bus_(media::AudioBus::Create(params)),
+      no_effects_(params.effects() == AudioParameters::NO_EFFECTS) {
   DVLOG(2) << __PRETTY_FUNCTION__;
+  DVLOG(1) << "Audio effects enabled: " << !no_effects_;
 
   const SampleFormat kSampleFormat = kSampleFormatS16;
 
@@ -164,31 +166,25 @@
 }
 
 double OpenSLESInputStream::GetMaxVolume() {
-  NOTIMPLEMENTED();
   return 0.0;
 }
 
 void OpenSLESInputStream::SetVolume(double volume) {
-  NOTIMPLEMENTED();
 }
 
 double OpenSLESInputStream::GetVolume() {
-  NOTIMPLEMENTED();
   return 0.0;
 }
 
 bool OpenSLESInputStream::SetAutomaticGainControl(bool enabled) {
-  NOTIMPLEMENTED();
   return false;
 }
 
 bool OpenSLESInputStream::GetAutomaticGainControl() {
-  NOTIMPLEMENTED();
   return false;
 }
 
 bool OpenSLESInputStream::IsMuted() {
-  NOTIMPLEMENTED();
   return false;
 }
 
@@ -257,8 +253,11 @@
                                      &recorder_config),
       false);
 
-  // Uses the main microphone tuned for audio communications.
-  SLint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
+  // Uses the main microphone tuned for audio communications if effects are
+  // enabled and disables all audio processing if effects are disabled.
+  SLint32 stream_type = no_effects_
+                            ? SL_ANDROID_RECORDING_PRESET_CAMCORDER
+                            : SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
   LOG_ON_FAILURE_AND_RETURN(
       (*recorder_config)->SetConfiguration(recorder_config,
                                            SL_ANDROID_KEY_RECORDING_PRESET,
diff --git a/media/audio/android/opensles_input.h b/media/audio/android/opensles_input.h
index f79e3ee..a3afed0e 100644
--- a/media/audio/android/opensles_input.h
+++ b/media/audio/android/opensles_input.h
@@ -105,6 +105,9 @@
 
   std::unique_ptr<media::AudioBus> audio_bus_;
 
+  // Set to true at construction if user wants to disable all audio effects.
+  const bool no_effects_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(OpenSLESInputStream);
 };
 
diff --git a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
index d6dc90e..fe320a26 100644
--- a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
+++ b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
@@ -98,22 +98,6 @@
         }
     }
 
-    // List if device models which have been vetted for good quality platform
-    // echo cancellation.
-    // NOTE: only add new devices to this list if manual tests have been
-    // performed where the AEC performance is evaluated using e.g. a WebRTC
-    // audio client such as https://apprtc.appspot.com/?r=<ROOM NAME>.
-    private static final String[] SUPPORTED_AEC_MODELS = new String[] {
-            "GT-I9300", // Galaxy S3
-            "GT-I9500", // Galaxy S4
-            "GT-N7105", // Galaxy Note 2
-            "Nexus 4", // Nexus 4
-            "Nexus 5", // Nexus 5
-            "Nexus 7", // Nexus 7
-            "SM-N9005", // Galaxy Note 3
-            "SM-T310", // Galaxy Tab 3 8.0 (WiFi)
-    };
-
     // Supported audio device types.
     private static final int DEVICE_DEFAULT = -2;
     private static final int DEVICE_INVALID = -1;
@@ -522,18 +506,7 @@
     }
 
     @CalledByNative
-    private static boolean shouldUseAcousticEchoCanceler() {
-        // Verify that this device is among the supported/tested models.
-        List<String> supportedModels = Arrays.asList(SUPPORTED_AEC_MODELS);
-        if (!supportedModels.contains(Build.MODEL)) {
-            return false;
-        }
-        if (DEBUG && AcousticEchoCanceler.isAvailable()) {
-            logd("Approved for use of hardware acoustic echo canceler.");
-        }
-
-        // As a final check, verify that the device supports acoustic echo
-        // cancellation.
+    private static boolean acousticEchoCancelerIsAvailable() {
         return AcousticEchoCanceler.isAvailable();
     }
 
diff --git a/media/capture/video/fake_video_capture_device.cc b/media/capture/video/fake_video_capture_device.cc
index 3ea1f3d..6788e97 100644
--- a/media/capture/video/fake_video_capture_device.cc
+++ b/media/capture/video/fake_video_capture_device.cc
@@ -46,6 +46,10 @@
 static const double kMaxExposureTime = 100.0;
 static const double kExposureTimeStep = 5.0;
 
+static const double kMinFocusDistance = 10.0;
+static const double kMaxFocusDistance = 100.0;
+static const double kFocusDistanceStep = 5.0;
+
 // Larger int means better.
 enum class PixelFormatMatchType : int {
   INCOMPATIBLE = 0,
@@ -466,7 +470,6 @@
   photo_state->supported_exposure_modes.push_back(
       mojom::MeteringMode::CONTINUOUS);
   photo_state->current_exposure_mode = fake_device_state_->exposure_mode;
-  photo_state->current_focus_mode = mojom::MeteringMode::NONE;
 
   photo_state->exposure_compensation = mojom::Range::New();
 
@@ -488,11 +491,15 @@
   photo_state->saturation = media::mojom::Range::New();
   photo_state->sharpness = media::mojom::Range::New();
 
+  photo_state->supported_focus_modes.push_back(mojom::MeteringMode::MANUAL);
+  photo_state->supported_focus_modes.push_back(mojom::MeteringMode::CONTINUOUS);
+  photo_state->current_focus_mode = fake_device_state_->focus_mode;
+
   photo_state->focus_distance = mojom::Range::New();
-  photo_state->focus_distance->current = 3.0;
-  photo_state->focus_distance->max = 5.0;
-  photo_state->focus_distance->min = 1.0;
-  photo_state->focus_distance->step = 1.0;
+  photo_state->focus_distance->current = fake_device_state_->focus_distance;
+  photo_state->focus_distance->max = kMaxFocusDistance;
+  photo_state->focus_distance->min = kMinFocusDistance;
+  photo_state->focus_distance->step = kFocusDistanceStep;
 
   photo_state->zoom = mojom::Range::New();
   photo_state->zoom->current = fake_device_state_->zoom;
@@ -540,8 +547,12 @@
     device_state_write_access->exposure_time = std::max(
         kMinExposureTime, std::min(settings->exposure_time, kMaxExposureTime));
   }
-  if (settings->has_exposure_mode)
-    device_state_write_access->exposure_mode = mojom::MeteringMode::MANUAL;
+
+  if (settings->has_focus_distance) {
+    device_state_write_access->focus_distance =
+        std::max(kMinFocusDistance,
+                 std::min(settings->focus_distance, kMaxFocusDistance));
+  }
 
   std::move(callback).Run(true);
 }
diff --git a/media/capture/video/fake_video_capture_device.h b/media/capture/video/fake_video_capture_device.h
index 81be3ea..164054d1 100644
--- a/media/capture/video/fake_video_capture_device.h
+++ b/media/capture/video/fake_video_capture_device.h
@@ -104,17 +104,24 @@
 struct FakeDeviceState {
   FakeDeviceState(float zoom,
                   float exposure_time,
-                  mojom::MeteringMode exposure_mode,
+                  float focus_distance,
                   float frame_rate,
                   VideoPixelFormat pixel_format)
       : zoom(zoom),
         exposure_time(exposure_time),
-        exposure_mode(exposure_mode),
-        format(gfx::Size(), frame_rate, pixel_format) {}
+        focus_distance(focus_distance),
+        format(gfx::Size(), frame_rate, pixel_format) {
+    exposure_mode = (exposure_time >= 0.0f) ? mojom::MeteringMode::MANUAL
+                                            : mojom::MeteringMode::CONTINUOUS;
+    focus_mode = (focus_distance >= 0.0f) ? mojom::MeteringMode::MANUAL
+                                          : mojom::MeteringMode::CONTINUOUS;
+  }
 
   uint32_t zoom;
   uint32_t exposure_time;
   mojom::MeteringMode exposure_mode;
+  uint32_t focus_distance;
+  mojom::MeteringMode focus_mode;
   VideoCaptureFormat format;
 };
 
diff --git a/media/capture/video/fake_video_capture_device_factory.cc b/media/capture/video/fake_video_capture_device_factory.cc
index 9ec17464..6f33ce384 100644
--- a/media/capture/video/fake_video_capture_device_factory.cc
+++ b/media/capture/video/fake_video_capture_device_factory.cc
@@ -37,8 +37,7 @@
 
 static const double kInitialZoom = 100.0;
 static const double kInitialExposureTime = 50.0;
-static const media::mojom::MeteringMode kExposureMode =
-    media::mojom::MeteringMode::MANUAL;
+static const double kInitialFocusDistance = 50.0;
 
 static const media::VideoPixelFormat kSupportedPixelFormats[] = {
     media::PIXEL_FORMAT_I420, media::PIXEL_FORMAT_Y16,
@@ -136,7 +135,7 @@
 
   const VideoCaptureFormat& initial_format = settings.supported_formats.front();
   auto device_state = std::make_unique<FakeDeviceState>(
-      kInitialZoom, kInitialExposureTime, kExposureMode,
+      kInitialZoom, kInitialExposureTime, kInitialFocusDistance,
       initial_format.frame_rate, initial_format.pixel_format);
 
   auto photo_frame_painter = std::make_unique<PacmanFramePainter>(
diff --git a/media/capture/video/fake_video_capture_device_unittest.cc b/media/capture/video/fake_video_capture_device_unittest.cc
index eb8b0be..330283f0 100644
--- a/media/capture/video/fake_video_capture_device_unittest.cc
+++ b/media/capture/video/fake_video_capture_device_unittest.cc
@@ -364,7 +364,7 @@
   ASSERT_TRUE(state);
   EXPECT_EQ(mojom::MeteringMode::NONE, state->current_white_balance_mode);
   EXPECT_EQ(mojom::MeteringMode::MANUAL, state->current_exposure_mode);
-  EXPECT_EQ(mojom::MeteringMode::NONE, state->current_focus_mode);
+  EXPECT_EQ(mojom::MeteringMode::MANUAL, state->current_focus_mode);
 
   EXPECT_EQ(0, state->exposure_compensation->min);
   EXPECT_EQ(0, state->exposure_compensation->max);
@@ -403,10 +403,10 @@
   EXPECT_FALSE(state->supports_torch);
   EXPECT_FALSE(state->torch);
 
-  EXPECT_EQ(1.0, state->focus_distance->min);
-  EXPECT_EQ(5.0, state->focus_distance->max);
-  EXPECT_EQ(3.0, state->focus_distance->current);
-  EXPECT_EQ(1.0, state->focus_distance->step);
+  EXPECT_EQ(10, state->focus_distance->min);
+  EXPECT_EQ(100, state->focus_distance->max);
+  EXPECT_EQ(50, state->focus_distance->current);
+  EXPECT_EQ(5, state->focus_distance->step);
 
   EXPECT_EQ(mojom::RedEyeReduction::NEVER, state->red_eye_reduction);
   EXPECT_EQ(capture_params.requested_format.frame_size.height(),
diff --git a/media/gpu/test/video_frame_validator.cc b/media/gpu/test/video_frame_validator.cc
index eda1cffc..5db02df 100644
--- a/media/gpu/test/video_frame_validator.cc
+++ b/media/gpu/test/video_frame_validator.cc
@@ -48,19 +48,29 @@
 VideoFrameValidator::~VideoFrameValidator() {}
 
 void VideoFrameValidator::EvaluateVideoFrame(
-    scoped_refptr<VideoFrame> video_frame) {
+    scoped_refptr<VideoFrame> video_frame,
+    size_t frame_index) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   std::string expected_md5;
-  LOG_IF(FATAL, frame_index_ >= md5_of_frames_.size())
+  LOG_IF(FATAL, frame_index >= md5_of_frames_.size())
       << "Frame number is over than the number of read md5 values in file.";
-  expected_md5 = md5_of_frames_[frame_index_];
+  expected_md5 = md5_of_frames_[frame_index];
 
-  std::string computed_md5 = ComputeMD5FromVideoFrame(std::move(video_frame));
+  auto standard_frame = CreateStandardizedFrame(video_frame);
+  if (!standard_frame) {
+    LOG(ERROR) << "Failed to create standardized frame.";
+    return;
+  }
+  std::string computed_md5 = ComputeMD5FromVideoFrame(standard_frame);
   if (computed_md5 != expected_md5) {
     mismatched_frames_.push_back(
-        MismatchedFrameInfo{frame_index_, computed_md5, expected_md5});
+        MismatchedFrameInfo{frame_index, computed_md5, expected_md5});
   }
-  frame_index_++;
+  if (!prefix_output_yuv_.empty()) {
+    // Output yuv.
+    LOG_IF(WARNING, !WriteI420ToFile(frame_index, standard_frame.get()))
+        << "Failed to write yuv into file.";
+  }
 }
 
 std::vector<VideoFrameValidator::MismatchedFrameInfo>
@@ -68,34 +78,27 @@
   return mismatched_frames_;
 }
 
-std::string VideoFrameValidator::ComputeMD5FromVideoFrame(
+scoped_refptr<VideoFrame> VideoFrameValidator::CreateStandardizedFrame(
     scoped_refptr<VideoFrame> video_frame) const {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   auto mapped_frame = video_frame_mapper_->Map(std::move(video_frame));
   if (!mapped_frame) {
     LOG(FATAL) << "Failed to map decoded picture.";
-    return std::string();
+    return nullptr;
   }
 
-  auto i420_frame = CreateI420Frame(mapped_frame.get());
-  if (!i420_frame) {
-    LOG(ERROR) << "Failed to convert to I420";
-    return std::string();
-  }
+  return CreateI420Frame(mapped_frame.get());
+}
 
+std::string VideoFrameValidator::ComputeMD5FromVideoFrame(
+    scoped_refptr<VideoFrame> video_frame) const {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   base::MD5Context context;
   base::MD5Init(&context);
-  VideoFrame::HashFrameForTesting(&context, i420_frame);
+  VideoFrame::HashFrameForTesting(&context, video_frame);
   base::MD5Digest digest;
   base::MD5Final(&digest, &context);
-  auto md5_string = MD5DigestToBase16(digest);
-
-  if (!prefix_output_yuv_.empty()) {
-    // Output yuv.
-    LOG_IF(WARNING, !WriteI420ToFile(frame_index_, i420_frame.get()))
-        << "Failed to write yuv into file.";
-  }
-  return md5_string;
+  return MD5DigestToBase16(digest);
 }
 
 scoped_refptr<VideoFrame> VideoFrameValidator::CreateI420Frame(
diff --git a/media/gpu/test/video_frame_validator.h b/media/gpu/test/video_frame_validator.h
index 6efb1c7..6dc9750c 100644
--- a/media/gpu/test/video_frame_validator.h
+++ b/media/gpu/test/video_frame_validator.h
@@ -55,10 +55,9 @@
   // This checks if |video_frame|'s pixel content is as expected.
   // A client of VideoFrameValidator would call this function on each frame in
   // PictureReady().
-  // The client MUST pass video frames in display order.
-  // TODO(crbug.com/856562): Specify frame index and compare the index-th video
-  // frame, so that a client can call this in any order.
-  void EvaluateVideoFrame(scoped_refptr<VideoFrame> video_frame);
+  // |frame_index| is the index of video frame in display order.
+  void EvaluateVideoFrame(scoped_refptr<VideoFrame> video_frame,
+                          size_t frame_index);
 
   // Returns information of frames that don't match golden md5 values.
   // If there is no mismatched frame, returns an empty vector.
@@ -69,13 +68,17 @@
                       std::vector<std::string> md5_of_frames,
                       std::unique_ptr<VideoFrameMapper> video_frame_mapper);
 
-  // This maps |video_frame|, converts it to I420 format and computes the MD5
-  // value of the converted I420 video frame.
+  // This maps |video_frame|, converts it to I420 format.
+  // Returns the resulted I420 frame on success, and otherwise return nullptr.
   // |video_frame| is unchanged in this method.
+  scoped_refptr<VideoFrame> CreateStandardizedFrame(
+      scoped_refptr<VideoFrame> video_frame) const;
+
+  // Returns md5 values of video frame represented by |video_frame|.
   std::string ComputeMD5FromVideoFrame(
       scoped_refptr<VideoFrame> video_frame) const;
 
-  // Create VideoFrame with I420 format from |src_frame|.
+  // Creates VideoFrame with I420 format from |src_frame|.
   scoped_refptr<VideoFrame> CreateI420Frame(
       const VideoFrame* const src_frame) const;
 
@@ -86,9 +89,6 @@
   // The results of invalid frame data.
   std::vector<MismatchedFrameInfo> mismatched_frames_;
 
-  // Current frame index to be evaluated.
-  size_t frame_index_ = 0;
-
   // Prefix of saved yuv files.
   const base::FilePath prefix_output_yuv_;
 
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc
index b78cc751..388205d3f 100644
--- a/media/gpu/video_decode_accelerator_unittest.cc
+++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -365,6 +365,7 @@
   size_t num_queued_fragments_;
   size_t num_decoded_frames_;
   size_t num_done_bitstream_buffers_;
+  size_t frame_index_;
   base::TimeTicks initialize_done_ticks_;
   GLenum texture_target_;
   VideoPixelFormat pixel_format_;
@@ -426,6 +427,7 @@
       num_queued_fragments_(0),
       num_decoded_frames_(0),
       num_done_bitstream_buffers_(0),
+      frame_index_(0),
       texture_target_(0),
       pixel_format_(PIXEL_FORMAT_UNKNOWN),
       next_picture_buffer_id_(1),
@@ -604,7 +606,9 @@
   if (video_frame_validator_) {
     auto video_frame = texture_it->second->CreateVideoFrame(visible_rect);
     ASSERT_NE(video_frame.get(), nullptr);
-    video_frame_validator_->EvaluateVideoFrame(std::move(video_frame));
+    video_frame_validator_->EvaluateVideoFrame(std::move(video_frame),
+                                               frame_index_);
+    frame_index_++;
   }
   rendering_helper_->ConsumeVideoFrame(config_.window_id,
                                        std::move(video_frame_texture));
@@ -706,6 +710,7 @@
   if (decoder_deleted())
     return;
 
+  frame_index_ = 0;
   switch (reset_point_) {
     case DONE_RESET_AFTER_FIRST_CONFIG_INFO:
     case MID_STREAM_RESET:
@@ -1201,10 +1206,7 @@
   notes_.resize(num_concurrent_decoders);
   clients_.resize(num_concurrent_decoders);
 
-  // TODO(crbug.com/856562): Use Frame Validator in every test case, not
-  // limited to thumbnail test case.
-  bool use_video_frame_validator =
-      render_as_thumbnails && g_frame_validator && g_test_import;
+  bool use_video_frame_validator = g_frame_validator && g_test_import;
   if (use_video_frame_validator) {
     LOG(INFO) << "Using Frame Validator..";
 #if !defined(OS_CHROMEOS)
diff --git a/printing/backend/printing_restrictions.cc b/printing/backend/printing_restrictions.cc
index b284818a..073107a 100644
--- a/printing/backend/printing_restrictions.cc
+++ b/printing/backend/printing_restrictions.cc
@@ -8,6 +8,8 @@
 
 const char kAllowedColorModes[] = "allowedColorModes";
 const char kAllowedDuplexModes[] = "allowedDuplexModes";
+const char kDefaultColorMode[] = "defaultColorMode";
+const char kDefaultDuplexMode[] = "defaultDuplexMode";
 const char kPageWidthUm[] = "WidthUm";
 const char kPageHeightUm[] = "HeightUm";
 
diff --git a/printing/backend/printing_restrictions.h b/printing/backend/printing_restrictions.h
index d9ef7fef..133b0c6 100644
--- a/printing/backend/printing_restrictions.h
+++ b/printing/backend/printing_restrictions.h
@@ -50,6 +50,8 @@
 // chrome/browser/resources/print_preview/native_layer.js
 PRINTING_EXPORT extern const char kAllowedColorModes[];
 PRINTING_EXPORT extern const char kAllowedDuplexModes[];
+PRINTING_EXPORT extern const char kDefaultColorMode[];
+PRINTING_EXPORT extern const char kDefaultDuplexMode[];
 
 // Dictionary keys to be used with |kPrintingAllowedPageSizes| and
 // |kPrintingSizeDefault| policies.
diff --git a/services/identity/BUILD.gn b/services/identity/BUILD.gn
index 938c3bf4..7a25dfe 100644
--- a/services/identity/BUILD.gn
+++ b/services/identity/BUILD.gn
@@ -55,6 +55,7 @@
     "identity_manager_impl_unittest.cc",
     "public/cpp/access_token_fetcher_unittest.cc",
     "public/cpp/identity_manager_unittest.cc",
+    "public/cpp/identity_test_environment_unittest.cc",
     "public/cpp/primary_account_access_token_fetcher_unittest.cc",
   ]
 }
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc
index b9b604a..37b703a6 100644
--- a/services/identity/public/cpp/identity_test_environment.cc
+++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -143,7 +143,8 @@
     SigninManagerForTest* signin_manager,
     FakeGaiaCookieManagerService* gaia_cookie_manager_service,
     std::unique_ptr<IdentityManagerDependenciesOwner> dependencies_owner,
-    IdentityManager* identity_manager) {
+    IdentityManager* identity_manager)
+    : weak_ptr_factory_(this) {
   if (dependencies_owner) {
     DCHECK(!(account_tracker_service || token_service || signin_manager ||
              gaia_cookie_manager_service || identity_manager));
@@ -333,7 +334,7 @@
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&IdentityTestEnvironment::HandleOnAccessTokenRequested,
-                     base::Unretained(this), account_id));
+                     weak_ptr_factory_.GetWeakPtr(), account_id));
 }
 
 void IdentityTestEnvironment::HandleOnAccessTokenRequested(
diff --git a/services/identity/public/cpp/identity_test_environment.h b/services/identity/public/cpp/identity_test_environment.h
index f1380bf..33b9cb8 100644
--- a/services/identity/public/cpp/identity_test_environment.h
+++ b/services/identity/public/cpp/identity_test_environment.h
@@ -295,6 +295,8 @@
   base::OnceClosure on_access_token_requested_callback_;
   std::vector<AccessTokenRequestState> requesters_;
 
+  base::WeakPtrFactory<IdentityTestEnvironment> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(IdentityTestEnvironment);
 };
 
diff --git a/services/identity/public/cpp/identity_test_environment_unittest.cc b/services/identity/public/cpp/identity_test_environment_unittest.cc
new file mode 100644
index 0000000..c17347ca
--- /dev/null
+++ b/services/identity/public/cpp/identity_test_environment_unittest.cc
@@ -0,0 +1,50 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/identity/public/cpp/identity_test_environment.h"
+#include "base/test/scoped_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace identity {
+
+class IdentityTestEnvironmentTest : public testing::Test {
+ public:
+  IdentityTestEnvironmentTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
+            base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {}
+
+  ~IdentityTestEnvironmentTest() override {
+    scoped_task_environment_.RunUntilIdle();
+  }
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  DISALLOW_COPY_AND_ASSIGN(IdentityTestEnvironmentTest);
+};
+
+TEST_F(IdentityTestEnvironmentTest,
+       IdentityTestEnvironmentCancelsPendingRequestsOnDestruction) {
+  std::unique_ptr<identity::IdentityTestEnvironment> identity_test_environment =
+      std::make_unique<identity::IdentityTestEnvironment>();
+
+  identity_test_environment->MakePrimaryAccountAvailable("primary@example.com");
+  AccessTokenFetcher::TokenCallback callback = base::BindOnce(
+      [](GoogleServiceAuthError error, AccessTokenInfo access_token_info) {});
+  std::set<std::string> scopes{"scope"};
+
+  identity_test_environment->identity_manager()
+      ->CreateAccessTokenFetcherForAccount(
+          identity_test_environment->identity_manager()->GetPrimaryAccountId(),
+          "dummy_consumer", scopes, std::move(callback),
+          AccessTokenFetcher::Mode::kImmediate);
+
+  // Deleting the IdentityTestEnvironment should cancel any pending
+  // task in order to avoid use-after-free crashes. The destructor of
+  // the test will spin the runloop which would run
+  // IdentityTestEnvironment pending tasks if not canceled.
+  identity_test_environment.reset();
+}
+
+}  // namespace identity
diff --git a/services/network/resource_scheduler.cc b/services/network/resource_scheduler.cc
index 7aa62cd..70aa8c09 100644
--- a/services/network/resource_scheduler.cc
+++ b/services/network/resource_scheduler.cc
@@ -1088,9 +1088,13 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   ClientId client_id = MakeClientId(child_id, route_id);
   ClientMap::iterator it = client_map_.find(client_id);
-  DCHECK(it != client_map_.end());
+  // TODO(crbug.com/873959): Turns this CHECK to DCHECK once the investigation
+  // is done.
+  CHECK(it != client_map_.end());
 
   Client* client = it->second.get();
+  // TODO(crbug.com/873959): Remove this CHECK once the investigation is done.
+  CHECK(client);
   // ResourceDispatcherHost cancels all requests except for cross-renderer
   // navigations, async revalidations and detachable requests after
   // OnClientDeleted() returns.
diff --git a/services/resource_coordinator/BUILD.gn b/services/resource_coordinator/BUILD.gn
index a12720f..a3d7a55 100644
--- a/services/resource_coordinator/BUILD.gn
+++ b/services/resource_coordinator/BUILD.gn
@@ -51,6 +51,8 @@
     "observers/metrics_collector.h",
     "observers/page_signal_generator_impl.cc",
     "observers/page_signal_generator_impl.h",
+    "observers/working_set_trimmer_win.cc",
+    "observers/working_set_trimmer_win.h",
     "resource_coordinator_clock.cc",
     "resource_coordinator_clock.h",
     "resource_coordinator_service.cc",
@@ -110,6 +112,7 @@
     "observers/ipc_volume_reporter_unittest.cc",
     "observers/metrics_collector_unittest.cc",
     "observers/page_signal_generator_impl_unittest.cc",
+    "observers/working_set_trimmer_win_unittest.cc",
     "public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits_unittest.cc",
     "public/cpp/memory_instrumentation/os_metrics_unittest.cc",
     "public/cpp/memory_instrumentation/tracing_integration_unittest.cc",
diff --git a/services/resource_coordinator/observers/working_set_trimmer_win.cc b/services/resource_coordinator/observers/working_set_trimmer_win.cc
new file mode 100644
index 0000000..3ec3494
--- /dev/null
+++ b/services/resource_coordinator/observers/working_set_trimmer_win.cc
@@ -0,0 +1,67 @@
+// 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 "services/resource_coordinator/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 "services/resource_coordinator/coordination_unit/coordination_unit_base.h"
+#include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
+
+namespace resource_coordinator {
+
+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(base::ProcessId process_id,
+                     base::Time process_creation_time) {
+  base::Process process = base::Process::OpenWithAccess(
+      process_id, PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_SET_QUOTA);
+  if (!process.IsValid()) {
+    DPLOG(ERROR) << "Working set not emptied because process handle could not "
+                    "be obtained.";
+    return;
+  }
+
+  if (process.CreationTime() != process_creation_time) {
+    DLOG(ERROR) << "Working set not emptied because actual process creation "
+                   "time does not match expected process creation time";
+    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;
+
+bool WorkingSetTrimmer::ShouldObserve(
+    const CoordinationUnitBase* coordination_unit) {
+  return coordination_unit->id().type == CoordinationUnitType::kProcess;
+}
+
+void WorkingSetTrimmer::OnAllFramesInProcessFrozen(
+    const ProcessCoordinationUnitImpl* process_cu) {
+  const base::ProcessId process_id = process_cu->process_id();
+  if (process_id != base::kNullProcessId) {
+    EmptyWorkingSet(process_id, process_cu->launch_time());
+  }
+}
+
+}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/observers/working_set_trimmer_win.h b/services/resource_coordinator/observers/working_set_trimmer_win.h
new file mode 100644
index 0000000..64f45ce
--- /dev/null
+++ b/services/resource_coordinator/observers/working_set_trimmer_win.h
@@ -0,0 +1,45 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_RESOURCE_COORDINATOR_OBSERVERS_WORKING_SET_TRIMMER_WIN_H_
+#define SERVICES_RESOURCE_COORDINATOR_OBSERVERS_WORKING_SET_TRIMMER_WIN_H_
+
+#include "base/macros.h"
+#include "services/resource_coordinator/observers/coordination_unit_graph_observer.h"
+
+namespace resource_coordinator {
+
+// Empties the working set of processes in which all frames are frozen.
+//
+// Objective #1: Track working set growth rate.
+//   Swap trashing occurs when a lot of pages are accessed in a short period of
+//   time. Swap trashing can be reduced by reducing the number of pages accessed
+//   by processes in which all frames are frozen. To track efforts towards this
+//   goal, we empty the working set of processes when all their frames become
+//   frozen and record the size of their working set after x minutes.
+//   TODO(fdoray): Record the working set size x minutes after emptying it.
+//   https://crbug.com/885293
+//
+// Objective #2: Improve performance.
+//   We hypothesize that emptying the working set of a process causes its pages
+//   to be compressed and/or written to disk preemptively, which makes more
+//   memory available quickly for foreground processes and improves global
+//   browser performance.
+class WorkingSetTrimmer : public CoordinationUnitGraphObserver {
+ public:
+  WorkingSetTrimmer();
+  ~WorkingSetTrimmer() override;
+
+  // CoordinationUnitGraphObserver:
+  bool ShouldObserve(const CoordinationUnitBase* coordination_unit) override;
+  void OnAllFramesInProcessFrozen(
+      const ProcessCoordinationUnitImpl* process_cu) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmer);
+};
+
+}  // namespace resource_coordinator
+
+#endif  // SERVICES_RESOURCE_COORDINATOR_OBSERVERS_WORKING_SET_TRIMMER_WIN_H_
diff --git a/services/resource_coordinator/observers/working_set_trimmer_win_unittest.cc b/services/resource_coordinator/observers/working_set_trimmer_win_unittest.cc
new file mode 100644
index 0000000..52ae4efa
--- /dev/null
+++ b/services/resource_coordinator/observers/working_set_trimmer_win_unittest.cc
@@ -0,0 +1,138 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/resource_coordinator/observers/working_set_trimmer_win.h"
+
+#include <windows.h>  // Must be in front of other Windows header files.
+
+#include <psapi.h>
+
+#include <cstring>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/multiprocess_test.h"
+#include "services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h"
+#include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace resource_coordinator {
+
+namespace {
+
+constexpr char kTestProcessIdSwitchName[] = "test_test_process_id";
+constexpr base::char16 kBufferInitializedEventName[] =
+    L"RCEmptyWorkingSetTestBufferInitialized";
+constexpr base::char16 kChildProcessExitEventName[] =
+    L"RCEmptyWorkingSetTestChildProcessExit";
+
+base::win::ScopedHandle CreateEvent(const base::string16& name,
+                                    const base::string16& test_process_id) {
+  base::win::ScopedHandle event(::CreateEvent(
+      nullptr, TRUE, FALSE, (L"Local\\" + name + test_process_id).c_str()));
+  DCHECK(event.IsValid());
+  return event;
+}
+
+SIZE_T GetWorkingSetSizeMb(base::ProcessHandle handle) {
+  PROCESS_MEMORY_COUNTERS_EX pmc;
+  if (::GetProcessMemoryInfo(handle,
+                             reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc),
+                             sizeof(pmc))) {
+    return pmc.WorkingSetSize / 1024 / 1024;
+  }
+
+  ADD_FAILURE() << "GetProcessMemoryInfo failed";
+  return 0;
+}
+
+MULTIPROCESS_TEST_MAIN(ProcessWithLargeWorkingSet) {
+  const base::string16 test_process_id =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
+          kTestProcessIdSwitchName);
+
+  constexpr int k10MbInBytes = 10 * 1024 * 1024;
+  std::vector<char> buffer(k10MbInBytes);
+  std::memset(buffer.data(), 0x80, buffer.size());
+
+  base::WaitableEvent buffer_initialized_event(
+      CreateEvent(kBufferInitializedEventName, test_process_id));
+  buffer_initialized_event.Signal();
+
+  base::WaitableEvent child_process_exit_event(
+      CreateEvent(kChildProcessExitEventName, test_process_id));
+  child_process_exit_event.Wait();
+
+  return 0;
+}
+
+class WorkingSetTrimmerTest : public CoordinationUnitTestHarness {
+ protected:
+  WorkingSetTrimmerTest() {
+    // Create a child process and wait until it allocates a 10 MB buffer.
+    base::CommandLine command_line(
+        base::GetMultiProcessTestChildBaseCommandLine());
+    command_line.AppendSwitchNative(kTestProcessIdSwitchName, test_process_id_);
+
+    child_process_ = base::SpawnMultiProcessTestChild(
+        "ProcessWithLargeWorkingSet", command_line, base::LaunchOptions());
+
+    base::WaitableEvent buffer_initialized_event(
+        CreateEvent(kBufferInitializedEventName, test_process_id_));
+    buffer_initialized_event.Wait();
+
+    process_cu_->SetPID(child_process_.Pid());
+
+    EXPECT_GE(GetWorkingSetSizeMb(child_process_.Handle()), 10U);
+  }
+
+  ~WorkingSetTrimmerTest() override {
+    // Wait for the child process to exit.
+    base::WaitableEvent child_process_exit_event(
+        CreateEvent(kChildProcessExitEventName, test_process_id_));
+    child_process_exit_event.Signal();
+
+    child_process_.WaitForExit(nullptr);
+  }
+
+  const base::string16 test_process_id_ =
+      base::NumberToString16(base::GetCurrentProcId());
+  base::Process child_process_;
+  TestCoordinationUnitWrapper<ProcessCoordinationUnitImpl> process_cu_ =
+      CreateCoordinationUnit<ProcessCoordinationUnitImpl>();
+  WorkingSetTrimmer working_set_trimmer_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WorkingSetTrimmerTest);
+};
+
+}  // namespace
+
+TEST_F(WorkingSetTrimmerTest, EmptyWorkingSet) {
+  // Set the launch time of the process CU to match |child_process_|.
+  process_cu_->SetLaunchTime(child_process_.CreationTime());
+
+  // When all frames in the Process CU are frozen, the working set of
+  // |child_process_| should be emptied.
+  working_set_trimmer_.OnAllFramesInProcessFrozen(process_cu_.get());
+  EXPECT_EQ(GetWorkingSetSizeMb(child_process_.Handle()), 0U);
+}
+
+TEST_F(WorkingSetTrimmerTest, EmptyWorkingSetInconsistentLaunchTime) {
+  // Set the launch time on the process CU to a dummy time.
+  process_cu_->SetLaunchTime(base::Time::Now() + base::TimeDelta::FromDays(1));
+
+  // When all frames in the Process CU are frozen, the working set of
+  // |child_process_| should not be emptied because its creation time is after
+  // |process_cu_->launch_time()|.
+  working_set_trimmer_.OnAllFramesInProcessFrozen(process_cu_.get());
+  EXPECT_GE(GetWorkingSetSizeMb(child_process_.Handle()), 10U);
+}
+
+}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/public/cpp/process_resource_coordinator.cc b/services/resource_coordinator/public/cpp/process_resource_coordinator.cc
index 7255681..aacac596 100644
--- a/services/resource_coordinator/public/cpp/process_resource_coordinator.cc
+++ b/services/resource_coordinator/public/cpp/process_resource_coordinator.cc
@@ -4,6 +4,9 @@
 
 #include "services/resource_coordinator/public/cpp/process_resource_coordinator.h"
 
+#include "base/time/time.h"
+#include "build/build_config.h"
+
 namespace resource_coordinator {
 
 ProcessResourceCoordinator::ProcessResourceCoordinator(
@@ -12,33 +15,34 @@
   CoordinationUnitID new_cu_id(CoordinationUnitType::kProcess,
                                CoordinationUnitID::RANDOM_ID);
   ResourceCoordinatorInterface::ConnectToService(connector, new_cu_id);
+  DCHECK(service_);
 }
 
 ProcessResourceCoordinator::~ProcessResourceCoordinator() = default;
 
+void ProcessResourceCoordinator::OnProcessLaunched(
+    const base::Process& process) {
+  // TODO(fdoray): Merge ProcessCoordinationUnit::SetPID/SetLaunchTime().
+  service_->SetPID(process.Pid());
+  service_->SetLaunchTime(
+#if defined(OS_ANDROID)
+      // Process::CreationTime() is not available on Android. Since this method
+      // is called immediately after the process is launched, the process launch
+      // time can be approximated with the current time.
+      base::Time::Now()
+#else
+      process.CreationTime()
+#endif
+          );
+}
+
 void ProcessResourceCoordinator::SetCPUUsage(double cpu_usage) {
-  if (!service_)
-    return;
   service_->SetCPUUsage(cpu_usage);
 }
 
-void ProcessResourceCoordinator::SetLaunchTime(base::Time launch_time) {
-  if (!service_)
-    return;
-  service_->SetLaunchTime(launch_time);
-}
-
-void ProcessResourceCoordinator::SetPID(base::ProcessId pid) {
-  if (!service_)
-    return;
-  service_->SetPID(pid);
-}
-
 void ProcessResourceCoordinator::AddFrame(
     const FrameResourceCoordinator& frame) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!service_)
-    return;
   // We could keep the ID around ourselves, but this hop ensures that the child
   // has been created on the service-side.
   frame.service()->GetID(
diff --git a/services/resource_coordinator/public/cpp/process_resource_coordinator.h b/services/resource_coordinator/public/cpp/process_resource_coordinator.h
index 3831763..5828056 100644
--- a/services/resource_coordinator/public/cpp/process_resource_coordinator.h
+++ b/services/resource_coordinator/public/cpp/process_resource_coordinator.h
@@ -6,7 +6,7 @@
 #define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_PROCESS_RESOURCE_COORDINATOR_H_
 
 #include "base/memory/weak_ptr.h"
-#include "base/process/process_handle.h"
+#include "base/process/process.h"
 #include "base/threading/thread_checker.h"
 #include "services/resource_coordinator/public/cpp/frame_resource_coordinator.h"
 #include "services/resource_coordinator/public/cpp/resource_coordinator_interface.h"
@@ -22,10 +22,10 @@
   ProcessResourceCoordinator(service_manager::Connector* connector);
   ~ProcessResourceCoordinator() override;
 
-  void SetCPUUsage(double usage);
-  void SetLaunchTime(base::Time launch_time);
-  void SetPID(base::ProcessId pid);
+  // Must be called immediately after the process is launched.
+  void OnProcessLaunched(const base::Process& process);
 
+  void SetCPUUsage(double usage);
   void AddFrame(const FrameResourceCoordinator& frame);
 
  private:
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_features.cc b/services/resource_coordinator/public/cpp/resource_coordinator_features.cc
index be20e36..9be373c 100644
--- a/services/resource_coordinator/public/cpp/resource_coordinator_features.cc
+++ b/services/resource_coordinator/public/cpp/resource_coordinator_features.cc
@@ -25,6 +25,12 @@
 const base::Feature kPerformanceMeasurement{"PerformanceMeasurement",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
+#if defined(OS_WIN)
+// Empty the working set of processes in which all frames are frozen.
+const base::Feature kEmptyWorkingSet{"EmptyWorkingSet",
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
 }  // namespace features
 
 namespace resource_coordinator {
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_features.h b/services/resource_coordinator/public/cpp/resource_coordinator_features.h
index 29754640..52c9cca 100644
--- a/services/resource_coordinator/public/cpp/resource_coordinator_features.h
+++ b/services/resource_coordinator/public/cpp/resource_coordinator_features.h
@@ -10,6 +10,7 @@
 
 #include "base/component_export.h"
 #include "base/feature_list.h"
+#include "build/build_config.h"
 
 namespace features {
 
@@ -22,6 +23,11 @@
 extern const COMPONENT_EXPORT(SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_FEATURES)
     base::Feature kPerformanceMeasurement;
 
+#if defined(OS_WIN)
+extern const COMPONENT_EXPORT(SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_FEATURES)
+    base::Feature kEmptyWorkingSet;
+#endif
+
 }  // namespace features
 
 namespace resource_coordinator {
diff --git a/services/resource_coordinator/resource_coordinator_service.cc b/services/resource_coordinator/resource_coordinator_service.cc
index 57fc53a..194aa4a 100644
--- a/services/resource_coordinator/resource_coordinator_service.cc
+++ b/services/resource_coordinator/resource_coordinator_service.cc
@@ -6,14 +6,21 @@
 
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/timer/timer.h"
+#include "build/build_config.h"
 #include "services/metrics/public/cpp/mojo_ukm_recorder.h"
 #include "services/resource_coordinator/memory_instrumentation/coordinator_impl.h"
 #include "services/resource_coordinator/observers/ipc_volume_reporter.h"
 #include "services/resource_coordinator/observers/metrics_collector.h"
 #include "services/resource_coordinator/observers/page_signal_generator_impl.h"
+#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
+#if defined(OS_WIN)
+#include "services/resource_coordinator/observers/working_set_trimmer_win.h"
+#endif
+
 namespace resource_coordinator {
 
 std::unique_ptr<service_manager::Service> ResourceCoordinatorService::Create() {
@@ -52,6 +59,13 @@
   coordination_unit_graph_.RegisterObserver(std::make_unique<IPCVolumeReporter>(
       std::make_unique<base::OneShotTimer>()));
 
+#if defined(OS_WIN)
+  if (base::FeatureList::IsEnabled(features::kEmptyWorkingSet)) {
+    coordination_unit_graph_.RegisterObserver(
+        std::make_unique<WorkingSetTrimmer>());
+  }
+#endif
+
   coordination_unit_graph_.OnStart(&registry_, ref_factory_.get());
   coordination_unit_graph_.set_ukm_recorder(ukm_recorder_.get());
 
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 6991e8a..70878091 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -5852,7 +5852,7 @@
       }
     ]
   },
-  "linux-code-coverage-tester": {
+  "linux-code-coverage": {
     "gtest_tests": [
       {
         "isolate_coverage_data": true,
diff --git a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter
index 32dc0fe..8a2fcf6 100644
--- a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter
@@ -13,9 +13,6 @@
 # https://crbug.com/882650
 -*__multiprocess_mode
 
-# https://crbug.com/893561
--org.chromium.android_webview.test.AcceptLanguageTest.testAcceptLanguage
-
 # https://crbug.com/893563
 -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testExitFullscreenEndsIfAppInvokesCallbackFromOnHideCustomView
 -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testFullscreenForNonVideoElementIsSupportedInSoftwareMode
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 94fc02e..73604a60 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1375,7 +1375,7 @@
           'isolated_scripts': 'chromium_linux_rel_isolated_scripts',
         },
       },
-      'linux-code-coverage-tester': {
+      'linux-code-coverage': {
         'mixins': [
             'code-coverage',
         ],
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 5c00a42..4278a7dc 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -756,14 +756,9 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "AutofillEnforceMinRequiredFieldsForHeuristics",
-                        "AutofillEnforceMinRequiredFieldsForUpload"
-                    ],
+                    "name": "Enabled_NoSmallAddressForms",
                     "disable_features": [
-                        "AutofillEnforceMinRequiredFieldsForQuery",
-                        "AutofillRestrictUnownedFieldsToFormlessCheckout"
+                        "AutofillEnforceMinRequiredFieldsForQuery"
                     ]
                 }
             ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 3cdd44d9..8275d93 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -5507,7 +5507,8 @@
 crbug.com/891155 [ Linux ] fast/events/middleClickAutoscroll-event-fired.html [ Failure Pass ]
 crbug.com/891155 [ Linux ] fast/events/middleClickAutoscroll-drag.html [ Failure Pass ]
 
-# ecosystem-infra sheriff 2018-10-16
+# run_web_tests.py crashes content_shell when <link href="about:blank"> is present
+crbug.com/895777 external/wpt/css/css-transforms/text-perspective-001.html [ Pass Crash ]
 crbug.com/895777 external/wpt/infrastructure/assumptions/blank.html [ Failure Crash ]
 
 #Sheriff 2018-10-18
@@ -5567,3 +5568,7 @@
 crbug.com/899222 [ Linux Win ] virtual/user-activation-v2/fast/events/touch/gesture/gesture-scrollbar-touchscreen-fling.html [ Failure Pass ]
 crbug.com/899222 [ Linux Win ] virtual/scroll_customization/fast/events/touch/gesture/gesture-scrollbar-touchscreen-fling.html [ Failure Pass ]
 crbug.com/900356 [ Win ] virtual/threaded/animations/animationworklet/worklet-animation-style-update.html [ Failure Pass ]
+
+# Sheriff 2018-10-31
+crbug.com/726520 [ Win10 ] virtual/layout_ng_experimental/printing/iframe-print.html [ Failure ]
+crbug.com/900326 [ Win7 Mac10.12 ] http/tests/devtools/network/preview-searchable.js [ Timeout Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
index 7f5deb5..7734647 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
@@ -69379,6 +69379,18 @@
      {}
     ]
    ],
+   "css/css-transforms/text-perspective-001.html": [
+    [
+     "/css/css-transforms/text-perspective-001.html",
+     [
+      [
+       "about:blank",
+       "!="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-transforms/transform-3d-rotateY-stair-above-001.xht": [
     [
      "/css/css-transforms/transform-3d-rotateY-stair-above-001.xht",
@@ -101159,6 +101171,18 @@
      {}
     ]
    ],
+   "html/rendering/replaced-elements/the-select-element/select-1-block-size.html": [
+    [
+     "/html/rendering/replaced-elements/the-select-element/select-1-block-size.html",
+     [
+      [
+       "/html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/rendering/replaced-elements/the-select-element/select-1-line-height.html": [
     [
      "/html/rendering/replaced-elements/the-select-element/select-1-line-height.html",
@@ -101171,6 +101195,18 @@
      {}
     ]
    ],
+   "html/rendering/replaced-elements/the-select-element/select-empty.html": [
+    [
+     "/html/rendering/replaced-elements/the-select-element/select-empty.html",
+     [
+      [
+       "/html/rendering/replaced-elements/the-select-element/select-empty-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/rendering/the-css-user-agent-style-sheet-and-presentational-hints/body-bgcolor-attribute-change.html": [
     [
      "/html/rendering/the-css-user-agent-style-sheet-and-presentational-hints/body-bgcolor-attribute-change.html",
@@ -109509,6 +109545,11 @@
      {}
     ]
    ],
+   "IndexedDB/key-generators/reading-autoincrement-common.js": [
+    [
+     {}
+    ]
+   ],
    "IndexedDB/nested-cloning-common.js": [
     [
      {}
@@ -134889,6 +134930,11 @@
      {}
     ]
    ],
+   "css/css-properties-values-api/registered-property-computation-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-properties-values-api/resources/utils.js": [
     [
      {}
@@ -161614,11 +161660,21 @@
      {}
     ]
    ],
+   "html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html": [
+    [
+     {}
+    ]
+   ],
    "html/rendering/replaced-elements/the-select-element/select-1-line-height-ref.html": [
     [
      {}
     ]
    ],
+   "html/rendering/replaced-elements/the-select-element/select-empty-ref.html": [
+    [
+     {}
+    ]
+   ],
    "html/rendering/replaced-elements/tools/gen-svgsizing-tests.py": [
     [
      {}
@@ -169899,11 +169955,6 @@
      {}
     ]
    ],
-   "picture-in-picture/idlharness.window-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "picture-in-picture/resources/picture-in-picture-helpers.js": [
     [
      {}
@@ -184629,6 +184680,11 @@
      {}
     ]
    ],
+   "xhr/resources/header-content-length-twice.asis": [
+    [
+     {}
+    ]
+   ],
    "xhr/resources/header-content-length.asis": [
     [
      {}
@@ -184644,6 +184700,16 @@
      {}
     ]
    ],
+   "xhr/resources/headers-double-empty.asis": [
+    [
+     {}
+    ]
+   ],
+   "xhr/resources/headers-some-are-empty.asis": [
+    [
+     {}
+    ]
+   ],
    "xhr/resources/headers-www-authenticate.asis": [
     [
      {}
@@ -184959,6 +185025,11 @@
      {}
     ]
    ],
+   "xhr/setrequestheader-combining.window-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "xhr/setrequestheader-content-type-expected.txt": [
     [
      {}
@@ -192004,6 +192075,78 @@
      }
     ]
    ],
+   "IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.js": [
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.serviceworker.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.sharedworker.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.worker.html",
+     {}
+    ]
+   ],
+   "IndexedDB/key-generators/reading-autoincrement-indexes.any.js": [
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-indexes.any.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-indexes.any.serviceworker.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-indexes.any.sharedworker.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-indexes.any.worker.html",
+     {}
+    ]
+   ],
+   "IndexedDB/key-generators/reading-autoincrement-store-cursors.any.js": [
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-store-cursors.any.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-store-cursors.any.serviceworker.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-store-cursors.any.sharedworker.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-store-cursors.any.worker.html",
+     {}
+    ]
+   ],
+   "IndexedDB/key-generators/reading-autoincrement-store.any.js": [
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-store.any.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-store.any.serviceworker.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-store.any.sharedworker.html",
+     {}
+    ],
+    [
+     "/IndexedDB/key-generators/reading-autoincrement-store.any.worker.html",
+     {}
+    ]
+   ],
    "IndexedDB/key_invalid.htm": [
     [
      "/IndexedDB/key_invalid.htm",
@@ -202934,6 +203077,12 @@
      {}
     ]
    ],
+   "css/css-scoping/shadow-reassign-dynamic-003.html": [
+    [
+     "/css/css-scoping/shadow-reassign-dynamic-003.html",
+     {}
+    ]
+   ],
    "css/css-scoping/slot-non-html-display-value.html": [
     [
      "/css/css-scoping/slot-non-html-display-value.html",
@@ -263660,6 +263809,12 @@
      {}
     ]
    ],
+   "service-workers/service-worker/postmessage-to-client-message-queue.https.html": [
+    [
+     "/service-workers/service-worker/postmessage-to-client-message-queue.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/postmessage-to-client.https.html": [
     [
      "/service-workers/service-worker/postmessage-to-client.https.html",
@@ -277580,6 +277735,12 @@
      {}
     ]
    ],
+   "xhr/setrequestheader-combining.window.js": [
+    [
+     "/xhr/setrequestheader-combining.window.html",
+     {}
+    ]
+   ],
    "xhr/setrequestheader-content-type.htm": [
     [
      "/xhr/setrequestheader-content-type.htm",
@@ -289990,7 +290151,7 @@
    "testharness"
   ],
   "IndexedDB/idbindex-rename-abort.html": [
-   "b14d30122610bc7025a478c146fbac42128f7428",
+   "b61988e9b5c764b5b72b4937b8d76fd3aed15e67",
    "testharness"
   ],
   "IndexedDB/idbindex-rename-errors.html": [
@@ -290170,7 +290331,7 @@
    "testharness"
   ],
   "IndexedDB/idbobjectstore-rename-abort.html": [
-   "6e16c31e339f731e218044ee9320edba3d965661",
+   "75893cd84c012d4bc662ba11fd79ef1eacaf49cc",
    "testharness"
   ],
   "IndexedDB/idbobjectstore-rename-errors.html": [
@@ -290577,6 +290738,26 @@
    "4dd5d9005b6cb6e4c2c7dccaef62804bfcdb73ec",
    "testharness"
   ],
+  "IndexedDB/key-generators/reading-autoincrement-common.js": [
+   "45c8ffef923870909cb9b0e2af128081e5bce41a",
+   "support"
+  ],
+  "IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.js": [
+   "d7938768fa152c20b4b58538350a51b78b38e445",
+   "testharness"
+  ],
+  "IndexedDB/key-generators/reading-autoincrement-indexes.any.js": [
+   "d945b78bf3743bccd632dabdcb846af52c183110",
+   "testharness"
+  ],
+  "IndexedDB/key-generators/reading-autoincrement-store-cursors.any.js": [
+   "05971098fa893ebe58de4b2ad05d84a4965b6e0d",
+   "testharness"
+  ],
+  "IndexedDB/key-generators/reading-autoincrement-store.any.js": [
+   "bbba6a335139d5b2946b5f6d71a635fd5ee014c3",
+   "testharness"
+  ],
   "IndexedDB/key_invalid.htm": [
    "30759d5ef3e594852990808621ce75c840d0ac39",
    "testharness"
@@ -290686,7 +290867,7 @@
    "testharness"
   ],
   "IndexedDB/support-promises.js": [
-   "d320ba04ce951d905a754aa63a89619e0c941c20",
+   "433af5092701d617e2964f7d1ea3ea089b50c441",
    "support"
   ],
   "IndexedDB/support.js": [
@@ -290782,7 +290963,7 @@
    "support"
   ],
   "WebCryptoAPI/META.yml": [
-   "ec95611b3fed980e2897a5fe2bedc6bb7fa2913d",
+   "8f27e484996c51eb9ebbbd96902fa1f885af7be0",
    "support"
   ],
   "WebCryptoAPI/OWNERS": [
@@ -331198,7 +331379,7 @@
    "reftest"
   ],
   "css/css-grid/META.yml": [
-   "f8482e16f983ca24e3333ae8989277f82b297ad1",
+   "18c574ac68bac7e5b95085d96c49347d5eb36814",
    "support"
   ],
   "css/css-grid/OWNERS": [
@@ -338017,8 +338198,12 @@
    "614a72a797bc91a76742efc990e07669bee87c11",
    "testharness"
   ],
+  "css/css-properties-values-api/registered-property-computation-expected.txt": [
+   "c657b7c6ade75ac7b55ae10ca699b8d85db53025",
+   "support"
+  ],
   "css/css-properties-values-api/registered-property-computation.html": [
-   "180cdf601edd4a82398d29239141bf38e55bd0c1",
+   "2525e43ef51e1e5af94426346e51a68b87fea055",
    "testharness"
   ],
   "css/css-properties-values-api/registered-property-cssom.html": [
@@ -338026,15 +338211,15 @@
    "testharness"
   ],
   "css/css-properties-values-api/registered-property-initial.html": [
-   "24543d5c5fdc84706a28502d8cf8c2c7f925978e",
+   "77aa9cd11a3eabfd154cc98869699e6f24c64c5c",
    "testharness"
   ],
   "css/css-properties-values-api/resources/utils.js": [
-   "c4dc3fd5a8d98106395e3e99566f05d6d9a30c0c",
+   "bef59560f68d84ed0d681bb22e0611ea2466024f",
    "support"
   ],
   "css/css-properties-values-api/self-utils.html": [
-   "530c5f677ad25858a06281a9e526584e57081af5",
+   "05aa4b2fb03b29feee47177624715230768a44a0",
    "testharness"
   ],
   "css/css-properties-values-api/support/alt/alt.css": [
@@ -338513,6 +338698,10 @@
    "7874e2e13987246c1160c419967aba9db32bbf63",
    "reftest"
   ],
+  "css/css-scoping/shadow-reassign-dynamic-003.html": [
+   "bc6392176eb58acff55b740fbd4e9f6321982d91",
+   "testharness"
+  ],
   "css/css-scoping/shadow-root-insert-into-document.html": [
    "a3b89be389a780dd53a1b53224810ecb4866c287",
    "reftest"
@@ -345878,11 +346067,11 @@
    "support"
   ],
   "css/css-transforms/animation/list-interpolation-expected.txt": [
-   "5189f990e0bdbf5a786e025d6a81b5a931c9fec4",
+   "786f6c1e86700cb19346abb712e25c404e5b8211",
    "support"
   ],
   "css/css-transforms/animation/list-interpolation.html": [
-   "91092c88aac0747dabf54934381478f9dc8fac66",
+   "90cdebbb6cdb643e4c55cb7c0dcd5340fad9a9bd",
    "testharness"
   ],
   "css/css-transforms/animation/matrix-interpolation-expected.txt": [
@@ -345894,7 +346083,7 @@
    "testharness"
   ],
   "css/css-transforms/animation/resources/interpolation-testcommon.js": [
-   "5ab5551152e97b5c76c653aebf44aec9d27a825f",
+   "3791b0af9db63fe7c8ef6baad4cc566e4a3e950a",
    "support"
   ],
   "css/css-transforms/animation/rotate-interpolation.html": [
@@ -348461,6 +348650,10 @@
    "2145190fec4cddb59f18a5ac1d5bfead0ce548fa",
    "support"
   ],
+  "css/css-transforms/text-perspective-001.html": [
+   "e98b3e73b36a323a60ad5ef74e090ff193ad41b9",
+   "reftest"
+  ],
   "css/css-transforms/transform-2d-getComputedStyle-001-expected.txt": [
    "ecab08ef439acb7e9e398eae9cccfecbf0eaba39",
    "support"
@@ -364438,7 +364631,7 @@
    "testharness"
   ],
   "css/geometry/META.yml": [
-   "9e3a7979ed80210ccba78da767526aad875e00c2",
+   "98a2ae9860b2d682220dbf21eb2f3606ca68ff61",
    "support"
   ],
   "css/geometry/OWNERS": [
@@ -377670,11 +377863,11 @@
    "testharness"
   ],
   "fetch/api/basic/header-value-combining.any.js": [
-   "fd08072ea52214fdd83741d5b7fbef8c572a3f15",
+   "bb70d87d250cda383e1155be3838a7b97160b025",
    "testharness"
   ],
   "fetch/api/basic/header-value-combining.any.serviceworker-expected.txt": [
-   "979efeaf0d6cd55ddd8a59b11b783873e92b92a5",
+   "8298561c690746c205266fc0ece3f6c7df4feb27",
    "support"
   ],
   "fetch/api/basic/header-value-null-byte.any.js": [
@@ -384206,11 +384399,11 @@
    "testharness"
   ],
   "html/dom/elements/the-innertext-idl-attribute/getter-expected.txt": [
-   "ab79f07a2dc09aeaf7f84a3387b391d97c3ee768",
+   "47170099c0134979f3e89fa3ebc3c0dbf647fa42",
    "support"
   ],
   "html/dom/elements/the-innertext-idl-attribute/getter-tests.js": [
-   "5139ec97b05ce6d3cd9b84a20770065e9f81adb0",
+   "4dd2b6be20619cde5f244ca76d239aa9bbc50044",
    "support"
   ],
   "html/dom/elements/the-innertext-idl-attribute/getter.html": [
@@ -389517,6 +389710,14 @@
    "3b8d992cc2a07dfd902dbb1011e2c348e862baaa",
    "reftest"
   ],
+  "html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html": [
+   "3e437494c0ad8dadd4d58b630194678753516fde",
+   "support"
+  ],
+  "html/rendering/replaced-elements/the-select-element/select-1-block-size.html": [
+   "4aecc596ce693a6cff3f6ffd5dbac1fa4911dfe8",
+   "reftest"
+  ],
   "html/rendering/replaced-elements/the-select-element/select-1-line-height-ref.html": [
    "26e5f33282192b10f56cd66fefeda2c1b9d9b389",
    "support"
@@ -389525,6 +389726,14 @@
    "e6383f089ffa5550005f99257ecac7984dd09110",
    "reftest"
   ],
+  "html/rendering/replaced-elements/the-select-element/select-empty-ref.html": [
+   "31ba23a5cf86f161b1204ea3f4c9fef4585af909",
+   "support"
+  ],
+  "html/rendering/replaced-elements/the-select-element/select-empty.html": [
+   "6568a6de34985a7fc201ce0bd530b86b145083e8",
+   "reftest"
+  ],
   "html/rendering/replaced-elements/tools/gen-svgsizing-tests.py": [
    "5ba69f8ab5ba0a74810c570d9a4f3d7ddd90a3ba",
    "support"
@@ -399962,7 +400171,7 @@
    "support"
   ],
   "interfaces/IndexedDB.idl": [
-   "3982d1105034101eb312b08039b3bbf86ec0b0ac",
+   "137528c148ae434141eb72e9720bd9e3eaf04a30",
    "support"
   ],
   "interfaces/InputDeviceCapabilities.idl": [
@@ -400754,7 +400963,7 @@
    "support"
   ],
   "lint.whitelist": [
-   "296699bb61ebafb0cb506d6f2ed4637a9d92942f",
+   "e138450611c7ccc4a0cee68624b42ef382a5c71f",
    "support"
   ],
   "longtask-timing/META.yml": [
@@ -412617,10 +412826,6 @@
    "c8d76f5244a41754e4a8a5b0c9fd01d056caee96",
    "testharness"
   ],
-  "picture-in-picture/idlharness.window-expected.txt": [
-   "6c3e97c13915781641c74761ac2b5db3fd4b223e",
-   "support"
-  ],
   "picture-in-picture/idlharness.window.js": [
    "31cd4a14177bccd277023a98ea5956e5f018e2e1",
    "testharness"
@@ -412654,7 +412859,7 @@
    "testharness"
   ],
   "pointerevents/META.yml": [
-   "ef94157ef9a9df762f940f1c6b04128dd69f4f3b",
+   "be61ddddaf62acb3396ada6779ad3f50e6caa709",
    "support"
   ],
   "pointerevents/OWNERS": [
@@ -424649,8 +424854,12 @@
    "29c056080c79d581975e0929dcebd84d63b86a20",
    "testharness"
   ],
+  "service-workers/service-worker/postmessage-to-client-message-queue.https.html": [
+   "caa4f9445d3d8ad0ab92ba73713da17a33af185c",
+   "testharness"
+  ],
   "service-workers/service-worker/postmessage-to-client.https.html": [
-   "b1dc41a018f273832f4ac90c17b4b981f095b0ef",
+   "15d2e889337078869e3c3e97d312649e6a8bd8b2",
    "testharness"
   ],
   "service-workers/service-worker/postmessage.https.html": [
@@ -426938,7 +427147,7 @@
    "testharness"
   ],
   "speech-api/META.yml": [
-   "17263d91d367f5571ac7df3616aa026bdb4f6433",
+   "ac4b89b03490dbb46c257a2e5fdec3a741acdd52",
    "support"
   ],
   "speech-api/OWNERS": [
@@ -428406,7 +428615,7 @@
    "testharness"
   ],
   "subresource-integrity/META.yml": [
-   "740ad1412f671ad86d88098ae437a817cbd620d5",
+   "2b8891ec6b498cc6b24df46e21fffad437732b54",
    "support"
   ],
   "subresource-integrity/OWNERS": [
@@ -430326,7 +430535,7 @@
    "testharness"
   ],
   "url/META.yml": [
-   "459152f6f078042714905b3e1d2eaba1c415807b",
+   "3a789a0d513f0a78bf362dd73c8a807d0cd55a50",
    "support"
   ],
   "url/OWNERS": [
@@ -432166,7 +432375,7 @@
    "support"
   ],
   "webaudio/META.yml": [
-   "37276da53345515f79453de8c5ade6037ff6f9eb",
+   "e8f8cc59489e381dba1fd35e9d088a6de86a3783",
    "support"
   ],
   "webaudio/OWNERS": [
@@ -441230,7 +441439,7 @@
    "testharness"
   ],
   "xhr/getallresponseheaders-expected.txt": [
-   "bf36826db53c0154322979d7fb4840d145c4fa2d",
+   "04b1beca8eddc2c1329533b951335d58e04a0346",
    "support"
   ],
   "xhr/getallresponseheaders-status.htm": [
@@ -441238,7 +441447,7 @@
    "testharness"
   ],
   "xhr/getallresponseheaders.htm": [
-   "e5747331a8ce078d9ab6be7e040f9623c8aeb162",
+   "72e27a5947c1e00ce1edeedf21a9db83c42832fa",
    "testharness"
   ],
   "xhr/getresponseheader-case-insensitive.htm": [
@@ -441270,7 +441479,7 @@
    "testharness"
   ],
   "xhr/getresponseheader.any.js": [
-   "4ff791aeb1635719b948ce7edcf5d1592b87c351",
+   "6eeccd03f6222e936055ee85a4a6b41948332b30",
    "testharness"
   ],
   "xhr/header-user-agent-async.htm": [
@@ -441729,6 +441938,10 @@
    "f17f92e4cc17792d7b558d1cd4e1e1d76350dd27",
    "support"
   ],
+  "xhr/resources/header-content-length-twice.asis": [
+   "e3196984c06e09883c6770d56f2d2d5fe66ec6a8",
+   "support"
+  ],
   "xhr/resources/header-content-length.asis": [
    "ef7071d7428d9593d69ec10675cff30c46610e09",
    "support"
@@ -441741,6 +441954,14 @@
    "fe37b1b38e9f8698581affe8d74f176688c11d15",
    "support"
   ],
+  "xhr/resources/headers-double-empty.asis": [
+   "14304b2b434a25f587765cd3c68a0a4d7cea78b3",
+   "support"
+  ],
+  "xhr/resources/headers-some-are-empty.asis": [
+   "1783e1a11b46aa0db11404c426d2b121da697b78",
+   "support"
+  ],
   "xhr/resources/headers-www-authenticate.asis": [
    "6f9905ee7a06627efcb244180367b13b65c0d0c4",
    "support"
@@ -442134,11 +442355,11 @@
    "testharness"
   ],
   "xhr/send-content-type-charset-expected.txt": [
-   "8143f7d5c3a565b57c44269decb8da06a102559c",
+   "068a31bd05baa9c53eec185283b80b6960a053d3",
    "support"
   ],
   "xhr/send-content-type-charset.htm": [
-   "4e75df234682c91b7effa0de52f5f95a3ac438a4",
+   "0a91e1fbd7e061df3123163e049cc8aab90a67e2",
    "testharness"
   ],
   "xhr/send-content-type-string.htm": [
@@ -442365,6 +442586,14 @@
    "1aed30d1c2a13fcb35e90a31e599a6cc963c6491",
    "testharness"
   ],
+  "xhr/setrequestheader-combining.window-expected.txt": [
+   "7bdad1441ec748a1951e21ebddafa0846628ae37",
+   "support"
+  ],
+  "xhr/setrequestheader-combining.window.js": [
+   "fc847eb79a87fefd8dbeff16b6abd85b06f74126",
+   "testharness"
+  ],
   "xhr/setrequestheader-content-type-expected.txt": [
    "65bfab876d25398d7331803d5a34793fde38061d",
    "support"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/WebCryptoAPI/META.yml b/third_party/WebKit/LayoutTests/external/wpt/WebCryptoAPI/META.yml
index ec95611..8f27e48 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/WebCryptoAPI/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/WebCryptoAPI/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/webcrypto/
 suggested_reviewers:
-  - Wafflespeanut
   - jimsch
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/META.yml b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/META.yml
index f8482e1..18c574ac 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid/META.yml
@@ -1,7 +1,6 @@
 spec: https://drafts.csswg.org/css-grid/
 suggested_reviewers:
   - mrego
-  - tomalec
   - plinss
   - jxs
   - tabatkins
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-scoping/shadow-reassign-dynamic-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-scoping/shadow-reassign-dynamic-003.html
new file mode 100644
index 0000000..bc63921
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-scoping/shadow-reassign-dynamic-003.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://drafts.csswg.org/css-scoping/#slots-in-shadow-tree">
+<div id="host"><span id="slotted">This text should be green.</span></div>
+<script>
+  const root = host.attachShadow({mode:"open"});
+  root.innerHTML = '<slot name="nomatch" style="color:green"></slot><slot style="color:red"></slot>';
+
+  test(() => {
+    assert_equals(getComputedStyle(slotted).color, "rgb(255, 0, 0)");
+  }, "Initial computed color.");
+
+  test(() => {
+    root.querySelector("slot").removeAttribute("name");
+    assert_equals(getComputedStyle(slotted).color, "rgb(0, 128, 0)");
+
+  }, "Computed color after re-slotting.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/list-interpolation-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/list-interpolation-expected.txt
index 5189f990..786f6c1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/list-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/list-interpolation-expected.txt
@@ -1,23 +1,27 @@
 This is a testharness.js-based test.
-PASS "none" and "none" are valid transform values
-FAIL Animation between "none" and "none" at progress 0.25 assert_equals: expected "none" but got "matrix(1, 0, 0, 1, 0, 0)"
-PASS "none" and "translate(200px) rotate(720deg)" are valid transform values
-PASS Animation between "none" and "translate(200px) rotate(720deg)" at progress 0.25
-PASS "translate(200px) rotate(720deg)" and "none" are valid transform values
-PASS Animation between "translate(200px) rotate(720deg)" and "none" at progress 0.25
-PASS "translate(100px)" and "translate(200px) rotate(720deg)" are valid transform values
-FAIL Animation between "translate(100px)" and "translate(200px) rotate(720deg)" at progress 0.25 assert_equals: expected "matrix(-1, 1.22465e-16, -1.22465e-16, -1, 125, 0)" but got "matrix(1, 0, 0, 1, 125, 0)"
-PASS "translate(100px) rotate(720deg)" and "translate(200px)" are valid transform values
-FAIL Animation between "translate(100px) rotate(720deg)" and "translate(200px)" at progress 0.25 assert_equals: expected "matrix(-1, 3.67394e-16, -3.67394e-16, -1, 125, 0)" but got "matrix(1, -4.89859e-16, 4.89859e-16, 1, 125, 0)"
-PASS "scale(2) rotate(360deg) translate(100px) matrix(1, 0, 0, 1, 100, 0) skew(0deg)" and "scale(3) rotate(1080deg) translate(200px) matrix(1, 0, 0, 1, 0, 200) skew(720deg)" are valid transform values
-PASS Animation between "scale(2) rotate(360deg) translate(100px) matrix(1, 0, 0, 1, 100, 0) skew(0deg)" and "scale(3) rotate(1080deg) translate(200px) matrix(1, 0, 0, 1, 0, 200) skew(720deg)" at progress 0.25
-PASS "translateX(100px) scaleX(3) translate(500px) scale(2)" and "translateY(200px) scale(5) translateX(100px) scaleY(3)" are valid transform values
-PASS Animation between "translateX(100px) scaleX(3) translate(500px) scale(2)" and "translateY(200px) scale(5) translateX(100px) scaleY(3)" at progress 0.25
-PASS "rotate(0deg) translate(100px)" and "rotate(720deg) scale(2) translate(200px)" are valid transform values
-FAIL Animation between "rotate(0deg) translate(100px)" and "rotate(720deg) scale(2) translate(200px)" at progress 0.25 assert_equals: expected "matrix(-1.25, 1.53081e-16, -1.53081e-16, -1.25, -175, 2.14313e-14)" but got "matrix(1.25, 0, 0, 1.25, 175, -4.89859e-14)"
-PASS "scale(2) rotate(0deg) translate(100px)" and "rotate(720deg) scale(2) translate(200px)" are valid transform values
-FAIL Animation between "scale(2) rotate(0deg) translate(100px)" and "rotate(720deg) scale(2) translate(200px)" at progress 0.25 assert_equals: expected "matrix(2, 0, 0, 2, 250, 0)" but got "matrix(2, 0, 0, 2, 250, -4.89859e-14)"
-PASS "scale(2) rotate(0deg)" and "rotate(720deg) scale(2) translate(200px)" are valid transform values
-FAIL Animation between "scale(2) rotate(0deg)" and "rotate(720deg) scale(2) translate(200px)" at progress 0.25 assert_equals: expected "matrix(2, 0, 0, 2, 100, 0)" but got "matrix(2, 0, 0, 2, 100, -4.89859e-14)"
+PASS none -> none: "none" and "none" are valid transform values
+FAIL none -> none: Animation between "none" and "none" at progress 0.25 assert_equals: expected "none" but got "matrix(1, 0, 0, 1, 0, 0)"
+PASS none -> something: "none" and "translate(200px) rotate(720deg)" are valid transform values
+PASS none -> something: Animation between "none" and "translate(200px) rotate(720deg)" at progress 0.25
+PASS something -> none: "translate(200px) rotate(720deg)" and "none" are valid transform values
+PASS something -> none: Animation between "translate(200px) rotate(720deg)" and "none" at progress 0.25
+PASS Mismatched lengths (from is shorter), common part matches: "translate(100px)" and "translate(200px) rotate(720deg)" are valid transform values
+FAIL Mismatched lengths (from is shorter), common part matches: Animation between "translate(100px)" and "translate(200px) rotate(720deg)" at progress 0.25 assert_equals: expected "matrix(-1, 1.22465e-16, -1.22465e-16, -1, 125, 0)" but got "matrix(1, 0, 0, 1, 125, 0)"
+PASS Mismatched lengths (to is shorter), common part matches: "translate(100px) rotate(720deg)" and "translate(200px)" are valid transform values
+FAIL Mismatched lengths (to is shorter), common part matches: Animation between "translate(100px) rotate(720deg)" and "translate(200px)" at progress 0.25 assert_equals: expected "matrix(-1, 3.67394e-16, -3.67394e-16, -1, 125, 0)" but got "matrix(1, -4.89859e-16, 4.89859e-16, 1, 125, 0)"
+PASS Perfect match: "scale(2) rotate(360deg) translate(100px) matrix(1, 0, 0, 1, 100, 0) skew(0deg)" and "scale(3) rotate(1080deg) translate(200px) matrix(1, 0, 0, 1, 0, 200) skew(720deg)" are valid transform values
+PASS Perfect match: Animation between "scale(2) rotate(360deg) translate(100px) matrix(1, 0, 0, 1, 100, 0) skew(0deg)" and "scale(3) rotate(1080deg) translate(200px) matrix(1, 0, 0, 1, 0, 200) skew(720deg)" at progress 0.25
+PASS Matches on primitives: "translateX(100px) scaleX(3) translate(500px) scale(2)" and "translateY(200px) scale(5) translateX(100px) scaleY(3)" are valid transform values
+PASS Matches on primitives: Animation between "translateX(100px) scaleX(3) translate(500px) scale(2)" and "translateY(200px) scale(5) translateX(100px) scaleY(3)" at progress 0.25
+PASS Match on rotation vector: "rotateX(90deg) translateX(100px)" and "rotate3d(50, 0, 0, 180deg) translateY(200px)" are valid transform values
+FAIL Match on rotation vector: Animation between "rotateX(90deg) translateX(100px)" and "rotate3d(50, 0, 0, 180deg) translateY(200px)" at progress 0.25 assert_equals: expected "matrix3d(1, 0, 0, 0, 0, -0.382683, 0.92388, 0, 0, -0.92388, -0.382683, 0, 75, -19.1342, 46.194, 1)" but got "matrix3d(1, 0, 0, 0, 0, -1, 1.22465e-16, 0, 0, -1.22465e-16, -1, 0, 75, -50, 6.12323e-15, 1)"
+PASS Match on rotation due to 0deg angle: "rotateX(90deg) translateX(100px)" and "rotateY(0deg) translateY(200px)" are valid transform values
+FAIL Match on rotation due to 0deg angle: Animation between "rotateX(90deg) translateX(100px)" and "rotateY(0deg) translateY(200px)" at progress 0.25 assert_equals: expected "matrix3d(1, 0, 0, 0, 0, 0.382683, 0.92388, 0, 0, -0.92388, 0.382683, 0, 75, 19.1342, 46.194, 1)" but got "matrix(1, 0, 0, 1, 75, 50)"
+PASS Common prefix: "rotate(0deg) translate(100px)" and "rotate(720deg) scale(2) translate(200px)" are valid transform values
+FAIL Common prefix: Animation between "rotate(0deg) translate(100px)" and "rotate(720deg) scale(2) translate(200px)" at progress 0.25 assert_equals: expected "matrix(-1.25, 1.53081e-16, -1.53081e-16, -1.25, -175, 2.14313e-14)" but got "matrix(1.25, 0, 0, 1.25, 175, -4.89859e-14)"
+PASS Complete mismatch (except length): "scale(2) rotate(0deg) translate(100px)" and "rotate(720deg) scale(2) translate(200px)" are valid transform values
+FAIL Complete mismatch (except length): Animation between "scale(2) rotate(0deg) translate(100px)" and "rotate(720deg) scale(2) translate(200px)" at progress 0.25 assert_equals: expected "matrix(2, 0, 0, 2, 250, 0)" but got "matrix(2, 0, 0, 2, 250, -4.89859e-14)"
+PASS Complete mismatch including length: "scale(2) rotate(0deg)" and "rotate(720deg) scale(2) translate(200px)" are valid transform values
+FAIL Complete mismatch including length: Animation between "scale(2) rotate(0deg)" and "rotate(720deg) scale(2) translate(200px)" at progress 0.25 assert_equals: expected "matrix(2, 0, 0, 2, 100, 0)" but got "matrix(2, 0, 0, 2, 100, -4.89859e-14)"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/list-interpolation.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/list-interpolation.html
index 91092c88..90cdebb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/list-interpolation.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/list-interpolation.html
@@ -11,57 +11,56 @@
 </head>
 <body>
 <script>
-// none -> none
 test_interpolation(
   {
     property: 'transform',
     from: 'none',
     to: 'none',
   },
-  [{ at: 0.25, expect: 'none' }]
+  [{ at: 0.25, expect: 'none' }],
+  'none -> none'
 );
 
-// none -> something
 test_interpolation(
   {
     property: 'transform',
     from: 'none',
     to: 'translate(200px) rotate(720deg)',
   },
-  [{ at: 0.25, expect: 'translate(50px) rotate(180deg)' }]
+  [{ at: 0.25, expect: 'translate(50px) rotate(180deg)' }],
+  'none -> something'
 );
 
-// something -> none
 test_interpolation(
   {
     property: 'transform',
     from: 'translate(200px) rotate(720deg)',
     to: 'none',
   },
-  [{ at: 0.25, expect: 'translate(150px) rotate(540deg)' }]
+  [{ at: 0.25, expect: 'translate(150px) rotate(540deg)' }],
+  'something -> none'
 );
 
-// Mismatched lengths (from is shorter), common part matches
 test_interpolation(
   {
     property: 'transform',
     from: 'translate(100px)',
     to: 'translate(200px) rotate(720deg)',
   },
-  [{ at: 0.25, expect: 'translate(125px) rotate(180deg)' }]
+  [{ at: 0.25, expect: 'translate(125px) rotate(180deg)' }],
+  'Mismatched lengths (from is shorter), common part matches'
 );
 
-// Mismatched lengths (to is shorter), common part matches
 test_interpolation(
   {
     property: 'transform',
     from: 'translate(100px) rotate(720deg)',
     to: 'translate(200px)',
   },
-  [{ at: 0.25, expect: 'translate(125px) rotate(540deg)' }]
+  [{ at: 0.25, expect: 'translate(125px) rotate(540deg)' }],
+  'Mismatched lengths (to is shorter), common part matches'
 );
 
-// Perfect match
 test_interpolation(
   {
     property: 'transform',
@@ -73,47 +72,68 @@
       at: 0.25,
       expect: 'scale(2.25) rotate(540deg) translate(125px) matrix(1, 0, 0, 1, 75, 50) skew(180deg)',
     },
-  ]
+  ],
+  'Perfect match'
 );
 
-// Matches on primitives
 test_interpolation(
   {
     property: 'transform',
     from: 'translateX(100px) scaleX(3) translate(500px) scale(2)',
     to: 'translateY(200px) scale(5) translateX(100px) scaleY(3)',
   },
-  [{ at: 0.25, expect: 'translate(75px, 50px) scale(3.5, 2) translate(400px, 0px) scale(1.75, 2.25)' }]
+  [{ at: 0.25, expect: 'translate(75px, 50px) scale(3.5, 2) translate(400px, 0px) scale(1.75, 2.25)' }],
+  'Matches on primitives'
 );
 
-// Common prefix
+test_interpolation(
+  {
+    property: 'transform',
+    from: 'rotateX(90deg) translateX(100px)',
+    to: 'rotate3d(50, 0, 0, 180deg) translateY(200px)',
+  },
+  [{ at: 0.25, expect: 'rotateX(112.5deg) translate(75px, 50px)' }],
+  'Match on rotation vector'
+);
+
+test_interpolation(
+  {
+    property: 'transform',
+    from: 'rotateX(90deg) translateX(100px)',
+    to: 'rotateY(0deg) translateY(200px)',
+  },
+  [{ at: 0.25, expect: 'rotateX(67.5deg) translate(75px, 50px)' }],
+  'Match on rotation due to 0deg angle'
+);
+
 test_interpolation(
   {
     property: 'transform',
     from: 'rotate(0deg) translate(100px)',
     to: 'rotate(720deg) scale(2) translate(200px)',
   },
-  [{ at: 0.25, expect: 'rotate(180deg) matrix(1.25, 0, 0, 1.25, 175, 0)' }]
+  [{ at: 0.25, expect: 'rotate(180deg) matrix(1.25, 0, 0, 1.25, 175, 0)' }],
+  'Common prefix'
 );
 
-// Complete mismatch (except length)
 test_interpolation(
   {
     property: 'transform',
     from: 'scale(2) rotate(0deg) translate(100px)',
     to: 'rotate(720deg) scale(2) translate(200px)',
   },
-  [{ at: 0.25, expect: 'matrix(2, 0, 0, 2, 250, 0)' }]
+  [{ at: 0.25, expect: 'matrix(2, 0, 0, 2, 250, 0)' }],
+  'Complete mismatch (except length)'
 );
 
-// Complete mismatch including length
 test_interpolation(
   {
     property: 'transform',
     from: 'scale(2) rotate(0deg)',
     to: 'rotate(720deg) scale(2) translate(200px)',
   },
-  [{ at: 0.25, expect: 'matrix(2, 0, 0, 2, 100, 0)' }]
+  [{ at: 0.25, expect: 'matrix(2, 0, 0, 2, 100, 0)' }],
+  'Complete mismatch including length'
 );
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/resources/interpolation-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/resources/interpolation-testcommon.js
index 5ab5551..3791b0a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/resources/interpolation-testcommon.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/animation/resources/interpolation-testcommon.js
@@ -1,5 +1,6 @@
 'use strict';
-function test_interpolation(settings, expectations) {
+function test_interpolation(settings, expectations, name) {
+  var message_prefix = name ? name + ': ' : '';
   // Returns a timing function that at 0.5 evaluates to progress.
   function timingFunction(progress) {
     if (progress === 0)
@@ -13,7 +14,7 @@
   test(function(){
     assert_true(CSS.supports(settings.property, settings.from), 'Value "' + settings.from + '" is supported by ' + settings.property);
     assert_true(CSS.supports(settings.property, settings.to), 'Value "' + settings.to + '" is supported by ' + settings.property);
-  }, '"' + settings.from + '" and "' + settings.to + '" are valid ' + settings.property + ' values');
+  }, message_prefix + '"' + settings.from + '" and "' + settings.to + '" are valid ' + settings.property + ' values');
 
   for (var i = 0; i < expectations.length; ++i) {
     var progress = expectations[i].at;
@@ -49,6 +50,6 @@
       reference.style = '';
 
       assert_equals(getComputedStyle(target)[settings.property], getComputedStyle(reference)[settings.property]);
-    }, 'Animation between "' + settings.from + '" and "' + settings.to + '" at progress ' + progress);
+    }, message_prefix + 'Animation between "' + settings.from + '" and "' + settings.to + '" at progress ' + progress);
   }
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/text-perspective-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/text-perspective-001.html
new file mode 100644
index 0000000..e98b3e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/text-perspective-001.html
@@ -0,0 +1,27 @@
+<!doctype>
+<meta charset="utf-8">
+<title>CSS Test: Text is not incorrectly clipped in presence of perspective.</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://bugzilla.mozilla.org/show_bug.cgi?id=1494685">
+<link rel="mismatch" href="about:blank">
+<style>
+* {
+  margin: 0;
+  padding: 0;
+}
+.container {
+  perspective: 1px;
+}
+.heading {
+  transform: translateZ(-9px) scale(10);
+}
+h1 {
+  font-size: 100px;
+}
+</style>
+<div class="container">
+  <div class="heading">
+    <h1>X</h1>
+  </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry/META.yml b/third_party/WebKit/LayoutTests/external/wpt/css/geometry/META.yml
index 9e3a797..98a2ae9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/geometry/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/geometry/META.yml
@@ -1,5 +1,4 @@
 spec: https://drafts.fxtf.org/geometry/
 suggested_reviewers:
   - peterjoel
-  - tschneidereit
   - dirkschulze
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/header-value-combining.any.js b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/header-value-combining.any.js
index fd08072..bb70d87 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/header-value-combining.any.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/header-value-combining.any.js
@@ -1,11 +1,15 @@
 // META: global=window,worker
 
-promise_test(async t => {
-  const response = await fetch("../../../xhr/resources/headers-basic.asis");
-  assert_equals(response.headers.get("foo-test"), "1, 2, 3");
-}, "response.headers.get('foo-test')");
-
-promise_test(async t => {
-  const response = await fetch("../../../xhr/resources/headers-www-authenticate.asis");
-  assert_equals(response.headers.get("www-authenticate"), "1, 2, 3, 4");
-}, "response.headers.get('www-authenticate')");
+[
+  ["content-length", "0", "header-content-length"],
+  ["content-length", "0, 0", "header-content-length-twice"],
+  ["double-trouble", ", ", "headers-double-empty"],
+  ["foo-test", "1, 2, 3", "headers-basic"],
+  ["heya", ", \u000B\u000C, 1, , , 2", "headers-some-are-empty"],
+  ["www-authenticate", "1, 2, 3, 4", "headers-www-authenticate"],
+].forEach(testValues => {
+  promise_test(async t => {
+    const response = await fetch("../../../xhr/resources/" + testValues[2] + ".asis");
+    assert_equals(response.headers.get(testValues[0]), testValues[1]);
+  }, "response.headers.get('" + testValues[0] + "') expects " + testValues[1]);
+});
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/header-value-combining.any.serviceworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/header-value-combining.any.serviceworker-expected.txt
index 979efea..8298561 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/header-value-combining.any.serviceworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/header-value-combining.any.serviceworker-expected.txt
@@ -1,5 +1,9 @@
 This is a testharness.js-based test.
-FAIL response.headers.get('foo-test') promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
-FAIL response.headers.get('www-authenticate') promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL response.headers.get('content-length') expects 0 promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL response.headers.get('content-length') expects 0, 0 promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL response.headers.get('double-trouble') expects ,  promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL response.headers.get('foo-test') expects 1, 2, 3 promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL response.headers.get('heya') expects , , 1, , , 2 promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+FAIL response.headers.get('www-authenticate') expects 1, 2, 3, 4 promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements/the-innertext-idl-attribute/getter-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements/the-innertext-idl-attribute/getter-expected.txt
index ab79f07a..4717009 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements/the-innertext-idl-attribute/getter-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements/the-innertext-idl-attribute/getter-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 229 tests; 226 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 237 tests; 233 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Simplest possible test ("<div>abc")
 PASS Leading whitespace removed ("<div> abc")
 PASS Trailing whitespace removed ("<div>abc ")
@@ -186,6 +186,9 @@
 PASS Newline-separated table rows ("<div><div class='itable'><span class='row'><span class='cell'>abc</span></span>\n<span class='row'><span class='cell'>def</span></span></div>")
 PASS No newlines around inline-table ("<div>abc<div class='itable'><span class='cell'>def</span></div>ghi")
 PASS Single newline in two-row inline-table ("<div>abc<div class='itable'><span class='row'><span class='cell'>def</span></span>\n<span class='row'><span class='cell'>123</span></span></div>ghi")
+PASS display:table-row on the element itself ("<div style='display:table-row'>")
+PASS display:table-cell on the element itself ("<div style='display:table-cell'>")
+PASS display:table-caption on the element itself ("<div style='display:table-caption'>")
 PASS <ol> list items get no special treatment ("<div><ol><li>abc")
 PASS <ul> list items get no special treatment ("<div><ul><li>abc")
 PASS display:block <script> is rendered ("<div><script style='display:block'>abc")
@@ -200,14 +203,19 @@
 PASS <hr><hr><hr> induces just one line break ("<div>abc<hr><hr><hr>def")
 PASS <hr> content rendered ("<div><hr class='poke'>")
 PASS comment ignored ("<div>abc<!--comment-->def")
+FAIL <br> ("<br>") assert_equals: expected "" but got "\n"
+PASS empty <p> ("<p>")
+PASS empty <div> ("<div>")
 PASS text-transform is applied ("<div><div style='text-transform:uppercase'>abc")
 PASS text-transform handles es-zet ("<div><div style='text-transform:uppercase'>Maß")
 PASS text-transform handles Turkish casing ("<div><div lang='tr' style='text-transform:uppercase'>i ı")
 PASS block-in-inline doesn't add unnecessary newlines ("<div>abc<span>123<div>456</div>789</span>def")
 PASS floats induce a block boundary ("<div>abc<div style='float:left'>123</div>def")
 PASS floats induce a block boundary ("<div>abc<span style='float:left'>123</span>def")
+PASS float on the element itself ("<div style='float:left'>123")
 PASS position:absolute induces a block boundary ("<div>abc<div style='position:absolute'>123</div>def")
 PASS position:absolute induces a block boundary ("<div>abc<span style='position:absolute'>123</span>def")
+PASS position:absolute on the element itself ("<div style='position:absolute'>123")
 PASS position:relative has no effect ("<div>abc<div style='position:relative'>123</div>def")
 PASS position:relative has no effect ("<div>abc<span style='position:relative'>123</span>def")
 PASS overflow:hidden ignored ("<div style='overflow:hidden'>abc")
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements/the-innertext-idl-attribute/getter-tests.js b/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements/the-innertext-idl-attribute/getter-tests.js
index 5139ec9..4dd2b6b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements/the-innertext-idl-attribute/getter-tests.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/elements/the-innertext-idl-attribute/getter-tests.js
@@ -273,6 +273,11 @@
 testText("<div>abc<div class='itable'><span class='row'><span class='cell'>def</span></span>\n<span class='row'><span class='cell'>123</span></span></div>ghi",
          "abcdef\n123ghi", "Single newline in two-row inline-table");
 
+/**** display:table-row/table-cell/table-caption ****/
+testText("<div style='display:table-row'>", "", "display:table-row on the element itself");
+testText("<div style='display:table-cell'>", "", "display:table-cell on the element itself");
+testText("<div style='display:table-caption'>", "", "display:table-caption on the element itself");
+
 /**** Lists ****/
 
 testText("<div><ol><li>abc", "abc", "<ol> list items get no special treatment");
@@ -293,6 +298,9 @@
 testText("<div>abc<hr><hr><hr>def", "abc\ndef", "<hr><hr><hr> induces just one line break");
 testText("<div><hr class='poke'>", "abc", "<hr> content rendered");
 testText("<div>abc<!--comment-->def", "abcdef", "comment ignored");
+testText("<br>", "", "<br>");
+testText("<p>", "", "empty <p>");
+testText("<div>", "", "empty <div>");
 
 /**** text-transform ****/
 
@@ -308,11 +316,13 @@
 
 testText("<div>abc<div style='float:left'>123</div>def", "abc\n123\ndef", "floats induce a block boundary");
 testText("<div>abc<span style='float:left'>123</span>def", "abc\n123\ndef", "floats induce a block boundary");
+testText("<div style='float:left'>123", "123", "float on the element itself");
 
 /**** position ****/
 
 testText("<div>abc<div style='position:absolute'>123</div>def", "abc\n123\ndef", "position:absolute induces a block boundary");
 testText("<div>abc<span style='position:absolute'>123</span>def", "abc\n123\ndef", "position:absolute induces a block boundary");
+testText("<div style='position:absolute'>123", "123", "position:absolute on the element itself");
 testText("<div>abc<div style='position:relative'>123</div>def", "abc\n123\ndef", "position:relative has no effect");
 testText("<div>abc<span style='position:relative'>123</span>def", "abc123def", "position:relative has no effect");
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html
new file mode 100644
index 0000000..3e43749
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference: Combobox block-size test</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+select { -webkit-appearance: none; }
+
+.big { font-size: 48pt;  min-height: 40pt; }
+.lh { line-height: 48pt; min-height: 40pt; }
+
+.mask { position:fixed; left:20px; right:0; top:0; bottom:0; background: black; }
+  </style>
+</head>
+<body>
+
+<!-- mask off differences on the right side -->
+<div class="mask"></div>
+
+<select><optgroup label="label"><option>option</option></select><br>
+<select class="big"><optgroup label="label"><option>option</option></select><br>
+<select class="lh"><optgroup label="label"><option>option</option></select><br>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size.html
new file mode 100644
index 0000000..4aecc59
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Test: Combobox block-size test</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+  <link rel="match" href="select-1-block-size-ref.html">
+  <link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
+  <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1499578">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+select { -webkit-appearance: none; }
+
+optgroup { font-size: 32pt; }
+option { font-size: 24pt; }
+.big { font-size: 48pt; }
+.lh { line-height: 48pt; }
+
+.mask { position:fixed; left:20px; right:0; top:0; bottom:0; background: black; }
+  </style>
+</head>
+<body>
+
+<!-- mask off differences on the right side -->
+<div class="mask"></div>
+
+<select><optgroup label="label"><option>option</option></select><br>
+<select class="big"><optgroup label="label"><option>option</option></select><br>
+<select class="lh"><optgroup label="label"><option>option</option></select><br>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-empty-ref.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-empty-ref.html
new file mode 100644
index 0000000..31ba23a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-empty-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference: empty SELECT</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+  <style>
+
+.none { display: none; }
+
+  </style>
+</head>
+<body>
+
+<table border="1" cellpadding="10">
+<tr>
+<td><select size="4"><option class="none"></select>
+<td><select size="4" style="-webkit-appearance: none"><option class="none">option</select>
+<td><select size="4" style="-webkit-appearance: none; border: 1px solid black"><option class="none">option</select>
+<td><select size="4" style="border: 1px solid black"><option class="none">option</select>
+</table>
+
+<table border="1" cellpadding="10">
+<tr>
+<td><select size="1"><option class="none"></select>
+<td><select size="1" style="-webkit-appearance: none"><option class="none"></select>
+<td><select size="1" style="-webkit-appearance: none; border: 1px solid black"><option class="none"></select>
+<td><select size="1" style="border: 1px solid black"><option class="none"></select>
+</table>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-empty.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-empty.html
new file mode 100644
index 0000000..6568a6d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/the-select-element/select-empty.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Test: empty SELECT</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+  <link rel="match" href="select-empty-ref.html">
+  <link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
+  <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1499230">
+</head>
+<body>
+
+<table border="1" cellpadding="10">
+<tr>
+<td><select size="4"></select>
+<td><select size="4" style="-webkit-appearance: none"></select>
+<td><select size="4" style="-webkit-appearance: none; border: 1px solid black"></select>
+<td><select size="4" style="border: 1px solid black"></select>
+</table>
+
+<table border="1" cellpadding="10">
+<tr>
+<td><select size="1"></select>
+<td><select size="1" style="-webkit-appearance: none"></select>
+<td><select size="1" style="-webkit-appearance: none; border: 1px solid black"></select>
+<td><select size="1" style="border: 1px solid black"></select>
+</table>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/IndexedDB.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/IndexedDB.idl
index 3982d11..137528c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/IndexedDB.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/IndexedDB.idl
@@ -50,9 +50,16 @@
                                     optional [EnforceRange] unsigned long long version);
   [NewObject] IDBOpenDBRequest deleteDatabase(DOMString name);
 
+  Promise<sequence<IDBDatabaseInfo>> databases();
+
   short cmp(any first, any second);
 };
 
+dictionary IDBDatabaseInfo {
+  DOMString name;
+  unsigned long long version;
+};
+
 [Exposed=(Window,Worker)]
 interface IDBDatabase : EventTarget {
   readonly attribute DOMString name;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist b/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist
index 296699b..e138450 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist
+++ b/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist
@@ -59,6 +59,10 @@
 TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.wasm
 TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.bmp
 
+## Whitespace needed for testing
+
+TRAILING WHITESPACE: xhr/resources/headers-some-are-empty.asis
+
 ## Documentation ##
 
 W3C-TEST.ORG: README.md
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/META.yml b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/META.yml
index ef94157e..be61ddd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/META.yml
@@ -4,6 +4,5 @@
   - jacobrossi
   - plehegar
   - scottgonzalez
-  - staktrace
   - RByers
   - NavidZ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/META.yml b/third_party/WebKit/LayoutTests/external/wpt/speech-api/META.yml
index 17263d9..ac4b89b0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/speech-api/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/speech-api/
 suggested_reviewers:
-  - andrenatal
   - gshires
diff --git a/third_party/WebKit/LayoutTests/external/wpt/subresource-integrity/META.yml b/third_party/WebKit/LayoutTests/external/wpt/subresource-integrity/META.yml
index 740ad14..2b8891ec 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/subresource-integrity/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/subresource-integrity/META.yml
@@ -1,8 +1,6 @@
 spec: https://w3c.github.io/webappsec-subresource-integrity/
 suggested_reviewers:
   - metromoxie
-  - fmarier
   - jonathanKingston
   - mikewest
   - hillbrad
-  - mastahyeti
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/META.yml b/third_party/WebKit/LayoutTests/external/wpt/url/META.yml
index 459152f..3a789a0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/META.yml
@@ -1,7 +1,6 @@
 spec: https://url.spec.whatwg.org/
 suggested_reviewers:
   - mikewest
-  - smola
   - domenic
   - Sebmaster
   - annevk
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/META.yml b/third_party/WebKit/LayoutTests/external/wpt/webaudio/META.yml
index 37276da..e8f8cc5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/META.yml
@@ -1,5 +1,4 @@
 spec: https://webaudio.github.io/web-audio-api/
 suggested_reviewers:
-  - chrislo
   - padenot
   - rtoy
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/getallresponseheaders-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/xhr/getallresponseheaders-expected.txt
index bf36826..04b1bec 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/xhr/getallresponseheaders-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/getallresponseheaders-expected.txt
@@ -1,7 +1,10 @@
 This is a testharness.js-based test.
-PASS XMLHttpRequest: getAllResponseHeaders()
-FAIL XMLHttpRequest: getAllResponseHeaders() 1 assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n" but got "also-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+FAIL XMLHttpRequest: getAllResponseHeaders() assert_equals: expected "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n" but got "also-here: Mr. PB\r\nfoo-test: 1, 2\r\newok: lego\r\n"
+PASS XMLHttpRequest: getAllResponseHeaders() 1
 PASS XMLHttpRequest: getAllResponseHeaders() 2
 PASS XMLHttpRequest: getAllResponseHeaders() 3
+PASS XMLHttpRequest: getAllResponseHeaders() 4
+PASS XMLHttpRequest: getAllResponseHeaders() 5
+PASS XMLHttpRequest: getAllResponseHeaders() 6
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/getallresponseheaders.htm b/third_party/WebKit/LayoutTests/external/wpt/xhr/getallresponseheaders.htm
index e574733..72e27a59 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/xhr/getallresponseheaders.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/getallresponseheaders.htm
@@ -7,37 +7,29 @@
 async_test((t) => {
   const client = new XMLHttpRequest()
   client.onload = t.step_func_done(() => {
-    assert_equals(client.getAllResponseHeaders(), "foo-test: 1, 2, 3\r\n")
-  })
-  client.onerror = t.unreached_func("unexpected error")
-  client.open("GET", "resources/headers-basic.asis")
-  client.send(null)
-})
-
-async_test((t) => {
-  const client = new XMLHttpRequest()
-  client.onload = t.step_func_done(() => {
     assert_equals(client.getAllResponseHeaders(), "also-here: Mr. PB\r\newok: lego\r\nfoo-test: 1, 2\r\n")
   })
   client.onerror = t.unreached_func("unexpected error")
   client.open("GET", "resources/headers.asis")
   client.send(null)
-})
+});
 
-test(() => {
-  const client = new XMLHttpRequest
-  client.open("GET", "resources/header-content-length.asis", false)
-  client.send()
-  assert_equals(client.getAllResponseHeaders(), "content-length: 0\r\n")
-})
-
-async_test(t => {
-  const client = new XMLHttpRequest();
-  client.onload = t.step_func_done(() => {
-    assert_equals(client.getAllResponseHeaders(), "www-authenticate: 1, 2, 3, 4\r\n");
+[
+  ["content-length", "0", "header-content-length"],
+  ["content-length", "0, 0", "header-content-length-twice"],
+  ["double-trouble", ", ", "headers-double-empty"],
+  ["foo-test", "1, 2, 3", "headers-basic"],
+  ["heya", ", \u000B\u000C, 1, , , 2", "headers-some-are-empty"],
+  ["www-authenticate", "1, 2, 3, 4", "headers-www-authenticate"],
+].forEach(testValues => {
+  async_test(t => {
+    const client = new XMLHttpRequest();
+    client.onload = t.step_func_done(() => {
+      assert_equals(client.getAllResponseHeaders(), testValues[0] + ": " + testValues[1] + "\r\n");
+    });
+    client.onerror = t.unreached_func("unexpected error");
+    client.open("GET", "resources/" + testValues[2] + ".asis");
+    client.send();
   });
-  client.onerror = t.unreached_func("unexpected error");
-  client.open("GET", "resources/headers-www-authenticate.asis");
-  client.send();
 });
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/getresponseheader.any.js b/third_party/WebKit/LayoutTests/external/wpt/xhr/getresponseheader.any.js
index 4ff791a..6eeccd03 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/xhr/getresponseheader.any.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/getresponseheader.any.js
@@ -1,19 +1,18 @@
-async_test(t => {
-  const client = new XMLHttpRequest();
-  client.onload = t.step_func_done(() => {
-    assert_equals(client.getResponseHeader("foo-test"), "1, 2, 3");
-  });
-  client.onerror = t.unreached_func("unexpected error");
-  client.open("GET", "resources/headers-basic.asis");
-  client.send();
-}, "getResponseHeader('foo-test')");
-
-async_test(t => {
-  const client = new XMLHttpRequest();
-  client.onload = t.step_func_done(() => {
-    assert_equals(client.getResponseHeader("www-authenticate"), "1, 2, 3, 4");
-  });
-  client.onerror = t.unreached_func("unexpected error");
-  client.open("GET", "resources/headers-www-authenticate.asis");
-  client.send();
-}, "getResponseHeader('www-authenticate')");
+[
+  ["content-length", "0", "header-content-length"],
+  ["content-length", "0, 0", "header-content-length-twice"],
+  ["double-trouble", ", ", "headers-double-empty"],
+  ["foo-test", "1, 2, 3", "headers-basic"],
+  ["heya", ", \u000B\u000C, 1, , , 2", "headers-some-are-empty"],
+  ["www-authenticate", "1, 2, 3, 4", "headers-www-authenticate"],
+].forEach(testValues => {
+  async_test(t => {
+    const client = new XMLHttpRequest();
+    client.onload = t.step_func_done(() => {
+      assert_equals(client.getResponseHeader(testValues[0]), testValues[1]);
+    });
+    client.onerror = t.unreached_func("unexpected error");
+    client.open("GET", "resources/" + testValues[2] + ".asis");
+    client.send();
+  }, "getResponseHeader('" + testValues[0] + "') expects " + testValues[1]);
+});
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/resources/header-content-length-twice.asis b/third_party/WebKit/LayoutTests/external/wpt/xhr/resources/header-content-length-twice.asis
new file mode 100644
index 0000000..e3196984
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/resources/header-content-length-twice.asis
@@ -0,0 +1,3 @@
+HTTP/1.0 200 NANANA
+CONTENT-LENGTH:  0
+content-length:	 0
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/resources/headers-double-empty.asis b/third_party/WebKit/LayoutTests/external/wpt/xhr/resources/headers-double-empty.asis
new file mode 100644
index 0000000..14304b2b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/resources/headers-double-empty.asis
@@ -0,0 +1,3 @@
+HTTP/1.1 444 HI
+double-trouble:
+double-trouble:
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/resources/headers-some-are-empty.asis b/third_party/WebKit/LayoutTests/external/wpt/xhr/resources/headers-some-are-empty.asis
new file mode 100644
index 0000000..1783e1a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/resources/headers-some-are-empty.asis
@@ -0,0 +1,7 @@
+HTTP/1.0 200 MEH
+HEYA:	 
+HEYA: 
+HEYA: 1	
+HEYA:
+HEYA:	
+HEYA: 	2
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/send-content-type-charset-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/xhr/send-content-type-charset-expected.txt
index 8143f7d5..068a31b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/xhr/send-content-type-charset-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/send-content-type-charset-expected.txt
@@ -3,19 +3,19 @@
 PASS header with invalid MIME type (empty string) is not changed
 PASS known charset but bogus header - missing MIME type
 PASS bogus charset and bogus header - missing MIME type
-PASS Correct text/plain MIME with charset
+FAIL If charset= param is UTF-8 (case-insensitive), it should not be changed assert_equals: expected "text/plain;charset=utf-8" but got "text/plain;charset=UTF-8"
 PASS If no charset= param is given, implementation should not add one - unknown MIME
 PASS If no charset= param is given, implementation should not add one - known MIME
 PASS If no charset= param is given, implementation should not add one - known MIME, unknown param, two spaces
 FAIL charset given but wrong, fix it (unknown MIME, bogus charset) assert_equals: expected "text/x-thepiano;charset=UTF-8" but got "text/x-thepiano;charset= UTF-8"
-FAIL charset given but wrong, fix it (known MIME, bogus charset) assert_equals: expected "text/plain;charset=UTF-8" but got "text/plain;charset=UTF-8;charset=UTF-8"
+FAIL If charset= param is UTF-8 (case-insensitive), it should not be changed (bogus charset) assert_equals: expected "text/plain;charset=utf-8;charset=waddup" but got "text/plain;charset=UTF-8;charset=UTF-8"
 PASS charset given but wrong, fix it (known MIME, actual charset)
-FAIL Multiple charset parameters deduplicate, bogus parameter dropped assert_equals: expected "text/x-pink-unicorn;charset=UTF-8" but got "text/x-pink-unicorn; charset=UTF-8; charset=UTF-8; notrelated; charset=UTF-8"
+FAIL Multiple non-UTF-8 charset parameters deduplicate, bogus parameter dropped assert_equals: expected "text/x-pink-unicorn;charset=UTF-8" but got "text/x-pink-unicorn; charset=UTF-8; charset=UTF-8; notrelated; charset=UTF-8"
 PASS No content type set, give MIME and charset
-FAIL charset with space assert_equals: expected "text/plain;charset=UTF-8" but got "text/plain;charset= UTF-8"
-FAIL charset in double quotes assert_equals: expected "text/plain;charset=UTF-8" but got "text/plain;charset=\"UTF-8\""
+FAIL charset with space that is UTF-8 does not change assert_equals: expected "text/plain;charset= utf-8" but got "text/plain;charset= UTF-8"
+FAIL charset in double quotes that is UTF-8 does not change assert_equals: expected "text/plain;charset=\"utf-8\"" but got "text/plain;charset=\"UTF-8\""
 FAIL charset in double quotes with space assert_equals: expected "text/plain;charset=UTF-8" but got "text/plain;charset=\" UTF-8\""
-FAIL charset in double quotes with backslashes assert_equals: expected "text/plain;charset=UTF-8" but got "text/plain;charset=\"UTF-8\""
+FAIL charset in double quotes with backslashes that is UTF-8 does not change assert_equals: expected "text/plain;charset=\"u\\t\f-8\"" but got "text/plain;charset=\"UTF-8\""
 FAIL unknown parameters need to be preserved assert_equals: expected "yo/yo;charset=UTF-8;yo=YO;x=y" but got "YO/yo;charset=UTF-8;yo=YO; X=y"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/send-content-type-charset.htm b/third_party/WebKit/LayoutTests/external/wpt/xhr/send-content-type-charset.htm
index 4e75df2..0a91e1f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/xhr/send-content-type-charset.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/send-content-type-charset.htm
@@ -4,8 +4,6 @@
     <title>XMLHttpRequest: send() - charset parameter of Content-Type</title>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#the-send()-method" data-tested-assertations="following::ol[1]/li[4]/p/code[contains(text(),'Content-Type')]/.. following::ol[1]/li[4]/p/code[contains(text(),'Content-Type')]/../following-sibling::p" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-XMLHttpRequest-send-a-string" data-tested-assertations="following::p[2]" />
   </head>
   <body>
     <div id="log"></div>
@@ -45,8 +43,8 @@
       )
       request(
         "text/plain;charset=utf-8",
-        "text/plain;charset=UTF-8",
-        "Correct text/plain MIME with charset"
+        "text/plain;charset=utf-8",
+        "If charset= param is UTF-8 (case-insensitive), it should not be changed"
       )
       request(
         "text/x-pink-unicorn",
@@ -70,8 +68,8 @@
       )
       request(
         "text/plain;charset=utf-8;charset=waddup",
-        "text/plain;charset=UTF-8",
-        "charset given but wrong, fix it (known MIME, bogus charset)"
+        "text/plain;charset=utf-8;charset=waddup",
+        "If charset= param is UTF-8 (case-insensitive), it should not be changed (bogus charset)"
       )
       request(
         "text/plain;charset=shift-jis",
@@ -81,7 +79,7 @@
       request(
         "text/x-pink-unicorn; charset=windows-1252; charset=bogus; notrelated; charset=ascii",
         "text/x-pink-unicorn;charset=UTF-8",
-        "Multiple charset parameters deduplicate, bogus parameter dropped"
+        "Multiple non-UTF-8 charset parameters deduplicate, bogus parameter dropped"
       )
       request(
         null,
@@ -90,20 +88,20 @@
       )
       request(
         "text/plain;charset= utf-8",
-        "text/plain;charset=UTF-8",
-        "charset with space")
+        "text/plain;charset= utf-8",
+        "charset with space that is UTF-8 does not change")
       request(
         "text/plain;charset=\"utf-8\"",
-        "text/plain;charset=UTF-8",
-        "charset in double quotes")
+        "text/plain;charset=\"utf-8\"",
+        "charset in double quotes that is UTF-8 does not change")
       request(
         "text/plain;charset=\" utf-8\"",
         "text/plain;charset=UTF-8",
         "charset in double quotes with space")
       request(
         "text/plain;charset=\"u\\t\\f-8\"",
-        "text/plain;charset=UTF-8",
-        "charset in double quotes with backslashes")
+        "text/plain;charset=\"u\\t\\f-8\"",
+        "charset in double quotes with backslashes that is UTF-8 does not change")
       request(
         "YO/yo;charset=x;yo=YO; X=y",
         "yo/yo;charset=UTF-8;yo=YO;x=y",
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/setrequestheader-combining.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/xhr/setrequestheader-combining.window-expected.txt
new file mode 100644
index 0000000..7bdad144
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/setrequestheader-combining.window-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL setRequestHeader() combining header values assert_equals: expected "test-me: , , , , x\tx, \n" but got "test-me: , , , , x\tx,\n"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/setrequestheader-combining.window.js b/third_party/WebKit/LayoutTests/external/wpt/xhr/setrequestheader-combining.window.js
new file mode 100644
index 0000000..fc847eb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/setrequestheader-combining.window.js
@@ -0,0 +1,12 @@
+test(() => {
+  const client = new XMLHttpRequest();
+  client.open("POST", "resources/inspect-headers.py?filter_name=test-me", false);
+  client.setRequestHeader("test-me", "");
+  client.setRequestHeader("test-me", "");
+  client.setRequestHeader("test-me", " ");
+  client.setRequestHeader("test-me", "\t");
+  client.setRequestHeader("test-me", "x\tx");
+  client.setRequestHeader("test-me", "");
+  client.send();
+  assert_equals(client.responseText, "test-me: , , , , x\tx, \n");
+}, "setRequestHeader() combining header values");
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resource-load-priorities.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resource-load-priorities.html
new file mode 100644
index 0000000..88de91c1a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resource-load-priorities.html
@@ -0,0 +1,93 @@
+<title>ResourceLoadPriority tests</title>
+
+<script src="resources/common.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+function openWindow(url) {
+  const win = window.open(url, '_blank');
+  add_result_callback(() => win.close());
+  return win;
+}
+
+function resource_load_priority_test(windowURL, expected_priority, description) {
+  promise_test(async () => {
+    openWindow('resources/' + windowURL);
+    const priority_event =
+      await new Promise(resolve => window.onmessage = resolve);
+    assert_not_equals(priority_event.data,
+                      'FAILED',
+                      'The resource failed to load for some reason.');
+
+    assert_equals(priority_event.data, expected_priority);
+  }, description);
+}
+
+resource_load_priority_test(
+  'off-screen-image.html', kLow,
+  'Off-screen images should be loaded with kLow priority');
+
+resource_load_priority_test(
+  'render-blocking-stylesheet.html', kVeryHigh,
+  'Render-blocking style sheets should be loaded with kVeryHigh priority');
+
+resource_load_priority_test(
+  'parser-blocking-script.html', kHigh,
+  'Parser-blocking scripts should be loaded with kHigh priority');
+
+resource_load_priority_test(
+  'async-script.html', kHigh,
+  'Async scripts should be loaded with kLow priority');
+
+resource_load_priority_test(
+  'defer-script.html', kHigh,
+  'Deferred scripts should be loaded with kLow priority');
+
+resource_load_priority_test(
+  'module-script.html', kHigh,
+  'Module scripts should be loaded with kHigh priority');
+
+resource_load_priority_test(
+  'iframe.html', kVeryHigh, 'Iframes should be loaded with kVeryHigh priority');
+
+resource_load_priority_test(
+  'fetch.html', kHigh,
+  'Requests from the Fetch API should be loaded with kHigh priority');
+
+resource_load_priority_test(
+  'xhr.html', kHigh, 'XHRs should be loaded with kHigh priority');
+
+resource_load_priority_test(
+  'sync-xhr.html', kVeryHigh,
+  'Synchronous XHRs should be loaded with kVeryHigh priority');
+
+// Preload tests.
+resource_load_priority_test(
+  'preload/as-style.html', kVeryHigh,
+  'Preloaded style sheets should be loaded with kVeryHigh priority');
+
+resource_load_priority_test(
+  'preload/as-script.html', kHigh,
+  'Preloaded scripts should be loaded with kHigh priority');
+
+resource_load_priority_test(
+  'preload/as-font.html', kHigh,
+  'Preloaded fonts should be loaded with kHigh priority');
+
+resource_load_priority_test(
+  'preload/as-audio.html', kLow,
+  'Preloaded audio files should be loaded with kLow priority');
+
+resource_load_priority_test(
+  'preload/as-video.html', kLow,
+  'Preloaded videos should be loaded with kLow priority');
+
+resource_load_priority_test(
+  'preload/as-fetch.html', kHigh,
+  'Preloaded fetches should be loaded with kHigh priority');
+
+resource_load_priority_test(
+  'preload/as-image.html', kLow,
+  'Preloaded images should be loaded with kLow priority');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/async-script.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/async-script.html
new file mode 100644
index 0000000..3a42ced
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/async-script.html
@@ -0,0 +1,2 @@
+<script src="common.js"></script>
+<script src="../../resources/dummy.js" async onload="reportPriority(this.src)" onerror="reportFailure()"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/common.js b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/common.js
new file mode 100644
index 0000000..7128410
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/common.js
@@ -0,0 +1,21 @@
+/**
+ * These values map to some of the the current
+ * priority enum members in blink::ResourceLoadPriority.
+ * The values are exposed through window.internals
+ * and in these tests, we use the below variables to represent
+ * the exposed values in a readable way.
+ */
+const kLow = 1,
+      kMedium = 2,
+      kHigh = 3,
+      kVeryHigh = 4;
+
+function reportPriority(url, optionalDoc) {
+  const documentToUse = optionalDoc ? optionalDoc : document;
+  const loadPriority = internals.getResourcePriority(url, documentToUse);
+  window.opener.postMessage(loadPriority, '*');
+}
+
+function reportFailure() {
+  window.opener.postMessage('FAILED', '*');
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/defer-script.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/defer-script.html
new file mode 100644
index 0000000..d66f135e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/defer-script.html
@@ -0,0 +1,2 @@
+<script src="common.js"></script>
+<script src="../../resources/dummy.js" defer onload="reportPriority(this.src)" onerror="reportFailure()"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/fetch.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/fetch.html
new file mode 100644
index 0000000..3cde8df
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/fetch.html
@@ -0,0 +1,10 @@
+<script src="common.js"></script>
+<script>
+  fetch('../../resources/dummy.html')
+    .then(response => {
+      reportPriority(response.url);
+    })
+    .catch(() => {
+      reportFailure();
+    });
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/iframe.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/iframe.html
new file mode 100644
index 0000000..de711b5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/iframe.html
@@ -0,0 +1,2 @@
+<script src="common.js"></script>
+<iframe src="../../resources/dummy.html" onload="reportPriority(this.src, this.contentDocument)" onerror="reportFailure()"></iframe>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/module-script.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/module-script.html
new file mode 100644
index 0000000..69526cc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/module-script.html
@@ -0,0 +1,2 @@
+<script src="common.js"></script>
+<script src="../../resources/dummy.js" type=module onload="reportPriority(this.src)" onerror="reportFailure()"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/off-screen-image.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/off-screen-image.html
new file mode 100644
index 0000000..e9bd03b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/off-screen-image.html
@@ -0,0 +1,11 @@
+<script src="common.js"></script>
+<script>
+  const image = new Image();
+  image.src = '../../resources/square.png';
+
+  image.onload = e => {
+    reportPriority(image.src);
+  };
+
+  image.onerror = e => reportFailure;
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/parser-blocking-script.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/parser-blocking-script.html
new file mode 100644
index 0000000..35ca0021
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/parser-blocking-script.html
@@ -0,0 +1,2 @@
+<script src="common.js"></script>
+<script src="../../resources/dummy.js" onload="reportPriority(this.src)" onerror="reportFailure()"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-audio.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-audio.html
new file mode 100644
index 0000000..f5ac644
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-audio.html
@@ -0,0 +1,3 @@
+<script src="../common.js"></script>
+
+<link rel="preload" as="audio" href="../../../resources/test.wav" type="audio/wav" onload="reportPriority(this.href)" onerror="reportFailure()"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-fetch.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-fetch.html
new file mode 100644
index 0000000..ff52efbe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-fetch.html
@@ -0,0 +1,3 @@
+<script src="../common.js"></script>
+
+<link rel="preload" as="fetch" href=../../../resources/dummy.html onload="reportPriority(this.href)" onerror="reportFailure()"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-font.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-font.html
new file mode 100644
index 0000000..e0ed25c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-font.html
@@ -0,0 +1,3 @@
+<script src="../common.js"></script>
+
+<link rel="preload" as="font" href=../../../resources/Ahem.ttf type="font/ttf" onload="reportPriority(this.href)" onerror="reportFailure()">
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-image.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-image.html
new file mode 100644
index 0000000..2398373
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-image.html
@@ -0,0 +1,3 @@
+<script src="../common.js"></script>
+
+<link rel="preload" as="image" href="../../../resources/square.png" onload="reportPriority(this.href)" onerror="reportFailure()"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-script.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-script.html
new file mode 100644
index 0000000..1e8b100
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-script.html
@@ -0,0 +1,3 @@
+<script src="../common.js"></script>
+
+<link rel="preload" as="script" href="../../../resources/dummy.js" onload="reportPriority(this.href)" onerror="reportFailure()"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-style.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-style.html
new file mode 100644
index 0000000..c1c4e82
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-style.html
@@ -0,0 +1,4 @@
+<script src="../common.js"></script>
+
+<!-- Media-matching style sheets block rendering, and are critical -->
+<link rel="preload" as="style" href="../../../resources/dummy.css" onload="reportPriority(this.href)" onerror="reportFailure()">
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-video.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-video.html
new file mode 100644
index 0000000..1f318d29
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/preload/as-video.html
@@ -0,0 +1,3 @@
+<script src="../common.js"></script>
+
+<link rel="preload" as="video" href=../../../resources/test.mp4 type="video/mp4" onload="reportPriority(this.href)" onerror="reportFailure()"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/render-blocking-stylesheet.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/render-blocking-stylesheet.html
new file mode 100644
index 0000000..be4bc0ec
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/render-blocking-stylesheet.html
@@ -0,0 +1,4 @@
+<script src="common.js"></script>
+
+<!-- Media-matching style sheets block rendering, and are critical -->
+<link rel="stylesheet" href="../../resources/dummy.css" onload="reportPriority(this.href)" onerror="reportFailure()">
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/sync-xhr.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/sync-xhr.html
new file mode 100644
index 0000000..aff9177
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/sync-xhr.html
@@ -0,0 +1,11 @@
+<script src="common.js"></script>
+<script>
+  const xhr = new XMLHttpRequest();
+  xhr.open('GET', '../../resources/dummy.html', false);
+  xhr.send();
+
+  if (xhr.status === 200)
+    reportPriority(xhr.responseURL);
+  else
+    reportFailure();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/priorities/resources/xhr.html b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/xhr.html
new file mode 100644
index 0000000..b124dd5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/priorities/resources/xhr.html
@@ -0,0 +1,12 @@
+<script src="common.js"></script>
+<script>
+  const xhr = new XMLHttpRequest();
+  xhr.open('GET', '../../resources/dummy.html');
+  xhr.send();
+
+  xhr.onload = e => {
+    reportPriority(xhr.responseURL);
+  }
+
+  xhr.onerror = reportFailure;
+</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 85d4f5d..6a09d7c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png
index d46ec31..a272b20 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png
index 78014c8..dc28245 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
index 78014c8..dc28245 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
index d46ec31..a272b20 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.png
index 8c2df1c..b805516 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.png
index 45b8be89..fca4441 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.png
index 744888a..a9db566 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.png
index e4574ee..a2cdbded 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.png
index 43d1d77..16a2b350 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.png
index 78014c8..dc28245 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.png
index 51f69271..6feaffe6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.png
index d6e30d2..e53564fe 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.png
index bb9aa8b3..64a762c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.png
index 6201165..b7fcfb2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.png
new file mode 100644
index 0000000..e773d1c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index e773d1c..41f94c3b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png
index 60349c2..48e2c70 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
index 60349c2..48e2c70 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-after-reload-expected.png
index f23c766..bc86a51bc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-after-reload-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-after-reload-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-strict-expected.png
index 918138b..a7dcd69 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-strict-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-strict-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-expected.png
index 2a62ad5..2fce9b0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-strict-expected.png
index 14c39a3..b55884d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-strict-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-strict-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-without-preload-expected.png
index e43fdb7..96294b9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-without-preload-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-without-preload-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-controls-rendering-expected.png
index ce354585f..2d5c5b1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-display-toggle-expected.png
index bd14330..0af2bac 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-display-toggle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-display-toggle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png
index 947ca89..503862dc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.png
new file mode 100644
index 0000000..6e13f8ee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 6e13f8ee..1d593fbc7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png
index b985e1a..d578ae1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.png
index 3166d16..44c64cd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.png
index 1232bba86..7939add5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.png
index 70870275..776ad4d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.png
index c74ab967..032e640 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.png
index 1d20bca..e761cf9c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.png
index 5c4be3a..be2ea72 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.png
index 61bab506..f5b9495 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png
index 058e324..555c3d0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 15254408..dd6a5bde 100644
--- a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png
index fdefc931..c7a5749 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.png
index 54b8c22..560ede0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.png
index c18b578..801ffeb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.png
index bd7c6c4..9053a0944 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.png
index 79086fad..27bb09ae 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.png
index b99686f5..d41ef4a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.png
index 2008981..c030883 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.png
index e000e22..fb91e2c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.png
index ffbabb6..bbe1ca4d7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.png
index b6d0785..cbfb1da 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.png
new file mode 100644
index 0000000..15254408
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h
index f74b3f13..711006c 100644
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h
+++ b/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h
@@ -50,10 +50,9 @@
 //
 // It is implemented by content::WebServiceWorkerProviderImpl.
 //
-// WebServiceWorkerProvider is created in ServiceWorkerContainerClient::From(),
-// which is used to instantiate navigator.serviceWorker. It is
-// owned by ServiceWorkerContainerClient, which is a
-// garbage collected Supplement for Document.
+// WebServiceWorkerProvider is created in ServiceWorkerContainer::From(),
+// which is used to instantiate navigator.serviceWorker. It is owned by
+// ServiceWorkerContainer, which is a garbage collected Supplement for Document.
 //
 // Each ServiceWorkerContainer instance has a WebServiceWorkerProvider.
 // ServiceWorkerContainer is called the "client" of the
diff --git a/third_party/blink/public/platform/web_content_settings_client.h b/third_party/blink/public/platform/web_content_settings_client.h
index 04a501da..3fff8c71 100644
--- a/third_party/blink/public/platform/web_content_settings_client.h
+++ b/third_party/blink/public/platform/web_content_settings_client.h
@@ -46,9 +46,7 @@
   }
 
   // Controls whether access to Indexed DB are allowed for this frame.
-  virtual bool AllowIndexedDB(const WebString& name, const WebSecurityOrigin&) {
-    return true;
-  }
+  virtual bool AllowIndexedDB(const WebSecurityOrigin&) { return true; }
 
   // Controls whether scripts are allowed to execute for this frame.
   virtual bool AllowScript(bool enabled_per_settings) {
diff --git a/third_party/blink/public/platform/web_document_subresource_filter.h b/third_party/blink/public/platform/web_document_subresource_filter.h
index 614366e..17d20f8 100644
--- a/third_party/blink/public/platform/web_document_subresource_filter.h
+++ b/third_party/blink/public/platform/web_document_subresource_filter.h
@@ -36,8 +36,6 @@
   // console.
   virtual bool ShouldLogToConsole() = 0;
 
-  virtual bool GetIsAssociatedWithAdSubframe() const = 0;
-
   // Report that the resource request corresponding to |request_id|  was tagged
   // as an ad.
   virtual void ReportAdRequestId(int request_id) {}
diff --git a/third_party/blink/public/web/worker_content_settings_proxy.mojom b/third_party/blink/public/web/worker_content_settings_proxy.mojom
index 9b22c742..500a16a 100644
--- a/third_party/blink/public/web/worker_content_settings_proxy.mojom
+++ b/third_party/blink/public/web/worker_content_settings_proxy.mojom
@@ -16,7 +16,7 @@
 
   // Returns whether the worker is allowed access to IndexedDB.
   [Sync]
-  AllowIndexedDB(mojo_base.mojom.String16 name) => (bool result);
+  AllowIndexedDB() => (bool result);
 
   // Returns whether the worker is allowed access to the file system.
   [Sync]
diff --git a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc b/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
index 90aff06..7965b38 100644
--- a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
+++ b/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/platform/bindings/to_v8.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "v8/include/v8.h"
 
 namespace blink {
@@ -87,6 +88,10 @@
 }
 
 void AddOriginals(ScriptState* script_state, v8::Local<v8::Object> binding) {
+  // These values are only used when serialization is enabled.
+  if (!RuntimeEnabledFeatures::TransferableStreamsEnabled())
+    return;
+
   v8::Local<v8::Object> global = script_state->GetContext()->Global();
   v8::Local<v8::Context> context = script_state->GetContext();
   v8::Isolate* isolate = script_state->GetIsolate();
diff --git a/third_party/blink/renderer/core/animation/effect_stack_test.cc b/third_party/blink/renderer/core/animation/effect_stack_test.cc
index 0ccd068..9cf45e9 100644
--- a/third_party/blink/renderer/core/animation/effect_stack_test.cc
+++ b/third_party/blink/renderer/core/animation/effect_stack_test.cc
@@ -180,8 +180,8 @@
 
   UpdateTimeline(TimeDelta::FromSeconds(11));
   ThreadState::Current()->CollectAllGarbage();
-  interpolations =
-      new ActiveInterpolationsMap(EffectStack::ActiveInterpolations(
+  interpolations = MakeGarbageCollected<ActiveInterpolationsMap>(
+      EffectStack::ActiveInterpolations(
           &element->GetElementAnimations()->GetEffectStack(), nullptr, nullptr,
           KeyframeEffect::kDefaultPriority));
   EXPECT_EQ(1u, interpolations->size());
@@ -190,8 +190,8 @@
 
   UpdateTimeline(TimeDelta::FromSeconds(13));
   ThreadState::Current()->CollectAllGarbage();
-  interpolations =
-      new ActiveInterpolationsMap(EffectStack::ActiveInterpolations(
+  interpolations = MakeGarbageCollected<ActiveInterpolationsMap>(
+      EffectStack::ActiveInterpolations(
           &element->GetElementAnimations()->GetEffectStack(), nullptr, nullptr,
           KeyframeEffect::kDefaultPriority));
   EXPECT_EQ(1u, interpolations->size());
@@ -200,8 +200,8 @@
 
   UpdateTimeline(TimeDelta::FromSeconds(15));
   ThreadState::Current()->CollectAllGarbage();
-  interpolations =
-      new ActiveInterpolationsMap(EffectStack::ActiveInterpolations(
+  interpolations = MakeGarbageCollected<ActiveInterpolationsMap>(
+      EffectStack::ActiveInterpolations(
           &element->GetElementAnimations()->GetEffectStack(), nullptr, nullptr,
           KeyframeEffect::kDefaultPriority));
   EXPECT_EQ(1u, interpolations->size());
@@ -210,8 +210,8 @@
 
   UpdateTimeline(TimeDelta::FromSeconds(17));
   ThreadState::Current()->CollectAllGarbage();
-  interpolations =
-      new ActiveInterpolationsMap(EffectStack::ActiveInterpolations(
+  interpolations = MakeGarbageCollected<ActiveInterpolationsMap>(
+      EffectStack::ActiveInterpolations(
           &element->GetElementAnimations()->GetEffectStack(), nullptr, nullptr,
           KeyframeEffect::kDefaultPriority));
   EXPECT_EQ(1u, interpolations->size());
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_model.cc b/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
index 3a5c62de..2c4e8d31 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
@@ -310,7 +310,7 @@
   if (keyframe_groups_)
     return;
 
-  keyframe_groups_ = new KeyframeGroupMap;
+  keyframe_groups_ = MakeGarbageCollected<KeyframeGroupMap>();
   scoped_refptr<TimingFunction> zero_offset_easing = default_keyframe_easing_;
   Vector<double> computed_offsets = GetComputedOffsets(keyframes_);
   DCHECK_EQ(computed_offsets.size(), keyframes_.size());
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 58a1697..d9682c498 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -2617,7 +2617,6 @@
     {
       name: "scroll-margin-block-end",
       property_methods: ["ParseSingleValue"],
-      runtime_flag: "CSSScrollSnapPoints",
       direction_aware_options: {
         logical_side: "after",
         shorthand_for_physical_side: "scrollMarginShorthand",
@@ -2639,7 +2638,6 @@
     {
       name: "scroll-margin-block-start",
       property_methods: ["ParseSingleValue"],
-      runtime_flag: "CSSScrollSnapPoints",
       direction_aware_options: {
         logical_side: "before",
         shorthand_for_physical_side: "scrollMarginShorthand",
@@ -2649,7 +2647,6 @@
     {
       name: "scroll-margin-bottom",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "primitive",
       default_value: "0.0f",
@@ -2660,7 +2657,6 @@
     {
       name: "scroll-margin-inline-end",
       property_methods: ["ParseSingleValue"],
-      runtime_flag: "CSSScrollSnapPoints",
       direction_aware_options: {
         logical_side: "end",
         shorthand_for_physical_side: "scrollMarginShorthand",
@@ -2670,7 +2666,6 @@
     {
       name: "scroll-margin-inline-start",
       property_methods: ["ParseSingleValue"],
-      runtime_flag: "CSSScrollSnapPoints",
       direction_aware_options: {
         logical_side: "start",
         shorthand_for_physical_side: "scrollMarginShorthand",
@@ -2680,7 +2675,6 @@
     {
       name: "scroll-margin-left",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "primitive",
       default_value: "0.0f",
@@ -2691,7 +2685,6 @@
     {
       name: "scroll-margin-right",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "primitive",
       default_value: "0.0f",
@@ -2702,7 +2695,6 @@
     {
       name: "scroll-margin-top",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "primitive",
       default_value: "0.0f",
@@ -2713,7 +2705,6 @@
     {
       name: "scroll-padding-block-end",
       property_methods: ["ParseSingleValue"],
-      runtime_flag: "CSSScrollSnapPoints",
       include_paths: ["third_party/blink/renderer/platform/geometry/length.h"],
       typedom_types: ["Keyword", "Length", "Percentage"],
       type_name: "Length",
@@ -2726,7 +2717,6 @@
     {
       name: "scroll-padding-block-start",
       property_methods: ["ParseSingleValue"],
-      runtime_flag: "CSSScrollSnapPoints",
       include_paths: ["third_party/blink/renderer/platform/geometry/length.h"],
       typedom_types: ["Keyword", "Length", "Percentage"],
       type_name: "Length",
@@ -2739,7 +2729,6 @@
     {
       name: "scroll-padding-bottom",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "<length>",
       default_value: "Length()",
@@ -2749,7 +2738,6 @@
     {
       name: "scroll-padding-inline-end",
       property_methods: ["ParseSingleValue"],
-      runtime_flag: "CSSScrollSnapPoints",
       include_paths: ["third_party/blink/renderer/platform/geometry/length.h"],
       typedom_types: ["Keyword", "Length", "Percentage"],
       type_name: "Length",
@@ -2762,7 +2750,6 @@
     {
       name: "scroll-padding-inline-start",
       property_methods: ["ParseSingleValue"],
-      runtime_flag: "CSSScrollSnapPoints",
       include_paths: ["third_party/blink/renderer/platform/geometry/length.h"],
       typedom_types: ["Keyword", "Length", "Percentage"],
       type_name: "Length",
@@ -2775,7 +2762,6 @@
     {
       name: "scroll-padding-left",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "<length>",
       default_value: "Length()",
@@ -2785,7 +2771,6 @@
     {
       name: "scroll-padding-right",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "<length>",
       default_value: "Length()",
@@ -2795,7 +2780,6 @@
     {
       name: "scroll-padding-top",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "<length>",
       default_value: "Length()",
@@ -2805,7 +2789,6 @@
     {
       name: "scroll-snap-align",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "external",
       include_paths: ["third_party/blink/renderer/platform/scroll/scroll_snap_data.h"],
@@ -2819,7 +2802,6 @@
     {
       name: "scroll-snap-stop",
       property_methods: ["CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_template: "keyword",
       keywords: ["normal", "always"],
       default_value: "normal",
@@ -2828,7 +2810,6 @@
     {
       name: "scroll-snap-type",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
       field_group: "*",
       field_template: "external",
       include_paths: ["third_party/blink/renderer/platform/scroll/scroll_snap_data.h"],
@@ -4918,19 +4899,16 @@
       name: "scroll-margin",
       longhands: ["scroll-margin-top", "scroll-margin-right", "scroll-margin-bottom", "scroll-margin-left"],
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
     },
     {
       name: "scroll-margin-block",
       longhands: ["scroll-margin-block-start", "scroll-margin-block-end"],
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
     },
     {
       name: "scroll-margin-inline",
       longhands: ["scroll-margin-inline-start", "scroll-margin-inline-end"],
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
     },
     {
       name: "scroll-padding",
@@ -4939,19 +4917,16 @@
         "scroll-padding-left"
       ],
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
     },
     {
       name: "scroll-padding-block",
       longhands: ["scroll-padding-block-start", "scroll-padding-block-end"],
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
     },
     {
       name: "scroll-padding-inline",
       longhands: ["scroll-padding-inline-start", "scroll-padding-inline-end"],
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSScrollSnapPoints",
     },
     {
       name: "text-decoration",
diff --git a/third_party/blink/renderer/core/css/css_style_rule.cc b/third_party/blink/renderer/core/css/css_style_rule.cc
index c2e6d1b4..f0a3feb 100644
--- a/third_party/blink/renderer/core/css/css_style_rule.cc
+++ b/third_party/blink/renderer/core/css/css_style_rule.cc
@@ -37,7 +37,7 @@
 
 static SelectorTextCache& GetSelectorTextCache() {
   DEFINE_STATIC_LOCAL(Persistent<SelectorTextCache>, cache,
-                      (new SelectorTextCache));
+                      (MakeGarbageCollected<SelectorTextCache>()));
   return *cache;
 }
 
diff --git a/third_party/blink/renderer/core/css/font_face_cache.cc b/third_party/blink/renderer/core/css/font_face_cache.cc
index 68c4e3c..0e434aba8 100644
--- a/third_party/blink/renderer/core/css/font_face_cache.cc
+++ b/third_party/blink/renderer/core/css/font_face_cache.cc
@@ -51,8 +51,10 @@
   SegmentedFacesByFamily::AddResult capabilities_result =
       segmented_faces_.insert(font_face->family(), nullptr);
 
-  if (capabilities_result.is_new_entry)
-    capabilities_result.stored_value->value = new CapabilitiesSet();
+  if (capabilities_result.is_new_entry) {
+    capabilities_result.stored_value->value =
+        MakeGarbageCollected<CapabilitiesSet>();
+  }
 
   DCHECK(font_face->GetFontSelectionCapabilities().IsValid() &&
          !font_face->GetFontSelectionCapabilities().IsHashTableDeletedValue());
@@ -156,8 +158,8 @@
   // Either add or retrieve a cache entry in the selection query cache for the
   // specified family.
   FontSelectionQueryCache::AddResult cache_entry_for_family_add =
-      font_selection_query_cache_.insert(family,
-                                         new FontSelectionQueryResult());
+      font_selection_query_cache_.insert(
+          family, MakeGarbageCollected<FontSelectionQueryResult>());
   auto cache_entry_for_family = cache_entry_for_family_add.stored_value->value;
 
   const FontSelectionRequest& request =
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc b/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
index 19be541..1f7fb1b 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
@@ -883,7 +883,6 @@
       return value_id == CSSValueNormal || value_id == CSSValueBreakAll ||
              value_id == CSSValueKeepAll || value_id == CSSValueBreakWord;
     case CSSPropertyScrollSnapStop:
-      DCHECK(RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled());
       return value_id == CSSValueNormal || value_id == CSSValueAlways;
     case CSSPropertyOverscrollBehaviorX:
       return value_id == CSSValueAuto || value_id == CSSValueContain ||
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
index 27faa263..9f64fd7 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
@@ -169,7 +169,8 @@
   HeapHashMap<CSSPropertyID, Member<const CSSValue>>* map =
       parsed_properties_for_pending_substitution_cache_.at(&value);
   if (!map) {
-    map = new HeapHashMap<CSSPropertyID, Member<const CSSValue>>;
+    map = MakeGarbageCollected<
+        HeapHashMap<CSSPropertyID, Member<const CSSValue>>>();
     parsed_properties_for_pending_substitution_cache_.Set(&value, map);
   }
   return *map;
diff --git a/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc b/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc
index 5413c5ee..f377fc4 100644
--- a/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc
+++ b/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc
@@ -46,7 +46,8 @@
     AccumulatorMap;
 
 static AccumulatorMap& GetAccumulatorMap() {
-  DEFINE_STATIC_LOCAL(Persistent<AccumulatorMap>, map, (new AccumulatorMap));
+  DEFINE_STATIC_LOCAL(Persistent<AccumulatorMap>, map,
+                      (MakeGarbageCollected<AccumulatorMap>()));
   return *map;
 }
 
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index a5b727b..9b35d145 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -1933,9 +1933,7 @@
     return true;
   if (NeedsStyleInvalidation())
     return true;
-  // FIXME: The childNeedsDistributionRecalc bit means either self or children,
-  // we should fix that.
-  if (ChildNeedsDistributionRecalc())
+  if (IsSlotAssignmentOrLegacyDistributionDirty())
     return true;
   if (DocumentAnimations::NeedsAnimationTimingUpdate(*this))
     return true;
@@ -6977,8 +6975,7 @@
 }
 
 SnapCoordinator* Document::GetSnapCoordinator() {
-  if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled() &&
-      !snap_coordinator_)
+  if (!snap_coordinator_)
     snap_coordinator_ = SnapCoordinator::Create();
 
   return snap_coordinator_.Get();
@@ -7665,10 +7662,11 @@
   return *slot_assignment_engine_;
 }
 
-bool Document::IsSlotAssignmentOrLegacyDistributionDirty() {
+bool Document::IsSlotAssignmentOrLegacyDistributionDirty() const {
   if (ChildNeedsDistributionRecalc())
     return true;
-  if (GetSlotAssignmentEngine().HasPendingSlotAssignmentRecalc()) {
+  if (slot_assignment_engine_ &&
+      slot_assignment_engine_->HasPendingSlotAssignmentRecalc()) {
     return true;
   }
   return false;
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 34d79b4f..16822e79 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1468,7 +1468,7 @@
 
   SlotAssignmentEngine& GetSlotAssignmentEngine();
 
-  bool IsSlotAssignmentOrLegacyDistributionDirty();
+  bool IsSlotAssignmentOrLegacyDistributionDirty() const;
 
 #if DCHECK_IS_ON()
   unsigned& SlotAssignmentRecalcForbiddenRecursionDepth() {
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 71a93b4..4216705 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -763,15 +763,13 @@
 
     FloatPoint end_point(new_left * box->Style()->EffectiveZoom(),
                          box->ScrollTop().ToFloat());
-    if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-      std::unique_ptr<SnapSelectionStrategy> strategy =
-          SnapSelectionStrategy::CreateForEndPosition(
-              gfx::ScrollOffset(end_point), true, false);
-      end_point = GetDocument()
-                      .GetSnapCoordinator()
-                      ->GetSnapPosition(*box, *strategy)
-                      .value_or(end_point);
-    }
+    std::unique_ptr<SnapSelectionStrategy> strategy =
+        SnapSelectionStrategy::CreateForEndPosition(
+            gfx::ScrollOffset(end_point), true, false);
+    end_point = GetDocument()
+                    .GetSnapCoordinator()
+                    ->GetSnapPosition(*box, *strategy)
+                    .value_or(end_point);
     box->SetScrollLeft(LayoutUnit::FromFloatRound(end_point.X()));
   }
 }
@@ -797,15 +795,13 @@
 
     FloatPoint end_point(box->ScrollLeft().ToFloat(),
                          new_top * box->Style()->EffectiveZoom());
-    if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-      std::unique_ptr<SnapSelectionStrategy> strategy =
-          SnapSelectionStrategy::CreateForEndPosition(
-              gfx::ScrollOffset(end_point), false, true);
-      end_point = GetDocument()
-                      .GetSnapCoordinator()
-                      ->GetSnapPosition(*box, *strategy)
-                      .value_or(end_point);
-    }
+    std::unique_ptr<SnapSelectionStrategy> strategy =
+        SnapSelectionStrategy::CreateForEndPosition(
+            gfx::ScrollOffset(end_point), false, true);
+    end_point = GetDocument()
+                    .GetSnapCoordinator()
+                    ->GetSnapPosition(*box, *strategy)
+                    .value_or(end_point);
     box->SetScrollTop(LayoutUnit::FromFloatRound(end_point.Y()));
   }
 }
@@ -920,15 +916,13 @@
     gfx::ScrollOffset new_offset(current_position + displacement);
     FloatPoint new_position(new_offset.x(), new_offset.y());
 
-    if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-      std::unique_ptr<SnapSelectionStrategy> strategy =
-          SnapSelectionStrategy::CreateForEndAndDirection(current_position,
-                                                          displacement);
-      new_position = GetDocument()
-                         .GetSnapCoordinator()
-                         ->GetSnapPosition(*box, *strategy)
-                         .value_or(new_position);
-    }
+    std::unique_ptr<SnapSelectionStrategy> strategy =
+        SnapSelectionStrategy::CreateForEndAndDirection(current_position,
+                                                        displacement);
+    new_position = GetDocument()
+                       .GetSnapCoordinator()
+                       ->GetSnapPosition(*box, *strategy)
+                       .value_or(new_position);
     box->ScrollToPosition(new_position, scroll_behavior);
   }
 }
@@ -953,16 +947,14 @@
           box->Style()->EffectiveZoom());
     }
 
-    if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-      std::unique_ptr<SnapSelectionStrategy> strategy =
-          SnapSelectionStrategy::CreateForEndPosition(
-              gfx::ScrollOffset(new_position), scroll_to_options.hasLeft(),
-              scroll_to_options.hasTop());
-      new_position = GetDocument()
-                         .GetSnapCoordinator()
-                         ->GetSnapPosition(*box, *strategy)
-                         .value_or(new_position);
-    }
+    std::unique_ptr<SnapSelectionStrategy> strategy =
+        SnapSelectionStrategy::CreateForEndPosition(
+            gfx::ScrollOffset(new_position), scroll_to_options.hasLeft(),
+            scroll_to_options.hasTop());
+    new_position = GetDocument()
+                       .GetSnapCoordinator()
+                       ->GetSnapPosition(*box, *strategy)
+                       .value_or(new_position);
     box->ScrollToPosition(new_position, scroll_behavior);
   }
 }
@@ -993,17 +985,15 @@
   FloatPoint new_position = viewport->ScrollPosition() +
                             FloatPoint(displacement.x(), displacement.y());
 
-  if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-    gfx::ScrollOffset current_position(viewport->ScrollPosition());
-    std::unique_ptr<SnapSelectionStrategy> strategy =
-        SnapSelectionStrategy::CreateForEndAndDirection(current_position,
-                                                        displacement);
-    new_position =
-        GetDocument()
-            .GetSnapCoordinator()
-            ->GetSnapPosition(*GetDocument().GetLayoutView(), *strategy)
-            .value_or(new_position);
-  }
+  gfx::ScrollOffset current_position(viewport->ScrollPosition());
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndAndDirection(current_position,
+                                                      displacement);
+  new_position =
+      GetDocument()
+          .GetSnapCoordinator()
+          ->GetSnapPosition(*GetDocument().GetLayoutView(), *strategy)
+          .value_or(new_position);
   viewport->SetScrollOffset(viewport->ScrollPositionToOffset(new_position),
                             kProgrammaticScroll, scroll_behavior);
 }
@@ -1032,19 +1022,17 @@
         frame->PageZoomFactor());
   }
 
-  if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-    FloatPoint new_position = viewport->ScrollOffsetToPosition(new_offset);
-    std::unique_ptr<SnapSelectionStrategy> strategy =
-        SnapSelectionStrategy::CreateForEndPosition(
-            gfx::ScrollOffset(new_position), scroll_to_options.hasLeft(),
-            scroll_to_options.hasTop());
-    new_position =
-        GetDocument()
-            .GetSnapCoordinator()
-            ->GetSnapPosition(*GetDocument().GetLayoutView(), *strategy)
-            .value_or(new_position);
-    new_offset = viewport->ScrollPositionToOffset(new_position);
-  }
+  FloatPoint new_position = viewport->ScrollOffsetToPosition(new_offset);
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(
+          gfx::ScrollOffset(new_position), scroll_to_options.hasLeft(),
+          scroll_to_options.hasTop());
+  new_position =
+      GetDocument()
+          .GetSnapCoordinator()
+          ->GetSnapPosition(*GetDocument().GetLayoutView(), *strategy)
+          .value_or(new_position);
+  new_offset = viewport->ScrollPositionToOffset(new_position);
   viewport->SetScrollOffset(new_offset, kProgrammaticScroll, scroll_behavior);
 }
 
@@ -1993,14 +1981,13 @@
     data->ClearComputedStyle();
   }
 
-  if (CanParticipateInFlatTree()) {
-    LayoutTreeBuilderForElement builder(*this, GetNonAttachedStyle());
+  ComputedStyle* style = GetNonAttachedStyle();
+  if (style && CanParticipateInFlatTree()) {
+    LayoutTreeBuilderForElement builder(*this, style);
     builder.CreateLayoutObjectIfNeeded();
 
-    if (ComputedStyle* style = builder.ResolvedStyle()) {
-      if (!GetLayoutObject() && ShouldStoreNonLayoutObjectComputedStyle(*style))
-        StoreNonLayoutObjectComputedStyle(style);
-    }
+    if (!GetLayoutObject() && ShouldStoreNonLayoutObjectComputedStyle(*style))
+      StoreNonLayoutObjectComputedStyle(style);
   }
 
   if (HasRareData() && !GetLayoutObject() &&
diff --git a/third_party/blink/renderer/core/dom/element_rare_data.cc b/third_party/blink/renderer/core/dom/element_rare_data.cc
index c300ff2..162506f 100644
--- a/third_party/blink/renderer/core/dom/element_rare_data.cc
+++ b/third_party/blink/renderer/core/dom/element_rare_data.cc
@@ -85,9 +85,11 @@
 
 ElementRareData::ResizeObserverDataMap&
 ElementRareData::EnsureResizeObserverData() {
-  if (!resize_observer_data_)
-    resize_observer_data_ = new HeapHashMap<TraceWrapperMember<ResizeObserver>,
-                                            Member<ResizeObservation>>();
+  if (!resize_observer_data_) {
+    resize_observer_data_ =
+        MakeGarbageCollected<HeapHashMap<TraceWrapperMember<ResizeObserver>,
+                                         Member<ResizeObservation>>>();
+  }
   return *resize_observer_data_;
 }
 
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.cc b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
index ba586f17..24f2266 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder.cc
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
@@ -76,6 +76,7 @@
                                                          ComputedStyle* style)
     : LayoutTreeBuilder(element, nullptr), style_(style) {
   DCHECK(element.CanParticipateInFlatTree());
+  DCHECK(style_);
   // TODO(ecobos): Move the first-letter logic inside ParentLayoutObject too?
   // It's an extra (unnecessary) check for text nodes, though.
   if (element.IsFirstLetterPseudoElement()) {
@@ -127,36 +128,24 @@
       !CanHaveGeneratedChildren(*parent_layout_object)) {
     return false;
   }
-  return node_->LayoutObjectIsNeeded(Style());
-}
-
-ComputedStyle& LayoutTreeBuilderForElement::Style() const {
-  if (!style_) {
-    // TODO(futhark@chromium.org): this should never happen, but we currently
-    // have crashes in the wild because of this (https://crbug.com/875796).
-    // Please report if you ever end up here.
-    NOTREACHED();
-    style_ = node_->StyleForLayoutObject();
-  }
-  return *style_;
+  return node_->LayoutObjectIsNeeded(*style_);
 }
 
 DISABLE_CFI_PERF
 void LayoutTreeBuilderForElement::CreateLayoutObject() {
-  ComputedStyle& style = Style();
   ReattachLegacyLayoutObjectList& legacy_layout_objects =
       node_->GetDocument().GetReattachLegacyLayoutObjectList();
   if (legacy_layout_objects.IsForcingLegacyLayout()) {
     DCHECK(!node_->GetLayoutObject());
-    style.SetForceLegacyLayout(true);
+    style_->SetForceLegacyLayout(true);
   }
-  LayoutObject* new_layout_object = node_->CreateLayoutObject(style);
+  LayoutObject* new_layout_object = node_->CreateLayoutObject(*style_);
   if (!new_layout_object)
     return;
 
   LayoutObject* parent_layout_object = ParentLayoutObject();
 
-  if (!parent_layout_object->IsChildAllowed(new_layout_object, style)) {
+  if (!parent_layout_object->IsChildAllowed(new_layout_object, *style_)) {
     new_layout_object->Destroy();
     return;
   }
@@ -171,7 +160,7 @@
   LayoutObject* next_layout_object = NextLayoutObject();
   node_->SetLayoutObject(new_layout_object);
   new_layout_object->SetStyle(
-      &style);  // SetStyle() can depend on LayoutObject() already being set.
+      style_);  // SetStyle() can depend on LayoutObject() already being set.
 
   // Note: Adding new_layout_object instead of LayoutObject(). LayoutObject()
   // may be a child of new_layout_object.
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.h b/third_party/blink/renderer/core/dom/layout_tree_builder.h
index 0f53a07..f71adc0 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder.h
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder.h
@@ -105,16 +105,13 @@
       CreateLayoutObject();
   }
 
-  ComputedStyle* ResolvedStyle() const { return style_.get(); }
-
  private:
   LayoutObject* ParentLayoutObject() const;
   LayoutObject* NextLayoutObject() const;
   bool ShouldCreateLayoutObject() const;
-  ComputedStyle& Style() const;
   void CreateLayoutObject();
 
-  mutable scoped_refptr<ComputedStyle> style_;
+  scoped_refptr<ComputedStyle> style_;
 };
 
 class LayoutTreeBuilderForText : public LayoutTreeBuilder<Text> {
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index 811a272..ca79724 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -2340,7 +2340,7 @@
     HeapHashMap<WeakMember<Node>, TraceWrapperMember<EventTargetData>>;
 static EventTargetDataMap& GetEventTargetDataMap() {
   DEFINE_STATIC_LOCAL(Persistent<EventTargetDataMap>, map,
-                      (new EventTargetDataMap));
+                      (MakeGarbageCollected<EventTargetDataMap>()));
   return *map;
 }
 
diff --git a/third_party/blink/renderer/core/dom/nth_index_cache.cc b/third_party/blink/renderer/core/dom/nth_index_cache.cc
index 988c02c..c7072bd 100644
--- a/third_party/blink/renderer/core/dom/nth_index_cache.cc
+++ b/third_party/blink/renderer/core/dom/nth_index_cache.cc
@@ -152,7 +152,7 @@
 void NthIndexCache::CacheNthIndexDataForParent(Element& element) {
   DCHECK(element.parentNode());
   if (!parent_map_)
-    parent_map_ = new ParentMap();
+    parent_map_ = MakeGarbageCollected<ParentMap>();
 
   ParentMap::AddResult add_result =
       parent_map_->insert(element.parentNode(), nullptr);
@@ -163,12 +163,12 @@
 NthIndexCache::IndexByType& NthIndexCache::EnsureTypeIndexMap(
     ContainerNode& parent) {
   if (!parent_map_for_type_)
-    parent_map_for_type_ = new ParentMapForType();
+    parent_map_for_type_ = MakeGarbageCollected<ParentMapForType>();
 
   ParentMapForType::AddResult add_result =
       parent_map_for_type_->insert(&parent, nullptr);
   if (add_result.is_new_entry)
-    add_result.stored_value->value = new IndexByType();
+    add_result.stored_value->value = MakeGarbageCollected<IndexByType>();
 
   DCHECK(add_result.stored_value->value);
   return *add_result.stored_value->value;
diff --git a/third_party/blink/renderer/core/dom/presentation_attribute_style.cc b/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
index c87712a..78e52699 100644
--- a/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
+++ b/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
@@ -76,7 +76,7 @@
                 AlreadyHashed>;
 static PresentationAttributeCache& GetPresentationAttributeCache() {
   DEFINE_STATIC_LOCAL(Persistent<PresentationAttributeCache>, cache,
-                      (new PresentationAttributeCache));
+                      (MakeGarbageCollected<PresentationAttributeCache>()));
   return *cache;
 }
 
@@ -182,7 +182,7 @@
     return style;
 
   PresentationAttributeCacheEntry* new_entry =
-      new PresentationAttributeCacheEntry;
+      MakeGarbageCollected<PresentationAttributeCacheEntry>();
   new_entry->key = cache_key;
   new_entry->value = style;
 
diff --git a/third_party/blink/renderer/core/execution_context/security_context.cc b/third_party/blink/renderer/core/execution_context/security_context.cc
index f990180..60748fa6f 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.cc
+++ b/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -115,6 +115,11 @@
     const ParsedFeaturePolicy& parsed_header,
     const ParsedFeaturePolicy& container_policy,
     const FeaturePolicy* parent_feature_policy) {
+  if (!HasCustomizedFeaturePolicy()) {
+    feature_policy_ = FeaturePolicy::CreateFromParentPolicy(
+        nullptr, {}, security_origin_->ToUrlOrigin());
+    return;
+  }
   feature_policy_ = FeaturePolicy::CreateFromParentPolicy(
       parent_feature_policy, container_policy, security_origin_->ToUrlOrigin());
   feature_policy_->SetHeaderPolicy(parsed_header);
diff --git a/third_party/blink/renderer/core/execution_context/security_context.h b/third_party/blink/renderer/core/execution_context/security_context.h
index 62cacfe..52347473d 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.h
+++ b/third_party/blink/renderer/core/execution_context/security_context.h
@@ -154,6 +154,11 @@
 
   void SetContentSecurityPolicy(ContentSecurityPolicy*);
 
+  // Determines whether or not the SecurityContext has a customized feature
+  // policy. If this method returns false, |feature_policy_| is reset to a
+  // default value ignoring container, header, and inherited policies.
+  virtual bool HasCustomizedFeaturePolicy() const { return true; }
+
   SandboxFlags sandbox_flags_;
 
  private:
diff --git a/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc b/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
index edc05fc..2e017cd 100644
--- a/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
+++ b/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
@@ -63,8 +63,6 @@
     return queried_subresource_paths_;
   }
 
-  bool GetIsAssociatedWithAdSubframe() const override { return false; }
-
  private:
   // Using STL types for compatibility with gtest/gmock.
   std::vector<std::string> queried_subresource_paths_;
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 70824a1..1ec3d126 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -1093,17 +1093,14 @@
                           y * GetFrame()->PageZoomFactor());
   FloatPoint new_scaled_position = current_position + scaled_delta;
 
-  if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-    std::unique_ptr<SnapSelectionStrategy> strategy =
-        SnapSelectionStrategy::CreateForEndAndDirection(
-            gfx::ScrollOffset(current_position),
-            gfx::ScrollOffset(scaled_delta));
-    new_scaled_position =
-        document()
-            ->GetSnapCoordinator()
-            ->GetSnapPosition(*document()->GetLayoutView(), *strategy)
-            .value_or(new_scaled_position);
-  }
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndAndDirection(
+          gfx::ScrollOffset(current_position), gfx::ScrollOffset(scaled_delta));
+  new_scaled_position =
+      document()
+          ->GetSnapCoordinator()
+          ->GetSnapPosition(*document()->GetLayoutView(), *strategy)
+          .value_or(new_scaled_position);
 
   ScrollBehavior scroll_behavior = kScrollBehaviorAuto;
   ScrollableArea::ScrollBehaviorFromString(scroll_to_options.behavior(),
@@ -1160,17 +1157,15 @@
   FloatPoint new_scaled_position =
       viewport->ScrollOffsetToPosition(ScrollOffset(scaled_x, scaled_y));
 
-  if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-    std::unique_ptr<SnapSelectionStrategy> strategy =
-        SnapSelectionStrategy::CreateForEndPosition(
-            gfx::ScrollOffset(new_scaled_position), scroll_to_options.hasLeft(),
-            scroll_to_options.hasTop());
-    new_scaled_position =
-        document()
-            ->GetSnapCoordinator()
-            ->GetSnapPosition(*document()->GetLayoutView(), *strategy)
-            .value_or(new_scaled_position);
-  }
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(
+          gfx::ScrollOffset(new_scaled_position), scroll_to_options.hasLeft(),
+          scroll_to_options.hasTop());
+  new_scaled_position =
+      document()
+          ->GetSnapCoordinator()
+          ->GetSnapPosition(*document()->GetLayoutView(), *strategy)
+          .value_or(new_scaled_position);
   ScrollBehavior scroll_behavior = kScrollBehaviorAuto;
   ScrollableArea::ScrollBehaviorFromString(scroll_to_options.behavior(),
                                            scroll_behavior);
diff --git a/third_party/blink/renderer/core/frame/performance_monitor.cc b/third_party/blink/renderer/core/frame/performance_monitor.cc
index 7306f6c2..a005c41 100644
--- a/third_party/blink/renderer/core/frame/performance_monitor.cc
+++ b/third_party/blink/renderer/core/frame/performance_monitor.cc
@@ -89,7 +89,7 @@
   DCHECK(violation < kAfterLast);
   ClientThresholds* client_thresholds = subscriptions_.at(violation);
   if (!client_thresholds) {
-    client_thresholds = new ClientThresholds();
+    client_thresholds = MakeGarbageCollected<ClientThresholds>();
     subscriptions_.Set(violation, client_thresholds);
   }
   client_thresholds->Set(client, threshold);
diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
index 17a5d43..1166172 100644
--- a/third_party/blink/renderer/core/fullscreen/fullscreen.cc
+++ b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
@@ -125,7 +125,7 @@
 
 ElementRequestTypeMap& FullscreenFlagMap() {
   DEFINE_STATIC_LOCAL(Persistent<ElementRequestTypeMap>, map,
-                      (new ElementRequestTypeMap));
+                      (MakeGarbageCollected<ElementRequestTypeMap>()));
   return *map;
 }
 
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
index c4ca5d9..b2995b013 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
@@ -90,7 +90,7 @@
     : element_definition_is_running_(false),
       owner_(owner),
       v0_(new V0RegistrySet()),
-      upgrade_candidates_(new UpgradeCandidateMap()),
+      upgrade_candidates_(MakeGarbageCollected<UpgradeCandidateMap>()),
       reaction_stack_(&CustomElementReactionStack::Current()) {}
 
 void CustomElementRegistry::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.cc b/third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.cc
index 8c2d88e..f27ab37 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.cc
@@ -16,7 +16,7 @@
 
 CustomElementUpgradeSorter::CustomElementUpgradeSorter()
     : elements_(new HeapHashSet<Member<Element>>()),
-      parent_child_map_(new ParentChildMap()) {}
+      parent_child_map_(MakeGarbageCollected<ParentChildMap>()) {}
 
 static HTMLLinkElement* GetLinkElementForImport(const Document& import) {
   if (HTMLImportLoader* loader = import.ImportLoader())
diff --git a/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.cc b/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.cc
index 637440bd..a450e76 100644
--- a/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.cc
+++ b/third_party/blink/renderer/core/html/custom/v0_custom_element_observer.cc
@@ -42,7 +42,7 @@
 
 static ElementObserverMap& ElementObservers() {
   DEFINE_STATIC_LOCAL(Persistent<ElementObserverMap>, map,
-                      (new ElementObserverMap));
+                      (MakeGarbageCollected<ElementObserverMap>()));
   return *map;
 }
 
diff --git a/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc b/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc
index 42c3237..7a8ba361 100644
--- a/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc
+++ b/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc
@@ -52,7 +52,7 @@
 
 static ElementCallbackQueueMap& CallbackQueues() {
   DEFINE_STATIC_LOCAL(Persistent<ElementCallbackQueueMap>, map,
-                      (new ElementCallbackQueueMap));
+                      (MakeGarbageCollected<ElementCallbackQueueMap>()));
   return *map;
 }
 
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.cc b/third_party/blink/renderer/core/html/forms/html_form_element.cc
index 95a4873..ffe1d02 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_form_element.cc
@@ -768,7 +768,7 @@
   if (past_name.IsEmpty())
     return;
   if (!past_names_map_)
-    past_names_map_ = new PastNamesMap;
+    past_names_map_ = MakeGarbageCollected<PastNamesMap>();
   past_names_map_->Set(past_name, element);
 }
 
diff --git a/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc b/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc
index 55825268..7f152f3 100644
--- a/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc
+++ b/third_party/blink/renderer/core/html/forms/radio_button_group_scope.cc
@@ -213,7 +213,7 @@
     return;
 
   if (!name_to_group_map_)
-    name_to_group_map_ = new NameToGroupMap;
+    name_to_group_map_ = MakeGarbageCollected<NameToGroupMap>();
 
   auto* key_value =
       name_to_group_map_->insert(element->GetName(), nullptr).stored_value;
diff --git a/third_party/blink/renderer/core/html/html_view_source_document.h b/third_party/blink/renderer/core/html/html_view_source_document.h
index e6a540b..09b0cfe 100644
--- a/third_party/blink/renderer/core/html/html_view_source_document.h
+++ b/third_party/blink/renderer/core/html/html_view_source_document.h
@@ -80,6 +80,9 @@
   Element* AddLink(const AtomicString& url, bool is_anchor);
   Element* AddBase(const AtomicString& href);
 
+  // A view-source document is not a regular WebPage.
+  bool HasCustomizedFeaturePolicy() const final { return false; }
+
   String type_;
   Member<Element> current_;
   Member<HTMLTableSectionElement> tbody_;
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index 759b7ae..4b5d3cc6 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -209,7 +209,7 @@
 
 DocumentElementSetMap& DocumentToElementSetMap() {
   DEFINE_STATIC_LOCAL(Persistent<DocumentElementSetMap>, map,
-                      (new DocumentElementSetMap));
+                      (MakeGarbageCollected<DocumentElementSetMap>()));
   return *map;
 }
 
diff --git a/third_party/blink/renderer/core/input/scroll_manager.cc b/third_party/blink/renderer/core/input/scroll_manager.cc
index ec6763f..81dfda6 100644
--- a/third_party/blink/renderer/core/input/scroll_manager.cc
+++ b/third_party/blink/renderer/core/input/scroll_manager.cc
@@ -70,8 +70,7 @@
 }  // namespace
 
 ScrollManager::ScrollManager(LocalFrame& frame) : frame_(frame) {
-  if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled())
-    snap_fling_controller_ = std::make_unique<cc::SnapFlingController>(this);
+  snap_fling_controller_ = std::make_unique<cc::SnapFlingController>(this);
 
   Clear();
 }
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
index 7a1353f..00f58467 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
@@ -236,7 +236,7 @@
       inspected_frames_(inspected_frames),
       v8_session_(v8_session),
       dom_listener_(nullptr),
-      document_node_to_id_map_(new NodeToIdMap()),
+      document_node_to_id_map_(MakeGarbageCollected<NodeToIdMap>()),
       last_node_id_(1),
       suppress_attribute_modified_event_(false),
       enabled_(&agent_state_, /*default_value=*/false) {}
@@ -712,7 +712,7 @@
     node = parent;
 
   // Node being pushed is detached -> push subtree root.
-  NodeToIdMap* new_map = new NodeToIdMap;
+  NodeToIdMap* new_map = MakeGarbageCollected<NodeToIdMap>();
   NodeToIdMap* dangling_map = new_map;
   dangling_node_to_id_maps_.push_back(new_map);
   std::unique_ptr<protocol::Array<protocol::DOM::Node>> children =
diff --git a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
index abd7aa87..1401925a 100644
--- a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
+++ b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
@@ -47,17 +47,17 @@
 }
 
 // Returns true if there is at least one edge between block_start and block_end.
-bool HasSolidEdges(const Vector<scoped_refptr<const NGExclusion>, 1>& edges,
-                   LayoutUnit block_start,
-                   LayoutUnit block_end) {
+bool HasSolidEdges(
+    const Vector<NGExclusionSpaceInternal::NGShelfEdge, 1>& edges,
+    LayoutUnit block_start,
+    LayoutUnit block_end) {
   // If there aren't any adjacent exclusions, we must be the initial shelf.
   // This always has "solid" edges on either side.
   if (edges.IsEmpty())
     return true;
 
   for (const auto& edge : edges) {
-    if (edge->rect.BlockEndOffset() > block_start &&
-        edge->rect.BlockStartOffset() < block_end)
+    if (edge.block_end > block_start && edge.block_start < block_end)
       return true;
   }
 
@@ -68,12 +68,13 @@
 // (block_offset, LayoutUnit::Max())
 // to the given out_edges vector.
 // edges will be invalid after this call.
-void CollectSolidEdges(Vector<scoped_refptr<const NGExclusion>, 1>* edges,
-                       LayoutUnit block_offset,
-                       Vector<scoped_refptr<const NGExclusion>, 1>* out_edges) {
+void CollectSolidEdges(
+    Vector<NGExclusionSpaceInternal::NGShelfEdge, 1>* edges,
+    LayoutUnit block_offset,
+    Vector<NGExclusionSpaceInternal::NGShelfEdge, 1>* out_edges) {
   *out_edges = std::move(*edges);
   for (auto* it = out_edges->begin(); it != out_edges->end();) {
-    if ((*it)->rect.BlockEndOffset() <= block_offset) {
+    if ((*it).block_end <= block_offset) {
       out_edges->erase(it);
     } else {
       ++it;
@@ -403,7 +404,9 @@
             if (exclusion.rect.LineEndOffset() > shelf.line_left)
               shelf.line_left_edges.clear();
             shelf.line_left = exclusion.rect.LineEndOffset();
-            shelf.line_left_edges.emplace_back(&exclusion);
+            shelf.line_left_edges.emplace_back(
+                exclusion.rect.BlockStartOffset(),
+                exclusion.rect.BlockEndOffset());
           }
           shelf.shape_exclusions->line_left_shapes.emplace_back(&exclusion);
         } else {
@@ -413,7 +416,9 @@
             if (exclusion.rect.LineStartOffset() < shelf.line_right)
               shelf.line_right_edges.clear();
             shelf.line_right = exclusion.rect.LineStartOffset();
-            shelf.line_right_edges.emplace_back(&exclusion);
+            shelf.line_right_edges.emplace_back(
+                exclusion.rect.BlockStartOffset(),
+                exclusion.rect.BlockEndOffset());
           }
           shelf.shape_exclusions->line_right_shapes.emplace_back(&exclusion);
         }
diff --git a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
index 5a5c61a..8097267 100644
--- a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
+++ b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
@@ -88,6 +88,15 @@
     return !(*this == other);
   }
 
+  // This struct represents the side of a float against the "edge" of a shelf.
+  struct NGShelfEdge {
+    NGShelfEdge(LayoutUnit block_start, LayoutUnit block_end)
+        : block_start(block_start), block_end(block_end) {}
+
+    LayoutUnit block_start;
+    LayoutUnit block_end;
+  };
+
   // The shelf is an internal data-structure representing the bottom of a
   // float. A shelf has a inline-size which is defined by the line_left and
   // line_right members. E.g.
@@ -146,8 +155,8 @@
     LayoutUnit line_left;
     LayoutUnit line_right;
 
-    Vector<scoped_refptr<const NGExclusion>, 1> line_left_edges;
-    Vector<scoped_refptr<const NGExclusion>, 1> line_right_edges;
+    Vector<NGShelfEdge, 1> line_left_edges;
+    Vector<NGShelfEdge, 1> line_right_edges;
 
     // shape_exclusions contains all the floats which sit below this shelf. The
     // has_shape_exclusions member will be true if shape_exclusions contains an
@@ -368,4 +377,7 @@
 
 }  // namespace blink
 
+WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
+    blink::NGExclusionSpaceInternal::NGShelfEdge);
+
 #endif  // NGExclusionSpace_h
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 a21710e..241c366 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
@@ -1323,18 +1323,12 @@
   //
   // The resulting margin strut in the above example will be {40, -30}. See
   // ComputeInflowPosition for how this end margin strut is used.
-  bool empty_block_affected_by_clearance_needs_relayout = false;
   if (empty_block_affected_by_clearance) {
     NGMarginStrut margin_strut;
     margin_strut.Append(child_data.margins.block_start,
                         child.Style().HasMarginBeforeQuirk());
 
-    // We only need to relayout if the new margin strut is different to the
-    // previous one.
-    if (child_data.margin_strut != margin_strut) {
-      child_data.margin_strut = margin_strut;
-      empty_block_affected_by_clearance_needs_relayout = true;
-    }
+    child_data.margin_strut = margin_strut;
   }
 
   // We need to layout a child if we know its BFC block offset and:
@@ -1342,8 +1336,7 @@
   //  - It has some unpositioned floats.
   //  - It was affected by clearance.
   if ((layout_result->Status() == NGLayoutResult::kBfcBlockOffsetResolved ||
-       relayout_child_when_bfc_resolved ||
-       empty_block_affected_by_clearance_needs_relayout) &&
+       relayout_child_when_bfc_resolved || empty_block_affected_by_clearance) &&
       child_bfc_block_offset) {
     NGConstraintSpace new_child_space = CreateConstraintSpaceForChild(
         child, child_data, child_available_size_, child_bfc_block_offset);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
index 66fad9a82..e2cb27b 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
@@ -43,7 +43,8 @@
 }
 
 LayoutSVGResourceFilter::LayoutSVGResourceFilter(SVGFilterElement* node)
-    : LayoutSVGResourceContainer(node), filter_(new FilterMap) {}
+    : LayoutSVGResourceContainer(node),
+      filter_(MakeGarbageCollected<FilterMap>()) {}
 
 LayoutSVGResourceFilter::~LayoutSVGResourceFilter() = default;
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
index 1eb83b1..66a23138 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
@@ -29,7 +29,7 @@
 LayoutSVGResourceGradient::LayoutSVGResourceGradient(SVGGradientElement* node)
     : LayoutSVGResourcePaintServer(node),
       should_collect_gradient_attributes_(true),
-      gradient_map_(new GradientMap) {}
+      gradient_map_(MakeGarbageCollected<GradientMap>()) {}
 
 void LayoutSVGResourceGradient::RemoveAllClientsFromCache(
     bool mark_for_invalidation) {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
index 61a7258..34353ae 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
@@ -49,7 +49,7 @@
     : LayoutSVGResourcePaintServer(node),
       should_collect_pattern_attributes_(true),
       attributes_wrapper_(PatternAttributesWrapper::Create()),
-      pattern_map_(new PatternMap) {}
+      pattern_map_(MakeGarbageCollected<PatternMap>()) {}
 
 void LayoutSVGResourcePattern::RemoveAllClientsFromCache(
     bool mark_for_invalidation) {
diff --git a/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc b/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc
index c30ff61..d3eaed4 100644
--- a/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc
+++ b/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc
@@ -56,17 +56,21 @@
 
 // Helper function to decide what to do with with a given mime type. This takes
 // - a mime type
-// - inputs that affect the decision (is_same_origin, is_worker_global_scope).
+// - inputs that affect the decision (is_same_origin, mime_type_check_mode).
 //
 // The return value determines whether this mime should be allowed or blocked.
 // Additionally, warn returns whether we should log a console warning about
 // expected future blocking of this resource. 'counter' determines which
-// Use counter should be used to count this.
+// Use counter should be used to count this. 'is_worker_global_scope' is used
+// for choosing 'counter' value.
 bool AllowMimeTypeAsScript(const String& mime_type,
                            bool same_origin,
+                           AllowedByNosniff::MimeTypeCheck mime_type_check_mode,
                            bool is_worker_global_scope,
                            bool& warn,
                            WebFeature& counter) {
+  using MimeTypeCheck = AllowedByNosniff::MimeTypeCheck;
+
   // The common case: A proper JavaScript MIME type
   if (MIMETypeRegistry::IsSupportedJavaScriptMIMEType(mime_type))
     return true;
@@ -94,7 +98,7 @@
   // we still wish to accept them (or log them using UseCounter, or add a
   // deprecation warning to the console).
 
-  if (!is_worker_global_scope &&
+  if (mime_type_check_mode == MimeTypeCheck::kLax &&
       mime_type.StartsWithIgnoringASCIICase("text/") &&
       MIMETypeRegistry::IsLegacySupportedJavaScriptLanguage(
           mime_type.Substring(5))) {
@@ -116,16 +120,18 @@
 
   // Depending on RuntimeEnabledFeatures, we'll allow, allow-but-warn, or block
   // these types when we're in a worker.
-  bool allow = !is_worker_global_scope ||
+  bool allow = mime_type_check_mode == MimeTypeCheck::kLax ||
                !RuntimeEnabledFeatures::WorkerNosniffBlockEnabled();
-  warn = allow && is_worker_global_scope &&
+  warn = allow && mime_type_check_mode == MimeTypeCheck::kStrict &&
          RuntimeEnabledFeatures::WorkerNosniffWarnEnabled();
   return allow;
 }
 
-bool MimeTypeAsScriptImpl(ExecutionContext* execution_context,
-                          const ResourceResponse& response,
-                          bool is_worker_global_scope) {
+}  // namespace
+
+bool AllowedByNosniff::MimeTypeAsScript(ExecutionContext* execution_context,
+                                        const ResourceResponse& response,
+                                        MimeTypeCheck mime_type_check_mode) {
   // The content type is really only meaningful for the http:-family & data
   // schemes.
   bool is_http_family_or_data = response.Url().ProtocolIsInHTTPFamily() ||
@@ -164,8 +170,9 @@
   const WebFeature kWebFeatureNone = WebFeature::kNumberOfFeatures;
   bool warn = false;
   WebFeature counter = kWebFeatureNone;
-  bool allow = AllowMimeTypeAsScript(mime_type, same_origin,
-                                     is_worker_global_scope, warn, counter);
+  bool allow = AllowMimeTypeAsScript(
+      mime_type, same_origin, mime_type_check_mode,
+      execution_context->IsWorkerGlobalScope(), warn, counter);
 
   // These record usages for two MIME types (without subtypes), per same/cross
   // origin.
@@ -192,20 +199,4 @@
   return allow;
 }
 
-}  // namespace
-
-bool AllowedByNosniff::MimeTypeAsScript(ExecutionContext* execution_context,
-                                        const ResourceResponse& response) {
-  return MimeTypeAsScriptImpl(execution_context, response,
-                              execution_context->IsWorkerGlobalScope());
-}
-
-bool AllowedByNosniff::MimeTypeAsScriptForTesting(
-    ExecutionContext* execution_context,
-    const ResourceResponse& response,
-    bool is_worker_global_scope) {
-  return MimeTypeAsScriptImpl(execution_context, response,
-                              is_worker_global_scope);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/allowed_by_nosniff.h b/third_party/blink/renderer/core/loader/allowed_by_nosniff.h
index 757f0f8..16b4b5a 100644
--- a/third_party/blink/renderer/core/loader/allowed_by_nosniff.h
+++ b/third_party/blink/renderer/core/loader/allowed_by_nosniff.h
@@ -13,12 +13,11 @@
 
 class CORE_EXPORT AllowedByNosniff {
  public:
-  static bool MimeTypeAsScript(ExecutionContext*, const ResourceResponse&);
+  enum class MimeTypeCheck { kStrict, kLax };
 
-  // For testing:
-  static bool MimeTypeAsScriptForTesting(ExecutionContext*,
-                                         const ResourceResponse&,
-                                         bool is_worker_global_scope);
+  static bool MimeTypeAsScript(ExecutionContext*,
+                               const ResourceResponse&,
+                               MimeTypeCheck mime_type_check_mode);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc b/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc
index 8fd08c6..6016392 100644
--- a/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc
+++ b/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc
@@ -14,6 +14,8 @@
 
 namespace blink {
 
+using MimeTypeCheck = AllowedByNosniff::MimeTypeCheck;
+
 class AllowedByNosniffTest : public testing::Test {
  public:
   void SetUp() override {
@@ -108,10 +110,10 @@
     RuntimeEnabledFeatures::SetWorkerNosniffBlockEnabled(false);
     RuntimeEnabledFeatures::SetWorkerNosniffWarnEnabled(false);
     size_t message_count = ConsoleMessageStoreSize();
-    EXPECT_EQ(testcase.allowed,
-              AllowedByNosniff::MimeTypeAsScript(doc(), response));
-    EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScriptForTesting(
-                                    doc(), response, true));
+    EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
+                                    doc(), response, MimeTypeCheck::kLax));
+    EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
+                                    doc(), response, MimeTypeCheck::kStrict));
     EXPECT_EQ(ConsoleMessageStoreSize(), message_count + 2 * !testcase.allowed);
 
     // Nosniff worker blocked: Workers follow the 'strict_allow' setting.
@@ -119,12 +121,12 @@
     RuntimeEnabledFeatures::SetWorkerNosniffBlockEnabled(true);
     RuntimeEnabledFeatures::SetWorkerNosniffWarnEnabled(false);
     message_count = ConsoleMessageStoreSize();
-    EXPECT_EQ(testcase.allowed,
-              AllowedByNosniff::MimeTypeAsScript(doc(), response));
+    EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
+                                    doc(), response, MimeTypeCheck::kLax));
     EXPECT_EQ(ConsoleMessageStoreSize(), message_count + !testcase.allowed);
-    EXPECT_EQ(
-        testcase.strict_allowed,
-        AllowedByNosniff::MimeTypeAsScriptForTesting(doc(), response, true));
+    EXPECT_EQ(testcase.strict_allowed,
+              AllowedByNosniff::MimeTypeAsScript(doc(), response,
+                                                 MimeTypeCheck::kStrict));
     EXPECT_EQ(ConsoleMessageStoreSize(),
               message_count + !testcase.allowed + !testcase.strict_allowed);
 
@@ -133,11 +135,11 @@
     RuntimeEnabledFeatures::SetWorkerNosniffBlockEnabled(false);
     RuntimeEnabledFeatures::SetWorkerNosniffWarnEnabled(true);
     message_count = ConsoleMessageStoreSize();
-    EXPECT_EQ(testcase.allowed,
-              AllowedByNosniff::MimeTypeAsScript(doc(), response));
+    EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
+                                    doc(), response, MimeTypeCheck::kLax));
     EXPECT_EQ(ConsoleMessageStoreSize(), message_count + !testcase.allowed);
-    EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScriptForTesting(
-                                    doc(), response, true));
+    EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
+                                    doc(), response, MimeTypeCheck::kStrict));
     EXPECT_EQ(ConsoleMessageStoreSize(),
               message_count + !testcase.allowed + !testcase.strict_allowed);
   }
@@ -184,7 +186,7 @@
     ResourceResponse response(KURL(testcase.url));
     response.SetHTTPHeaderField("Content-Type", testcase.mimetype);
 
-    AllowedByNosniff::MimeTypeAsScript(doc(), response);
+    AllowedByNosniff::MimeTypeAsScript(doc(), response, MimeTypeCheck::kLax);
     EXPECT_TRUE(UseCounter::IsCounted(*doc(), testcase.expected));
   }
 }
@@ -221,8 +223,8 @@
     ResourceResponse response(KURL(testcase.url));
     response.SetHTTPHeaderField("Content-Type", "invalid");
     response.SetHTTPHeaderField("X-Content-Type-Options", "nosniff");
-    EXPECT_EQ(testcase.allowed,
-              AllowedByNosniff::MimeTypeAsScript(doc(), response));
+    EXPECT_EQ(testcase.allowed, AllowedByNosniff::MimeTypeAsScript(
+                                    doc(), response, MimeTypeCheck::kLax));
   }
 }
 
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
index 304434f8..52fe972a 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -109,9 +109,7 @@
   FixedPolicySubresourceFilter(LoadPolicy policy,
                                int* filtered_load_counter,
                                bool is_associated_with_ad_subframe)
-      : policy_(policy),
-        filtered_load_counter_(filtered_load_counter),
-        is_associated_with_ad_subframe_(is_associated_with_ad_subframe) {}
+      : policy_(policy), filtered_load_counter_(filtered_load_counter) {}
 
   LoadPolicy GetLoadPolicy(const WebURL& resource_url,
                            mojom::RequestContextType) override {
@@ -126,14 +124,9 @@
 
   bool ShouldLogToConsole() override { return false; }
 
-  bool GetIsAssociatedWithAdSubframe() const override {
-    return is_associated_with_ad_subframe_;
-  }
-
  private:
   const LoadPolicy policy_;
   int* filtered_load_counter_;
-  bool is_associated_with_ad_subframe_;
 };
 
 class FrameFetchContextTest : public testing::Test {
@@ -1187,17 +1180,6 @@
   EXPECT_EQ(0, GetFilteredLoadCallCount());
 }
 
-// Tests that if a subresource is allowed as per subresource filter ruleset but
-// is fetched from a frame that is tagged as an ad, then the subresource should
-// be tagged as well.
-TEST_F(FrameFetchContextSubresourceFilterTest, AdTaggingBasedOnFrame) {
-  SetFilterPolicy(WebDocumentSubresourceFilter::kAllow,
-                  true /* is_associated_with_ad_subframe */);
-
-  EXPECT_EQ(base::nullopt, CanRequestAndVerifyIsAd(true));
-  EXPECT_EQ(0, GetFilteredLoadCallCount());
-}
-
 TEST_F(FrameFetchContextTest, AddAdditionalRequestHeadersWhenDetached) {
   const KURL document_url("https://www2.example.com/fuga/hoge.html");
   const String origin = "https://www2.example.com";
diff --git a/third_party/blink/renderer/core/loader/subresource_filter.cc b/third_party/blink/renderer/core/loader/subresource_filter.cc
index b290e63..beedd9d 100644
--- a/third_party/blink/renderer/core/loader/subresource_filter.cc
+++ b/third_party/blink/renderer/core/loader/subresource_filter.cc
@@ -50,7 +50,7 @@
   // associated with an ad subframe.
   if (auto* document = DynamicTo<Document>(execution_context_.Get())) {
     auto* loader = document->Loader();
-    if (subresource_filter_->GetIsAssociatedWithAdSubframe()) {
+    if (document->GetFrame()->IsAdSubframe()) {
       ReportAdRequestId(loader->GetResponse().RequestId());
     }
   }
@@ -96,9 +96,6 @@
 bool SubresourceFilter::IsAdResource(
     const KURL& resource_url,
     mojom::RequestContextType request_context) {
-  if (subresource_filter_->GetIsAssociatedWithAdSubframe())
-    return true;
-
   WebDocumentSubresourceFilter::LoadPolicy load_policy;
   if (last_resource_check_result_.first ==
       std::make_pair(resource_url, request_context)) {
diff --git a/third_party/blink/renderer/core/script/classic_pending_script.cc b/third_party/blink/renderer/core/script/classic_pending_script.cc
index 68d4925..4fea45c 100644
--- a/third_party/blink/renderer/core/script/classic_pending_script.cc
+++ b/third_party/blink/renderer/core/script/classic_pending_script.cc
@@ -364,7 +364,7 @@
   // If the MIME check fails, which is considered as load failure.
   if (!AllowedByNosniff::MimeTypeAsScript(
           GetElement()->GetDocument().ContextDocument(),
-          resource->GetResponse())) {
+          resource->GetResponse(), AllowedByNosniff::MimeTypeCheck::kLax)) {
     return nullptr;
   }
 
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
index 3d47a35..a0b1baa7 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
@@ -121,7 +121,7 @@
 
 static ScrollbarPainterMap& GetScrollbarPainterMap() {
   DEFINE_STATIC_LOCAL(Persistent<ScrollbarPainterMap>, map,
-                      (new ScrollbarPainterMap));
+                      (MakeGarbageCollected<ScrollbarPainterMap>()));
   return *map;
 }
 
diff --git a/third_party/blink/renderer/core/streams/readable_stream_operations.cc b/third_party/blink/renderer/core/streams/readable_stream_operations.cc
index 679a8bd..9d71368 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_operations.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_operations.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/streams/underlying_source_base.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 
 namespace blink {
@@ -271,6 +272,7 @@
     ScriptValue stream,
     ExceptionState& exception_state) {
   DCHECK(IsReadableStreamForDCheck(script_state, stream));
+  DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
   v8::TryCatch block(script_state->GetIsolate());
   v8::Local<v8::Value> args[] = {stream.V8Value()};
   ScriptValue result(
@@ -297,6 +299,7 @@
     MessagePort* port,
     ExceptionState& exception_state) {
   DCHECK(port);
+  DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
   auto* isolate = script_state->GetIsolate();
   v8::Local<v8::Context> context = script_state->GetContext();
   v8::Local<v8::Value> port_v8 = ToV8(port, context->Global(), isolate);
diff --git a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc b/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
index 7459b41fd..00162693 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "v8/include/v8.h"
 
@@ -494,6 +495,8 @@
 }
 
 TEST(ReadableStreamOperationsTest, Serialize) {
+  RuntimeEnabledFeatures::SetTransferableStreamsEnabled(true);
+
   V8TestingScope scope;
   TryCatchScope try_catch_scope(scope.GetIsolate());
   ScriptValue original = EvalWithPrintingError(&scope,
diff --git a/third_party/blink/renderer/core/style/style_inherited_variables.cc b/third_party/blink/renderer/core/style/style_inherited_variables.cc
index 3c4be35..deb2754 100644
--- a/third_party/blink/renderer/core/style/style_inherited_variables.cc
+++ b/third_party/blink/renderer/core/style/style_inherited_variables.cc
@@ -31,19 +31,22 @@
 }
 
 StyleInheritedVariables::StyleInheritedVariables()
-    : registered_data_(new HeapHashMap<AtomicString, Member<CSSValue>>),
+    : registered_data_(
+          MakeGarbageCollected<HeapHashMap<AtomicString, Member<CSSValue>>>()),
       root_(nullptr),
       needs_resolution_(false) {}
 
 StyleInheritedVariables::StyleInheritedVariables(
     StyleInheritedVariables& other) {
   if (!other.root_) {
-    registered_data_ = new HeapHashMap<AtomicString, Member<CSSValue>>;
+    registered_data_ =
+        MakeGarbageCollected<HeapHashMap<AtomicString, Member<CSSValue>>>();
     root_ = &other;
   } else {
     data_ = other.data_;
-    registered_data_ = new HeapHashMap<AtomicString, Member<CSSValue>>(
-        *other.registered_data_);
+    registered_data_ =
+        MakeGarbageCollected<HeapHashMap<AtomicString, Member<CSSValue>>>(
+            *other.registered_data_);
     root_ = other.root_;
   }
   needs_resolution_ = other.needs_resolution_;
diff --git a/third_party/blink/renderer/core/style/style_non_inherited_variables.cc b/third_party/blink/renderer/core/style/style_non_inherited_variables.cc
index e13afe9..ea34e3c 100644
--- a/third_party/blink/renderer/core/style/style_non_inherited_variables.cc
+++ b/third_party/blink/renderer/core/style/style_non_inherited_variables.cc
@@ -40,14 +40,16 @@
 }
 
 StyleNonInheritedVariables::StyleNonInheritedVariables()
-    : registered_data_(new HeapHashMap<AtomicString, Member<CSSValue>>),
+    : registered_data_(
+          MakeGarbageCollected<HeapHashMap<AtomicString, Member<CSSValue>>>()),
       needs_resolution_(false) {}
 
 StyleNonInheritedVariables::StyleNonInheritedVariables(
     StyleNonInheritedVariables& other) {
   data_ = other.data_;
   registered_data_ =
-      new HeapHashMap<AtomicString, Member<CSSValue>>(*other.registered_data_);
+      MakeGarbageCollected<HeapHashMap<AtomicString, Member<CSSValue>>>(
+          *other.registered_data_);
   needs_resolution_ = other.needs_resolution_;
 }
 
diff --git a/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.cc b/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.cc
index 5d4894ca..262aeea 100644
--- a/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.cc
+++ b/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.cc
@@ -15,10 +15,9 @@
 SharedWorkerContentSettingsProxy::~SharedWorkerContentSettingsProxy() = default;
 
 bool SharedWorkerContentSettingsProxy::AllowIndexedDB(
-    const WebString& name,
     const WebSecurityOrigin& origin) {
   bool result = false;
-  GetService()->AllowIndexedDB(name, &result);
+  GetService()->AllowIndexedDB(&result);
   return result;
 }
 
diff --git a/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.h b/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.h
index 1fb2dcc..f1a3f2e 100644
--- a/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.h
+++ b/third_party/blink/renderer/core/workers/shared_worker_content_settings_proxy.h
@@ -22,7 +22,7 @@
   ~SharedWorkerContentSettingsProxy() override;
 
   // WebContentSettingsClient overrides.
-  bool AllowIndexedDB(const WebString& name, const WebSecurityOrigin&) override;
+  bool AllowIndexedDB(const WebSecurityOrigin&) override;
   bool RequestFileSystemAccessSync() override;
 
  private:
diff --git a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
index 6636d27f..2d550a09 100644
--- a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
+++ b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
@@ -33,7 +33,6 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/loader/allowed_by_nosniff.h"
 #include "third_party/blink/renderer/core/loader/resource/script_resource.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
@@ -48,7 +47,8 @@
 namespace blink {
 
 WorkerClassicScriptLoader::WorkerClassicScriptLoader()
-    : response_address_space_(mojom::IPAddressSpace::kPublic) {}
+    : response_address_space_(mojom::IPAddressSpace::kPublic),
+      mime_type_check_mode_(AllowedByNosniff::MimeTypeCheck::kStrict) {}
 
 WorkerClassicScriptLoader::~WorkerClassicScriptLoader() {
   // If |threadable_loader_| is still working, we have to cancel it here.
@@ -67,6 +67,10 @@
   url_ = url;
   execution_context_ = &execution_context;
 
+  // Impose strict MIME-type checks on importScripts(). See
+  // https://crbug.com/794548.
+  mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kStrict;
+
   ResourceRequest request(url);
   request.SetHTTPMethod(http_names::kGET);
   request.SetExternalRequestStateFromRequestorAddressSpace(
@@ -101,6 +105,20 @@
   execution_context_ = &execution_context;
   forbid_cross_origin_redirects_ = true;
 
+  if (execution_context.IsDocument()) {
+    // For worker creation on a document, don't impose strict MIME-type checks
+    // on the top-level worker script for backward compatibility. Note that
+    // there is a plan to deprecate legacy mime types for workers. See
+    // https://crbug.com/794548.
+    mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kLax;
+  } else {
+    // For nested workers, impose the strict MIME-type checks because the
+    // feature is new (enabled by default in M69) and there is no backward
+    // compatibility issue.
+    DCHECK(execution_context.IsWorkerGlobalScope());
+    mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kStrict;
+  }
+
   ResourceRequest request(url);
   request.SetHTTPMethod(http_names::kGET);
   request.SetExternalRequestStateFromRequestorAddressSpace(
@@ -138,7 +156,8 @@
     NotifyError();
     return;
   }
-  if (!AllowedByNosniff::MimeTypeAsScript(execution_context_, response)) {
+  if (!AllowedByNosniff::MimeTypeAsScript(execution_context_, response,
+                                          mime_type_check_mode_)) {
     NotifyError();
     return;
   }
diff --git a/third_party/blink/renderer/core/workers/worker_classic_script_loader.h b/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
index 2739806..2efe4a77 100644
--- a/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
+++ b/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
@@ -35,6 +35,7 @@
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/loader/allowed_by_nosniff.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
@@ -155,6 +156,9 @@
   mojom::IPAddressSpace response_address_space_;
   std::unique_ptr<Vector<String>> origin_trial_tokens_;
   String referrer_policy_;
+
+  // TODO(nhiroki): Move this to FetchClientSettingsObject.
+  AllowedByNosniff::MimeTypeCheck mime_type_check_mode_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/workers/worker_content_settings_client.cc b/third_party/blink/renderer/core/workers/worker_content_settings_client.cc
index 484c4f3..6de21a2 100644
--- a/third_party/blink/renderer/core/workers/worker_content_settings_client.cc
+++ b/third_party/blink/renderer/core/workers/worker_content_settings_client.cc
@@ -51,10 +51,10 @@
   return client_->RequestFileSystemAccessSync();
 }
 
-bool WorkerContentSettingsClient::AllowIndexedDB(const WebString& name) {
+bool WorkerContentSettingsClient::AllowIndexedDB() {
   if (!client_)
     return true;
-  return client_->AllowIndexedDB(name, WebSecurityOrigin());
+  return client_->AllowIndexedDB(WebSecurityOrigin());
 }
 
 bool WorkerContentSettingsClient::AllowScriptFromSource(
diff --git a/third_party/blink/renderer/core/workers/worker_content_settings_client.h b/third_party/blink/renderer/core/workers/worker_content_settings_client.h
index 4db0bf22..8d73578 100644
--- a/third_party/blink/renderer/core/workers/worker_content_settings_client.h
+++ b/third_party/blink/renderer/core/workers/worker_content_settings_client.h
@@ -42,7 +42,6 @@
 class ExecutionContext;
 class KURL;
 class SecurityOrigin;
-class WebString;
 
 class CORE_EXPORT WorkerContentSettingsClient final
     : public GarbageCollectedFinalized<WorkerContentSettingsClient>,
@@ -57,7 +56,7 @@
   virtual ~WorkerContentSettingsClient();
 
   bool RequestFileSystemAccessSync();
-  bool AllowIndexedDB(const WebString& name);
+  bool AllowIndexedDB();
   bool AllowRunningInsecureContent(bool enabled_per_settings,
                                    const SecurityOrigin*,
                                    const KURL&);
diff --git a/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc b/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc
index afe6c23..eedef03b 100644
--- a/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc
+++ b/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc
@@ -504,7 +504,7 @@
 
 EnabledAgentsMultimap& EnabledAgents() {
   DEFINE_STATIC_LOCAL(Persistent<EnabledAgentsMultimap>, enabled_agents,
-                      (new EnabledAgentsMultimap()));
+                      (MakeGarbageCollected<EnabledAgentsMultimap>()));
   return *enabled_agents;
 }
 
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_factory.cc b/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
index 1e123b7a..77491a1 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
@@ -227,8 +227,7 @@
   }
 
   if (!IndexedDBClient::From(ExecutionContext::From(script_state))
-           ->AllowIndexedDB(ExecutionContext::From(script_state),
-                            "Database Listing")) {
+           ->AllowIndexedDB(ExecutionContext::From(script_state))) {
     request->HandleResponse(DOMException::Create(
         DOMExceptionCode::kUnknownError, kPermissionDeniedErrorMessage));
     return request;
@@ -283,7 +282,7 @@
                                version, std::move(metrics));
 
   if (!IndexedDBClient::From(ExecutionContext::From(script_state))
-           ->AllowIndexedDB(ExecutionContext::From(script_state), name)) {
+           ->AllowIndexedDB(ExecutionContext::From(script_state))) {
     request->HandleResponse(DOMException::Create(
         DOMExceptionCode::kUnknownError, kPermissionDeniedErrorMessage));
     return request;
@@ -349,7 +348,7 @@
       std::move(metrics));
 
   if (!IndexedDBClient::From(ExecutionContext::From(script_state))
-           ->AllowIndexedDB(ExecutionContext::From(script_state), name)) {
+           ->AllowIndexedDB(ExecutionContext::From(script_state))) {
     request->HandleResponse(DOMException::Create(
         DOMExceptionCode::kUnknownError, kPermissionDeniedErrorMessage));
     return request;
diff --git a/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc b/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc
index b495303..3d1313b 100644
--- a/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc
+++ b/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc
@@ -41,8 +41,7 @@
   return Supplement<WorkerClients>::From<IndexedDBClient>(clients);
 }
 
-bool IndexedDBClient::AllowIndexedDB(ExecutionContext* context,
-                                     const String& name) {
+bool IndexedDBClient::AllowIndexedDB(ExecutionContext* context) {
   DCHECK(context->IsContextThread());
   SECURITY_DCHECK(context->IsDocument() || context->IsWorkerGlobalScope());
 
@@ -52,14 +51,14 @@
       return false;
     if (auto* settings_client = frame->GetContentSettingsClient()) {
       return settings_client->AllowIndexedDB(
-          name, WebSecurityOrigin(context->GetSecurityOrigin()));
+          WebSecurityOrigin(context->GetSecurityOrigin()));
     }
     return true;
   }
 
   WorkerGlobalScope& worker_global_scope = *To<WorkerGlobalScope>(context);
   return WorkerContentSettingsClient::From(worker_global_scope)
-      ->AllowIndexedDB(name);
+      ->AllowIndexedDB();
 }
 
 // static
diff --git a/third_party/blink/renderer/modules/indexeddb/indexed_db_client.h b/third_party/blink/renderer/modules/indexeddb/indexed_db_client.h
index e34ad57..42ef27c2 100644
--- a/third_party/blink/renderer/modules/indexeddb/indexed_db_client.h
+++ b/third_party/blink/renderer/modules/indexeddb/indexed_db_client.h
@@ -58,7 +58,7 @@
   void Trace(blink::Visitor*) override;
   const char* NameInHeapSnapshot() const override { return "IndexedDBClient"; }
 
-  bool AllowIndexedDB(ExecutionContext*, const String& name);
+  bool AllowIndexedDB(ExecutionContext*);
 
   static IndexedDBClient* From(ExecutionContext*);
 
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
index 2bb858f..c261bf07 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
@@ -34,6 +34,7 @@
 namespace {
 
 const double kCurrentTimeBufferedDelta = 1.0;
+const int kThumbRadius = 6;
 
 // Only respond to main button of primary pointer(s).
 bool IsValidPointerEvent(const blink::Event& event) {
@@ -198,6 +199,18 @@
   }
 
   double current_position = current_time / duration;
+
+  // Transform the current_position to always align with the center of thumb
+  // At time 0, the thumb's center is 6px away from beginning of progress bar
+  // At the end of video, thumb's center is -6px away from end of progress bar
+  // Convert 6px into ratio respect to progress bar width since
+  // current_position is range from 0 to 1
+  double width = TrackWidth() / ZoomFactor();
+  if (width != 0) {
+    double offset = kThumbRadius / width;
+    current_position += offset - 2 * offset * current_position;
+  }
+
   MediaControlSliderElement::Position before_segment(0, 0);
   MediaControlSliderElement::Position after_segment(0, 0);
 
diff --git a/third_party/blink/renderer/modules/mediasource/media_source_registry.cc b/third_party/blink/renderer/modules/mediasource/media_source_registry.cc
index 84c35851..62a3c7b 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source_registry.cc
+++ b/third_party/blink/renderer/modules/mediasource/media_source_registry.cc
@@ -70,7 +70,8 @@
 }
 
 MediaSourceRegistry::MediaSourceRegistry()
-    : media_sources_(new HeapHashMap<String, Member<MediaSource>>) {
+    : media_sources_(
+          MakeGarbageCollected<HeapHashMap<String, Member<MediaSource>>>()) {
   HTMLMediaSource::SetRegistry(this);
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/BUILD.gn b/third_party/blink/renderer/modules/service_worker/BUILD.gn
index 8e4a8ab..82bfd0f 100644
--- a/third_party/blink/renderer/modules/service_worker/BUILD.gn
+++ b/third_party/blink/renderer/modules/service_worker/BUILD.gn
@@ -30,8 +30,6 @@
     "service_worker_clients.h",
     "service_worker_container.cc",
     "service_worker_container.h",
-    "service_worker_container_client.cc",
-    "service_worker_container_client.h",
     "service_worker_content_settings_proxy.cc",
     "service_worker_content_settings_proxy.h",
     "service_worker_error.cc",
diff --git a/third_party/blink/renderer/modules/service_worker/navigation_preload_manager.cc b/third_party/blink/renderer/modules/service_worker/navigation_preload_manager.cc
index 47f3079c..7183dc9 100644
--- a/third_party/blink/renderer/modules/service_worker/navigation_preload_manager.cc
+++ b/third_party/blink/renderer/modules/service_worker/navigation_preload_manager.cc
@@ -8,7 +8,6 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_container_client.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
 #include "third_party/blink/renderer/platform/network/http_parsers.h"
 
diff --git a/third_party/blink/renderer/modules/service_worker/navigator_service_worker.cc b/third_party/blink/renderer/modules/service_worker/navigator_service_worker.cc
index 4c438f47..e04a38af 100644
--- a/third_party/blink/renderer/modules/service_worker/navigator_service_worker.cc
+++ b/third_party/blink/renderer/modules/service_worker/navigator_service_worker.cc
@@ -122,23 +122,13 @@
              frame->GetSecurityContext()->GetSecurityOrigin()->IsLocal()) {
     UseCounter::Count(frame, WebFeature::kFileAccessedServiceWorker);
   }
-  if (!service_worker_ && frame) {
-    // We need to create a new ServiceWorkerContainer when the frame
-    // navigates to a new document. In practice, this happens only when the
-    // frame navigates from the initial empty page to a new same-origin page.
-    DCHECK(frame->DomWindow());
-    service_worker_ = ServiceWorkerContainer::Create(
-        frame->DomWindow()->GetExecutionContext(), this);
-  }
-  return service_worker_.Get();
-}
-
-void NavigatorServiceWorker::ClearServiceWorker() {
-  service_worker_ = nullptr;
+  if (!frame)
+    return nullptr;
+  return ServiceWorkerContainer::From(
+      To<Document>(frame->DomWindow()->GetExecutionContext()));
 }
 
 void NavigatorServiceWorker::Trace(blink::Visitor* visitor) {
-  visitor->Trace(service_worker_);
   Supplement<Navigator>::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/navigator_service_worker.h b/third_party/blink/renderer/modules/service_worker/navigator_service_worker.h
index 681910d..d1961026 100644
--- a/third_party/blink/renderer/modules/service_worker/navigator_service_worker.h
+++ b/third_party/blink/renderer/modules/service_worker/navigator_service_worker.h
@@ -35,16 +35,12 @@
   static ServiceWorkerContainer* serviceWorker(ScriptState*,
                                                Navigator&,
                                                String& error_message);
-  void ClearServiceWorker();
-
   void Trace(blink::Visitor*) override;
 
  private:
   explicit NavigatorServiceWorker(Navigator&);
   ServiceWorkerContainer* serviceWorker(LocalFrame*, ExceptionState&);
   ServiceWorkerContainer* serviceWorker(LocalFrame*, String& error_message);
-
-  Member<ServiceWorkerContainer> service_worker_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker.cc b/third_party/blink/renderer/modules/service_worker/service_worker.cc
index 835dd60..e236e25d 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker.cc
@@ -41,7 +41,7 @@
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/core/messaging/post_message_options.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_container_client.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_container.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -161,7 +161,7 @@
     return scope->GetOrCreateServiceWorker(std::move(info));
   }
 
-  return ServiceWorkerContainerClient::From(To<Document>(context))
+  return ServiceWorkerContainer::From(To<Document>(context))
       ->GetOrCreateServiceWorker(std::move(info));
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
index 05909631..96aa30f 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
@@ -34,7 +34,6 @@
 
 #include "base/macros.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
@@ -49,14 +48,14 @@
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/messaging/blink_transferable_message.h"
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
-#include "third_party/blink/renderer/modules/service_worker/navigator_service_worker.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_container_client.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_error.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -137,7 +136,7 @@
     if (ready_->GetExecutionContext() &&
         !ready_->GetExecutionContext()->IsContextDestroyed()) {
       ready_->Resolve(
-          ServiceWorkerContainerClient::From(
+          ServiceWorkerContainer::From(
               To<Document>(ready_->GetExecutionContext()))
               ->GetOrCreateServiceWorkerRegistration(std::move(info)));
     }
@@ -148,10 +147,37 @@
   DISALLOW_COPY_AND_ASSIGN(GetRegistrationForReadyCallback);
 };
 
-ServiceWorkerContainer* ServiceWorkerContainer::Create(
-    ExecutionContext* execution_context,
-    NavigatorServiceWorker* navigator) {
-  return new ServiceWorkerContainer(execution_context, navigator);
+const char ServiceWorkerContainer::kSupplementName[] = "ServiceWorkerContainer";
+
+ServiceWorkerContainer* ServiceWorkerContainer::From(Document* document) {
+  if (!document)
+    return nullptr;
+
+  ServiceWorkerContainer* container =
+      Supplement<Document>::From<ServiceWorkerContainer>(document);
+  if (!container) {
+    // TODO(leonhsl): Figure out whether it's really necessary to create an
+    // instance when there's no frame or frame client for |document|.
+    container = new ServiceWorkerContainer(document);
+    Supplement<Document>::ProvideTo(*document, container);
+    if (document->GetFrame() && document->GetFrame()->Client()) {
+      std::unique_ptr<WebServiceWorkerProvider> provider =
+          document->GetFrame()->Client()->CreateServiceWorkerProvider();
+      if (provider) {
+        provider->SetClient(container);
+        container->provider_ = std::move(provider);
+      }
+    }
+  }
+  return container;
+}
+
+ServiceWorkerContainer* ServiceWorkerContainer::CreateForTesting(
+    Document* document,
+    std::unique_ptr<WebServiceWorkerProvider> provider) {
+  ServiceWorkerContainer* container = new ServiceWorkerContainer(document);
+  container->provider_ = std::move(provider);
+  return container;
 }
 
 ServiceWorkerContainer::~ServiceWorkerContainer() {
@@ -164,14 +190,15 @@
     provider_ = nullptr;
   }
   controller_ = nullptr;
-  navigator_->ClearServiceWorker();
 }
 
 void ServiceWorkerContainer::Trace(blink::Visitor* visitor) {
   visitor->Trace(controller_);
   visitor->Trace(ready_);
-  visitor->Trace(navigator_);
+  visitor->Trace(service_worker_registration_objects_);
+  visitor->Trace(service_worker_objects_);
   EventTargetWithInlineData::Trace(visitor);
+  Supplement<Document>::Trace(visitor);
   ContextLifecycleObserver::Trace(visitor);
 }
 
@@ -476,27 +503,48 @@
     Deprecation::CountDeprecation(GetExecutionContext(), feature);
 }
 
+ExecutionContext* ServiceWorkerContainer::GetExecutionContext() const {
+  return GetSupplementable();
+}
+
 const AtomicString& ServiceWorkerContainer::InterfaceName() const {
   return EventTargetNames::ServiceWorkerContainer;
 }
 
-ServiceWorkerContainer::ServiceWorkerContainer(
-    ExecutionContext* execution_context,
-    NavigatorServiceWorker* navigator)
-    : ContextLifecycleObserver(execution_context),
-      provider_(nullptr),
-      navigator_(navigator) {
-  if (!execution_context)
-    return;
+ServiceWorkerRegistration*
+ServiceWorkerContainer::GetOrCreateServiceWorkerRegistration(
+    WebServiceWorkerRegistrationObjectInfo info) {
+  if (info.registration_id == mojom::blink::kInvalidServiceWorkerRegistrationId)
+    return nullptr;
 
-  if (ServiceWorkerContainerClient* client =
-          ServiceWorkerContainerClient::From(To<Document>(execution_context))) {
-    provider_ = client->Provider();
-    if (provider_)
-      provider_->SetClient(this);
+  ServiceWorkerRegistration* registration =
+      service_worker_registration_objects_.at(info.registration_id);
+  if (registration) {
+    registration->Attach(std::move(info));
+    return registration;
   }
+
+  registration =
+      new ServiceWorkerRegistration(GetSupplementable(), std::move(info));
+  service_worker_registration_objects_.Set(info.registration_id, registration);
+  return registration;
 }
 
+ServiceWorker* ServiceWorkerContainer::GetOrCreateServiceWorker(
+    WebServiceWorkerObjectInfo info) {
+  if (info.version_id == mojom::blink::kInvalidServiceWorkerVersionId)
+    return nullptr;
+  ServiceWorker* worker = service_worker_objects_.at(info.version_id);
+  if (!worker) {
+    worker = new ServiceWorker(GetSupplementable(), std::move(info));
+    service_worker_objects_.Set(info.version_id, worker);
+  }
+  return worker;
+}
+
+ServiceWorkerContainer::ServiceWorkerContainer(Document* document)
+    : Supplement<Document>(*document), ContextLifecycleObserver(document) {}
+
 ServiceWorkerContainer::ReadyProperty*
 ServiceWorkerContainer::CreateReadyProperty() {
   return new ReadyProperty(GetExecutionContext(), this, ReadyProperty::kReady);
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container.h b/third_party/blink/renderer/modules/service_worker/service_worker_container.h
index d45a9db..b3cff74 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_container.h
@@ -38,6 +38,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_property.h"
 #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/service_worker/registration_options.h"
@@ -50,11 +51,10 @@
 namespace blink {
 
 class ExecutionContext;
-class NavigatorServiceWorker;
-class WebServiceWorkerProvider;
 
 class MODULES_EXPORT ServiceWorkerContainer final
     : public EventTargetWithInlineData,
+      public Supplement<Document>,
       public ContextLifecycleObserver,
       public WebServiceWorkerProviderClient {
   DEFINE_WRAPPERTYPEINFO();
@@ -64,15 +64,19 @@
   using RegistrationCallbacks =
       WebServiceWorkerProvider::WebServiceWorkerRegistrationCallbacks;
 
-  static ServiceWorkerContainer* Create(ExecutionContext*,
-                                        NavigatorServiceWorker*);
+  static const char kSupplementName[];
+
+  static ServiceWorkerContainer* From(Document*);
+
+  static ServiceWorkerContainer* CreateForTesting(
+      Document*,
+      std::unique_ptr<WebServiceWorkerProvider>);
   ~ServiceWorkerContainer() override;
 
   void Trace(blink::Visitor*) override;
 
   ServiceWorker* controller() { return controller_; }
   ScriptPromise ready(ScriptState*);
-  WebServiceWorkerProvider* Provider() { return provider_; }
 
   ScriptPromise registerServiceWorker(ScriptState*,
                                       const String& pattern,
@@ -90,16 +94,23 @@
   void CountFeature(mojom::WebFeature) override;
 
   // EventTarget overrides.
-  ExecutionContext* GetExecutionContext() const override {
-    return ContextLifecycleObserver::GetExecutionContext();
-  }
+  ExecutionContext* GetExecutionContext() const override;
   const AtomicString& InterfaceName() const override;
 
   DEFINE_ATTRIBUTE_EVENT_LISTENER(controllerchange);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(message);
 
+  // Returns the ServiceWorkerRegistration object described by the given info.
+  // Creates a new object if needed, or else returns the existing one.
+  ServiceWorkerRegistration* GetOrCreateServiceWorkerRegistration(
+      WebServiceWorkerRegistrationObjectInfo);
+
+  // Returns the ServiceWorker object described by the given info. Creates a new
+  // object if needed, or else returns the existing one.
+  ServiceWorker* GetOrCreateServiceWorker(WebServiceWorkerObjectInfo);
+
  private:
-  ServiceWorkerContainer(ExecutionContext*, NavigatorServiceWorker*);
+  explicit ServiceWorkerContainer(Document*);
 
   class GetRegistrationForReadyCallback;
   using ReadyProperty =
@@ -108,10 +119,24 @@
                             Member<ServiceWorkerRegistration>>;
   ReadyProperty* CreateReadyProperty();
 
-  WebServiceWorkerProvider* provider_;
+  std::unique_ptr<WebServiceWorkerProvider> provider_;
   Member<ServiceWorker> controller_;
   Member<ReadyProperty> ready_;
-  Member<NavigatorServiceWorker> navigator_;
+
+  // Map from service worker registration id to JavaScript
+  // ServiceWorkerRegistration object in current execution context.
+  HeapHashMap<int64_t,
+              WeakMember<ServiceWorkerRegistration>,
+              WTF::IntHash<int64_t>,
+              WTF::UnsignedWithZeroKeyHashTraits<int64_t>>
+      service_worker_registration_objects_;
+  // Map from service worker version id to JavaScript ServiceWorker object in
+  // current execution context.
+  HeapHashMap<int64_t,
+              WeakMember<ServiceWorker>,
+              WTF::IntHash<int64_t>,
+              WTF::UnsignedWithZeroKeyHashTraits<int64_t>>
+      service_worker_objects_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container_client.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container_client.cc
deleted file mode 100644
index 14951fd8..0000000
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container_client.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/service_worker/service_worker_container_client.h"
-
-#include <memory>
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/local_frame_client.h"
-
-namespace blink {
-
-ServiceWorkerContainerClient::ServiceWorkerContainerClient(
-    Document& document,
-    std::unique_ptr<WebServiceWorkerProvider> provider)
-    : Supplement<Document>(document), provider_(std::move(provider)) {}
-
-ServiceWorkerContainerClient::~ServiceWorkerContainerClient() = default;
-
-const char ServiceWorkerContainerClient::kSupplementName[] =
-    "ServiceWorkerContainerClient";
-
-ServiceWorkerRegistration*
-ServiceWorkerContainerClient::GetOrCreateServiceWorkerRegistration(
-    WebServiceWorkerRegistrationObjectInfo info) {
-  if (info.registration_id == mojom::blink::kInvalidServiceWorkerRegistrationId)
-    return nullptr;
-
-  ServiceWorkerRegistration* registration =
-      service_worker_registration_objects_.at(info.registration_id);
-  if (registration) {
-    registration->Attach(std::move(info));
-    return registration;
-  }
-
-  registration =
-      new ServiceWorkerRegistration(GetSupplementable(), std::move(info));
-  service_worker_registration_objects_.Set(info.registration_id, registration);
-  return registration;
-}
-
-ServiceWorker* ServiceWorkerContainerClient::GetOrCreateServiceWorker(
-    WebServiceWorkerObjectInfo info) {
-  if (info.version_id == mojom::blink::kInvalidServiceWorkerVersionId)
-    return nullptr;
-  ServiceWorker* worker = service_worker_objects_.at(info.version_id);
-  if (!worker) {
-    worker = new ServiceWorker(GetSupplementable(), std::move(info));
-    service_worker_objects_.Set(info.version_id, worker);
-  }
-  return worker;
-}
-
-ServiceWorkerContainerClient* ServiceWorkerContainerClient::From(
-    Document* document) {
-  if (!document)
-    return nullptr;
-  if (!document->GetFrame() || !document->GetFrame()->Client())
-    return nullptr;
-
-  ServiceWorkerContainerClient* client =
-      Supplement<Document>::From<ServiceWorkerContainerClient>(document);
-  if (!client) {
-    client = new ServiceWorkerContainerClient(
-        *document,
-        document->GetFrame()->Client()->CreateServiceWorkerProvider());
-    Supplement<Document>::ProvideTo(*document, client);
-  }
-  return client;
-}
-
-void ServiceWorkerContainerClient::Trace(blink::Visitor* visitor) {
-  visitor->Trace(service_worker_registration_objects_);
-  visitor->Trace(service_worker_objects_);
-  Supplement<Document>::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container_client.h b/third_party/blink/renderer/modules/service_worker/service_worker_container_client.h
deleted file mode 100644
index 98503a677..0000000
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container_client.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_CONTAINER_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_CONTAINER_CLIENT_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
-#include "third_party/blink/renderer/platform/bindings/name_client.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-
-namespace blink {
-
-class WebServiceWorkerProvider;
-
-// This mainly exists to provide access to WebServiceWorkerProvider.
-// Owned by Document.
-class MODULES_EXPORT ServiceWorkerContainerClient final
-    : public GarbageCollectedFinalized<ServiceWorkerContainerClient>,
-      public Supplement<Document>,
-      public NameClient {
-  USING_GARBAGE_COLLECTED_MIXIN(ServiceWorkerContainerClient);
-
- public:
-  static const char kSupplementName[];
-
-  ServiceWorkerContainerClient(Document&,
-                               std::unique_ptr<WebServiceWorkerProvider>);
-  virtual ~ServiceWorkerContainerClient();
-
-  // Returns the ServiceWorkerRegistration object described by the object info
-  // in current execution context. Creates a new object if needed, or else
-  // returns the existing one.
-  ServiceWorkerRegistration* GetOrCreateServiceWorkerRegistration(
-      WebServiceWorkerRegistrationObjectInfo);
-
-  // Returns the ServiceWorker object described by the object info in current
-  // execution context. Creates a new object if needed, or else returns the
-  // existing one.
-  ServiceWorker* GetOrCreateServiceWorker(WebServiceWorkerObjectInfo);
-
-  WebServiceWorkerProvider* Provider() { return provider_.get(); }
-
-  static ServiceWorkerContainerClient* From(Document*);
-
-  void Trace(blink::Visitor* visitor) override;
-
-  const char* NameInHeapSnapshot() const override {
-    return "ServiceWorkerContainerClient";
-  }
-
- private:
-  std::unique_ptr<WebServiceWorkerProvider> provider_;
-  // Map from service worker registration id to JavaScript
-  // ServiceWorkerRegistration object in current execution context.
-  HeapHashMap<int64_t,
-              WeakMember<ServiceWorkerRegistration>,
-              WTF::IntHash<int64_t>,
-              WTF::UnsignedWithZeroKeyHashTraits<int64_t>>
-      service_worker_registration_objects_;
-  // Map from service worker version id to JavaScript ServiceWorker object in
-  // current execution context.
-  HeapHashMap<int64_t,
-              WeakMember<ServiceWorker>,
-              WTF::IntHash<int64_t>,
-              WTF::UnsignedWithZeroKeyHashTraits<int64_t>>
-      service_worker_objects_;
-
-  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContainerClient);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_CONTAINER_CLIENT_H_
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
index a750ba0..5022e6c 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
@@ -24,7 +24,6 @@
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
 #include "third_party/blink/renderer/modules/service_worker/navigator_service_worker.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_container_client.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -154,21 +153,11 @@
     V8GCController::CollectAllGarbageForTesting(GetIsolate());
   }
 
-  ExecutionContext* GetExecutionContext() { return &GetDocument(); }
-  NavigatorServiceWorker* GetNavigatorServiceWorker() {
-    return NavigatorServiceWorker::From(GetDocument());
-  }
   v8::Isolate* GetIsolate() { return v8::Isolate::GetCurrent(); }
   ScriptState* GetScriptState() {
     return ToScriptStateForMainWorld(GetDocument().GetFrame());
   }
 
-  void Provide(std::unique_ptr<WebServiceWorkerProvider> provider) {
-    Supplement<Document>::ProvideTo(
-        GetDocument(),
-        new ServiceWorkerContainerClient(GetDocument(), std::move(provider)));
-  }
-
   void SetPageURL(const String& url) {
     // For URL completion.
     GetDocument().SetURL(KURL(NullURL(), url));
@@ -187,10 +176,10 @@
                             const ScriptValueTest& value_test) {
     // When the registration is rejected, a register call must not reach
     // the provider.
-    Provide(std::make_unique<NotReachedWebServiceWorkerProvider>());
-
-    ServiceWorkerContainer* container = ServiceWorkerContainer::Create(
-        GetExecutionContext(), GetNavigatorServiceWorker());
+    ServiceWorkerContainer* container =
+        ServiceWorkerContainer::CreateForTesting(
+            &GetDocument(),
+            std::make_unique<NotReachedWebServiceWorkerProvider>());
     ScriptState::Scope script_scope(GetScriptState());
     RegistrationOptions options;
     options.setScope(scope);
@@ -201,10 +190,10 @@
 
   void TestGetRegistrationRejected(const String& document_url,
                                    const ScriptValueTest& value_test) {
-    Provide(std::make_unique<NotReachedWebServiceWorkerProvider>());
-
-    ServiceWorkerContainer* container = ServiceWorkerContainer::Create(
-        GetExecutionContext(), GetNavigatorServiceWorker());
+    ServiceWorkerContainer* container =
+        ServiceWorkerContainer::CreateForTesting(
+            &GetDocument(),
+            std::make_unique<NotReachedWebServiceWorkerProvider>());
     ScriptState::Scope script_scope(GetScriptState());
     ScriptPromise promise =
         container->getRegistration(GetScriptState(), document_url);
@@ -334,10 +323,8 @@
   SetPageURL("http://localhost/x/index.html");
 
   StubWebServiceWorkerProvider stub_provider;
-  Provide(stub_provider.Provider());
-
-  ServiceWorkerContainer* container = ServiceWorkerContainer::Create(
-      GetExecutionContext(), GetNavigatorServiceWorker());
+  ServiceWorkerContainer* container = ServiceWorkerContainer::CreateForTesting(
+      &GetDocument(), stub_provider.Provider());
 
   // register
   {
@@ -363,10 +350,8 @@
   SetPageURL("http://localhost/x/index.html");
 
   StubWebServiceWorkerProvider stub_provider;
-  Provide(stub_provider.Provider());
-
-  ServiceWorkerContainer* container = ServiceWorkerContainer::Create(
-      GetExecutionContext(), GetNavigatorServiceWorker());
+  ServiceWorkerContainer* container = ServiceWorkerContainer::CreateForTesting(
+      &GetDocument(), stub_provider.Provider());
 
   {
     ScriptState::Scope script_scope(GetScriptState());
@@ -385,10 +370,8 @@
   SetPageURL("http://localhost/x/index.html");
 
   StubWebServiceWorkerProvider stub_provider;
-  Provide(stub_provider.Provider());
-
-  ServiceWorkerContainer* container = ServiceWorkerContainer::Create(
-      GetExecutionContext(), GetNavigatorServiceWorker());
+  ServiceWorkerContainer* container = ServiceWorkerContainer::CreateForTesting(
+      &GetDocument(), stub_provider.Provider());
 
   // register
   {
@@ -413,10 +396,8 @@
   SetPageURL("http://localhost/x/index.html");
 
   StubWebServiceWorkerProvider stub_provider;
-  Provide(stub_provider.Provider());
-
-  ServiceWorkerContainer* container = ServiceWorkerContainer::Create(
-      GetExecutionContext(), GetNavigatorServiceWorker());
+  ServiceWorkerContainer* container = ServiceWorkerContainer::CreateForTesting(
+      &GetDocument(), stub_provider.Provider());
 
   // register
   {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.cc
index f545f92..e11ec2a1 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.cc
@@ -21,10 +21,9 @@
 }
 
 bool ServiceWorkerContentSettingsProxy::AllowIndexedDB(
-    const blink::WebString& name,
     const blink::WebSecurityOrigin&) {
   bool result = false;
-  GetService()->AllowIndexedDB(name, &result);
+  GetService()->AllowIndexedDB(&result);
   return result;
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h
index 188a62b..75ce9b1 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h
@@ -28,7 +28,7 @@
   // Asks the browser process about the settings.
   // Blocks until the response arrives.
   bool RequestFileSystemAccessSync() override;
-  bool AllowIndexedDB(const WebString& name, const WebSecurityOrigin&) override;
+  bool AllowIndexedDB(const WebSecurityOrigin&) override;
 
  private:
   // To ensure the returned pointer is destructed on the same thread
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index 091b66e..04b19b3 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -109,9 +109,8 @@
 
   void SetRegistration(WebServiceWorkerRegistrationObjectInfo info);
 
-  // Returns the ServiceWorker object described by the object info in current
-  // execution context. Creates a new object if needed, or else returns the
-  // existing one.
+  // Returns the ServiceWorker object described by the given info. Creates a new
+  // object if needed, or else returns the existing one.
   ServiceWorker* GetOrCreateServiceWorker(WebServiceWorkerObjectInfo);
 
   // EventTarget
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc b/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc
index 4aa81a3..c3cd461 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc
@@ -14,7 +14,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/service_worker/navigation_preload_state.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_container_client.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_container.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_error.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 
@@ -120,7 +120,7 @@
 ServiceWorkerRegistration* ServiceWorkerRegistration::Take(
     ScriptPromiseResolver* resolver,
     WebServiceWorkerRegistrationObjectInfo info) {
-  return ServiceWorkerContainerClient::From(
+  return ServiceWorkerContainer::From(
              To<Document>(resolver->GetExecutionContext()))
       ->GetOrCreateServiceWorkerRegistration(std::move(info));
 }
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_registration.h b/third_party/blink/renderer/modules/service_worker/service_worker_registration.h
index 893be3d..d250ebe 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_registration.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_registration.h
@@ -46,7 +46,7 @@
 
   // Eager finalization needed to promptly invalidate the corresponding entry of
   // the (registration id, WeakMember<ServiceWorkerRegistration>) map inside
-  // ServiceWorkerContainerClient.
+  // ServiceWorkerContainer.
   EAGERLY_FINALIZE();
 
   // Called in 2 scenarios:
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.cc b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
index ab074375..f2fb489 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.cc
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
@@ -230,7 +230,7 @@
       mojo_area_(area.get()),
       mojo_area_ptr_(std::move(area)),
       binding_(this),
-      areas_(new HeapHashMap<WeakMember<Source>, String>),
+      areas_(MakeGarbageCollected<HeapHashMap<WeakMember<Source>, String>>()),
       weak_factory_(this) {
   mojom::blink::StorageAreaObserverAssociatedPtrInfo ptr_info;
   binding_.Bind(mojo::MakeRequest(&ptr_info), std::move(ipc_runner));
@@ -248,7 +248,7 @@
       mojo_area_(area.get()),
       mojo_area_associated_ptr_(std::move(area)),
       binding_(this),
-      areas_(new HeapHashMap<WeakMember<Source>, String>),
+      areas_(MakeGarbageCollected<HeapHashMap<WeakMember<Source>, String>>()),
       weak_factory_(this) {
   mojom::blink::StorageAreaObserverAssociatedPtrInfo ptr_info;
   binding_.Bind(mojo::MakeRequest(&ptr_info), std::move(ipc_runner));
diff --git a/third_party/blink/renderer/modules/storage/storage_controller.cc b/third_party/blink/renderer/modules/storage/storage_controller.cc
index 226df21..2eacd57d 100644
--- a/third_party/blink/renderer/modules/storage/storage_controller.cc
+++ b/third_party/blink/renderer/modules/storage/storage_controller.cc
@@ -61,7 +61,8 @@
     mojom::blink::StoragePartitionServicePtr storage_partition_service,
     size_t total_cache_limit)
     : ipc_runner_(std::move(ipc_runner)),
-      namespaces_(new HeapHashMap<String, WeakMember<StorageNamespace>>()),
+      namespaces_(MakeGarbageCollected<
+                  HeapHashMap<String, WeakMember<StorageNamespace>>>()),
       total_cache_limit_(total_cache_limit),
       storage_partition_service_(std::move(storage_partition_service)) {}
 
diff --git a/third_party/blink/renderer/modules/webdatabase/database_manager.cc b/third_party/blink/renderer/modules/webdatabase/database_manager.cc
index 919a6e19..0f9e353 100644
--- a/third_party/blink/renderer/modules/webdatabase/database_manager.cc
+++ b/third_party/blink/renderer/modules/webdatabase/database_manager.cc
@@ -49,7 +49,8 @@
   return *g_database_manager;
 }
 
-DatabaseManager::DatabaseManager() : context_map_(new ContextMap) {}
+DatabaseManager::DatabaseManager()
+    : context_map_(MakeGarbageCollected<ContextMap>()) {}
 
 DatabaseManager::~DatabaseManager() = default;
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 3991053..9504d65 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -149,7 +149,8 @@
   Persistent<WebGLRenderingContextBaseMap>&
       forcibly_evicted_contexts_persistent = *forcibly_evicted_contexts;
   if (!forcibly_evicted_contexts_persistent) {
-    forcibly_evicted_contexts_persistent = new WebGLRenderingContextBaseMap();
+    forcibly_evicted_contexts_persistent =
+        MakeGarbageCollected<WebGLRenderingContextBaseMap>();
     forcibly_evicted_contexts_persistent.RegisterAsStaticReference();
   }
   return *forcibly_evicted_contexts_persistent;
diff --git a/third_party/blink/renderer/platform/audio/cpu/arm/vector_math_neon.h b/third_party/blink/renderer/platform/audio/cpu/arm/vector_math_neon.h
index 77a23bf1..8d22f8a0 100644
--- a/third_party/blink/renderer/platform/audio/cpu/arm/vector_math_neon.h
+++ b/third_party/blink/renderer/platform/audio/cpu/arm/vector_math_neon.h
@@ -13,10 +13,10 @@
 
 namespace blink {
 namespace vector_math {
-namespace NEON {
+namespace neon {
 
 // TODO: Consider optimizing this.
-using Scalar::Conv;
+using scalar::Conv;
 
 static ALWAYS_INLINE void Vadd(const float* source1p,
                                int source_stride1,
@@ -43,7 +43,7 @@
     n = tail_frames;
   }
 
-  Scalar::Vadd(source1p, source_stride1, source2p, source_stride2, dest_p,
+  scalar::Vadd(source1p, source_stride1, source2p, source_stride2, dest_p,
                dest_stride, n);
 }
 
@@ -71,7 +71,7 @@
     n = tail_frames;
   }
 
-  Scalar::Vclip(source_p, source_stride, low_threshold_p, high_threshold_p,
+  scalar::Vclip(source_p, source_stride, low_threshold_p, high_threshold_p,
                 dest_p, dest_stride, n);
 }
 
@@ -101,7 +101,7 @@
     n = tail_frames;
   }
 
-  Scalar::Vmaxmgv(source_p, source_stride, max_p, n);
+  scalar::Vmaxmgv(source_p, source_stride, max_p, n);
 }
 
 static ALWAYS_INLINE void Vmul(const float* source1p,
@@ -129,7 +129,7 @@
     n = tail_frames;
   }
 
-  Scalar::Vmul(source1p, source_stride1, source2p, source_stride2, dest_p,
+  scalar::Vmul(source1p, source_stride1, source2p, source_stride2, dest_p,
                dest_stride, n);
 }
 
@@ -159,7 +159,7 @@
     n = tail_frames;
   }
 
-  Scalar::Vsma(source_p, source_stride, scale, dest_p, dest_stride, n);
+  scalar::Vsma(source_p, source_stride, scale, dest_p, dest_stride, n);
 }
 
 static ALWAYS_INLINE void Vsmul(const float* source_p,
@@ -185,7 +185,7 @@
     n = tail_frames;
   }
 
-  Scalar::Vsmul(source_p, source_stride, scale, dest_p, dest_stride, n);
+  scalar::Vsmul(source_p, source_stride, scale, dest_p, dest_stride, n);
 }
 
 static ALWAYS_INLINE void Vsvesq(const float* source_p,
@@ -214,7 +214,7 @@
     n = tail_frames;
   }
 
-  Scalar::Vsvesq(source_p, source_stride, sum_p, n);
+  scalar::Vsvesq(source_p, source_stride, sum_p, n);
 }
 
 static ALWAYS_INLINE void Zvmul(const float* real1p,
@@ -242,11 +242,11 @@
     i += 4;
   }
 
-  Scalar::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
+  scalar::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
                 imag_dest_p + i, frames_to_process - i);
 }
 
-}  // namespace NEON
+}  // namespace neon
 }  // namespace vector_math
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/audio/cpu/mips/vector_math_msa.h b/third_party/blink/renderer/platform/audio/cpu/mips/vector_math_msa.h
index 0a13b67b..be8ed49e 100644
--- a/third_party/blink/renderer/platform/audio/cpu/mips/vector_math_msa.h
+++ b/third_party/blink/renderer/platform/audio/cpu/mips/vector_math_msa.h
@@ -12,12 +12,12 @@
 
 namespace blink {
 namespace vector_math {
-namespace MSA {
+namespace msa {
 
 // TODO: Consider optimizing these.
-using Scalar::Conv;
-using Scalar::Vsvesq;
-using Scalar::Zvmul;
+using scalar::Conv;
+using scalar::Vsvesq;
+using scalar::Zvmul;
 
 static ALWAYS_INLINE void Vadd(const float* source1p,
                                int source_stride1,
@@ -48,7 +48,7 @@
     }
   }
 
-  Scalar::Vadd(source1p, source_stride1, source2p, source_stride2, dest_p,
+  scalar::Vadd(source1p, source_stride1, source2p, source_stride2, dest_p,
                dest_stride, n);
 }
 
@@ -83,7 +83,7 @@
     }
   }
 
-  Scalar::Vclip(source_p, source_stride, low_threshold_p, high_threshold_p,
+  scalar::Vclip(source_p, source_stride, low_threshold_p, high_threshold_p,
                 dest_p, dest_stride, n);
 }
 
@@ -115,7 +115,7 @@
     *max_p = std::max(*max_p, vMax[3]);
   }
 
-  Scalar::Vmaxmgv(source_p, source_stride, max_p, n);
+  scalar::Vmaxmgv(source_p, source_stride, max_p, n);
 }
 
 static ALWAYS_INLINE void Vmul(const float* source1p,
@@ -147,7 +147,7 @@
     }
   }
 
-  Scalar::Vmul(source1p, source_stride1, source2p, source_stride2, dest_p,
+  scalar::Vmul(source1p, source_stride1, source2p, source_stride2, dest_p,
                dest_stride, n);
 }
 
@@ -180,7 +180,7 @@
     }
   }
 
-  Scalar::Vsma(source_p, source_stride, scale, dest_p, dest_stride, n);
+  scalar::Vsma(source_p, source_stride, scale, dest_p, dest_stride, n);
 }
 
 static ALWAYS_INLINE void Vsmul(const float* source_p,
@@ -209,10 +209,10 @@
     }
   }
 
-  Scalar::Vsmul(source_p, source_stride, scale, dest_p, dest_stride, n);
+  scalar::Vsmul(source_p, source_stride, scale, dest_p, dest_stride, n);
 }
 
-}  // namespace MSA
+}  // namespace msa
 }  // namespace vector_math
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_avx.cc b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_avx.cc
index 328f407..d613ff6a 100644
--- a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_avx.cc
+++ b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_avx.cc
@@ -12,16 +12,16 @@
 
 namespace blink {
 namespace vector_math {
-namespace AVX {
+namespace avx {
 
 using MType = __m256;
 
-}  // namespace AVX
+}  // namespace avx
 }  // namespace vector_math
 }  // namespace blink
 
 #define MM_PS(name) _mm256_##name##_ps
-#define VECTOR_MATH_SIMD_NAMESPACE_NAME AVX
+#define VECTOR_MATH_SIMD_NAMESPACE_NAME avx
 
 #include "third_party/blink/renderer/platform/audio/cpu/x86/vector_math_impl.h"
 
diff --git a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_avx.h b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_avx.h
index 61ee64d3..d10022e 100644
--- a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_avx.h
+++ b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_avx.h
@@ -11,7 +11,7 @@
 
 namespace blink {
 namespace vector_math {
-namespace AVX {
+namespace avx {
 
 constexpr size_t kBitsPerRegister = 256u;
 constexpr size_t kPackedFloatsPerRegister = kBitsPerRegister / 32u;
@@ -83,7 +83,7 @@
            float* imag_dest_p,
            size_t frames_to_process);
 
-}  // namespace AVX
+}  // namespace avx
 }  // namespace vector_math
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_impl.h b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_impl.h
index c193604f..b7dc97e 100644
--- a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_impl.h
+++ b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_impl.h
@@ -22,9 +22,9 @@
 namespace VECTOR_MATH_SIMD_NAMESPACE_NAME {
 
 // This stride is chosen so that the same prepared filter created by
-// AVX::PrepareFilterForConv can be used by both AVX::Conv and SSE::Conv.
-// A prepared filter created by SSE::PrepareFilterForConv can only be used
-// by SSE::Conv.
+// AVX::PrepareFilterForConv can be used by both AVX::Conv and sse::Conv.
+// A prepared filter created by sse::PrepareFilterForConv can only be used
+// by sse::Conv.
 constexpr size_t kReversedFilterStride = 8u / kPackedFloatsPerRegister;
 
 bool IsAligned(const float* p) {
diff --git a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_sse.cc b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_sse.cc
index 3c08782c..582f8fa 100644
--- a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_sse.cc
+++ b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_sse.cc
@@ -12,16 +12,16 @@
 
 namespace blink {
 namespace vector_math {
-namespace SSE {
+namespace sse {
 
 using MType = __m128;
 
-}  // namespace SSE
+}  // namespace sse
 }  // namespace vector_math
 }  // namespace blink
 
 #define MM_PS(name) _mm_##name##_ps
-#define VECTOR_MATH_SIMD_NAMESPACE_NAME SSE
+#define VECTOR_MATH_SIMD_NAMESPACE_NAME sse
 
 #include "third_party/blink/renderer/platform/audio/cpu/x86/vector_math_impl.h"
 
diff --git a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_sse.h b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_sse.h
index c026281..bcc8c8b 100644
--- a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_sse.h
+++ b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_sse.h
@@ -11,7 +11,7 @@
 
 namespace blink {
 namespace vector_math {
-namespace SSE {
+namespace sse {
 
 constexpr size_t kBitsPerRegister = 128u;
 constexpr size_t kPackedFloatsPerRegister = kBitsPerRegister / 32u;
@@ -83,7 +83,7 @@
            float* imag_dest_p,
            size_t frames_to_process);
 
-}  // namespace SSE
+}  // namespace sse
 }  // namespace vector_math
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_x86.h b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_x86.h
index a09fa93..c7c6ca3 100644
--- a/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_x86.h
+++ b/third_party/blink/renderer/platform/audio/cpu/x86/vector_math_x86.h
@@ -13,7 +13,7 @@
 
 namespace blink {
 namespace vector_math {
-namespace X86 {
+namespace x86 {
 
 struct FrameCounts {
   size_t scalar_for_alignment;
@@ -29,7 +29,7 @@
 }
 
 static size_t GetAVXAlignmentOffsetInNumberOfFloats(const float* source_p) {
-  constexpr size_t kBytesPerRegister = AVX::kBitsPerRegister / 8u;
+  constexpr size_t kBytesPerRegister = avx::kBitsPerRegister / 8u;
   constexpr size_t kAlignmentOffsetMask = kBytesPerRegister - 1u;
   size_t offset = reinterpret_cast<size_t>(source_p) & kAlignmentOffsetMask;
   DCHECK_EQ(0u, offset % sizeof(*source_p));
@@ -46,43 +46,43 @@
   // If the first frame is not AVX aligned, the first several frames (at most
   // seven) must be processed separately for proper alignment.
   const size_t total_for_alignment =
-      (AVX::kPackedFloatsPerRegister - avx_alignment_offset) &
-      ~AVX::kFramesToProcessMask;
+      (avx::kPackedFloatsPerRegister - avx_alignment_offset) &
+      ~avx::kFramesToProcessMask;
   const size_t scalar_for_alignment =
-      total_for_alignment & ~SSE::kFramesToProcessMask;
+      total_for_alignment & ~sse::kFramesToProcessMask;
   const size_t sse_for_alignment =
-      total_for_alignment & SSE::kFramesToProcessMask;
+      total_for_alignment & sse::kFramesToProcessMask;
 
   // Check which CPU features can be used based on the number of frames to
   // process and based on CPU support.
   const bool use_at_least_avx =
       CPUSupportsAVX() &&
       frames_to_process >= scalar_for_alignment + sse_for_alignment +
-                               AVX::kPackedFloatsPerRegister;
+                               avx::kPackedFloatsPerRegister;
   const bool use_at_least_sse =
       use_at_least_avx ||
-      frames_to_process >= scalar_for_alignment + SSE::kPackedFloatsPerRegister;
+      frames_to_process >= scalar_for_alignment + sse::kPackedFloatsPerRegister;
 
   if (use_at_least_sse) {
     counts.scalar_for_alignment = scalar_for_alignment;
     frames_to_process -= counts.scalar_for_alignment;
     // The remaining frames are SSE aligned.
-    DCHECK(SSE::IsAligned(source_p + counts.scalar_for_alignment));
+    DCHECK(sse::IsAligned(source_p + counts.scalar_for_alignment));
 
     if (use_at_least_avx) {
       counts.sse_for_alignment = sse_for_alignment;
       frames_to_process -= counts.sse_for_alignment;
       // The remaining frames are AVX aligned.
-      DCHECK(AVX::IsAligned(source_p + counts.scalar_for_alignment +
+      DCHECK(avx::IsAligned(source_p + counts.scalar_for_alignment +
                             counts.sse_for_alignment));
 
       // Process as many as possible of the remaining frames using AVX.
-      counts.avx = frames_to_process & AVX::kFramesToProcessMask;
+      counts.avx = frames_to_process & avx::kFramesToProcessMask;
       frames_to_process -= counts.avx;
     }
 
     // Process as many as possible of the remaining frames using SSE.
-    counts.sse = frames_to_process & SSE::kFramesToProcessMask;
+    counts.sse = frames_to_process & sse::kFramesToProcessMask;
     frames_to_process -= counts.sse;
   }
 
@@ -97,10 +97,10 @@
     size_t filter_size,
     AudioFloatArray* prepared_filter) {
   if (CPUSupportsAVX()) {
-    AVX::PrepareFilterForConv(filter_p, filter_stride, filter_size,
+    avx::PrepareFilterForConv(filter_p, filter_stride, filter_size,
                               prepared_filter);
   } else {
-    SSE::PrepareFilterForConv(filter_p, filter_stride, filter_size,
+    sse::PrepareFilterForConv(filter_p, filter_stride, filter_size,
                               prepared_filter);
   }
 }
@@ -117,24 +117,24 @@
   const float* prepared_filter_p =
       prepared_filter ? prepared_filter->Data() : nullptr;
   if (source_stride == 1 && dest_stride == 1 && prepared_filter_p) {
-    if (CPUSupportsAVX() && (filter_size & ~AVX::kFramesToProcessMask) == 0u) {
+    if (CPUSupportsAVX() && (filter_size & ~avx::kFramesToProcessMask) == 0u) {
       // |frames_to_process| is always a multiply of render quantum and
       // therefore the frames can always be processed using AVX.
-      CHECK_EQ(frames_to_process & ~AVX::kFramesToProcessMask, 0u);
-      AVX::Conv(source_p, prepared_filter_p, dest_p, frames_to_process,
+      CHECK_EQ(frames_to_process & ~avx::kFramesToProcessMask, 0u);
+      avx::Conv(source_p, prepared_filter_p, dest_p, frames_to_process,
                 filter_size);
       return;
     }
-    if ((filter_size & ~SSE::kFramesToProcessMask) == 0u) {
+    if ((filter_size & ~sse::kFramesToProcessMask) == 0u) {
       // |frames_to_process| is always a multiply of render quantum and
       // therefore the frames can always be processed using SSE.
-      CHECK_EQ(frames_to_process & ~SSE::kFramesToProcessMask, 0u);
-      SSE::Conv(source_p, prepared_filter_p, dest_p, frames_to_process,
+      CHECK_EQ(frames_to_process & ~sse::kFramesToProcessMask, 0u);
+      sse::Conv(source_p, prepared_filter_p, dest_p, frames_to_process,
                 filter_size);
       return;
     }
   }
-  Scalar::Conv(source_p, source_stride, filter_p, filter_stride, dest_p,
+  scalar::Conv(source_p, source_stride, filter_p, filter_stride, dest_p,
                dest_stride, frames_to_process, filter_size, nullptr);
 }
 
@@ -149,27 +149,27 @@
     const FrameCounts frame_counts =
         SplitFramesToProcess(source1p, frames_to_process);
 
-    Scalar::Vadd(source1p, 1, source2p, 1, dest_p, 1,
+    scalar::Vadd(source1p, 1, source2p, 1, dest_p, 1,
                  frame_counts.scalar_for_alignment);
     size_t i = frame_counts.scalar_for_alignment;
     if (frame_counts.sse_for_alignment > 0u) {
-      SSE::Vadd(source1p + i, source2p + i, dest_p + i,
+      sse::Vadd(source1p + i, source2p + i, dest_p + i,
                 frame_counts.sse_for_alignment);
       i += frame_counts.sse_for_alignment;
     }
     if (frame_counts.avx > 0u) {
-      AVX::Vadd(source1p + i, source2p + i, dest_p + i, frame_counts.avx);
+      avx::Vadd(source1p + i, source2p + i, dest_p + i, frame_counts.avx);
       i += frame_counts.avx;
     }
     if (frame_counts.sse > 0u) {
-      SSE::Vadd(source1p + i, source2p + i, dest_p + i, frame_counts.sse);
+      sse::Vadd(source1p + i, source2p + i, dest_p + i, frame_counts.sse);
       i += frame_counts.sse;
     }
-    Scalar::Vadd(source1p + i, 1, source2p + i, 1, dest_p + i, 1,
+    scalar::Vadd(source1p + i, 1, source2p + i, 1, dest_p + i, 1,
                  frame_counts.scalar);
     DCHECK_EQ(frames_to_process, i + frame_counts.scalar);
   } else {
-    Scalar::Vadd(source1p, source_stride1, source2p, source_stride2, dest_p,
+    scalar::Vadd(source1p, source_stride1, source2p, source_stride2, dest_p,
                  dest_stride, frames_to_process);
   }
 }
@@ -185,29 +185,29 @@
     const FrameCounts frame_counts =
         SplitFramesToProcess(source_p, frames_to_process);
 
-    Scalar::Vclip(source_p, 1, low_threshold_p, high_threshold_p, dest_p, 1,
+    scalar::Vclip(source_p, 1, low_threshold_p, high_threshold_p, dest_p, 1,
                   frame_counts.scalar_for_alignment);
     size_t i = frame_counts.scalar_for_alignment;
     if (frame_counts.sse_for_alignment > 0u) {
-      SSE::Vclip(source_p + i, low_threshold_p, high_threshold_p, dest_p + i,
+      sse::Vclip(source_p + i, low_threshold_p, high_threshold_p, dest_p + i,
                  frame_counts.sse_for_alignment);
       i += frame_counts.sse_for_alignment;
     }
     if (frame_counts.avx > 0u) {
-      AVX::Vclip(source_p + i, low_threshold_p, high_threshold_p, dest_p + i,
+      avx::Vclip(source_p + i, low_threshold_p, high_threshold_p, dest_p + i,
                  frame_counts.avx);
       i += frame_counts.avx;
     }
     if (frame_counts.sse > 0u) {
-      SSE::Vclip(source_p + i, low_threshold_p, high_threshold_p, dest_p + i,
+      sse::Vclip(source_p + i, low_threshold_p, high_threshold_p, dest_p + i,
                  frame_counts.sse);
       i += frame_counts.sse;
     }
-    Scalar::Vclip(source_p + i, 1, low_threshold_p, high_threshold_p,
+    scalar::Vclip(source_p + i, 1, low_threshold_p, high_threshold_p,
                   dest_p + i, 1, frame_counts.scalar);
     DCHECK_EQ(frames_to_process, i + frame_counts.scalar);
   } else {
-    Scalar::Vclip(source_p, source_stride, low_threshold_p, high_threshold_p,
+    scalar::Vclip(source_p, source_stride, low_threshold_p, high_threshold_p,
                   dest_p, dest_stride, frames_to_process);
   }
 }
@@ -220,24 +220,24 @@
     const FrameCounts frame_counts =
         SplitFramesToProcess(source_p, frames_to_process);
 
-    Scalar::Vmaxmgv(source_p, 1, max_p, frame_counts.scalar_for_alignment);
+    scalar::Vmaxmgv(source_p, 1, max_p, frame_counts.scalar_for_alignment);
     size_t i = frame_counts.scalar_for_alignment;
     if (frame_counts.sse_for_alignment > 0u) {
-      SSE::Vmaxmgv(source_p + i, max_p, frame_counts.sse_for_alignment);
+      sse::Vmaxmgv(source_p + i, max_p, frame_counts.sse_for_alignment);
       i += frame_counts.sse_for_alignment;
     }
     if (frame_counts.avx > 0u) {
-      AVX::Vmaxmgv(source_p + i, max_p, frame_counts.avx);
+      avx::Vmaxmgv(source_p + i, max_p, frame_counts.avx);
       i += frame_counts.avx;
     }
     if (frame_counts.sse > 0u) {
-      SSE::Vmaxmgv(source_p + i, max_p, frame_counts.sse);
+      sse::Vmaxmgv(source_p + i, max_p, frame_counts.sse);
       i += frame_counts.sse;
     }
-    Scalar::Vmaxmgv(source_p + i, 1, max_p, frame_counts.scalar);
+    scalar::Vmaxmgv(source_p + i, 1, max_p, frame_counts.scalar);
     DCHECK_EQ(frames_to_process, i + frame_counts.scalar);
   } else {
-    Scalar::Vmaxmgv(source_p, source_stride, max_p, frames_to_process);
+    scalar::Vmaxmgv(source_p, source_stride, max_p, frames_to_process);
   }
 }
 
@@ -252,27 +252,27 @@
     const FrameCounts frame_counts =
         SplitFramesToProcess(source1p, frames_to_process);
 
-    Scalar::Vmul(source1p, 1, source2p, 1, dest_p, 1,
+    scalar::Vmul(source1p, 1, source2p, 1, dest_p, 1,
                  frame_counts.scalar_for_alignment);
     size_t i = frame_counts.scalar_for_alignment;
     if (frame_counts.sse_for_alignment > 0u) {
-      SSE::Vmul(source1p + i, source2p + i, dest_p + i,
+      sse::Vmul(source1p + i, source2p + i, dest_p + i,
                 frame_counts.sse_for_alignment);
       i += frame_counts.sse_for_alignment;
     }
     if (frame_counts.avx > 0u) {
-      AVX::Vmul(source1p + i, source2p + i, dest_p + i, frame_counts.avx);
+      avx::Vmul(source1p + i, source2p + i, dest_p + i, frame_counts.avx);
       i += frame_counts.avx;
     }
     if (frame_counts.sse > 0u) {
-      SSE::Vmul(source1p + i, source2p + i, dest_p + i, frame_counts.sse);
+      sse::Vmul(source1p + i, source2p + i, dest_p + i, frame_counts.sse);
       i += frame_counts.sse;
     }
-    Scalar::Vmul(source1p + i, 1, source2p + i, 1, dest_p + i, 1,
+    scalar::Vmul(source1p + i, 1, source2p + i, 1, dest_p + i, 1,
                  frame_counts.scalar);
     DCHECK_EQ(frames_to_process, i + frame_counts.scalar);
   } else {
-    Scalar::Vmul(source1p, source_stride1, source2p, source_stride2, dest_p,
+    scalar::Vmul(source1p, source_stride1, source2p, source_stride2, dest_p,
                  dest_stride, frames_to_process);
   }
 }
@@ -287,26 +287,26 @@
     const FrameCounts frame_counts =
         SplitFramesToProcess(source_p, frames_to_process);
 
-    Scalar::Vsma(source_p, 1, scale, dest_p, 1,
+    scalar::Vsma(source_p, 1, scale, dest_p, 1,
                  frame_counts.scalar_for_alignment);
     size_t i = frame_counts.scalar_for_alignment;
     if (frame_counts.sse_for_alignment > 0u) {
-      SSE::Vsma(source_p + i, scale, dest_p + i,
+      sse::Vsma(source_p + i, scale, dest_p + i,
                 frame_counts.sse_for_alignment);
       i += frame_counts.sse_for_alignment;
     }
     if (frame_counts.avx > 0u) {
-      AVX::Vsma(source_p + i, scale, dest_p + i, frame_counts.avx);
+      avx::Vsma(source_p + i, scale, dest_p + i, frame_counts.avx);
       i += frame_counts.avx;
     }
     if (frame_counts.sse > 0u) {
-      SSE::Vsma(source_p + i, scale, dest_p + i, frame_counts.sse);
+      sse::Vsma(source_p + i, scale, dest_p + i, frame_counts.sse);
       i += frame_counts.sse;
     }
-    Scalar::Vsma(source_p + i, 1, scale, dest_p + i, 1, frame_counts.scalar);
+    scalar::Vsma(source_p + i, 1, scale, dest_p + i, 1, frame_counts.scalar);
     DCHECK_EQ(frames_to_process, i + frame_counts.scalar);
   } else {
-    Scalar::Vsma(source_p, source_stride, scale, dest_p, dest_stride,
+    scalar::Vsma(source_p, source_stride, scale, dest_p, dest_stride,
                  frames_to_process);
   }
 }
@@ -321,26 +321,26 @@
     const FrameCounts frame_counts =
         SplitFramesToProcess(source_p, frames_to_process);
 
-    Scalar::Vsmul(source_p, 1, scale, dest_p, 1,
+    scalar::Vsmul(source_p, 1, scale, dest_p, 1,
                   frame_counts.scalar_for_alignment);
     size_t i = frame_counts.scalar_for_alignment;
     if (frame_counts.sse_for_alignment > 0u) {
-      SSE::Vsmul(source_p + i, scale, dest_p + i,
+      sse::Vsmul(source_p + i, scale, dest_p + i,
                  frame_counts.sse_for_alignment);
       i += frame_counts.sse_for_alignment;
     }
     if (frame_counts.avx > 0u) {
-      AVX::Vsmul(source_p + i, scale, dest_p + i, frame_counts.avx);
+      avx::Vsmul(source_p + i, scale, dest_p + i, frame_counts.avx);
       i += frame_counts.avx;
     }
     if (frame_counts.sse > 0u) {
-      SSE::Vsmul(source_p + i, scale, dest_p + i, frame_counts.sse);
+      sse::Vsmul(source_p + i, scale, dest_p + i, frame_counts.sse);
       i += frame_counts.sse;
     }
-    Scalar::Vsmul(source_p + i, 1, scale, dest_p + i, 1, frame_counts.scalar);
+    scalar::Vsmul(source_p + i, 1, scale, dest_p + i, 1, frame_counts.scalar);
     DCHECK_EQ(frames_to_process, i + frame_counts.scalar);
   } else {
-    Scalar::Vsmul(source_p, source_stride, scale, dest_p, dest_stride,
+    scalar::Vsmul(source_p, source_stride, scale, dest_p, dest_stride,
                   frames_to_process);
   }
 }
@@ -353,24 +353,24 @@
     const FrameCounts frame_counts =
         SplitFramesToProcess(source_p, frames_to_process);
 
-    Scalar::Vsvesq(source_p, 1, sum_p, frame_counts.scalar_for_alignment);
+    scalar::Vsvesq(source_p, 1, sum_p, frame_counts.scalar_for_alignment);
     size_t i = frame_counts.scalar_for_alignment;
     if (frame_counts.sse_for_alignment > 0u) {
-      SSE::Vsvesq(source_p + i, sum_p, frame_counts.sse_for_alignment);
+      sse::Vsvesq(source_p + i, sum_p, frame_counts.sse_for_alignment);
       i += frame_counts.sse_for_alignment;
     }
     if (frame_counts.avx > 0u) {
-      AVX::Vsvesq(source_p + i, sum_p, frame_counts.avx);
+      avx::Vsvesq(source_p + i, sum_p, frame_counts.avx);
       i += frame_counts.avx;
     }
     if (frame_counts.sse > 0u) {
-      SSE::Vsvesq(source_p + i, sum_p, frame_counts.sse);
+      sse::Vsvesq(source_p + i, sum_p, frame_counts.sse);
       i += frame_counts.sse;
     }
-    Scalar::Vsvesq(source_p + i, 1, sum_p, frame_counts.scalar);
+    scalar::Vsvesq(source_p + i, 1, sum_p, frame_counts.scalar);
     DCHECK_EQ(frames_to_process, i + frame_counts.scalar);
   } else {
-    Scalar::Vsvesq(source_p, source_stride, sum_p, frames_to_process);
+    scalar::Vsvesq(source_p, source_stride, sum_p, frames_to_process);
   }
 }
 
@@ -383,30 +383,30 @@
                                 size_t frames_to_process) {
   FrameCounts frame_counts = SplitFramesToProcess(real1p, frames_to_process);
 
-  Scalar::Zvmul(real1p, imag1p, real2p, imag2p, real_dest_p, imag_dest_p,
+  scalar::Zvmul(real1p, imag1p, real2p, imag2p, real_dest_p, imag_dest_p,
                 frame_counts.scalar_for_alignment);
   size_t i = frame_counts.scalar_for_alignment;
   if (frame_counts.sse_for_alignment > 0u) {
-    SSE::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
+    sse::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
                imag_dest_p + i, frame_counts.sse_for_alignment);
     i += frame_counts.sse_for_alignment;
   }
   if (frame_counts.avx > 0u) {
-    AVX::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
+    avx::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
                imag_dest_p + i, frame_counts.avx);
     i += frame_counts.avx;
   }
   if (frame_counts.sse > 0u) {
-    SSE::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
+    sse::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
                imag_dest_p + i, frame_counts.sse);
     i += frame_counts.sse;
   }
-  Scalar::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
+  scalar::Zvmul(real1p + i, imag1p + i, real2p + i, imag2p + i, real_dest_p + i,
                 imag_dest_p + i, frame_counts.scalar);
   DCHECK_EQ(frames_to_process, i + frame_counts.scalar);
 }
 
-}  // namespace X86
+}  // namespace x86
 }  // namespace vector_math
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/audio/mac/vector_math_mac.h b/third_party/blink/renderer/platform/audio/mac/vector_math_mac.h
index ada79f7d..40242dcb 100644
--- a/third_party/blink/renderer/platform/audio/mac/vector_math_mac.h
+++ b/third_party/blink/renderer/platform/audio/mac/vector_math_mac.h
@@ -12,7 +12,7 @@
 
 namespace blink {
 namespace vector_math {
-namespace Mac {
+namespace mac {
 
 // On the Mac we use the highly optimized versions in Accelerate.framework
 // In 32-bit mode (__ppc__ or __i386__) <Accelerate/Accelerate.h> includes
@@ -143,7 +143,7 @@
 #endif
 }
 
-}  // namespace Mac
+}  // namespace mac
 }  // namespace vector_math
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/audio/vector_math.cc b/third_party/blink/renderer/platform/audio/vector_math.cc
index 83ae8b7..99019c1 100644
--- a/third_party/blink/renderer/platform/audio/vector_math.cc
+++ b/third_party/blink/renderer/platform/audio/vector_math.cc
@@ -49,15 +49,15 @@
 
 namespace {
 #if defined(OS_MACOSX)
-namespace Impl = Mac;
+namespace impl = mac;
 #elif WTF_CPU_ARM_NEON
-namespace Impl = NEON;
+namespace impl = neon;
 #elif HAVE_MIPS_MSA_INTRINSICS
-namespace Impl = MSA;
+namespace impl = msa;
 #elif defined(ARCH_CPU_X86_FAMILY)
-namespace Impl = X86;
+namespace impl = x86;
 #else
-namespace Impl = Scalar;
+namespace impl = scalar;
 #endif
 }  // namespace
 
@@ -71,7 +71,7 @@
   DCHECK_EQ(-1, filter_stride);
   DCHECK(prepared_filter);
 #if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_MACOSX)
-  X86::PrepareFilterForConv(filter_p, filter_stride, filter_size,
+  x86::PrepareFilterForConv(filter_p, filter_stride, filter_size,
                             prepared_filter);
 #endif
 }
@@ -91,7 +91,7 @@
   DCHECK_EQ(1, source_stride);
   DCHECK_EQ(-1, filter_stride);
   DCHECK_EQ(1, dest_stride);
-  Impl::Conv(source_p, source_stride, filter_p, filter_stride, dest_p,
+  impl::Conv(source_p, source_stride, filter_p, filter_stride, dest_p,
              dest_stride, frames_to_process, filter_size, prepared_filter);
 }
 
@@ -102,7 +102,7 @@
           float* dest_p,
           int dest_stride,
           size_t frames_to_process) {
-  Impl::Vadd(source1p, source_stride1, source2p, source_stride2, dest_p,
+  impl::Vadd(source1p, source_stride1, source2p, source_stride2, dest_p,
              dest_stride, frames_to_process);
 }
 
@@ -125,7 +125,7 @@
   DCHECK_LE(low_threshold, high_threshold);
 #endif
 
-  Impl::Vclip(source_p, source_stride, &low_threshold, &high_threshold, dest_p,
+  impl::Vclip(source_p, source_stride, &low_threshold, &high_threshold, dest_p,
               dest_stride, frames_to_process);
 }
 
@@ -135,7 +135,7 @@
              size_t frames_to_process) {
   float max = 0;
 
-  Impl::Vmaxmgv(source_p, source_stride, &max, frames_to_process);
+  impl::Vmaxmgv(source_p, source_stride, &max, frames_to_process);
 
   DCHECK(max_p);
   *max_p = max;
@@ -148,7 +148,7 @@
           float* dest_p,
           int dest_stride,
           size_t frames_to_process) {
-  Impl::Vmul(source1p, source_stride1, source2p, source_stride2, dest_p,
+  impl::Vmul(source1p, source_stride1, source2p, source_stride2, dest_p,
              dest_stride, frames_to_process);
 }
 
@@ -160,7 +160,7 @@
           size_t frames_to_process) {
   const float k = *scale;
 
-  Impl::Vsma(source_p, source_stride, &k, dest_p, dest_stride,
+  impl::Vsma(source_p, source_stride, &k, dest_p, dest_stride,
              frames_to_process);
 }
 
@@ -172,7 +172,7 @@
            size_t frames_to_process) {
   const float k = *scale;
 
-  Impl::Vsmul(source_p, source_stride, &k, dest_p, dest_stride,
+  impl::Vsmul(source_p, source_stride, &k, dest_p, dest_stride,
               frames_to_process);
 }
 
@@ -182,7 +182,7 @@
             size_t frames_to_process) {
   float sum = 0;
 
-  Impl::Vsvesq(source_p, source_stride, &sum, frames_to_process);
+  impl::Vsvesq(source_p, source_stride, &sum, frames_to_process);
 
   DCHECK(sum_p);
   *sum_p = sum;
@@ -195,7 +195,7 @@
            float* real_dest_p,
            float* imag_dest_p,
            size_t frames_to_process) {
-  Impl::Zvmul(real1p, imag1p, real2p, imag2p, real_dest_p, imag_dest_p,
+  impl::Zvmul(real1p, imag1p, real2p, imag2p, real_dest_p, imag_dest_p,
               frames_to_process);
 }
 
diff --git a/third_party/blink/renderer/platform/audio/vector_math_scalar.h b/third_party/blink/renderer/platform/audio/vector_math_scalar.h
index 5a806e2..bede75c 100644
--- a/third_party/blink/renderer/platform/audio/vector_math_scalar.h
+++ b/third_party/blink/renderer/platform/audio/vector_math_scalar.h
@@ -14,7 +14,7 @@
 
 namespace blink {
 namespace vector_math {
-namespace Scalar {
+namespace scalar {
 
 static ALWAYS_INLINE void Conv(const float* source_p,
                                int source_stride,
@@ -426,7 +426,7 @@
   }
 }
 
-}  // namespace Scalar
+}  // namespace scalar
 }  // namespace vector_math
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc b/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
index 70b71cff5..20c5c4df 100644
--- a/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
+++ b/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
@@ -52,7 +52,7 @@
       context_holder_(std::make_unique<gin::ContextHolder>(isolate_)),
       context_(isolate_, context),
       activity_logger_(nullptr),
-      data_map_(new DataMap()) {
+      data_map_(MakeGarbageCollected<DataMap>()) {
   context_holder_->SetContext(context);
   context_.Get().AnnotateStrongRetainer("blink::V8PerContextData::context_");
 
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.h b/third_party/blink/renderer/platform/heap/heap_allocator.h
index 2c3c76ef..f4ccffa3 100644
--- a/third_party/blink/renderer/platform/heap/heap_allocator.h
+++ b/third_party/blink/renderer/platform/heap/heap_allocator.h
@@ -441,10 +441,30 @@
                                    MappedTraitsArg,
                                    HeapAllocator> {
   IS_GARBAGE_COLLECTED_TYPE();
+  using Base =
+      HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>;
   static_assert(WTF::IsTraceable<KeyArg>::value ||
                     WTF::IsTraceable<MappedArg>::value,
                 "For hash maps without traceable elements, use HashMap<> "
                 "instead of HeapHashMap<>");
+
+ public:
+  static void* AllocateObject(size_t size, bool eagerly_sweep) {
+    return ThreadHeap::Allocate<
+        HeapHashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>>(
+        size, eagerly_sweep);
+  }
+
+  void* operator new(size_t size) = delete;
+  void operator delete(void* p) = delete;
+  void* operator new[](size_t size) = delete;
+  void operator delete[](void* p) = delete;
+  void* operator new(size_t size, NotNullTag null_tag, void* location) {
+    return Base::operator new(size, null_tag, location);
+  }
+  void* operator new(size_t size, void* location) {
+    return Base::operator new(size, location);
+  }
 };
 
 template <typename ValueArg,
diff --git a/third_party/blink/renderer/platform/heap/heap_compact_test.cc b/third_party/blink/renderer/platform/heap/heap_compact_test.cc
index e5e7e2ef..3f1044da 100644
--- a/third_party/blink/renderer/platform/heap/heap_compact_test.cc
+++ b/third_party/blink/renderer/platform/heap/heap_compact_test.cc
@@ -257,7 +257,7 @@
 TEST(HeapCompactTest, CompactHashMap) {
   ClearOutOldGarbage();
 
-  Persistent<IntMap> int_map = new IntMap();
+  Persistent<IntMap> int_map = MakeGarbageCollected<IntMap>();
   for (wtf_size_t i = 0; i < 100; ++i) {
     IntWrapper* val = IntWrapper::Create(i, HashTablesAreCompacted);
     int_map->insert(val, 100 - i);
@@ -315,7 +315,8 @@
 
   using IntVectorMap = HeapHashMap<int, IntVector>;
 
-  Persistent<IntVectorMap> int_vector_map = new IntVectorMap();
+  Persistent<IntVectorMap> int_vector_map =
+      MakeGarbageCollected<IntVectorMap>();
   for (wtf_size_t i = 0; i < 10; ++i) {
     IntVector vector;
     for (wtf_size_t j = 0; j < 10; ++j) {
@@ -509,10 +510,11 @@
   using Value = HeapVector<Member<IntWrapper>, 64>;
   using MapWithInlinedBacking = HeapHashMap<Key, Value>;
 
-  Persistent<MapWithInlinedBacking> map = new MapWithInlinedBacking;
+  Persistent<MapWithInlinedBacking> map =
+      MakeGarbageCollected<MapWithInlinedBacking>();
   {
     // Create a map that is reclaimed during compaction.
-    (new MapWithInlinedBacking)
+    (MakeGarbageCollected<MapWithInlinedBacking>())
         ->insert(IntWrapper::Create(1, HashTablesAreCompacted), Value());
 
     IntWrapper* wrapper = IntWrapper::Create(1, HashTablesAreCompacted);
diff --git a/third_party/blink/renderer/platform/heap/heap_test.cc b/third_party/blink/renderer/platform/heap/heap_test.cc
index 9d146ad..53a3328 100644
--- a/third_party/blink/renderer/platform/heap/heap_test.cc
+++ b/third_party/blink/renderer/platform/heap/heap_test.cc
@@ -622,7 +622,8 @@
     while (!Done()) {
       {
         Persistent<HeapHashMap<ThreadMarker, WeakMember<IntWrapper>>> weak_map =
-            new HeapHashMap<ThreadMarker, WeakMember<IntWrapper>>;
+            MakeGarbageCollected<
+                HeapHashMap<ThreadMarker, WeakMember<IntWrapper>>>();
 
         for (int i = 0; i < kNumberOfAllocations; i++) {
           weak_map->insert(static_cast<unsigned>(i), IntWrapper::Create(0));
@@ -1249,8 +1250,10 @@
 
  private:
   static ObserverMap& Observers() {
-    if (!observer_map_)
-      observer_map_ = new Persistent<ObserverMap>(new ObserverMap());
+    if (!observer_map_) {
+      observer_map_ =
+          new Persistent<ObserverMap>(MakeGarbageCollected<ObserverMap>());
+    }
     return **observer_map_;
   }
 
@@ -1898,6 +1901,7 @@
 
 TEST(HeapTest, SimpleFinalization) {
   {
+    SimpleFinalizedObject::destructor_calls_ = 0;
     Persistent<SimpleFinalizedObject> finalized =
         SimpleFinalizedObject::Create();
     EXPECT_EQ(0, SimpleFinalizedObject::destructor_calls_);
@@ -2069,6 +2073,8 @@
 
 TEST(HeapTest, Finalization) {
   {
+    HeapTestSubClass::destructor_calls_ = 0;
+    HeapTestSuperClass::destructor_calls_ = 0;
     HeapTestSubClass* t1 = HeapTestSubClass::Create();
     HeapTestSubClass* t2 = HeapTestSubClass::Create();
     HeapTestSuperClass* t3 = HeapTestSuperClass::Create();
@@ -2216,7 +2222,8 @@
                         HashTraits<Member<IntWrapper>>>
         HeapObjectIdentityMap;
 
-    Persistent<HeapObjectIdentityMap> map = new HeapObjectIdentityMap();
+    Persistent<HeapObjectIdentityMap> map =
+        MakeGarbageCollected<HeapObjectIdentityMap>();
 
     map->clear();
     size_t after_set_was_created = heap.ObjectPayloadSizeForTesting();
@@ -2388,7 +2395,7 @@
   wtf_size_t size = kMaxHeapObjectSize /
                     sizeof(HeapHashMap<int, Member<IntWrapper>>::ValueType);
   Persistent<HeapHashMap<int, Member<IntWrapper>>> map =
-      new HeapHashMap<int, Member<IntWrapper>>();
+      MakeGarbageCollected<HeapHashMap<int, Member<IntWrapper>>>();
   map->ReserveCapacityForSize(size);
   EXPECT_LE(size, map->Capacity());
 }
@@ -2613,11 +2620,15 @@
   typedef HeapDeque<PairWrappedUnwrapped, 0> DequeWU;
   typedef HeapDeque<PairUnwrappedWrapped, 0> DequeUW;
 
-  Persistent<MemberMember> member_member = new MemberMember();
-  Persistent<MemberMember> member_member2 = new MemberMember();
-  Persistent<MemberMember> member_member3 = new MemberMember();
-  Persistent<MemberPrimitive> member_primitive = new MemberPrimitive();
-  Persistent<PrimitiveMember> primitive_member = new PrimitiveMember();
+  Persistent<MemberMember> member_member = MakeGarbageCollected<MemberMember>();
+  Persistent<MemberMember> member_member2 =
+      MakeGarbageCollected<MemberMember>();
+  Persistent<MemberMember> member_member3 =
+      MakeGarbageCollected<MemberMember>();
+  Persistent<MemberPrimitive> member_primitive =
+      MakeGarbageCollected<MemberPrimitive>();
+  Persistent<PrimitiveMember> primitive_member =
+      MakeGarbageCollected<PrimitiveMember>();
   Persistent<MemberSet> set = new MemberSet();
   Persistent<MemberSet> set2 = new MemberSet();
   Persistent<MemberCountedSet> set3 = new MemberCountedSet();
@@ -3194,9 +3205,9 @@
   typedef HeapHashSet<WeakMember<IntWrapper>> WeakSet;
   typedef HeapHashCountedSet<WeakMember<IntWrapper>> WeakCountedSet;
 
-  Persistent<WeakStrong> weak_strong = new WeakStrong();
-  Persistent<StrongWeak> strong_weak = new StrongWeak();
-  Persistent<WeakWeak> weak_weak = new WeakWeak();
+  Persistent<WeakStrong> weak_strong = MakeGarbageCollected<WeakStrong>();
+  Persistent<StrongWeak> strong_weak = MakeGarbageCollected<StrongWeak>();
+  Persistent<WeakWeak> weak_weak = MakeGarbageCollected<WeakWeak>();
   Persistent<WeakSet> weak_set = new WeakSet();
   Persistent<WeakCountedSet> weak_counted_set = new WeakCountedSet();
 
@@ -3397,8 +3408,8 @@
                       HashTraits<WeakMember<IntWrapper>>>
       Map;
 
-  Persistent<Map> map(new Map());
-  Persistent<RefMap> ref_map(new RefMap());
+  Persistent<Map> map(MakeGarbageCollected<Map>());
+  Persistent<RefMap> ref_map(MakeGarbageCollected<RefMap>());
 
   Persistent<IntWrapper> luck(IntWrapper::Create(103));
 
@@ -3643,9 +3654,9 @@
 
       unsigned added = add_afterwards ? 100 : 0;
 
-      Persistent<WeakStrong> weak_strong = new WeakStrong();
-      Persistent<StrongWeak> strong_weak = new StrongWeak();
-      Persistent<WeakWeak> weak_weak = new WeakWeak();
+      Persistent<WeakStrong> weak_strong = MakeGarbageCollected<WeakStrong>();
+      Persistent<StrongWeak> strong_weak = MakeGarbageCollected<StrongWeak>();
+      Persistent<WeakWeak> weak_weak = MakeGarbageCollected<WeakWeak>();
 
       Persistent<WeakSet> weak_set = new WeakSet();
       Persistent<WeakOrderedSet> weak_ordered_set = new WeakOrderedSet();
@@ -4099,8 +4110,10 @@
   IntWrapper::destructor_calls_ = 0;
   typedef HeapVector<Member<IntWrapper>> IntVector;
   typedef HeapDeque<Member<IntWrapper>> IntDeque;
-  HeapHashMap<void*, IntVector>* map = new HeapHashMap<void*, IntVector>();
-  HeapHashMap<void*, IntDeque>* map2 = new HeapHashMap<void*, IntDeque>();
+  HeapHashMap<void*, IntVector>* map =
+      MakeGarbageCollected<HeapHashMap<void*, IntVector>>();
+  HeapHashMap<void*, IntDeque>* map2 =
+      MakeGarbageCollected<HeapHashMap<void*, IntDeque>>();
   static_assert(WTF::IsTraceable<IntVector>::value,
                 "Failed to recognize HeapVector as traceable");
   static_assert(WTF::IsTraceable<IntDeque>::value,
@@ -4165,7 +4178,8 @@
   void* key = &IntWrapper::destructor_calls_;
   IntWrapper::destructor_calls_ = 0;
   typedef HeapHashSet<Member<IntWrapper>> IntSet;
-  HeapHashMap<void*, IntSet>* map = new HeapHashMap<void*, IntSet>();
+  HeapHashMap<void*, IntSet>* map =
+      MakeGarbageCollected<HeapHashMap<void*, IntSet>>();
 
   map->insert(key, IntSet());
 
@@ -4888,11 +4902,11 @@
   ClearOutOldGarbage();
   OffHeapInt::destructor_calls_ = 0;
 
-  Persistent<Map> map1(new Map());
+  Persistent<Map> map1(MakeGarbageCollected<Map>());
   Persistent<IntWrapper> living_int(IntWrapper::Create(42));
   {
     Map map2;
-    Map* map3 = new Map();
+    Map* map3 = MakeGarbageCollected<Map>();
     map2.insert(
         PairWithWeakHandling(IntWrapper::Create(0), IntWrapper::Create(1)),
         OffHeapInt::Create(1001));
@@ -4970,12 +4984,12 @@
   ClearOutOldGarbage();
   OffHeapInt::destructor_calls_ = 0;
 
-  Persistent<Map> map1(new Map());
+  Persistent<Map> map1(MakeGarbageCollected<Map>());
   Persistent<IntWrapper> living_int(IntWrapper::Create(42));
 
   {
     Map map2;
-    Map* map3 = new Map();
+    Map* map3 = MakeGarbageCollected<Map>();
     map2.insert(
         OffHeapInt::Create(1001),
         PairWithWeakHandling(IntWrapper::Create(0), IntWrapper::Create(1)));
@@ -5057,7 +5071,7 @@
 // If it doesn't assert a concurrent modification to the map, then it's passing.
 TEST(HeapTest, RegressNullIsStrongified) {
   Persistent<HeapHashMap<int, WeakMember<IntWrapper>>> map =
-      new HeapHashMap<int, WeakMember<IntWrapper>>();
+      MakeGarbageCollected<HeapHashMap<int, WeakMember<IntWrapper>>>();
   AddElementsToWeakMap(map);
   HeapHashMap<int, WeakMember<IntWrapper>>::AddResult result =
       map->insert(800, nullptr);
@@ -5147,7 +5161,7 @@
   typedef HeapHashMap<Key, WeakSet, WTF::DefaultHash<Key>::Hash,
                       HashTraits<Key>, EmptyClearingHashSetTraits>
       Map;
-  Persistent<Map> map(new Map());
+  Persistent<Map> map(MakeGarbageCollected<Map>());
   map->insert(OffHeapInt::Create(1), WeakSet());
   {
     WeakSet& set = map->begin()->value;
@@ -5180,7 +5194,7 @@
 
   for (int keep_outer_alive = 0; keep_outer_alive <= 1; keep_outer_alive++) {
     for (int keep_inner_alive = 0; keep_inner_alive <= 1; keep_inner_alive++) {
-      Persistent<OuterMap> outer = new OuterMap();
+      Persistent<OuterMap> outer = MakeGarbageCollected<OuterMap>();
       Persistent<IntWrapper> one = IntWrapper::Create(1);
       Persistent<IntWrapper> two = IntWrapper::Create(2);
       outer->insert(one, InnerMap());
@@ -5291,13 +5305,13 @@
   typedef HeapHashMap<PairWithWeakHandling, WeakMember<IntWrapper>> PairWeakMap;
   typedef HeapHashSet<WeakMember<IntWrapper>> Set;
 
-  Persistent<WeakPairMap> weak_pair_map = new WeakPairMap();
-  Persistent<WeakPairMap> weak_pair_map2 = new WeakPairMap();
-  Persistent<WeakPairMap> weak_pair_map3 = new WeakPairMap();
-  Persistent<WeakPairMap> weak_pair_map4 = new WeakPairMap();
+  Persistent<WeakPairMap> weak_pair_map = MakeGarbageCollected<WeakPairMap>();
+  Persistent<WeakPairMap> weak_pair_map2 = MakeGarbageCollected<WeakPairMap>();
+  Persistent<WeakPairMap> weak_pair_map3 = MakeGarbageCollected<WeakPairMap>();
+  Persistent<WeakPairMap> weak_pair_map4 = MakeGarbageCollected<WeakPairMap>();
 
-  Persistent<PairWeakMap> pair_weak_map = new PairWeakMap();
-  Persistent<PairWeakMap> pair_weak_map2 = new PairWeakMap();
+  Persistent<PairWeakMap> pair_weak_map = MakeGarbageCollected<PairWeakMap>();
+  Persistent<PairWeakMap> pair_weak_map2 = MakeGarbageCollected<PairWeakMap>();
 
   Persistent<Set> set = new Set();
 
@@ -5382,7 +5396,7 @@
 
 TEST(HeapTest, IndirectStrongToWeak) {
   typedef HeapHashMap<WeakMember<IntWrapper>, Member<Link1>> Map;
-  Persistent<Map> map = new Map();
+  Persistent<Map> map = MakeGarbageCollected<Map>();
   Persistent<IntWrapper> dead_object =
       IntWrapper::Create(100);  // Named for "Drowning by Numbers" (1988).
   Persistent<IntWrapper> life_object = IntWrapper::Create(42);
@@ -5490,7 +5504,8 @@
     Persistent<IntWrapper> wrapper4 = IntWrapper::Create(32);
     Persistent<IntWrapper> wrapper5 = IntWrapper::Create(32);
     Persistent<IntWrapper> wrapper6 = IntWrapper::Create(32);
-    Persistent<WeakCollectionType> weak_collection = new WeakCollectionType;
+    Persistent<WeakCollectionType> weak_collection =
+        MakeGarbageCollected<WeakCollectionType>();
     weak_collection->insert(wrapper1, wrapper1);
     weak_collection->insert(wrapper2, wrapper2);
     weak_collection->insert(wrapper3, wrapper3);
@@ -5884,7 +5899,7 @@
 
 TEST(HeapTest, GCInHashMapOperations) {
   typedef HeapHashMap<AllocatesOnAssignment, AllocatesOnAssignment> Map;
-  Map* map = new Map();
+  Map* map = MakeGarbageCollected<Map>();
   IntWrapper* key = new IntWrapper(42);
   map->insert(key, AllocatesOnAssignment(103));
   map->erase(key);
diff --git a/third_party/blink/renderer/platform/loader/BUILD.gn b/third_party/blink/renderer/platform/loader/BUILD.gn
index bf3f926..4c1d9dc 100644
--- a/third_party/blink/renderer/platform/loader/BUILD.gn
+++ b/third_party/blink/renderer/platform/loader/BUILD.gn
@@ -120,6 +120,7 @@
     "fetch/raw_resource_test.cc",
     "fetch/resource_fetcher_test.cc",
     "fetch/resource_load_scheduler_test.cc",
+    "fetch/resource_loader_defer_loading_test.cc",
     "fetch/resource_loader_test.cc",
     "fetch/resource_request_test.cc",
     "fetch/resource_response_test.cc",
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc b/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
index 6d4b6d9..2fd59c6 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
@@ -124,8 +124,8 @@
 MemoryCache::ResourceMap* MemoryCache::EnsureResourceMap(
     const String& cache_identifier) {
   if (!resource_maps_.Contains(cache_identifier)) {
-    ResourceMapIndex::AddResult result =
-        resource_maps_.insert(cache_identifier, new ResourceMap);
+    ResourceMapIndex::AddResult result = resource_maps_.insert(
+        cache_identifier, MakeGarbageCollected<ResourceMap>());
     CHECK(result.is_new_entry);
   }
   return resource_maps_.at(cache_identifier);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc
new file mode 100644
index 0000000..66c097c
--- /dev/null
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader_defer_loading_test.cc
@@ -0,0 +1,275 @@
+// 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 "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
+#include "third_party/blink/public/platform/web_url_loader.h"
+#include "third_party/blink/public/platform/web_url_loader_factory.h"
+#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
+
+namespace blink {
+
+class ResourceLoaderDefersLoadingTest : public testing::Test {
+ public:
+  using ProcessCodeCacheRequestCallback =
+      base::RepeatingCallback<void(CodeCacheLoader::FetchCodeCacheCallback)>;
+  class TestingPlatformSupportWithMockCodeCacheLoader;
+  class TestCodeCacheLoader;
+  class TestWebURLLoaderFactory;
+  class TestWebURLLoader;
+
+  ResourceLoaderDefersLoadingTest();
+
+  void SetUp() override {
+    context_ =
+        MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
+  }
+
+  void SaveCodeCacheCallback(CodeCacheLoader::FetchCodeCacheCallback callback) {
+    // Store the callback to send back a response.
+    code_cache_response_callback_ = std::move(callback);
+  }
+
+  CodeCacheLoader::FetchCodeCacheCallback code_cache_response_callback_;
+  // Passed to TestWebURLLoader (via |platform_|) and updated when its
+  // SetDefersLoading method is called.
+  bool web_url_loader_defers_ = false;
+  Persistent<MockFetchContext> context_;
+  const KURL test_url_;
+
+  ScopedTestingPlatformSupport<
+      ResourceLoaderDefersLoadingTest::
+          TestingPlatformSupportWithMockCodeCacheLoader,
+      bool*>
+      platform_;
+};
+
+// A mock code cache loader that calls the processing function whenever it
+// receives fetch requests.
+class ResourceLoaderDefersLoadingTest::TestCodeCacheLoader
+    : public CodeCacheLoader {
+ public:
+  explicit TestCodeCacheLoader(ProcessCodeCacheRequestCallback callback)
+      : process_request_(callback) {}
+  ~TestCodeCacheLoader() override = default;
+
+  // CodeCacheLoader methods:
+  void FetchFromCodeCacheSynchronously(
+      const GURL& url,
+      base::Time* response_time_out,
+      std::vector<uint8_t>* data_out) override {}
+  void FetchFromCodeCache(
+      blink::mojom::CodeCacheType cache_type,
+      const GURL& url,
+      CodeCacheLoader::FetchCodeCacheCallback callback) override {
+    process_request_.Run(std::move(callback));
+  }
+
+ private:
+  ProcessCodeCacheRequestCallback process_request_;
+};
+
+// A mock WebURLLoader to know the status of defers flag.
+class ResourceLoaderDefersLoadingTest::TestWebURLLoader final
+    : public WebURLLoader {
+ public:
+  explicit TestWebURLLoader(bool* const defers_flag_ptr)
+      : defers_flag_ptr_(defers_flag_ptr) {}
+  ~TestWebURLLoader() override = default;
+
+  void LoadSynchronously(const WebURLRequest&,
+                         WebURLLoaderClient*,
+                         WebURLResponse&,
+                         base::Optional<WebURLError>&,
+                         WebData&,
+                         int64_t& encoded_data_length,
+                         int64_t& encoded_body_length,
+                         WebBlobInfo& downloaded_blob) override {
+    NOTREACHED();
+  }
+  void LoadAsynchronously(const WebURLRequest&, WebURLLoaderClient*) override {}
+
+  void Cancel() override {}
+  void SetDefersLoading(bool defers) override { *defers_flag_ptr_ = defers; }
+  void DidChangePriority(WebURLRequest::Priority, int) override {
+    NOTREACHED();
+  }
+
+ private:
+  // Points to |ResourceLoaderDefersLoadingTest::web_url_loader_defers_|.
+  bool* const defers_flag_ptr_;
+};
+
+// Mock WebURLLoaderFactory.
+class ResourceLoaderDefersLoadingTest::TestWebURLLoaderFactory final
+    : public WebURLLoaderFactory {
+ public:
+  explicit TestWebURLLoaderFactory(bool* const defers_flag)
+      : defers_flag_(defers_flag) {}
+
+  std::unique_ptr<WebURLLoader> CreateURLLoader(
+      const WebURLRequest& request,
+      std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>) override {
+    return std::make_unique<TestWebURLLoader>(defers_flag_);
+  }
+
+ private:
+  // Points to |ResourceLoaderDefersLoadingTest::web_url_loader_defers_|.
+  bool* const defers_flag_;
+};
+
+// Mock TestPlatform to create the specific WebURLLoaderFactory and
+// CodeCacheLoader required for the tests.
+class ResourceLoaderDefersLoadingTest::
+    TestingPlatformSupportWithMockCodeCacheLoader
+    : public TestingPlatformSupportWithMockScheduler {
+ public:
+  TestingPlatformSupportWithMockCodeCacheLoader(bool* const defers_flag)
+      : defers_flag_(defers_flag) {}
+
+  std::unique_ptr<CodeCacheLoader> CreateCodeCacheLoader() override {
+    return std::make_unique<TestCodeCacheLoader>(process_code_cache_request_);
+  }
+
+  std::unique_ptr<WebURLLoaderFactory> CreateDefaultURLLoaderFactory()
+      override {
+    return std::make_unique<TestWebURLLoaderFactory>(defers_flag_);
+  }
+
+  void SetCodeCacheProcessFunction(ProcessCodeCacheRequestCallback callback) {
+    process_code_cache_request_ = callback;
+  }
+
+ private:
+  ProcessCodeCacheRequestCallback process_code_cache_request_;
+  // Points to |ResourceLoaderDefersLoadingTest::web_url_loader_defers_|.
+  bool* const defers_flag_;
+};
+
+ResourceLoaderDefersLoadingTest::ResourceLoaderDefersLoadingTest()
+    : test_url_("http://example.com/"), platform_(&web_url_loader_defers_) {
+  // Saves the callback to control when the response is sent from
+  // the code cache loader.
+  platform_->SetCodeCacheProcessFunction(base::BindRepeating(
+      &ResourceLoaderDefersLoadingTest::SaveCodeCacheCallback,
+      base::Unretained(this)));
+}
+
+TEST_F(ResourceLoaderDefersLoadingTest, CodeCacheFetchCheckDefers) {
+  ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+
+  ResourceRequest request;
+  request.SetURL(test_url_);
+  request.SetRequestContext(mojom::RequestContextType::FRAME);
+  request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
+  FetchParameters fetch_parameters(request);
+
+  Resource* resource = RawResource::FetchMainResource(
+      fetch_parameters, fetcher, nullptr, SubstituteData());
+
+  // After code cache fetch it should have deferred WebURLLoader.
+  DCHECK(web_url_loader_defers_);
+  DCHECK(resource);
+  std::move(code_cache_response_callback_)
+      .Run(base::Time(), std::vector<uint8_t>());
+  // Once the response is received it should be reset.
+  DCHECK(!web_url_loader_defers_);
+}
+
+TEST_F(ResourceLoaderDefersLoadingTest, CodeCacheFetchSyncReturn) {
+  platform_->SetCodeCacheProcessFunction(
+      base::BindRepeating([](CodeCacheLoader::FetchCodeCacheCallback callback) {
+        std::move(callback).Run(base::Time(), std::vector<uint8_t>());
+      }));
+
+  ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+
+  ResourceRequest request;
+  request.SetURL(test_url_);
+  request.SetRequestContext(mojom::RequestContextType::FRAME);
+  request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
+  FetchParameters fetch_parameters(request);
+
+  Resource* resource = RawResource::FetchMainResource(
+      fetch_parameters, fetcher, nullptr, SubstituteData());
+  DCHECK(resource);
+  // The callback would be called so it should not be deferred.
+  DCHECK(!web_url_loader_defers_);
+}
+
+TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToFalse) {
+  ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+
+  ResourceRequest request;
+  request.SetURL(test_url_);
+  request.SetRequestContext(mojom::RequestContextType::FRAME);
+  request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
+  FetchParameters fetch_parameters(request);
+
+  Resource* resource = RawResource::FetchMainResource(
+      fetch_parameters, fetcher, nullptr, SubstituteData());
+  DCHECK(web_url_loader_defers_);
+
+  // Change Defers loading to false. This should not be sent to
+  // WebURLLoader since a code cache request is still pending.
+  ResourceLoader* loader = resource->Loader();
+  loader->SetDefersLoading(false);
+  DCHECK(web_url_loader_defers_);
+}
+
+TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToTrue) {
+  ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+
+  ResourceRequest request;
+  request.SetURL(test_url_);
+  request.SetRequestContext(mojom::RequestContextType::FRAME);
+  request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
+  FetchParameters fetch_parameters(request);
+
+  Resource* resource = RawResource::FetchMainResource(
+      fetch_parameters, fetcher, nullptr, SubstituteData());
+  DCHECK(web_url_loader_defers_);
+
+  ResourceLoader* loader = resource->Loader();
+  loader->SetDefersLoading(true);
+  DCHECK(web_url_loader_defers_);
+
+  std::move(code_cache_response_callback_)
+      .Run(base::Time(), std::vector<uint8_t>());
+  // Since it was requested to be deferred, it should be reset to the
+  // correct value.
+  DCHECK(web_url_loader_defers_);
+}
+
+TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersMultipleTimes) {
+  ResourceFetcher* fetcher = ResourceFetcher::Create(context_);
+
+  ResourceRequest request;
+  request.SetURL(test_url_);
+  request.SetRequestContext(mojom::RequestContextType::FRAME);
+  request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
+
+  FetchParameters fetch_parameters(request);
+  Resource* resource = RawResource::FetchMainResource(
+      fetch_parameters, fetcher, nullptr, SubstituteData());
+  DCHECK(web_url_loader_defers_);
+
+  ResourceLoader* loader = resource->Loader();
+  loader->SetDefersLoading(true);
+  DCHECK(web_url_loader_defers_);
+
+  loader->SetDefersLoading(false);
+  DCHECK(web_url_loader_defers_);
+
+  std::move(code_cache_response_callback_)
+      .Run(base::Time(), std::vector<uint8_t>());
+  DCHECK(!web_url_loader_defers_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 2b003eb2..b28886c7 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -326,10 +326,6 @@
       status: "experimental",
     },
     {
-      name: "CSSScrollSnapPoints",
-      status: "stable",
-    },
-    {
       name: "CSSSnapSize",
       status: "experimental",
     },
@@ -1257,6 +1253,9 @@
       name: "TrackLayoutPassesPerBlock",
     },
     {
+      name: "TransferableStreams",
+    },
+    {
       name: "TrustedDOMTypes",
       status: "experimental",
     },
diff --git a/third_party/cacheinvalidation/BUILD.gn b/third_party/cacheinvalidation/BUILD.gn
index fd4d77b..b5affe28 100644
--- a/third_party/cacheinvalidation/BUILD.gn
+++ b/third_party/cacheinvalidation/BUILD.gn
@@ -14,8 +14,6 @@
 static_library("cacheinvalidation") {
   sources = [
     "overrides/google/cacheinvalidation/deps/callback.h",
-    "overrides/google/cacheinvalidation/deps/gmock.h",
-    "overrides/google/cacheinvalidation/deps/googletest.h",
     "overrides/google/cacheinvalidation/deps/logging.h",
     "overrides/google/cacheinvalidation/deps/mutex.h",
     "overrides/google/cacheinvalidation/deps/random.cc",
@@ -92,6 +90,8 @@
 
 test("cacheinvalidation_unittests") {
   sources = [
+    "overrides/google/cacheinvalidation/deps/gmock.h",
+    "overrides/google/cacheinvalidation/deps/googletest.h",
     "src/google/cacheinvalidation/impl/invalidation-client-impl_test.cc",
     "src/google/cacheinvalidation/impl/protocol-handler_test.cc",
     "src/google/cacheinvalidation/impl/recurring-task_test.cc",
diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn
index b44bda66..4764ec1c 100644
--- a/third_party/zlib/BUILD.gn
+++ b/third_party/zlib/BUILD.gn
@@ -10,22 +10,30 @@
   include_dirs = [ "." ]
 }
 
+use_arm_neon_optimizations = false
+if (current_cpu == "arm" || current_cpu == "arm64") {
+  if (arm_use_neon) {
+    use_arm_neon_optimizations = true
+  }
+}
+
+use_x86_x64_optimizations =
+    (current_cpu == "x86" || current_cpu == "x64") && !is_ios
+
 config("zlib_adler32_simd_config") {
-  if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
+  if (use_x86_x64_optimizations) {
     defines = [ "ADLER32_SIMD_SSSE3" ]
   }
 
-  if (current_cpu == "arm" || current_cpu == "arm64") {
-    if (arm_use_neon) {
-      defines = [ "ADLER32_SIMD_NEON" ]
-    }
+  if (use_arm_neon_optimizations) {
+    defines = [ "ADLER32_SIMD_NEON" ]
   }
 }
 
 source_set("zlib_adler32_simd") {
   visibility = [ ":*" ]
 
-  if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
+  if (use_x86_x64_optimizations) {
     sources = [
       "adler32_simd.c",
       "adler32_simd.h",
@@ -36,26 +44,23 @@
     }
   }
 
-  if (current_cpu == "arm" || current_cpu == "arm64") {
-    if (arm_use_neon) {
-      sources = [
-        "adler32_simd.c",
-        "adler32_simd.h",
-      ]
-
-      if (!is_debug) {
-        # Use optimize_speed (-O3) to output the _smallest_ code.
-        configs -= [ "//build/config/compiler:default_optimization" ]
-        configs += [ "//build/config/compiler:optimize_speed" ]
-      }
+  if (use_arm_neon_optimizations) {
+    sources = [
+      "adler32_simd.c",
+      "adler32_simd.h",
+    ]
+    if (!is_debug) {
+      # Use optimize_speed (-O3) to output the _smallest_ code.
+      configs -= [ "//build/config/compiler:default_optimization" ]
+      configs += [ "//build/config/compiler:optimize_speed" ]
     }
   }
 
   public_configs = [ ":zlib_adler32_simd_config" ]
 }
 
-config("zlib_arm_crc32_config") {
-  if (current_cpu == "arm" || current_cpu == "arm64") {
+if (use_arm_neon_optimizations) {
+  config("zlib_arm_crc32_config") {
     # Restrictions:
     #  - Disabled for iPhones, as described in DDI0487C_a_armv8_arm:
     #     "All implementations of the ARMv8.1 architecture are required to
@@ -72,9 +77,7 @@
       }
     }
   }
-}
 
-if (current_cpu == "arm" || current_cpu == "arm64") {
   source_set("zlib_arm_crc32") {
     visibility = [ ":*" ]
 
@@ -108,7 +111,7 @@
 }
 
 config("zlib_inflate_chunk_simd_config") {
-  if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
+  if (use_x86_x64_optimizations) {
     defines = [ "INFLATE_CHUNK_SIMD_SSE2" ]
 
     if (current_cpu == "x64") {
@@ -116,17 +119,15 @@
     }
   }
 
-  if (current_cpu == "arm" || current_cpu == "arm64") {
-    if (arm_use_neon) {
-      defines = [ "INFLATE_CHUNK_SIMD_NEON" ]
-    }
+  if (use_arm_neon_optimizations) {
+    defines = [ "INFLATE_CHUNK_SIMD_NEON" ]
   }
 }
 
 source_set("zlib_inflate_chunk_simd") {
   visibility = [ ":*" ]
 
-  if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
+  if (use_x86_x64_optimizations || use_arm_neon_optimizations) {
     include_dirs = [ "." ]
 
     sources = [
@@ -135,26 +136,13 @@
       "contrib/optimizations/inffast_chunk.h",
       "contrib/optimizations/inflate.c",
     ]
-  }
 
-  if (current_cpu == "arm" || current_cpu == "arm64") {
-    if (arm_use_neon) {
-      include_dirs = [ "." ]
-
-      sources = [
-        "contrib/optimizations/chunkcopy.h",
-        "contrib/optimizations/inffast_chunk.c",
-        "contrib/optimizations/inffast_chunk.h",
-        "contrib/optimizations/inflate.c",
-      ]
-
-      if (!is_debug) {
-        # Here we trade better performance on newer/bigger ARMv8 cores
-        # for less perf on ARMv7. For details, check:
-        # https://bugs.chromium.org/p/chromium/issues/detail?id=772870#c40
-        configs -= [ "//build/config/compiler:default_optimization" ]
-        configs += [ "//build/config/compiler:optimize_speed" ]
-      }
+    if (use_arm_neon_optimizations && !is_debug) {
+      # Here we trade better performance on newer/bigger ARMv8 cores
+      # for less perf on ARMv7. For details, check:
+      # https://bugs.chromium.org/p/chromium/issues/detail?id=772870#c40
+      configs -= [ "//build/config/compiler:default_optimization" ]
+      configs += [ "//build/config/compiler:optimize_speed" ]
     }
   }
 
@@ -165,7 +153,7 @@
 }
 
 config("zlib_crc32_simd_config") {
-  if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
+  if (use_x86_x64_optimizations) {
     defines = [ "CRC32_SIMD_SSE42_PCLMUL" ]
   }
 }
@@ -173,7 +161,7 @@
 source_set("zlib_crc32_simd") {
   visibility = [ ":*" ]
 
-  if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
+  if (use_x86_x64_optimizations) {
     sources = [
       "crc32_simd.c",
       "crc32_simd.h",
@@ -193,7 +181,7 @@
 static_library("zlib_x86_simd") {
   visibility = [ ":*" ]
 
-  if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
+  if (use_x86_x64_optimizations) {
     sources = [
       "crc_folding.c",
       "fill_window_sse.c",
@@ -216,7 +204,7 @@
 }
 
 config("zlib_warnings") {
-  if (is_clang && !is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
+  if (is_clang && use_x86_x64_optimizations) {
     cflags = [ "-Wno-incompatible-pointer-types" ]
   }
 }
@@ -243,7 +231,6 @@
     "inffast.c",
     "inffast.h",
     "inffixed.h",
-    "inflate.c",
     "inflate.h",
     "inftrees.c",
     "inftrees.h",
@@ -261,26 +248,21 @@
   defines = []
   deps = []
 
-  if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
-    deps += [ ":zlib_crc32_simd" ]
+  if (use_x86_x64_optimizations || use_arm_neon_optimizations) {
+    deps += [
+      ":zlib_adler32_simd",
+      ":zlib_inflate_chunk_simd",
+    ]
 
-    deps += [ ":zlib_adler32_simd" ]
-    sources += [ "x86.c" ]
-
-    deps += [ ":zlib_inflate_chunk_simd" ]
-    sources -= [ "inflate.c" ]
-  }
-
-  if (current_cpu == "arm" || current_cpu == "arm64") {
-    if (arm_use_neon) {
-      deps += [ ":zlib_adler32_simd" ]
-
-      deps += [ ":zlib_arm_crc32" ]
-
-      deps += [ ":zlib_inflate_chunk_simd" ]
-      sources -= [ "inflate.c" ]
+    if (use_x86_x64_optimizations) {
+      sources += [ "x86.c" ]
+      deps += [ ":zlib_crc32_simd" ]
+    } else if (use_arm_neon_optimizations) {
       sources += [ "contrib/optimizations/slide_hash_neon.h" ]
+      deps += [ ":zlib_arm_crc32" ]
     }
+  } else {
+    sources += [ "inflate.c" ]
   }
 
   configs -= [ "//build/config/compiler:chromium_code" ]
@@ -294,6 +276,7 @@
   public_configs = [ ":zlib_config" ]
 
   deps += [ ":zlib_x86_simd" ]
+  allow_circular_includes_from = deps
 }
 
 config("minizip_warnings") {
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index c4b697d..12878da 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -230,8 +230,7 @@
       'linux-blink-heap-incremental-marking': 'debug_bot_enable_blink_heap_incremental_marking',
       'linux-blink-heap-verification': 'release_bot_enable_blink_heap_verification_dcheck_always_on',
       'linux-chromium-tests-staging-builder': 'release_bot',
-      'linux-code-coverage-builder': 'clang_code_coverage',
-      'linux-code-coverage-tester': 'clang_code_coverage',
+      'linux-code-coverage': 'clang_code_coverage',
       'Mac deterministic': 'release_bot_mac_strip',
       'Mac deterministic (dbg)': 'debug_bot',
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9813542..ee6092ca 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -37452,6 +37452,9 @@
 </enum>
 
 <enum name="OmniboxEnteredKeywordMode">
+  <obsolete>
+    Deprecated 10/2018 and replaced with OmniboxEnteredKeywordMode2.
+  </obsolete>
   <int value="0" label="via tab"/>
   <int value="1" label="via space at end"/>
   <int value="2" label="via space in middle"/>
@@ -37461,6 +37464,18 @@
   <int value="6" label="tap gesture on hint view"/>
 </enum>
 
+<enum name="OmniboxEnteredKeywordMode2">
+  <int value="0" label="invalid"/>
+  <int value="1" label="via tab"/>
+  <int value="2" label="via space at end"/>
+  <int value="3" label="via space in middle"/>
+  <int value="4" label="keyboard shortcut"/>
+  <int value="5" label="question mark"/>
+  <int value="6" label="mouse click on hint view"/>
+  <int value="7" label="tap gesture on hint view"/>
+  <int value="8" label="select suggestion"/>
+</enum>
+
 <enum name="OmniboxFocusReason">
   <int value="0" label="Omnibox tapped."/>
   <int value="1" label="Omnibox long-pressed."/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index aac4d21..11e2dfc 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -69815,6 +69815,10 @@
 </histogram>
 
 <histogram name="Omnibox.EnteredKeywordMode" enum="OmniboxEnteredKeywordMode">
+  <obsolete>
+    Deprecated 10/2018 and replaced with
+    &quot;Omnibox.EnteredKeywordMode2&quot;.
+  </obsolete>
   <owner>mpearson@chromium.org</owner>
   <summary>
     The number of times users enter keyword hint mode &quot;Search ___
@@ -69822,6 +69826,17 @@
   </summary>
 </histogram>
 
+<histogram name="Omnibox.EnteredKeywordMode2" enum="OmniboxEnteredKeywordMode2">
+  <owner>mpearson@chromium.org</owner>
+  <summary>
+    The new enumeration of how many times users enter keyword hint mode
+    &quot;Search ___ for:&quot; and how. Note that we don't recognize the
+    changing of the keyword itself as entering keyword mode, if the user never
+    left keyword mode e.g. if the user was arrowing around the suggestions, so
+    we'll preserve the original keyword mode entry method in this case.
+  </summary>
+</histogram>
+
 <histogram name="Omnibox.FocusToEditTime" units="ms">
   <owner>mpearson@chromium.org</owner>
   <summary>
diff --git a/tools/traffic_annotation/bin/OWNERS b/tools/traffic_annotation/bin/OWNERS
index b5290ef..33258f6 100644
--- a/tools/traffic_annotation/bin/OWNERS
+++ b/tools/traffic_annotation/bin/OWNERS
@@ -1,2 +1,3 @@
 georgesak@chromium.org
+nicolaso@chromium.org
 rhalavati@chromium.org
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index dbfd47ea..257117a 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -972,8 +972,6 @@
   if (dirEntry instanceof VolumeEntry)
     dirEntry = assert(dirEntry.rootEntry);
 
-  // TODO(lucmult): Remove this log once flakiness is fixed.
-  console.log('changeDirectoryEntry: ',  dirEntry.name);
   // Increment the sequence value.
   this.changeDirectorySequence_++;
   this.clearSearch_();
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
index d755308..d3ee5e83 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
@@ -187,16 +187,6 @@
   this.myFilesModel_ = null;
 
   /**
-   * True when MyFiles should be a volume and Downloads just a plain folder
-   * inside it. When false MyFiles is an EntryList, which means UI only type,
-   * which contains Downloads as a child volume.
-   * @private {boolean}
-   */
-  this.myFilesVolumeEnabled_ =
-      loadTimeData.valueExists('MY_FILES_VOLUME_ENABLED') &&
-      loadTimeData.getBoolean('MY_FILES_VOLUME_ENABLED');
-
-  /**
    * All root navigation items in display order.
    * @private {!Array<!NavigationModelItem>}
    */
@@ -497,29 +487,12 @@
 
   let myFilesEntry, myFilesModel;
   if (!this.myFilesModel_) {
-    if (this.myFilesVolumeEnabled_) {
-      // When MyFilesVolume is enabled we use the Downloads volume to be the
-      // MyFiles volume.
-      const myFilesVolumeModel =
-          getSingleVolume(VolumeManagerCommon.VolumeType.DOWNLOADS);
-      if (myFilesVolumeModel) {
-        myFilesEntry = new VolumeEntry(myFilesVolumeModel.volumeInfo);
-        myFilesModel = new NavigationModelFakeItem(
-            str('MY_FILES_ROOT_LABEL'), NavigationModelItemType.ENTRY_LIST,
-            myFilesEntry);
-        this.myFilesModel_ = myFilesModel;
-      }
-    } else {
-      // Here is the initial version for MyFiles, which is only an entry in JS
-      // to be displayed in the DirectoryTree, cotaining Downloads, Linux and
-      // Play files volumes.
-      myFilesEntry = new EntryList(
-          str('MY_FILES_ROOT_LABEL'), VolumeManagerCommon.RootType.MY_FILES);
-      myFilesModel = new NavigationModelFakeItem(
-          myFilesEntry.label, NavigationModelItemType.ENTRY_LIST, myFilesEntry);
-      myFilesModel.section = NavigationSection.MY_FILES;
-      this.myFilesModel_ = myFilesModel;
-    }
+    myFilesEntry = new EntryList(
+        str('MY_FILES_ROOT_LABEL'), VolumeManagerCommon.RootType.MY_FILES);
+    myFilesModel = new NavigationModelFakeItem(
+        myFilesEntry.label, NavigationModelItemType.ENTRY_LIST, myFilesEntry);
+    myFilesModel.section = NavigationSection.MY_FILES;
+    this.myFilesModel_ = myFilesModel;
   } else {
     myFilesEntry = this.myFilesModel_.entry;
     myFilesModel = this.myFilesModel_;
@@ -527,18 +500,15 @@
   this.navigationItems_.push(myFilesModel);
 
   // Add Downloads to My Files.
-  if (!this.myFilesVolumeEnabled_) {
-    const downloadsVolume =
-        getSingleVolume(VolumeManagerCommon.VolumeType.DOWNLOADS);
-    if (downloadsVolume) {
-      // Only add volume if MyFiles doesn't have it yet.
-      if (myFilesEntry.findIndexByVolumeInfo(downloadsVolume.volumeInfo) ===
-          -1) {
-        myFilesEntry.addEntry(new VolumeEntry(downloadsVolume.volumeInfo));
-      }
-    } else {
-      myFilesEntry.removeByVolumeType(VolumeManagerCommon.VolumeType.DOWNLOADS);
+  const downloadsVolume =
+      getSingleVolume(VolumeManagerCommon.VolumeType.DOWNLOADS);
+  if (downloadsVolume) {
+    // Only add volume if MyFiles doesn't have it yet.
+    if (myFilesEntry.findIndexByVolumeInfo(downloadsVolume.volumeInfo) === -1) {
+      myFilesEntry.addEntry(new VolumeEntry(downloadsVolume.volumeInfo));
     }
+  } else {
+    myFilesEntry.removeByVolumeType(VolumeManagerCommon.VolumeType.DOWNLOADS);
   }
 
   // Add Android to My Files.
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js
index 3df6297..1103dbe 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js
@@ -28,16 +28,11 @@
 function setUp() {
   new MockCommandLinePrivate();
   // Override VolumeInfo.prototype.resolveDisplayRoot.
-  VolumeInfoImpl.prototype.resolveDisplayRoot = function(successCallback) {
-    this.displayRoot_ = this.fileSystem_.root;
-    successCallback(this.displayRoot_);
-  };
+  VolumeInfoImpl.prototype.resolveDisplayRoot = function() {};
 
   // TODO(crbug.com/834103): Add integration test for Crostini.
   drive = new MockFileSystem('drive');
   hoge = new MockFileSystem('removable:hoge');
-
-  loadTimeData.data_['MY_FILES_VOLUME_ENABLED'] = false;
 }
 
 function testModel() {
@@ -55,6 +50,10 @@
           'linux-files-label', VolumeManagerCommon.RootType.CROSTINI));
 
   assertEquals(4, model.length);
+  console.log(model.item(0).label);
+  console.log(model.item(1).label);
+  console.log(model.item(2).label);
+  console.log(model.item(3).label);
   assertEquals('fake-entry://recent', model.item(0).entry.toURL());
   assertEquals('/root/shortcut', model.item(1).entry.fullPath);
   assertEquals('My files', model.item(2).label);
@@ -62,6 +61,8 @@
 
   // Downloads and Crostini are displayed within My files.
   const myFilesEntry = model.item(2).entry;
+  console.log(myFilesEntry.children[0].name);
+  console.log(myFilesEntry.children[1].name);
   assertEquals(2, myFilesEntry.children.length);
   assertEquals('Downloads', myFilesEntry.children[0].name);
   assertEquals('linux-files-label', myFilesEntry.children[1].name);
@@ -296,69 +297,3 @@
   // expects it to be the same instance to be able to find it on the tree.
   assertEquals(myFilesModel, model.item(6));
 }
-
-
-function testMyFilesVolumeEnabled(callback) {
-  loadTimeData.data_['MY_FILES_VOLUME_ENABLED'] = true;
-  const volumeManager = new MockVolumeManager();
-  // Index 1 is Downloads.
-  assertEquals(
-      VolumeManagerCommon.VolumeType.DOWNLOADS,
-      volumeManager.volumeInfoList.item(1).volumeType);
-
-  // Create a downloads folder inside it.
-  const downloadsVolume = volumeManager.volumeInfoList.item(1);
-  downloadsVolume.fileSystem.populate(['/Downloads/']);
-
-  const shortcutListModel = new MockFolderShortcutDataModel([]);
-  const recentItem = null;
-
-
-  const crostiniFakeItem = new NavigationModelFakeItem(
-      'linux-files-label', NavigationModelItemType.CROSTINI,
-      new FakeEntry(
-          'linux-files-label', VolumeManagerCommon.RootType.CROSTINI));
-
-  // Create Android volume.
-  volumeManager.volumeInfoList.add(MockVolumeManager.createMockVolumeInfo(
-      VolumeManagerCommon.VolumeType.ANDROID_FILES, 'android_files:droid'));
-
-  // Navigation items built above:
-  //  1. My files
-  //       -> Play files
-  //       -> Linux files
-  //  2. Drive  - added by default by MockVolumeManager.
-
-  // Constructor already calls orderAndNestItems_.
-  const model =
-      new NavigationListModel(volumeManager, shortcutListModel, recentItem);
-  model.linuxFilesItem = crostiniFakeItem;
-
-  assertEquals(2, model.length);
-  assertEquals('My files', model.item(0).label);
-  assertEquals('My Drive', model.item(1).label);
-
-  // Android and Crostini are displayed within My files. And there is no
-  // Downloads volume inside it. Downloads should be a normal folder inside My
-  // files volume.
-  const myFilesEntry = model.item(0).entry;
-  assertEquals(2, myFilesEntry.children_.length);
-  assertEquals('android_files:droid', myFilesEntry.children_[0].name);
-  assertEquals('linux-files-label', myFilesEntry.children_[1].name);
-
-  const reader = myFilesEntry.createReader();
-  const foundEntries = [];
-  reader.readEntries((entries) => {
-    for (entry of entries)
-      foundEntries.push(entry);
-  });
-  reportPromise(
-      waitUntil(() => {
-        // Wait for Downloads folder to be read from My files volume.
-        return foundEntries.length >= 1;
-      }).then(() => {
-        assertEquals(foundEntries[0].name, 'Downloads');
-        assertTrue(foundEntries[0].isDirectory);
-      }),
-      callback);
-}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index 5d81c30..723bf4e0 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -483,17 +483,6 @@
 };
 
 /**
- * Default sorting for DirectoryItem sub-dirrectories.
- * @param {!Array<!Entry>} entries Entries to be sorted.
- * @returns {!Array<!Entry>}
- */
-DirectoryItem.prototype.sortEntries = function(entries) {
-  entries.sort(util.compareName);
-  const filter = this.fileFilter_.filter.bind(this.fileFilter_);
-  return entries.filter(filter);
-};
-
-/**
  * Retrieves the latest subdirectories and update them on the tree.
  * @param {boolean} recursive True if the update is recursively.
  * @param {function()=} opt_successCallback Callback called on success.
@@ -501,11 +490,17 @@
  */
 DirectoryItem.prototype.updateSubDirectories = function(
     recursive, opt_successCallback, opt_errorCallback) {
-  if (!this.entry || this.entry.createReader === undefined) {
-    opt_errorCallback && opt_errorCallback();
+  if (!this.entry || util.isFakeEntry(this.entry)) {
+    if (opt_errorCallback)
+      opt_errorCallback();
     return;
   }
 
+  const sortEntries = (fileFilter, entries) => {
+    entries.sort(util.compareName);
+    return entries.filter(fileFilter.filter.bind(fileFilter));
+  };
+
   const onSuccess = (entries) => {
     this.entries_ = entries;
     this.updateSubElementsFromList(recursive);
@@ -517,7 +512,7 @@
   const readEntry = () => {
     reader.readEntries((results) => {
       if (!results.length) {
-        onSuccess(this.sortEntries(entries));
+        onSuccess(sortEntries(this.fileFilter_, entries));
         return;
       }
 
@@ -748,46 +743,26 @@
  */
 EntryListItem.prototype.updateSubDirectories = function(
     recursive, opt_successCallback, opt_errorCallback) {
-  if (!this.entry || this.entry.createReader === undefined) {
+  if (!this.entry) {
     opt_errorCallback && opt_errorCallback();
     return;
   }
   this.entries_ = [];
-
-  const onSuccess = (entries) => {
-    this.entries_ = entries;
-    this.updateSubElementsFromList(recursive);
-    if (this.entries_.length > 0)
-      this.expanded = true;
-    opt_successCallback && opt_successCallback();
-    // TODO(lucmult): Remove this log once flakiness is fixed.
-    console.log('EntryListItem children loaded.');
-  };
-
-  const reader = this.entry.createReader();
-  const entries = [];
-  const readEntry = () => {
-    reader.readEntries((results) => {
-      if (!results.length) {
-        onSuccess(this.sortEntries(entries));
-        return;
+  if (this.entry && this.entry.children) {
+    for (let childEntry of this.entry.children) {
+      if (childEntry instanceof VolumeEntry) {
+        // For VolumeEntry we want to display its root.
+        this.entries_.push(childEntry.rootEntry);
+      } else {
+        this.entries_.push(childEntry);
       }
-
-      for (let i = 0; i < results.length; i++) {
-        const entry = results[i];
-        if (entry.isDirectory) {
-          // For VolumeEntry we want to display its root.
-          if (entry instanceof VolumeEntry) {
-            entries.push(entry.rootEntry);
-          } else {
-            entries.push(entry);
-          }
-        }
-      }
-      readEntry();
-    });
-  };
-  readEntry();
+    }
+  }
+  if (this.entries_.length > 0) {
+    this.expanded = true;
+  }
+  this.updateSubElementsFromList(recursive);
+  opt_successCallback && opt_successCallback();
 };
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.js
index 9f968ced..ca62cb95 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.js
@@ -501,10 +501,8 @@
   assertEquals(NavigationSection.MY_FILES, myFilesItem.section);
   assertEquals(NavigationSection.CLOUD, driveItem.section);
 
-  const metadataModel = mockMetadataModel();
-  DirectoryTree.decorate(
-      directoryTree, directoryModel, volumeManager, metadataModel,
-      fileOperationManager, true);
+  DirectoryTree.decorate(directoryTree, directoryModel, volumeManager,
+      null, fileOperationManager, true);
   directoryTree.dataModel = treeModel;
   directoryTree.updateSubElementsFromList(false);
 
@@ -960,10 +958,9 @@
       .webkitResolveLocalFileSystemURLEntries['filesystem:downloads/folder1'] =
       new MockDirectoryEntry(downloadsFileSystem, '/folder1');
 
-  const metadataModel = mockMetadataModel();
   DirectoryTree.decorate(
-      directoryTree, directoryModel, volumeManager, metadataModel,
-      fileOperationManager, true);
+      directoryTree, directoryModel, volumeManager, null, fileOperationManager,
+      true);
   directoryTree.dataModel = new MockNavigationListModel(volumeManager);
   directoryTree.redraw(true);
 
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn
index 9924381..2397f056 100644
--- a/ui/message_center/BUILD.gn
+++ b/ui/message_center/BUILD.gn
@@ -253,6 +253,7 @@
         "views/message_popup_collection_unittest.cc",
         "views/notification_view_md_unittest.cc",
         "views/notification_view_unittest.cc",
+        "views/slide_out_controller_unittest.cc",
       ]
       if (!is_chromeos) {
         sources += [ "views/notification_menu_model_unittest.cc" ]
diff --git a/ui/message_center/views/slide_out_controller_unittest.cc b/ui/message_center/views/slide_out_controller_unittest.cc
new file mode 100644
index 0000000..ae2348f
--- /dev/null
+++ b/ui/message_center/views/slide_out_controller_unittest.cc
@@ -0,0 +1,121 @@
+// 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 "ui/message_center/views/slide_out_controller.h"
+
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+
+namespace message_center {
+
+class SlideOutControllerDelegate : public SlideOutController::Delegate {
+ public:
+  explicit SlideOutControllerDelegate(views::View* target) : target_(target) {}
+  virtual ~SlideOutControllerDelegate() = default;
+
+  ui::Layer* GetSlideOutLayer() override { return target_->layer(); }
+
+  void OnSlideStarted() override { ++slide_started_count_; }
+
+  void OnSlideChanged(bool in_progress) override {
+    slide_changed_last_value_ = in_progress;
+    ++slide_changed_count_;
+  }
+
+  void OnSlideOut() override { ++slide_out_count_; }
+
+  base::Optional<bool> slide_changed_last_value_;
+  int slide_started_count_ = 0;
+  int slide_changed_count_ = 0;
+  int slide_out_count_ = 0;
+
+ private:
+  views::View* const target_;
+};
+
+class SlideOutControllerTest : public views::ViewsTestBase {
+ public:
+  SlideOutControllerTest() = default;
+  ~SlideOutControllerTest() override = default;
+
+  void SetUp() override {
+    views::ViewsTestBase::SetUp();
+
+    widget_ = std::make_unique<views::Widget>();
+
+    views::Widget::InitParams params =
+        CreateParams(views::Widget::InitParams::TYPE_POPUP);
+    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    params.bounds = gfx::Rect(50, 50, 650, 650);
+    widget_->Init(params);
+    views::View* root = widget_->GetRootView();
+
+    views::View* target_ = new views::View();
+    target_->SetPaintToLayer(ui::LAYER_TEXTURED);
+    target_->SetSize(gfx::Size(50, 50));
+
+    root->AddChildView(target_);
+    widget_->Show();
+
+    delegate_ = std::make_unique<SlideOutControllerDelegate>(target_);
+    slide_out_controller_ =
+        std::make_unique<SlideOutController>(target_, delegate_.get());
+  }
+
+  void TearDown() override {
+    slide_out_controller_.reset();
+    delegate_.reset();
+    widget_.reset();
+
+    views::ViewsTestBase::TearDown();
+  }
+
+ protected:
+  SlideOutController* slide_out_controller() {
+    return slide_out_controller_.get();
+  }
+
+  SlideOutControllerDelegate* delegate() { return delegate_.get(); }
+
+ private:
+  std::unique_ptr<views::Widget> widget_;
+  std::unique_ptr<SlideOutController> slide_out_controller_;
+  std::unique_ptr<SlideOutControllerDelegate> delegate_;
+};
+
+TEST_F(SlideOutControllerTest, OnGestureEventAndDelegate) {
+  ui::GestureEvent scroll_begin(
+      0, 0, ui::EF_NONE,
+      base::TimeTicks() + base::TimeDelta::FromMicroseconds(1),
+      ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
+  slide_out_controller()->OnGestureEvent(&scroll_begin);
+
+  EXPECT_EQ(1, delegate()->slide_started_count_);
+  EXPECT_EQ(0, delegate()->slide_changed_count_);
+  EXPECT_EQ(0, delegate()->slide_out_count_);
+
+  ui::GestureEvent scroll_update(
+      0, 0, ui::EF_NONE,
+      base::TimeTicks() + base::TimeDelta::FromMicroseconds(2),
+      ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE));
+  slide_out_controller()->OnGestureEvent(&scroll_update);
+
+  EXPECT_EQ(1, delegate()->slide_started_count_);
+  EXPECT_EQ(1, delegate()->slide_changed_count_);
+  EXPECT_TRUE(delegate()->slide_changed_last_value_.value());
+  EXPECT_EQ(0, delegate()->slide_out_count_);
+
+  ui::GestureEvent scroll_end(
+      0, 0, ui::EF_NONE,
+      base::TimeTicks() + base::TimeDelta::FromMicroseconds(3),
+      ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
+  slide_out_controller()->OnGestureEvent(&scroll_end);
+
+  EXPECT_EQ(1, delegate()->slide_started_count_);
+  EXPECT_EQ(2, delegate()->slide_changed_count_);
+  EXPECT_FALSE(delegate()->slide_changed_last_value_.value());
+  EXPECT_EQ(0, delegate()->slide_out_count_);
+}
+
+}  // namespace message_center
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_password_input.html b/ui/webui/resources/cr_components/chromeos/network/network_password_input.html
index debe4f1..8ed1335c 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_password_input.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_password_input.html
@@ -32,7 +32,7 @@
           disabled="[[getDisabled_(disabled, property)]]"
           type="[[getInputType_(showPassword)]]" on-keypress="onInputKeypress_">
       </cr-input>
-      <template is="dom-if" if="[[!getDisabled_(disabled, property)]]" restamp>
+      <template is="dom-if" if="[[!showPolicyIndicator_]]" restamp>
         <paper-icon-button-light id="icon" slot="suffix"
             class$="[[getIconClass_(showPassword)]]">
           <button on-tap="onShowPasswordTap_"
@@ -40,7 +40,7 @@
           </button>
         </paper-icon-button-light>
       </template>
-      <template is="dom-if" if="[[getDisabled_(disabled, property)]]" restamp>
+      <template is="dom-if" if="[[showPolicyIndicator_]]" restamp>
         <cr-policy-network-indicator
             property="[[property]]" tooltip-position="left">
         </cr-policy-network-indicator>
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_password_input.js b/ui/webui/resources/cr_components/chromeos/network/network_password_input.js
index 4072b8a5..9b0b47e 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_password_input.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_password_input.js
@@ -29,6 +29,13 @@
       type: Boolean,
       value: false,
     },
+
+    /** @private */
+    showPolicyIndicator_: {
+      type: Boolean,
+      value: false,
+      computed: 'getDisabled_(disabled, property)',
+    },
   },
 
   focus: function() {