diff --git a/WATCHLISTS b/WATCHLISTS
index f588378..42bd3b2a 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2262,7 +2262,8 @@
     'video': ['posciak+watch@chromium.org'],
     'video_capture': ['chfremer+watch@chromium.org'],
     'views': ['tfarina@chromium.org'],
-    'virtual_keyboard': ['dfaden+virtualkb@google.com',
+    'virtual_keyboard': ['blakeo+virtualkb@chromium.org',
+                         'dfaden+virtualkb@google.com',
                          'groby+virtualkb@chromium.org',
                          'oka+watchvk@chromium.org',
                          'yhanada+watchvk@chromium.org'],
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index 242c6d0..5474a60 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -1064,13 +1064,14 @@
   keyboard_window->set_owned_by_parent(false);
   keyboard_window->SetBounds(keyboard::FullWidthKeyboardBoundsFromRootBounds(
       root_window->bounds(), keyboard_height));
+  keyboard_window->Show();
 
   ui->EnsureCaretInWorkArea();
   ASSERT_EQ(root_window->bounds().width(),
             text_input_client.caret_exclude_rect().width());
   ASSERT_EQ(keyboard_height, text_input_client.caret_exclude_rect().height());
 
-  input_method->SetFocusedTextInputClient(NULL);
+  input_method->SetFocusedTextInputClient(nullptr);
 }
 
 TEST_F(VirtualKeyboardRootWindowControllerTest,
@@ -1111,9 +1112,13 @@
   keyboard_window->set_owned_by_parent(false);
   keyboard_window->SetBounds(keyboard::FullWidthKeyboardBoundsFromRootBounds(
       primary_root_window->bounds(), keyboard_height));
+  keyboard_window->Show();
 
+  ui->EnsureCaretInWorkArea();
   EXPECT_TRUE(primary_root_window->GetBoundsInScreen().Contains(
       text_input_client.caret_exclude_rect()));
+  EXPECT_EQ(primary_root_window->GetBoundsInScreen().width(),
+            text_input_client.caret_exclude_rect().width());
   EXPECT_FALSE(secondary_root_window->GetBoundsInScreen().Contains(
       text_input_client.caret_exclude_rect()));
 
@@ -1128,6 +1133,8 @@
       text_input_client.caret_exclude_rect()));
   EXPECT_TRUE(secondary_root_window->GetBoundsInScreen().Contains(
       text_input_client.caret_exclude_rect()));
+  EXPECT_EQ(secondary_root_window->GetBoundsInScreen().width(),
+            text_input_client.caret_exclude_rect().width());
 
   input_method->SetFocusedTextInputClient(nullptr);
 }
diff --git a/ash/shell.h b/ash/shell.h
index 53363db..e3991f2 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -13,7 +13,6 @@
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/session/session_observer.h"
-#include "ash/wm/cursor_manager_chromeos.h"
 #include "ash/wm/system_modal_container_event_filter_delegate.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
@@ -25,6 +24,10 @@
 #include "ui/wm/core/cursor_manager.h"
 #include "ui/wm/public/activation_change_observer.h"
 
+#if defined(OS_CHROMEOS)
+#include "ash/wm/cursor_manager_chromeos.h"
+#endif  // defined(OS_CHROMEOS)
+
 class PrefRegistrySimple;
 class PrefService;
 
diff --git a/ash/wm_window.cc b/ash/wm_window.cc
index d8387b9..2365c63 100644
--- a/ash/wm_window.cc
+++ b/ash/wm_window.cc
@@ -42,6 +42,7 @@
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/core/easy_resize_window_targeter.h"
+#include "ui/wm/core/ime_util_chromeos.h"
 #include "ui/wm/core/transient_window_manager.h"
 #include "ui/wm/core/visibility_controller.h"
 #include "ui/wm/core/window_util.h"
@@ -420,6 +421,7 @@
 
 void WmWindow::ClearRestoreBounds() {
   window_->ClearProperty(aura::client::kRestoreBoundsKey);
+  window_->ClearProperty(::wm::kVirtualKeyboardRestoreBoundsKey);
 }
 
 void WmWindow::SetRestoreBoundsInScreen(const gfx::Rect& bounds) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 3a91d289..9e158aec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -725,7 +725,7 @@
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        tracker.dismissed();
+                        tracker.dismissed(FeatureConstants.DOWNLOAD_HOME_FEATURE);
                         getAppMenuHandler().setMenuHighlight(null);
                     }
                 });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/IPHInfoBarSupport.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/IPHInfoBarSupport.java
index f4a986f5..595583a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/IPHInfoBarSupport.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/IPHInfoBarSupport.java
@@ -9,6 +9,7 @@
 import android.view.View;
 import android.widget.PopupWindow.OnDismissListener;
 
+import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.feature_engagement_tracker.FeatureEngagementTrackerFactory;
 import org.chromium.chrome.browser.infobar.InfoBarContainer.InfoBarContainerObserver;
@@ -52,6 +53,9 @@
 
         /** The bubble that is currently showing the in-product help. */
         public TextBubble bubble;
+
+        /** The in-product help feature that the popup relates to. */
+        public String feature;
     }
 
     /** The state of the currently showing in-product window or {@code null} if none is showing. */
@@ -68,6 +72,12 @@
     @Override
     public void notifyAnimationFinished(int animationType) {}
 
+    // Calling {@link ViewAnchoredTextBubble#dismiss()} will invoke {@link #onDismiss} which will
+    // set the value of {@link #mCurrentState} to null, which is what the assert checks. Since this
+    // goes through the Android SDK, FindBugs does not see this as happening, so the FindBugs
+    // warning for a field guaranteed to be non-null being checked for null equality needs to be
+    // suppressed.
+    @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
     @Override
     public void notifyAllAnimationsFinished(Item frontInfoBar) {
         View view = frontInfoBar == null ? null : frontInfoBar.getView();
@@ -76,7 +86,7 @@
             // Clean up any old infobar if necessary.
             if (mCurrentState.view != view) {
                 mCurrentState.bubble.dismiss();
-                mCurrentState = null;
+                assert mCurrentState == null;
             }
         }
 
@@ -97,17 +107,24 @@
         mCurrentState.bubble.addOnDismissListener(this);
         mCurrentState.bubble.setDismissOnTouchInteraction(true);
         mCurrentState.bubble.show();
+        mCurrentState.feature = params.feature;
     }
 
     // InfoBarContainerObserver implementation.
     @Override
     public void onAddInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isFirst) {}
 
+    // Calling {@link ViewAnchoredTextBubble#dismiss()} will invoke {@link #onDismiss} which will
+    // set the value of {@link #mCurrentState} to null, which is what the assert checks. Since this
+    // goes through the Android SDK, FindBugs does not see this as happening, so the FindBugs
+    // warning for a field guaranteed to be non-null being checked for null equality needs to be
+    // suppressed.
+    @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
     @Override
     public void onRemoveInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isLast) {
         if (mCurrentState != null && infoBar.getView() == mCurrentState.view) {
             mCurrentState.bubble.dismiss();
-            mCurrentState = null;
+            assert mCurrentState == null;
         }
     }
 
@@ -117,8 +134,10 @@
     // PopupWindow.OnDismissListener implementation.
     @Override
     public void onDismiss() {
+        assert mCurrentState != null;
+        String feature = mCurrentState.feature;
         mCurrentState = null;
-        mTracker.dismissed();
+        mTracker.dismissed(feature);
     }
 
     private void logEvent(Item infoBar) {
@@ -140,4 +159,4 @@
                 return null;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 411f44b..6477a20 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -534,7 +534,7 @@
                         mHandler.post(new Runnable() {
                             @Override
                             public void run() {
-                                tracker.dismissed();
+                                tracker.dismissed(FeatureConstants.DOWNLOAD_PAGE_FEATURE);
                                 activity.getAppMenuHandler().setMenuHighlight(null);
                             }
                         });
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index f4cbb0f3..d3c3ebf 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -12,9 +12,6 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
-#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
-#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
 #include "chrome/browser/net/nss_context.h"
 #include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
 #include "chrome/common/net/x509_certificate_model.h"
@@ -27,6 +24,15 @@
 #include "net/cert/x509_certificate.h"
 #include "ui/base/l10n/l10n_util.h"
 
+// TODO(wychen): ChromeOS headers should only be included when building
+//               ChromeOS, and the following headers should be guarded by
+//               #if defined(OS_CHROMEOS). However, the types are actually
+//               used, and it takes another CL to clean them up.
+//               Reference: crbug.com/720159
+#include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
+#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
+#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
+
 using content::BrowserThread;
 
 // CertificateManagerModel is created on the UI thread. It needs a
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index dfb99af..00d589b5 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -118,7 +118,6 @@
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/installer/util/google_update_settings.h"
-#include "chromeos/chromeos_constants.h"
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 #include "components/autofill/core/common/autofill_switches.h"
 #include "components/browsing_data/core/browsing_data_utils.h"
@@ -246,6 +245,7 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chromeos/chromeos_constants.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/user_manager/user_manager.h"
 #include "mash/public/interfaces/launchable.mojom.h"
diff --git a/chrome/browser/cryptauth/chrome_cryptauth_service.cc b/chrome/browser/cryptauth/chrome_cryptauth_service.cc
index 3429a5e..cb91f83 100644
--- a/chrome/browser/cryptauth/chrome_cryptauth_service.cc
+++ b/chrome/browser/cryptauth/chrome_cryptauth_service.cc
@@ -11,7 +11,6 @@
 #include "base/version.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_content_browser_client.h"
-#include "chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -38,6 +37,7 @@
 #if defined(OS_CHROMEOS)
 #include "ash/shell.h"
 #include "base/linux_util.h"
+#include "chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/manager/managed_display_info.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/chrome/browser/diagnostics/diagnostics_controller_unittest.cc b/chrome/browser/diagnostics/diagnostics_controller_unittest.cc
index eb18d80..d004fb35 100644
--- a/chrome/browser/diagnostics/diagnostics_controller_unittest.cc
+++ b/chrome/browser/diagnostics/diagnostics_controller_unittest.cc
@@ -18,9 +18,12 @@
 #include "chrome/browser/diagnostics/sqlite_diagnostics.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
-#include "chromeos/chromeos_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/chromeos_constants.h"
+#endif  // defined(OS_CHROMEOS)
+
 namespace diagnostics {
 
 // Basic harness to acquire and release the required temporary environment to
diff --git a/chrome/browser/diagnostics/sqlite_diagnostics.cc b/chrome/browser/diagnostics/sqlite_diagnostics.cc
index 42056e4..07401504 100644
--- a/chrome/browser/diagnostics/sqlite_diagnostics.cc
+++ b/chrome/browser/diagnostics/sqlite_diagnostics.cc
@@ -22,7 +22,6 @@
 #include "build/build_config.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
-#include "chromeos/chromeos_constants.h"
 #include "components/history/core/browser/history_constants.h"
 #include "components/webdata/common/webdata_constants.h"
 #include "content/public/common/content_constants.h"
@@ -31,6 +30,10 @@
 #include "storage/browser/database/database_tracker.h"
 #include "third_party/sqlite/sqlite3.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/chromeos_constants.h"
+#endif  // defined(OS_CHROMEOS)
+
 namespace diagnostics {
 
 namespace {
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
index 8cb98ee..f00d182c 100644
--- a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
+++ b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
@@ -8,12 +8,15 @@
 #include "chrome/browser/extensions/api/page_capture/page_capture_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/common/chrome_switches.h"
-#include "chromeos/login/login_state.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "net/dns/mock_host_resolver.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/login/login_state.h"
+#endif  // defined(OS_CHROMEOS)
+
 using extensions::PageCaptureSaveAsMHTMLFunction;
 using extensions::ScopedTestDialogAutoConfirm;
 
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_event_router.h b/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
index 4c2f166..3b79001d 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
+++ b/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
@@ -9,12 +9,18 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/extensions/api/settings_private/prefs_util.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "extensions/browser/event_router.h"
 
+// TODO(wychen): ChromeOS headers should only be included when building
+//               ChromeOS, and the following headers should be guarded by
+//               #if defined(OS_CHROMEOS). However, the types are actually
+//               used, and it takes another CL to clean them up.
+//               Reference: crbug.com/720159
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+
 namespace content {
 class BrowserContext;
 }
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 9bbcc9d..ef400b6 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -22,7 +22,6 @@
 #include "chrome/common/extensions/extension_process_policy.h"
 #include "chrome/test/base/search_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/login/login_state.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
@@ -42,6 +41,10 @@
 #include "net/test/test_data_directory.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/login/login_state.h"
+#endif  // defined(OS_CHROMEOS)
+
 using content::WebContents;
 
 namespace extensions {
diff --git a/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc
index af3259e..f9abaf7 100644
--- a/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "chrome/common/extensions/extension_test_util.h"
-#include "chromeos/login/login_state.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -24,6 +23,10 @@
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/login/login_state.h"
+#endif  // defined(OS_CHROMEOS)
+
 using content::ResourceRequestInfo;
 using extensions::Extension;
 using extensions::Manifest;
diff --git a/chrome/browser/net/predictor_tab_helper.cc b/chrome/browser/net/predictor_tab_helper.cc
index 7b08a01..20f4157d 100644
--- a/chrome/browser/net/predictor_tab_helper.cc
+++ b/chrome/browser/net/predictor_tab_helper.cc
@@ -5,13 +5,16 @@
 #include "chrome/browser/net/predictor_tab_helper.h"
 
 #include "base/feature_list.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/net/predictor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#endif  // defined(OS_CHROMEOS)
+
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(chrome_browser_net::PredictorTabHelper);
 
 namespace chrome_browser_net {
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index 4e3f002..f1dd3c1b 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/prefs/browser_prefs.h"
diff --git a/chrome/browser/resources/safe_browsing/README.md b/chrome/browser/resources/safe_browsing/README.md
index c745b96..15916e4 100644
--- a/chrome/browser/resources/safe_browsing/README.md
+++ b/chrome/browser/resources/safe_browsing/README.md
@@ -10,7 +10,7 @@
 
 
 ## Procedure for adding/modifying file type(s)
-  * **Edit** `download_file_types.asciipb` and update `histograms.xml`
+  * **Edit** `download_file_types.asciipb` and update `enums.xml`
   * Get it reviewed, **submit.**
   * **Push** it to all users via component update:
     * Wait 1-3 day for this to run on Canary to verify it doesn't crash Chrome.
@@ -34,7 +34,7 @@
     first one wins. Only the `default_file_type` should leave this unset.
 
   * `uma_value`: (required) must be unique and match one in the
-    `SBClientDownloadExtensions` enum in `histograms.xml`.
+    `SBClientDownloadExtensions` enum in `enums.xml`.
 
   * `is_archive`: `True` if this filetype is a container for other files.
      Leave it unset for `false`.
diff --git a/chrome/browser/resources/safe_browsing/download_file_types.asciipb b/chrome/browser/resources/safe_browsing/download_file_types.asciipb
index 6641e0de..a61c0826 100644
--- a/chrome/browser/resources/safe_browsing/download_file_types.asciipb
+++ b/chrome/browser/resources/safe_browsing/download_file_types.asciipb
@@ -8,7 +8,7 @@
 ##
 ## Top level settings
 ##
-version_id: 9
+version_id: 10
 sampled_ping_probability: 0.01
 default_file_type {
   uma_value: 18
@@ -1809,6 +1809,28 @@
   }
 }
 file_types {
+  # HTML file. This extension is abused by UwS campaigns to evade referrer
+  # attribution via a two-level download scheme. crbug.com/719784
+  extension: "htm"
+  uma_value: 284
+  ping_setting: FULL_PING
+  platform_settings {
+    danger_level: NOT_DANGEROUS
+    auto_open_hint: ALLOW_AUTO_OPEN
+  }
+}
+file_types {
+  # HTML file. This extension is abused by UwS campaigns to evade referrer
+  # attribution via a two-level download scheme. crbug.com/719784
+  extension: "html"
+  uma_value: 285
+  ping_setting: FULL_PING
+  platform_settings {
+    danger_level: NOT_DANGEROUS
+    auto_open_hint: ALLOW_AUTO_OPEN
+  }
+}
+file_types {
   # Hypertext Template File. See https://support.microsoft.com/kb/181689.
   extension: "htt"
   uma_value: 79
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index 03ec3dbd..4152ac0 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -74,11 +74,11 @@
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyFinchControlForLowReputationPingSBEROnlyNoIncognito) {
   MockChromePasswordProtectionService service;
-  // By default kLowReputationPinging feature is disabled.
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  // By default kPasswordFieldOnFocusPinging feature is disabled.
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
 
-  // Enables kLowReputationPinging feature.
-  scoped_feature_list_.InitAndEnableFeature(kLowReputationPinging);
+  // Enables kPasswordFieldOnFocusPinging feature.
+  scoped_feature_list_.InitAndEnableFeature(kPasswordFieldOnFocusPinging);
   // Creates finch trial parameters correspond to the following experiment:
   // "name": "SBEROnlyNoIncognito",
   // "params": {
@@ -87,38 +87,38 @@
   //     "history_sync": "false"
   // },
   // "enable_features": [
-  //     "LowReputationPinging"
+  //     "PasswordFieldOnFocusPinging"
   // ]
   Parameters sber_and_no_incognito =
       CreateParameters(false, false, true, false);
-  SetFeatureParams(kLowReputationPinging, "SBEROnlyNoIncognito",
+  SetFeatureParams(kPasswordFieldOnFocusPinging, "SBEROnlyNoIncognito",
                    sber_and_no_incognito);
   service.ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyFinchControlForLowReputationPingSBERAndHistorySyncNoIncognito) {
   MockChromePasswordProtectionService service;
-  // By default kLowReputationPinging feature is disabled.
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  // By default kPasswordFieldOnFocusPinging feature is disabled.
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
 
-  // Enables kLowReputationPinging feature.
-  scoped_feature_list_.InitAndEnableFeature(kLowReputationPinging);
+  // Enables kPasswordFieldOnFocusPinging feature.
+  scoped_feature_list_.InitAndEnableFeature(kPasswordFieldOnFocusPinging);
   // Creates finch trial parameters correspond to the following experiment:
   // "name": "SBERAndHistorySyncNoIncognito",
   // "params": {
@@ -127,38 +127,38 @@
   //     "history_sync": "true"
   // },
   // "enable_features": [
-  //     "LowReputationPinging"
+  //     "PasswordFieldOnFocusPinging"
   // ]
   Parameters sber_and_sync_no_incognito =
       CreateParameters(false, false, true, true);
-  SetFeatureParams(kLowReputationPinging, "SBERAndHistorySyncNoIncognito",
-                   sber_and_sync_no_incognito);
+  SetFeatureParams(kPasswordFieldOnFocusPinging,
+                   "SBERAndHistorySyncNoIncognito", sber_and_sync_no_incognito);
   service.ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyFinchControlForLowReputationPingAllButNoIncognito) {
   MockChromePasswordProtectionService service;
-  // By default kLowReputationPinging feature is disabled.
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  // By default kPasswordFieldOnFocusPinging feature is disabled.
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
 
-  // Enables kLowReputationPinging feature.
-  scoped_feature_list_.InitAndEnableFeature(kLowReputationPinging);
+  // Enables kPasswordFieldOnFocusPinging feature.
+  scoped_feature_list_.InitAndEnableFeature(kPasswordFieldOnFocusPinging);
   // Creates finch trial parameters correspond to the following experiment:
   // "name": "AllButNoIncognito",
   // "params": {
@@ -166,36 +166,37 @@
   //     "incongito": "false"
   // },
   // "enable_features": [
-  //     "LowReputationPinging"
+  //     "PasswordFieldOnFocusPinging"
   // ]
   Parameters all_users = CreateParameters(false, true, true, true);
-  SetFeatureParams(kLowReputationPinging, "AllButNoIncognito", all_users);
+  SetFeatureParams(kPasswordFieldOnFocusPinging, "AllButNoIncognito",
+                   all_users);
   service.ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyFinchControlForLowReputationPingAll) {
   MockChromePasswordProtectionService service;
-  // By default kLowReputationPinging feature is disabled.
-  EXPECT_FALSE(service.IsPingingEnabled(kLowReputationPinging));
+  // By default kPasswordFieldOnFocusPinging feature is disabled.
+  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
 
-  // Enables kLowReputationPinging feature.
-  scoped_feature_list_.InitAndEnableFeature(kLowReputationPinging);
+  // Enables kPasswordFieldOnFocusPinging feature.
+  scoped_feature_list_.InitAndEnableFeature(kPasswordFieldOnFocusPinging);
   // Creates finch trial parameters correspond to the following experiment:
   // "name": "All",
   // "params": {
@@ -203,26 +204,26 @@
   //     "incognito": "true"
   // },
   // "enable_features": [
-  //     "LowReputationPinging"
+  //     "PasswordFieldOnFocusPinging"
   // ]
   Parameters all_users = CreateParameters(true, true, true, true);
-  SetFeatureParams(kLowReputationPinging, "All", all_users);
+  SetFeatureParams(kPasswordFieldOnFocusPinging, "All", all_users);
   service.ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
   service.ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kLowReputationPinging));
+  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging));
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/ssl/security_state_tab_helper.cc b/chrome/browser/ssl/security_state_tab_helper.cc
index 56bb713..a5c7c94 100644
--- a/chrome/browser/ssl/security_state_tab_helper.cc
+++ b/chrome/browser/ssl/security_state_tab_helper.cc
@@ -9,8 +9,6 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/policy/policy_cert_service.h"
-#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
@@ -29,6 +27,11 @@
 #include "third_party/boringssl/src/include/openssl/ssl.h"
 #include "ui/base/l10n/l10n_util.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/policy/policy_cert_service.h"
+#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
+#endif  // defined(OS_CHROMEOS)
+
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SecurityStateTabHelper);
 
 using safe_browsing::SafeBrowsingUIManager;
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index eb9a252..7d0394f 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1035,6 +1035,11 @@
                                WebContents* new_contents,
                                int index,
                                int reason) {
+// Mac correctly sets the initial background color of new tabs to the theme
+// background color, so it does not need this block of code. Aura should
+// implement this as well.
+// https://crbug.com/719230
+#if !defined(OS_MACOSX)
   // Copies the background color from an old WebContents to a new one that
   // replaces it on the screen. This allows the new WebContents to use the
   // old one's background color as the starting background color, before having
@@ -1050,6 +1055,7 @@
     if (old_view && new_view)
       new_view->SetBackgroundColor(old_view->background_color());
   }
+#endif
 
   base::RecordAction(UserMetricsAction("ActiveTabChanged"));
 
diff --git a/chrome/browser/ui/browser_unittest.cc b/chrome/browser/ui/browser_unittest.cc
index 62bcd32..9e99d68 100644
--- a/chrome/browser/ui/browser_unittest.cc
+++ b/chrome/browser/ui/browser_unittest.cc
@@ -68,7 +68,14 @@
   EXPECT_TRUE(contents2->IsCrashed());
 }
 
-TEST_F(BrowserUnitTest, SetBackgroundColorForNewTab) {
+// This tests a workaround which is not necessary on Mac.
+// https://crbug.com/719230
+#if defined(OS_MACOSX)
+#define MAYBE_SetBackgroundColorForNewTab DISABLED_SetBackgroundColorForNewTab
+#else
+#define MAYBE_SetBackgroundColorForNewTab SetBackgroundColorForNewTab
+#endif
+TEST_F(BrowserUnitTest, MAYBE_SetBackgroundColorForNewTab) {
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
 
   WebContents* contents1 = CreateTestWebContents();
diff --git a/chrome/browser/ui/input_method/input_method_engine_base.h b/chrome/browser/ui/input_method/input_method_engine_base.h
index 9076c73..db7d6f6 100644
--- a/chrome/browser/ui/input_method/input_method_engine_base.h
+++ b/chrome/browser/ui/input_method/input_method_engine_base.h
@@ -11,11 +11,14 @@
 #include <vector>
 
 #include "base/time/time.h"
-#include "ui/base/ime/chromeos/input_method_descriptor.h"
 #include "ui/base/ime/composition_text.h"
 #include "ui/base/ime/ime_engine_handler_interface.h"
 #include "url/gurl.h"
 
+#if defined(OS_CHROMEOS)
+#include "ui/base/ime/chromeos/input_method_descriptor.h"
+#endif  // defined(OS_CHROMEOS)
+
 class Profile;
 
 namespace ui {
diff --git a/components/feature_engagement_tracker/internal/BUILD.gn b/components/feature_engagement_tracker/internal/BUILD.gn
index 8f629d9..4673bdc 100644
--- a/components/feature_engagement_tracker/internal/BUILD.gn
+++ b/components/feature_engagement_tracker/internal/BUILD.gn
@@ -23,11 +23,8 @@
     "editable_configuration.h",
     "feature_config_storage_validator.cc",
     "feature_config_storage_validator.h",
-    "feature_constants.cc",
     "feature_engagement_tracker_impl.cc",
     "feature_engagement_tracker_impl.h",
-    "feature_list.cc",
-    "feature_list.h",
     "in_memory_store.cc",
     "in_memory_store.h",
     "model.h",
diff --git a/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc b/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc
index f22a3d12..c2dd33f 100644
--- a/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc
+++ b/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc
@@ -13,8 +13,8 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
 #include "components/feature_engagement_tracker/public/feature_engagement_tracker.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 #include "jni/FeatureEngagementTrackerImpl_jni.h"
 
 namespace feature_engagement_tracker {
@@ -121,8 +121,12 @@
 
 void FeatureEngagementTrackerImplAndroid::Dismissed(
     JNIEnv* env,
-    const base::android::JavaRef<jobject>& jobj) {
-  feature_engagement_tracker_impl_->Dismissed();
+    const base::android::JavaRef<jobject>& jobj,
+    const base::android::JavaParamRef<jstring>& jfeature) {
+  std::string feature = ConvertJavaStringToUTF8(env, jfeature);
+  DCHECK(features_.find(feature) != features_.end());
+
+  feature_engagement_tracker_impl_->Dismissed(*features_[feature]);
 }
 
 bool FeatureEngagementTrackerImplAndroid::IsInitialized(
diff --git a/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h b/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h
index 79f3c41..8818474 100644
--- a/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h
+++ b/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h
@@ -14,7 +14,7 @@
 #include "base/macros.h"
 #include "base/supports_user_data.h"
 #include "components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 namespace base {
 struct Feature;
@@ -53,7 +53,8 @@
       const base::android::JavaRef<jobject>& jobj,
       const base::android::JavaParamRef<jstring>& jfeature);
   virtual void Dismissed(JNIEnv* env,
-                         const base::android::JavaRef<jobject>& jobj);
+                         const base::android::JavaRef<jobject>& jobj,
+                         const base::android::JavaParamRef<jstring>& jfeature);
   virtual bool IsInitialized(JNIEnv* env,
                              const base::android::JavaRef<jobject>& jobj);
   virtual void AddOnInitializedCallback(
diff --git a/components/feature_engagement_tracker/internal/android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java b/components/feature_engagement_tracker/internal/android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java
index 8626790..1ef81e75 100644
--- a/components/feature_engagement_tracker/internal/android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java
+++ b/components/feature_engagement_tracker/internal/android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java
@@ -42,9 +42,9 @@
     }
 
     @Override
-    public void dismissed() {
+    public void dismissed(String feature) {
         assert mNativePtr != 0;
-        nativeDismissed(mNativePtr);
+        nativeDismissed(mNativePtr, feature);
     }
 
     @Override
@@ -74,7 +74,8 @@
             long nativeFeatureEngagementTrackerImplAndroid, String event);
     private native boolean nativeShouldTriggerHelpUI(
             long nativeFeatureEngagementTrackerImplAndroid, String feature);
-    private native void nativeDismissed(long nativeFeatureEngagementTrackerImplAndroid);
+    private native void nativeDismissed(
+            long nativeFeatureEngagementTrackerImplAndroid, String feature);
     private native boolean nativeIsInitialized(long nativeFeatureEngagementTrackerImplAndroid);
     private native void nativeAddOnInitializedCallback(
             long nativeFeatureEngagementTrackerImplAndroid, Callback<Boolean> callback);
diff --git a/components/feature_engagement_tracker/internal/chrome_variations_configuration.cc b/components/feature_engagement_tracker/internal/chrome_variations_configuration.cc
index e388ec2..9207b57 100644
--- a/components/feature_engagement_tracker/internal/chrome_variations_configuration.cc
+++ b/components/feature_engagement_tracker/internal/chrome_variations_configuration.cc
@@ -18,7 +18,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 namespace {
 
diff --git a/components/feature_engagement_tracker/internal/chrome_variations_configuration.h b/components/feature_engagement_tracker/internal/chrome_variations_configuration.h
index e140d13f..15774ae7 100644
--- a/components/feature_engagement_tracker/internal/chrome_variations_configuration.h
+++ b/components/feature_engagement_tracker/internal/chrome_variations_configuration.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 namespace base {
 struct Feature;
diff --git a/components/feature_engagement_tracker/internal/condition_validator.h b/components/feature_engagement_tracker/internal/condition_validator.h
index 14c4316..3272b7b 100644
--- a/components/feature_engagement_tracker/internal/condition_validator.h
+++ b/components/feature_engagement_tracker/internal/condition_validator.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 namespace base {
 struct Feature;
diff --git a/components/feature_engagement_tracker/internal/feature_config_storage_validator.cc b/components/feature_engagement_tracker/internal/feature_config_storage_validator.cc
index 1af635e..fe08b24 100644
--- a/components/feature_engagement_tracker/internal/feature_config_storage_validator.cc
+++ b/components/feature_engagement_tracker/internal/feature_config_storage_validator.cc
@@ -8,7 +8,7 @@
 #include <unordered_set>
 
 #include "components/feature_engagement_tracker/internal/configuration.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 namespace feature_engagement_tracker {
 
diff --git a/components/feature_engagement_tracker/internal/feature_config_storage_validator.h b/components/feature_engagement_tracker/internal/feature_config_storage_validator.h
index d0ba4241..c511548 100644
--- a/components/feature_engagement_tracker/internal/feature_config_storage_validator.h
+++ b/components/feature_engagement_tracker/internal/feature_config_storage_validator.h
@@ -10,8 +10,8 @@
 #include <unordered_set>
 
 #include "base/macros.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
 #include "components/feature_engagement_tracker/internal/storage_validator.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 namespace feature_engagement_tracker {
 class Configuration;
diff --git a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc
index ecda0ed..1e8f031 100644
--- a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc
+++ b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc
@@ -9,7 +9,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/feature_engagement_tracker/internal/editable_configuration.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
 #include "components/feature_engagement_tracker/internal/in_memory_store.h"
 #include "components/feature_engagement_tracker/internal/model_impl.h"
 #include "components/feature_engagement_tracker/internal/never_condition_validator.h"
@@ -17,6 +16,7 @@
 #include "components/feature_engagement_tracker/internal/once_condition_validator.h"
 #include "components/feature_engagement_tracker/internal/single_invalid_configuration.h"
 #include "components/feature_engagement_tracker/public/feature_constants.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 namespace feature_engagement_tracker {
 
@@ -98,7 +98,7 @@
   return result;
 }
 
-void FeatureEngagementTrackerImpl::Dismissed() {
+void FeatureEngagementTrackerImpl::Dismissed(const base::Feature& feature) {
   // TODO(nyquist): Track this event.
   model_->SetIsCurrentlyShowing(false);
 }
diff --git a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h
index 9ce2dc9..9f7db4a39 100644
--- a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h
+++ b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h
@@ -35,7 +35,7 @@
   // FeatureEngagementTracker implementation.
   void NotifyEvent(const std::string& event) override;
   bool ShouldTriggerHelpUI(const base::Feature& feature) override;
-  void Dismissed() override;
+  void Dismissed(const base::Feature& feature) override;
   bool IsInitialized() override;
   void AddOnInitializedCallback(OnInitializedCallback callback) override;
 
diff --git a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
index 05eb055..2b44010 100644
--- a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
+++ b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
@@ -278,14 +278,14 @@
 
   // After dismissing the current in-product help, that feature can not be shown
   // again, but a different feature should.
-  tracker_->Dismissed();
+  tracker_->Dismissed(kTestFeatureFoo);
   EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo));
   EXPECT_TRUE(tracker_->ShouldTriggerHelpUI(kTestFeatureBar));
   EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureQux));
 
   // After dismissing the second registered feature, no more in-product help
   // should be shown, since kTestFeatureQux is invalid.
-  tracker_->Dismissed();
+  tracker_->Dismissed(kTestFeatureBar);
   EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo));
   EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureBar));
   EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureQux));
diff --git a/components/feature_engagement_tracker/internal/never_condition_validator.h b/components/feature_engagement_tracker/internal/never_condition_validator.h
index 7f67212..0a51ca6 100644
--- a/components/feature_engagement_tracker/internal/never_condition_validator.h
+++ b/components/feature_engagement_tracker/internal/never_condition_validator.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "components/feature_engagement_tracker/internal/condition_validator.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 namespace base {
 struct Feature;
diff --git a/components/feature_engagement_tracker/internal/once_condition_validator.h b/components/feature_engagement_tracker/internal/once_condition_validator.h
index dfcb70e8..a5d6cb7c 100644
--- a/components/feature_engagement_tracker/internal/once_condition_validator.h
+++ b/components/feature_engagement_tracker/internal/once_condition_validator.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "components/feature_engagement_tracker/internal/condition_validator.h"
-#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 namespace base {
 struct Feature;
diff --git a/components/feature_engagement_tracker/public/BUILD.gn b/components/feature_engagement_tracker/public/BUILD.gn
index c69469b2..3be36c7 100644
--- a/components/feature_engagement_tracker/public/BUILD.gn
+++ b/components/feature_engagement_tracker/public/BUILD.gn
@@ -9,8 +9,11 @@
 
 source_set("public") {
   sources = [
+    "feature_constants.cc",
     "feature_constants.h",
     "feature_engagement_tracker.h",
+    "feature_list.cc",
+    "feature_list.h",
   ]
 
   deps = [
diff --git a/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.java b/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.java
index 633993f..0f702b18 100644
--- a/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.java
+++ b/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.java
@@ -31,9 +31,9 @@
     boolean shouldTriggerHelpUI(String feature);
 
     /**
-     * Must be called after display of feature enlightenment finishes.
+     * Must be called after display of feature enlightenment finishes for a particular feature.
      */
-    void dismissed();
+    void dismissed(String feature);
 
     /**
      * Returns whether the tracker has been successfully initialized. During startup, this will be
diff --git a/components/feature_engagement_tracker/internal/feature_constants.cc b/components/feature_engagement_tracker/public/feature_constants.cc
similarity index 100%
rename from components/feature_engagement_tracker/internal/feature_constants.cc
rename to components/feature_engagement_tracker/public/feature_constants.cc
diff --git a/components/feature_engagement_tracker/public/feature_engagement_tracker.h b/components/feature_engagement_tracker/public/feature_engagement_tracker.h
index d969a81..53f82b2 100644
--- a/components/feature_engagement_tracker/public/feature_engagement_tracker.h
+++ b/components/feature_engagement_tracker/public/feature_engagement_tracker.h
@@ -58,8 +58,9 @@
   virtual bool ShouldTriggerHelpUI(const base::Feature& feature)
       WARN_UNUSED_RESULT = 0;
 
-  // Must be called after display of feature enlightenment finishes.
-  virtual void Dismissed() = 0;
+  // Must be called after display of feature enlightenment finishes for a
+  // particular |feature|.
+  virtual void Dismissed(const base::Feature& feature) = 0;
 
   // Returns whether the tracker has been successfully initialized. During
   // startup, this will be false until the internal model has been loaded at
diff --git a/components/feature_engagement_tracker/internal/feature_list.cc b/components/feature_engagement_tracker/public/feature_list.cc
similarity index 89%
rename from components/feature_engagement_tracker/internal/feature_list.cc
rename to components/feature_engagement_tracker/public/feature_list.cc
index 9dcbae3..6d600c4 100644
--- a/components/feature_engagement_tracker/internal/feature_list.cc
+++ b/components/feature_engagement_tracker/public/feature_list.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/feature_engagement_tracker/internal/feature_list.h"
+#include "components/feature_engagement_tracker/public/feature_list.h"
 
 #include "base/feature_list.h"
 #include "components/feature_engagement_tracker/public/feature_constants.h"
diff --git a/components/feature_engagement_tracker/internal/feature_list.h b/components/feature_engagement_tracker/public/feature_list.h
similarity index 100%
rename from components/feature_engagement_tracker/internal/feature_list.h
rename to components/feature_engagement_tracker/public/feature_list.h
diff --git a/components/leveldb/leveldb_database_impl.cc b/components/leveldb/leveldb_database_impl.cc
index 5387409..59ab078 100644
--- a/components/leveldb/leveldb_database_impl.cc
+++ b/components/leveldb/leveldb_database_impl.cc
@@ -6,6 +6,7 @@
 
 #include <map>
 #include <string>
+#include <utility>
 
 #include "base/optional.h"
 #include "base/rand_util.h"
@@ -48,33 +49,32 @@
 
 void LevelDBDatabaseImpl::Put(const std::vector<uint8_t>& key,
                               const std::vector<uint8_t>& value,
-                              const PutCallback& callback) {
+                              PutCallback callback) {
   leveldb::Status status =
       db_->Put(leveldb::WriteOptions(), GetSliceFor(key), GetSliceFor(value));
-  callback.Run(LeveldbStatusToError(status));
+  std::move(callback).Run(LeveldbStatusToError(status));
 }
 
 void LevelDBDatabaseImpl::Delete(const std::vector<uint8_t>& key,
-                                 const DeleteCallback& callback) {
+                                 DeleteCallback callback) {
   leveldb::Status status =
       db_->Delete(leveldb::WriteOptions(), GetSliceFor(key));
-  callback.Run(LeveldbStatusToError(status));
+  std::move(callback).Run(LeveldbStatusToError(status));
 }
 
-void LevelDBDatabaseImpl::DeletePrefixed(
-    const std::vector<uint8_t>& key_prefix,
-    const DeletePrefixedCallback& callback) {
+void LevelDBDatabaseImpl::DeletePrefixed(const std::vector<uint8_t>& key_prefix,
+                                         DeletePrefixedCallback callback) {
   leveldb::WriteBatch batch;
   leveldb::Status status = DeletePrefixedHelper(
       GetSliceFor(key_prefix), &batch);
   if (status.ok())
     status = db_->Write(leveldb::WriteOptions(), &batch);
-  callback.Run(LeveldbStatusToError(status));
+  std::move(callback).Run(LeveldbStatusToError(status));
 }
 
 void LevelDBDatabaseImpl::Write(
     std::vector<mojom::BatchedOperationPtr> operations,
-    const WriteCallback& callback) {
+    WriteCallback callback) {
   leveldb::WriteBatch batch;
 
   for (size_t i = 0; i < operations.size(); ++i) {
@@ -100,19 +100,20 @@
   }
 
   leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch);
-  callback.Run(LeveldbStatusToError(status));
+  std::move(callback).Run(LeveldbStatusToError(status));
 }
 
 void LevelDBDatabaseImpl::Get(const std::vector<uint8_t>& key,
-                              const GetCallback& callback) {
+                              GetCallback callback) {
   std::string value;
   leveldb::Status status =
       db_->Get(leveldb::ReadOptions(), GetSliceFor(key), &value);
-  callback.Run(LeveldbStatusToError(status), StdStringToUint8Vector(value));
+  std::move(callback).Run(LeveldbStatusToError(status),
+                          StdStringToUint8Vector(value));
 }
 
 void LevelDBDatabaseImpl::GetPrefixed(const std::vector<uint8_t>& key_prefix,
-                                      const GetPrefixedCallback& callback) {
+                                      GetPrefixedCallback callback) {
   std::vector<mojom::KeyValuePtr> data;
   leveldb::Status status = ForEachWithPrefix(
       db_.get(), GetSliceFor(key_prefix),
@@ -122,14 +123,14 @@
         kv->value = GetVectorFor(value);
         data.push_back(std::move(kv));
       });
-  callback.Run(LeveldbStatusToError(status), std::move(data));
+  std::move(callback).Run(LeveldbStatusToError(status), std::move(data));
 }
 
-void LevelDBDatabaseImpl::GetSnapshot(const GetSnapshotCallback& callback) {
+void LevelDBDatabaseImpl::GetSnapshot(GetSnapshotCallback callback) {
   const Snapshot* s = db_->GetSnapshot();
   base::UnguessableToken token = base::UnguessableToken::Create();
   snapshot_map_.insert(std::make_pair(token, s));
-  callback.Run(token);
+  std::move(callback).Run(token);
 }
 
 void LevelDBDatabaseImpl::ReleaseSnapshot(
@@ -144,12 +145,12 @@
 void LevelDBDatabaseImpl::GetFromSnapshot(
     const base::UnguessableToken& snapshot,
     const std::vector<uint8_t>& key,
-    const GetCallback& callback) {
+    GetCallback callback) {
   // If the snapshot id is invalid, send back invalid argument
   auto it = snapshot_map_.find(snapshot);
   if (it == snapshot_map_.end()) {
-    callback.Run(mojom::DatabaseError::INVALID_ARGUMENT,
-                 std::vector<uint8_t>());
+    std::move(callback).Run(mojom::DatabaseError::INVALID_ARGUMENT,
+                            std::vector<uint8_t>());
     return;
   }
 
@@ -157,23 +158,24 @@
   leveldb::ReadOptions options;
   options.snapshot = it->second;
   leveldb::Status status = db_->Get(options, GetSliceFor(key), &value);
-  callback.Run(LeveldbStatusToError(status), StdStringToUint8Vector(value));
+  std::move(callback).Run(LeveldbStatusToError(status),
+                          StdStringToUint8Vector(value));
 }
 
-void LevelDBDatabaseImpl::NewIterator(const NewIteratorCallback& callback) {
+void LevelDBDatabaseImpl::NewIterator(NewIteratorCallback callback) {
   Iterator* iterator = db_->NewIterator(leveldb::ReadOptions());
   base::UnguessableToken token = base::UnguessableToken::Create();
   iterator_map_.insert(std::make_pair(token, iterator));
-  callback.Run(token);
+  std::move(callback).Run(token);
 }
 
 void LevelDBDatabaseImpl::NewIteratorFromSnapshot(
     const base::UnguessableToken& snapshot,
-    const NewIteratorFromSnapshotCallback& callback) {
+    NewIteratorFromSnapshotCallback callback) {
   // If the snapshot id is invalid, send back invalid argument
   auto it = snapshot_map_.find(snapshot);
   if (it == snapshot_map_.end()) {
-    callback.Run(base::Optional<base::UnguessableToken>());
+    std::move(callback).Run(base::Optional<base::UnguessableToken>());
     return;
   }
 
@@ -183,7 +185,7 @@
   Iterator* iterator = db_->NewIterator(options);
   base::UnguessableToken new_token = base::UnguessableToken::Create();
   iterator_map_.insert(std::make_pair(new_token, iterator));
-  callback.Run(new_token);
+  std::move(callback).Run(new_token);
 }
 
 void LevelDBDatabaseImpl::ReleaseIterator(
@@ -197,89 +199,88 @@
 
 void LevelDBDatabaseImpl::IteratorSeekToFirst(
     const base::UnguessableToken& iterator,
-    const IteratorSeekToFirstCallback& callback) {
+    IteratorSeekToFirstCallback callback) {
   auto it = iterator_map_.find(iterator);
   if (it == iterator_map_.end()) {
-    callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
-                 base::nullopt);
+    std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT,
+                            base::nullopt, base::nullopt);
     return;
   }
 
   it->second->SeekToFirst();
 
-  ReplyToIteratorMessage(it->second, callback);
+  ReplyToIteratorMessage(it->second, std::move(callback));
 }
 
 void LevelDBDatabaseImpl::IteratorSeekToLast(
     const base::UnguessableToken& iterator,
-    const IteratorSeekToLastCallback& callback) {
+    IteratorSeekToLastCallback callback) {
   auto it = iterator_map_.find(iterator);
   if (it == iterator_map_.end()) {
-    callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
-                 base::nullopt);
+    std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT,
+                            base::nullopt, base::nullopt);
     return;
   }
 
   it->second->SeekToLast();
 
-  ReplyToIteratorMessage(it->second, callback);
+  ReplyToIteratorMessage(it->second, std::move(callback));
 }
 
-void LevelDBDatabaseImpl::IteratorSeek(
-    const base::UnguessableToken& iterator,
-    const std::vector<uint8_t>& target,
-    const IteratorSeekToLastCallback& callback) {
+void LevelDBDatabaseImpl::IteratorSeek(const base::UnguessableToken& iterator,
+                                       const std::vector<uint8_t>& target,
+                                       IteratorSeekToLastCallback callback) {
   auto it = iterator_map_.find(iterator);
   if (it == iterator_map_.end()) {
-    callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
-                 base::nullopt);
+    std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT,
+                            base::nullopt, base::nullopt);
     return;
   }
 
   it->second->Seek(GetSliceFor(target));
 
-  ReplyToIteratorMessage(it->second, callback);
+  ReplyToIteratorMessage(it->second, std::move(callback));
 }
 
 void LevelDBDatabaseImpl::IteratorNext(const base::UnguessableToken& iterator,
-                                       const IteratorNextCallback& callback) {
+                                       IteratorNextCallback callback) {
   auto it = iterator_map_.find(iterator);
   if (it == iterator_map_.end()) {
-    callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
-                 base::nullopt);
+    std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT,
+                            base::nullopt, base::nullopt);
     return;
   }
 
   it->second->Next();
 
-  ReplyToIteratorMessage(it->second, callback);
+  ReplyToIteratorMessage(it->second, std::move(callback));
 }
 
 void LevelDBDatabaseImpl::IteratorPrev(const base::UnguessableToken& iterator,
-                                       const IteratorPrevCallback& callback) {
+                                       IteratorPrevCallback callback) {
   auto it = iterator_map_.find(iterator);
   if (it == iterator_map_.end()) {
-    callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
-                 base::nullopt);
+    std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT,
+                            base::nullopt, base::nullopt);
     return;
   }
 
   it->second->Prev();
 
-  ReplyToIteratorMessage(it->second, callback);
+  ReplyToIteratorMessage(it->second, std::move(callback));
 }
 
 void LevelDBDatabaseImpl::ReplyToIteratorMessage(
     leveldb::Iterator* it,
-    const IteratorSeekToFirstCallback& callback) {
+    IteratorSeekToFirstCallback callback) {
   if (!it->Valid()) {
-    callback.Run(false, LeveldbStatusToError(it->status()), base::nullopt,
-                 base::nullopt);
+    std::move(callback).Run(false, LeveldbStatusToError(it->status()),
+                            base::nullopt, base::nullopt);
     return;
   }
 
-  callback.Run(true, LeveldbStatusToError(it->status()),
-               GetVectorFor(it->key()), GetVectorFor(it->value()));
+  std::move(callback).Run(true, LeveldbStatusToError(it->status()),
+                          GetVectorFor(it->key()), GetVectorFor(it->value()));
 }
 
 leveldb::Status LevelDBDatabaseImpl::DeletePrefixedHelper(
diff --git a/components/leveldb/leveldb_database_impl.h b/components/leveldb/leveldb_database_impl.h
index f621c5f5..277748d4 100644
--- a/components/leveldb/leveldb_database_impl.h
+++ b/components/leveldb/leveldb_database_impl.h
@@ -24,46 +24,44 @@
   // Overridden from LevelDBDatabase:
   void Put(const std::vector<uint8_t>& key,
            const std::vector<uint8_t>& value,
-           const PutCallback& callback) override;
+           PutCallback callback) override;
   void Delete(const std::vector<uint8_t>& key,
-              const DeleteCallback& callback) override;
+              DeleteCallback callback) override;
   void DeletePrefixed(const std::vector<uint8_t>& key_prefix,
-                      const DeletePrefixedCallback& callback) override;
+                      DeletePrefixedCallback callback) override;
   void Write(std::vector<mojom::BatchedOperationPtr> operations,
-             const WriteCallback& callback) override;
-  void Get(const std::vector<uint8_t>& key,
-           const GetCallback& callback) override;
+             WriteCallback callback) override;
+  void Get(const std::vector<uint8_t>& key, GetCallback callback) override;
   void GetPrefixed(const std::vector<uint8_t>& key_prefix,
-                   const GetPrefixedCallback& callback) override;
-  void GetSnapshot(const GetSnapshotCallback& callback) override;
+                   GetPrefixedCallback callback) override;
+  void GetSnapshot(GetSnapshotCallback callback) override;
   void ReleaseSnapshot(const base::UnguessableToken& snapshot) override;
   void GetFromSnapshot(const base::UnguessableToken& snapshot,
                        const std::vector<uint8_t>& key,
-                       const GetCallback& callback) override;
-  void NewIterator(const NewIteratorCallback& callback) override;
+                       GetCallback callback) override;
+  void NewIterator(NewIteratorCallback callback) override;
   void NewIteratorFromSnapshot(
       const base::UnguessableToken& snapshot,
-      const NewIteratorFromSnapshotCallback& callback) override;
+      NewIteratorFromSnapshotCallback callback) override;
   void ReleaseIterator(const base::UnguessableToken& iterator) override;
-  void IteratorSeekToFirst(
-      const base::UnguessableToken& iterator,
-      const IteratorSeekToFirstCallback& callback) override;
+  void IteratorSeekToFirst(const base::UnguessableToken& iterator,
+                           IteratorSeekToFirstCallback callback) override;
   void IteratorSeekToLast(const base::UnguessableToken& iterator,
-                          const IteratorSeekToLastCallback& callback) override;
+                          IteratorSeekToLastCallback callback) override;
   void IteratorSeek(const base::UnguessableToken& iterator,
                     const std::vector<uint8_t>& target,
-                    const IteratorSeekToLastCallback& callback) override;
+                    IteratorSeekToLastCallback callback) override;
   void IteratorNext(const base::UnguessableToken& iterator,
-                    const IteratorNextCallback& callback) override;
+                    IteratorNextCallback callback) override;
   void IteratorPrev(const base::UnguessableToken& iterator,
-                    const IteratorPrevCallback& callback) override;
+                    IteratorPrevCallback callback) override;
 
  private:
   // Returns the state of |it| to a caller. Note: This assumes that all the
   // iterator movement methods have the same callback signature. We don't
   // directly reference the underlying type in case of bindings change.
   void ReplyToIteratorMessage(leveldb::Iterator* it,
-                              const IteratorSeekToFirstCallback& callback);
+                              IteratorSeekToFirstCallback callback);
 
   leveldb::Status DeletePrefixedHelper(const leveldb::Slice& key_prefix,
                                        leveldb::WriteBatch* batch);
diff --git a/components/leveldb/leveldb_service_impl.cc b/components/leveldb/leveldb_service_impl.cc
index 2f754112..f2e4eb85 100644
--- a/components/leveldb/leveldb_service_impl.cc
+++ b/components/leveldb/leveldb_service_impl.cc
@@ -5,6 +5,7 @@
 #include "components/leveldb/leveldb_service_impl.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/memory/ptr_util.h"
 #include "components/leveldb/env_mojo.h"
@@ -30,9 +31,9 @@
     filesystem::mojom::DirectoryPtr directory,
     const std::string& dbname,
     leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
-    const OpenCallback& callback) {
+    OpenCallback callback) {
   OpenWithOptions(leveldb::mojom::OpenOptions::New(), std::move(directory),
-                  dbname, std::move(database), callback);
+                  dbname, std::move(database), std::move(callback));
 }
 
 void LevelDBServiceImpl::OpenWithOptions(
@@ -40,7 +41,7 @@
     filesystem::mojom::DirectoryPtr directory,
     const std::string& dbname,
     leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
-    const OpenCallback& callback) {
+    OpenCallback callback) {
   leveldb::Options options;
   options.create_if_missing = open_options->create_if_missing;
   options.error_if_exists = open_options->error_if_exists;
@@ -68,12 +69,12 @@
         std::move(database));
   }
 
-  callback.Run(LeveldbStatusToError(s));
+  std::move(callback).Run(LeveldbStatusToError(s));
 }
 
 void LevelDBServiceImpl::OpenInMemory(
     leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
-    const OpenCallback& callback) {
+    OpenCallback callback) {
   leveldb::Options options;
   options.create_if_missing = true;
   options.max_open_files = 0;  // Use minimum.
@@ -91,19 +92,20 @@
                                       std::move(database));
   }
 
-  callback.Run(LeveldbStatusToError(s));
+  std::move(callback).Run(LeveldbStatusToError(s));
 }
 
 void LevelDBServiceImpl::Destroy(filesystem::mojom::DirectoryPtr directory,
                                  const std::string& dbname,
-                                 const DestroyCallback& callback) {
+                                 DestroyCallback callback) {
   leveldb::Options options;
   // Register our directory with the file thread.
   LevelDBMojoProxy::OpaqueDir* dir =
       thread_->RegisterDirectory(std::move(directory));
   std::unique_ptr<MojoEnv> env_mojo(new MojoEnv(thread_, dir));
   options.env = env_mojo.get();
-  callback.Run(LeveldbStatusToError(leveldb::DestroyDB(dbname, options)));
+  std::move(callback).Run(
+      LeveldbStatusToError(leveldb::DestroyDB(dbname, options)));
 }
 
 }  // namespace leveldb
diff --git a/components/leveldb/leveldb_service_impl.h b/components/leveldb/leveldb_service_impl.h
index 3cc1210..344168c4 100644
--- a/components/leveldb/leveldb_service_impl.h
+++ b/components/leveldb/leveldb_service_impl.h
@@ -26,18 +26,18 @@
   void Open(filesystem::mojom::DirectoryPtr directory,
             const std::string& dbname,
             leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
-            const OpenCallback& callback) override;
+            OpenCallback callback) override;
   void OpenWithOptions(
       leveldb::mojom::OpenOptionsPtr open_options,
       filesystem::mojom::DirectoryPtr directory,
       const std::string& dbname,
       leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
-      const OpenCallback& callback) override;
+      OpenCallback callback) override;
   void OpenInMemory(leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
-                    const OpenInMemoryCallback& callback) override;
+                    OpenInMemoryCallback callback) override;
   void Destroy(filesystem::mojom::DirectoryPtr directory,
                const std::string& dbname,
-               const DestroyCallback& callback) override;
+               DestroyCallback callback) override;
 
  private:
   // Thread to own the mojo message pipe. Because leveldb spawns multiple
diff --git a/components/leveldb/public/interfaces/BUILD.gn b/components/leveldb/public/interfaces/BUILD.gn
index 514eeb9..317863f 100644
--- a/components/leveldb/public/interfaces/BUILD.gn
+++ b/components/leveldb/public/interfaces/BUILD.gn
@@ -16,4 +16,6 @@
   public_deps = [
     "//mojo/common:common_custom_types",
   ]
+
+  use_once_callback = true
 }
diff --git a/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc b/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc
index c7c99c9..b6802d3 100644
--- a/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc
+++ b/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc
@@ -40,45 +40,45 @@
 
   // CallStackProfileCollectorTest:
   void BounceFrame(const base::StackSamplingProfiler::Frame& in,
-                   const BounceFrameCallback& callback) override {
-    callback.Run(in);
+                   BounceFrameCallback callback) override {
+    std::move(callback).Run(in);
   }
 
   void BounceModule(const base::StackSamplingProfiler::Module& in,
-                    const BounceModuleCallback& callback) override {
-    callback.Run(in);
+                    BounceModuleCallback callback) override {
+    std::move(callback).Run(in);
   }
 
   void BounceProfile(base::StackSamplingProfiler::CallStackProfile in,
-                     const BounceProfileCallback& callback) override {
-    callback.Run(std::move(in));
+                     BounceProfileCallback callback) override {
+    std::move(callback).Run(std::move(in));
   }
 
   void BounceTrigger(CallStackProfileParams::Trigger in,
-                     const BounceTriggerCallback& callback) override {
-    callback.Run(in);
+                     BounceTriggerCallback callback) override {
+    std::move(callback).Run(in);
   }
 
   void BounceProcess(CallStackProfileParams::Process in,
-                     const BounceProcessCallback& callback) override {
-    callback.Run(in);
+                     BounceProcessCallback callback) override {
+    std::move(callback).Run(in);
   }
 
   void BounceThread(CallStackProfileParams::Thread in,
-                    const BounceThreadCallback& callback) override {
-    callback.Run(in);
+                    BounceThreadCallback callback) override {
+    std::move(callback).Run(in);
   }
 
   void BounceSampleOrderingSpec(
       CallStackProfileParams::SampleOrderingSpec in,
-      const BounceSampleOrderingSpecCallback& callback) override {
-    callback.Run(in);
+      BounceSampleOrderingSpecCallback callback) override {
+    std::move(callback).Run(in);
   }
 
   void BounceCallStackProfileParams(
       const CallStackProfileParams& in,
-      const BounceCallStackProfileParamsCallback& callback) override {
-    callback.Run(in);
+      BounceCallStackProfileParamsCallback callback) override {
+    std::move(callback).Run(in);
   }
 
  private:
diff --git a/components/metrics/public/interfaces/BUILD.gn b/components/metrics/public/interfaces/BUILD.gn
index cfe9661..df9ec797 100644
--- a/components/metrics/public/interfaces/BUILD.gn
+++ b/components/metrics/public/interfaces/BUILD.gn
@@ -23,6 +23,8 @@
     ":call_stack_mojo_bindings",
     "//mojo/common:common_custom_types",
   ]
+
+  use_once_callback = true
 }
 
 mojom("single_sample_metrics_mojo_bindings") {
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index 3203837..ee3af7c 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -64,8 +64,8 @@
 
 }  // namespace
 
-const base::Feature kLowReputationPinging{"LowReputationPinging",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPasswordFieldOnFocusPinging{
+    "PasswordFieldOnFocusPinging", base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kProtectedPasswordEntryPinging{
     "ProtectedPasswordEntryPinging", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -221,7 +221,7 @@
     const GURL& password_form_action,
     const GURL& password_form_frame_url) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!IsPingingEnabled(kLowReputationPinging))
+  if (!IsPingingEnabled(kPasswordFieldOnFocusPinging))
     return;
 
   // Skip URLs that we can't get a reliable reputation for.
@@ -317,7 +317,7 @@
   user_population->set_is_history_sync_enabled(IsHistorySyncEnabled());
 
   base::FieldTrial* low_reputation_field_trial =
-      base::FeatureList::GetFieldTrial(kLowReputationPinging);
+      base::FeatureList::GetFieldTrial(kPasswordFieldOnFocusPinging);
   if (low_reputation_field_trial) {
     user_population->add_finch_active_groups(
         low_reputation_field_trial->trial_name() + "|" +
diff --git a/components/safe_browsing/password_protection/password_protection_service.h b/components/safe_browsing/password_protection/password_protection_service.h
index 9963266..e688efc 100644
--- a/components/safe_browsing/password_protection/password_protection_service.h
+++ b/components/safe_browsing/password_protection/password_protection_service.h
@@ -33,7 +33,7 @@
 class SafeBrowsingDatabaseManager;
 class PasswordProtectionRequest;
 
-extern const base::Feature kLowReputationPinging;
+extern const base::Feature kPasswordFieldOnFocusPinging;
 extern const base::Feature kProtectedPasswordEntryPinging;
 
 // Manage password protection pings and verdicts. There is one instance of this
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 308bdc71..b92c30d 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -78,6 +78,7 @@
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/ime/input_method.h"
+#include "ui/base/ui_base_switches.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/compositor/compositor_vsync_manager.h"
 #include "ui/compositor/dip_util.h"
@@ -94,6 +95,7 @@
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/touch_selection/touch_selection_controller.h"
+#include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/public/activation_client.h"
 #include "ui/wm/public/scoped_tooltip_disabler.h"
 #include "ui/wm/public/tooltip_client.h"
@@ -119,6 +121,10 @@
 #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "ui/wm/core/ime_util_chromeos.h"
+#endif
+
 using gfx::RectToSkIRect;
 using gfx::SkIRectToRect;
 
@@ -1281,22 +1287,11 @@
 
 gfx::Rect RenderWidgetHostViewAura::ConvertRectFromScreen(
     const gfx::Rect& rect) const {
-  gfx::Point origin = rect.origin();
-  gfx::Point end = gfx::Point(rect.right(), rect.bottom());
-
-  aura::Window* root_window = window_->GetRootWindow();
-  if (root_window) {
-    aura::client::ScreenPositionClient* screen_position_client =
-        aura::client::GetScreenPositionClient(root_window);
-    screen_position_client->ConvertPointFromScreen(window_, &origin);
-    screen_position_client->ConvertPointFromScreen(window_, &end);
-    return gfx::Rect(origin.x(),
-                     origin.y(),
-                     end.x() - origin.x(),
-                     end.y() - origin.y());
-  }
-
-  return rect;
+  gfx::Rect result = rect;
+  if (window_->GetRootWindow() &&
+      aura::client::GetScreenPositionClient(window_->GetRootWindow()))
+    wm::ConvertRectFromScreen(window_, &result);
+  return result;
 }
 
 gfx::Rect RenderWidgetHostViewAura::GetCaretBounds() const {
@@ -1434,16 +1429,24 @@
     rfh->ExtendSelectionAndDelete(before, after);
 }
 
-void RenderWidgetHostViewAura::EnsureCaretNotInRect(const gfx::Rect& rect) {
-  gfx::Rect rect_in_local_space = ConvertRectFromScreen(rect);
-  gfx::Rect hiding_area_in_this_window =
-      gfx::IntersectRects(rect_in_local_space, window_->bounds());
+void RenderWidgetHostViewAura::EnsureCaretNotInRect(
+    const gfx::Rect& rect_in_screen) {
+  aura::Window* top_level_window = window_->GetToplevelWindow();
+#if defined(OS_CHROMEOS)
+  wm::EnsureWindowNotInRect(top_level_window, rect_in_screen);
+#endif
 
-  if (hiding_area_in_this_window.IsEmpty())
+  // Perform overscroll if the caret is still hidden by the keyboard.
+  const gfx::Rect hidden_window_bounds_in_screen = gfx::IntersectRects(
+      rect_in_screen, top_level_window->GetBoundsInScreen());
+  if (hidden_window_bounds_in_screen.IsEmpty())
     return;
 
-  host_->ScrollFocusedEditableNodeIntoRect(
-      gfx::SubtractRects(window_->bounds(), hiding_area_in_this_window));
+  gfx::Rect visible_area_in_local_space = gfx::SubtractRects(
+      window_->GetBoundsInScreen(), hidden_window_bounds_in_screen);
+  visible_area_in_local_space =
+      ConvertRectFromScreen(visible_area_in_local_space);
+  host_->ScrollFocusedEditableNodeIntoRect(visible_area_in_local_space);
 }
 
 bool RenderWidgetHostViewAura::IsTextEditCommandEnabled(
@@ -2225,8 +2228,12 @@
 
 void RenderWidgetHostViewAura::DetachFromInputMethod() {
   ui::InputMethod* input_method = GetInputMethod();
-  if (input_method)
+  if (input_method) {
     input_method->DetachTextInputClient(this);
+#if defined(OS_CHROMEOS)
+    wm::RestoreWindowBoundsOnClientFocusLost(window_->GetToplevelWindow());
+#endif  // defined(OS_CHROMEOS)
+  }
 }
 
 void RenderWidgetHostViewAura::ForwardKeyboardEvent(
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 1e3d1099..b4a4c994 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -374,6 +374,8 @@
                            FinishCompositionByMouse);
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
                            ForwardsBeginFrameAcks);
+  FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
+                           VirtualKeyboardFocusEnsureCaretInRect);
   FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest,
                            WebContentsViewReparent);
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index adcb5bf6..3694c796 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -83,6 +83,7 @@
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_observer.h"
 #include "ui/base/clipboard/clipboard.h"
+#include "ui/base/ui_base_switches.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/layer_tree_owner.h"
@@ -102,6 +103,10 @@
 #include "ui/wm/core/default_screen_position_client.h"
 #include "ui/wm/core/window_util.h"
 
+#if defined(OS_CHROMEOS)
+#include "ui/base/ime/input_method.h"
+#endif
+
 using testing::_;
 
 using blink::WebGestureEvent;
@@ -4687,6 +4692,56 @@
   EXPECT_EQ(4U, sink_->message_count());
 }
 
+#if defined(OS_CHROMEOS)
+// Check that when accessibility virtual keyboard is enabled, windows are
+// shifted up when focused and restored when focus is lost.
+TEST_F(RenderWidgetHostViewAuraTest, VirtualKeyboardFocusEnsureCaretInRect) {
+  // TODO (oshima): Test that overscroll occurs.
+
+  // Enable new virtual keyboard behavior.
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (!command_line->HasSwitch(::switches::kUseNewVirtualKeyboardBehavior))
+    command_line->AppendSwitch(::switches::kUseNewVirtualKeyboardBehavior);
+
+  view_->InitAsChild(nullptr);
+  aura::client::ParentWindowWithContext(
+      view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
+      gfx::Rect());
+  aura::Window* root_window = parent_view_->GetNativeView()->GetRootWindow();
+  wm::DefaultScreenPositionClient screen_position_client;
+  aura::client::SetScreenPositionClient(root_window, &screen_position_client);
+
+  const gfx::Rect orig_view_bounds = gfx::Rect(0, 300, 400, 200);
+  const gfx::Rect shifted_view_bounds = gfx::Rect(0, 200, 400, 200);
+  const gfx::Rect root_bounds = root_window->bounds();
+  const int keyboard_height = 200;
+  const gfx::Rect keyboard_view_bounds =
+      gfx::Rect(0, root_bounds.height() - keyboard_height, root_bounds.width(),
+                keyboard_height);
+
+  ui::InputMethod* input_method = root_window->GetHost()->GetInputMethod();
+
+  // Focus the window.
+  view_->SetBounds(orig_view_bounds);
+  input_method->SetFocusedTextInputClient(view_);
+  EXPECT_EQ(view_->GetNativeView()->bounds(), orig_view_bounds);
+
+  // Simulate virtual keyboard.
+  input_method->SetOnScreenKeyboardBounds(keyboard_view_bounds);
+
+  // Window should be shifted.
+  EXPECT_EQ(view_->GetNativeView()->bounds(), shifted_view_bounds);
+
+  // Detach the RenderWidgetHostViewAura from the IME.
+  view_->DetachFromInputMethod();
+
+  // Window should be restored.
+  EXPECT_EQ(view_->GetNativeView()->bounds(), orig_view_bounds);
+
+  aura::client::SetScreenPositionClient(root_window, nullptr);
+}
+#endif  // defined(OS_CHROMEOS)
+
 // Tests that when view initiated shutdown happens (i.e. RWHView is deleted
 // before RWH), we clean up properly and don't leak the RWHVGuest.
 TEST_F(RenderWidgetHostViewGuestAuraTest, GuestViewDoesNotLeak) {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 1122904..b2f3540e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1519,6 +1519,7 @@
     "//third_party/widevine/cdm:headers",
     "//ui/accessibility",
     "//ui/base:test_support",
+    "//ui/base/ime",
     "//ui/compositor:test_support",
     "//ui/display",
     "//ui/display:test_support",
diff --git a/content/test/data/media/mediarecorder_test_utils.js b/content/test/data/media/mediarecorder_test_utils.js
index 400b19e..1cec7a7 100644
--- a/content/test/data/media/mediarecorder_test_utils.js
+++ b/content/test/data/media/mediarecorder_test_utils.js
@@ -22,13 +22,13 @@
     console.log('Waiting for', description.toString());
     var check = setInterval(function() {
       var elapsed = new Date() - startTime;
-      if (elapsed > 3000) {
+      if (predicate()) {
+        clearInterval(check);
+        resolve();
+      } else if (elapsed > 3000) {
         startTime = new Date();
         console.log('Still waiting for satisfaction of ' +
             predicate.toString());
-      } else if (predicate()) {
-        clearInterval(check);
-        resolve();
       }
     }, 50);
   });
diff --git a/content/test/mock_leveldb_database.cc b/content/test/mock_leveldb_database.cc
index 60a5db7..83b7d5f2 100644
--- a/content/test/mock_leveldb_database.cc
+++ b/content/test/mock_leveldb_database.cc
@@ -4,6 +4,8 @@
 
 #include "content/test/mock_leveldb_database.h"
 
+#include <utility>
+
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 
@@ -49,28 +51,27 @@
 
 void MockLevelDBDatabase::Put(const std::vector<uint8_t>& key,
                               const std::vector<uint8_t>& value,
-                              const PutCallback& callback) {
+                              PutCallback callback) {
   mock_data_[key] = value;
-  callback.Run(leveldb::mojom::DatabaseError::OK);
+  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
 }
 
 void MockLevelDBDatabase::Delete(const std::vector<uint8_t>& key,
-                                 const DeleteCallback& callback) {
+                                 DeleteCallback callback) {
   mock_data_.erase(key);
-  callback.Run(leveldb::mojom::DatabaseError::OK);
+  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
 }
 
-void MockLevelDBDatabase::DeletePrefixed(
-    const std::vector<uint8_t>& key_prefix,
-    const DeletePrefixedCallback& callback) {
+void MockLevelDBDatabase::DeletePrefixed(const std::vector<uint8_t>& key_prefix,
+                                         DeletePrefixedCallback callback) {
   mock_data_.erase(mock_data_.lower_bound(key_prefix),
                    mock_data_.lower_bound(successor(key_prefix)));
-  callback.Run(leveldb::mojom::DatabaseError::OK);
+  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
 }
 
 void MockLevelDBDatabase::Write(
     std::vector<leveldb::mojom::BatchedOperationPtr> operations,
-    const WriteCallback& callback) {
+    WriteCallback callback) {
   for (const auto& op : operations) {
     switch (op->type) {
       case leveldb::mojom::BatchOperationType::PUT_KEY:
@@ -85,33 +86,31 @@
         break;
     }
   }
-  callback.Run(leveldb::mojom::DatabaseError::OK);
+  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
 }
 
 void MockLevelDBDatabase::Get(const std::vector<uint8_t>& key,
-                              const GetCallback& callback) {
+                              GetCallback callback) {
   if (mock_data_.find(key) != mock_data_.end()) {
-    callback.Run(leveldb::mojom::DatabaseError::OK, mock_data_[key]);
+    std::move(callback).Run(leveldb::mojom::DatabaseError::OK, mock_data_[key]);
   } else {
-    callback.Run(leveldb::mojom::DatabaseError::NOT_FOUND,
-                 std::vector<uint8_t>());
+    std::move(callback).Run(leveldb::mojom::DatabaseError::NOT_FOUND,
+                            std::vector<uint8_t>());
   }
 }
 
-void MockLevelDBDatabase::GetPrefixed(
-    const std::vector<uint8_t>& key_prefix,
-    const GetPrefixedCallback& callback) {
+void MockLevelDBDatabase::GetPrefixed(const std::vector<uint8_t>& key_prefix,
+                                      GetPrefixedCallback callback) {
   std::vector<leveldb::mojom::KeyValuePtr> data;
   for (const auto& row : mock_data_) {
     if (StartsWith(row.first, key_prefix)) {
       data.push_back(CreateKeyValue(row.first, row.second));
     }
   }
-  callback.Run(leveldb::mojom::DatabaseError::OK, std::move(data));
+  std::move(callback).Run(leveldb::mojom::DatabaseError::OK, std::move(data));
 }
 
-void MockLevelDBDatabase::GetSnapshot(
-    const GetSnapshotCallback& callback) {
+void MockLevelDBDatabase::GetSnapshot(GetSnapshotCallback callback) {
   NOTREACHED();
 }
 
@@ -123,18 +122,17 @@
 void MockLevelDBDatabase::GetFromSnapshot(
     const base::UnguessableToken& snapshot,
     const std::vector<uint8_t>& key,
-    const GetCallback& callback) {
+    GetCallback callback) {
   NOTREACHED();
 }
 
-void MockLevelDBDatabase::NewIterator(
-    const NewIteratorCallback& callback) {
+void MockLevelDBDatabase::NewIterator(NewIteratorCallback callback) {
   NOTREACHED();
 }
 
 void MockLevelDBDatabase::NewIteratorFromSnapshot(
     const base::UnguessableToken& snapshot,
-    const NewIteratorFromSnapshotCallback& callback) {
+    NewIteratorFromSnapshotCallback callback) {
   NOTREACHED();
 }
 
@@ -145,32 +143,29 @@
 
 void MockLevelDBDatabase::IteratorSeekToFirst(
     const base::UnguessableToken& iterator,
-    const IteratorSeekToFirstCallback& callback) {
+    IteratorSeekToFirstCallback callback) {
   NOTREACHED();
 }
 
 void MockLevelDBDatabase::IteratorSeekToLast(
     const base::UnguessableToken& iterator,
-    const IteratorSeekToLastCallback& callback) {
+    IteratorSeekToLastCallback callback) {
   NOTREACHED();
 }
 
-void MockLevelDBDatabase::IteratorSeek(
-    const base::UnguessableToken& iterator,
-    const std::vector<uint8_t>& target,
-    const IteratorSeekToLastCallback& callback) {
+void MockLevelDBDatabase::IteratorSeek(const base::UnguessableToken& iterator,
+                                       const std::vector<uint8_t>& target,
+                                       IteratorSeekToLastCallback callback) {
   NOTREACHED();
 }
 
-void MockLevelDBDatabase::IteratorNext(
-    const base::UnguessableToken& iterator,
-    const IteratorNextCallback& callback) {
+void MockLevelDBDatabase::IteratorNext(const base::UnguessableToken& iterator,
+                                       IteratorNextCallback callback) {
   NOTREACHED();
 }
 
-void MockLevelDBDatabase::IteratorPrev(
-    const base::UnguessableToken& iterator,
-    const IteratorPrevCallback& callback) {
+void MockLevelDBDatabase::IteratorPrev(const base::UnguessableToken& iterator,
+                                       IteratorPrevCallback callback) {
   NOTREACHED();
 }
 
diff --git a/content/test/mock_leveldb_database.h b/content/test/mock_leveldb_database.h
index 29a2abd..4d5728d 100644
--- a/content/test/mock_leveldb_database.h
+++ b/content/test/mock_leveldb_database.h
@@ -19,39 +19,37 @@
   // LevelDBDatabase:
   void Put(const std::vector<uint8_t>& key,
            const std::vector<uint8_t>& value,
-           const PutCallback& callback) override;
+           PutCallback callback) override;
   void Delete(const std::vector<uint8_t>& key,
-              const DeleteCallback& callback) override;
+              DeleteCallback callback) override;
   void DeletePrefixed(const std::vector<uint8_t>& key_prefix,
-                      const DeletePrefixedCallback& callback) override;
+                      DeletePrefixedCallback callback) override;
   void Write(std::vector<leveldb::mojom::BatchedOperationPtr> operations,
-             const WriteCallback& callback) override;
-  void Get(const std::vector<uint8_t>& key,
-           const GetCallback& callback) override;
+             WriteCallback callback) override;
+  void Get(const std::vector<uint8_t>& key, GetCallback callback) override;
   void GetPrefixed(const std::vector<uint8_t>& key_prefix,
-                   const GetPrefixedCallback& callback) override;
-  void GetSnapshot(const GetSnapshotCallback& callback) override;
+                   GetPrefixedCallback callback) override;
+  void GetSnapshot(GetSnapshotCallback callback) override;
   void ReleaseSnapshot(const base::UnguessableToken& snapshot) override;
   void GetFromSnapshot(const base::UnguessableToken& snapshot,
                        const std::vector<uint8_t>& key,
-                       const GetCallback& callback) override;
-  void NewIterator(const NewIteratorCallback& callback) override;
+                       GetCallback callback) override;
+  void NewIterator(NewIteratorCallback callback) override;
   void NewIteratorFromSnapshot(
       const base::UnguessableToken& snapshot,
-      const NewIteratorFromSnapshotCallback& callback) override;
+      NewIteratorFromSnapshotCallback callback) override;
   void ReleaseIterator(const base::UnguessableToken& iterator) override;
-  void IteratorSeekToFirst(
-      const base::UnguessableToken& iterator,
-      const IteratorSeekToFirstCallback& callback) override;
+  void IteratorSeekToFirst(const base::UnguessableToken& iterator,
+                           IteratorSeekToFirstCallback callback) override;
   void IteratorSeekToLast(const base::UnguessableToken& iterator,
-                          const IteratorSeekToLastCallback& callback) override;
+                          IteratorSeekToLastCallback callback) override;
   void IteratorSeek(const base::UnguessableToken& iterator,
                     const std::vector<uint8_t>& target,
-                    const IteratorSeekToLastCallback& callback) override;
+                    IteratorSeekToLastCallback callback) override;
   void IteratorNext(const base::UnguessableToken& iterator,
-                    const IteratorNextCallback& callback) override;
+                    IteratorNextCallback callback) override;
   void IteratorPrev(const base::UnguessableToken& iterator,
-                    const IteratorPrevCallback& callback) override;
+                    IteratorPrevCallback callback) override;
 
  private:
   std::map<std::vector<uint8_t>, std::vector<uint8_t>>& mock_data_;
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 334f3f4..d2e23090 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -24,7 +24,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chromeos/login/login_state.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/browser_side_navigation_policy.h"
@@ -72,6 +71,10 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/login/login_state.h"
+#endif  // defined(OS_CHROMEOS)
+
 using content::BrowserThread;
 using content::ResourceRequestInfo;
 using extension_web_request_api_helpers::ExtraInfoSpec;
diff --git a/extensions/browser/api/web_request/web_request_permissions.cc b/extensions/browser/api/web_request/web_request_permissions.cc
index 8b2f2f4..22dcaf58 100644
--- a/extensions/browser/api/web_request/web_request_permissions.cc
+++ b/extensions/browser/api/web_request/web_request_permissions.cc
@@ -7,7 +7,6 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "chromeos/login/login_state.h"
 #include "content/public/browser/resource_request_info.h"
 #include "extensions/browser/extension_navigation_ui_data.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
@@ -20,6 +19,10 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/login/login_state.h"
+#endif  // defined(OS_CHROMEOS)
+
 using content::ResourceRequestInfo;
 using extensions::PermissionsData;
 
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
index 113d24f..4e28b1c 100644
--- a/ios/chrome/browser/tabs/BUILD.gn
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -33,8 +33,6 @@
 
 source_set("tabs_internal") {
   sources = [
-    "tab.h",
-    "tab.mm",
     "tab_model.mm",
     "tab_model_synced_window_delegate.mm",
     "tab_model_synced_window_delegate_getter.mm",
@@ -124,6 +122,8 @@
 source_set("tabs_internal_arc") {
   sources = [
     "legacy_tab_helper.mm",
+    "tab.h",
+    "tab.mm",
     "tab_helper_util.mm",
     "tab_model_closing_web_state_observer.h",
     "tab_model_closing_web_state_observer.mm",
@@ -142,34 +142,82 @@
   deps = [
     ":tabs",
     "//base",
+    "//components/content_settings/core/browser",
+    "//components/favicon/core",
     "//components/favicon/ios",
+    "//components/google/core/browser",
     "//components/history/core/browser",
     "//components/history/ios/browser",
+    "//components/infobars/core",
     "//components/keyed_service/core",
+    "//components/metrics_services_manager",
+    "//components/navigation_metrics",
+    "//components/prefs",
+    "//components/reading_list/core",
+    "//components/search_engines",
     "//components/sessions",
+    "//components/signin/core/browser",
     "//components/signin/ios/browser",
+    "//components/strings",
+    "//components/url_formatter",
+    "//ios/chrome/app/strings",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/autofill:autofill_internal",
     "//ios/chrome/browser/bookmarks",
     "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/content_settings",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/find_in_page",
+    "//ios/chrome/browser/geolocation:geolocation_internal",
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/metrics",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/native_app_launcher:native_app_launcher_internal",
+    "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/passwords:passwords_internal",
     "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/sessions:serialisation",
     "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/signin:signin_internal",
+    "//ios/chrome/browser/snapshots",
+    "//ios/chrome/browser/snapshots:snapshots_internal",
     "//ios/chrome/browser/ssl",
     "//ios/chrome/browser/store_kit",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/translate",
+    "//ios/chrome/browser/u2f",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/downloads",
+    "//ios/chrome/browser/ui/overscroll_actions",
+    "//ios/chrome/browser/ui/reader_mode",
+    "//ios/chrome/browser/ui/sad_tab",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web",
+    "//ios/chrome/browser/web:sad_tab_tab_helper_delegate",
     "//ios/chrome/browser/web:web_internal",
     "//ios/chrome/browser/web_state_list",
+    "//ios/net",
     "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/native_app_launcher",
     "//ios/web",
+    "//ios/web:user_agent",
+    "//net",
+    "//ui/base",
     "//url",
   ]
-  libs = [ "Foundation.framework" ]
+  libs = [
+    "CoreLocation.framework",
+    "Foundation.framework",
+    "UIKit.framework",
+  ]
   configs += [ "//build/config/compiler:enable_arc" ]
 }
 
diff --git a/ios/chrome/browser/tabs/tab.h b/ios/chrome/browser/tabs/tab.h
index 43091fc..075f848 100644
--- a/ios/chrome/browser/tabs/tab.h
+++ b/ios/chrome/browser/tabs/tab.h
@@ -113,7 +113,7 @@
 @property(nonatomic, readonly) const GURL& visibleURL;
 
 // The Passkit Dialog provider used to show the UI to download a passkit object.
-@property(nonatomic, assign) id<PassKitDialogProvider> passKitDialogProvider;
+@property(nonatomic, weak) id<PassKitDialogProvider> passKitDialogProvider;
 
 // The current title of the tab.
 @property(nonatomic, readonly) NSString* title;
@@ -133,27 +133,27 @@
 @property(nonatomic, readonly) web::WebState* webState;
 
 @property(nonatomic, readonly) CRWWebController* webController;
+
+// Handles saving and autofill of passwords.
 @property(nonatomic, readonly) PasswordController* passwordController;
 @property(nonatomic, readonly) BOOL canGoBack;
 @property(nonatomic, readonly) BOOL canGoForward;
-@property(nonatomic, assign) id<TabDelegate> delegate;
-@property(nonatomic, assign) id<TabHeadersDelegate> tabHeadersDelegate;
-@property(nonatomic, assign) id<TabSnapshottingDelegate>
-    tabSnapshottingDelegate;
+@property(nonatomic, weak) id<TabDelegate> delegate;
+@property(nonatomic, weak) id<TabHeadersDelegate> tabHeadersDelegate;
+@property(nonatomic, weak) id<TabSnapshottingDelegate> tabSnapshottingDelegate;
 @property(nonatomic, readonly) id<FindInPageControllerDelegate>
     findInPageControllerDelegate;
 
 // Whether or not desktop user agent is used for the currently visible page.
 @property(nonatomic, readonly) BOOL usesDesktopUserAgent;
 
-@property(nonatomic, assign) id<FullScreenControllerDelegate>
+@property(nonatomic, weak) id<FullScreenControllerDelegate>
     fullScreenControllerDelegate;
 @property(nonatomic, readonly)
     OverscrollActionsController* overscrollActionsController;
-@property(nonatomic, assign) id<OverscrollActionsControllerDelegate>
+@property(nonatomic, weak) id<OverscrollActionsControllerDelegate>
     overscrollActionsControllerDelegate;
-@property(nonatomic, assign) id<SnapshotOverlayProvider>
-    snapshotOverlayProvider;
+@property(nonatomic, weak) id<SnapshotOverlayProvider> snapshotOverlayProvider;
 
 // Delegate used to show HTTP Authentication dialogs.
 @property(nonatomic, weak) id<TabDialogDelegate> dialogDelegate;
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index 0162ee0..56df201 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -12,13 +12,11 @@
 
 #include "base/bind.h"
 #include "base/ios/block_types.h"
-#import "base/ios/weak_nsobject.h"
 #include "base/json/string_escape.h"
 #include "base/logging.h"
 #include "base/mac/bind_objc_block.h"
 #include "base/mac/foundation_util.h"
-#include "base/mac/objc_property_releaser.h"
-#include "base/mac/scoped_nsobject.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
@@ -144,9 +142,9 @@
 #include "ui/base/page_transition_types.h"
 #include "url/origin.h"
 
-using base::UserMetricsAction;
-using web::NavigationManagerImpl;
-using net::RequestTracker;
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
 
 NSString* const kTabUrlStartedLoadingNotificationForCrashReporting =
     @"kTabUrlStartedLoadingNotificationForCrashReporting";
@@ -204,17 +202,27 @@
   return (ui::PageTransition::PAGE_TRANSITION_IS_REDIRECT_MASK &
           item->GetTransitionType()) == 0;
 }
+
+// TabHistoryContext is used by history to scope the lifetime of navigation
+// entry references to Tab.
+class TabHistoryContext : public history::Context {
+ public:
+  TabHistoryContext() {}
+  ~TabHistoryContext() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TabHistoryContext);
+};
 }  // namespace
 
 @interface Tab ()<CRWWebStateObserver,
                   CRWWebControllerObserver,
                   FindInPageControllerDelegate,
                   ReaderModeControllerDelegate> {
-  TabModel* parentTabModel_;               // weak
-  ios::ChromeBrowserState* browserState_;  // weak
+  __weak TabModel* parentTabModel_;
+  ios::ChromeBrowserState* browserState_;
 
-  base::scoped_nsobject<OpenInController> openInController_;
-  base::WeakNSProtocol<id<PassKitDialogProvider>> passKitDialogProvider_;
+  OpenInController* openInController_;
 
   // Whether or not this tab is currently being displayed.
   BOOL visible_;
@@ -237,69 +245,41 @@
   // Last visited timestamp.
   double lastVisitedTimestamp_;
 
-  base::mac::ObjCPropertyReleaser propertyReleaser_Tab_;
-
-  id<TabDelegate> delegate_;  // weak
-  base::WeakNSProtocol<id<TabDialogDelegate>> dialogDelegate_;
-  base::WeakNSProtocol<id<SnapshotOverlayProvider>> snapshotOverlayProvider_;
-
-  // Delegate used for snapshotting geometry.
-  id<TabSnapshottingDelegate> tabSnapshottingDelegate_;  // weak
-
   // The Full Screen Controller responsible for hiding/showing the toolbar.
-  base::scoped_nsobject<FullScreenController> fullScreenController_;
-
-  // The delegate responsible for headers over the tab.
-  id<TabHeadersDelegate> tabHeadersDelegate_;  // weak
-
-  base::WeakNSProtocol<id<FullScreenControllerDelegate>>
-      fullScreenControllerDelegate_;
+  FullScreenController* fullScreenController_;
 
   // The Overscroll controller responsible for displaying the
   // overscrollActionsView above the toolbar.
-  base::scoped_nsobject<OverscrollActionsController>
-      overscrollActionsController_;
-  base::WeakNSProtocol<id<OverscrollActionsControllerDelegate>>
-      overscrollActionsControllerDelegate_;
-
-  base::scoped_nsobject<NSString> tabId_;
+  OverscrollActionsController* overscrollActionsController_;
 
   // Lightweight object dealing with various different UI behaviours when
   // opening a URL in an external application.
-  base::scoped_nsobject<ExternalAppLauncher> externalAppLauncher_;
+  ExternalAppLauncher* externalAppLauncher_;
 
   // Handles suggestions for form entry.
-  base::scoped_nsobject<FormSuggestionController> suggestionController_;
+  FormSuggestionController* suggestionController_;
 
   // Manages the input accessory view during form input.
-  base::scoped_nsobject<FormInputAccessoryViewController>
-      inputAccessoryViewController_;
-
-  // TODO(crbug.com/661665): move the WebContentsObservers into their own
-  // container.
-  // Handles saving and autofill of passwords.
-  base::scoped_nsobject<PasswordController> passwordController_;
+  FormInputAccessoryViewController* inputAccessoryViewController_;
 
   // Handles autofill.
-  base::scoped_nsobject<AutofillController> autofillController_;
+  AutofillController* autofillController_;
 
   // Handles GAL infobar on web pages.
-  base::scoped_nsobject<NativeAppNavigationController>
-      nativeAppNavigationController_;
+  NativeAppNavigationController* nativeAppNavigationController_;
 
   // Handles caching and retrieving of snapshots.
-  base::scoped_nsobject<SnapshotManager> snapshotManager_;
+  SnapshotManager* snapshotManager_;
 
   // Handles retrieving, generating and updating snapshots of CRWWebController's
   // web page.
-  base::scoped_nsobject<WebControllerSnapshotHelper>
-      webControllerSnapshotHelper_;
+  WebControllerSnapshotHelper* webControllerSnapshotHelper_;
 
   // Handles support for window.print JavaScript calls.
   std::unique_ptr<PrintObserver> printObserver_;
 
   // AutoReloadBridge for this tab.
-  base::scoped_nsobject<AutoReloadBridge> autoReloadBridge_;
+  AutoReloadBridge* autoReloadBridge_;
 
   // WebStateImpl for this tab.
   web::WebStateImpl* webStateImpl_;
@@ -309,16 +289,13 @@
 
   // Context used by history to scope the lifetime of navigation entry
   // references to Tab.
-  std::unique_ptr<TabHistoryContext> tabHistoryContext_;
-
-  // The controller for everything related to reader mode.
-  base::scoped_nsobject<ReaderModeController> readerModeController_;
+  TabHistoryContext tabHistoryContext_;
 
   // C++ bridge that receives notifications from the FaviconDriver.
   std::unique_ptr<FaviconDriverObserverBridge> faviconDriverObserverBridge_;
 
   // U2F call controller object.
-  base::scoped_nsobject<U2FController> U2FController_;
+  U2FController* U2FController_;
 
   // C++ observer used to trigger snapshots after the removal of InfoBars.
   std::unique_ptr<TabInfoBarObserver> tabInfoBarObserver_;
@@ -367,17 +344,6 @@
 @end
 
 namespace {
-// TabHistoryContext is used by history to scope the lifetime of navigation
-// entry references to Tab.
-class TabHistoryContext : public history::Context {
- public:
-  TabHistoryContext() {}
-  ~TabHistoryContext() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TabHistoryContext);
-};
-
 class FaviconDriverObserverBridge : public favicon::FaviconDriverObserver {
  public:
   FaviconDriverObserverBridge(Tab* owner,
@@ -392,7 +358,7 @@
                         const gfx::Image& image) override;
 
  private:
-  Tab* owner_;  // Owns this instance.
+  __weak Tab* owner_;
   ScopedObserver<favicon::FaviconDriver, favicon::FaviconDriverObserver>
       scoped_observer_;
   DISALLOW_COPY_AND_ASSIGN(FaviconDriverObserverBridge);
@@ -428,7 +394,7 @@
                          infobars::InfoBar* new_infobar) override;
 
  private:
-  Tab* owner_;  // Owns this instance;
+  __weak Tab* owner_;
   ScopedObserver<infobars::InfoBarManager, TabInfoBarObserver> scoped_observer_;
   DISALLOW_COPY_AND_ASSIGN(TabInfoBarObserver);
 };
@@ -473,27 +439,33 @@
 @implementation Tab
 
 @synthesize browserState = browserState_;
+@synthesize tabId = tabId_;
 @synthesize useGreyImageCache = useGreyImageCache_;
 @synthesize isPrerenderTab = isPrerenderTab_;
 @synthesize isLinkLoadingPrerenderTab = isLinkLoadingPrerenderTab_;
 @synthesize isVoiceSearchResultsTab = isVoiceSearchResultsTab_;
+@synthesize passwordController = passwordController_;
+@synthesize overscrollActionsController = overscrollActionsController_;
+@synthesize readerModeController = readerModeController_;
+@synthesize overscrollActionsControllerDelegate =
+    overscrollActionsControllerDelegate_;
+@synthesize passKitDialogProvider = passKitDialogProvider_;
 @synthesize delegate = delegate_;
+@synthesize dialogDelegate = dialogDelegate_;
+@synthesize snapshotOverlayProvider = snapshotOverlayProvider_;
 @synthesize tabSnapshottingDelegate = tabSnapshottingDelegate_;
 @synthesize tabHeadersDelegate = tabHeadersDelegate_;
+@synthesize fullScreenControllerDelegate = fullScreenControllerDelegate_;
 
 - (instancetype)initWithWebState:(web::WebState*)webState {
   DCHECK(webState);
   self = [super init];
   if (self) {
-    propertyReleaser_Tab_.Init(self, [Tab class]);
-
     // TODO(crbug.com/620465): Tab should only use public API of WebState.
     // Remove this cast once this is the case.
     webStateImpl_ = static_cast<web::WebStateImpl*>(webState);
     browserState_ =
         ios::ChromeBrowserState::FromBrowserState(webState->GetBrowserState());
-
-    tabHistoryContext_ = base::MakeUnique<TabHistoryContext>();
     webStateObserver_ =
         base::MakeUnique<web::WebStateObserverBridge>(webState, self);
 
@@ -501,10 +473,10 @@
     [[self webController] addObserver:self];
     [[self webController] setDelegate:self];
 
-    snapshotManager_.reset([[SnapshotManager alloc] init]);
-    webControllerSnapshotHelper_.reset([[WebControllerSnapshotHelper alloc]
+    snapshotManager_ = [[SnapshotManager alloc] init];
+    webControllerSnapshotHelper_ = [[WebControllerSnapshotHelper alloc]
         initWithSnapshotManager:snapshotManager_
-                            tab:self]);
+                            tab:self];
 
     if (experimental_flags::IsNativeAppLauncherEnabled())
       [self initNativeAppNavigationController];
@@ -519,40 +491,39 @@
 }
 
 - (void)attachTabHelpers {
-  tabInfoBarObserver_.reset(new TabInfoBarObserver(self));
+  tabInfoBarObserver_ = base::MakeUnique<TabInfoBarObserver>(self);
   tabInfoBarObserver_->SetShouldObserveInfoBarManager(true);
 
-  if (experimental_flags::IsAutoReloadEnabled()) {
-    autoReloadBridge_.reset([[AutoReloadBridge alloc] initWithTab:self]);
-  }
+  if (experimental_flags::IsAutoReloadEnabled())
+    autoReloadBridge_ = [[AutoReloadBridge alloc] initWithTab:self];
   printObserver_ = base::MakeUnique<PrintObserver>(self.webState);
 
-  base::scoped_nsprotocol<id<PasswordsUiDelegate>> passwordsUiDelegate(
-      [[PasswordsUiDelegateImpl alloc] init]);
-  passwordController_.reset([[PasswordController alloc]
-         initWithWebState:self.webState
-      passwordsUiDelegate:passwordsUiDelegate]);
+  id<PasswordsUiDelegate> passwordsUiDelegate =
+      [[PasswordsUiDelegateImpl alloc] init];
+  passwordController_ =
+      [[PasswordController alloc] initWithWebState:self.webState
+                               passwordsUiDelegate:passwordsUiDelegate];
   password_manager::PasswordGenerationManager* passwordGenerationManager =
       [passwordController_ passwordGenerationManager];
-  autofillController_.reset([[AutofillController alloc]
-           initWithBrowserState:browserState_
-      passwordGenerationManager:passwordGenerationManager
-                       webState:self.webState]);
-  suggestionController_.reset([[FormSuggestionController alloc]
+  autofillController_ =
+      [[AutofillController alloc] initWithBrowserState:browserState_
+                             passwordGenerationManager:passwordGenerationManager
+                                              webState:self.webState];
+  suggestionController_ = [[FormSuggestionController alloc]
       initWithWebState:self.webState
-             providers:[self suggestionProviders]]);
-  inputAccessoryViewController_.reset([[FormInputAccessoryViewController alloc]
+             providers:[self suggestionProviders]];
+  inputAccessoryViewController_ = [[FormInputAccessoryViewController alloc]
       initWithWebState:self.webState
-             providers:[self accessoryViewProviders]]);
+             providers:[self accessoryViewProviders]];
 
   [self setShouldObserveFaviconChanges:YES];
 
   // Create the ReaderModeController immediately so it can register for
   // WebState changes.
   if (experimental_flags::IsReaderModeEnabled()) {
-    readerModeController_.reset([[ReaderModeController alloc]
-        initWithWebState:self.webState
-                delegate:self]);
+    readerModeController_ =
+        [[ReaderModeController alloc] initWithWebState:self.webState
+                                              delegate:self];
   }
 }
 
@@ -604,10 +575,6 @@
   return [self.webController loadPhase] == web::PAGE_LOADED;
 }
 
-- (void)setDialogDelegate:(id<TabDialogDelegate>)dialogDelegate {
-  dialogDelegate_.reset(dialogDelegate);
-}
-
 - (void)setIsVoiceSearchResultsTab:(BOOL)isVoiceSearchResultsTab {
   // There is intentionally no equality check in this setter, as we want the
   // notificaiton to be sent regardless of whether the value has changed.
@@ -615,10 +582,6 @@
   [parentTabModel_ notifyTabChanged:self];
 }
 
-- (PasswordController*)passwordController {
-  return passwordController_.get();
-}
-
 - (void)retrieveSnapshot:(void (^)(UIImage*))callback {
   [webControllerSnapshotHelper_
       retrieveSnapshotForWebController:self.webController
@@ -671,7 +634,7 @@
 
 - (NSString*)tabId {
   if (tabId_)
-    return tabId_.get();
+    return tabId_;
 
   DCHECK(self.webState);
   web::SerializableUserDataManager* userDataManager =
@@ -684,8 +647,8 @@
     userDataManager->AddSerializableData(tabId, kTabIDKey);
   }
 
-  tabId_.reset([tabId copy]);
-  return tabId_.get();
+  tabId_ = [tabId copy];
+  return tabId_;
 }
 
 - (web::WebState*)webState {
@@ -699,9 +662,8 @@
 
   favicon::FaviconDriver* faviconDriver =
       favicon::WebFaviconDriver::FromWebState(self.webState);
-  if (faviconDriver) {
+  if (faviconDriver)
     faviconDriver->FetchFavicon(url);
-  }
 }
 
 - (void)setFavicon:(const gfx::Image*)image {
@@ -728,9 +690,8 @@
 
 - (UIView*)view {
   // Record reload of previously-evicted tab.
-  if (![self.webController isViewAlive] && [parentTabModel_ tabUsageRecorder]) {
+  if (![self.webController isViewAlive] && [parentTabModel_ tabUsageRecorder])
     [parentTabModel_ tabUsageRecorder]->RecordPageLoadStart(self);
-  }
   return self.webState ? self.webState->GetView() : nil;
 }
 
@@ -770,10 +731,10 @@
   if (fullScreenController_) {
     [fullScreenController_ invalidate];
     [self.webController removeObserver:fullScreenController_];
-    fullScreenController_.reset([[FullScreenController alloc]
+    fullScreenController_ = [[FullScreenController alloc]
          initWithDelegate:fullScreenControllerDelegate_
         navigationManager:self.navigationManager
-                sessionID:self.tabId]);
+                sessionID:self.tabId];
     [self.webController addObserver:fullScreenController_];
     // If the content of the page was loaded without knowledge of the
     // toolbar position it will be misplaced under the toolbar instead of
@@ -817,23 +778,18 @@
   [self countMainFrameLoad];
 }
 
-- (id<FullScreenControllerDelegate>)fullScreenControllerDelegate {
-  return fullScreenControllerDelegate_.get();
-}
-
 - (void)setFullScreenControllerDelegate:
     (id<FullScreenControllerDelegate>)fullScreenControllerDelegate {
-  if (fullScreenControllerDelegate == fullScreenControllerDelegate_) {
+  if (fullScreenControllerDelegate == fullScreenControllerDelegate_)
     return;
-  }
   // Lazily create a FullScreenController.
   // The check for fullScreenControllerDelegate is necessary to avoid recreating
   // a FullScreenController during teardown.
   if (!fullScreenController_ && fullScreenControllerDelegate) {
-    fullScreenController_.reset([[FullScreenController alloc]
+    fullScreenController_ = [[FullScreenController alloc]
          initWithDelegate:fullScreenControllerDelegate
         navigationManager:self.navigationManager
-                sessionID:self.tabId]);
+                sessionID:self.tabId];
     [self.webController addObserver:fullScreenController_];
     // If the content of the page was loaded without knowledge of the
     // toolbar position it will be misplaced under the toolbar instead of
@@ -841,41 +797,31 @@
     // sure the content is moved to the right place.
     [fullScreenController_ moveContentBelowHeader];
   }
-  fullScreenControllerDelegate_.reset(fullScreenControllerDelegate);
-}
-
-- (OverscrollActionsController*)overscrollActionsController {
-  return overscrollActionsController_.get();
-}
-
-- (id<OverscrollActionsControllerDelegate>)overscrollActionsControllerDelegate {
-  return overscrollActionsControllerDelegate_.get();
+  fullScreenControllerDelegate_ = fullScreenControllerDelegate;
 }
 
 - (void)setOverscrollActionsControllerDelegate:
     (id<OverscrollActionsControllerDelegate>)
         overscrollActionsControllerDelegate {
   if (overscrollActionsControllerDelegate_ ==
-      overscrollActionsControllerDelegate)
+      overscrollActionsControllerDelegate) {
     return;
+  }
 
   // Lazily create a OverscrollActionsController.
   // The check for overscrollActionsControllerDelegate is necessary to avoid
   // recreating a OverscrollActionsController during teardown.
   if (!overscrollActionsController_) {
-    overscrollActionsController_.reset(
-        [[OverscrollActionsController alloc] init]);
+    overscrollActionsController_ = [[OverscrollActionsController alloc] init];
     [self.webController addObserver:overscrollActionsController_];
   }
   OverscrollStyle style = OverscrollStyle::REGULAR_PAGE_NON_INCOGNITO;
-  if (browserState_->IsOffTheRecord()) {
+  if (browserState_->IsOffTheRecord())
     style = OverscrollStyle::REGULAR_PAGE_INCOGNITO;
-  }
   [overscrollActionsController_ setStyle:style];
   [overscrollActionsController_
       setDelegate:overscrollActionsControllerDelegate];
-  overscrollActionsControllerDelegate_.reset(
-      overscrollActionsControllerDelegate);
+  overscrollActionsControllerDelegate_ = overscrollActionsControllerDelegate;
 }
 
 - (void)saveTitleToHistoryDB {
@@ -885,8 +831,9 @@
   // Don't update the history if current entry has no title.
   NSString* title = [self title];
   if (![title length] ||
-      [title isEqualToString:l10n_util::GetNSString(IDS_DEFAULT_TAB_TITLE)])
+      [title isEqualToString:l10n_util::GetNSString(IDS_DEFAULT_TAB_TITLE)]) {
     return;
+  }
 
   history::HistoryService* historyService =
       ios::HistoryServiceFactory::GetForBrowserState(
@@ -952,12 +899,12 @@
         referrer.url != GURL(kChromeContentSuggestionsReferrer);
 
     history::HistoryAddPageArgs args(
-        url, item->GetTimestamp(), tabHistoryContext_.get(),
-        item->GetUniqueID(), referrer.url, redirects, item->GetTransitionType(),
+        url, item->GetTimestamp(), &tabHistoryContext_, item->GetUniqueID(),
+        referrer.url, redirects, item->GetTransitionType(),
         history::SOURCE_BROWSED, false, consider_for_ntp_most_visited);
     addPageVector_.push_back(args);
   } else {
-    historyService->AddPage(url, item->GetTimestamp(), tabHistoryContext_.get(),
+    historyService->AddPage(url, item->GetTimestamp(), &tabHistoryContext_,
                             item->GetUniqueID(), referrer.url, redirects,
                             item->GetTransitionType(), history::SOURCE_BROWSED,
                             false);
@@ -1005,7 +952,7 @@
   if (!initialNavigation && !isPrerenderTab_ &&
       !PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD) &&
       (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) == 0) {
-    base::RecordAction(UserMetricsAction("MobileTabClobbered"));
+    base::RecordAction(base::UserMetricsAction("MobileTabClobbered"));
   }
   if ([parentTabModel_ tabUsageRecorder])
     [parentTabModel_ tabUsageRecorder]->RecordPageLoadStart(self);
@@ -1034,9 +981,8 @@
 }
 
 - (void)webWillReload {
-  if ([parentTabModel_ tabUsageRecorder]) {
+  if ([parentTabModel_ tabUsageRecorder])
     [parentTabModel_ tabUsageRecorder]->RecordReload(self);
-  }
 }
 
 // Halt the tab, which amounts to halting its webController.
@@ -1054,24 +1000,24 @@
   [[NSNotificationCenter defaultCenter] removeObserver:self];
 
   [passwordController_ detach];
-  passwordController_.reset();
+  passwordController_ = nil;
   tabInfoBarObserver_.reset();
 
   faviconDriverObserverBridge_.reset();
   [openInController_ detachFromWebController];
-  openInController_.reset();
+  openInController_ = nil;
   [autofillController_ detachFromWebState];
   [suggestionController_ detachFromWebState];
   if (fullScreenController_)
     [self.webController removeObserver:fullScreenController_];
   [fullScreenController_ invalidate];
-  fullScreenController_.reset();
+  fullScreenController_ = nil;
   if (overscrollActionsController_)
     [self.webController removeObserver:overscrollActionsController_];
   [overscrollActionsController_ invalidate];
-  overscrollActionsController_.reset();
+  overscrollActionsController_ = nil;
   [readerModeController_ detachFromWebState];
-  readerModeController_.reset();
+  readerModeController_ = nil;
 
   // Invalidate any snapshot stored for this session.
   DCHECK(self.tabId);
@@ -1100,8 +1046,8 @@
         favicon::WebFaviconDriver::FromWebState(self.webState);
     // Some MockWebContents used in tests do not support the FaviconDriver.
     if (faviconDriver) {
-      faviconDriverObserverBridge_.reset(
-          new FaviconDriverObserverBridge(self, faviconDriver));
+      faviconDriverObserverBridge_ =
+          base::MakeUnique<FaviconDriverObserverBridge>(self, faviconDriver);
     }
   } else {
     faviconDriverObserverBridge_.reset();
@@ -1111,7 +1057,7 @@
 - (void)goBack {
   if (self.navigationManager) {
     DCHECK(self.navigationManager->CanGoBack());
-    base::RecordAction(UserMetricsAction("Back"));
+    base::RecordAction(base::UserMetricsAction("Back"));
     self.navigationManager->GoBack();
   }
 }
@@ -1119,7 +1065,7 @@
 - (void)goForward {
   if (self.navigationManager) {
     DCHECK(self.navigationManager->CanGoForward());
-    base::RecordAction(UserMetricsAction("Forward"));
+    base::RecordAction(base::UserMetricsAction("Forward"));
     self.navigationManager->GoForward();
   }
 }
@@ -1147,21 +1093,16 @@
 - (BOOL)openExternalURL:(const GURL&)url
               sourceURL:(const GURL&)sourceURL
             linkClicked:(BOOL)linkClicked {
-  if (!externalAppLauncher_.get())
-    externalAppLauncher_.reset([[ExternalAppLauncher alloc] init]);
-
-  // This method may release CRWWebController which may cause a crash
-  // (crbug.com/393949).
-  [[self.webController retain] autorelease];
+  if (!externalAppLauncher_)
+    externalAppLauncher_ = [[ExternalAppLauncher alloc] init];
 
   // Make a local url copy for possible modification.
   GURL finalURL = url;
 
   // Check if it's a direct FIDO U2F x-callback call. If so, do not open it, to
   // prevent pages from spoofing requests with different origins.
-  if (finalURL.SchemeIs("u2f-x-callback")) {
+  if (finalURL.SchemeIs("u2f-x-callback"))
     return NO;
-  }
 
   // Block attempts to open this application's settings in the native system
   // settings application.
@@ -1171,9 +1112,8 @@
   // Check if it's a FIDO U2F call.
   if (finalURL.SchemeIs("u2f")) {
     // Create U2FController object lazily.
-    if (!U2FController_) {
-      U2FController_.reset([[U2FController alloc] init]);
-    }
+    if (!U2FController_)
+      U2FController_ = [[U2FController alloc] init];
 
     DCHECK([self navigationManager]);
     GURL origin =
@@ -1185,9 +1125,8 @@
                                                 tabURL:self.url
                                                  tabID:self.tabId];
 
-    if (!finalURL.is_valid()) {
+    if (!finalURL.is_valid())
       return NO;
-    }
   }
 
   if ([externalAppLauncher_ openURL:finalURL linkClicked:linkClicked]) {
@@ -1202,9 +1141,8 @@
     if (sourceURL.is_valid()) {
       ReadingListModel* model =
           ReadingListModelFactory::GetForBrowserState(browserState_);
-      if (model && model->loaded()) {
+      if (model && model->loaded())
         model->SetReadStatus(sourceURL, true);
-      }
     }
 
     return YES;
@@ -1215,11 +1153,10 @@
 - (void)webState:(web::WebState*)webState
     didFinishNavigation:(web::NavigationContext*)navigation {
   if (navigation->IsSameDocument()) {
+    // Fetch the favicon for the new URL.
     auto* faviconDriver = favicon::WebFaviconDriver::FromWebState(webState);
-    if (faviconDriver) {
-      // Fetch the favicon for the new URL.
+    if (faviconDriver)
       faviconDriver->FetchFavicon(navigation->GetUrl());
-    }
   }
 
   if (!navigation->IsErrorPage()) {
@@ -1250,18 +1187,18 @@
 
 - (OpenInController*)openInController {
   if (!openInController_) {
-    openInController_.reset([[OpenInController alloc]
+    openInController_ = [[OpenInController alloc]
         initWithRequestContext:browserState_->GetRequestContext()
-                 webController:self.webController]);
+                 webController:self.webController];
   }
-  return openInController_.get();
+  return openInController_;
 }
 
 - (id<CRWNativeContent>)controllerForUnhandledContentAtURL:(const GURL&)url {
   // Shows download manager UI for unhandled content.
   DownloadManagerController* downloadController =
-      [[[DownloadManagerController alloc] initWithWebState:self.webState
-                                               downloadURL:url] autorelease];
+      [[DownloadManagerController alloc] initWithWebState:self.webState
+                                              downloadURL:url];
   [downloadController start];
   return downloadController;
 }
@@ -1294,22 +1231,21 @@
 }
 
 - (void)countMainFrameLoad {
-  if ([self isPrerenderTab] || [self url].SchemeIs(kChromeUIScheme)) {
+  if ([self isPrerenderTab] || [self url].SchemeIs(kChromeUIScheme))
     return;
-  }
-  base::RecordAction(UserMetricsAction("MobilePageLoaded"));
+  base::RecordAction(base::UserMetricsAction("MobilePageLoaded"));
 }
 
 - (void)applicationDidBecomeActive {
-  if (requireReloadAfterBecomingActive_) {
-    if (visible_) {
-      self.navigationManager->Reload(web::ReloadType::NORMAL,
-                                     false /* check_for_repost */);
-    } else {
-      [self.webController requirePageReload];
-    }
-    requireReloadAfterBecomingActive_ = NO;
+  if (!requireReloadAfterBecomingActive_)
+    return;
+  if (visible_) {
+    self.navigationManager->Reload(web::ReloadType::NORMAL,
+                                   false /* check_for_repost */);
+  } else {
+    [self.webController requirePageReload];
   }
+  requireReloadAfterBecomingActive_ = NO;
 }
 
 #pragma mark -
@@ -1335,10 +1271,6 @@
   return self.view;
 }
 
-- (ReaderModeController*)readerModeController {
-  return readerModeController_.get();
-}
-
 - (BOOL)canSwitchToReaderMode {
   // Only if the page is loaded and the page passes suitability checks.
   ReaderModeController* controller = self.readerModeController;
@@ -1416,15 +1348,6 @@
   navigationManager->LoadURLWithParams(params);
 }
 
-- (id<SnapshotOverlayProvider>)snapshotOverlayProvider {
-  return snapshotOverlayProvider_.get();
-}
-
-- (void)setSnapshotOverlayProvider:
-    (id<SnapshotOverlayProvider>)snapshotOverlayProvider {
-  snapshotOverlayProvider_.reset(snapshotOverlayProvider);
-}
-
 - (void)evaluateU2FResultFromURL:(const GURL&)URL {
   DCHECK(U2FController_);
   [U2FController_ evaluateU2FResultFromU2FURL:URL webState:self.webState];
@@ -1465,7 +1388,7 @@
   // checked in several places.
   if (isUserNavigationEvent && !isPrerenderTab_ &&
       ![self navigationManager]->GetPendingItem() && url != self.url) {
-    base::RecordAction(UserMetricsAction("MobileTabClobbered"));
+    base::RecordAction(base::UserMetricsAction("MobileTabClobbered"));
     if ([parentTabModel_ tabUsageRecorder])
       [parentTabModel_ tabUsageRecorder]->RecordPageLoadStart(self);
   }
@@ -1504,9 +1427,8 @@
   }
   favicon::FaviconDriver* faviconDriver =
       favicon::WebFaviconDriver::FromWebState(webState);
-  if (faviconDriver) {
+  if (faviconDriver)
     faviconDriver->FetchFavicon(lastCommittedURL);
-  }
   [parentTabModel_ notifyTabChanged:self];
   if (parentTabModel_) {
     [[NSNotificationCenter defaultCenter]
@@ -1559,9 +1481,8 @@
   else
     [autoReloadBridge_ loadFailedForURL:lastCommittedURL wasPost:wasPost];
   [webControllerSnapshotHelper_ setSnapshotCoalescingEnabled:YES];
-  if (!loadSuccess) {
+  if (!loadSuccess)
     [fullScreenController_ disableFullScreen];
-  }
   [self recordInterfaceOrientation];
   navigation_metrics::RecordMainFrameNavigation(
       lastCommittedURL, true, self.browserState->IsOffTheRecord());
@@ -1590,9 +1511,8 @@
       finishPageLoadForTab:self
                loadSuccess:loadSuccess];
 
-  if (loadSuccess) {
+  if (loadSuccess)
     [self updateSnapshotWithOverlay:YES visibleFrameOnly:YES];
-  }
   [webControllerSnapshotHelper_ setSnapshotCoalescingEnabled:NO];
 }
 
@@ -1642,9 +1562,9 @@
   if (isPrerenderTab_ || self.browserState->IsOffTheRecord())
     return NO;
 
-  base::scoped_nsprotocol<id<NativeAppMetadata>> metadata(
-      [[ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()
-          nativeAppForURL:url] retain]);
+  id<NativeAppMetadata> metadata =
+      [ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()
+          nativeAppForURL:url];
   if (![metadata shouldAutoOpenLinks])
     return NO;
 
@@ -1698,9 +1618,8 @@
 
   // Always allow frame loads.
   BOOL isFrameLoad = (url != mainDocumentURL);
-  if (isFrameLoad) {
+  if (isFrameLoad)
     return YES;
-  }
 
   // TODO(crbug.com/546402): If this turns out to be useful, find a less hacky
   // hook point to send this from.
@@ -1829,9 +1748,8 @@
   }
 
   if (visible_) {
-    if (!applicationIsNotActive) {
+    if (!applicationIsNotActive)
       [fullScreenController_ disableFullScreen];
-    }
   } else {
     [self.webController requirePageReload];
   }
@@ -1873,8 +1791,8 @@
   signin_metrics::LogAccountReconcilorStateOnGaiaResponse(
       ios::AccountReconcilorFactory::GetForBrowserState(browserState_)
           ->GetState());
-  base::scoped_nsobject<GenericChromeCommand> command(
-      [[GenericChromeCommand alloc] initWithTag:IDC_SHOW_ACCOUNTS_SETTINGS]);
+  GenericChromeCommand* command =
+      [[GenericChromeCommand alloc] initWithTag:IDC_SHOW_ACCOUNTS_SETTINGS];
   [self.view chromeExecuteCommand:command];
 }
 
@@ -1889,8 +1807,8 @@
   signin_metrics::LogAccountReconcilorStateOnGaiaResponse(
       ios::AccountReconcilorFactory::GetForBrowserState(browserState_)
           ->GetState());
-  base::scoped_nsobject<GenericChromeCommand> command(
-      [[GenericChromeCommand alloc] initWithTag:IDC_SHOW_ADD_ACCOUNT]);
+  GenericChromeCommand* command =
+      [[GenericChromeCommand alloc] initWithTag:IDC_SHOW_ADD_ACCOUNT];
   [self.view chromeExecuteCommand:command];
 }
 
@@ -1911,17 +1829,17 @@
   [self goBack];
 
   if (url.is_valid()) {
-    base::scoped_nsobject<OpenUrlCommand> command([[OpenUrlCommand alloc]
+    OpenUrlCommand* command = [[OpenUrlCommand alloc]
          initWithURL:url
             referrer:web::Referrer()  // Strip referrer when switching modes.
          inIncognito:YES
         inBackground:NO
-            appendTo:kLastTab]);
+            appendTo:kLastTab];
     [self.view chromeExecuteCommand:command];
   } else {
-    base::scoped_nsobject<GenericChromeCommand> chromeCommand(
-        [[GenericChromeCommand alloc] initWithTag:IDC_NEW_INCOGNITO_TAB]);
-    [self.view chromeExecuteCommand:chromeCommand];
+    GenericChromeCommand* command =
+        [[GenericChromeCommand alloc] initWithTag:IDC_NEW_INCOGNITO_TAB];
+    [self.view chromeExecuteCommand:command];
   }
 }
 
@@ -1937,19 +1855,11 @@
   if (browserState_->IsOffTheRecord())
     return;
   DCHECK(!nativeAppNavigationController_);
-  nativeAppNavigationController_.reset(
-      [[NativeAppNavigationController alloc] initWithWebState:self.webState]);
+  nativeAppNavigationController_ =
+      [[NativeAppNavigationController alloc] initWithWebState:self.webState];
   DCHECK(nativeAppNavigationController_);
 }
 
-- (id<PassKitDialogProvider>)passKitDialogProvider {
-  return passKitDialogProvider_.get();
-}
-
-- (void)setPassKitDialogProvider:(id<PassKitDialogProvider>)provider {
-  passKitDialogProvider_.reset(provider);
-}
-
 - (void)wasShown {
   visible_ = YES;
   [self updateFullscreenWithToolbarVisible:YES];
@@ -1978,7 +1888,7 @@
 @implementation Tab (TestingSupport)
 
 - (void)replaceExternalAppLauncher:(id)externalAppLauncher {
-  externalAppLauncher_.reset([externalAppLauncher retain]);
+  externalAppLauncher_ = externalAppLauncher;
 }
 
 - (TabModel*)parentTabModel {
@@ -1986,7 +1896,7 @@
 }
 
 - (FormInputAccessoryViewController*)inputAccessoryViewController {
-  return inputAccessoryViewController_.get();
+  return inputAccessoryViewController_;
 }
 
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
index 42b2a02..49fc3a1 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
@@ -8,12 +8,8 @@
     "content_suggestions_article_item.mm",
     "content_suggestions_footer_item.h",
     "content_suggestions_footer_item.mm",
-    "content_suggestions_most_visited.h",
-    "content_suggestions_most_visited.mm",
     "content_suggestions_most_visited_item.h",
     "content_suggestions_most_visited_item.mm",
-    "content_suggestions_most_visited_tile.h",
-    "content_suggestions_most_visited_tile.mm",
     "content_suggestions_reading_list_item.h",
     "content_suggestions_reading_list_item.mm",
     "content_suggestions_text_item.h",
@@ -40,8 +36,6 @@
     "content_suggestions_article_item_unittest.mm",
     "content_suggestions_footer_item_unittest.mm",
     "content_suggestions_most_visited_item_unittest.mm",
-    "content_suggestions_most_visited_tile_unittest.mm",
-    "content_suggestions_most_visited_unittest.mm",
   ]
   deps = [
     ":cells",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.h
deleted file mode 100644
index 1914cc52..0000000
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_H_
-#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_H_
-
-#import <Foundation/Foundation.h>
-
-@class FaviconAttributes;
-
-// Object representing a Most Visited suggestion.
-@interface ContentSuggestionsMostVisited : NSObject
-
-// Title of the Most Visited suggestion.
-@property(nonatomic, copy, nullable) NSString* title;
-// Attributes used to display the favicon of the Most Visited suggestion.
-// Setting this to nil displays an empty grey background.
-@property(nonatomic, strong, nullable) FaviconAttributes* attributes;
-
-// Returns a Most Visited with the properties set.
-+ (nullable ContentSuggestionsMostVisited*)
-mostVisitedWithTitle:(nullable NSString*)title
-          attributes:(nullable FaviconAttributes*)attributes;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.mm
deleted file mode 100644
index 122367aa..0000000
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.mm
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.h"
-
-#import "ios/chrome/browser/ui/favicon/favicon_attributes.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation ContentSuggestionsMostVisited
-
-@synthesize title = _title;
-@synthesize attributes = _attributes;
-
-+ (ContentSuggestionsMostVisited*)mostVisitedWithTitle:(NSString*)title
-                                            attributes:
-                                                (FaviconAttributes*)attributes {
-  ContentSuggestionsMostVisited* mostVisited =
-      [[ContentSuggestionsMostVisited alloc] init];
-  mostVisited.title = title;
-  mostVisited.attributes = attributes;
-  return mostVisited;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h
index 1808434..f2f7f974 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h
@@ -9,31 +9,33 @@
 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h"
 #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
 
-@class ContentSuggestionsMostVisited;
 @class FaviconAttributes;
+@class FaviconViewNew;
 
-// Item containing the Most Visited suggestions.
+// Item containing a Most Visited suggestion.
 @interface ContentSuggestionsMostVisitedItem
     : CollectionViewItem<ContentSuggestionIdentification>
 
-// Most Visited suggestions for this item.
-@property(nonatomic, copy, nonnull)
-    NSArray<ContentSuggestionsMostVisited*>* suggestions;
+// Attributes to configure the favicon view.
+@property(nonatomic, strong, nonnull) FaviconAttributes* attributes;
+
+// Text for the title and the accessibility label of the cell.
+@property(nonatomic, copy, nonnull) NSString* title;
 
 @end
 
-// Associated cell to display the Most Visited suggestions.
-// This cell displays the most visited suggestions on two rows, vertically
-// stacked. Each row is a horizontal stack of ContentSuggestionsTiles. The
-// number of tiles per row depends of the available width.
+// Associated cell to display a Most Visited tile based on the suggestion.
+// It displays the favicon for this Most Visited suggestion and its title.
 @interface ContentSuggestionsMostVisitedCell : MDCCollectionViewCell
 
-// Sets the Most Visited suggestions of this cell.
-- (void)setSuggestions:
-    (nonnull NSArray<ContentSuggestionsMostVisited*>*)suggestions;
+// FaviconView displaying the favicon.
+@property(nonatomic, strong, readonly, nonnull) FaviconViewNew* faviconView;
 
-// Returns the maximum number of tiles per line, limited to 4.
-- (NSUInteger)numberOfTilesPerLine;
+// Title of the Most Visited.
+@property(nonatomic, strong, readonly, nonnull) UILabel* titleLabel;
+
+// Size for a Most Visited tile.
++ (CGSize)defaultSize;
 
 @end
 
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
index bdad43a9..0e121d4 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
@@ -4,21 +4,23 @@
 
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.h"
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile.h"
 #import "ios/chrome/browser/ui/favicon/favicon_attributes.h"
 #import "ios/chrome/browser/ui/favicon/favicon_view.h"
-#include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
-#include "url/gurl.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
 namespace {
-const CGFloat kSpacingIPhone = 16;
-const CGFloat kSpacingIPad = 24;
+const CGFloat kLabelTextColor = 0.314;
+const NSInteger kLabelNumLines = 2;
+const CGFloat kFaviconSize = 48;
+const CGFloat kSpaceFaviconTitle = 10;
+
+// Size of a Most Visited cell.
+const CGSize kCellSize = {73, 100};
 }
 
 #pragma mark - ContentSuggestionsMostVisitedItem
@@ -26,7 +28,8 @@
 @implementation ContentSuggestionsMostVisitedItem
 
 @synthesize suggestionIdentifier = _suggestionIdentifier;
-@synthesize suggestions = _suggestions;
+@synthesize attributes = _attributes;
+@synthesize title = _title;
 
 - (instancetype)initWithType:(NSInteger)type {
   self = [super initWithType:type];
@@ -38,173 +41,66 @@
 
 - (void)configureCell:(ContentSuggestionsMostVisitedCell*)cell {
   [super configureCell:cell];
-  [cell setSuggestions:self.suggestions];
+  cell.titleLabel.text = self.title;
+  cell.accessibilityLabel = self.title;
+  [cell.faviconView configureWithAttributes:self.attributes];
 }
 
 @end
 
 #pragma mark - ContentSuggestionsMostVisitedCell
 
-@interface ContentSuggestionsMostVisitedCell ()
-
-// The Most Visited tiles to be displayed.
-@property(nonatomic, strong)
-    NSMutableArray<ContentSuggestionsMostVisitedTile*>* tiles;
-
-// The first line of Most Visited tiles.
-@property(nonatomic, strong) UIStackView* firstLine;
-
-// The second line of Most Visited tiles, displayed below the first one.
-@property(nonatomic, strong) UIStackView* secondLine;
-
-// Contains both stack views.
-@property(nonatomic, copy) NSArray<UIStackView*>* stackViews;
-
-// Superview for the stack views, used to center them.
-@property(nonatomic, strong) UIView* stackContainer;
-
-// Width of the |stackContainer|, allowing resizing.
-@property(nonatomic, strong) NSLayoutConstraint* containerWidth;
-
-// Number of tiles per line during the previous layout.
-@property(nonatomic, assign) NSUInteger previousNumberOfTilesPerLine;
-
-@end
-
 @implementation ContentSuggestionsMostVisitedCell : MDCCollectionViewCell
 
-@synthesize tiles = _tiles;
-@synthesize firstLine = _firstLine;
-@synthesize secondLine = _secondLine;
-@synthesize stackViews = _stackViews;
-@synthesize stackContainer = _stackContainer;
-@synthesize containerWidth = _containerWidth;
-@synthesize previousNumberOfTilesPerLine = _previousNumberOfTilesPerLine;
+@synthesize faviconView = _faviconView;
+@synthesize titleLabel = _titleLabel;
 
 #pragma mark - Public
 
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
-    _tiles = [NSMutableArray array];
-    _firstLine = [[UIStackView alloc] init];
-    _secondLine = [[UIStackView alloc] init];
-    _stackViews = @[ _firstLine, _secondLine ];
-    _stackContainer = [[UIView alloc] init];
-    _previousNumberOfTilesPerLine = 0;
+    _titleLabel = [[UILabel alloc] init];
+    _titleLabel.textColor = [UIColor colorWithWhite:kLabelTextColor alpha:1.0];
+    _titleLabel.font = [MDCTypography captionFont];
+    _titleLabel.textAlignment = NSTextAlignmentCenter;
+    _titleLabel.preferredMaxLayoutWidth = [[self class] defaultSize].width;
+    _titleLabel.numberOfLines = kLabelNumLines;
 
-    for (UIStackView* row in self.stackViews) {
-      row.axis = UILayoutConstraintAxisHorizontal;
-      row.spacing = [self spacing];
-      row.translatesAutoresizingMaskIntoConstraints = NO;
-      [_stackContainer addSubview:row];
-      row.layoutMarginsRelativeArrangement = YES;
-    }
+    _faviconView = [[FaviconViewNew alloc] init];
+    _faviconView.font = [MDCTypography headlineFont];
 
-    _stackContainer.translatesAutoresizingMaskIntoConstraints = NO;
+    _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+    _faviconView.translatesAutoresizingMaskIntoConstraints = NO;
 
-    [self.contentView addSubview:_stackContainer];
+    [self addSubview:_titleLabel];
+    [self addSubview:_faviconView];
 
-    [_stackContainer.centerXAnchor
-        constraintEqualToAnchor:self.contentView.centerXAnchor]
-        .active = YES;
-    _containerWidth = [_stackContainer.widthAnchor constraintEqualToConstant:0];
-    _containerWidth.active = YES;
+    [NSLayoutConstraint activateConstraints:@[
+      [_faviconView.widthAnchor constraintEqualToConstant:kFaviconSize],
+      [_faviconView.heightAnchor
+          constraintEqualToAnchor:_faviconView.widthAnchor],
+      [_faviconView.centerXAnchor
+          constraintEqualToAnchor:_titleLabel.centerXAnchor],
+    ]];
 
-    ApplyVisualConstraints(@[ @"V:|[container]|" ],
-                           @{ @"container" : _stackContainer });
-    ApplyVisualConstraints(
-        @[
-          @"V:|[first][second]|", @"H:|[first]-(>=0)-|",
-          @"H:|[second]-(>=0)-|"
-        ],
-        @{ @"first" : _firstLine,
-           @"second" : _secondLine });
+    ApplyVisualConstraintsWithMetrics(
+        @[ @"V:|[favicon]-(space)-[title]", @"H:|[title]|" ],
+        @{ @"favicon" : _faviconView,
+           @"title" : _titleLabel },
+        @{ @"space" : @(kSpaceFaviconTitle) });
+
+    self.isAccessibilityElement = YES;
   }
   return self;
 }
 
-- (void)setSuggestions:(NSArray<ContentSuggestionsMostVisited*>*)suggestions {
-  [self.tiles removeAllObjects];
-  for (ContentSuggestionsMostVisited* suggestion in suggestions) {
-    [self.tiles addObject:[ContentSuggestionsMostVisitedTile
-                              tileWithTitle:suggestion.title
-                                 attributes:suggestion.attributes]];
-  }
++ (CGSize)defaultSize {
+  return kCellSize;
 }
 
-- (NSUInteger)numberOfTilesPerLine {
-  CGFloat availableWidth = self.contentView.bounds.size.width;
-
-  if (availableWidth > [self widthForNumberOfItem:4])
-    return 4;
-  if (availableWidth > [self widthForNumberOfItem:3])
-    return 3;
-  if (availableWidth > [self widthForNumberOfItem:2])
-    return 2;
-
-  NOTREACHED();
-  return 2;
-}
-
-#pragma mark - UIView
-
-// Implements -layoutSubviews as per instructions in documentation for
-// +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:].
-- (void)layoutSubviews {
-  [super layoutSubviews];
-
-  [self applyLayout];
-
-  [super layoutSubviews];
-}
-
-#pragma mark - Private
-
-// Layouts the tiles. The view is modified only if the number of tiles per line
-// changes.
-- (void)applyLayout {
-  NSUInteger numberOfTilesPerLine = [self numberOfTilesPerLine];
-
-  if (numberOfTilesPerLine == self.previousNumberOfTilesPerLine) {
-    return;
-  }
-  self.previousNumberOfTilesPerLine = numberOfTilesPerLine;
-
-  for (UIStackView* row in self.stackViews) {
-    while (row.arrangedSubviews.count > 0) {
-      UIView* view = row.arrangedSubviews.firstObject;
-      [row removeArrangedSubview:view];
-      [view removeFromSuperview];
-    }
-  }
-
-  NSUInteger numberOfTilesFirstLine =
-      MIN(numberOfTilesPerLine, self.tiles.count);
-  for (NSUInteger i = 0; i < numberOfTilesFirstLine; i++) {
-    [self.firstLine addArrangedSubview:self.tiles[i]];
-  }
-  if (self.tiles.count > numberOfTilesPerLine) {
-    NSUInteger totalNumberOfTiles =
-        MIN(2 * numberOfTilesPerLine, self.tiles.count);
-    for (NSUInteger i = numberOfTilesPerLine; i < totalNumberOfTiles; i++) {
-      [self.secondLine addArrangedSubview:self.tiles[i]];
-    }
-  }
-
-  self.containerWidth.constant =
-      [self widthForNumberOfItem:numberOfTilesPerLine];
-}
-
-// Returns the spacing between tiles, based on the device.
-- (CGFloat)spacing {
-  return IsIPadIdiom() ? kSpacingIPad : kSpacingIPhone;
-}
-
-// Returns the width necessary to fit |numberOfItem| items.
-- (CGFloat)widthForNumberOfItem:(NSUInteger)numberOfItem {
-  return (numberOfItem - 1) * [self spacing] +
-         numberOfItem * [ContentSuggestionsMostVisitedTile width];
+- (CGSize)intrinsicContentSize {
+  return [[self class] defaultSize];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item_unittest.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item_unittest.mm
index 50a147c..40357305 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item_unittest.mm
@@ -4,8 +4,12 @@
 
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 
+#import "ios/chrome/browser/ui/favicon/favicon_attributes.h"
+#import "ios/chrome/browser/ui/favicon/favicon_view.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#import "third_party/ocmock/gtest_support.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -13,7 +17,7 @@
 
 namespace {
 
-TEST(ContentSuggestionsMostVisitedItemTest, Configure) {
+TEST(ContentSuggestionsMostVisitedItemTest, CellClass) {
   // Setup.
   ContentSuggestionsMostVisitedItem* item =
       [[ContentSuggestionsMostVisitedItem alloc] initWithType:0];
@@ -25,57 +29,25 @@
   ASSERT_EQ([ContentSuggestionsMostVisitedCell class], [cell class]);
 }
 
-TEST(ContentSuggestionsMostVisitedItemTest, SizeIPhone6) {
+TEST(ContentSuggestionsMostVisitedItemTest, Configure) {
   // Setup.
-  if (IsIPadIdiom())
-    return;
+  NSString* title = @"Test title.";
+  ContentSuggestionsMostVisitedItem* item =
+      [[ContentSuggestionsMostVisitedItem alloc] initWithType:0];
+  item.title = title;
+  item.attributes =
+      [FaviconAttributes attributesWithMonogram:@"C"
+                                      textColor:[UIColor whiteColor]
+                                backgroundColor:[UIColor blackColor]];
+  ContentSuggestionsMostVisitedCell* cell = [[[item cellClass] alloc] init];
+  id faviconViewMock = OCMPartialMock(cell.faviconView);
+  OCMExpect([faviconViewMock configureWithAttributes:item.attributes]);
 
-  ContentSuggestionsMostVisitedCell* cell =
-      [[ContentSuggestionsMostVisitedCell alloc] init];
-  cell.frame = CGRectMake(0, 0, 360, 0);
-  [cell layoutIfNeeded];
+  // Action.
+  [item configureCell:cell];
 
   // Test.
-  EXPECT_EQ(4U, [cell numberOfTilesPerLine]);
-}
-
-TEST(ContentSuggestionsMostVisitedItemTest, SizeIPhone5) {
-  // Setup.
-  if (IsIPadIdiom())
-    return;
-
-  ContentSuggestionsMostVisitedCell* cell =
-      [[ContentSuggestionsMostVisitedCell alloc] init];
-  cell.frame = CGRectMake(0, 0, 320, 0);
-  [cell layoutIfNeeded];
-
-  // Test.
-  EXPECT_EQ(3U, [cell numberOfTilesPerLine]);
-}
-
-// Test for iPad portrait and iPhone landscape.
-TEST(ContentSuggestionsMostVisitedItemTest, SizeLarge) {
-  // Setup.
-  ContentSuggestionsMostVisitedCell* cell =
-      [[ContentSuggestionsMostVisitedCell alloc] init];
-  cell.frame = CGRectMake(0, 0, 720, 0);
-  [cell layoutIfNeeded];
-
-  // Test.
-  EXPECT_EQ(4U, [cell numberOfTilesPerLine]);
-}
-
-TEST(ContentSuggestionsMostVisitedItemTest, SizeIPadSplit) {
-  // Setup.
-  if (!IsIPadIdiom())
-    return;
-
-  ContentSuggestionsMostVisitedCell* cell =
-      [[ContentSuggestionsMostVisitedCell alloc] init];
-  cell.frame = CGRectMake(0, 0, 360, 0);
-  [cell layoutIfNeeded];
-
-  // Test.
-  EXPECT_EQ(3U, [cell numberOfTilesPerLine]);
+  ASSERT_EQ(title, cell.titleLabel.text);
+  ASSERT_OCMOCK_VERIFY(faviconViewMock);
 }
 }
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile.h
deleted file mode 100644
index 478245df..0000000
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_TILE_H_
-#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_TILE_H_
-
-#import <UIKit/UIKit.h>
-
-@class FaviconAttributes;
-@class FaviconViewNew;
-
-// View used to display a Most Visited tile.
-@interface ContentSuggestionsMostVisitedTile : UIView
-
-// Width of a Most Visited tile.
-+ (CGFloat)width;
-
-// Creates a tile with a |title| and its favicon view configured with
-// |attributes|.
-+ (nullable ContentSuggestionsMostVisitedTile*)
-tileWithTitle:(nullable NSString*)title
-   attributes:(nullable FaviconAttributes*)attributes;
-
-// FaviconView displaying the favicon.
-@property(nonatomic, strong, readonly, nonnull) FaviconViewNew* faviconView;
-
-// Sets the text and the accessibility label of this view.
-- (void)setTitle:(nullable NSString*)title;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_TILE_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile.mm
deleted file mode 100644
index 2ba638c..0000000
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile.mm
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile.h"
-
-#import "ios/chrome/browser/ui/favicon/favicon_attributes.h"
-#import "ios/chrome/browser/ui/favicon/favicon_view.h"
-#import "ios/chrome/browser/ui/uikit_ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-const CGFloat kLabelTextColor = 0.314;
-const NSInteger kLabelNumLines = 2;
-const CGFloat kFaviconSize = 48;
-const CGFloat kSpaceFaviconTitle = 10;
-
-// Size of the tile.
-const CGFloat kWidth = 73;
-const CGFloat kHeight = 100;
-}
-
-@interface ContentSuggestionsMostVisitedTile ()
-
-@property(nonatomic, strong) UILabel* titleLabel;
-
-@end
-
-@implementation ContentSuggestionsMostVisitedTile
-
-@synthesize titleLabel = _titleLabel;
-@synthesize faviconView = _faviconView;
-
-+ (CGFloat)width {
-  return kWidth;
-}
-
-+ (ContentSuggestionsMostVisitedTile*)tileWithTitle:(NSString*)title
-                                         attributes:
-                                             (FaviconAttributes*)attributes {
-  ContentSuggestionsMostVisitedTile* tile =
-      [[ContentSuggestionsMostVisitedTile alloc] init];
-  [tile.faviconView configureWithAttributes:attributes];
-  [tile setTitle:title];
-  return tile;
-}
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    _titleLabel = [[UILabel alloc] init];
-    _titleLabel.textColor = [UIColor colorWithWhite:kLabelTextColor alpha:1.0];
-    _titleLabel.font = [MDCTypography captionFont];
-    _titleLabel.textAlignment = NSTextAlignmentCenter;
-    _titleLabel.preferredMaxLayoutWidth = [[self class] width];
-    _titleLabel.numberOfLines = kLabelNumLines;
-
-    _faviconView = [[FaviconViewNew alloc] init];
-    _faviconView.font = [MDCTypography headlineFont];
-
-    _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _faviconView.translatesAutoresizingMaskIntoConstraints = NO;
-
-    [self addSubview:_titleLabel];
-    [self addSubview:_faviconView];
-
-    [NSLayoutConstraint activateConstraints:@[
-      [_faviconView.widthAnchor constraintEqualToConstant:kFaviconSize],
-      [_faviconView.heightAnchor
-          constraintEqualToAnchor:_faviconView.widthAnchor],
-      [_faviconView.centerXAnchor
-          constraintEqualToAnchor:_titleLabel.centerXAnchor],
-    ]];
-
-    ApplyVisualConstraintsWithMetrics(
-        @[ @"V:|[favicon]-(space)-[title]", @"H:|[title]|" ],
-        @{ @"favicon" : _faviconView,
-           @"title" : _titleLabel },
-        @{ @"space" : @(kSpaceFaviconTitle) });
-
-    self.isAccessibilityElement = YES;
-  }
-  return self;
-}
-
-- (void)setTitle:(NSString*)title {
-  self.titleLabel.text = title;
-  self.accessibilityLabel = title;
-}
-
-- (CGSize)intrinsicContentSize {
-  return CGSizeMake(kWidth, kHeight);
-}
-
-@end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile_unittest.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile_unittest.mm
deleted file mode 100644
index 8ad6eb02..0000000
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile_unittest.mm
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-TEST(ContentSuggestionsMostVisitedTileTest, Constructor) {
-  NSString* title = @"Test title";
-  ContentSuggestionsMostVisitedTile* tile =
-      [ContentSuggestionsMostVisitedTile tileWithTitle:title attributes:nil];
-
-  ASSERT_TRUE([title isEqualToString:tile.accessibilityLabel]);
-}
-}
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_unittest.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_unittest.mm
deleted file mode 100644
index a8f4ac3..0000000
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_unittest.mm
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.h"
-
-#import "ios/chrome/browser/ui/favicon/favicon_attributes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-TEST(ContentSuggestionsMostVisitedTest, Constructor) {
-  NSString* title = @"Test title";
-  FaviconAttributes* attributes =
-      [[FaviconAttributes alloc] initWithImage:[[UIImage alloc] init]];
-  ContentSuggestionsMostVisited* mostVisited =
-      [ContentSuggestionsMostVisited mostVisitedWithTitle:title
-                                               attributes:attributes];
-
-  ASSERT_TRUE([title isEqualToString:mostVisited.title]);
-  ASSERT_EQ(attributes, mostVisited.attributes);
-}
-}
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
index cc7a811..a682c7c0 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
@@ -14,7 +14,6 @@
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_article_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_footer_item.h"
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_reading_list_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h"
@@ -238,9 +237,6 @@
     return [NSArray array];
   }
 
-  NSMutableArray<ContentSuggestionsMostVisited*>* mostVisitedToAdd =
-      [NSMutableArray array];
-
   CSCollectionViewModel* model =
       self.collectionViewController.collectionViewModel;
   NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray array];
@@ -293,37 +289,18 @@
         break;
       }
       case ContentSuggestionTypeMostVisited: {
-        NSInteger section =
-            [model sectionForSectionIdentifier:SectionIdentifierMostVisited];
-        NSIndexPath* indexPath =
-            [NSIndexPath indexPathForItem:0 inSection:section];
-
-        if ([model numberOfItemsInSection:section] == 0) {
-          [model addItem:[[ContentSuggestionsMostVisitedItem alloc]
-                             initWithType:ItemTypeMostVisited]
-              toSectionWithIdentifier:SectionIdentifierMostVisited];
-          [indexPaths addObject:indexPath];
-        }
-
-        ContentSuggestionsMostVisited* mostVisited =
-            [ContentSuggestionsMostVisited mostVisitedWithTitle:suggestion.title
-                                                     attributes:nil];
-        [mostVisitedToAdd addObject:mostVisited];
+        ContentSuggestionsMostVisitedItem* mostVisitedItem =
+            [[ContentSuggestionsMostVisitedItem alloc]
+                initWithType:ItemTypeMostVisited];
+        mostVisitedItem.title = suggestion.title;
+        [model addItem:mostVisitedItem
+            toSectionWithIdentifier:SectionIdentifierMostVisited];
+        [indexPaths addObject:indexPath];
         break;
       }
     }
   }
 
-  if ([model hasSectionForSectionIdentifier:SectionIdentifierMostVisited]) {
-    NSInteger section =
-        [model sectionForSectionIdentifier:SectionIdentifierMostVisited];
-    NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:section];
-    ContentSuggestionsMostVisitedItem* item =
-        base::mac::ObjCCast<ContentSuggestionsMostVisitedItem>(
-            [model itemAtIndexPath:indexPath]);
-    item.suggestions = mostVisitedToAdd;
-  }
-
   return indexPaths;
 }
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c232f4b..80370081 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2025,7 +2025,7 @@
             ]
         }
     ],
-    "PasswordProtectionLowReputationPing": [
+    "PasswordProtectionPasswordFieldOnFocusPing": [
         {
             "platforms": [
                 "chromeos",
@@ -2042,7 +2042,7 @@
                         "incognito": "false"
                     },
                     "enable_features": [
-                        "LowReputationPinging"
+                        "PasswordFieldOnFocusPinging"
                     ]
                 }
             ]
@@ -2113,46 +2113,40 @@
             ],
             "experiments": [
                 {
-                    "name": "ModalGestureEnabled",
-                    "params": {
-                        "require_gesture": "true"
-                    },
+                    "name": "BlockPromptsEnabled",
                     "enable_features": [
-                        "ModalPermissionPrompts"
-                    ],
-                    "disable_features": [
-                        "DisplayPersistenceToggleInPermissionPrompts"
+                        "BlockPromptsIfDismissedOften"
                     ]
-                },
+                }
+            ]
+        }
+    ],
+    "PermissionPromptUIAndroidModal": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
                 {
-                    "name": "ModalNoGestureEnabled",
-                    "params": {
-                        "require_gesture": "false"
-                    },
-                    "enable_features": [
-                        "ModalPermissionPrompts"
-                    ],
-                    "disable_features": [
-                        "DisplayPersistenceToggleInPermissionPrompts"
-                    ]
-                },
-                {
-                    "name": "ModalAndToggleEnabled",
-                    "params": {
-                        "require_gesture": "false"
-                    },
+                    "name": "ModalToggleEnabled",
                     "enable_features": [
                         "DisplayPersistenceToggleInPermissionPrompts",
                         "ModalPermissionPrompts"
                     ]
-                },
+                }
+            ]
+        }
+    ],
+    "PermissionPromptUICocoa": [
+        {
+            "platforms": [
+                "mac"
+            ],
+            "experiments": [
                 {
-                    "name": "ToggleEnabled",
+                    "name": "BlockPromptsEnabled",
                     "enable_features": [
-                        "DisplayPersistenceToggleInPermissionPrompts"
-                    ],
-                    "disable_features": [
-                        "ModalPermissionPrompts"
+                        "BlockPromptsIfDismissedOften"
                     ]
                 }
             ]
@@ -2167,9 +2161,9 @@
             ],
             "experiments": [
                 {
-                    "name": "ToggleEnabled",
+                    "name": "BlockPromptsEnabled",
                     "enable_features": [
-                        "DisplayPersistenceToggleInPermissionPrompts"
+                        "BlockPromptsIfDismissedOften"
                     ]
                 }
             ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/aom.html b/third_party/WebKit/LayoutTests/accessibility/aom.html
index 46c1043..cc22ccc5 100644
--- a/third_party/WebKit/LayoutTests/accessibility/aom.html
+++ b/third_party/WebKit/LayoutTests/accessibility/aom.html
@@ -52,21 +52,9 @@
     assert_equals(axButton.role, "AXRole: AXCheckBox");
     assert_equals(axButton.name, "Check Me");
 
-    assert_equals(aomButton.role, "checkbox");
-    assert_equals(aomButton.label, "Check Me");
-}, "ARIA attributes are reflected into AOM properties");
-
-test(function(t) {
-    var button = document.getElementById("button");
-    var aomButton = button.accessibleNode;
-    var axButton = accessibilityController.accessibleElementById("button");
-
-    button.setAttribute("role", "beyonce");
-
-    assert_equals(axButton.role, "AXRole: AXButton");
-
-    assert_equals(aomButton.role, "beyonce");
-}, "Invalid ARIA roles are still reflected into AOM properties");
+    assert_equals(aomButton.role, null);
+    assert_equals(aomButton.label, null);
+}, "ARIA attributes are not reflected into AOM properties");
 
 test(function(t) {
     var button = document.getElementById("button");
@@ -161,14 +149,9 @@
 
     aomButton.role = null;
     aomButton.label = null;
-    assert_equals(axButton.role, "AXRole: AXButton");
-    assert_equals(axButton.name, "Click Me");
-
-    button.setAttribute("role", "combobox");
-    button.setAttribute("aria-label", "ARIA 2");
-    assert_equals(axButton.role, "AXRole: AXButton");
-    assert_equals(axButton.name, "Click Me");
-}, "Once an AOM property has been set, ARIA no longer has any effect");
+    assert_equals(axButton.role, "AXRole: AXTextField");
+    assert_equals(axButton.name, "ARIA");
+}, "Clearing an AOM property falls back on an ARIA attribute");
 </script>
 
 <button id="button4">Click Me</button>
@@ -178,9 +161,9 @@
     var aomButton;
     (function() {
         var button = document.getElementById("button4");
-        button.setAttribute("role", "checkbox");
-        button.setAttribute("aria-label", "Check Me");
         aomButton = button.accessibleNode;
+        aomButton.role = "checkbox";
+        aomButton.label = "Check Me";
     })();
     assert_equals(aomButton.role, "checkbox");
     assert_equals(aomButton.label, "Check Me");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-001-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-001-expected.txt
index 3646c6d..a97e4e5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-001-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-001-expected.txt
@@ -1,20 +1,100 @@
 This is a testharness.js-based test.
-PASS testConstructor0 
-PASS testConstructor1 
-FAIL testConstructor2 Failed to construct 'DOMMatrix': Failed to parse '0,0'.
-FAIL testConstructor3 Failed to construct 'DOMMatrix': Failed to parse '0,0'.
-FAIL testConstructor4 Failed to construct 'DOMMatrix': Failed to parse '2,0,0,0,0,2,0,0,0,0,1,0,10,10,0,1'.
-FAIL testConstructor5 Failed to construct 'DOMMatrix': Failed to parse '0,0'.
-PASS testConstructor6 
-FAIL testConstructor7 float64Array is not defined
-FAIL testConstructor8 assert_equals: Expected value for is2D is false expected false but got true
-FAIL testConstructor9 Failed to construct 'DOMMatrix': Failed to parse 'scale(2 2) translateX(5) translateY(5)'.
-FAIL testConstructor10 Failed to construct 'DOMMatrix': Failed to parse 'scale(2, 2), translateX(5)  ,translateY(5)'.
-FAIL testConstructor11 assert_throws: function "function () { new DOMMatrix('scale(2)translateX(5px)'); }" did not throw
-PASS testConstructor12 
-PASS testConstructor13 
-FAIL testConstructorIllegal0 assert_throws: function "function () { new DOMMatrixReadOnly(); }" did not throw
-FAIL testConstructorIllegal1 assert_throws: function "function () { new DOMMatrixReadOnly(string); }" threw object "SyntaxError: Failed to construct 'DOMMatrixReadOnly': Failed to parse 'scale(2, 2), translateX(5px) translateY(5px)'." ("SyntaxError") expected object "TypeError" ("TypeError")
-PASS testConstructorIllegal2 
+Found 96 tests; 76 PASS, 20 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS new DOMMatrix() 
+FAIL new DOMMatrix(undefined) Failed to construct 'DOMMatrix': Failed to parse 'undefined'.
+PASS new DOMMatrix(new DOMMatrix()) 
+PASS new DOMMatrix("none") 
+PASS new DOMMatrix(" none") 
+PASS new DOMMatrix("none ") 
+PASS new DOMMatrix("NONE") 
+PASS new DOMMatrix("none/**/") 
+PASS new DOMMatrix("/**/none") 
+PASS new DOMMatrix("") 
+FAIL new DOMMatrix(float32Array) 16 elements Failed to construct 'DOMMatrix': Failed to parse '0,0'.
+FAIL new DOMMatrix(float32Array) 6 elements Failed to construct 'DOMMatrix': Failed to parse '0,0'.
+FAIL new DOMMatrix(float64Array) 16 elements Failed to construct 'DOMMatrix': Failed to parse '2,0,0,0,0,2,0,0,0,0,1,0,10,10,0,1'.
+FAIL new DOMMatrix((float64Array) 6 elements Failed to construct 'DOMMatrix': Failed to parse '0,0'.
+PASS new DOMMatrix(sequence) 16 elements 
+FAIL new DOMMatrix(sequence) 6 elements assert_equals: Expected value for is2D is false expected false but got true
+FAIL new DOMMatrix("scale(2) translateX(5px) translateY(5px)") assert_equals: Expected value for is2D is false expected false but got true
+FAIL new DOMMatrix("scale(2 2) translateX(5) translateY(5)") Failed to construct 'DOMMatrix': Failed to parse 'scale(2 2) translateX(5) translateY(5)'.
+FAIL new DOMMatrix("scale(2, 2), translateX(5)  ,translateY(5)") Failed to construct 'DOMMatrix': Failed to parse 'scale(2, 2), translateX(5)  ,translateY(5)'.
+PASS new DOMMatrix("translateX    (5px)") 
+FAIL new DOMMatrix("scale(2)translateX(5px)") assert_throws: function "function () { new self[constr](string); }" did not throw
+PASS new DOMMatrix("translateX(5em)") 
+PASS new DOMMatrix("translateX(5ex)") 
+PASS new DOMMatrix("translateX(5ch)") 
+PASS new DOMMatrix("translateX(5rem)") 
+PASS new DOMMatrix("translateX(5vw)") 
+PASS new DOMMatrix("translateX(5vh)") 
+PASS new DOMMatrix("translateX(5vmin)") 
+PASS new DOMMatrix("translateX(5vmax)") 
+PASS new DOMMatrix("translateX(5%)") 
+PASS new DOMMatrix(" ") 
+PASS new DOMMatrix("/**/") 
+PASS new DOMMatrix("\0") 
+PASS new DOMMatrix(";") 
+PASS new DOMMatrix("none;") 
+PASS new DOMMatrix("null") 
+PASS new DOMMatrix(null) 
+PASS new DOMMatrix("undefined") 
+PASS new DOMMatrix("inherit") 
+PASS new DOMMatrix("initial") 
+PASS new DOMMatrix("unset") 
+PASS new DOMMatrix(sequence) 
+PASS new DOMMatrix(matrix) 
+PASS new DOMMatrix("scale(2, 2), translateX(5px) translateY(5px)") 
+PASS new DOMMatrix(sequence) 17 elements 
+PASS new DOMMatrix(sequence) 15 elements 
+PASS new DOMMatrix(sequence) 5 elements 
+PASS new DOMMatrix(sequence) 0 elements 
+PASS new DOMMatrixReadOnly() 
+FAIL new DOMMatrixReadOnly(undefined) Failed to construct 'DOMMatrixReadOnly': Failed to parse 'undefined'.
+PASS new DOMMatrixReadOnly(new DOMMatrixReadOnly()) 
+PASS new DOMMatrixReadOnly("none") 
+PASS new DOMMatrixReadOnly(" none") 
+PASS new DOMMatrixReadOnly("none ") 
+PASS new DOMMatrixReadOnly("NONE") 
+PASS new DOMMatrixReadOnly("none/**/") 
+PASS new DOMMatrixReadOnly("/**/none") 
+PASS new DOMMatrixReadOnly("") 
+FAIL new DOMMatrixReadOnly(float32Array) 16 elements Failed to construct 'DOMMatrixReadOnly': Failed to parse '0,0'.
+FAIL new DOMMatrixReadOnly(float32Array) 6 elements Failed to construct 'DOMMatrixReadOnly': Failed to parse '0,0'.
+FAIL new DOMMatrixReadOnly(float64Array) 16 elements Failed to construct 'DOMMatrixReadOnly': Failed to parse '2,0,0,0,0,2,0,0,0,0,1,0,10,10,0,1'.
+FAIL new DOMMatrixReadOnly((float64Array) 6 elements Failed to construct 'DOMMatrixReadOnly': Failed to parse '0,0'.
+PASS new DOMMatrixReadOnly(sequence) 16 elements 
+FAIL new DOMMatrixReadOnly(sequence) 6 elements assert_equals: Expected value for is2D is false expected false but got true
+FAIL new DOMMatrixReadOnly("scale(2) translateX(5px) translateY(5px)") assert_equals: Expected value for is2D is false expected false but got true
+FAIL new DOMMatrixReadOnly("scale(2 2) translateX(5) translateY(5)") Failed to construct 'DOMMatrixReadOnly': Failed to parse 'scale(2 2) translateX(5) translateY(5)'.
+FAIL new DOMMatrixReadOnly("scale(2, 2), translateX(5)  ,translateY(5)") Failed to construct 'DOMMatrixReadOnly': Failed to parse 'scale(2, 2), translateX(5)  ,translateY(5)'.
+PASS new DOMMatrixReadOnly("translateX    (5px)") 
+FAIL new DOMMatrixReadOnly("scale(2)translateX(5px)") assert_throws: function "function () { new self[constr](string); }" did not throw
+PASS new DOMMatrixReadOnly("translateX(5em)") 
+PASS new DOMMatrixReadOnly("translateX(5ex)") 
+PASS new DOMMatrixReadOnly("translateX(5ch)") 
+PASS new DOMMatrixReadOnly("translateX(5rem)") 
+PASS new DOMMatrixReadOnly("translateX(5vw)") 
+PASS new DOMMatrixReadOnly("translateX(5vh)") 
+PASS new DOMMatrixReadOnly("translateX(5vmin)") 
+PASS new DOMMatrixReadOnly("translateX(5vmax)") 
+PASS new DOMMatrixReadOnly("translateX(5%)") 
+PASS new DOMMatrixReadOnly(" ") 
+PASS new DOMMatrixReadOnly("/**/") 
+PASS new DOMMatrixReadOnly("\0") 
+PASS new DOMMatrixReadOnly(";") 
+PASS new DOMMatrixReadOnly("none;") 
+PASS new DOMMatrixReadOnly("null") 
+PASS new DOMMatrixReadOnly(null) 
+PASS new DOMMatrixReadOnly("undefined") 
+PASS new DOMMatrixReadOnly("inherit") 
+PASS new DOMMatrixReadOnly("initial") 
+PASS new DOMMatrixReadOnly("unset") 
+PASS new DOMMatrixReadOnly(sequence) 
+PASS new DOMMatrixReadOnly(matrix) 
+PASS new DOMMatrixReadOnly("scale(2, 2), translateX(5px) translateY(5px)") 
+PASS new DOMMatrixReadOnly(sequence) 17 elements 
+PASS new DOMMatrixReadOnly(sequence) 15 elements 
+PASS new DOMMatrixReadOnly(sequence) 5 elements 
+PASS new DOMMatrixReadOnly(sequence) 0 elements 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-001.html
index c054e89..1ff5a9b9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-001.html
@@ -3,18 +3,17 @@
 <head>
     <title>Geometry Interfaces: DOMMatrix and DOMMatrixReadOnly constructors</title>
     <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com" />
-    <link rel="help" href="http://www.w3.org/TR/geometry-1/#DOMMatrix">
-    <link rel="help" href="http://www.w3.org/TR/geometry-1/#dommatrix-constructors">
-    <link rel="help" href="http://www.w3.org/TR/geometry-1/#dom-dommatrix-dommatrix">
+    <link rel="help" href="https://drafts.fxtf.org/geometry/#DOMMatrix">
+    <link rel="help" href="https://drafts.fxtf.org/geometry/#dommatrix-constructors">
+    <link rel="help" href="https://drafts.fxtf.org/geometry/#dom-dommatrix-dommatrix">
     <script src="support/dommatrix-test-util.js"></script>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-    <p>Test DOMMatrix and DOMMatrixReadOnly contructors</p>
     <div id="log"></div>
     <script>
-        initial = {
+        var initial = {
             m11: 1, m21: 0, m31: 0, m41: 0,
             m12: 0, m22: 1, m32: 0, m42: 0,
             m13: 0, m23: 0, m33: 1, m43: 0,
@@ -22,7 +21,7 @@
             is2D: true,
             isIdentity: true
         };
-        scaleTranslate2D = {
+        var scaleTranslate2D = {
             m11: 2, m21: 0, m31: 0, m41: 10,
             m12: 0, m22: 2, m32: 0, m42: 10,
             m13: 0, m23: 0, m33: 1, m43: 0,
@@ -30,116 +29,165 @@
             is2D: false,
             isIdentity: false
         };
+        ["DOMMatrix", "DOMMatrixReadOnly"].forEach(function(constr) {
+            test(function() {
+                checkDOMMatrix(new self[constr](), initial);
+            }, `new ${constr}()`);
 
-        test(function() {
-            checkDOMMatrix(new DOMMatrix(), initial);
-        },'testConstructor0');
-        test(function() {
-            checkDOMMatrix(new DOMMatrix(new DOMMatrix()), initial);
-        },'testConstructor1');
-        test(function() {
-            var float32Array = new Float32Array(
-                2.0, 0.0, 0.0, 0.0,
-                0.0, 2.0, 0.0, 0.0,
-                0.0, 0.0, 1.0, 0.0,
-                10.0, 10.0, 0.0, 1.0);
-            checkDOMMatrix(new DOMMatrix(float32Array), scaleTranslate2D, false);
-        },'testConstructor2');
-        test(function() {
-            var float32Array = new Float32Array(2.0, 0.0, 0.0, 2.0, 10.0, 10.0);
-            checkDOMMatrix(new DOMMatrix(float32Array), scaleTranslate2D);
-        },'testConstructor3');
-        test(function() {
-            var float64Array = new Float64Array([
-                2.0, 0.0, 0.0, 0.0,
-                0.0, 2.0, 0.0, 0.0,
-                0.0, 0.0, 1.0, 0.0,
-                10.0, 10.0, 0.0, 1.0]);
-            checkDOMMatrix(new DOMMatrix(float64Array), scaleTranslate2D, false);
-        },'testConstructor4');
-        test(function() {
-            var float64Array = new Float64Array(2.0, 0.0, 0.0, 2.0, 10.0, 10.0);
-            checkDOMMatrix(new DOMMatrix(float64Array), scaleTranslate2D);
-        },'testConstructor5');
-        test(function() {
-            var sequence = [
-                2.0, 0.0, 0.0, 0.0,
-                0.0, 2.0, 0.0, 0.0,
-                0.0, 0.0, 1.0, 0.0,
-                10.0, 10.0, 0.0, 1.0];
-            checkDOMMatrix(new DOMMatrix(sequence), scaleTranslate2D, false);
-        },'testConstructor6');
-        test(function() {
-            var sequence = [ 2.0, 0.0, 0.0, 2.0, 10.0, 10.0];
-            checkDOMMatrix(new DOMMatrix(float64Array), scaleTranslate2D);
-        },'testConstructor7');
-        test(function() {
-            var string = 'scale(2) translateX(5px) translateY(5px)';
-            checkDOMMatrix(new DOMMatrix(string), scaleTranslate2D);
-        },'testConstructor8');
-        test(function() {
-            var string = 'scale(2 2) translateX(5) translateY(5)';
-            checkDOMMatrix(new DOMMatrix(string), scaleTranslate2D);
-        },'testConstructor9');
-        test(function() {
-            var string = 'scale(2, 2), translateX(5)  ,translateY(5)';
-            checkDOMMatrix(new DOMMatrix(string), scaleTranslate2D);
-        },'testConstructor10');
-        test(function() {
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX    (5px)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('scale(2)translateX(5px)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX(5em)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX(5ex)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX(5ch)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX(5rem)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX(5vw)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX(5vh)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX(5vmin)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX(5vmax)'); });
-            assert_throws('SyntaxError', function() { new DOMMatrix('translateX(5%)'); });
-        },'testConstructor11');
-        test(function() {
-            var sequence = [
-                2.0, 1.0, 0.0, 0.0,
-                1.0, 2.0, 0.0, 0.0,
-                0.0, 0.0, 1.0, 0.0,
-                10.0, 10.0, 0.0, 1.0];
-            checkDOMMatrix(new DOMMatrix(sequence), {
-                m11: 2, m21: 1, m31: 0, m41: 10,
-                m12: 1, m22: 2, m32: 0, m42: 10,
-                m13: 0, m23: 0, m33: 1, m43: 0,
-                m14: 0, m24: 0, m34: 0, m44: 1,
-                is2D: false,
-                isIdentity: false
+            test(function() {
+                checkDOMMatrix(new self[constr](undefined), initial);
+            }, `new ${constr}(undefined)`);
+
+            test(function() {
+                checkDOMMatrix(new self[constr](new self[constr]()), initial);
+            }, `new ${constr}(new ${constr}())`);
+
+            ['none',
+             ' none',
+             'none ',
+             'NONE',
+             'none/**/',
+             '/**/none',
+             '',
+            ].forEach(function(string) {
+                test(function() {
+                    checkDOMMatrix(new self[constr](string), initial);
+                }, `new ${constr}(${format_value(string)})`);
             });
-        },'testConstructor12');
-        test(function() {
-            var matrix = new DOMMatrix([
-                2.0, 1.0, 0.0, 0.0,
-                1.0, 2.0, 0.0, 0.0,
+
+            test(function() {
+                var float32Array = new Float32Array(
+                    2.0, 0.0, 0.0, 0.0,
+                    0.0, 2.0, 0.0, 0.0,
+                    0.0, 0.0, 1.0, 0.0,
+                    10.0, 10.0, 0.0, 1.0);
+                checkDOMMatrix(new self[constr](float32Array), scaleTranslate2D, false);
+            }, `new ${constr}(float32Array) 16 elements`);
+
+            test(function() {
+                var float32Array = new Float32Array(2.0, 0.0, 0.0, 2.0, 10.0, 10.0);
+                checkDOMMatrix(new self[constr](float32Array), scaleTranslate2D);
+            }, `new ${constr}(float32Array) 6 elements`);
+
+            test(function() {
+                var float64Array = new Float64Array([
+                    2.0, 0.0, 0.0, 0.0,
+                    0.0, 2.0, 0.0, 0.0,
+                    0.0, 0.0, 1.0, 0.0,
+                    10.0, 10.0, 0.0, 1.0]);
+                checkDOMMatrix(new self[constr](float64Array), scaleTranslate2D, false);
+            }, `new ${constr}(float64Array) 16 elements`);
+
+            test(function() {
+                var float64Array = new Float64Array(2.0, 0.0, 0.0, 2.0, 10.0, 10.0);
+                checkDOMMatrix(new self[constr](float64Array), scaleTranslate2D);
+            }, `new ${constr}((float64Array) 6 elements`);
+
+            [
+                [2.0, 0.0, 0.0, 0.0,
+                0.0, 2.0, 0.0, 0.0,
                 0.0, 0.0, 1.0, 0.0,
-                10.0, 10.0, 0.0, 1.0]);
-            checkDOMMatrix(new DOMMatrix(matrix), {
-                m11: 2, m21: 1, m31: 0, m41: 10,
-                m12: 1, m22: 2, m32: 0, m42: 10,
-                m13: 0, m23: 0, m33: 1, m43: 0,
-                m14: 0, m24: 0, m34: 0, m44: 1,
-                is2D: false,
-                isIdentity: false
+                10.0, 10.0, 0.0, 1.0],
+                [2.0, 0.0, 0.0, 2.0, 10.0, 10.0],
+            ].forEach(function(sequence) {
+                test(function() {
+                    checkDOMMatrix(new self[constr](sequence), scaleTranslate2D, false);
+                }, `new ${constr}(sequence) ${sequence.length} elements`);
             });
-        },'testConstructor13');
-        test(function() {
-            assert_throws(new TypeError(), function() { new DOMMatrixReadOnly(); });
-        },'testConstructorIllegal0');
-        test(function() {
-            var string = 'scale(2, 2), translateX(5px) translateY(5px)';
-            assert_throws(new TypeError(), function() { new DOMMatrixReadOnly(string); });
-        },'testConstructorIllegal1');
-        test(function() {
-            var sequence = [ 2.0, 0.0, 0.0, 2.0, 10.0];
-            assert_throws(new TypeError(), function() { new DOMMatrixReadOnly(sequence); });
-        },'testConstructorIllegal2');
-        
+
+            ['scale(2) translateX(5px) translateY(5px)',
+             'scale(2 2) translateX(5) translateY(5)',
+             'scale(2, 2), translateX(5)  ,translateY(5)',
+            ].forEach(function(string) {
+                test(function() {
+                    checkDOMMatrix(new self[constr](string), scaleTranslate2D);
+                }, `new ${constr}(${format_value(string)})`);
+            });
+
+            ['translateX    (5px)',
+             'scale(2)translateX(5px)',
+             'translateX(5em)',
+             'translateX(5ex)',
+             'translateX(5ch)',
+             'translateX(5rem)',
+             'translateX(5vw)',
+             'translateX(5vh)',
+             'translateX(5vmin)',
+             'translateX(5vmax)',
+             'translateX(5%)',
+             ' ',
+             '/**/',
+             '\0',
+             ';',
+             'none;',
+             'null',
+             null, // is converted to 'null' by IDL
+             'undefined',
+             'inherit',
+             'initial',
+             'unset',
+            ].forEach(function(string) {
+                test(function() {
+                    assert_throws('SyntaxError', function() { new self[constr](string); });
+                }, `new ${constr}(${format_value(string)})`);
+            });
+
+            test(function() {
+                var sequence = [
+                    2.0, 1.0, 0.0, 0.0,
+                    1.0, 2.0, 0.0, 0.0,
+                    0.0, 0.0, 1.0, 0.0,
+                    10.0, 10.0, 0.0, 1.0];
+                checkDOMMatrix(new self[constr](sequence), {
+                    m11: 2, m21: 1, m31: 0, m41: 10,
+                    m12: 1, m22: 2, m32: 0, m42: 10,
+                    m13: 0, m23: 0, m33: 1, m43: 0,
+                    m14: 0, m24: 0, m34: 0, m44: 1,
+                    is2D: false,
+                    isIdentity: false
+                });
+            }, `new ${constr}(sequence)`);
+
+            test(function() {
+                var matrix = new self[constr]([
+                    2.0, 1.0, 0.0, 0.0,
+                    1.0, 2.0, 0.0, 0.0,
+                    0.0, 0.0, 1.0, 0.0,
+                    10.0, 10.0, 0.0, 1.0]);
+                checkDOMMatrix(new self[constr](matrix), {
+                    m11: 2, m21: 1, m31: 0, m41: 10,
+                    m12: 1, m22: 2, m32: 0, m42: 10,
+                    m13: 0, m23: 0, m33: 1, m43: 0,
+                    m14: 0, m24: 0, m34: 0, m44: 1,
+                    is2D: false,
+                    isIdentity: false
+                });
+            }, `new ${constr}(matrix)`);
+
+            ['scale(2, 2), translateX(5px) translateY(5px)',
+            ].forEach(function(string) {
+                test(function() {
+                    assert_throws("SyntaxError", function() { new self[constr](string); });
+                }, `new ${constr}(${format_value(string)})`);
+            });
+
+            [
+                [2.0, 0.0, 0.0, 0.0,
+                0.0, 2.0, 0.0, 0.0,
+                0.0, 0.0, 1.0, 0.0,
+                10.0, 10.0, 0.0, 2.0, 0.0], // 17 elements
+                [2.0, 0.0, 0.0, 0.0,
+                0.0, 2.0, 0.0, 0.0,
+                0.0, 0.0, 1.0, 0.0,
+                10.0, 10.0, 0.0], // 15 elements
+                [2.0, 0.0, 0.0, 2.0, 10.0], // 5 elements
+                [], // 0 elements
+            ].forEach(function(sequence) {
+                test(function() {
+                    assert_throws(new TypeError(), function() { new self[constr](sequence); });
+                }, `new ${constr}(sequence) ${sequence.length} elements`);
+            });
+        });
     </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-css-string.worker.js b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-css-string.worker.js
new file mode 100644
index 0000000..2dd3eea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/DOMMatrix-css-string.worker.js
@@ -0,0 +1,18 @@
+// https://drafts.fxtf.org/geometry/#DOMMatrix
+
+importScripts("/resources/testharness.js");
+
+['DOMMatrix', 'DOMMatrixReadOnly'].forEach(constr => {
+  test(() => {
+    assert_true(constr in self, `${constr} should exist`);
+    assert_throws(new TypeError(), () => new self[constr]('matrix(1,0,0,1,0,0)') );
+  }, `${constr} constructor with string argument in worker`);
+});
+
+test(() => {
+  assert_false('setMatrixValue' in DOMMatrix.prototype, 'on prototype');
+  const matrix = new DOMMatrix();
+  assert_false('setMatrixValue' in matrix, 'on instance');
+}, 'DOMMatrix setMatrixValue in worker');
+
+done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/WebKitCSSMatrix-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/WebKitCSSMatrix-expected.txt
new file mode 100644
index 0000000..dd0272a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/WebKitCSSMatrix-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL Equivalence test assert_equals: interface object expected function "function DOMMatrix() { [native code] }" but got function "function WebKitCSSMatrix() { [native code] }"
+PASS Property descriptor for WebKitCSSMatrix 
+PASS Property descriptor for DOMMatrix 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/WebKitCSSMatrix.html b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/WebKitCSSMatrix.html
new file mode 100644
index 0000000..7c28a5c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/WebKitCSSMatrix.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Geometry Interfaces: WebKitCSSMatrix</title>
+<link rel="help" href="https://drafts.fxtf.org/geometry/#DOMMatrix">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+  assert_true('WebKitCSSMatrix' in self, 'WebKitCSSMatrix should exist');
+  assert_true('DOMMatrix' in self, 'DOMMatrix should exist');
+  assert_equals(WebKitCSSMatrix, DOMMatrix, 'interface object');
+  assert_equals(WebKitCSSMatrix.prototype, DOMMatrix.prototype, 'prototype');
+}, 'Equivalence test');
+
+['WebKitCSSMatrix', 'DOMMatrix'].forEach(interf => {
+  test(() => {
+    const desc = Object.getOwnPropertyDescriptor(self, interf);
+    assert_equals(desc.value, self[interf], 'value');
+    assert_true(desc.writable, 'writable');
+    assert_true(desc.configurable, 'configurable');
+    assert_false(desc.enumerable, 'enumerable');
+    assert_equals(desc.get, undefined, 'get');
+    assert_equals(desc.set, undefined, 'set');
+  }, `Property descriptor for ${interf}`);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/WebKitCSSMatrix.worker.js b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/WebKitCSSMatrix.worker.js
new file mode 100644
index 0000000..71e2ecd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/WebKitCSSMatrix.worker.js
@@ -0,0 +1,9 @@
+// https://drafts.fxtf.org/geometry/#DOMMatrix
+
+importScripts('/resources/testharness.js');
+
+test(() => {
+  assert_false('WebKitCSSMatrix' in self);
+}, 'WebKitCSSMatrix in worker');
+
+done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/historical.html b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/historical.html
new file mode 100644
index 0000000..9d6864e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/historical.html
@@ -0,0 +1,78 @@
+<!doctype html>
+<title>Historical Geometry APIs</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<link rel=help href="https://drafts.fxtf.org/geometry/#changes">
+<script>
+// Removed members
+[
+  // https://github.com/w3c/fxtf-drafts/commit/99e3212469026b2f2f50926a41912d110a1741b7
+  ['DOMMatrixReadOnly', 'scaleNonUniform'],
+  ['DOMMatrix', 'scaleNonUniformSelf'],
+  // https://github.com/w3c/fxtf-drafts/commit/86da3dc961d442f9d8dc7ab59065a9804e109286
+  ['DOMMatrix', 'multiplyBy'],
+  ['DOMMatrix', 'preMultiplyBy'],
+  ['DOMMatrix', 'translateBy'],
+  ['DOMMatrix', 'scaleBy'],
+  ['DOMMatrix', 'scale3dBy'],
+  ['DOMMatrix', 'scaleNonUniformBy'],
+  ['DOMMatrix', 'rotateBy'],
+  ['DOMMatrix', 'rotateFromVectorBy'],
+  ['DOMMatrix', 'rotateAxisAngleBy'],
+  ['DOMMatrix', 'skewXBy'],
+  ['DOMMatrix', 'skewYBy'],
+].forEach(([interf, member]) => {
+  test(() => {
+    assert_true(interf in self, `${interf} should exist`);
+    assert_false(member in self[interf].prototype, 'on prototype');
+    const instance = new self[interf]();
+    assert_false(member in instance, 'on instance');
+  }, `${interf} ${member} must be nuked`);
+});
+
+// Removed static methods
+// https://github.com/w3c/fxtf-drafts/commit/3c43462bcc857bb830f8af04532cdf33c5a634aa
+['DOMMatrix', 'DOMMatrixReadOnly'].forEach(interf => {
+  test(() => {
+    assert_true(interf in self, `${interf} should exist`);
+    assert_false('fromString' in self[interf], 'on interface object');
+  }, `${interf} fromString static member must be nuked`);
+});
+
+// Optional arguments
+[
+  // https://github.com/w3c/fxtf-drafts/commit/99e3212469026b2f2f50926a41912d110a1741b7
+  ['DOMMatrixReadOnly', 'scale'],
+  ['DOMMatrix', 'scaleSelf'],
+  // https://github.com/w3c/fxtf-drafts/commit/8493a9c3d94da91ead5db6e05b51319494f5855f
+  ['DOMMatrixReadOnly', 'translate'],
+  ['DOMMatrixReadOnly', 'scale3d'],
+  ['DOMMatrixReadOnly', 'rotateFromVector'],
+  ['DOMMatrixReadOnly', 'rotateAxisAngle'],
+  ['DOMMatrixReadOnly', 'skewX'],
+  ['DOMMatrixReadOnly', 'skewY'],
+  ['DOMMatrix', 'translateSelf'],
+  ['DOMMatrix', 'scale3dSelf'],
+  ['DOMMatrix', 'rotateFromVectorSelf'],
+  ['DOMMatrix', 'rotateAxisAngleSelf'],
+  ['DOMMatrix', 'skewXSelf'],
+  ['DOMMatrix', 'skewYSelf'],
+  // https://github.com/w3c/fxtf-drafts/commit/62b9cb9d5be4982d2a9cbf314e3a59efb8a68dd6
+  ['DOMPointReadOnly', 'matrixTransform'],
+  ['DOMMatrixReadOnly', 'multiply'],
+  ['DOMMatrix', 'multiplySelf'],
+  ['DOMMatrix', 'preMultiplySelf'],
+].forEach(([interf, member]) => {
+  test(() => {
+    assert_equals(self[interf].prototype[member].length, 0, 'on prototype');
+    const instance = new self[interf]();
+    assert_equals(instance[member].length, 0, 'on instance');
+  }, `${interf} ${member} number of required arguments`);
+});
+
+// Renamed interfaces
+// https://github.com/w3c/fxtf-drafts/commit/9031c94c8536cec7f7007c18d7be037a793e5ed5
+test(() => {
+  assert_false('CSSMatrix' in self);
+}, 'CSSMatrix must be nuked');
+</script>
diff --git a/third_party/WebKit/Source/core/dom/AccessibleNode.cpp b/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
index 8e5437a..a8dd6c11 100644
--- a/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
+++ b/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
@@ -32,6 +32,20 @@
     }
   }
 
+  return g_null_atom;
+}
+
+// static
+const AtomicString& AccessibleNode::GetPropertyOrARIAAttribute(
+    Element* element,
+    AOMStringProperty property) {
+  if (!element)
+    return g_null_atom;
+
+  const AtomicString& result = GetProperty(element, property);
+  if (!result.IsNull())
+    return result;
+
   // Fall back on the equivalent ARIA attribute.
   switch (property) {
     case AOMStringProperty::kAutocomplete:
diff --git a/third_party/WebKit/Source/core/dom/AccessibleNode.h b/third_party/WebKit/Source/core/dom/AccessibleNode.h
index d082d34..333d5ef1 100644
--- a/third_party/WebKit/Source/core/dom/AccessibleNode.h
+++ b/third_party/WebKit/Source/core/dom/AccessibleNode.h
@@ -49,9 +49,13 @@
   explicit AccessibleNode(Element*);
   virtual ~AccessibleNode();
 
+  // Returns the given string property if the Element has an AccessibleNode.
+  static const AtomicString& GetProperty(Element*, AOMStringProperty);
+
   // Returns the given string property if the Element has an AccessibleNode,
   // otherwise returns the equivalent ARIA attribute.
-  static const AtomicString& GetProperty(Element*, AOMStringProperty);
+  static const AtomicString& GetPropertyOrARIAAttribute(Element*,
+                                                        AOMStringProperty);
 
   AtomicString autocomplete() const;
   void setAutocomplete(const AtomicString&);
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 88f37a8..53e007a 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1578,6 +1578,7 @@
     kElementNameDOMValidHTMLParserInvalid = 1969,
     kGATTServerDisconnectedEvent = 1970,
     kAnchorClickDispatchForNonConnectedNode = 1971,
+    kHTMLParseErrorNestedForm = 1972,
 
     // Add new features immediately above this line. Don't change assigned
     // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp b/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp
index 056c065..3b3c58b 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp
@@ -618,6 +618,8 @@
   if (token->GetName() == formTag) {
     if (tree_.IsFormElementPointerNonNull() && !IsParsingTemplateContents()) {
       ParseError(token);
+      UseCounter::Count(tree_.CurrentNode()->GetDocument(),
+                        UseCounter::kHTMLParseErrorNestedForm);
       return;
     }
     ProcessFakePEndTagIfPInButtonScope();
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
index 8d63c1de..2cae448c 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
@@ -389,7 +389,7 @@
   if (!node || !node->IsElementNode())
     return g_null_atom;
 
-  return AccessibleNode::GetProperty(ToElement(node), property);
+  return AccessibleNode::GetPropertyOrARIAAttribute(ToElement(node), property);
 }
 
 bool AXObject::IsARIATextControl() const {
diff --git a/third_party/WebKit/Source/platform/fonts/SymbolsIteratorTest.cpp b/third_party/WebKit/Source/platform/fonts/SymbolsIteratorTest.cpp
index 79c1ae70..8fbc26a 100644
--- a/third_party/WebKit/Source/platform/fonts/SymbolsIteratorTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/SymbolsIteratorTest.cpp
@@ -222,4 +222,150 @@
                FontFallbackPriority::kEmojiEmoji}});
 }
 
+// Extracted from http://unicode.org/emoji/charts/emoji-released.html for Emoji
+// v5.0, except for the subdivision-flag section. Currently blocked on ICU 59
+// upgrade, TODO(jshin): crbug.com/699469
+// Before ICU 59 new emoji sequences and new single emoji are not detected as
+// emoji type text and sequences get split up in the middle so that shaping
+// cannot form the right glyph from the emoji font. Running this as one run in
+// one test ensures that the new emoji form an unbroken emoji-type sequence.
+TEST_F(SymbolsIteratorTest, DISABLED_Emoji5AdditionsExceptFlags) {
+  CHECK_RUNS(
+      {{"\xF0\x9F\xA7\x94\xF0\x9F\x8F\xBB\xF0\x9F\xA7\x94\xF0\x9F\x8F\xBC\xF0"
+        "\x9F\xA7\x94\xF0\x9F\x8F\xBD\xF0\x9F\xA7\x94\xF0\x9F\x8F\xBE\xF0\x9F"
+        "\xA7\x94\xF0\x9F\x8F\xBF\xF0\x9F\xA4\xB1\xF0\x9F\xA4\xB1\xF0\x9F\x8F"
+        "\xBB\xF0\x9F\xA4\xB1\xF0\x9F\x8F\xBC\xF0\x9F\xA4\xB1\xF0\x9F\x8F\xBD"
+        "\xF0\x9F\xA4\xB1\xF0\x9F\x8F\xBE\xF0\x9F\xA4\xB1\xF0\x9F\x8F\xBF\xF0"
+        "\x9F\xA7\x99\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBB\xF0\x9F\xA7\x99\xF0\x9F"
+        "\x8F\xBC\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBD\xF0\x9F\xA7\x99\xF0\x9F\x8F"
+        "\xBE\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBF\xF0\x9F\xA7\x99\xE2\x80\x8D\xE2"
+        "\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBB\xE2\x80\x8D\xE2"
+        "\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBC\xE2\x80\x8D\xE2"
+        "\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBD\xE2\x80\x8D\xE2"
+        "\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBE\xE2\x80\x8D\xE2"
+        "\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBF\xE2\x80\x8D\xE2"
+        "\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x99\xE2\x80\x8D\xE2\x99\x82\xEF\xB8"
+        "\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBB\xE2\x80\x8D\xE2\x99\x82\xEF\xB8"
+        "\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBC\xE2\x80\x8D\xE2\x99\x82\xEF\xB8"
+        "\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBD\xE2\x80\x8D\xE2\x99\x82\xEF\xB8"
+        "\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBE\xE2\x80\x8D\xE2\x99\x82\xEF\xB8"
+        "\x8F\xF0\x9F\xA7\x99\xF0\x9F\x8F\xBF\xE2\x80\x8D\xE2\x99\x82\xEF\xB8"
+        "\x8F\xF0\x9F\xA7\x9A\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBB\xF0\x9F\xA7\x9A"
+        "\xF0\x9F\x8F\xBC\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBD\xF0\x9F\xA7\x9A\xF0"
+        "\x9F\x8F\xBE\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBF\xF0\x9F\xA7\x9A\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBB\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBC\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBD\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBE\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBF\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBB\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBC\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBD\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBE\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x9A\xF0\x9F\x8F\xBF\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBB\xF0\x9F"
+        "\xA7\x9B\xF0\x9F\x8F\xBC\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBD\xF0\x9F\xA7"
+        "\x9B\xF0\x9F\x8F\xBE\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBF\xF0\x9F\xA7\x9B"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBB"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBC"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBD"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBE"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBF"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBB\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBC\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBD\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBE\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9B\xF0\x9F\x8F\xBF\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F\xA7\x9C\xF0\x9F\x8F\xBB"
+        "\xF0\x9F\xA7\x9C\xF0\x9F\x8F\xBC\xF0\x9F\xA7\x9C\xF0\x9F\x8F\xBD\xF0"
+        "\x9F\xA7\x9C\xF0\x9F\x8F\xBE\xF0\x9F\xA7\x9C\xF0\x9F\x8F\xBF\xF0\x9F"
+        "\xA7\x9C\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F"
+        "\x8F\xBB\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F"
+        "\x8F\xBC\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F"
+        "\x8F\xBD\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F"
+        "\x8F\xBE\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F"
+        "\x8F\xBF\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F\x8F\xBB\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F\x8F\xBC\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F\x8F\xBD\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F\x8F\xBE\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9C\xF0\x9F\x8F\xBF\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9D\xF0\x9F\xA7\x9D\xF0\x9F"
+        "\x8F\xBB\xF0\x9F\xA7\x9D\xF0\x9F\x8F\xBC\xF0\x9F\xA7\x9D\xF0\x9F\x8F"
+        "\xBD\xF0\x9F\xA7\x9D\xF0\x9F\x8F\xBE\xF0\x9F\xA7\x9D\xF0\x9F\x8F\xBF"
+        "\xF0\x9F\xA7\x9D\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9D"
+        "\xF0\x9F\x8F\xBB\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9D"
+        "\xF0\x9F\x8F\xBC\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9D"
+        "\xF0\x9F\x8F\xBD\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9D"
+        "\xF0\x9F\x8F\xBE\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9D"
+        "\xF0\x9F\x8F\xBF\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9D"
+        "\xE2\x80\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9D\xF0\x9F\x8F\xBB"
+        "\xE2\x80\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9D\xF0\x9F\x8F\xBC"
+        "\xE2\x80\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9D\xF0\x9F\x8F\xBD"
+        "\xE2\x80\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9D\xF0\x9F\x8F\xBE"
+        "\xE2\x80\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9D\xF0\x9F\x8F\xBF"
+        "\xE2\x80\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9E\xF0\x9F\xA7\x9E"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9E\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x9F\xF0\x9F\xA7\x9F\xE2\x80\x8D\xE2"
+        "\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x9F\xE2\x80\x8D\xE2\x99\x82\xEF\xB8"
+        "\x8F\xF0\x9F\xA7\x96\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBB\xF0\x9F\xA7\x96"
+        "\xF0\x9F\x8F\xBC\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBD\xF0\x9F\xA7\x96\xF0"
+        "\x9F\x8F\xBE\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBF\xF0\x9F\xA7\x96\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBB\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBC\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBD\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBE\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBF\xE2\x80"
+        "\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x96\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBB\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBC\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBD\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBE\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x96\xF0\x9F\x8F\xBF\xE2\x80\x8D\xE2\x99\x82"
+        "\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBB\xF0\x9F"
+        "\xA7\x97\xF0\x9F\x8F\xBC\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBD\xF0\x9F\xA7"
+        "\x97\xF0\x9F\x8F\xBE\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBF\xF0\x9F\xA7\x97"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBB"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBC"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBD"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBE"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBF"
+        "\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x97\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBB\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBC\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBD\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBE\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x97\xF0\x9F\x8F\xBF\xE2\x80\x8D\xE2"
+        "\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F\xA7\x98\xF0\x9F\x8F\xBB"
+        "\xF0\x9F\xA7\x98\xF0\x9F\x8F\xBC\xF0\x9F\xA7\x98\xF0\x9F\x8F\xBD\xF0"
+        "\x9F\xA7\x98\xF0\x9F\x8F\xBE\xF0\x9F\xA7\x98\xF0\x9F\x8F\xBF\xF0\x9F"
+        "\xA7\x98\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F"
+        "\x8F\xBB\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F"
+        "\x8F\xBC\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F"
+        "\x8F\xBD\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F"
+        "\x8F\xBE\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F"
+        "\x8F\xBF\xE2\x80\x8D\xE2\x99\x80\xEF\xB8\x8F\xF0\x9F\xA7\x98\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F\x8F\xBB\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F\x8F\xBC\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F\x8F\xBD\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F\x8F\xBE\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA7\x98\xF0\x9F\x8F\xBF\xE2\x80"
+        "\x8D\xE2\x99\x82\xEF\xB8\x8F\xF0\x9F\xA4\x9F\xF0\x9F\xA4\x9F\xF0\x9F"
+        "\x8F\xBB\xF0\x9F\xA4\x9F\xF0\x9F\x8F\xBC\xF0\x9F\xA4\x9F\xF0\x9F\x8F"
+        "\xBD\xF0\x9F\xA4\x9F\xF0\x9F\x8F\xBE\xF0\x9F\xA4\x9F\xF0\x9F\x8F\xBF"
+        "\xF0\x9F\xA4\xB2\xF0\x9F\xA4\xB2\xF0\x9F\x8F\xBB\xF0\x9F\xA4\xB2\xF0"
+        "\x9F\x8F\xBC\xF0\x9F\xA4\xB2\xF0\x9F\x8F\xBD\xF0\x9F\xA4\xB2\xF0\x9F"
+        "\x8F\xBE\xF0\x9F\xA4\xB2\xF0\x9F\x8F\xBF\xF0\x9F\xA7\xA0\xF0\x9F\xA7"
+        "\xA1\xF0\x9F\xA7\xA3\xF0\x9F\xA7\xA4\xF0\x9F\xA7\xA5\xF0\x9F\xA7\xA6"
+        "\xF0\x9F\xA7\xA2\xF0\x9F\xA6\x93\xF0\x9F\xA6\x92\xF0\x9F\xA6\x94\xF0"
+        "\x9F\xA6\x95\xF0\x9F\xA6\x96\xF0\x9F\xA6\x97\xF0\x9F\xA5\xA5\xF0\x9F"
+        "\xA5\xA6\xF0\x9F\xA5\xA8\xF0\x9F\xA5\xA9\xF0\x9F\xA5\xAA\xF0\x9F\xA5"
+        "\xA3\xF0\x9F\xA5\xAB\xF0\x9F\xA5\x9F\xF0\x9F\xA5\xA0\xF0\x9F\xA5\xA1"
+        "\xF0\x9F\xA5\xA7\xF0\x9F\xA5\xA4\xF0\x9F\xA5\xA2\xF0\x9F\x9B\xB8\xF0"
+        "\x9F\x9B\xB7\xF0\x9F\xA5\x8C",
+        FontFallbackPriority::kEmojiEmoji}});
+}
+
 }  // namespace blink
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 3036796..816d6b7 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -14847,6 +14847,7 @@
   <int value="1969" label="ElementNameDOMValidHTMLParserInvalid"/>
   <int value="1970" label="GATTServerDisconnectedEvent"/>
   <int value="1971" label="AnchorClickDispatchForNonConnectedNode"/>
+  <int value="1972" label="HTMLParseErrorNestedForm"/>
 </enum>
 
 <enum name="FeedbackSource" type="int">
@@ -30740,6 +30741,8 @@
   <int value="281" label="PPSX"/>
   <int value="282" label="SLDX"/>
   <int value="283" label="SLDM"/>
+  <int value="284" label="HTM"/>
+  <int value="285" label="HTML"/>
 </enum>
 
 <enum name="SBClientDownloadIsSignedBinary" type="int">
diff --git a/ui/base/ime/input_method.h b/ui/base/ime/input_method.h
index 67010a3..6b1d526 100644
--- a/ui/base/ime/input_method.h
+++ b/ui/base/ime/input_method.h
@@ -15,6 +15,7 @@
 #include "build/build_config.h"
 #include "ui/base/ime/text_input_mode.h"
 #include "ui/base/ime/text_input_type.h"
+#include "ui/gfx/geometry/rect.h"
 
 namespace extensions {
 class InputImeApiTest;
@@ -160,6 +161,9 @@
   virtual void AddObserver(InputMethodObserver* observer) = 0;
   virtual void RemoveObserver(InputMethodObserver* observer) = 0;
 
+  // Set screen bounds of a on-screen keyboard.
+  virtual void SetOnScreenKeyboardBounds(const gfx::Rect& new_bounds) {}
+
  protected:
   friend class extensions::InputImeApiTest;
 
diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc
index 492d7f9a..f436c5d5 100644
--- a/ui/base/ime/input_method_base.cc
+++ b/ui/base/ime/input_method_base.cc
@@ -63,6 +63,12 @@
   return text_input_client_;
 }
 
+void InputMethodBase::SetOnScreenKeyboardBounds(const gfx::Rect& new_bounds) {
+  keyboard_bounds_ = new_bounds;
+  if (text_input_client_)
+    text_input_client_->EnsureCaretNotInRect(keyboard_bounds_);
+}
+
 void InputMethodBase::OnTextInputTypeChanged(const TextInputClient* client) {
   if (!IsTextInputClientFocused(client))
     return;
@@ -152,6 +158,10 @@
   text_input_client_ = client;  // nullptr allowed.
   OnDidChangeFocusedClient(old, client);
   NotifyTextInputStateChanged(text_input_client_);
+
+  // Move new focused window if necessary.
+  if (text_input_client_)
+    text_input_client_->EnsureCaretNotInRect(keyboard_bounds_);
 }
 
 std::vector<gfx::Rect> InputMethodBase::GetCompositionBounds(
diff --git a/ui/base/ime/input_method_base.h b/ui/base/ime/input_method_base.h
index 1daa0e9..aa16c6f 100644
--- a/ui/base/ime/input_method_base.h
+++ b/ui/base/ime/input_method_base.h
@@ -43,6 +43,7 @@
   void SetFocusedTextInputClient(TextInputClient* client) override;
   void DetachTextInputClient(TextInputClient* client) override;
   TextInputClient* GetTextInputClient() const override;
+  void SetOnScreenKeyboardBounds(const gfx::Rect& new_bounds) override;
 
   // If a derived class overrides this method, it should call parent's
   // implementation.
@@ -124,6 +125,9 @@
 
   std::vector<std::unique_ptr<ui::KeyEvent>> key_events_for_testing_;
 
+  // Screen bounds of a on-screen keyboard.
+  gfx::Rect keyboard_bounds_;
+
   DISALLOW_COPY_AND_ASSIGN(InputMethodBase);
 };
 
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index e07e020a..c5569e3 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -520,6 +520,7 @@
   ui_->HideKeyboardContainer(container_.get());
   for (KeyboardControllerObserver& observer : observer_list_)
     observer.OnKeyboardHidden();
+  ui_->EnsureCaretInWorkArea();
 }
 
 void KeyboardController::AdjustKeyboardBounds() {
diff --git a/ui/keyboard/keyboard_ui.cc b/ui/keyboard/keyboard_ui.cc
index 896add64..69b1f1e 100644
--- a/ui/keyboard/keyboard_ui.cc
+++ b/ui/keyboard/keyboard_ui.cc
@@ -4,9 +4,11 @@
 
 #include "ui/keyboard/keyboard_ui.h"
 
+#include "base/command_line.h"
 #include "ui/aura/window.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/text_input_client.h"
+#include "ui/base/ui_base_switches.h"
 #include "ui/keyboard/keyboard_controller.h"
 
 namespace keyboard {
@@ -29,10 +31,26 @@
 }
 
 void KeyboardUI::EnsureCaretInWorkArea() {
-  if (GetInputMethod()->GetTextInputClient()) {
-    aura::Window* keyboard_window = GetKeyboardWindow();
+  if (!GetInputMethod())
+    return;
+
+  const aura::Window* keyboard_window = GetKeyboardWindow();
+  const gfx::Rect keyboard_bounds_in_screen =
+      keyboard_window->IsVisible() ? keyboard_window->GetBoundsInScreen()
+                                   : gfx::Rect();
+
+  // Use new virtual keyboard behavior only if the flag enabled and in
+  // non-sticky mode.
+  const bool new_vk_behavior =
+      (base::CommandLine::ForCurrentProcess()->HasSwitch(
+           ::switches::kUseNewVirtualKeyboardBehavior) &&
+       !keyboard::KeyboardController::GetInstance()->keyboard_locked());
+
+  if (new_vk_behavior) {
+    GetInputMethod()->SetOnScreenKeyboardBounds(keyboard_bounds_in_screen);
+  } else if (GetInputMethod()->GetTextInputClient()) {
     GetInputMethod()->GetTextInputClient()->EnsureCaretNotInRect(
-        keyboard_window->GetBoundsInScreen());
+        keyboard_bounds_in_screen);
   }
 }
 
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 2c7c520d..147e648 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -7,12 +7,15 @@
 #include <string>
 #include <utility>
 
+#include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/base/default_style.h"
@@ -21,6 +24,7 @@
 #include "ui/base/ime/text_edit_commands.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_switches.h"
 #include "ui/base/ui_base_switches_util.h"
 #include "ui/compositor/canvas_painter.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -47,6 +51,7 @@
 #include "ui/views/style/platform_style.h"
 #include "ui/views/views_delegate.h"
 #include "ui/views/widget/widget.h"
+#include "ui/wm/core/coordinate_conversion.h"
 
 #if defined(OS_WIN)
 #include "base/win/win_util.h"
@@ -63,6 +68,10 @@
 #include "ui/base/x/x11_util_internal.h"  // nogncheck
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "ui/wm/core/ime_util_chromeos.h"
+#endif
+
 namespace views {
 
 namespace {
@@ -1013,8 +1022,13 @@
 void Textfield::OnBlur() {
   gfx::RenderText* render_text = GetRenderText();
   render_text->set_focused(false);
-  if (GetInputMethod())
+  if (GetInputMethod()) {
     GetInputMethod()->DetachTextInputClient(this);
+#if defined(OS_CHROMEOS)
+    wm::RestoreWindowBoundsOnClientFocusLost(
+        GetNativeView()->GetToplevelWindow());
+#endif  // defined(OS_CHROMEOS)
+  }
   StopBlinkingCursor();
   cursor_view_.SetVisible(false);
 
@@ -1485,7 +1499,12 @@
     DeleteRange(range);
 }
 
-void Textfield::EnsureCaretNotInRect(const gfx::Rect& rect) {}
+void Textfield::EnsureCaretNotInRect(const gfx::Rect& rect_in_screen) {
+#if defined(OS_CHROMEOS)
+  aura::Window* top_level_window = GetNativeView()->GetToplevelWindow();
+  wm::EnsureWindowNotInRect(top_level_window, rect_in_screen);
+#endif  // defined(OS_CHROMEOS)
+}
 
 bool Textfield::IsTextEditCommandEnabled(ui::TextEditCommand command) const {
   base::string16 result;
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index d712c65..c9e9d1c 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/aura/window.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
@@ -62,6 +63,10 @@
 #include "ui/events/event_utils.h"
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "ui/wm/core/ime_util_chromeos.h"
+#endif
+
 using base::ASCIIToUTF16;
 using base::UTF8ToUTF16;
 using base::WideToUTF16;
@@ -2953,6 +2958,48 @@
   EXPECT_TRUE(test_api_->IsCursorBlinkTimerRunning());
 }
 
+#if defined(OS_CHROMEOS)
+// Check that when accessibility virtual keyboard is enabled, windows are
+// shifted up when focused and restored when focus is lost.
+TEST_F(TextfieldTest, VirtualKeyboardFocusEnsureCaretNotInRect) {
+  InitTextfield();
+
+  // Enable new virtual keyboard behavior.
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (!command_line->HasSwitch(::switches::kUseNewVirtualKeyboardBehavior)) {
+    command_line->AppendSwitch(::switches::kUseNewVirtualKeyboardBehavior);
+  }
+
+  aura::Window* root_window = widget_->GetNativeView()->GetRootWindow();
+  int keyboard_height = 200;
+  gfx::Rect root_bounds = root_window->bounds();
+  gfx::Rect orig_widget_bounds = gfx::Rect(0, 300, 400, 200);
+  gfx::Rect shifted_widget_bounds = gfx::Rect(0, 200, 400, 200);
+  gfx::Rect keyboard_view_bounds =
+      gfx::Rect(0, root_bounds.height() - keyboard_height, root_bounds.width(),
+                keyboard_height);
+
+  // Focus the window.
+  widget_->SetBounds(orig_widget_bounds);
+  input_method_->SetFocusedTextInputClient(textfield_);
+  EXPECT_EQ(widget_->GetNativeView()->bounds(), orig_widget_bounds);
+
+  // Simulate virtual keyboard.
+  input_method_->SetOnScreenKeyboardBounds(keyboard_view_bounds);
+
+  // Window should be shifted.
+  EXPECT_EQ(widget_->GetNativeView()->bounds(), shifted_widget_bounds);
+
+  // Detach the textfield from the IME
+  input_method_->DetachTextInputClient(textfield_);
+  wm::RestoreWindowBoundsOnClientFocusLost(
+      widget_->GetNativeView()->GetToplevelWindow());
+
+  // Window should be restored.
+  EXPECT_EQ(widget_->GetNativeView()->bounds(), orig_widget_bounds);
+}
+#endif  // defined(OS_CHROMEOS)
+
 class TextfieldTouchSelectionTest : public TextfieldTest {
  protected:
   // Simulates a complete tap.
diff --git a/ui/wm/BUILD.gn b/ui/wm/BUILD.gn
index a490bbe2..16674713 100644
--- a/ui/wm/BUILD.gn
+++ b/ui/wm/BUILD.gn
@@ -86,6 +86,13 @@
     configs += [ "//build/config/linux:x11" ]
     deps += [ "//ui/events/devices/x11" ]
   }
+
+  if (is_chromeos) {
+    sources += [
+      "core/ime_util_chromeos.cc",
+      "core/ime_util_chromeos.h",
+    ]
+  }
 }
 
 static_library("test_support") {
@@ -149,4 +156,8 @@
   data_deps = [
     "//ui/resources:ui_test_pak_data",
   ]
+
+  if (is_chromeos) {
+    sources += [ "core/ime_util_chromeos_unittest.cc" ]
+  }
 }
diff --git a/ui/wm/core/ime_util_chromeos.cc b/ui/wm/core/ime_util_chromeos.cc
new file mode 100644
index 0000000..4e57d2d4
--- /dev/null
+++ b/ui/wm/core/ime_util_chromeos.cc
@@ -0,0 +1,100 @@
+// 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 "ui/wm/core/ime_util_chromeos.h"
+
+#include "base/command_line.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/wm/core/coordinate_conversion.h"
+
+namespace wm {
+namespace {
+
+// Moves the window to ensure caret not in rect.
+// Returns whether the window was moved or not.
+void MoveWindowToEnsureCaretNotInRect(aura::Window* window,
+                                      const gfx::Rect& rect_in_screen) {
+  gfx::Rect original_window_bounds = window->GetBoundsInScreen();
+  if (window->GetProperty(kVirtualKeyboardRestoreBoundsKey)) {
+    original_window_bounds =
+        *window->GetProperty(kVirtualKeyboardRestoreBoundsKey);
+  }
+
+  // Calculate vertical window shift.
+  gfx::Rect rect_in_root_window = rect_in_screen;
+  ::wm::ConvertRectFromScreen(window->GetRootWindow(), &rect_in_root_window);
+  gfx::Rect bounds_in_root_window = original_window_bounds;
+  ::wm::ConvertRectFromScreen(window->GetRootWindow(), &bounds_in_root_window);
+  const int top_y =
+      std::max(rect_in_root_window.y() - bounds_in_root_window.height(), 0);
+
+  // No need to move the window up.
+  if (top_y >= bounds_in_root_window.y())
+    return;
+
+  // Set restore bounds and move the window.
+  window->SetProperty(kVirtualKeyboardRestoreBoundsKey,
+                      new gfx::Rect(original_window_bounds));
+
+  gfx::Rect new_bounds_in_root_window = bounds_in_root_window;
+  new_bounds_in_root_window.set_y(top_y);
+  window->SetBounds(new_bounds_in_root_window);
+}
+
+}  // namespace
+
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Rect,
+                                   kVirtualKeyboardRestoreBoundsKey,
+                                   nullptr);
+
+void RestoreWindowBoundsOnClientFocusLost(aura::Window* window) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          ::switches::kUseNewVirtualKeyboardBehavior))
+    return;
+
+  // Get restore bounds of the window
+  gfx::Rect* vk_restore_bounds =
+      window->GetProperty(kVirtualKeyboardRestoreBoundsKey);
+
+  if (!vk_restore_bounds)
+    return;
+
+  // Restore the window bounds
+  // TODO(yhanada): Don't move the window if a user has moved it while the
+  // keyboard is shown.
+  if (window->GetBoundsInScreen() != *vk_restore_bounds) {
+    gfx::Rect original_bounds = *vk_restore_bounds;
+    ::wm::ConvertRectFromScreen(window->GetRootWindow(), &original_bounds);
+    window->SetBounds(original_bounds);
+  }
+  window->ClearProperty(wm::kVirtualKeyboardRestoreBoundsKey);
+}
+
+void EnsureWindowNotInRect(aura::Window* window,
+                           const gfx::Rect& rect_in_screen) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          ::switches::kUseNewVirtualKeyboardBehavior))
+    return;
+
+  gfx::Rect original_window_bounds = window->GetBoundsInScreen();
+  if (window->GetProperty(wm::kVirtualKeyboardRestoreBoundsKey)) {
+    original_window_bounds =
+        *window->GetProperty(wm::kVirtualKeyboardRestoreBoundsKey);
+  }
+
+  gfx::Rect hidden_window_bounds_in_screen =
+      gfx::IntersectRects(rect_in_screen, original_window_bounds);
+  if (hidden_window_bounds_in_screen.IsEmpty()) {
+    // The window isn't covered by the keyboard, restore the window position if
+    // necessary.
+    RestoreWindowBoundsOnClientFocusLost(window);
+    return;
+  }
+
+  MoveWindowToEnsureCaretNotInRect(window, rect_in_screen);
+}
+
+}  // namespace wm
diff --git a/ui/wm/core/ime_util_chromeos.h b/ui/wm/core/ime_util_chromeos.h
new file mode 100644
index 0000000..39ed2228
--- /dev/null
+++ b/ui/wm/core/ime_util_chromeos.h
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_WM_CORE_IME_UTIL_CHROMEOS_H_
+#define UI_WM_CORE_IME_UTIL_CHROMEOS_H_
+
+#include "ui/aura/window.h"
+#include "ui/wm/wm_export.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace wm {
+
+// A property key to store the restore bounds for a window when moved by the
+// virtual keyboard.
+WM_EXPORT extern const aura::WindowProperty<gfx::Rect*>* const
+    kVirtualKeyboardRestoreBoundsKey;
+
+// Moves the window, if needed, to ensure it does not intersect with
+// |rect_in_screen|.
+WM_EXPORT void EnsureWindowNotInRect(aura::Window* window,
+                                     const gfx::Rect& rect_in_screen);
+
+// Restores the window bounds when input client loses the focus on the window.
+WM_EXPORT void RestoreWindowBoundsOnClientFocusLost(
+    aura::Window* top_level_window);
+
+}  // namespace wm
+
+#endif  // UI_WM_CORE_IME_UTIL_CHROMEOS_H_
diff --git a/ui/wm/core/ime_util_chromeos_unittest.cc b/ui/wm/core/ime_util_chromeos_unittest.cc
new file mode 100644
index 0000000..a0887bb
--- /dev/null
+++ b/ui/wm/core/ime_util_chromeos_unittest.cc
@@ -0,0 +1,143 @@
+// 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 "ui/wm/core/ime_util_chromeos.h"
+
+#include "base/command_line.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/wm/core/default_screen_position_client.h"
+
+namespace wm {
+
+class ImeUtilChromeosTest : public aura::test::AuraTestBase {
+ public:
+  ImeUtilChromeosTest() = default;
+  ~ImeUtilChromeosTest() override = default;
+
+  void SetUp() override {
+    AuraTestBase::SetUp();
+    screen_position_client_ = base::MakeUnique<DefaultScreenPositionClient>();
+    aura::client::SetScreenPositionClient(root_window(),
+                                          screen_position_client_.get());
+
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    if (!command_line->HasSwitch(::switches::kUseNewVirtualKeyboardBehavior))
+      command_line->AppendSwitch(::switches::kUseNewVirtualKeyboardBehavior);
+  }
+
+  void TearDown() override {
+    aura::client::SetScreenPositionClient(root_window(), nullptr);
+    AuraTestBase::TearDown();
+  }
+
+ private:
+  std::unique_ptr<aura::client::ScreenPositionClient> screen_position_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImeUtilChromeosTest);
+};
+
+TEST_F(ImeUtilChromeosTest, RestoreWindowBounds) {
+  const gfx::Rect bounds(10, 20, 100, 200);
+  aura::Window* window =
+      aura::test::CreateTestWindowWithBounds(bounds, root_window());
+
+  EXPECT_EQ(nullptr, window->GetProperty(kVirtualKeyboardRestoreBoundsKey));
+  EXPECT_EQ(bounds, window->bounds());
+
+  RestoreWindowBoundsOnClientFocusLost(window);
+  EXPECT_EQ(bounds, window->bounds());
+
+  gfx::Rect r1(40, 50, 150, 200);
+  window->SetProperty(kVirtualKeyboardRestoreBoundsKey, new gfx::Rect(r1));
+  RestoreWindowBoundsOnClientFocusLost(window);
+  EXPECT_EQ(r1, window->bounds());
+  EXPECT_EQ(nullptr, window->GetProperty(kVirtualKeyboardRestoreBoundsKey));
+}
+
+TEST_F(ImeUtilChromeosTest, EnsureWindowNotInRect_NotCovered) {
+  const gfx::Rect bounds(0, 0, 100, 200);
+  aura::Window* window =
+      aura::test::CreateTestWindowWithBounds(bounds, root_window());
+  EXPECT_EQ(bounds, window->bounds());
+  EXPECT_EQ(bounds, window->GetBoundsInScreen());
+
+  // The rect doesn't overlap on the window.
+  gfx::Rect rect(300, 300, 100, 100);
+  EXPECT_TRUE(gfx::IntersectRects(window->GetBoundsInScreen(), rect).IsEmpty());
+  EnsureWindowNotInRect(window, rect);
+  // The bounds should not be changed.
+  EXPECT_EQ(bounds, window->bounds());
+  EXPECT_EQ(bounds, window->GetBoundsInScreen());
+}
+
+TEST_F(ImeUtilChromeosTest, EnsureWindowNotInRect_MoveUp) {
+  const gfx::Rect original_bounds(10, 100, 100, 10);
+  aura::Window* window =
+      aura::test::CreateTestWindowWithBounds(original_bounds, root_window());
+  EXPECT_EQ(original_bounds, window->bounds());
+  EXPECT_EQ(original_bounds, window->GetBoundsInScreen());
+
+  // The rect overlaps the window. The window is moved up by
+  // EnsureWindowNotInRect.
+  gfx::Rect rect(50, 50, 200, 200);
+  EXPECT_FALSE(
+      gfx::IntersectRects(window->GetBoundsInScreen(), rect).IsEmpty());
+  EnsureWindowNotInRect(window, rect);
+  EXPECT_EQ(gfx::Rect(10, 40, 100, 10), window->bounds());
+  EXPECT_EQ(gfx::Rect(10, 40, 100, 10), window->GetBoundsInScreen());
+}
+
+TEST_F(ImeUtilChromeosTest, EnsureWindowNotInRect_MoveToTop) {
+  const gfx::Rect original_bounds(10, 10, 100, 100);
+  aura::Window* window =
+      aura::test::CreateTestWindowWithBounds(original_bounds, root_window());
+  EXPECT_EQ(original_bounds, window->bounds());
+  EXPECT_EQ(original_bounds, window->GetBoundsInScreen());
+
+  // The rect overlaps the window. The window is moved up by
+  // EnsureWinodwNotInRect, but there is not enough space above the window.
+  gfx::Rect rect(50, 50, 200, 200);
+  EXPECT_FALSE(
+      gfx::IntersectRects(window->GetBoundsInScreen(), rect).IsEmpty());
+  EnsureWindowNotInRect(window, rect);
+  EXPECT_EQ(gfx::Rect(10, 0, 100, 100), window->bounds());
+  EXPECT_EQ(gfx::Rect(10, 0, 100, 100), window->GetBoundsInScreen());
+}
+
+TEST_F(ImeUtilChromeosTest, MoveUpThenRestore) {
+  const gfx::Rect original_bounds(50, 50, 100, 100);
+  aura::Window* window =
+      aura::test::CreateTestWindowWithBounds(original_bounds, root_window());
+  EXPECT_EQ(original_bounds, window->bounds());
+  EXPECT_EQ(original_bounds, window->GetBoundsInScreen());
+
+  // EnsureWindowNotInRect moves up the window.
+  gfx::Rect rect(50, 50, 200, 200);
+  EXPECT_FALSE(
+      gfx::IntersectRects(window->GetBoundsInScreen(), rect).IsEmpty());
+  EnsureWindowNotInRect(window, rect);
+  EXPECT_EQ(gfx::Rect(50, 0, 100, 100), window->bounds());
+  EXPECT_EQ(gfx::Rect(50, 0, 100, 100), window->GetBoundsInScreen());
+
+  // The new rect doesn't overlap the moved window bounds, but still overlaps
+  // the original window bounds.
+  rect = gfx::Rect(50, 120, 200, 200);
+  EXPECT_FALSE(gfx::IntersectRects(rect, original_bounds).IsEmpty());
+  EnsureWindowNotInRect(window, rect);
+  EXPECT_EQ(gfx::Rect(50, 20, 100, 100), window->bounds());
+  EXPECT_EQ(gfx::Rect(50, 20, 100, 100), window->GetBoundsInScreen());
+
+  // Now the rect doesn't overlap the original window bounds. The original
+  // window bounds should be restored.
+  rect = gfx::Rect(200, 200, 200, 200);
+  EXPECT_TRUE(gfx::IntersectRects(rect, original_bounds).IsEmpty());
+  EnsureWindowNotInRect(window, rect);
+  EXPECT_EQ(original_bounds, window->bounds());
+  EXPECT_EQ(original_bounds, window->GetBoundsInScreen());
+}
+
+}  // namespace wm