diff --git a/BUILD.gn b/BUILD.gn
index 6943ee4..39aace08 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -546,7 +546,6 @@
     deps += [
       "//third_party/breakpad:crash_inspector",
       "//third_party/breakpad:dump_syms",
-      "//third_party/molokocacao",
     ]
     deps -= [
       # Mojo in GN contains some things which are never compiled in GYP on Mac,
diff --git a/DEPS b/DEPS
index 211d474f..8795c742 100644
--- a/DEPS
+++ b/DEPS
@@ -105,7 +105,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd37570b325e2a8c78aa232d13e502c8d24de7d46',
+  'skia_revision': 'f18c297cfb74a48b748bc7909991f98dabb8d460',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -117,7 +117,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'b36a4816a5460120249e89258af3c5741301de40',
+  'angle_revision': '299bdfe75173549470981d70e88dd55c02123abb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -129,7 +129,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'fed6e124109f089a38e24e37b104d983231bee78',
+  'pdfium_revision': '072d829e2cd1586645022498a01a61db83a2db4d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -620,7 +620,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8e64369342f22b0541d438bac748c93fe4b8d14e',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c4a7356a469b3b6267965d7bcc318cf35cdd3b62',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1137,7 +1137,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@be0a57bc9068ed15b2c91555ab9c5622baf18a36',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d57b80dd25bd5e5766a2efa2f7b602c7588de818',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 7b89949b..48b0bc0 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -1082,12 +1082,7 @@
     version_name = chrome_version_name
     android_manifest = system_webview_android_manifest
     android_manifest_dep = ":system_webview_manifest"
-    deps = [
-      ":platform_service_bridge_upstream_implementation_java",
-      ":system_webview_resources",
-      "//android_webview/glue",
-      "//android_webview/support_library:support_lib_glue_java",
-    ]
+    deps = upstream_only_webview_deps
     apk_name = "SystemWebView"
   }
 }
diff --git a/android_webview/browser/aw_autofill_client.cc b/android_webview/browser/aw_autofill_client.cc
index e60f6db8..4c9dbc2 100644
--- a/android_webview/browser/aw_autofill_client.cc
+++ b/android_webview/browser/aw_autofill_client.cc
@@ -290,7 +290,7 @@
 
 void AwAutofillClient::ConfirmSaveCreditCardLocally(
     const autofill::CreditCard& card,
-    const base::Closure& callback) {
+    base::OnceClosure callback) {
   NOTIMPLEMENTED();
 }
 
@@ -309,7 +309,7 @@
 }
 
 void AwAutofillClient::LoadRiskData(
-    const base::Callback<void(const std::string&)>& callback) {
+    base::OnceCallback<void(const std::string&)> callback) {
   NOTIMPLEMENTED();
 }
 
diff --git a/android_webview/browser/aw_autofill_client.h b/android_webview/browser/aw_autofill_client.h
index 610de1e5..311542f 100644
--- a/android_webview/browser/aw_autofill_client.h
+++ b/android_webview/browser/aw_autofill_client.h
@@ -83,7 +83,7 @@
   void ConfirmSaveAutofillProfile(const autofill::AutofillProfile& profile,
                                   base::OnceClosure callback) override;
   void ConfirmSaveCreditCardLocally(const autofill::CreditCard& card,
-                                    const base::Closure& callback) override;
+                                    base::OnceClosure callback) override;
   void ConfirmSaveCreditCardToCloud(
       const autofill::CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
@@ -92,7 +92,7 @@
   void ConfirmCreditCardFillAssist(const autofill::CreditCard& card,
                                    const base::Closure& callback) override;
   void LoadRiskData(
-      const base::Callback<void(const std::string&)>& callback) override;
+      base::OnceCallback<void(const std::string&)> callback) override;
   bool HasCreditCardScanFeature() override;
   void ScanCreditCard(const CreditCardScanCallback& callback) override;
   void ShowAutofillPopup(
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/IsomorphicAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/IsomorphicAdapter.java
index a2ac025..0fc210f0 100644
--- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/IsomorphicAdapter.java
+++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/IsomorphicAdapter.java
@@ -18,6 +18,9 @@
     @Override
     public Object getOrCreatePeer(Callable<Object> creationCallable) throws Exception {
         AwSupportLibIsomorphic peeredObject = getPeeredObject();
+        if (peeredObject == null) {
+            return null;
+        }
         Object peer = peeredObject.getSupportLibObject();
         if (peer == null) {
             peeredObject.setSupportLibObject(peer = creationCallable.call());
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 37ca66e..759173f 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -15,6 +15,8 @@
       "//android_webview:assets",
       "//android_webview/apk:webview_license_activity_java",
       "//android_webview/apk:webview_license_provider_java",
+      "//android_webview/glue",
+      "//android_webview/support_library:support_lib_glue_java",
       "//base:base_java",
     ]
 
diff --git a/android_webview/variables.gni b/android_webview/variables.gni
index 656c14fb..94b8559 100644
--- a/android_webview/variables.gni
+++ b/android_webview/variables.gni
@@ -4,3 +4,8 @@
 
 system_webview_android_manifest =
     "$root_gen_dir/android_webview/system_webview_apk/AndroidManifest.xml"
+
+upstream_only_webview_deps = [
+  "//android_webview:platform_service_bridge_upstream_implementation_java",
+  "//android_webview:system_webview_resources",
+]
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 3269965..243a270 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -239,6 +239,8 @@
     "assistant/util/views_util.h",
     "autoclick/autoclick_controller.cc",
     "autoclick/autoclick_controller.h",
+    "bluetooth_devices_observer.cc",
+    "bluetooth_devices_observer.h",
     "cancel_mode.cc",
     "cancel_mode.h",
     "cast_config_controller.cc",
@@ -1775,6 +1777,7 @@
     "login/ui/login_keyboard_test_base.h",
     "login/ui/login_password_view_test.cc",
     "login/ui/login_pin_view_unittest.cc",
+    "login/ui/login_public_account_user_view_unittest.cc",
     "login/ui/login_test_base.cc",
     "login/ui/login_test_base.h",
     "login/ui/login_test_utils.cc",
diff --git a/ash/bluetooth_devices_observer.cc b/ash/bluetooth_devices_observer.cc
new file mode 100644
index 0000000..e301b12a
--- /dev/null
+++ b/ash/bluetooth_devices_observer.cc
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/bluetooth_devices_observer.h"
+
+#include "base/bind.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+
+namespace ash {
+
+BluetoothDevicesObserver::BluetoothDevicesObserver(
+    const DeviceChangedCallback& device_changed_callback)
+    : device_changed_callback_(device_changed_callback), weak_factory_(this) {
+  device::BluetoothAdapterFactory::GetAdapter(
+      base::Bind(&BluetoothDevicesObserver::InitializeOnAdapterReady,
+                 weak_factory_.GetWeakPtr()));
+}
+
+BluetoothDevicesObserver::~BluetoothDevicesObserver() {
+  if (bluetooth_adapter_)
+    bluetooth_adapter_->RemoveObserver(this);
+}
+
+void BluetoothDevicesObserver::DeviceChanged(device::BluetoothAdapter* adapter,
+                                             device::BluetoothDevice* device) {
+  device_changed_callback_.Run(device);
+}
+
+void BluetoothDevicesObserver::InitializeOnAdapterReady(
+    scoped_refptr<device::BluetoothAdapter> adapter) {
+  bluetooth_adapter_ = std::move(adapter);
+  bluetooth_adapter_->AddObserver(this);
+}
+
+bool BluetoothDevicesObserver::IsConnectedBluetoothDevice(
+    const ui::InputDevice& input_device) const {
+  if (!bluetooth_adapter_ || !bluetooth_adapter_->IsPowered())
+    return false;
+
+  // Since there is no map from an InputDevice to a BluetoothDevice. We just
+  // comparing their vendor id and product id to guess a match.
+  for (auto* device : bluetooth_adapter_->GetDevices()) {
+    if (!device->IsConnected())
+      continue;
+
+    if (device->GetVendorID() == input_device.vendor_id &&
+        device->GetProductID() == input_device.product_id) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+}  // namespace ash
diff --git a/ash/bluetooth_devices_observer.h b/ash/bluetooth_devices_observer.h
new file mode 100644
index 0000000..5612ec1c
--- /dev/null
+++ b/ash/bluetooth_devices_observer.h
@@ -0,0 +1,63 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_BLUETOOTH_DEVICES_OBSERVER_H_
+#define ASH_BLUETOOTH_DEVICES_OBSERVER_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "ui/events/devices/input_device.h"
+
+namespace ash {
+
+// This class observes the bluetooth devices and sends out notification when
+// bluetooth device changes. It's used as a supplementary to the class
+// ui::InputDeviceEventObserver as InputDeviceEventObserver does not have
+// knowledge about bluetooth device status thus does not send notifications of
+// bluetooth device changes.
+class BluetoothDevicesObserver : public device::BluetoothAdapter::Observer {
+ public:
+  using DeviceChangedCallback =
+      base::RepeatingCallback<void(device::BluetoothDevice* device)>;
+
+  explicit BluetoothDevicesObserver(
+      const DeviceChangedCallback& device_changed_callback);
+  ~BluetoothDevicesObserver() override;
+
+  // device::BluetoothAdapter::Observer:
+  void DeviceChanged(device::BluetoothAdapter* adapter,
+                     device::BluetoothDevice* device) override;
+
+  // Returns true if |input_device| is a connected bluetooth device. Note this
+  // function may not work well if there are more than one identical Bluetooth
+  // devices: the function might return true even if it should return false.
+  // E.g., Connect two idential bluetooth devices (Input device A & input device
+  // B, thus the same vendor id and same product id) to Chrome OS, and then
+  // disconnect device A, calling IsConnectedBluetoothDevice(Input device A)
+  // still returns true although it should return false as Input device B is
+  // still connected. Unfortunately there is no good map from an InputDevice to
+  // a BluetoothDevice, thus we can only guess a match.
+  bool IsConnectedBluetoothDevice(const ui::InputDevice& input_device) const;
+
+ private:
+  void InitializeOnAdapterReady(
+      scoped_refptr<device::BluetoothAdapter> adapter);
+
+  // Reference to the underlying Bluetooth Adapter. Used to listen for bluetooth
+  // device change event.
+  scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
+
+  // Callback function to be called when a bluetooth device status changes.
+  DeviceChangedCallback device_changed_callback_;
+
+  base::WeakPtrFactory<BluetoothDevicesObserver> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothDevicesObserver);
+};
+
+}  // namespace ash
+
+#endif  // ASH_BLUETOOTH_DEVICES_OBSERVER_H_
diff --git a/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc b/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc
index a9636cb..efad1e5 100644
--- a/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc
+++ b/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc
@@ -137,9 +137,8 @@
   // redundant child label text is not also spoken.
   GetViewAccessibility().OverrideRole(ax::mojom::Role::kListItem);
   GetViewAccessibility().OverrideIsLeaf();
-  accessible_name_ = GetStringForCategory(category_) +
-                     description_label_view_->text() +
-                     shortcut_label_view_->text();
+  accessible_name_ = description_label_view_->text() +
+                     base::ASCIIToUTF16(", ") + shortcut_label_view_->text();
 }
 
 void KeyboardShortcutItemView::GetAccessibleNodeData(
diff --git a/ash/display/cros_display_config_unittest.cc b/ash/display/cros_display_config_unittest.cc
index 66a23a0..a2990d9c 100644
--- a/ash/display/cros_display_config_unittest.cc
+++ b/ash/display/cros_display_config_unittest.cc
@@ -36,9 +36,9 @@
 }
 
 void InitExternalTouchDevices(int64_t display_id) {
-  ui::TouchscreenDevice touchdevice(
-      123, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
-      std::string("test external touch device"), gfx::Size(1000, 1000), 1);
+  ui::TouchscreenDevice touchdevice(123, ui::InputDeviceType::INPUT_DEVICE_USB,
+                                    std::string("test external touch device"),
+                                    gfx::Size(1000, 1000), 1);
   ws::InputDeviceClientTestApi().SetTouchscreenDevices({touchdevice});
 
   std::vector<ui::TouchDeviceTransform> transforms;
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index c50fb0e..276afb4 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -1190,7 +1190,7 @@
   display::test::TouchDeviceManagerTestApi tdm_test_api(touch_device_manager);
 
   const ui::TouchscreenDevice touchdevice(
-      11, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      11, ui::InputDeviceType::INPUT_DEVICE_USB,
       std::string("test touch device"), gfx::Size(123, 456), 1);
   const display::TouchDeviceIdentifier touch_device_identifier_2 =
       display::TouchDeviceIdentifier::FromDevice(touchdevice);
@@ -1265,7 +1265,7 @@
                             touchdevice, GetDisplayInfoAt(1).id()));
 
   const ui::TouchscreenDevice touchdevice_2(
-      12, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      12, ui::InputDeviceType::INPUT_DEVICE_USB,
       std::string("test touch device 2"), gfx::Size(234, 567), 1);
   display::TouchDeviceIdentifier touch_device_identifier_2_2 =
       display::TouchDeviceIdentifier::FromDevice(touchdevice_2);
diff --git a/ash/display/touch_calibrator_controller_unittest.cc b/ash/display/touch_calibrator_controller_unittest.cc
index 7ed9452..f50c6d1 100644
--- a/ash/display/touch_calibrator_controller_unittest.cc
+++ b/ash/display/touch_calibrator_controller_unittest.cc
@@ -38,7 +38,7 @@
 
 ui::TouchscreenDevice GetExternalTouchDevice(int touch_device_id) {
   return ui::TouchscreenDevice(
-      touch_device_id, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      touch_device_id, ui::InputDeviceType::INPUT_DEVICE_USB,
       std::string("test external touch device"), gfx::Size(1000, 1000), 1);
 }
 
@@ -338,7 +338,7 @@
       display_manager()->GetDisplayInfo(touch_display.id());
 
   ui::TouchscreenDevice random_touchdevice(
-      15, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      15, ui::InputDeviceType::INPUT_DEVICE_USB,
       std::string("random touch device"), gfx::Size(123, 456), 1);
   EXPECT_EQ(calibration_data, touch_device_manager()->GetCalibrationData(
                                   random_touchdevice, info.id()));
@@ -400,7 +400,7 @@
       kInternalTouchId, ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
       std::string("internal touch device"), gfx::Size(1000, 1000), 1);
   ui::TouchscreenDevice external_touchdevice(
-      kExternalTouchId, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      kExternalTouchId, ui::InputDeviceType::INPUT_DEVICE_USB,
       std::string("external touch device"), gfx::Size(1000, 1000), 1);
 
   ws::InputDeviceClientTestApi().SetTouchscreenDevices(
@@ -492,7 +492,7 @@
       kInternalTouchId, ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
       std::string("internal touch device"), gfx::Size(1000, 1000), 1);
   ui::TouchscreenDevice external_touchdevice(
-      kExternalTouchId, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      kExternalTouchId, ui::InputDeviceType::INPUT_DEVICE_USB,
       std::string("external touch device"), gfx::Size(1000, 1000), 1);
 
   ws::InputDeviceClientTestApi().SetTouchscreenDevices(
diff --git a/ash/keyboard/virtual_keyboard_controller.cc b/ash/keyboard/virtual_keyboard_controller.cc
index aefff26..a57a0b7 100644
--- a/ash/keyboard/virtual_keyboard_controller.cc
+++ b/ash/keyboard/virtual_keyboard_controller.cc
@@ -102,6 +102,10 @@
       chromeos::input_method::mojom::ImeKeyset::kEmoji));
 
   keyboard::KeyboardController::Get()->AddObserver(this);
+
+  bluetooth_devices_observer_ = std::make_unique<BluetoothDevicesObserver>(
+      base::BindRepeating(&VirtualKeyboardController::UpdateBluetoothDevice,
+                          base::Unretained(this)));
 }
 
 VirtualKeyboardController::~VirtualKeyboardController() {
@@ -213,8 +217,11 @@
     ui::InputDeviceType type = device.type;
     if (type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL)
       has_internal_keyboard_ = true;
-    if (type == ui::InputDeviceType::INPUT_DEVICE_EXTERNAL)
+    if (type == ui::InputDeviceType::INPUT_DEVICE_USB ||
+        (type == ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH &&
+         bluetooth_devices_observer_->IsConnectedBluetoothDevice(device))) {
       has_external_keyboard_ = true;
+    }
   }
   // Update keyboard state.
   UpdateKeyboardEnabled();
@@ -293,4 +300,16 @@
     Shell::Get()->EnableKeyboard();
 }
 
+void VirtualKeyboardController::UpdateBluetoothDevice(
+    device::BluetoothDevice* device) {
+  // We only care about keyboard type bluetooth device change.
+  if (device->GetDeviceType() != device::BluetoothDeviceType::KEYBOARD &&
+      device->GetDeviceType() !=
+          device::BluetoothDeviceType::KEYBOARD_MOUSE_COMBO) {
+    return;
+  }
+
+  UpdateDevices();
+}
+
 }  // namespace ash
diff --git a/ash/keyboard/virtual_keyboard_controller.h b/ash/keyboard/virtual_keyboard_controller.h
index 5ad4c51a..49bb8e5 100644
--- a/ash/keyboard/virtual_keyboard_controller.h
+++ b/ash/keyboard/virtual_keyboard_controller.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include "ash/ash_export.h"
+#include "ash/bluetooth_devices_observer.h"
 #include "ash/session/session_observer.h"
 #include "ash/wm/tablet_mode/tablet_mode_observer.h"
 #include "base/macros.h"
@@ -56,7 +57,7 @@
   void OnKeyboardDisabled() override;
   void OnKeyboardHidden(bool is_temporary_hide) override;
 
-  // SessionObserver
+  // SessionObserver:
   void OnActiveUserSessionChanged(const AccountId& account_id) override;
 
  private:
@@ -72,6 +73,10 @@
   // Force enable the keyboard and show it, even in laptop mode.
   void ForceShowKeyboard();
 
+  // Callback function of |bluetooth_devices_observer_|. Called when |device|
+  // changes.
+  void UpdateBluetoothDevice(device::BluetoothDevice* device);
+
   // True if an external keyboard is connected.
   bool has_external_keyboard_;
   // True if an internal keyboard is connected.
@@ -81,6 +86,9 @@
   // True if the presence of an external keyboard should be ignored.
   bool ignore_external_keyboard_;
 
+  // Observer to observe the bluetooth devices.
+  std::unique_ptr<BluetoothDevicesObserver> bluetooth_devices_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardController);
 };
 
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc
index 9d6d4dc7..b2621b6 100644
--- a/ash/keyboard/virtual_keyboard_controller_unittest.cc
+++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -285,7 +285,7 @@
   std::vector<ui::TouchscreenDevice> devices;
   // Add a touchscreen. Keyboard should deploy.
   devices.push_back(
-      ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB,
                             "Touchscreen", gfx::Size(800, 600), 0));
   ws::InputDeviceClientTestApi().SetTouchscreenDevices(devices);
   EXPECT_TRUE(keyboard::IsKeyboardEnabled());
@@ -301,8 +301,8 @@
       gfx::Size(1024, 768), 0, false /* has_stylus */));
   ws::InputDeviceClientTestApi().SetTouchscreenDevices(screens);
   std::vector<ui::InputDevice> keyboard_devices;
-  keyboard_devices.push_back(ui::InputDevice(
-      1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard"));
+  keyboard_devices.push_back(
+      ui::InputDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard"));
   ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices);
   ASSERT_FALSE(keyboard::IsKeyboardEnabled());
   ASSERT_TRUE(notified());
@@ -333,10 +333,10 @@
   std::vector<ui::InputDevice> keyboards;
   keyboards.push_back(ui::InputDevice(
       1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "keyboard"));
-  keyboards.push_back(ui::InputDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard"));
-  keyboards.push_back(ui::InputDevice(
-      3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard"));
+  keyboards.push_back(
+      ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard"));
+  keyboards.push_back(
+      ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard"));
   ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboards);
   ASSERT_FALSE(keyboard::IsKeyboardEnabled());
 }
@@ -371,8 +371,8 @@
   std::vector<ui::InputDevice> keyboard_devices;
   keyboard_devices.push_back(ui::InputDevice(
       1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "Keyboard"));
-  keyboard_devices.push_back(ui::InputDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "Keyboard"));
+  keyboard_devices.push_back(
+      ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "Keyboard"));
   ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices);
   // Toggle tablet mode on.
   TabletModeControllerTestApi().EnterTabletMode();
@@ -430,8 +430,8 @@
                             "Touchscreen", gfx::Size(1024, 768), 0));
   ws::InputDeviceClientTestApi().SetTouchscreenDevices(screens);
   std::vector<ui::InputDevice> keyboard_devices;
-  keyboard_devices.push_back(ui::InputDevice(
-      1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard"));
+  keyboard_devices.push_back(
+      ui::InputDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard"));
   ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices);
   ASSERT_TRUE(keyboard::IsKeyboardEnabled());
 }
diff --git a/ash/login/ui/login_expanded_public_account_view.cc b/ash/login/ui/login_expanded_public_account_view.cc
index 73e23bb..3cba5a0 100644
--- a/ash/login/ui/login_expanded_public_account_view.cc
+++ b/ash/login/ui/login_expanded_public_account_view.cc
@@ -12,7 +12,6 @@
 #include "ash/login/ui/arrow_button_view.h"
 #include "ash/login/ui/login_bubble.h"
 #include "ash/login/ui/login_button.h"
-#include "ash/login/ui/login_menu_view.h"
 #include "ash/login/ui/login_user_view.h"
 #include "ash/login/ui/public_account_warning_dialog.h"
 #include "ash/resources/vector_icons/vector_icons.h"
@@ -560,6 +559,34 @@
   return view_->right_pane_->learn_more_label_;
 }
 
+views::View*
+LoginExpandedPublicAccountView::TestApi::language_selection_button() {
+  return view_->right_pane_->language_selection_;
+}
+
+views::View*
+LoginExpandedPublicAccountView::TestApi::keyboard_selection_button() {
+  return view_->right_pane_->keyboard_selection_;
+}
+
+LoginBubble* LoginExpandedPublicAccountView::TestApi::language_menu() {
+  return view_->right_pane_->language_menu_.get();
+}
+
+LoginBubble* LoginExpandedPublicAccountView::TestApi::keyboard_menu() {
+  return view_->right_pane_->keyboard_menu_.get();
+}
+
+LoginMenuView::Item
+LoginExpandedPublicAccountView::TestApi::selected_language_item() {
+  return view_->right_pane_->selected_language_item_;
+}
+
+LoginMenuView::Item
+LoginExpandedPublicAccountView::TestApi::selected_keyboard_item() {
+  return view_->right_pane_->selected_keyboard_item_;
+}
+
 LoginExpandedPublicAccountView::LoginExpandedPublicAccountView(
     const OnPublicSessionViewDismissed& on_dismissed)
     : NonAccessibleView(kLoginExpandedPublicAccountViewClassName),
diff --git a/ash/login/ui/login_expanded_public_account_view.h b/ash/login/ui/login_expanded_public_account_view.h
index 76884d8..e865ea2 100644
--- a/ash/login/ui/login_expanded_public_account_view.h
+++ b/ash/login/ui/login_expanded_public_account_view.h
@@ -6,6 +6,7 @@
 #define ASH_LOGIN_UI_LOGIN_EXPANDED_PUBLIC_ACCOUNT_VIEW_H_
 
 #include "ash/ash_export.h"
+#include "ash/login/ui/login_menu_view.h"
 #include "ash/login/ui/non_accessible_view.h"
 #include "ash/public/interfaces/login_user_info.mojom.h"
 #include "ui/events/event_handler.h"
@@ -15,6 +16,7 @@
 namespace ash {
 
 class ArrowButtonView;
+class LoginBubble;
 class LoginUserView;
 class RightPaneView;
 class PublicAccountWarningDialog;
@@ -34,6 +36,12 @@
     views::View* advanced_view();
     PublicAccountWarningDialog* warning_dialog();
     views::StyledLabel* learn_more_label();
+    views::View* language_selection_button();
+    views::View* keyboard_selection_button();
+    LoginBubble* language_menu();
+    LoginBubble* keyboard_menu();
+    LoginMenuView::Item selected_language_item();
+    LoginMenuView::Item selected_keyboard_item();
 
    private:
     LoginExpandedPublicAccountView* const view_;
diff --git a/ash/login/ui/login_expanded_public_account_view_unittest.cc b/ash/login/ui/login_expanded_public_account_view_unittest.cc
index a46048d..d944411 100644
--- a/ash/login/ui/login_expanded_public_account_view_unittest.cc
+++ b/ash/login/ui/login_expanded_public_account_view_unittest.cc
@@ -3,9 +3,13 @@
 // found in the LICENSE file.
 
 #include "ash/login/ui/login_expanded_public_account_view.h"
+#include "ash/login/mock_login_screen_client.h"
+#include "ash/login/ui/arrow_button_view.h"
+#include "ash/login/ui/login_bubble.h"
 #include "ash/login/ui/login_test_base.h"
 #include "ash/login/ui/login_test_utils.h"
 #include "ash/login/ui/public_account_warning_dialog.h"
+#include "ash/login/ui/views_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/views/layout/box_layout.h"
@@ -20,6 +24,17 @@
 // Total height of the expanded view.
 constexpr int kBubbleTotalHeightDp = 324;
 
+// Fake language and keyboard information.
+constexpr char kEnglishLanguageCode[] = "language_code1";
+constexpr char kEnglishLanguageName[] = "English";
+constexpr char kFrenchLanguageCode[] = "language_code2";
+constexpr char kFrenchLanguageName[] = "French";
+
+constexpr char kKeyboardIdForItem1[] = "keyboard_id1";
+constexpr char kKeyboardNameForItem1[] = "keyboard1";
+constexpr char kKeyboardIdForItem2[] = "keyboard_id2";
+constexpr char kKeyboardNameForItem2[] = "keyboard2";
+
 class LoginExpandedPublicAccountViewTest : public LoginTestBase {
  protected:
   LoginExpandedPublicAccountViewTest() = default;
@@ -28,8 +43,10 @@
   // LoginTestBase:
   void SetUp() override {
     LoginTestBase::SetUp();
-
     user_ = CreatePublicAccountUser("user@domain.com");
+    SetupLanguageInfo();
+    SetupKeyboardInfo();
+
     public_account_ = new LoginExpandedPublicAccountView(base::DoNothing());
     public_account_->UpdateForUser(user_);
 
@@ -43,6 +60,47 @@
     SetWidget(CreateWidgetWithContent(container_));
   }
 
+  // Add two fake language items, the first item is selected by default.
+  void SetupLanguageInfo() {
+    std::vector<ash::mojom::LocaleItemPtr> result;
+    ash::mojom::LocaleItemPtr locale_item1 = ash::mojom::LocaleItem::New();
+    locale_item1->language_code = kEnglishLanguageCode;
+    locale_item1->title = kEnglishLanguageName;
+
+    ash::mojom::LocaleItemPtr locale_item2 = ash::mojom::LocaleItem::New();
+    locale_item2->language_code = kFrenchLanguageCode;
+    locale_item2->title = kFrenchLanguageName;
+    result.push_back(std::move(locale_item1));
+    result.push_back(std::move(locale_item2));
+    user_->public_account_info->available_locales = std::move(result);
+    user_->public_account_info->default_locale = kEnglishLanguageCode;
+  }
+
+  // Add two fake keyboard items, the second item is selected by default.
+  void SetupKeyboardInfo() {
+    std::vector<ash::mojom::InputMethodItemPtr> result;
+    ash::mojom::InputMethodItemPtr keyboard_item1 =
+        ash::mojom::InputMethodItem::New();
+    keyboard_item1->ime_id = kKeyboardIdForItem1;
+    keyboard_item1->title = kKeyboardNameForItem1;
+
+    ash::mojom::InputMethodItemPtr keyboard_item2 =
+        ash::mojom::InputMethodItem::New();
+    keyboard_item2->ime_id = kKeyboardIdForItem2;
+    keyboard_item2->title = kKeyboardNameForItem2;
+    keyboard_item2->selected = true;
+    result.push_back(std::move(keyboard_item1));
+    result.push_back(std::move(keyboard_item2));
+
+    user_->public_account_info->keyboard_layouts = std::move(result);
+  }
+
+  void TapOnView(views::View* tap_target) {
+    GetEventGenerator()->MoveMouseTo(
+        tap_target->GetBoundsInScreen().CenterPoint());
+    GetEventGenerator()->ClickLeftButton();
+  }
+
   mojom::LoginUserInfoPtr user_;
 
   // Owned by test widget view hierarchy.
@@ -76,10 +134,7 @@
   EXPECT_EQ(public_account_->height(), kBubbleTotalHeightDp);
 
   // Click on the show advanced button.
-  ui::test::EventGenerator* generator = GetEventGenerator();
-  generator->MoveMouseTo(
-      test_api.advanced_view_button()->GetBoundsInScreen().CenterPoint());
-  generator->ClickLeftButton();
+  TapOnView(test_api.advanced_view_button());
 
   // Advanced view is hidden and the overall size does not change.
   EXPECT_FALSE(test_api.advanced_view()->visible());
@@ -123,4 +178,118 @@
   EXPECT_FALSE(public_account_->visible());
 }
 
+// Verifies tap on submit button will try to launch public session.
+TEST_F(LoginExpandedPublicAccountViewTest, LaunchPublicSession) {
+  LoginExpandedPublicAccountView::TestApi test_api(public_account_);
+
+  // Verify the language and keyboard information is populated correctly.
+  std::string selected_language = test_api.selected_language_item().value;
+  std::string selected_keyboard = test_api.selected_keyboard_item().value;
+  EXPECT_EQ(selected_language, kEnglishLanguageCode);
+  EXPECT_EQ(selected_keyboard, kKeyboardIdForItem2);
+
+  // Expect LanuchPublicSession mojo call when the submit button is clicked.
+  std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient();
+  EXPECT_CALL(*client,
+              LaunchPublicSession(user_->basic_user_info->account_id,
+                                  selected_language, selected_keyboard));
+
+  // Click on the submit button.
+  TapOnView(test_api.submit_button());
+  base::RunLoop().RunUntilIdle();
+}
+
+// Verifies both language and keyboard menus shows up correctly.
+TEST_F(LoginExpandedPublicAccountViewTest, ShowLanguageAndKeyboardMenu) {
+  LoginExpandedPublicAccountView::TestApi test_api(public_account_);
+  EXPECT_FALSE(user_->public_account_info->show_advanced_view);
+  EXPECT_FALSE(test_api.advanced_view()->visible());
+
+  // Toggle show_advanced_view.
+  user_->public_account_info->show_advanced_view = true;
+  public_account_->UpdateForUser(user_);
+  EXPECT_TRUE(test_api.advanced_view()->visible());
+
+  // Tap on language selection button should bring up the language menu.
+  EXPECT_FALSE(test_api.language_menu()->IsVisible());
+  TapOnView(test_api.language_selection_button());
+  EXPECT_TRUE(test_api.language_menu()->IsVisible());
+
+  // First language item is selected, and selected item should have focus.
+  EXPECT_EQ(test_api.selected_language_item().value, kEnglishLanguageCode);
+  auto* language_menu_view =
+      static_cast<LoginMenuView*>(test_api.language_menu()->bubble_view());
+  LoginMenuView::TestApi language_test_api(language_menu_view);
+  EXPECT_TRUE(language_test_api.contents()->child_count() == 2);
+  EXPECT_TRUE(language_test_api.contents()->child_at(0)->HasFocus());
+
+  // Select language item should close the language menu.
+  GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
+  EXPECT_FALSE(test_api.language_menu()->IsVisible());
+
+  // Tap on keyboard selection button should bring up the keyboard menu.
+  EXPECT_FALSE(test_api.keyboard_menu()->IsVisible());
+  TapOnView(test_api.keyboard_selection_button());
+  EXPECT_TRUE(test_api.keyboard_menu()->IsVisible());
+
+  // Second keyboard item is selected, and selected item should have focus.
+  EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem2);
+  auto* keyboard_menu_view =
+      static_cast<LoginMenuView*>(test_api.keyboard_menu()->bubble_view());
+  LoginMenuView::TestApi keyboard_test_api(keyboard_menu_view);
+  EXPECT_TRUE(keyboard_test_api.contents()->child_count() == 2);
+  EXPECT_TRUE(keyboard_test_api.contents()->child_at(1)->HasFocus());
+
+  // Select keyboard item should close the keyboard menu.
+  GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
+  EXPECT_FALSE(test_api.keyboard_menu()->IsVisible());
+}
+
+TEST_F(LoginExpandedPublicAccountViewTest, ChangeMenuSelection) {
+  LoginExpandedPublicAccountView::TestApi test_api(public_account_);
+  user_->public_account_info->show_advanced_view = true;
+  public_account_->UpdateForUser(user_);
+  EXPECT_TRUE(test_api.advanced_view()->visible());
+
+  // Try to change language selection.
+  // Open language menu.
+  TapOnView(test_api.language_selection_button());
+  EXPECT_TRUE(test_api.language_menu()->IsVisible());
+
+  // Select second language item:
+  // 1. Language menu will be closed automatically.
+  // 2. Selected language item will change.
+  // 3. Expect RequestPublicSessionKeyboardLayouts mojo call with the selected
+  // language item.
+  std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient();
+  EXPECT_CALL(*client,
+              RequestPublicSessionKeyboardLayouts(
+                  user_->basic_user_info->account_id, kFrenchLanguageCode));
+
+  EXPECT_EQ(test_api.selected_language_item().value, kEnglishLanguageCode);
+  auto* language_menu_view =
+      static_cast<LoginMenuView*>(test_api.language_menu()->bubble_view());
+  LoginMenuView::TestApi language_test_api(language_menu_view);
+  TapOnView(language_test_api.contents()->child_at(1));
+  EXPECT_FALSE(test_api.language_menu()->IsVisible());
+  EXPECT_EQ(test_api.selected_language_item().value, kFrenchLanguageCode);
+  base::RunLoop().RunUntilIdle();
+
+  // Try to change keyboard selection.
+  // Open keyboard menu.
+  TapOnView(test_api.keyboard_selection_button());
+  EXPECT_TRUE(test_api.keyboard_menu()->IsVisible());
+
+  // Select first keyboard item:
+  // 1. Keyboard menu will be closed automatically.
+  // 2. Selected keyboard item will change.
+  EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem2);
+  auto* keyboard_menu_view =
+      static_cast<LoginMenuView*>(test_api.keyboard_menu()->bubble_view());
+  LoginMenuView::TestApi keyboard_test_api(keyboard_menu_view);
+  TapOnView(keyboard_test_api.contents()->child_at(0));
+  EXPECT_FALSE(test_api.keyboard_menu()->IsVisible());
+  EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem1);
+}
+
 }  // namespace ash
diff --git a/ash/login/ui/login_public_account_user_view.cc b/ash/login/ui/login_public_account_user_view.cc
index 31d8ae6f..5ad7ee7 100644
--- a/ash/login/ui/login_public_account_user_view.cc
+++ b/ash/login/ui/login_public_account_user_view.cc
@@ -41,6 +41,15 @@
 
 }  // namespace
 
+LoginPublicAccountUserView::TestApi::TestApi(LoginPublicAccountUserView* view)
+    : view_(view) {}
+
+LoginPublicAccountUserView::TestApi::~TestApi() = default;
+
+views::View* LoginPublicAccountUserView::TestApi::arrow_button() const {
+  return view_->arrow_button_;
+}
+
 LoginPublicAccountUserView::Callbacks::Callbacks() = default;
 
 LoginPublicAccountUserView::Callbacks::Callbacks(const Callbacks& other) =
diff --git a/ash/login/ui/login_public_account_user_view.h b/ash/login/ui/login_public_account_user_view.h
index b2f56b9..5bd46a4 100644
--- a/ash/login/ui/login_public_account_user_view.h
+++ b/ash/login/ui/login_public_account_user_view.h
@@ -19,10 +19,21 @@
 
 // This is the big user view for the public account user. It wraps a UserView
 // and a arrow button below.
-// TODO(crbug.com/809635): Add test for this class.
 class ASH_EXPORT LoginPublicAccountUserView : public NonAccessibleView,
                                               public views::ButtonListener {
  public:
+  // TestApi is used for tests to get internal implementation details.
+  class ASH_EXPORT TestApi {
+   public:
+    explicit TestApi(LoginPublicAccountUserView* view);
+    ~TestApi();
+
+    views::View* arrow_button() const;
+
+   private:
+    LoginPublicAccountUserView* const view_;
+  };
+
   using OnPublicAccountTapped = base::RepeatingClosure;
 
   struct Callbacks {
diff --git a/ash/login/ui/login_public_account_user_view_unittest.cc b/ash/login/ui/login_public_account_user_view_unittest.cc
new file mode 100644
index 0000000..91ebd04
--- /dev/null
+++ b/ash/login/ui/login_public_account_user_view_unittest.cc
@@ -0,0 +1,171 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/login/ui/login_public_account_user_view.h"
+#include "ash/login/ui/login_test_base.h"
+#include "ash/login/ui/login_test_utils.h"
+#include "ash/login/ui/login_user_view.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+namespace {
+
+// Used to trigger hover event in LoginPublicAccountUserView.
+constexpr int kNonEmptySize = 20;
+
+class LoginPublicAccountUserViewTest : public LoginTestBase {
+ protected:
+  LoginPublicAccountUserViewTest() = default;
+  ~LoginPublicAccountUserViewTest() override = default;
+
+  // LoginTestBase:
+  void SetUp() override {
+    LoginTestBase::SetUp();
+
+    user_ = CreatePublicAccountUser("user@domain.com");
+
+    LoginPublicAccountUserView::Callbacks public_account_callbacks;
+    public_account_callbacks.on_tap =
+        base::BindRepeating(&LoginPublicAccountUserViewTest::OnUserViewTapped,
+                            base::Unretained(this));
+    public_account_callbacks.on_public_account_tapped = base::BindRepeating(
+        &LoginPublicAccountUserViewTest::OnPublicAccountTapped,
+        base::Unretained(this));
+    public_account_view_ =
+        new LoginPublicAccountUserView(user_, public_account_callbacks);
+
+    focusable_view_ = new views::View();
+    focusable_view_->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
+    focusable_view_->SetPreferredSize(gfx::Size(kNonEmptySize, kNonEmptySize));
+
+    // We proxy |public_account_view_| inside of |container| so we can control
+    // layout.
+    auto* container = new views::View();
+    container->SetLayoutManager(
+        std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
+    container->AddChildView(public_account_view_);
+    container->AddChildView(focusable_view_);
+    SetWidget(CreateWidgetWithContent(container));
+  }
+
+  mojom::LoginUserInfoPtr user_;
+
+  LoginPublicAccountUserView* public_account_view_ = nullptr;
+  views::View* focusable_view_ = nullptr;
+
+  int user_view_tap_count_ = 0;
+  int public_account_tap_count_ = 0;
+
+ private:
+  void OnUserViewTapped() { ++user_view_tap_count_; }
+  void OnPublicAccountTapped() { ++public_account_tap_count_; }
+
+  DISALLOW_COPY_AND_ASSIGN(LoginPublicAccountUserViewTest);
+};
+
+}  // namespace
+
+// Verifies that an auth enabled public account user is opaque.
+// Verifies that hovered view is opaque.
+TEST_F(LoginPublicAccountUserViewTest, EnableAuthAndHoverOpaque) {
+  LoginPublicAccountUserView::TestApi public_account_test(public_account_view_);
+  LoginUserView::TestApi user_test(public_account_view_->user_view());
+
+  // Make focusable_view_ to hold focus. The user view cannot have focus
+  // since focus will keep it opaque.
+  focusable_view_->RequestFocus();
+  EXPECT_FALSE(public_account_view_->user_view()->HasFocus());
+  EXPECT_FALSE(user_test.is_opaque());
+  EXPECT_NE(public_account_test.arrow_button()->layer()->opacity(), 1);
+
+  // Auth enabled view must be opaque.
+  public_account_view_->SetAuthEnabled(true /*enabled*/, false /*animate*/);
+  EXPECT_TRUE(user_test.is_opaque());
+  EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1);
+
+  // Auth enabled view stays opaque regardless of hover.
+  GetEventGenerator()->MoveMouseTo(
+      public_account_view_->GetBoundsInScreen().CenterPoint());
+  EXPECT_TRUE(user_test.is_opaque());
+  EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1);
+  GetEventGenerator()->MoveMouseTo(
+      focusable_view_->GetBoundsInScreen().CenterPoint());
+  EXPECT_TRUE(user_test.is_opaque());
+  EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1);
+
+  // Disable auth makes view non-opaque.
+  public_account_view_->SetAuthEnabled(false /*enabled*/, false /*animate*/);
+  EXPECT_FALSE(user_test.is_opaque());
+  EXPECT_NE(public_account_test.arrow_button()->layer()->opacity(), 1);
+
+  // Move mouse over the view makes it opaque.
+  GetEventGenerator()->MoveMouseTo(
+      public_account_view_->user_view()->GetBoundsInScreen().CenterPoint());
+  EXPECT_TRUE(user_test.is_opaque());
+  EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1);
+
+  // Move out the view makes it non-opaque.
+  GetEventGenerator()->MoveMouseTo(
+      focusable_view_->GetBoundsInScreen().CenterPoint());
+  EXPECT_FALSE(user_test.is_opaque());
+  EXPECT_NE(public_account_test.arrow_button()->layer()->opacity(), 1);
+}
+
+// Verifies that LoginPublicAccountUserView::Callbacks run successfully.
+TEST_F(LoginPublicAccountUserViewTest, VerifyCallackRun) {
+  LoginPublicAccountUserView::TestApi public_account_test(public_account_view_);
+
+  // Tap on the user view and verify on_tap callback is run.
+  GetEventGenerator()->MoveMouseTo(
+      public_account_view_->user_view()->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+  EXPECT_EQ(user_view_tap_count_, 1);
+
+  // Tap on the arrow button and verify on_public_account_tapped callback is
+  // run.
+  GetEventGenerator()->MoveMouseTo(
+      public_account_test.arrow_button()->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+  EXPECT_EQ(public_account_tap_count_, 1);
+}
+
+// Verifies that displaying the arrow button does not change the view bounds.
+// Also arrow button should always have the same horizontal centering as user
+// view.
+TEST_F(LoginPublicAccountUserViewTest, ArrowButtonDoesNotChangeViewBounds) {
+  LoginPublicAccountUserView::TestApi public_account_test(public_account_view_);
+  EXPECT_FALSE(public_account_view_->auth_enabled());
+  const gfx::Rect auth_disabled_bounds =
+      public_account_view_->GetBoundsInScreen();
+  EXPECT_NE(auth_disabled_bounds, gfx::Rect());
+
+  // Move mouse over the view, the arrow button becomes opaque.
+  // View bounds should not change.
+  GetEventGenerator()->MoveMouseTo(
+      public_account_view_->user_view()->GetBoundsInScreen().CenterPoint());
+  EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1);
+  EXPECT_EQ(public_account_view_->GetBoundsInScreen(), auth_disabled_bounds);
+  EXPECT_EQ(public_account_view_->GetBoundsInScreen().x(),
+            public_account_test.arrow_button()->GetBoundsInScreen().x());
+
+  // Move out the view makes it non-opaque. View bounds should stay the same.
+  GetEventGenerator()->MoveMouseTo(
+      focusable_view_->GetBoundsInScreen().CenterPoint());
+  EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 0);
+  EXPECT_EQ(public_account_view_->GetBoundsInScreen(), auth_disabled_bounds);
+
+  // Set auth enable forces arrow button to be opaque.
+  // View bounds should not change.
+  public_account_view_->SetAuthEnabled(true /*enabled*/, false /*animate*/);
+  EXPECT_TRUE(public_account_view_->auth_enabled());
+  EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1);
+  EXPECT_EQ(public_account_view_->GetBoundsInScreen(), auth_disabled_bounds);
+  EXPECT_EQ(public_account_view_->GetBoundsInScreen().x(),
+            public_account_test.arrow_button()->GetBoundsInScreen().x());
+}
+
+}  // namespace ash
diff --git a/ash/login/ui/login_user_view.cc b/ash/login/ui/login_user_view.cc
index 5d410b8..16037ea 100644
--- a/ash/login/ui/login_user_view.cc
+++ b/ash/login/ui/login_user_view.cc
@@ -323,6 +323,10 @@
   return view_->menu_.get();
 }
 
+views::View* LoginUserView::TestApi::user_domain() const {
+  return view_->user_domain_;
+}
+
 bool LoginUserView::TestApi::is_opaque() const {
   return view_->is_opaque_;
 }
diff --git a/ash/login/ui/login_user_view.h b/ash/login/ui/login_user_view.h
index 746697a..c91a6b1 100644
--- a/ash/login/ui/login_user_view.h
+++ b/ash/login/ui/login_user_view.h
@@ -37,6 +37,7 @@
     views::View* tap_button() const;
     views::View* dropdown() const;
     LoginBubble* menu() const;
+    views::View* user_domain() const;
 
     bool is_opaque() const;
 
diff --git a/ash/login/ui/login_user_view_unittest.cc b/ash/login/ui/login_user_view_unittest.cc
index dc93a7f5..30d1e82 100644
--- a/ash/login/ui/login_user_view_unittest.cc
+++ b/ash/login/ui/login_user_view_unittest.cc
@@ -23,8 +23,8 @@
 
   // Builds a new LoginUserView instance and adds it to |container_|.
   LoginUserView* AddUserView(LoginDisplayStyle display_style,
-                             bool show_dropdown) {
-    // TODO(crbug.com/809635): Add test case for show_domain.
+                             bool show_dropdown,
+                             bool public_account) {
     LoginUserView::OnRemoveWarningShown on_remove_warning_shown;
     LoginUserView::OnRemove on_remove;
     if (show_dropdown) {
@@ -35,11 +35,14 @@
     }
 
     auto* view =
-        new LoginUserView(display_style, show_dropdown, false /*show_domain*/,
+        new LoginUserView(display_style, show_dropdown, public_account,
                           base::BindRepeating(&LoginUserViewUnittest::OnTapped,
                                               base::Unretained(this)),
                           on_remove_warning_shown, on_remove);
-    mojom::LoginUserInfoPtr user = CreateUser("foo@foo.com");
+
+    std::string email = "foo@foo.com";
+    mojom::LoginUserInfoPtr user =
+        public_account ? CreatePublicAccountUser(email) : CreateUser(email);
     view->UpdateForUser(user, false /*animate*/);
     container_->AddChildView(view);
     widget()->GetContentsView()->Layout();
@@ -79,10 +82,15 @@
 
 // Verifies that the user view does not change width for short/long usernames.
 TEST_F(LoginUserViewUnittest, DifferentUsernamesHaveSameWidth) {
-  LoginUserView* large = AddUserView(LoginDisplayStyle::kLarge, false);
-  LoginUserView* small = AddUserView(LoginDisplayStyle::kSmall, false);
+  LoginUserView* large =
+      AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/,
+                  false /*public_account*/);
+  LoginUserView* small =
+      AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/,
+                  false /*public_account*/);
   LoginUserView* extra_small =
-      AddUserView(LoginDisplayStyle::kExtraSmall, false);
+      AddUserView(LoginDisplayStyle::kExtraSmall, false /*show_dropdown*/,
+                  false /*public_account*/);
 
   int large_width = large->size().width();
   int small_width = small->size().width();
@@ -107,10 +115,15 @@
 // Verifies that the user views all have different sizes with different display
 // styles.
 TEST_F(LoginUserViewUnittest, DifferentStylesHaveDifferentSizes) {
-  LoginUserView* large = AddUserView(LoginDisplayStyle::kLarge, false);
-  LoginUserView* small = AddUserView(LoginDisplayStyle::kSmall, false);
+  LoginUserView* large =
+      AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/,
+                  false /*public_account*/);
+  LoginUserView* small =
+      AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/,
+                  false /*public_account*/);
   LoginUserView* extra_small =
-      AddUserView(LoginDisplayStyle::kExtraSmall, false);
+      AddUserView(LoginDisplayStyle::kExtraSmall, false /*show_dropdown*/,
+                  false /*public_account*/);
 
   EXPECT_NE(large->size(), gfx::Size());
   EXPECT_NE(large->size(), small->size());
@@ -121,8 +134,12 @@
 // Verifies that displaying the dropdown does not change the view size. Further,
 // the dropdown should not change the centering for the user label.
 TEST_F(LoginUserViewUnittest, DropdownDoesNotChangeSize) {
-  LoginUserView* with = AddUserView(LoginDisplayStyle::kLarge, true);
-  LoginUserView* without = AddUserView(LoginDisplayStyle::kLarge, false);
+  LoginUserView* with =
+      AddUserView(LoginDisplayStyle::kLarge, true /*show_dropdown*/,
+                  false /*public_account*/);
+  LoginUserView* without =
+      AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/,
+                  false /*public_account*/);
   EXPECT_NE(with->size(), gfx::Size());
   EXPECT_EQ(with->size(), without->size());
 
@@ -138,7 +155,9 @@
 // Verifies that the entire user view is a tap target, and not just (for
 // example) the user icon.
 TEST_F(LoginUserViewUnittest, EntireViewIsTapTarget) {
-  LoginUserView* view = AddUserView(LoginDisplayStyle::kSmall, false);
+  LoginUserView* view =
+      AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/,
+                  false /*public_account*/);
   EXPECT_NE(view->size(), gfx::Size());
 
   // Returns true if there is a tap at |point| offset by |dx|, |dy|.
@@ -165,8 +184,12 @@
 // Verifies the focused user view is opaque. Verifies that a hovered view is
 // opaque. Verifies the interaction between focus and hovered opaqueness.
 TEST_F(LoginUserViewUnittest, FocusHoverOpaqueInteractions) {
-  LoginUserView* one = AddUserView(LoginDisplayStyle::kSmall, false);
-  LoginUserView* two = AddUserView(LoginDisplayStyle::kSmall, false);
+  LoginUserView* one =
+      AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/,
+                  false /*public_account*/);
+  LoginUserView* two =
+      AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/,
+                  false /*public_account*/);
   LoginUserView::TestApi one_test(one);
   LoginUserView::TestApi two_test(two);
 
@@ -207,8 +230,12 @@
 // focus, and that a forced opaque element can transition to both
 // opaque/transparent when losing forced opaque.
 TEST_F(LoginUserViewUnittest, ForcedOpaque) {
-  LoginUserView* one = AddUserView(LoginDisplayStyle::kSmall, false);
-  LoginUserView* two = AddUserView(LoginDisplayStyle::kSmall, false);
+  LoginUserView* one =
+      AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/,
+                  false /*public_account*/);
+  LoginUserView* two =
+      AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/,
+                  false /*public_account*/);
   LoginUserView::TestApi one_test(one);
   LoginUserView::TestApi two_test(two);
 
@@ -248,7 +275,9 @@
 // Verifies that a long user name does not push the label or dropdown button
 // outside of the LoginUserView bounds.
 TEST_F(LoginUserViewUnittest, ElideUserLabel) {
-  LoginUserView* view = AddUserView(LoginDisplayStyle::kLarge, true);
+  LoginUserView* view =
+      AddUserView(LoginDisplayStyle::kLarge, true /*show_dropdown*/,
+                  false /*public_account*/);
   LoginUserView::TestApi view_test(view);
 
   mojom::LoginUserInfoPtr user =
@@ -262,4 +291,23 @@
       view_test.dropdown()->GetVisibleBounds()));
 }
 
+// Verifies that displaying the domain does not change the view width.
+// Also domain should have the same horizontal centering as user label.
+TEST_F(LoginUserViewUnittest, DomainDoesNotChangeWidth) {
+  LoginUserView* public_account =
+      AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/,
+                  true /*public_account*/);
+  LoginUserView* regular_user =
+      AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/,
+                  false /*public_account*/);
+  EXPECT_NE(regular_user->size().width(), 0);
+  EXPECT_EQ(regular_user->size().width(), public_account->size().width());
+
+  views::View* user_label = LoginUserView::TestApi(public_account).user_label();
+  views::View* user_domain =
+      LoginUserView::TestApi(public_account).user_label();
+  EXPECT_EQ(user_label->GetBoundsInScreen().CenterPoint().x(),
+            user_domain->GetBoundsInScreen().CenterPoint().x());
+}
+
 }  // namespace ash
diff --git a/ash/system/ime/tray_ime_chromeos_unittest.cc b/ash/system/ime/tray_ime_chromeos_unittest.cc
index 395ffce..1d59292 100644
--- a/ash/system/ime/tray_ime_chromeos_unittest.cc
+++ b/ash/system/ime/tray_ime_chromeos_unittest.cc
@@ -109,8 +109,8 @@
   input_device_client_test_api.SetTouchscreenDevices(screens);
 
   std::vector<ui::InputDevice> keyboards;
-  keyboards.push_back(ui::InputDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard"));
+  keyboards.push_back(
+      ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard"));
   input_device_client_test_api.SetKeyboardDevices(keyboards);
 }
 
diff --git a/ash/system/power/backlights_forced_off_setter_unittest.cc b/ash/system/power/backlights_forced_off_setter_unittest.cc
index aeaf22c..a584d38 100644
--- a/ash/system/power/backlights_forced_off_setter_unittest.cc
+++ b/ash/system/power/backlights_forced_off_setter_unittest.cc
@@ -223,7 +223,7 @@
 
   // Initialize an external touch device.
   ui::TouchscreenDevice external_touchdevice(
-      123, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      123, ui::InputDeviceType::INPUT_DEVICE_USB,
       std::string("test external touch device"), gfx::Size(1000, 1000), 1);
 
   ui::TouchscreenDevice internal_touchdevice(
diff --git a/ash/system/power/peripheral_battery_notifier_unittest.cc b/ash/system/power/peripheral_battery_notifier_unittest.cc
index fe747ba..420cf56 100644
--- a/ash/system/power/peripheral_battery_notifier_unittest.cc
+++ b/ash/system/power/peripheral_battery_notifier_unittest.cc
@@ -189,7 +189,7 @@
   const std::string kTestStylusName = "test_stylus";
 
   // Add an external stylus to our test device manager.
-  ui::TouchscreenDevice stylus(0 /* id */, ui::INPUT_DEVICE_EXTERNAL,
+  ui::TouchscreenDevice stylus(0 /* id */, ui::INPUT_DEVICE_USB,
                                kTestStylusName, gfx::Size(),
                                1 /* touch_points */, true /* has_stylus */);
   stylus.sys_path = base::FilePath(kTestStylusBatteryPath);
diff --git a/ash/system/power/power_prefs.cc b/ash/system/power/power_prefs.cc
index 0a90fada..ba0a2b36 100644
--- a/ash/system/power/power_prefs.cc
+++ b/ash/system/power/power_prefs.cc
@@ -256,6 +256,7 @@
       prefs->GetBoolean(prefs::kPowerWaitForInitialUserActivity);
   values.force_nonzero_brightness_for_user_activity =
       prefs->GetBoolean(prefs::kPowerForceNonzeroBrightnessForUserActivity);
+  values.smart_dim_enabled = prefs->GetBoolean(prefs::kPowerSmartDimEnabled);
 
   power_policy_controller_->ApplyPrefs(values);
 }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index 1c491c70..a336737 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -140,6 +140,9 @@
     Shell::Get()->window_tree_host_manager()->AddObserver(this);
     chromeos::AccelerometerReader::GetInstance()->AddObserver(this);
     ui::InputDeviceManager::GetInstance()->AddObserver(this);
+    bluetooth_devices_observer_ = std::make_unique<BluetoothDevicesObserver>(
+        base::BindRepeating(&TabletModeController::UpdateBluetoothDevice,
+                            base::Unretained(this)));
   }
   chromeos::PowerManagerClient* power_manager_client =
       chromeos::DBusThreadManager::Get()->GetPowerManagerClient();
@@ -562,7 +565,9 @@
   bool has_external_mouse = false;
   for (const ui::InputDevice& mouse :
        ui::InputDeviceManager::GetInstance()->GetMouseDevices()) {
-    if (mouse.type == ui::INPUT_DEVICE_EXTERNAL) {
+    if (mouse.type == ui::INPUT_DEVICE_USB ||
+        (mouse.type == ui::INPUT_DEVICE_BLUETOOTH &&
+         bluetooth_devices_observer_->IsConnectedBluetoothDevice(mouse))) {
       has_external_mouse = true;
       break;
     }
@@ -615,4 +620,19 @@
          lid_angle_ >= kEnterTabletModeAngle;
 }
 
+void TabletModeController::UpdateBluetoothDevice(
+    device::BluetoothDevice* device) {
+  // We only care about mouse type bluetooth device change. Note KEYBOARD
+  // type is also included here as sometimes a bluetooth keyboard comes with a
+  // touch pad.
+  if (device->GetDeviceType() != device::BluetoothDeviceType::MOUSE &&
+      device->GetDeviceType() !=
+          device::BluetoothDeviceType::KEYBOARD_MOUSE_COMBO &&
+      device->GetDeviceType() != device::BluetoothDeviceType::KEYBOARD) {
+    return;
+  }
+
+  HandleMouseAddedOrRemoved();
+}
+
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.h b/ash/wm/tablet_mode/tablet_mode_controller.h
index 4555e520..4b78118 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.h
+++ b/ash/wm/tablet_mode/tablet_mode_controller.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "ash/bluetooth_devices_observer.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/public/interfaces/tablet_mode.mojom.h"
 #include "ash/session/session_observer.h"
@@ -132,7 +133,7 @@
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
   void SuspendDone(const base::TimeDelta& sleep_duration) override;
 
-  // ui::InputDeviceEventObserver::
+  // ui::InputDeviceEventObserver:
   void OnMouseDeviceConfigurationChanged() override;
   void OnDeviceListsComplete() override;
 
@@ -211,6 +212,10 @@
   // angle range.
   bool LidAngleIsInTabletModeRange();
 
+  // Callback function for |bluetooth_devices_observer_|. Called when |device|
+  // changes.
+  void UpdateBluetoothDevice(device::BluetoothDevice* device);
+
   // The maximized window manager (if enabled).
   std::unique_ptr<TabletModeWindowManager> tablet_mode_window_manager_;
 
@@ -257,6 +262,11 @@
   // not enter tablet mode if this is true.
   bool has_external_mouse_ = false;
 
+  // Tracks if the device would enter tablet mode, but does not because of a
+  // attached external mouse. If the external mouse is detached and this is
+  // true, we will enter tablet mode.
+  bool should_enter_tablet_mode_ = false;
+
   // Tracks smoothed accelerometer data over time. This is done when the hinge
   // is approaching vertical to remove abrupt acceleration that can lead to
   // incorrect calculations of hinge angles.
@@ -277,6 +287,9 @@
 
   ScopedSessionObserver scoped_session_observer_;
 
+  // Observer to observe the bluetooth devices.
+  std::unique_ptr<BluetoothDevicesObserver> bluetooth_devices_observer_;
+
   base::ObserverList<TabletModeObserver>::Unchecked tablet_mode_observers_;
 
   base::WeakPtrFactory<TabletModeController> weak_factory_;
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc b/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc
index 89bae99..ef0d7439 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc
@@ -27,7 +27,7 @@
 
 void TabletModeControllerTestApi::AttachExternalMouse() {
   ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice(
-      3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")});
+      3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
   base::RunLoop().RunUntilIdle();
   tablet_mode_controller_->OnMouseDeviceConfigurationChanged();
 }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index a99be0c6..a21d35e 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -662,8 +662,8 @@
   EXPECT_TRUE(AreEventsBlocked());
 
   // Tests that attaching a external mouse will not change the mode.
-  ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice(
-      3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")});
+  ws::InputDeviceClientTestApi().SetMouseDevices(
+      {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsTabletModeStarted());
   EXPECT_TRUE(AreEventsBlocked());
@@ -761,8 +761,8 @@
   EXPECT_FALSE(IsTabletModeStarted());
 
   // Attach a external mouse.
-  ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice(
-      3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")});
+  ws::InputDeviceClientTestApi().SetMouseDevices(
+      {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
 
@@ -787,8 +787,8 @@
 
   // Attach external mouse and keyboard. Verify that tablet mode has ended, but
   // events are still blocked because the keyboard is still facing the bottom.
-  ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice(
-      3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")});
+  ws::InputDeviceClientTestApi().SetMouseDevices(
+      {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_TRUE(AreEventsBlocked());
@@ -816,7 +816,7 @@
 
   // Attach external mouse doesn't change the mode.
   ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice(
-      3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")});
+      3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_FALSE(AreEventsBlocked());
diff --git a/base/message_loop/message_loop_task_runner.cc b/base/message_loop/message_loop_task_runner.cc
index a941a01..abb632f7 100644
--- a/base/message_loop/message_loop_task_runner.cc
+++ b/base/message_loop/message_loop_task_runner.cc
@@ -108,8 +108,7 @@
 }
 
 void MessageLoopTaskRunner::SetAddQueueTimeToTasks(bool enable) {
-  DCHECK_NE(add_queue_time_to_tasks_, enable);
-  add_queue_time_to_tasks_ = enable;
+  base::subtle::NoBarrier_Store(&add_queue_time_to_tasks_, enable ? 1 : 0);
 }
 
 MessageLoopTaskRunner::~MessageLoopTaskRunner() = default;
@@ -127,7 +126,8 @@
 
   PendingTask pending_task(from_here, std::move(task),
                            CalculateDelayedRuntime(from_here, delay), nestable);
-  if (add_queue_time_to_tasks_) {
+
+  if (base::subtle::NoBarrier_Load(&add_queue_time_to_tasks_)) {
     if (pending_task.delayed_run_time.is_null()) {
       pending_task.queue_time = base::TimeTicks::Now();
     } else {
diff --git a/base/message_loop/message_loop_task_runner.h b/base/message_loop/message_loop_task_runner.h
index 37a4de4..f9ba2d1 100644
--- a/base/message_loop/message_loop_task_runner.h
+++ b/base/message_loop/message_loop_task_runner.h
@@ -5,6 +5,7 @@
 #ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
 #define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
 
+#include "base/atomicops.h"
 #include "base/base_export.h"
 #include "base/callback.h"
 #include "base/macros.h"
@@ -105,7 +106,7 @@
   int next_sequence_num_ = 0;
 
   // Whether to add the queue time to tasks.
-  bool add_queue_time_to_tasks_ = false;
+  base::subtle::Atomic32 add_queue_time_to_tasks_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(MessageLoopTaskRunner);
 };
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc
index 98f5d11..556719e 100644
--- a/base/trace_event/heap_profiler_allocation_context_tracker.cc
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -259,7 +259,13 @@
 
   ctx->backtrace.frame_count = backtrace - std::begin(ctx->backtrace.frames);
 
-  ctx->type_name = TaskContext();
+  // TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension
+  // (component name) in the heap profiler and not piggy back on the type name.
+  if (!task_contexts_.empty()) {
+    ctx->type_name = task_contexts_.back();
+  } else {
+    ctx->type_name = nullptr;
+  }
 
   return true;
 }
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.h b/base/trace_event/heap_profiler_allocation_context_tracker.h
index a117ea0..da03b7f6 100644
--- a/base/trace_event/heap_profiler_allocation_context_tracker.h
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.h
@@ -108,11 +108,6 @@
   void PushCurrentTaskContext(const char* context);
   void PopCurrentTaskContext(const char* context);
 
-  // Returns most recent task context added by ScopedTaskExecutionTracker.
-  const char* TaskContext() const {
-    return task_contexts_.empty() ? nullptr : task_contexts_.back();
-  }
-
   // Fills a snapshot of the current thread-local context. Doesn't fill and
   // returns false if allocations are being ignored.
   bool GetContextSnapshot(AllocationContext* snapshot);
diff --git a/build/chromeos/run_vm_test.py b/build/chromeos/run_vm_test.py
index cc7c078..964c0f3d 100755
--- a/build/chromeos/run_vm_test.py
+++ b/build/chromeos/run_vm_test.py
@@ -29,6 +29,8 @@
     0, os.path.join(CHROMIUM_SRC_PATH, 'tools', 'swarming_client', 'utils'))
 import subprocess42  # pylint: disable=import-error
 
+DEFAULT_CROS_CACHE = os.path.abspath(os.path.join(
+    CHROMIUM_SRC_PATH, 'build', 'cros_cache'))
 CHROMITE_PATH = os.path.abspath(os.path.join(
     CHROMIUM_SRC_PATH, 'third_party', 'chromite'))
 CROS_RUN_VM_TEST_PATH = os.path.abspath(os.path.join(
@@ -47,11 +49,9 @@
   def __init__(self, args, unknown_args):
     self._additional_args = unknown_args
     self._path_to_outdir = args.path_to_outdir
-    self._test_exe = args.test_exe
     self._test_launcher_summary_output = args.test_launcher_summary_output
     self._vm_logs_dir = args.vm_logs_dir
 
-    self._test_env = os.environ.copy()
     self._retries = 0
     self._timeout = None
 
@@ -67,6 +67,23 @@
           '--results-dest-dir', args.vm_logs_dir,
       ]
 
+    self._test_env = os.environ.copy()
+    # deploy_chrome needs a set of GN args used to build chrome to determine if
+    # certain libraries need to be pushed to the VM. It looks for the args via
+    # an env var. To trigger the default deploying behavior, give it a dummy set
+    # of args.
+    # TODO(crbug.com/823996): Make the GN-dependent deps controllable via cmd
+    # line args.
+    if not self._test_env.get('GN_ARGS'):
+      self._test_env['GN_ARGS'] = 'is_chromeos = true'
+    if not self._test_env.get('USE'):
+      self._test_env['USE'] = 'highdpi'
+    self._test_env['PATH'] = (
+        self._test_env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin'))
+  @property
+  def suite_name(self):
+    raise NotImplementedError('Child classes need to define suite name.')
+
   @property
   def vm_test_cmd(self):
     return self._vm_test_cmd
@@ -119,7 +136,45 @@
     return test_proc.returncode
 
   def post_run(self, return_code):
-    raise NotImplementedError()
+    # Create a simple json results file for a test run. The results will contain
+    # only one test (suite_name), and will either be a PASS or FAIL depending on
+    # return_code.
+    if self._test_launcher_summary_output:
+      result = (base_test_result.ResultType.FAIL if return_code else
+                    base_test_result.ResultType.PASS)
+      suite_result = base_test_result.BaseTestResult(self.suite_name, result)
+      run_results = base_test_result.TestRunResults()
+      run_results.AddResult(suite_result)
+      with open(self._test_launcher_summary_output, 'w') as f:
+        json.dump(json_results.GenerateResultsDict([run_results]), f)
+
+
+class TastTest(RemoteTest):
+
+  def __init__(self, args, unknown_args):
+    super(TastTest, self).__init__(args, unknown_args)
+
+    self._suite_name = args.suite_name
+    self._tests = args.tests
+
+  @property
+  def suite_name(self):
+    return self._suite_name
+
+  def build_test_command(self):
+    if self._additional_args:
+      raise TestFormatError(
+          'Tast tests should not have additional args: %s' % (
+              self._additional_args))
+
+    self._vm_test_cmd += [
+        '--deploy',
+        '--build-dir', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH),
+        '--cmd',
+        '--',
+        'local_test_runner',
+    ]
+    self._vm_test_cmd.extend(self._tests)
 
 
 class GTestTest(RemoteTest):
@@ -133,6 +188,7 @@
   def __init__(self, args, unknown_args):
     super(GTestTest, self).__init__(args, unknown_args)
 
+    self._test_exe = args.test_exe
     self._runtime_deps_path = args.runtime_deps_path
     self._vpython_dir = args.vpython_dir
 
@@ -141,6 +197,10 @@
 
     self._on_vm_script = None
 
+  @property
+  def suite_name(self):
+    return self._test_exe
+
   def build_test_command(self):
     # To keep things easy for us, ensure both types of output locations are
     # the same.
@@ -284,6 +344,10 @@
     self._retries = 2
     self._timeout = 300
 
+  @property
+  def suite_name(self):
+    return SANITY_TEST_TARGET
+
   def build_test_command(self):
     if '--gtest_filter=%s' % SANITY_TEST_TARGET in self._additional_args:
       logging.info(
@@ -304,33 +368,6 @@
         '--build-dir', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH),
     ]
 
-    # deploy_chrome needs a set of GN args used to build chrome to determine if
-    # certain libraries need to be pushed to the VM. It looks for the args via
-    # an env var. To trigger the default deploying behavior, give it a dummy set
-    # of args.
-    # TODO(crbug.com/823996): Make the GN-dependent deps controllable via cmd
-    # line args.
-    if not self._test_env.get('GN_ARGS'):
-      self._test_env['GN_ARGS'] = 'is_chromeos = true'
-    if not self._test_env.get('USE'):
-      self._test_env['USE'] = 'highdpi'
-    self._test_env['PATH'] = (
-        self._test_env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin'))
-
-  def post_run(self, return_code):
-    # Create a simple json results file for the sanity test if needed. The
-    # results will contain only one test (SANITY_TEST_TARGET), and will
-    # either be a PASS or FAIL depending on the return code of cros_run_vm_test.
-    if self._test_launcher_summary_output:
-      result = (base_test_result.ResultType.FAIL if return_code else
-                    base_test_result.ResultType.PASS)
-      sanity_test_result = base_test_result.BaseTestResult(
-          SANITY_TEST_TARGET, result)
-      run_results = base_test_result.TestRunResults()
-      run_results.AddResult(sanity_test_result)
-      with open(self._test_launcher_summary_output, 'w') as f:
-        json.dump(json_results.GenerateResultsDict([run_results]), f)
-
 
 def vm_test(args, unknown_args):
   # cros_run_vm_test has trouble with relative paths that go up directories,
@@ -340,7 +377,9 @@
   # pylint: disable=redefined-variable-type
   # TODO: Remove the above when depot_tool's pylint is updated to include the
   # fix to https://github.com/PyCQA/pylint/issues/710.
-  if args.test_exe == SANITY_TEST_TARGET:
+  if args.test_type == 'tast':
+    test = TastTest(args, unknown_args)
+  elif args.test_exe == SANITY_TEST_TARGET:
     test = BrowserSanityTest(args, unknown_args)
   else:
     test = GTestTest(args, unknown_args)
@@ -402,6 +441,30 @@
       cros_run_vm_test_cmd, stdout=sys.stdout, stderr=sys.stderr, env=test_env)
 
 
+def add_common_args(parser):
+   parser.add_argument(
+       '--cros-cache', type=str, default=DEFAULT_CROS_CACHE,
+       help='Path to cros cache.')
+   parser.add_argument(
+       '--path-to-outdir', type=str, required=True,
+       help='Path to output directory, all of whose contents will be '
+            'deployed to the device.')
+   parser.add_argument(
+       '--runtime-deps-path', type=str,
+       help='Runtime data dependency file from GN.')
+   parser.add_argument(
+       '--vpython-dir', type=str,
+       help='Location on host of a directory containing a vpython binary to '
+            'deploy to the VM before the test starts. The location of this '
+            'dir will be added onto PATH in the VM. WARNING: The arch of the '
+            'VM might not match the arch of the host, so avoid using '
+            '"${platform}" when downloading vpython via CIPD.')
+   parser.add_argument(
+       '--vm-logs-dir', type=str,
+       help='Will copy everything under /var/log/ from the VM after the test '
+            'into the specified dir.')
+
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('--verbose', '-v', action='store_true')
@@ -416,7 +479,8 @@
            '"--". Hostname and port for the VM will be 127.0.0.1:9222.')
   host_cmd_parser.set_defaults(func=host_cmd)
   host_cmd_parser.add_argument(
-      '--cros-cache', type=str, required=True, help='Path to cros cache.')
+      '--cros-cache', type=str, default=DEFAULT_CROS_CACHE,
+      help='Path to cros cache.')
   host_cmd_parser.add_argument(
       '--path-to-outdir', type=os.path.realpath,
       help='Path to output directory, all of whose contents will be deployed '
@@ -426,14 +490,13 @@
       help='Will deploy a locally built Chrome binary to the VM before running '
            'the host-cmd.')
   host_cmd_parser.add_argument('cmd', nargs=argparse.REMAINDER)
-  # VM-side test args.
-  vm_test_parser = subparsers.add_parser(
+  # GTest args.
+  # TODO(bpastene): Rename 'vm-test' arg to 'gtest'.
+  gtest_parser = subparsers.add_parser(
       'vm-test',
       help='Runs a vm-side gtest.')
-  vm_test_parser.set_defaults(func=vm_test)
-  vm_test_parser.add_argument(
-      '--cros-cache', type=str, required=True, help='Path to cros cache.')
-  vm_test_parser.add_argument(
+  gtest_parser.set_defaults(func=vm_test)
+  gtest_parser.add_argument(
       '--test-exe', type=str, required=True,
       help='Path to test executable to run inside VM. If the value is '
            '%s, the sanity test that ships with the VM '
@@ -444,39 +507,39 @@
 
   # GTest args. Some are passed down to the test binary in the VM. Others are
   # parsed here since they might need tweaking or special handling.
-  vm_test_parser.add_argument(
+  gtest_parser.add_argument(
       '--test-launcher-summary-output', type=str,
       help='When set, will pass the same option down to the test and retrieve '
            'its result file at the specified location.')
   # Shard args are parsed here since we might also specify them via env vars.
-  vm_test_parser.add_argument(
+  gtest_parser.add_argument(
       '--test-launcher-shard-index',
       type=int, default=os.environ.get('GTEST_SHARD_INDEX', 0),
       help='Index of the external shard to run.')
-  vm_test_parser.add_argument(
+  gtest_parser.add_argument(
       '--test-launcher-total-shards',
       type=int, default=os.environ.get('GTEST_TOTAL_SHARDS', 1),
       help='Total number of external shards.')
 
-  # Misc args.
-  vm_test_parser.add_argument(
-      '--path-to-outdir', type=str, required=True,
-      help='Path to output directory, all of whose contents will be deployed '
-           'to the device.')
-  vm_test_parser.add_argument(
-      '--runtime-deps-path', type=str,
-      help='Runtime data dependency file from GN.')
-  vm_test_parser.add_argument(
-      '--vpython-dir', type=str,
-      help='Location on host of a directory containing a vpython binary to '
-           'deploy to the VM before the test starts. The location of this dir '
-           'will be added onto PATH in the VM. WARNING: The arch of the VM '
-           'might not match the arch of the host, so avoid using "${platform}" '
-           'when downloading vpython via CIPD.')
-  vm_test_parser.add_argument(
-      '--vm-logs-dir', type=str,
-      help='Will copy everything under /var/log/ from the VM after the test '
-           'into the specified dir.')
+  # Tast test args.
+  tast_test_parser = subparsers.add_parser(
+      'tast',
+      help='Runs a vm-side set of Tast tests.')
+  tast_test_parser.set_defaults(func=vm_test)
+  tast_test_parser.add_argument(
+      '--suite-name', type=str, required=True,
+      help='Name to apply to the set of Tast tests to run. This has no effect '
+           'on what is executed, but is used mainly for test results reporting '
+           'and tracking (eg: flakiness dashboard).')
+  tast_test_parser.add_argument(
+      '--test-launcher-summary-output', type=str,
+      help='Generates a simple GTest-style JSON result file for the test run.')
+  tast_test_parser.add_argument(
+      '--test', '-t', action='append', dest='tests', required=True,
+      help='A Tast test to run in the VM (eg: "ui.ChromeLogin").')
+
+  add_common_args(gtest_parser)
+  add_common_args(tast_test_parser)
   args, unknown_args = parser.parse_known_args()
 
   logging.basicConfig(level=logging.DEBUG if args.verbose else logging.WARN)
diff --git a/build/fuchsia/device_target.py b/build/fuchsia/device_target.py
index 0f8e270..862b10b 100644
--- a/build/fuchsia/device_target.py
+++ b/build/fuchsia/device_target.py
@@ -5,11 +5,13 @@
 """Implements commands for running and interacting with Fuchsia on devices."""
 
 import boot_data
+import filecmp
 import logging
 import os
 import subprocess
 import sys
 import target
+import tempfile
 import time
 import uuid
 
@@ -21,6 +23,8 @@
 # Number of failed connection attempts before redirecting system logs to stdout.
 CONNECT_RETRY_COUNT_BEFORE_LOGGING = 10
 
+TARGET_HASH_FILE_PATH = '/data/.hash'
+
 class DeviceTarget(target.Target):
   def __init__(self, output_dir, target_cpu, host=None, port=None,
                ssh_config=None, system_log_file=None):
@@ -54,6 +58,20 @@
     if self._loglistener:
       self._loglistener.kill()
 
+  def _SDKHashMatches(self):
+    """Checks if /data/.hash on the device matches SDK_ROOT/.hash.
+
+    Returns True if the files are identical, or False otherwise.
+    """
+    with tempfile.NamedTemporaryFile() as tmp:
+      try:
+        self.GetFile(TARGET_HASH_FILE_PATH, tmp.name)
+      except subprocess.CalledProcessError:
+        # If the file is unretrievable for whatever reason, assume mismatch.
+        return False
+
+      return filecmp.cmp(tmp.name, os.path.join(SDK_ROOT, '.hash'), False)
+
   def __Discover(self, node_name):
     """Returns the IP address and port of a Fuchsia instance discovered on
     the local area network."""
@@ -75,9 +93,14 @@
       node_name = boot_data.GetNodeName(self._output_dir)
       self._host = self.__Discover(node_name)
       if self._host and self._WaitUntilReady(retries=0):
-        logging.info('Connected to an already booted device.')
-        self._new_instance = False
-        return
+        if not self._SDKHashMatches():
+          logging.info('SDK hash does not match, rebooting.')
+          self.RunCommand(['dm', 'reboot'])
+          self._started = False
+        else:
+          logging.info('Connected to an already booted device.')
+          self._new_instance = False
+          return
 
       logging.info('Netbooting Fuchsia. ' +
                    'Please ensure that your device is in bootloader mode.')
@@ -122,6 +145,9 @@
 
     self._WaitUntilReady();
 
+    # Update the target's hash to match the current tree's.
+    self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)
+
   def IsNewInstance(self):
     return self._new_instance
 
diff --git a/cc/cc.gni b/cc/cc.gni
index 51bbd51a..8539c01 100644
--- a/cc/cc.gni
+++ b/cc/cc.gni
@@ -11,7 +11,7 @@
   "//build/config/compiler:wexit_time_destructors",
 ]
 
-if (!is_debug && (is_win || is_android)) {
+if (!is_debug) {
   cc_remove_configs += [ "//build/config/compiler:default_optimization" ]
   cc_add_configs += [ "//build/config/compiler:optimize_max" ]
 }
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index a7d7f4ee..283e364 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -429,6 +429,8 @@
     test_hooks_->BeginMainFrame(args);
   }
 
+  void RecordEndOfFrameMetrics(base::TimeTicks) override {}
+
   void UpdateLayerTreeHost() override { test_hooks_->UpdateLayerTreeHost(); }
 
   void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta,
diff --git a/cc/test/stub_layer_tree_host_client.h b/cc/test/stub_layer_tree_host_client.h
index 57d56ffc..fa24c0fa 100644
--- a/cc/test/stub_layer_tree_host_client.h
+++ b/cc/test/stub_layer_tree_host_client.h
@@ -17,6 +17,7 @@
   void WillBeginMainFrame() override {}
   void DidBeginMainFrame() override {}
   void BeginMainFrame(const viz::BeginFrameArgs& args) override {}
+  void RecordEndOfFrameMetrics(base::TimeTicks) override {}
   void BeginMainFrameNotExpectedSoon() override {}
   void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override {}
   void UpdateLayerTreeHost() override {}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 716021c..a18aa62 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -945,6 +945,10 @@
   RecordWheelAndTouchScrollingCount(*info);
 }
 
+void LayerTreeHost::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) {
+  client_->RecordEndOfFrameMetrics(frame_begin_time);
+}
+
 const base::WeakPtr<InputHandler>& LayerTreeHost::GetInputHandler()
     const {
   return input_handler_weak_ptr_;
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 3531699..d2cd6ed 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -536,6 +536,7 @@
   // Called when the compositor completed page scale animation.
   void DidCompletePageScaleAnimation();
   void ApplyScrollAndScale(ScrollAndScaleSet* info);
+  void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time);
 
   LayerTreeHostClient* client() { return client_; }
 
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h
index 8950d17b..302521d 100644
--- a/cc/trees/layer_tree_host_client.h
+++ b/cc/trees/layer_tree_host_client.h
@@ -89,6 +89,9 @@
   virtual void DidPresentCompositorFrame(
       uint32_t frame_token,
       const gfx::PresentationFeedback& feedback) = 0;
+  // Record UMA and UKM metrics that require the time from the start of
+  // BeginMainFrame to the Commit, or early out.
+  virtual void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) = 0;
 
  protected:
   virtual ~LayerTreeHostClient() {}
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index c84c480f..c89bd779 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -228,6 +228,7 @@
   if (skip_commit) {
     TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit_InsideBeginMainFrame",
                          TRACE_EVENT_SCOPE_THREAD);
+    layer_tree_host_->RecordEndOfFrameMetrics(begin_main_frame_start_time);
     std::vector<std::unique_ptr<SwapPromise>> empty_swap_promises;
     ImplThreadTaskRunner()->PostTask(
         FROM_HERE, base::BindOnce(&ProxyImpl::BeginMainFrameAbortedOnImpl,
@@ -274,6 +275,7 @@
   current_pipeline_stage_ = COMMIT_PIPELINE_STAGE;
   if (final_pipeline_stage_ < COMMIT_PIPELINE_STAGE) {
     TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD);
+    layer_tree_host_->RecordEndOfFrameMetrics(begin_main_frame_start_time);
     std::vector<std::unique_ptr<SwapPromise>> swap_promises =
         layer_tree_host_->GetSwapPromiseManager()->TakeSwapPromises();
     ImplThreadTaskRunner()->PostTask(
@@ -308,6 +310,7 @@
   // coordinated by the Scheduler.
   {
     TRACE_EVENT0("cc", "ProxyMain::BeginMainFrame::commit");
+    layer_tree_host_->RecordEndOfFrameMetrics(begin_main_frame_start_time);
 
     DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
 
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 3cad880..ff156841 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2236,8 +2236,8 @@
         }
 
         if (!ChromeFeatureList.isInitialized()
-                || !ChromeFeatureList.isEnabled(
-                           ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)) {
+                || (!ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)
+                           && !DeviceClassManager.enableAccessibilityLayout())) {
             super.setStatusBarColor(tab,
                     ApiCompatibilityUtils.getColor(getResources(), R.color.modern_primary_color));
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NavigationBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/NavigationBarColorController.java
index 60af248..99db394c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/NavigationBarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/NavigationBarColorController.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
+import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -120,7 +121,8 @@
         boolean overviewVisible = mOverviewModeBehavior.overviewVisible() && !mOverviewModeHiding;
 
         boolean useLightNavigation;
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)) {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)
+                || DeviceClassManager.enableAccessibilityLayout()) {
             useLightNavigation = !mTabModelSelector.isIncognitoSelected();
         } else {
             useLightNavigation = !mTabModelSelector.isIncognitoSelected() || overviewVisible;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 6d1b70f..4ab8ab9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -98,6 +98,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
 import org.chromium.chrome.browser.tabmodel.TabReparentingParams;
 import org.chromium.chrome.browser.toolbar.ToolbarControlContainer;
+import org.chromium.chrome.browser.toolbar.ToolbarManager;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.chrome.browser.util.UrlUtilities;
@@ -793,6 +794,8 @@
         mTabObserverRegistrar.registerPageLoadMetricsObserver(
                 new FirstMeaningfulPaintObserver(mTabObserver, tab));
 
+        initalizePreviewsObserver();
+
         // Immediately add the observer to PageLoadMetrics to catch early events that may
         // be generated in the middle of tab initialization.
         mTabObserverRegistrar.addObserversForTab(tab);
@@ -805,6 +808,67 @@
         prepareTabBackground(tab);
     }
 
+    private void initalizePreviewsObserver() {
+        mTabObserverRegistrar.registerTabObserver(new EmptyTabObserver() {
+            /** Keeps track of the original color before the preview was shown. */
+            private int mOriginalColor;
+
+            /** True if a change to the toolbar color was made because of a preview. */
+            private boolean mTriggeredPreviewChange;
+
+            @Override
+            public void onPageLoadFinished(Tab tab) {
+                // Update the color when the page load finishes.
+                updateColor(tab);
+            }
+
+            @Override
+            public void didReloadLoFiImages(Tab tab) {
+                // Update the color when the LoFi preview is reloaded.
+                updateColor(tab);
+            }
+
+            @Override
+            public void onUrlUpdated(Tab tab) {
+                // Update the color on every new URL.
+                updateColor(tab);
+            }
+
+            /**
+             * Updates the color of the Activity's status bar and the CCT Toolbar. When a preview is
+             * shown, it should be reset to the default color. If the user later navigates away from
+             * that preview to a non-preview page, reset the color back to the original. This does
+             * not interfere with site-specific theme colors which are disabled when a preview is
+             * being shown.
+             */
+            private void updateColor(Tab tab) {
+                final ToolbarManager manager = getToolbarManager();
+                // Record the original toolbar color in case we need to revert back to it later
+                // after a preview has been shown then the user navigates to another non-preview
+                // page.
+                if (mOriginalColor == 0) mOriginalColor = manager.getPrimaryColor();
+
+                final boolean shouldUpdateOriginal = manager.getShouldUpdateToolbarPrimaryColor();
+                manager.setShouldUpdateToolbarPrimaryColor(true);
+
+                if (tab.isPreview()) {
+                    final int defaultColor = ColorUtils.getDefaultThemeColor(getResources(), false);
+                    manager.updatePrimaryColor(defaultColor, false);
+                    setStatusBarColor(defaultColor, false);
+                    mTriggeredPreviewChange = true;
+                } else if (mOriginalColor != manager.getPrimaryColor() && mTriggeredPreviewChange) {
+                    manager.updatePrimaryColor(mOriginalColor, false);
+                    setStatusBarColor(mOriginalColor, false);
+
+                    mTriggeredPreviewChange = false;
+                    mOriginalColor = 0;
+                }
+
+                manager.setShouldUpdateToolbarPrimaryColor(shouldUpdateOriginal);
+            }
+        });
+    }
+
     @Override
     public void initializeCompositor() {
         super.initializeCompositor();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
index e98ed46..f7f06217 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.explore_sites;
 
+import android.graphics.Bitmap;
+
 import org.chromium.base.Callback;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -29,6 +31,10 @@
         nativeGetEspCatalog(profile, result, callback);
     }
 
+    public static void getSiteImage(Profile profile, int siteID, Callback<Bitmap> callback) {
+        nativeGetIcon(profile, siteID, callback);
+    }
+
     /**
      * Causes a network request for updating the catalog.
      */
@@ -48,4 +54,7 @@
     static native int nativeGetVariation();
     private static native void nativeGetEspCatalog(Profile profile,
             List<ExploreSitesCategory> result, Callback<List<ExploreSitesCategory>> callback);
+
+    private static native void nativeGetIcon(
+            Profile profile, int siteID, Callback<Bitmap> callback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/TasksUma.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/TasksUma.java
index 099666a..dac3592 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/TasksUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/TasksUma.java
@@ -45,7 +45,7 @@
             }
         }
 
-        recordStatistic(tabInGroupsCount, tabGroupCount, model.getCount());
+        recordParentChildrenTabStatistic(tabInGroupsCount, tabGroupCount, model.getCount());
     }
 
     private static int getTabsInOneGroupCount(
@@ -62,17 +62,31 @@
 
     private static void getTabsRelationship(
             TabModel model, Map<Integer, List<Integer>> tabsRelationList) {
+        int duplicatedTabCount = 0;
+        Map<String, Integer> uniqueUrlCounterMap = new HashMap<>();
+
         for (int i = 0; i < model.getCount(); i++) {
             Tab currentTab = model.getTabAt(i);
+
+            String url = currentTab.getUrl();
+            int urlDuplicatedCount = 0;
+            if (uniqueUrlCounterMap.containsKey(url)) {
+                duplicatedTabCount++;
+                urlDuplicatedCount = uniqueUrlCounterMap.get(url);
+            }
+            uniqueUrlCounterMap.put(url, urlDuplicatedCount + 1);
+
             int parentIdOfCurrentTab = currentTab.getParentId();
             if (!tabsRelationList.containsKey(parentIdOfCurrentTab)) {
                 tabsRelationList.put(parentIdOfCurrentTab, new ArrayList<>());
             }
             tabsRelationList.get(parentIdOfCurrentTab).add(currentTab.getId());
         }
+
+        recordDuplicatedTabStatistic(duplicatedTabCount, model.getCount());
     }
 
-    private static void recordStatistic(
+    private static void recordParentChildrenTabStatistic(
             int tabsInGroupCount, int tabGroupCount, int totalTabCount) {
         if (totalTabCount == 0) return;
 
@@ -101,4 +115,15 @@
         Log.d(TAG, "TabsInGroupRatioPercent: %d", (int) tabsInGroupRatioPercent);
         Log.d(TAG, "TabGroupDensityPercent: %d", (int) tabGroupDensityPercent);
     }
+
+    private static void recordDuplicatedTabStatistic(int duplicatedTabCount, int totalTabCount) {
+        if (totalTabCount == 0 || duplicatedTabCount >= totalTabCount) return;
+
+        RecordHistogram.recordCountHistogram(
+                "Tabs.Tasks.DuplicatedTab.DuplicatedTabCount", duplicatedTabCount);
+
+        int duplicatedTabRatioPercent = 100 * duplicatedTabCount / totalTabCount;
+        RecordHistogram.recordPercentageHistogram(
+                "Tabs.Tasks.DuplicatedTab.DuplicatedTabRatio", duplicatedTabRatioPercent);
+    }
 }
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 0019d5b5..4f901ab 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
@@ -1408,6 +1408,14 @@
     }
 
     /**
+     * @return Whether we should be updating the toolbar primary color based on updates from the
+     * Tab.
+     */
+    public boolean getShouldUpdateToolbarPrimaryColor() {
+        return mShouldUpdateToolbarPrimaryColor;
+    }
+
+    /**
      * @return The primary toolbar color.
      */
     public int getPrimaryColor() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
index a2a27c0..01930f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
@@ -109,27 +109,24 @@
         mStandardButtonIcon = new TintedImageView(getContext());
         mStandardButtonIcon.setImageResource(R.drawable.btn_normal_tabs);
         mStandardButtonIcon.setScaleY(-1.0f);
+        mStandardButtonIcon.setContentDescription(
+                getResources().getString(R.string.accessibility_tab_switcher_standard_stack));
         mIncognitoButtonIcon = new TintedImageView(getContext());
         mIncognitoButtonIcon.setImageResource(R.drawable.btn_incognito_tabs);
         mIncognitoButtonIcon.setScaleY(-1.0f);
+        mIncognitoButtonIcon.setContentDescription(getResources().getString(
+                ChromeFeatureList.isEnabled(ChromeFeatureList.INCOGNITO_STRINGS)
+                        ? R.string.accessibility_tab_switcher_private_stack
+                        : R.string.accessibility_tab_switcher_incognito_stack));
 
         setDividerDrawable(null);
         ((ListView) findViewById(R.id.list_view)).setDivider(null);
 
         mLayout = findViewById(R.id.tab_wrapper);
         mStackButtonWrapper = findViewById(R.id.tab_layout);
-        mStandardButton =
-                mStackButtonWrapper.newTab()
-                        .setCustomView(mStandardButtonIcon)
-                        .setContentDescription(R.string.accessibility_tab_switcher_standard_stack);
+        mStandardButton = mStackButtonWrapper.newTab().setCustomView(mStandardButtonIcon);
         mStackButtonWrapper.addTab(mStandardButton);
-        mIncognitoButton =
-                mStackButtonWrapper.newTab()
-                        .setCustomView(mIncognitoButtonIcon)
-                        .setContentDescription(
-                                ChromeFeatureList.isEnabled(ChromeFeatureList.INCOGNITO_STRINGS)
-                                        ? R.string.accessibility_tab_switcher_private_stack
-                                        : R.string.accessibility_tab_switcher_incognito_stack);
+        mIncognitoButton = mStackButtonWrapper.newTab().setCustomView(mIncognitoButtonIcon);
         mStackButtonWrapper.addTab(mIncognitoButton);
         mStackButtonWrapper.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
             @Override
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 49e9cf3..2a7994f 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4078,7 +4078,7 @@
       <message name="IDS_EXTENSION_WEB_STORE_TITLE" desc="Text for the Chrome Web Store">
         Chrome Web Store
       </message>
-      <message name="IDS_EXTENSION_WEB_STORE_TITLE_SHORT" desc="Text for the Chrome Web Store">
+      <message name="IDS_EXTENSION_WEB_STORE_TITLE_SHORT" desc="Shortened version of text for the Chrome Web Store">
         Web Store
       </message>
       <message name="IDS_EXTENSIONS_SHOW_DETAILS" desc="Tooltip for the button next to an extension that shows more details">
diff --git a/chrome/app/nibs/BUILD.gn b/chrome/app/nibs/BUILD.gn
index 44e41aa..84880c6 100644
--- a/chrome/app/nibs/BUILD.gn
+++ b/chrome/app/nibs/BUILD.gn
@@ -10,7 +10,6 @@
 translated_xibs = [
   "SaveAccessoryView.xib",
   "TaskManager.xib",
-  "Toolbar.xib",
 ]
 
 mac_xib_bundle_data("chrome_xibs") {
diff --git a/chrome/app/nibs/Toolbar.xib b/chrome/app/nibs/Toolbar.xib
deleted file mode 100644
index bc6c940..0000000
--- a/chrome/app/nibs/Toolbar.xib
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13F1077" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
-    <dependencies>
-        <deployment version="1090" identifier="macosx"/>
-        <development version="5100" identifier="xcode"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
-    </dependencies>
-    <objects>
-        <customObject id="-2" userLabel="File's Owner" customClass="ToolbarController">
-            <connections>
-                <outlet property="backButton_" destination="2" id="17"/>
-                <outlet property="browserActionsContainerView_" destination="144" id="154"/>
-                <outlet property="forwardButton_" destination="7" id="18"/>
-                <outlet property="homeButton_" destination="8" id="35"/>
-                <outlet property="locationBar_" destination="4" id="31"/>
-                <outlet property="reloadButton_" destination="3" id="19"/>
-                <outlet property="view" destination="1" id="22"/>
-                <outlet property="appMenuButton_" destination="38" id="41"/>
-            </connections>
-        </customObject>
-        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
-        <customObject id="-3" userLabel="Application"/>
-        <customView id="1" customClass="ToolbarViewCocoa">
-            <rect key="frame" x="0.0" y="0.0" width="604" height="35"/>
-            <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
-            <subviews>
-                <button toolTip="^IDS_APPMENU_TOOLTIP" id="38" customClass="MenuButton">
-                    <rect key="frame" x="572" y="4" width="29" height="29"/>
-                    <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
-                    <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" borderStyle="border" inset="2" id="39" customClass="AppToolbarButtonCell">
-                        <behavior key="behavior" lightByContents="YES"/>
-                        <font key="font" metaFont="system"/>
-                    </buttonCell>
-                </button>
-                <button toolTip="^IDS_TOOLTIP_BACK" tag="33000" id="2" customClass="MenuButton">
-                    <rect key="frame" x="3" y="4" width="29" height="29"/>
-                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
-                    <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" state="on" borderStyle="border" inset="2" id="15" customClass="ClickHoldButtonCell">
-                        <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                        <font key="font" metaFont="system"/>
-                    </buttonCell>
-                    <connections>
-                        <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="138"/>
-                    </connections>
-                </button>
-                <button toolTip="^IDS_TOOLTIP_FORWARD" tag="33001" id="7" customClass="MenuButton">
-                    <rect key="frame" x="31" y="4" width="29" height="29"/>
-                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
-                    <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" state="on" borderStyle="border" inset="2" id="10" customClass="ClickHoldButtonCell">
-                        <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                        <font key="font" metaFont="system"/>
-                    </buttonCell>
-                    <connections>
-                        <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="139"/>
-                    </connections>
-                </button>
-                <button toolTip="^IDS_TOOLTIP_RELOAD" tag="33002" id="3" customClass="ReloadButtonCocoa">
-                    <rect key="frame" x="59" y="4" width="29" height="29"/>
-                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
-                    <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" borderStyle="border" inset="2" id="14" customClass="ClickHoldButtonCell">
-                        <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                        <font key="font" metaFont="system"/>
-                    </buttonCell>
-                    <connections>
-                        <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="26"/>
-                    </connections>
-                </button>
-                <button toolTip="^IDS_TOOLTIP_HOME" tag="33003" id="8" customClass="ToolbarButtonCocoa">
-                    <rect key="frame" x="87" y="4" width="29" height="29"/>
-                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
-                    <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" borderStyle="border" inset="2" id="9" customClass="ClickHoldButtonCell">
-                        <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                        <font key="font" metaFont="system"/>
-                    </buttonCell>
-                    <connections>
-                        <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="155"/>
-                    </connections>
-                </button>
-                <textField focusRingType="exterior" verticalHuggingPriority="750" tag="33004" id="4">
-                    <rect key="frame" x="119" y="4" width="454" height="29"/>
-                    <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
-                    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="exterior" alignment="left" drawsBackground="YES" id="13">
-                        <font key="font" metaFont="system"/>
-                        <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
-                        <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
-                    </textFieldCell>
-                    <connections>
-                        <action selector="commandDispatch:" target="-1" id="24"/>
-                    </connections>
-                </textField>
-                <customView hidden="YES" id="144" userLabel="Browser Actions Container">
-                    <rect key="frame" x="572" y="4" width="0.0" height="29"/>
-                    <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
-                </customView>
-            </subviews>
-        </customView>
-        <customObject id="122" customClass="ChromeUILocalizer">
-            <connections>
-                <outlet property="owner_" destination="-2" id="123"/>
-            </connections>
-        </customObject>
-        <userDefaultsController representsSharedInstance="YES" id="130"/>
-    </objects>
-</document>
diff --git a/chrome/browser/android/explore_sites/explore_sites_bridge.cc b/chrome/browser/android/explore_sites/explore_sites_bridge.cc
index 7da43f5..1861e62 100644
--- a/chrome/browser/android/explore_sites/explore_sites_bridge.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_bridge.cc
@@ -18,6 +18,7 @@
 #include "jni/ExploreSitesBridge_jni.h"
 #include "jni/ExploreSitesCategory_jni.h"
 #include "jni/ExploreSitesSite_jni.h"
+#include "ui/gfx/android/java_bitmap.h"
 
 namespace explore_sites {
 using base::android::ConvertUTF8ToJavaString;
@@ -51,6 +52,19 @@
   base::android::RunObjectCallbackAndroid(j_callback_obj, j_result_obj);
 }
 
+void ImageReady(ScopedJavaGlobalRef<jobject>(j_callback_obj),
+                std::unique_ptr<SkBitmap> bitmap) {
+  if (!bitmap) {
+    DVLOG(1) << "Site icon is empty.";
+    base::android::RunObjectCallbackAndroid(j_callback_obj, nullptr);
+    return;
+  }
+
+  ScopedJavaLocalRef<jobject> j_bitmap = gfx::ConvertToJavaBitmap(bitmap.get());
+
+  base::android::RunObjectCallbackAndroid(j_callback_obj, j_bitmap);
+}
+
 }  // namespace
 
 // static
@@ -83,4 +97,27 @@
       chrome::android::explore_sites::GetExploreSitesVariation());
 }
 
+// static
+void JNI_ExploreSitesBridge_GetIcon(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& j_caller,
+    const JavaParamRef<jobject>& j_profile,
+    const jint j_site_id,
+    const JavaParamRef<jobject>& j_callback_obj) {
+  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
+  DCHECK(profile);
+
+  ExploreSitesService* service =
+      ExploreSitesServiceFactory::GetForBrowserContext(profile);
+  if (!service) {
+    DLOG(ERROR) << "Unable to create the ExploreSitesService!";
+    base::android::RunObjectCallbackAndroid(j_callback_obj, nullptr);
+    return;
+  }
+  int site_id = static_cast<int>(j_site_id);
+
+  service->GetSiteImage(
+      site_id, base::BindOnce(&ImageReady,
+                              ScopedJavaGlobalRef<jobject>(j_callback_obj)));
+}
 }  // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
index 06daed0..fc17f08 100644
--- a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/android/explore_sites/explore_sites_service_impl.h"
 
+#include "base/task/post_task.h"
 #include "chrome/browser/android/explore_sites/catalog.pb.h"
 #include "chrome/browser/android/explore_sites/explore_sites_feature.h"
 #include "chrome/browser/android/explore_sites/explore_sites_store.h"
@@ -11,6 +12,12 @@
 #include "chrome/browser/android/explore_sites/get_images_task.h"
 #include "chrome/browser/android/explore_sites/import_catalog_task.h"
 #include "components/offline_pages/task/task.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/data_decoder/public/cpp/decode_image.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/size.h"
 
 using chrome::android::explore_sites::ExploreSitesVariation;
 using chrome::android::explore_sites::GetExploreSitesVariation;
@@ -20,12 +27,6 @@
 const int kFaviconsPerCategoryImage = 4;
 }
 
-void DecodeImageBytes(BitmapCallback callback, EncodedImageList images) {
-  // TODO(freedjm): implement image decode.
-  NOTIMPLEMENTED();
-  std::move(callback).Run(nullptr);
-}
-
 ExploreSitesServiceImpl::ExploreSitesServiceImpl(
     std::unique_ptr<ExploreSitesStore> store)
     : task_queue_(this), explore_sites_store_(std::move(store)) {}
@@ -49,7 +50,8 @@
                                                BitmapCallback callback) {
   task_queue_.AddTask(std::make_unique<GetImagesTask>(
       explore_sites_store_.get(), category_id, kFaviconsPerCategoryImage,
-      base::BindOnce(&DecodeImageBytes, std::move(callback))));
+      base::BindOnce(&ExploreSitesServiceImpl::DecodeImageBytes,
+                     std::move(callback))));
   // TODO(dewittj, freedjm): implement.
   std::move(callback).Run(nullptr);
 }
@@ -58,7 +60,8 @@
                                            BitmapCallback callback) {
   task_queue_.AddTask(std::make_unique<GetImagesTask>(
       explore_sites_store_.get(), site_id,
-      base::BindOnce(&DecodeImageBytes, std::move(callback))));
+      base::BindOnce(&ExploreSitesServiceImpl::DecodeImageBytes,
+                     std::move(callback))));
 }
 
 void ExploreSitesServiceImpl::Shutdown() {}
@@ -75,4 +78,32 @@
       explore_sites_store_.get(), version_token, std::move(catalog_proto)));
 }
 
+// static
+void ExploreSitesServiceImpl::OnDecodeDone(BitmapCallback callback,
+                                           const SkBitmap& decoded_image) {
+  std::unique_ptr<SkBitmap> bitmap = std::make_unique<SkBitmap>(decoded_image);
+  std::move(callback).Run(std::move(bitmap));
+}
+
+// static
+void ExploreSitesServiceImpl::DecodeImageBytes(BitmapCallback callback,
+                                               EncodedImageList images) {
+  // TODO(freedjm) Fix to handle multiple images when support is added for
+  // creating composite images for the NTP tiles.
+  DCHECK(images.size() > 0);
+  std::unique_ptr<EncodedImageBytes> image_data = std::move(images[0]);
+
+  service_manager::mojom::ConnectorRequest connector_request;
+  std::unique_ptr<service_manager::Connector> connector =
+      service_manager::Connector::Create(&connector_request);
+  content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->BindConnectorRequest(std::move(connector_request));
+
+  data_decoder::DecodeImage(connector.get(), *image_data,
+                            data_decoder::mojom::ImageCodec::DEFAULT, false,
+                            data_decoder::kDefaultMaxSizeInBytes, gfx::Size(),
+                            base::BindOnce(&OnDecodeDone, std::move(callback)));
+}
+
 }  // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.h b/chrome/browser/android/explore_sites/explore_sites_service_impl.h
index 003f5256..827de0c 100644
--- a/chrome/browser/android/explore_sites/explore_sites_service_impl.h
+++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.h
@@ -41,6 +41,11 @@
   void AddUpdatedCatalog(std::string version_token,
                          std::unique_ptr<Catalog> catalog_proto);
 
+  static void OnDecodeDone(BitmapCallback callback,
+                           const SkBitmap& decoded_image);
+  static void DecodeImageBytes(BitmapCallback callback,
+                               EncodedImageList images);
+
   // True when Chrome starts up, this is reset after the catalog is requested
   // the first time in Chrome. This prevents the ESP from changing out from
   // under a viewer.
diff --git a/chrome/browser/autofill/risk_util.cc b/chrome/browser/autofill/risk_util.cc
index 75db7b3..c9a271b9 100644
--- a/chrome/browser/autofill/risk_util.cc
+++ b/chrome/browser/autofill/risk_util.cc
@@ -38,12 +38,12 @@
 
 namespace {
 
-void PassRiskData(const base::Callback<void(const std::string&)>& callback,
+void PassRiskData(base::OnceCallback<void(const std::string&)> callback,
                   std::unique_ptr<risk::Fingerprint> fingerprint) {
   std::string proto_data, risk_data;
   fingerprint->SerializeToString(&proto_data);
   base::Base64Encode(proto_data, &risk_data);
-  callback.Run(risk_data);
+  std::move(callback).Run(risk_data);
 }
 
 #if !defined(OS_ANDROID)
@@ -66,10 +66,9 @@
 
 }  // namespace
 
-void LoadRiskData(
-    uint64_t obfuscated_gaia_id,
-    content::WebContents* web_contents,
-    const base::RepeatingCallback<void(const std::string&)>& callback) {
+void LoadRiskData(uint64_t obfuscated_gaia_id,
+                  content::WebContents* web_contents,
+                  base::OnceCallback<void(const std::string&)> callback) {
   // No easy way to get window bounds on Android, and that signal isn't very
   // useful anyway (given that we're also including the bounds of the web
   // contents).
@@ -96,7 +95,7 @@
       obfuscated_gaia_id, window_bounds, web_contents,
       version_info::GetVersionNumber(), charset, accept_languages, install_time,
       g_browser_process->GetApplicationLocale(), GetUserAgent(),
-      base::Bind(PassRiskData, callback), connector);
+      base::BindOnce(PassRiskData, std::move(callback)), connector);
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/autofill/risk_util.h b/chrome/browser/autofill/risk_util.h
index 32d38c0..e462a38 100644
--- a/chrome/browser/autofill/risk_util.h
+++ b/chrome/browser/autofill/risk_util.h
@@ -22,10 +22,9 @@
 // process if provided. |web_contents| is used during fingerprinting as well,
 // when retrieving user prefs, and in determining window bounds when not on
 // Android.
-void LoadRiskData(
-    uint64_t obfuscated_gaia_id,
-    content::WebContents* web_contents,
-    const base::RepeatingCallback<void(const std::string&)>& callback);
+void LoadRiskData(uint64_t obfuscated_gaia_id,
+                  content::WebContents* web_contents,
+                  base::OnceCallback<void(const std::string&)> callback);
 
 }  // namespace autofill
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 288ee38..011d8bb 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1586,6 +1586,12 @@
     "power/auto_screen_brightness/fake_als_reader.h",
     "power/auto_screen_brightness/fake_brightness_monitor.cc",
     "power/auto_screen_brightness/fake_brightness_monitor.h",
+    "power/auto_screen_brightness/modeller.h",
+    "power/auto_screen_brightness/modeller_impl.cc",
+    "power/auto_screen_brightness/modeller_impl.h",
+    "power/auto_screen_brightness/trainer.h",
+    "power/auto_screen_brightness/utils.cc",
+    "power/auto_screen_brightness/utils.h",
     "power/cpu_data_collector.cc",
     "power/cpu_data_collector.h",
     "power/extension_event_observer.cc",
@@ -2260,6 +2266,8 @@
     "policy/weekly_time/weekly_time_unittest.cc",
     "power/auto_screen_brightness/als_reader_impl_unittest.cc",
     "power/auto_screen_brightness/brightness_monitor_impl_unittest.cc",
+    "power/auto_screen_brightness/modeller_impl_unittest.cc",
+    "power/auto_screen_brightness/utils_unittest.cc",
     "power/cpu_data_collector_unittest.cc",
     "power/extension_event_observer_unittest.cc",
     "power/ml/adaptive_screen_brightness_manager_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
index 9d247972..d5b85cb 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
+++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
@@ -632,6 +632,11 @@
                                  class_name);
   }
 
+  if (!GetProperty(node, AXBooleanProperty::IMPORTANCE)) {
+    out_data->role = ax::mojom::Role::kIgnored;
+    return;
+  }
+
   if (GetProperty(node, AXBooleanProperty::EDITABLE)) {
     out_data->role = ax::mojom::Role::kTextField;
     return;
diff --git a/chrome/browser/chromeos/events/event_rewriter_unittest.cc b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
index a37e246..7f190b7 100644
--- a/chrome/browser/chromeos/events/event_rewriter_unittest.cc
+++ b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
@@ -310,8 +310,7 @@
       ui::INPUT_DEVICE_INTERNAL);
   rewriter_->KeyboardDeviceAddedForTesting(
       kKeyboardDeviceId + 1, "External Keyboard",
-      ui::EventRewriterChromeOS::kKbdTopRowLayoutDefault,
-      ui::INPUT_DEVICE_EXTERNAL);
+      ui::EventRewriterChromeOS::kKbdTopRowLayoutDefault, ui::INPUT_DEVICE_USB);
 
   // The Meta key on both external and internal keyboards should produce Search.
 
diff --git a/chrome/browser/chromeos/input_method/accessibility.cc b/chrome/browser/chromeos/input_method/accessibility.cc
index 2df2614..992dbe43 100644
--- a/chrome/browser/chromeos/input_method/accessibility.cc
+++ b/chrome/browser/chromeos/input_method/accessibility.cc
@@ -37,7 +37,7 @@
   const std::string medium_name = base::UTF16ToUTF8(
       imm_->GetInputMethodUtil()->GetInputMethodMediumName(descriptor));
 
-  AutomationManagerAura::GetInstance()->HandleAlert(profile, medium_name);
+  AutomationManagerAura::GetInstance()->HandleAlert(medium_name);
 }
 
 }  // namespace input_method
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index a0b95bb81..6f5c64b 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -1528,8 +1528,7 @@
 
 void ExistingUserController::SendAccessibilityAlert(
     const std::string& alert_text) {
-  AutomationManagerAura::GetInstance()->HandleAlert(
-      ProfileHelper::GetSigninProfile(), alert_text);
+  AutomationManagerAura::GetInstance()->HandleAlert(alert_text);
 }
 
 void ExistingUserController::SetPublicSessionKeyboardLayoutAndLogin(
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
index f7c64bd4..38962535 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
@@ -34,6 +34,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/test/ui_controls.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/compositor/layer_animator.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/views/widget/widget.h"
@@ -150,6 +151,11 @@
 };
 
 IN_PROC_BROWSER_TEST_F(WebUiScreenLockerTest, TestBasic) {
+  // WebUiScreenLockerTest fails with Mash because of unexpected window
+  // structure. Fortunately we will deprecate the WebUI-based screen locker
+  // soon, so it is okay to skip it.  See https://crbug.com/888779
+  if (features::IsUsingWindowService())
+    return;
   ScreenLocker::Show();
   std::unique_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
   tester->EmulateWindowManagerReady();
@@ -199,6 +205,11 @@
 
 // Test how locking the screen affects an active fullscreen window.
 IN_PROC_BROWSER_TEST_F(WebUiScreenLockerTest, TestFullscreenExit) {
+  // WebUiScreenLockerTest fails with Mash because of unexpected window
+  // structure. Fortunately we will deprecate the WebUI-based screen locker
+  // soon, so it is okay to skip it.  See https://crbug.com/888779
+  if (features::IsUsingWindowService())
+    return;
   // 1) If the active browser window is in fullscreen and the fullscreen window
   // does not have all the pixels (e.g. the shelf is auto hidden instead of
   // hidden), locking the screen should not exit fullscreen. The shelf is
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h b/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h
index d5f8b1f..cd3e54b 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h
@@ -32,9 +32,10 @@
   static constexpr int kMaxInitialAttempts = 20;
 
   // Interval for polling ambient light values.
-  // TODO(jiameng): revise frequency.
+  // TODO(jiameng): currently poll ALS samples every 250ms. May revise.
+  static constexpr int kNumberAlsPollPerSeconds = 4;
   static constexpr base::TimeDelta kAlsPollInterval =
-      base::TimeDelta::FromSeconds(1);
+      base::TimeDelta::FromSecondsD(1.0 / kNumberAlsPollPerSeconds);
 
   AlsReaderImpl();
   ~AlsReaderImpl() override;
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h b/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h
new file mode 100644
index 0000000..b61fada1
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h
@@ -0,0 +1,59 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_H_
+#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_H_
+
+#include "base/observer_list_types.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+// Interface to on-device adaptive model.
+class Modeller {
+ public:
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class Status {
+    kInitializing = 0,
+    kDisabled = 1,
+    kGlobal = 2,
+    kPersonal = 3,
+    kMaxValue = kPersonal
+  };
+
+  // Modeller must outlive its observers.
+  class Observer : public base::CheckedObserver {
+   public:
+    Observer() = default;
+    ~Observer() override = default;
+
+    // Called when a new curve (|brightness_curve|) is trained.
+    virtual void OnModelTrained(const BrightnessCurve& brightness_curve) = 0;
+
+    // Called when the model is initialized. Observers will be notified about
+    // both model status and initial curve (|brightness_curve|). If model status
+    // is |kDisabled|, the |brightness_curve| will be empty.
+    virtual void OnModelInitialized(
+        Status model_status,
+        const BrightnessCurve& brightness_curve) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Observer);
+  };
+
+  virtual ~Modeller() = default;
+
+  // Adds or removes an observer.
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(Observer* observer) = 0;
+};
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
new file mode 100644
index 0000000..071bac68
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
@@ -0,0 +1,341 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h"
+
+#include <cmath>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/task/post_task.h"
+#include "base/task_runner_util.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+namespace {
+// Loads data from a specified location on disk. This should run in another
+// thread to be non-blocking to the main thread (if |is_testing| is false).
+std::string LoadDataFromDisk(const base::FilePath& path, bool is_testing) {
+  DCHECK(is_testing ||
+         !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  if (!PathExists(path)) {
+    return "";
+  }
+
+  std::string content;
+  if (!base::ReadFileToString(path, &content)) {
+    return "";
+  }
+  return content;
+}
+
+// Saves data to disk. This should run in another thread to be non-blocking to
+// the main thread (if |is_testing| is false).
+// TODO(jiameng): alternative to WriteFile is WriteFileAtomically, but the
+// latter is very slow. Investigate whether we need to change to
+// WriteFileAtomically.
+void SaveCurveToDisk(const base::FilePath& path,
+                     const BrightnessCurve& curve,
+                     bool is_testing) {
+  DCHECK(is_testing ||
+         !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  const std::string data = CurveToString(curve);
+  const int bytes_written = base::WriteFile(path, data.data(), data.size());
+  if (bytes_written != static_cast<int>(data.size())) {
+    LOG(ERROR) << "Wrote " << bytes_written << " byte(s) instead of "
+               << data.size() << " to " << path.value();
+  }
+}
+
+// Trains a new curve using the current |curve| and training |data|. Returns the
+// new curve. This should run in another thread to be non-blocking to the main
+// thread (if |is_testing| is false).
+BrightnessCurve TrainModel(Trainer* trainer,
+                           const BrightnessCurve& curve,
+                           const std::vector<TrainingDataPoint>& data,
+                           bool is_testing) {
+  DCHECK(is_testing ||
+         !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  return trainer->Train(curve, data);
+}
+
+}  // namespace
+
+constexpr base::TimeDelta ModellerImpl::kTrainingDelay;
+constexpr int ModellerImpl::kMaxTrainingDataPoints;
+constexpr int ModellerImpl::kAmbientLightHorizonSeconds;
+constexpr base::TimeDelta ModellerImpl::kAmbientLightHorizon;
+constexpr int ModellerImpl::kNumberAmbientValuesToTrack;
+constexpr char ModellerImpl::kModelDir[];
+constexpr char ModellerImpl::kCurveFileName[];
+
+ModellerImpl::ModellerImpl(Profile* profile,
+                           AlsReader* als_reader,
+                           BrightnessMonitor* brightness_monitor,
+                           ui::UserActivityDetector* user_activity_detector,
+                           std::unique_ptr<Trainer> trainer)
+    : ModellerImpl(profile,
+                   als_reader,
+                   brightness_monitor,
+                   user_activity_detector,
+                   std::move(trainer),
+                   base::CreateSequencedTaskRunnerWithTraits(
+                       {base::TaskPriority::BEST_EFFORT, base::MayBlock(),
+                        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}),
+                   base::DefaultTickClock::GetInstance()) {}
+
+ModellerImpl::~ModellerImpl() = default;
+
+void ModellerImpl::AddObserver(Modeller::Observer* observer) {
+  DCHECK(observer);
+  observers_.AddObserver(observer);
+  if (model_status_ != Modeller::Status::kInitializing) {
+    observer->OnModelInitialized(model_status_, curve_);
+  }
+}
+
+void ModellerImpl::RemoveObserver(Modeller::Observer* observer) {
+  DCHECK(observer);
+  observers_.RemoveObserver(observer);
+}
+
+void ModellerImpl::OnAmbientLightUpdated(int lux) {
+  if (model_status_ == Status::kDisabled)
+    return;
+
+  const AmbientLightSample sample = {lux, tick_clock_->NowTicks()};
+  ambient_light_values_.SaveToBuffer(sample);
+}
+
+void ModellerImpl::OnAlsReaderInitialized(AlsReader::AlsInitStatus status) {
+  if (als_init_status_.has_value())
+    return;
+
+  als_init_status_ = status;
+
+  HandleStatusUpdate();
+}
+
+void ModellerImpl::OnBrightnessMonitorInitialized(bool success) {
+  if (brightness_monitor_success_.has_value())
+    return;
+
+  brightness_monitor_success_ = success;
+  HandleStatusUpdate();
+}
+
+void ModellerImpl::OnUserBrightnessChanged(double old_brightness_percent,
+                                           double new_brightness_percent) {
+  if (model_status_ == Status::kDisabled)
+    return;
+
+  // We don't add any training data if there is no ambient light sample.
+  if (ambient_light_values_.CurrentIndex() == 0)
+    return;
+
+  const double average_ambient_lux = AverageAmbient(ambient_light_values_, -1);
+  data_cache_.push_back({old_brightness_percent, new_brightness_percent,
+                         average_ambient_lux, tick_clock_->NowTicks()});
+
+  if (data_cache_.size() == kMaxTrainingDataPoints) {
+    model_timer_.Stop();
+    StartTraining();
+  }
+}
+
+void ModellerImpl::OnUserBrightnessChangeRequested() {}
+
+void ModellerImpl::OnUserActivity(const ui::Event* event) {
+  if (!event)
+    return;
+  ScheduleTrainerStart();
+}
+
+std::unique_ptr<ModellerImpl> ModellerImpl::CreateForTesting(
+    Profile* profile,
+    AlsReader* als_reader,
+    BrightnessMonitor* brightness_monitor,
+    ui::UserActivityDetector* user_activity_detector,
+    std::unique_ptr<Trainer> trainer,
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    const base::TickClock* tick_clock) {
+  return base::WrapUnique(new ModellerImpl(
+      profile, als_reader, brightness_monitor, user_activity_detector,
+      std::move(trainer), task_runner, tick_clock, true /* is_testing */));
+}
+
+double ModellerImpl::AverageAmbientForTesting() const {
+  return AverageAmbient(ambient_light_values_, -1);
+}
+
+int ModellerImpl::NumberTrainingDataPointsForTesting() const {
+  return data_cache_.size();
+}
+
+base::FilePath ModellerImpl::GetCurvePathForTesting(Profile* profile) const {
+  return GetCurvePathFromProfile(profile);
+}
+
+ModellerImpl::ModellerImpl(
+    Profile* profile,
+    AlsReader* als_reader,
+    BrightnessMonitor* brightness_monitor,
+    ui::UserActivityDetector* user_activity_detector,
+    std::unique_ptr<Trainer> trainer,
+    const scoped_refptr<base::SequencedTaskRunner> task_runner,
+    const base::TickClock* tick_clock,
+    bool is_testing)
+    : is_testing_(is_testing),
+      als_reader_observer_(this),
+      brightness_monitor_observer_(this),
+      user_activity_observer_(this),
+      model_task_runner_(task_runner),
+      trainer_(trainer.release(),
+               base::OnTaskRunnerDeleter(model_task_runner_)),
+      tick_clock_(tick_clock),
+      model_timer_(tick_clock_),
+      weak_ptr_factory_(this) {
+  DCHECK(als_reader);
+  DCHECK(brightness_monitor);
+  DCHECK(trainer_);
+  DCHECK(user_activity_detector);
+
+  if (!profile) {
+    model_status_ = Status::kDisabled;
+    return;
+  }
+
+  curve_path_ = GetCurvePathFromProfile(profile);
+  if (curve_path_.empty()) {
+    model_status_ = Status::kDisabled;
+    return;
+  }
+
+  model_timer_.SetTaskRunner(model_task_runner_);
+
+  als_reader_observer_.Add(als_reader);
+  brightness_monitor_observer_.Add(brightness_monitor);
+  user_activity_observer_.Add(user_activity_detector);
+}
+
+base::FilePath ModellerImpl::GetCurvePathFromProfile(Profile* profile) const {
+  DCHECK(profile);
+  const base::FilePath empty_path;
+
+  const base::FilePath profile_path = profile->GetPath();
+  if (profile_path.empty()) {
+    return empty_path;
+  }
+
+  const base::FilePath model_dir = profile_path.Append(kModelDir);
+  if (!base::DirectoryExists(model_dir) && !base::CreateDirectory(model_dir)) {
+    return empty_path;
+  }
+
+  return model_dir.Append(kCurveFileName);
+}
+
+void ModellerImpl::HandleStatusUpdate() {
+  if (model_status_ != Modeller::Status::kInitializing)
+    return;
+
+  if (!als_init_status_.has_value()) {
+    return;
+  }
+  const bool als_success =
+      als_init_status_.value() == AlsReader::AlsInitStatus::kSuccess;
+  if (!als_success) {
+    model_status_ = Modeller::Status::kDisabled;
+    OnInitializationComplete();
+    return;
+  }
+
+  if (!brightness_monitor_success_.has_value()) {
+    return;
+  }
+  if (!brightness_monitor_success_.value()) {
+    model_status_ = Modeller::Status::kDisabled;
+    OnInitializationComplete();
+    return;
+  }
+
+  base::PostTaskAndReplyWithResult(
+      model_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&LoadDataFromDisk, curve_path_, is_testing_),
+      base::BindOnce(&ModellerImpl::OnCurveLoadedFromDisk,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ModellerImpl::OnInitializationComplete() {
+  DCHECK_NE(model_status_, Status::kInitializing);
+  for (auto& observer : observers_)
+    observer.OnModelInitialized(model_status_, curve_);
+}
+
+// TODO(crbug.com/881215): add actual default curve and then add unit test too.
+void ModellerImpl::InitWithDefaultCurve() {
+  curve_.clear();
+  return;
+}
+
+void ModellerImpl::OnCurveLoadedFromDisk(const std::string& content) {
+  if (content.empty() || !CurveFromString(content, &curve_)) {
+    InitWithDefaultCurve();
+    model_status_ = Status::kGlobal;
+  } else {
+    model_status_ = Status::kPersonal;
+  }
+
+  OnInitializationComplete();
+
+  ScheduleTrainerStart();
+}
+
+void ModellerImpl::ScheduleTrainerStart() {
+  // Reset the timer if it's already running.
+  model_timer_.Start(FROM_HERE, kTrainingDelay, this,
+                     &ModellerImpl::StartTraining);
+}
+
+void ModellerImpl::StartTraining() {
+  if (data_cache_.empty()) {
+    ScheduleTrainerStart();
+    return;
+  }
+
+  base::PostTaskAndReplyWithResult(
+      model_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&TrainModel, trainer_.get(), curve_,
+                     std::move(data_cache_), is_testing_),
+      base::BindOnce(&ModellerImpl::OnTrainingFinished,
+                     weak_ptr_factory_.GetWeakPtr()));
+  data_cache_.clear();
+}
+
+void ModellerImpl::OnTrainingFinished(const BrightnessCurve& curve) {
+  curve_ = curve;
+  for (auto& observer : observers_)
+    observer.OnModelTrained(curve);
+
+  model_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&SaveCurveToDisk, curve_path_, curve_, is_testing_));
+  ScheduleTrainerStart();
+}
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h
new file mode 100644
index 0000000..50d3a16
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h
@@ -0,0 +1,204 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_
+
+#include <memory>
+
+#include "base/containers/ring_buffer.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/scoped_observer.h"
+#include "base/sequenced_task_runner.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
+#include "chrome/browser/profiles/profile.h"
+#include "ui/base/user_activity/user_activity_detector.h"
+#include "ui/base/user_activity/user_activity_observer.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+// Real implementation of Modeller.
+// It monitors user-requested brightness changes, ambient light values and
+// trains personal brightness curves when user remains idle for a period of
+// time.
+class ModellerImpl : public Modeller,
+                     public AlsReader::Observer,
+                     public BrightnessMonitor::Observer,
+                     public ui::UserActivityObserver {
+ public:
+  // Once user remains idle for |kTrainingDelay|, we start training the model.
+  static constexpr base::TimeDelta kTrainingDelay =
+      base::TimeDelta::FromSeconds(60);
+
+  // If number of recorded training data has reached |kMaxTrainingDataPoints| we
+  // start training immediately, without waiting for user to become idle for
+  // |kTrainingDelay|.
+  static constexpr int kMaxTrainingDataPoints = 100;
+
+  // TODO(jiameng): we currently use past 10 seconds of ambient values to
+  // calculate average. May revise.
+  static constexpr int kAmbientLightHorizonSeconds = 10;
+  static constexpr base::TimeDelta kAmbientLightHorizon =
+      base::TimeDelta::FromSeconds(kAmbientLightHorizonSeconds);
+
+  // Size of |data_cache_|.
+  static constexpr int kNumberAmbientValuesToTrack =
+      kAmbientLightHorizonSeconds * AlsReaderImpl::kNumberAlsPollPerSeconds;
+
+  static constexpr char kModelDir[] = "autobrightness";
+  static constexpr char kCurveFileName[] = "curve";
+
+  // ModellerImpl has weak dependencies on all parameters except |trainer|.
+  ModellerImpl(Profile* profile,
+               AlsReader* als_reader,
+               BrightnessMonitor* brightness_monitor,
+               ui::UserActivityDetector* user_activity_detector,
+               std::unique_ptr<Trainer> trainer);
+  ~ModellerImpl() override;
+
+  // Modeller overrides:
+  void AddObserver(Modeller::Observer* observer) override;
+  void RemoveObserver(Modeller::Observer* observer) override;
+
+  // AlsReader::Observer overrides:
+  void OnAmbientLightUpdated(int lux) override;
+  void OnAlsReaderInitialized(AlsReader::AlsInitStatus status) override;
+
+  // BrightnessMonitor::Observer overrides:
+  void OnBrightnessMonitorInitialized(bool success) override;
+  void OnUserBrightnessChanged(double old_brightness_percent,
+                               double new_brightness_percent) override;
+  void OnUserBrightnessChangeRequested() override;
+
+  // ui::UserActivityObserver overrides:
+  void OnUserActivity(const ui::Event* event) override;
+
+  // ModellerImpl has weak dependencies on all parameters except |trainer|.
+  static std::unique_ptr<ModellerImpl> CreateForTesting(
+      Profile* profile,
+      AlsReader* als_reader,
+      BrightnessMonitor* brightness_monitor,
+      ui::UserActivityDetector* user_activity_detector,
+      std::unique_ptr<Trainer> trainer,
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
+      const base::TickClock* tick_clock);
+
+  // Current average ambient light.
+  double AverageAmbientForTesting() const;
+
+  // Current number of training data points stored, which will be used for next
+  // training.
+  int NumberTrainingDataPointsForTesting() const;
+
+  // Calls GetCurvePathFromProfile directly.
+  base::FilePath GetCurvePathForTesting(Profile* profile) const;
+
+ private:
+  // ModellerImpl has weak dependencies on all parameters except |trainer|.
+  ModellerImpl(Profile* profile,
+               AlsReader* als_reader,
+               BrightnessMonitor* brightness_monitor,
+               ui::UserActivityDetector* user_activity_detector,
+               std::unique_ptr<Trainer> trainer,
+               scoped_refptr<base::SequencedTaskRunner> task_runner,
+               const base::TickClock* tick_clock,
+               bool is_testing = false);
+
+  // Returns the path that will be used to store curves. It also creates
+  // intermediate directories if they do not exist. Returns an empty path on
+  // failures.
+  base::FilePath GetCurvePathFromProfile(Profile* profile) const;
+
+  // Updates |model_status_| by checking |als_init_status_| and
+  // |brightness_monitor_status_| and optionally loads a curve.
+  // 1. |model_status_| is |kDisabled| if either |als_init_status_| is not
+  // |kSuccess|, or |brightness_monitor_success_| is false. The modeller will
+  // notify its observers as soon as |model_status_| is |kDisabled|.
+  // 2. If |als_init_status_| is |kSuccess| and |brightness_monitor_success_| is
+  // true, then this method loads a curve from the disk and sets |model_status_|
+  // to |kPersonal|. If no curve is found from the disk a default curve will be
+  // created and |model_status_| is set to |kGlobal|. All observers will be
+  // notified about the status and the curve.
+  void HandleStatusUpdate();
+
+  // Notifies its observers on the status of the model. It will be called either
+  // when HandleStatusUpdate is called and |model_status_| is no longer
+  // |kInitializing|, or when an observer is added to the modeller, and
+  // |model_status_| is not |kInitializing|.
+  void OnInitializationComplete();
+
+  // Called when there is no saved curve from the disk.
+  void InitWithDefaultCurve();
+
+  // Called after reading from disk is complete. |content| may be empty, in that
+  // case we'll construct a default curve.
+  void OnCurveLoadedFromDisk(const std::string& content);
+
+  // Starts |model_timer_| to start training after certain inactivity period.
+  void ScheduleTrainerStart();
+
+  // Starts model training and runs it in non UI thread. Also clears
+  // |data_cache_|.
+  void StartTraining();
+
+  // Called after training is complete with a new curve.
+  void OnTrainingFinished(const BrightnessCurve& curve);
+
+  // If |is_testing_| is false, we check curve saving/loading and training jobs
+  // are running on non-UI thread.
+  const bool is_testing_ = false;
+
+  ScopedObserver<AlsReader, AlsReader::Observer> als_reader_observer_;
+
+  ScopedObserver<BrightnessMonitor, BrightnessMonitor::Observer>
+      brightness_monitor_observer_;
+
+  ScopedObserver<ui::UserActivityDetector, ui::UserActivityObserver>
+      user_activity_observer_;
+
+  scoped_refptr<base::SequencedTaskRunner> model_task_runner_;
+  std::unique_ptr<Trainer, base::OnTaskRunnerDeleter> trainer_;
+
+  // This will be replaced by a mock tick clock during tests.
+  const base::TickClock* const tick_clock_;
+
+  base::OneShotTimer model_timer_;
+
+  base::Optional<AlsReader::AlsInitStatus> als_init_status_;
+  base::Optional<bool> brightness_monitor_success_;
+  Status model_status_ = Status::kInitializing;
+
+  base::FilePath curve_path_;
+
+  // Latest trained curve.
+  BrightnessCurve curve_;
+
+  // Recent |kNumberAmbientValuesToTrack| ambient values.
+  base::RingBuffer<AmbientLightSample, kNumberAmbientValuesToTrack>
+      ambient_light_values_;
+
+  std::vector<TrainingDataPoint> data_cache_;
+
+  base::ObserverList<Modeller::Observer> observers_;
+
+  base::WeakPtrFactory<ModellerImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ModellerImpl);
+};
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
new file mode 100644
index 0000000..b84454c
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
@@ -0,0 +1,391 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/fake_als_reader.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/fake_brightness_monitor.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/user_activity/user_activity_detector.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+namespace {
+
+void CompareBrightnessCurve(const BrightnessCurve& expected,
+                            const BrightnessCurve& actual) {
+  EXPECT_EQ(expected.size(), actual.size());
+  for (size_t i = 0; i < expected.size(); ++i) {
+    EXPECT_DOUBLE_EQ(expected[i].first, actual[i].first);
+    EXPECT_DOUBLE_EQ(expected[i].second, actual[i].second);
+  }
+}
+
+std::pair<double, double> DataToCurvePoint(const TrainingDataPoint& data) {
+  return std::make_pair(data.ambient_lux,
+                        (data.brightness_old + data.brightness_new) / 2);
+}
+
+// Testing trainer.
+class FakeTrainer : public Trainer {
+ public:
+  FakeTrainer() = default;
+  ~FakeTrainer() override = default;
+
+  // Trainer overrides:
+  BrightnessCurve Train(const BrightnessCurve& /* curve */,
+                        const std::vector<TrainingDataPoint>& data) override {
+    BrightnessCurve result_curve;
+    for (const auto& training_data_point : data) {
+      result_curve.push_back(DataToCurvePoint(training_data_point));
+    }
+    return result_curve;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeTrainer);
+};
+
+class TestObserver : public Modeller::Observer {
+ public:
+  TestObserver() {}
+  ~TestObserver() override = default;
+
+  // Modeller::Observer overrides:
+  void OnModelTrained(const BrightnessCurve& brightness_curve) override {
+    brightness_curve_ = base::Optional<BrightnessCurve>(brightness_curve);
+  }
+
+  void OnModelInitialized(const Modeller::Status model_status,
+                          const BrightnessCurve& brightness_curve) override {
+    model_status_ = base::Optional<Modeller::Status>(model_status);
+    brightness_curve_ = base::Optional<BrightnessCurve>(brightness_curve);
+  }
+
+  Modeller::Status model_status() const {
+    DCHECK(model_status_.has_value());
+    return model_status_.value();
+  }
+
+  BrightnessCurve brightness_curve() const {
+    DCHECK(brightness_curve_.has_value());
+    return brightness_curve_.value();
+  }
+
+  bool HasModelStatus() { return model_status_.has_value(); }
+  bool HasBrightnessCurve() { return brightness_curve_.has_value(); }
+
+ private:
+  base::Optional<Modeller::Status> model_status_;
+  base::Optional<BrightnessCurve> brightness_curve_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestObserver);
+};
+
+}  // namespace
+
+class ModellerImplTest : public testing::Test {
+ public:
+  ModellerImplTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
+        thread_bundle_(content::TestBrowserThreadBundle::PLAIN_MAINLOOP) {
+    CHECK(temp_dir_.CreateUniqueTempDir());
+    TestingProfile::Builder profile_builder;
+    profile_builder.SetProfileName("testuser@gmail.com");
+    profile_builder.SetPath(temp_dir_.GetPath().AppendASCII("TestProfile"));
+    profile_ = profile_builder.Build();
+  }
+
+  ~ModellerImplTest() override {
+    base::TaskScheduler::GetInstance()->FlushForTesting();
+  }
+
+  void SetUpModeller() {
+    modeller_ = ModellerImpl::CreateForTesting(
+        profile_.get(), &fake_als_reader_, &fake_brightness_monitor_,
+        &user_activity_detector_, std::make_unique<FakeTrainer>(),
+        base::SequencedTaskRunnerHandle::Get(),
+        scoped_task_environment_.GetMockTickClock());
+
+    test_observer_ = std::make_unique<TestObserver>();
+    modeller_->AddObserver(test_observer_.get());
+  }
+
+ protected:
+  void WriteCurveToFile(const BrightnessCurve& curve) {
+    const base::FilePath curve_path =
+        modeller_->GetCurvePathForTesting(profile_.get());
+    CHECK(!curve_path.empty());
+
+    const std::string& data = CurveToString(curve);
+    const int bytes_written =
+        base::WriteFile(curve_path, data.data(), data.size());
+    ASSERT_EQ(bytes_written, static_cast<int>(data.size()))
+        << "Wrote " << bytes_written << " byte(s) instead of " << data.size()
+        << " to " << curve_path;
+  }
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  content::TestBrowserThreadBundle thread_bundle_;
+
+  ui::UserActivityDetector user_activity_detector_;
+
+  base::ScopedTempDir temp_dir_;
+  std::unique_ptr<TestingProfile> profile_;
+
+  FakeAlsReader fake_als_reader_;
+  FakeBrightnessMonitor fake_brightness_monitor_;
+
+  std::unique_ptr<ModellerImpl> modeller_;
+  std::unique_ptr<TestObserver> test_observer_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ModellerImplTest);
+};
+
+// AlsReader is |kDisabled| when Modeller is created.
+TEST_F(ModellerImplTest, AlsReaderDisabledOnInit) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kDisabled);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status());
+}
+
+// BrightnessMonitor is |kDisabled| when Modeller is created.
+TEST_F(ModellerImplTest, BrightnessMonitorDisabledOnInit) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kDisabled);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status());
+}
+
+// AlsReader is |kDisabled| on later notification.
+TEST_F(ModellerImplTest, AlsReaderDisabledOnNotification) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kInProgress);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_FALSE(test_observer_->HasModelStatus());
+  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kDisabled);
+  fake_als_reader_.ReportReaderInitialized();
+  EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status());
+}
+
+// AlsReader is |kSuccess| on later notification.
+TEST_F(ModellerImplTest, AlsReaderEnabledOnNotification) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kInProgress);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_FALSE(test_observer_->HasModelStatus());
+  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_als_reader_.ReportReaderInitialized();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(Modeller::Status::kGlobal, test_observer_->model_status());
+  EXPECT_TRUE(test_observer_->brightness_curve().empty());
+}
+
+// BrightnessMonitor is |kDisabled| on later notification.
+TEST_F(ModellerImplTest, BrightnessMonitorDisabledOnNotification) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kInitializing);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_FALSE(test_observer_->HasModelStatus());
+  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kDisabled);
+  fake_brightness_monitor_.ReportBrightnessMonitorInitialized();
+  EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status());
+}
+
+// BrightnessMonitor is |kSuccess| on later notification.
+TEST_F(ModellerImplTest, BrightnessMonitorEnabledOnNotification) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kInitializing);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_FALSE(test_observer_->HasModelStatus());
+  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  fake_brightness_monitor_.ReportBrightnessMonitorInitialized();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(Modeller::Status::kGlobal, test_observer_->model_status());
+  EXPECT_TRUE(test_observer_->brightness_curve().empty());
+}
+
+// There is no saved curve, hence a global curve is created.
+TEST_F(ModellerImplTest, NoSavedCurve) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(Modeller::Status::kGlobal, test_observer_->model_status());
+  EXPECT_TRUE(test_observer_->brightness_curve().empty());
+}
+
+// A curve is loaded from disk, this is a personal curve.
+TEST_F(ModellerImplTest, CurveLoadedFromProfilePath) {
+  const BrightnessCurve curve = {{10, 15}, {20, 25}, {30, 35}, {40, 45},
+                                 {50, 55}, {60, 65}, {70, 75}, {80, 85}};
+  WriteCurveToFile(curve);
+
+  scoped_task_environment_.RunUntilIdle();
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+
+  EXPECT_EQ(Modeller::Status::kPersonal, test_observer_->model_status());
+  EXPECT_EQ(curve, test_observer_->brightness_curve());
+}
+
+// Ambient light values are received. We check average ambient light has been
+// calculated from the past |kNumberAmbientValuesToTrack| samples only.
+TEST_F(ModellerImplTest, OnAmbientLightUpdated) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  ASSERT_EQ(Modeller::Status::kGlobal, test_observer_->model_status());
+
+  const int first_lux = 1000;
+  double running_sum = first_lux;
+  fake_als_reader_.ReportAmbientLightUpdate(first_lux);
+  for (int i = 1; i < ModellerImpl::kNumberAmbientValuesToTrack; ++i) {
+    const int lux = i;
+    fake_als_reader_.ReportAmbientLightUpdate(lux);
+    running_sum += lux;
+    EXPECT_DOUBLE_EQ(running_sum / (i + 1),
+                     modeller_->AverageAmbientForTesting());
+  }
+
+  // Add another one should push the oldest |first_lux| out of the horizon.
+  fake_als_reader_.ReportAmbientLightUpdate(100);
+  running_sum = running_sum + 100 - first_lux;
+  EXPECT_DOUBLE_EQ(running_sum / ModellerImpl::kNumberAmbientValuesToTrack,
+                   modeller_->AverageAmbientForTesting());
+}
+
+// User brightness changes are received, training example cache reaches
+// |kMaxTrainingDataPoints| to trigger early training. This all happens within a
+// small window shorter than |kTrainingDelay|.
+TEST_F(ModellerImplTest, OnUserBrightnessChanged) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  ASSERT_EQ(Modeller::Status::kGlobal, test_observer_->model_status());
+
+  std::vector<TrainingDataPoint> expected_data;
+  for (int i = 0; i < ModellerImpl::kMaxTrainingDataPoints - 1; ++i) {
+    EXPECT_EQ(i, modeller_->NumberTrainingDataPointsForTesting());
+    scoped_task_environment_.FastForwardBy(
+        base::TimeDelta::FromMilliseconds(1));
+    const base::TimeTicks now =
+        scoped_task_environment_.GetMockTickClock()->NowTicks();
+    const int lux = i * 20;
+    fake_als_reader_.ReportAmbientLightUpdate(lux);
+    const double brightness_old = 10.0 + i;
+    const double brightness_new = 20.0 + i;
+    modeller_->OnUserBrightnessChanged(brightness_old, brightness_new);
+    expected_data.push_back({brightness_old, brightness_new,
+                             modeller_->AverageAmbientForTesting(), now});
+  }
+
+  // Training should not have started.
+  EXPECT_EQ(ModellerImpl::kMaxTrainingDataPoints - 1,
+            modeller_->NumberTrainingDataPointsForTesting());
+
+  // Add one more data point to trigger the training early.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1));
+  const base::TimeTicks now =
+      scoped_task_environment_.GetMockTickClock()->NowTicks();
+  const double brightness_old = 85;
+  const double brightness_new = 95;
+  modeller_->OnUserBrightnessChanged(brightness_old, brightness_new);
+  expected_data.push_back({brightness_old, brightness_new,
+                           modeller_->AverageAmbientForTesting(), now});
+  scoped_task_environment_.RunUntilIdle();
+
+  EXPECT_EQ(0, modeller_->NumberTrainingDataPointsForTesting());
+  const BrightnessCurve result_curve = test_observer_->brightness_curve();
+  BrightnessCurve expected_curve;
+  for (auto& training_data_point : expected_data) {
+    expected_curve.push_back(DataToCurvePoint(training_data_point));
+  }
+  CompareBrightnessCurve(expected_curve, result_curve);
+}
+
+// User activities resets timer used to start training.
+TEST_F(ModellerImplTest, MultipleUserActivities) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpModeller();
+  scoped_task_environment_.RunUntilIdle();
+  ASSERT_EQ(Modeller::Status::kGlobal, test_observer_->model_status());
+
+  fake_als_reader_.ReportAmbientLightUpdate(30);
+  modeller_->OnUserBrightnessChanged(10, 20);
+  const TrainingDataPoint expected_data = {
+      10, 20, 30, scoped_task_environment_.GetMockTickClock()->NowTicks()};
+  EXPECT_EQ(1, modeller_->NumberTrainingDataPointsForTesting());
+
+  scoped_task_environment_.FastForwardBy(ModellerImpl::kTrainingDelay -
+                                         base::TimeDelta::FromSeconds(10));
+  // A user activity is received, timer should be reset.
+  const ui::MouseEvent mouse_event(ui::ET_MOUSE_EXITED, gfx::Point(0, 0),
+                                   gfx::Point(0, 0), base::TimeTicks(), 0, 0);
+  modeller_->OnUserActivity(&mouse_event);
+
+  scoped_task_environment_.FastForwardBy(ModellerImpl::kTrainingDelay -
+                                         base::TimeDelta::FromSeconds(2));
+  EXPECT_EQ(1, modeller_->NumberTrainingDataPointsForTesting());
+
+  // Another user event is received.
+  modeller_->OnUserActivity(&mouse_event);
+
+  // After |kTrainingDelay| - 2 seconds, no training has started.
+  scoped_task_environment_.FastForwardBy(ModellerImpl::kTrainingDelay -
+                                         base::TimeDelta::FromSeconds(2));
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(1, modeller_->NumberTrainingDataPointsForTesting());
+
+  // After another 2 seconds, training is scheduled.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+  scoped_task_environment_.RunUntilIdle();
+
+  EXPECT_EQ(0, modeller_->NumberTrainingDataPointsForTesting());
+  const BrightnessCurve result_curve = test_observer_->brightness_curve();
+  BrightnessCurve expected_curve = {DataToCurvePoint(expected_data)};
+  CompareBrightnessCurve(expected_curve, result_curve);
+}
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h b/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h
new file mode 100644
index 0000000..0ed5c89
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_TRAINER_H_
+#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_TRAINER_H_
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+// It is a mapping from ambient light (in lux) to brightness percent. It should
+// be sorted in the ascending order in lux.
+using BrightnessCurve = std::vector<std::pair<double, double>>;
+
+struct TrainingDataPoint {
+  double brightness_old;
+  double brightness_new;
+  double ambient_lux;
+  base::TimeTicks sample_time;
+};
+
+// Interface to train an on-device adaptive brightness curve.
+class Trainer {
+ public:
+  virtual ~Trainer() = default;
+
+  virtual BrightnessCurve Train(const BrightnessCurve& curve,
+                                const std::vector<TrainingDataPoint>& data) = 0;
+};
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_TRAINER_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc b/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc
new file mode 100644
index 0000000..fc9b208
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc
@@ -0,0 +1,64 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+bool CurveFromString(const std::string& data, BrightnessCurve* const curve) {
+  DCHECK(curve);
+  curve->clear();
+  if (data.empty())
+    return true;
+
+  base::StringPairs key_value_pairs;
+  if (!base::SplitStringIntoKeyValuePairs(data, ',', '\n', &key_value_pairs)) {
+    LOG(ERROR) << "Ill-formatted curve";
+    return false;
+  }
+
+  for (base::StringPairs::iterator it = key_value_pairs.begin();
+       it != key_value_pairs.end(); ++it) {
+    double lux;
+    if (!base::StringToDouble(it->first, &lux)) {
+      LOG(ERROR) << "Ill-formatted lux";
+      curve->clear();
+      return false;
+    }
+
+    double brightness;
+    if (!base::StringToDouble(it->second, &brightness)) {
+      LOG(ERROR) << "Ill-formatted brightness";
+      curve->clear();
+      return false;
+    }
+
+    curve->push_back(std::make_pair(lux, brightness));
+  }
+  return true;
+}
+
+std::string CurveToString(const BrightnessCurve& curve) {
+  if (curve.empty())
+    return "";
+
+  std::vector<std::string> rows;
+  for (const auto& kv : curve) {
+    rows.push_back(base::JoinString(
+        {base::NumberToString(kv.first), base::NumberToString(kv.second)},
+        ","));
+  }
+
+  return base::JoinString(rows, "\n");
+}
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/utils.h b/chrome/browser/chromeos/power/auto_screen_brightness/utils.h
new file mode 100644
index 0000000..a5b6cbe
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/utils.h
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_UTILS_H_
+#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_UTILS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/containers/ring_buffer.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+// Replaces |curve| with the parsed curve data from |data|, returning true if
+// successful. Correct formatting in |data| should be 1 row per
+// (<ambient_light>, <brightness>) mapping. Ambient light should be a double and
+// brightness should be a double.
+bool CurveFromString(const std::string& data, BrightnessCurve* const curve);
+
+// Converts |curve| to a string. An empty string will be returned if |curve| is
+// empty.
+std::string CurveToString(const BrightnessCurve& curve);
+
+struct AmbientLightSample {
+  int lux;
+  base::TimeTicks sample_time;
+};
+
+// Calculates average ambient light over the most recent |num_recent| samples.
+// |num_recent| has to be no larger than the capacity of the buffer, but it can
+// be greater than the number of samples stored. If |num_recent| is greater than
+// the number of samples stored, it returns average of stored samples. If
+// |num_recent| is negative, it returns average over all stored samples. If
+// input |ambient_light_values| is empty, it returns 0.
+// TODO(jiameng): this is the very basic version of averaging, we need to change
+// it to allow for time decay.
+template <size_t size>
+double AverageAmbient(
+    const base::RingBuffer<AmbientLightSample, size>& ambient_light_values,
+    int num_recent) {
+  DCHECK_LE(num_recent, static_cast<int>(ambient_light_values.BufferSize()));
+  if (ambient_light_values.CurrentIndex() == 0)
+    return 0;
+
+  double sum = 0;
+  int count = 0;
+  const int used_num_recent =
+      num_recent < 0 ? ambient_light_values.BufferSize() : num_recent;
+  for (auto it = ambient_light_values.End(); it && count < used_num_recent;
+       --it) {
+    const auto& ambient_sample = **it;
+    sum += ambient_sample.lux;
+    ++count;
+  }
+  return sum / count;
+}
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_UTILS_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/utils_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/utils_unittest.cc
new file mode 100644
index 0000000..4bf53ed
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/utils_unittest.cc
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+TEST(AverageAmbient, FullBufferTest) {
+  base::SimpleTestTickClock tick_clock;
+  base::RingBuffer<AmbientLightSample, 5> data;
+  for (int i = 0; i < 5; ++i) {
+    const AmbientLightSample sample = {i, tick_clock.NowTicks()};
+    data.SaveToBuffer(sample);
+  }
+
+  double sum = 0;
+  for (int i = 0; i < 5; ++i) {
+    const int num_recent = i + 1;
+    // Reverse order.
+    const int head_value = 4 - i;
+    sum += head_value;
+    const double expected = sum / num_recent;
+    EXPECT_DOUBLE_EQ(AverageAmbient(data, num_recent), expected);
+  }
+
+  EXPECT_DOUBLE_EQ(AverageAmbient(data, -1), sum / 5);
+}
+
+TEST(AverageAmbient, NonFullBufferTest) {
+  base::SimpleTestTickClock tick_clock;
+  base::RingBuffer<AmbientLightSample, 5> data;
+  for (int i = 0; i < 3; ++i) {
+    const AmbientLightSample sample = {i, tick_clock.NowTicks()};
+    data.SaveToBuffer(sample);
+  }
+
+  double sum = 0;
+  for (int i = 0; i < 3; ++i) {
+    const int num_recent = i + 1;
+    // Reverse order.
+    const int head_value = 2 - i;
+    sum += head_value;
+    const double expected = sum / num_recent;
+    EXPECT_DOUBLE_EQ(AverageAmbient(data, num_recent), expected);
+  }
+
+  const double expected = sum / 3;
+  for (int i = 3; i < 5; ++i) {
+    const int num_recent = i + 1;
+    EXPECT_DOUBLE_EQ(AverageAmbient(data, num_recent), expected);
+  }
+
+  EXPECT_DOUBLE_EQ(AverageAmbient(data, -1), expected);
+}
+
+TEST(AverageAmbient, EmptyBufferTest) {
+  base::RingBuffer<AmbientLightSample, 5> data;
+  EXPECT_DOUBLE_EQ(AverageAmbient(data, 2), 0);
+  EXPECT_DOUBLE_EQ(AverageAmbient(data, -1), 0);
+}
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn b/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn
index 5707ed8..b994829 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn
+++ b/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn
@@ -21,6 +21,7 @@
     "//chrome/browser/chromeos:user_activity_event_proto",
     "//chrome/browser/chromeos/power/ml:user_activity_ukm_logger_helpers",
     "//chrome/common:constants",
+    "//chromeos:chromeos",
     "//components/assist_ranker",
     "//components/assist_ranker/proto",
     "//components/sessions",
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc b/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc
index 0864cae..5704816 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc
+++ b/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc
@@ -17,8 +17,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/chromeos/power/ml/smart_dim/tf_native_inference.h"
 #include "chrome/browser/chromeos/power/ml/user_activity_ukm_logger_helpers.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/grit/browser_resources.h"
+#include "chromeos/chromeos_features.h"
 #include "components/assist_ranker/example_preprocessing.h"
 #include "components/assist_ranker/proto/example_preprocessor.pb.h"
 #include "components/assist_ranker/proto/ranker_example.pb.h"
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc b/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc
index 591b6172..224f0f60 100644
--- a/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc
+++ b/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/power/ml/user_activity_event.pb.h"
-#include "chrome/common/chrome_features.h"
+#include "chromeos/chromeos_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/page_transition_types.h"
 
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.cc b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
index cbff5fe8d..046745f 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_features.h"
+#include "chromeos/chromeos_features.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
 #include "chromeos/system/devicetype.h"
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
index 8a01c45..8f7aad1 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
@@ -24,10 +24,10 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_activity_simulator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/test_browser_window_aura.h"
 #include "chrome/test/base/testing_profile.h"
+#include "chromeos/chromeos_features.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc
index f86480e..a3a28cc 100644
--- a/chrome/browser/extensions/api/automation/automation_apitest.cc
+++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -218,7 +218,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopFocusViews) {
-  AutomationManagerAura::GetInstance()->Enable(browser()->profile());
+  AutomationManagerAura::GetInstance()->Enable();
   // Trigger the shelf subtree to be computed.
   ash::Shell::Get()->accelerator_controller()->PerformActionIfEnabled(
       ash::FOCUS_SHELF);
@@ -248,7 +248,7 @@
 
 #if defined(OS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopActions) {
-  AutomationManagerAura::GetInstance()->Enable(browser()->profile());
+  AutomationManagerAura::GetInstance()->Enable();
   // Trigger the shelf subtree to be computed.
   ash::Shell::Get()->accelerator_controller()->PerformActionIfEnabled(
       ash::FOCUS_SHELF);
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
index 8897086f..19d5c616 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
+++ b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
@@ -544,7 +544,7 @@
   AutomationEventRouter::GetInstance()->RegisterListenerWithDesktopPermission(
       extension_id(), source_process_id());
 
-  AutomationManagerAura::GetInstance()->Enable(browser_context());
+  AutomationManagerAura::GetInstance()->Enable();
   return RespondNow(NoArguments());
 #else
   return RespondNow(Error("getDesktop is unsupported by this platform"));
diff --git a/chrome/browser/history/top_sites_factory.cc b/chrome/browser/history/top_sites_factory.cc
index 9daef8e..6fa7ee56 100644
--- a/chrome/browser/history/top_sites_factory.cc
+++ b/chrome/browser/history/top_sites_factory.cc
@@ -60,9 +60,9 @@
 // Android does not use prepopulated pages.
 const RawPrepopulatedPage kRawPrepopulatedPages[] = {
     {
-        IDS_WEBSTORE_URL, IDS_EXTENSION_WEB_STORE_TITLE, IDR_WEBSTORE_ICON_16,
-        IDR_WEBSTORE_ICON_32, IDR_NEWTAB_WEBSTORE_THUMBNAIL,
-        SkColorSetRGB(63, 132, 197),
+        IDS_WEBSTORE_URL, IDS_EXTENSION_WEB_STORE_TITLE_SHORT,
+        IDR_WEBSTORE_ICON_16, IDR_WEBSTORE_ICON_32,
+        IDR_NEWTAB_WEBSTORE_THUMBNAIL, SkColorSetRGB(63, 132, 197),
     },
 };
 #endif
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
index 3a1c1b3..65ddccc 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/metrics/net/network_metrics_provider.h"
+#include "net/http/http_response_headers.h"
 #include "services/metrics/public/cpp/metrics_utils.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
@@ -61,6 +62,10 @@
 UkmPageLoadMetricsObserver::ObservePolicy UkmPageLoadMetricsObserver::OnCommit(
     content::NavigationHandle* navigation_handle,
     ukm::SourceId source_id) {
+  const net::HttpResponseHeaders* response_headers =
+      navigation_handle->GetResponseHeaders();
+  if (response_headers)
+    http_response_code_ = response_headers->response_code();
   // The PageTransition for the navigation may be updated on commit.
   page_transition_ = navigation_handle->GetPageTransition();
   return CONTINUE_OBSERVING;
@@ -220,6 +225,10 @@
         static_cast<int64_t>(proto_effective_connection_type));
   }
 
+  if (http_response_code_) {
+    builder.SetNet_HttpResponseCode(
+        static_cast<int64_t>(http_response_code_.value()));
+  }
   if (http_rtt_estimate_) {
     builder.SetNet_HttpRttEstimate_OnNavigationStart(
         static_cast<int64_t>(http_rtt_estimate_.value().InMilliseconds()));
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
index e0c069a..b9698e33 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
@@ -80,6 +80,7 @@
   // Network quality estimates.
   net::EffectiveConnectionType effective_connection_type_ =
       net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+  base::Optional<int32_t> http_response_code_;
   base::Optional<base::TimeDelta> http_rtt_estimate_;
   base::Optional<base::TimeDelta> transport_rtt_estimate_;
   base::Optional<int32_t> downstream_kbps_estimate_;
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
index fd4c918..abdccd4 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -138,6 +138,8 @@
     test_ukm_recorder().ExpectEntryMetric(
         kv.second.get(),
         PageLoad::kDocumentTiming_NavigationToLoadEventFiredName, 500);
+    test_ukm_recorder().ExpectEntryMetric(
+        kv.second.get(), PageLoad::kNet_HttpResponseCodeName, 200);
     EXPECT_FALSE(test_ukm_recorder().EntryHasMetric(
         kv.second.get(),
         PageLoad::
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc
index 57e40d4..0c8febd9 100644
--- a/chrome/browser/previews/previews_lite_page_browsertest.cc
+++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -127,7 +127,7 @@
           {"previews_host", previews_server().spec()},
           {"blacklisted_path_suffixes", ".mp4,.jpg"},
           {"trigger_on_localhost", "true"},
-          {"navigation_timeout_milliseconds", use_timeout ? "2000" : "0"}};
+          {"navigation_timeout_milliseconds", use_timeout ? "250" : "0"}};
       base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
           "TrialName1", "GroupName1", feature_parameters);
 
@@ -275,7 +275,7 @@
       const net::test_server::HttpRequest& request) {
     std::unique_ptr<net::test_server::DelayedHttpResponse> response =
         std::make_unique<net::test_server::DelayedHttpResponse>(
-            base::TimeDelta::FromSeconds(3));
+            base::TimeDelta::FromMilliseconds(500));
     response->set_code(net::HttpStatusCode::HTTP_OK);
     return std::move(response);
   }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
index 206d6ac..d49e6cc 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
@@ -355,7 +355,7 @@
 AutomationPredicate.structuralContainer = AutomationPredicate.roles([
   Role.ALERT_DIALOG, Role.CLIENT, Role.DIALOG, Role.ROOT_WEB_AREA,
   Role.WEB_VIEW, Role.WINDOW, Role.EMBEDDED_OBJECT, Role.IFRAME,
-  Role.IFRAME_PRESENTATIONAL, Role.UNKNOWN
+  Role.IFRAME_PRESENTATIONAL, Role.IGNORED, Role.UNKNOWN
 ]);
 
 /**
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.js b/chrome/browser/resources/local_ntp/custom_links_edit.js
index 308b165..276ffef 100644
--- a/chrome/browser/resources/local_ntp/custom_links_edit.js
+++ b/chrome/browser/resources/local_ntp/custom_links_edit.js
@@ -121,19 +121,6 @@
 
 
 /**
- * Disables the "Done" button until the URL field is modified.
- */
-function disableSubmitUntilTextInput() {
-  $(IDS.DONE).disabled = true;
-  let reenable = (event) => {
-    $(IDS.DONE).disabled = false;
-    $(IDS.URL_FIELD).removeEventListener('input', reenable);
-  };
-  $(IDS.URL_FIELD).addEventListener('input', reenable);
-}
-
-
-/**
  * Shows the invalid URL error message until the URL field is modified.
  */
 function showInvalidUrlUntilTextInput() {
@@ -243,7 +230,7 @@
       document.title = addLinkTitle;
       $(IDS.DIALOG_TITLE).textContent = addLinkTitle;
       $(IDS.DELETE).disabled = true;
-      disableSubmitUntilTextInput();
+      $(IDS.DONE).disabled = true;
       // Set accessibility names.
       $(IDS.DONE).setAttribute('aria-label', addLinkTitle);
       $(IDS.DONE).title = addLinkTitle;
@@ -352,6 +339,9 @@
       .addEventListener('focusin', () => changeColor(IDS.URL_FIELD_NAME));
   $(IDS.URL_FIELD)
       .addEventListener('blur', () => changeColor(IDS.URL_FIELD_NAME));
+  // Disables the "Done" button when the URL field is empty.
+  $(IDS.URL_FIELD).addEventListener('input',
+      () => $(IDS.DONE).disabled = ($(IDS.URL_FIELD).value.trim() === ''));
 
   $(IDS.EDIT_DIALOG).showModal();
 
diff --git a/chrome/browser/resources/print_preview/new/pages_settings.html b/chrome/browser/resources/print_preview/new/pages_settings.html
index b6ec296..76c90cca 100644
--- a/chrome/browser/resources/print_preview/new/pages_settings.html
+++ b/chrome/browser/resources/print_preview/new/pages_settings.html
@@ -1,69 +1,71 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
-<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/html/md_select_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
 <link rel="import" href="../data/document_info.html">
 <link rel="import" href="../print_preview_utils.html">
 <link rel="import" href="input_behavior.html">
 <link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="select_behavior.html">
 <link rel="import" href="settings_behavior.html">
 <link rel="import" href="settings_section.html">
 <link rel="import" href="strings.html">
 
 <dom-module id="print-preview-pages-settings">
   <template>
-    <style include="print-preview-shared">
+    <style include="print-preview-shared md-select">
       :host([error-state_='0']) #pageSettingsCustomInput {
         --cr-input-error-display: none;
       }
 
-      :host(:not([error-state_='0'])) #custom-radio-button {
-        /* Margin = -1 * error height = -1 * (16px + 2 lines * line-height) */
-        --cr-radio-button-disc: {
-          margin-top: calc(-16px - 2 * .75rem);
-        };
+      #pageSettingsCustomInput {
+        --cr-input-row-container: {
+          min-height: 38px;
+        }
       }
 
       /* Margin = standard margin (16px) - error field margin (8px) */
-      :host(:not([error-state_='0'])) print-preview-settings-section {
+      :host(:not([error-state_='0'])) #customInputWrapper {
         margin-bottom: 8px;
       }
 
       #pageSettingsCustomInput {
         cursor: default;
-        height: 100%;
+        --cr-form-field-label-height: 100%;
       }
     </style>
-    <print-preview-settings-section
-        class="input-settings-section multirow-controls">
-      <span slot="title">$i18n{pagesLabel}</span>
-      <div slot="controls" id="controls">
-        <div class="radio">
-          <cr-radio-button name="pages" id="all-radio-button"
-              checked$="[[!customSelected_]]"
-              disabled$="[[getDisabled_(disabled)]]"
-              on-click="onAllRadioClick_">
-            <span>$i18n{optionAllPages}</span>
-          </cr-radio-button>
-          <cr-radio-button name="pages" id="custom-radio-button"
-              checked$="[[customSelected_]]"
-              disabled$="[[getDisabled_(disabled)]]"
-              aria-label="$i18n{optionCustomPages}"
-              on-click="onCustomRadioClick_"
-              on-focus="onCustomRadioFocus_"
-              on-blur="onCustomInputBlur_">
-            <cr-input id="pageSettingsCustomInput" type="text"
-                data-timeout-delay="500"
-                disabled$="[[getDisabled_(disabled)]]" spellcheck="false"
-                on-focus="onCustomInputFocus_" on-blur="onCustomInputBlur_"
-                placeholder="$i18n{examplePageRangeText}"
-                error-message="[[getHintMessage_(errorState_,
-                    documentInfo.pageCount)]]">
-            </cr-input>
-          </cr-radio-button>
-        </div>
+    <print-preview-settings-section>
+      <span slot="title" id="pages-label">$i18n{pagesLabel}</span>
+      <div slot="controls">
+        <select class="md-select" aria-labelledby="pages-label"
+            disabled$="[[getDisabled_(disabled)]]"
+            value="{{selectedValue::change}}"
+            on-blur="onSelectBlur_">
+          <option value="[[pagesValueEnum_.ALL]]" selected>
+            $i18n{optionAllPages}
+          </option>
+          <option value="[[pagesValueEnum_.CUSTOM]]">
+            $i18n{optionCustomPages}
+          </option>
+        </select>
       </div>
     </print-preview-settings-section>
+    <iron-collapse opened="[[customSelected_]]">
+      <print-preview-settings-section id="customInputWrapper">
+        <div slot="title"></div>
+        <div slot="controls">
+          <cr-input id="pageSettingsCustomInput" type="text"
+              data-timeout-delay="500"
+              disabled$="[[getDisabled_(disabled)]]" spellcheck="false"
+              on-blur="onCustomInputBlur_"
+              placeholder="$i18n{examplePageRangeText}"
+              error-message="[[getHintMessage_(errorState_,
+                  documentInfo.pageCount)]]">
+          </cr-input>
+        </div>
+      </print-preview-settings-section>
+    </iron-collapse>
   </template>
   <script src="pages_settings.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/print_preview/new/pages_settings.js b/chrome/browser/resources/print_preview/new/pages_settings.js
index 2db57211..9f12e46c 100644
--- a/chrome/browser/resources/print_preview/new/pages_settings.js
+++ b/chrome/browser/resources/print_preview/new/pages_settings.js
@@ -12,10 +12,19 @@
   OUT_OF_BOUNDS: 2,
 };
 
+/** @enum {number} */
+const PagesValue = {
+  ALL: 0,
+  CUSTOM: 1,
+};
+
 Polymer({
   is: 'print-preview-pages-settings',
 
-  behaviors: [SettingsBehavior, print_preview_new.InputBehavior],
+  behaviors: [
+    SettingsBehavior, print_preview_new.InputBehavior,
+    print_preview_new.SelectBehavior
+  ],
 
   properties: {
     /** @type {!print_preview.DocumentInfo} */
@@ -33,14 +42,14 @@
       computed: 'computeAllPagesArray_(documentInfo.pageCount)',
     },
 
+    disabled: Boolean,
+
     /** @private {boolean} */
     customSelected_: {
       type: Boolean,
       value: false,
     },
 
-    disabled: Boolean,
-
     /** @private {number} */
     errorState_: {
       type: Number,
@@ -60,6 +69,15 @@
       type: Array,
       computed: 'computeRangesToPrint_(pagesToPrint_, allPagesArray_)',
     },
+
+    /**
+     * Mirroring the enum so that it can be used from HTML bindings.
+     * @private
+     */
+    pagesValueEnum_: {
+      type: Object,
+      value: PagesValue,
+    },
   },
 
   observers: [
@@ -71,6 +89,11 @@
     'input-change': 'onInputChange_',
   },
 
+  // Initialize in attached() since this doesn't observe settings.pages.
+  attached: function() {
+    this.selectedValue = PagesValue.ALL.toString();
+  },
+
   /** @return {!CrInputElement} The cr-input field element for InputBehavior. */
   getInput: function() {
     return this.$.pageSettingsCustomInput;
@@ -84,6 +107,14 @@
     this.inputString_ = /** @type {string} */ (e.detail);
   },
 
+  onProcessSelectChange: function(value) {
+    this.customSelected_ = value === PagesValue.CUSTOM.toString();
+    if (this.customSelected_) {
+      /** @type {!CrInputElement} */ (this.$.pageSettingsCustomInput)
+          .inputElement.focus();
+    }
+  },
+
   /**
    * @return {boolean} Whether the controls should be disabled.
    * Does not need to depend on |errorState_|, since |errorState_| is always
@@ -274,28 +305,13 @@
   },
 
   /** @private */
-  onAllRadioClick_: function() {
-    this.customSelected_ = false;
-  },
+  onSelectBlur_: function(event) {
+    if (!this.customSelected_ ||
+        event.relatedTarget === this.$.pageSettingsCustomInput) {
+      return;
+    }
 
-  /**
-   * @param {Event} event Contains information about where focus came from.
-   * @private
-   */
-  onCustomRadioFocus_: function(event) {
-    if (event.relatedTarget !== this.$.pageSettingsCustomInput)
-      this.onCustomRadioClick_();
-  },
-
-  /** @private */
-  onCustomRadioClick_: function() {
-    /** @type {!CrInputElement} */ (this.$.pageSettingsCustomInput)
-        .inputElement.focus();
-  },
-
-  /** @private */
-  onCustomInputFocus_: function() {
-    this.customSelected_ = true;
+    this.onCustomInputBlur_(event);
   },
 
   /**
@@ -305,9 +321,11 @@
   onCustomInputBlur_: function(event) {
     this.resetAndUpdate();
 
-    if (this.inputString_.trim() == '' &&
-        event.relatedTarget != this.$$('#custom-radio-button')) {
+    if (this.inputString_ === '' &&
+        event.relatedTarget != this.$.customInputWrapper &&
+        event.relatedTarget != this.$$('.md-select')) {
       this.customSelected_ = false;
+      this.selectedValue = PagesValue.ALL.toString();
     }
   },
 
diff --git a/chrome/browser/resources/print_preview/new/print_preview_shared_css.html b/chrome/browser/resources/print_preview/new/print_preview_shared_css.html
index c74e79ef..5e3de37 100644
--- a/chrome/browser/resources/print_preview/new/print_preview_shared_css.html
+++ b/chrome/browser/resources/print_preview/new/print_preview_shared_css.html
@@ -15,7 +15,6 @@
           margin-top: 3px;
           margin-bottom: 3px;
         };
-        --cr-radio-button-size: 16px;
         --md-select-width: calc(100% - 17px);
         --print-preview-settings-border: 1px solid rgb(232, 234, 237);
         --print-preview-dialog-margin: 34px;
@@ -24,8 +23,7 @@
       }
 
       /* Default state ********************************************************/
-      input[type='checkbox'],
-      input[type='radio'] {
+      input[type='checkbox'] {
         margin-bottom: 0;
         margin-inline-end: 1px;
         margin-inline-start: 0;
@@ -48,13 +46,11 @@
         user-select: none;
       }
 
-      .checkbox cr-checkbox,
-      .radio cr-radio-button {
+      .checkbox cr-checkbox {
         margin-bottom: 3px;
         margin-top: 3px;
         min-height: 32px;
         --cr-checkbox-ripple-size: 38px;
-        --cr-radio-button-ink-size: 38px;
         --cr-checkbox-label-container: {
           overflow: hidden;
           padding-inline-start: 15px;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 0d17497..4593c0c 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -81,14 +81,8 @@
       "cocoa/chrome_browser_window.mm",
       "cocoa/chrome_event_processing_window.h",
       "cocoa/chrome_event_processing_window.mm",
-      "cocoa/clickhold_button_cell.h",
-      "cocoa/clickhold_button_cell.mm",
       "cocoa/cocoa_util.h",
       "cocoa/cocoa_util.mm",
-      "cocoa/constrained_window/constrained_window_alert.h",
-      "cocoa/constrained_window/constrained_window_alert.mm",
-      "cocoa/constrained_window/constrained_window_button.h",
-      "cocoa/constrained_window/constrained_window_button.mm",
       "cocoa/constrained_window/constrained_window_control_utils.h",
       "cocoa/constrained_window/constrained_window_control_utils.mm",
       "cocoa/constrained_window/constrained_window_custom_sheet.h",
@@ -104,7 +98,6 @@
       "cocoa/constrained_window/constrained_window_sheet_info.mm",
       "cocoa/constrained_window/constrained_window_web_dialog_sheet.h",
       "cocoa/constrained_window/constrained_window_web_dialog_sheet.mm",
-      "cocoa/create_native_web_modal_manager_cocoa.mm",
       "cocoa/drag_util.h",
       "cocoa/drag_util.mm",
       "cocoa/extensions/extension_keybinding_registry_cocoa.h",
@@ -138,15 +131,11 @@
       "cocoa/has_weak_browser_pointer.h",
       "cocoa/hover_close_button.h",
       "cocoa/hover_close_button.mm",
-      "cocoa/image_button_cell.h",
-      "cocoa/image_button_cell.mm",
       "cocoa/javascript_app_modal_dialog_cocoa.h",
       "cocoa/javascript_app_modal_dialog_cocoa.mm",
       "cocoa/location_bar/location_bar_view_mac.h",
       "cocoa/location_bar/location_bar_view_mac.mm",
       "cocoa/main_menu_item.h",
-      "cocoa/menu_button.h",
-      "cocoa/menu_button.mm",
       "cocoa/nsview_additions.h",
       "cocoa/nsview_additions.mm",
       "cocoa/rect_path_utils.h",
@@ -199,20 +188,6 @@
       "cocoa/tabs/tab_window_controller.mm",
       "cocoa/themed_window.h",
       "cocoa/themed_window.mm",
-      "cocoa/toolbar/app_toolbar_button.h",
-      "cocoa/toolbar/app_toolbar_button.mm",
-      "cocoa/toolbar/app_toolbar_button_cell.h",
-      "cocoa/toolbar/app_toolbar_button_cell.mm",
-      "cocoa/toolbar/back_forward_menu_controller.h",
-      "cocoa/toolbar/back_forward_menu_controller.mm",
-      "cocoa/toolbar/reload_button_cocoa.h",
-      "cocoa/toolbar/reload_button_cocoa.mm",
-      "cocoa/toolbar/toolbar_button_cocoa.h",
-      "cocoa/toolbar/toolbar_button_cocoa.mm",
-      "cocoa/toolbar/toolbar_controller.h",
-      "cocoa/toolbar/toolbar_controller.mm",
-      "cocoa/toolbar/toolbar_view_cocoa.h",
-      "cocoa/toolbar/toolbar_view_cocoa.mm",
       "cocoa/touchbar/credit_card_autofill_touch_bar_controller.h",
       "cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm",
       "cocoa/touchbar/text_suggestions_touch_bar_controller.h",
@@ -224,8 +199,6 @@
       "cocoa/view_id_util.h",
       "cocoa/view_id_util.mm",
       "cocoa/view_resizer.h",
-      "cocoa/web_contents_modal_dialog_manager_views_mac.h",
-      "cocoa/web_contents_modal_dialog_manager_views_mac.mm",
 
       # TODO(estade): this class should be deleted in favor of a combobox model.
       # See crbug.com/590850
@@ -2236,7 +2209,6 @@
       "//chrome/browser/apps/app_shim",
       "//extensions/components/native_app_window",
       "//third_party/google_toolbox_for_mac",
-      "//third_party/molokocacao",
       "//third_party/mozilla",
       "//ui/accelerated_widget_mac:accelerated_widget_mac",
     ]
@@ -3038,8 +3010,6 @@
         "views/frame/native_widget_mac_frameless_nswindow.mm",
         "views/policy/enterprise_startup_dialog_mac_util.h",
         "views/policy/enterprise_startup_dialog_mac_util.mm",
-        "views/relaunch_notification/get_app_menu_anchor_point.h",
-        "views/relaunch_notification/get_app_menu_anchor_point.mm",
       ]
     } else {
       sources += [
diff --git a/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc b/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc
index 938b9c5..b7b8f33 100644
--- a/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc
+++ b/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc
@@ -21,7 +21,7 @@
   DCHECK(context);
   AutomationManagerAura* manager = AutomationManagerAura::GetInstance();
   if (enabled)
-    manager->Enable(context);
+    manager->Enable();
   else
     manager->Disable();
 }
@@ -85,7 +85,7 @@
 
   if (msg) {
     AutomationManagerAura::GetInstance()->HandleAlert(
-        profile, l10n_util::GetStringUTF8(msg));
+        l10n_util::GetStringUTF8(msg));
     // After handling the alert, if the alert is screen-off, we should
     // disable automation manager to handle any following a11y events.
     if (alert == ash::mojom::AccessibilityAlert::SCREEN_OFF)
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
index 2d3eb06..df90b96 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -8,13 +8,9 @@
 
 #include "base/memory/singleton.h"
 #include "build/build_config.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/common/extensions/chrome_extension_messages.h"
 #include "content/public/browser/ax_event_notification_details.h"
-#include "content/public/browser/browser_context.h"
 #include "content/public/browser/render_frame_host.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_enum_util.h"
@@ -32,62 +28,22 @@
 #include "ash/shell.h"
 #include "ash/wm/window_util.h"
 #include "chrome/browser/chromeos/accessibility/ax_host_service.h"
-#include "components/session_manager/core/session_manager.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/views/widget/widget_delegate.h"
 #endif
 
-using content::BrowserContext;
 using extensions::AutomationEventRouter;
 
-namespace {
-
-// Returns default browser context for sending events in case it was not
-// provided. This works around a crash in profile creation during OOBE when
-// accessibility is enabled. https://crbug.com/738003
-BrowserContext* GetDefaultEventContext() {
-  ProfileManager* profile_manager = g_browser_process->profile_manager();
-  if (!profile_manager)
-    return nullptr;
-
-#if defined(OS_CHROMEOS)
-  session_manager::SessionManager* session_manager =
-      session_manager::SessionManager::Get();
-  // It is not guaranteed that user profile creation is completed for
-  // some session states. In this case use default profile.
-  const session_manager::SessionState session_state =
-      session_manager ? session_manager->session_state()
-                      : session_manager::SessionState::UNKNOWN;
-  switch (session_state) {
-    case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE:
-    case session_manager::SessionState::ACTIVE:
-    case session_manager::SessionState::LOCKED:
-      break;
-    case session_manager::SessionState::UNKNOWN:
-    case session_manager::SessionState::OOBE:
-    case session_manager::SessionState::LOGIN_PRIMARY:
-    case session_manager::SessionState::LOGIN_SECONDARY:
-      const base::FilePath defult_profile_dir =
-          profiles::GetDefaultProfileDir(profile_manager->user_data_dir());
-      return profile_manager->GetProfileByPath(defult_profile_dir);
-  }
-#endif
-
-  return ProfileManager::GetLastUsedProfile();
-}
-
-}  // namespace
-
 // static
 AutomationManagerAura* AutomationManagerAura::GetInstance() {
   return base::Singleton<AutomationManagerAura>::get();
 }
 
-void AutomationManagerAura::Enable(BrowserContext* context) {
+void AutomationManagerAura::Enable() {
   enabled_ = true;
   Reset(false);
 
-  SendEvent(context, current_tree_->GetRoot(), ax::mojom::Event::kLoadComplete);
+  SendEvent(current_tree_->GetRoot(), ax::mojom::Event::kLoadComplete);
   views::AXAuraObjCache::GetInstance()->SetDelegate(this);
 
 #if defined(OS_CHROMEOS)
@@ -98,7 +54,7 @@
       views::AXAuraObjWrapper* focus =
           views::AXAuraObjCache::GetInstance()->GetOrCreate(active_window);
       if (focus)
-        SendEvent(context, focus, ax::mojom::Event::kChildrenChanged);
+        SendEvent(focus, ax::mojom::Event::kChildrenChanged);
     }
   }
   // Gain access to out-of-process native windows.
@@ -115,14 +71,13 @@
 #endif
 }
 
-void AutomationManagerAura::HandleEvent(BrowserContext* context,
-                                        views::View* view,
+void AutomationManagerAura::HandleEvent(views::View* view,
                                         ax::mojom::Event event_type) {
   if (!enabled_)
     return;
 
   if (!view) {
-    SendEvent(nullptr, current_tree_->GetRoot(), event_type);
+    SendEvent(current_tree_->GetRoot(), event_type);
     return;
   }
 
@@ -146,18 +101,17 @@
                                                   ax::mojom::Event event_type) {
   views::AXAuraObjWrapper* obj = views::AXAuraObjCache::GetInstance()->Get(id);
   if (obj)
-    SendEvent(nullptr, obj, event_type);
+    SendEvent(obj, event_type);
 }
 
-void AutomationManagerAura::HandleAlert(content::BrowserContext* context,
-                                        const std::string& text) {
+void AutomationManagerAura::HandleAlert(const std::string& text) {
   if (!enabled_)
     return;
 
   views::AXAuraObjWrapper* obj =
       static_cast<AXRootObjWrapper*>(current_tree_->GetRoot())
           ->GetAlertForText(text);
-  SendEvent(context, obj, ax::mojom::Event::kAlert);
+  SendEvent(obj, ax::mojom::Event::kAlert);
 }
 
 void AutomationManagerAura::PerformAction(const ui::AXActionData& data) {
@@ -181,12 +135,12 @@
   if (!parent)
     parent = current_tree_->GetRoot();
 
-  SendEvent(nullptr, parent, ax::mojom::Event::kChildrenChanged);
+  SendEvent(parent, ax::mojom::Event::kChildrenChanged);
 }
 
 void AutomationManagerAura::OnEvent(views::AXAuraObjWrapper* aura_obj,
                                     ax::mojom::Event event_type) {
-  SendEvent(nullptr, aura_obj, event_type);
+  SendEvent(aura_obj, event_type);
 }
 
 AutomationManagerAura::AutomationManagerAura()
@@ -206,8 +160,7 @@
                          new AuraAXTreeSerializer(current_tree_.get()));
 }
 
-void AutomationManagerAura::SendEvent(BrowserContext* context,
-                                      views::AXAuraObjWrapper* aura_obj,
+void AutomationManagerAura::SendEvent(views::AXAuraObjWrapper* aura_obj,
                                       ax::mojom::Event event_type) {
   if (!enabled_)
     return;
@@ -215,14 +168,6 @@
   if (!current_tree_serializer_)
     return;
 
-  if (!context)
-    context = GetDefaultEventContext();
-
-  if (!context) {
-    LOG(WARNING) << "Accessibility notification but no browser context";
-    return;
-  }
-
   if (processing_events_) {
     pending_events_.push_back(std::make_pair(aura_obj, event_type));
     return;
@@ -271,9 +216,7 @@
   auto pending_events_copy = pending_events_;
   pending_events_.clear();
   for (size_t i = 0; i < pending_events_copy.size(); ++i) {
-    SendEvent(context,
-              pending_events_copy[i].first,
-              pending_events_copy[i].second);
+    SendEvent(pending_events_copy[i].first, pending_events_copy[i].second);
   }
 }
 
@@ -354,6 +297,6 @@
   views::AXAuraObjWrapper* window_wrapper =
       views::AXAuraObjCache::GetInstance()->GetOrCreate(window);
   if (window_wrapper)
-    SendEvent(nullptr, window_wrapper, action.hit_test_event_to_fire);
+    SendEvent(window_wrapper, action.hit_test_event_to_fire);
 #endif
 }
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
index c947f91..c7a4695 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
@@ -24,10 +24,6 @@
 struct DefaultSingletonTraits;
 }  // namespace base
 
-namespace content {
-class BrowserContext;
-}  // namespace content
-
 namespace views {
 class AXAuraObjWrapper;
 class View;
@@ -48,17 +44,15 @@
   static AutomationManagerAura* GetInstance();
 
   // Enable automation support for views.
-  void Enable(content::BrowserContext* context);
+  void Enable();
 
   // Disable automation support for views.
   void Disable();
 
   // Handle an event fired upon a |View|.
-  void HandleEvent(content::BrowserContext* context,
-                   views::View* view,
-                   ax::mojom::Event event_type);
+  void HandleEvent(views::View* view, ax::mojom::Event event_type);
 
-  void HandleAlert(content::BrowserContext* context, const std::string& text);
+  void HandleAlert(const std::string& text);
 
   // AXHostDelegate implementation.
   void PerformAction(const ui::AXActionData& data) override;
@@ -89,8 +83,7 @@
   // serializer to save memory.
   void Reset(bool reset_serializer);
 
-  void SendEvent(content::BrowserContext* context,
-                 views::AXAuraObjWrapper* aura_obj,
+  void SendEvent(views::AXAuraObjWrapper* aura_obj,
                  ax::mojom::Event event_type);
 
   void PerformHitTest(const ui::AXActionData& data);
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
index f0d9588..b15a37a 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
@@ -107,7 +107,7 @@
   content::BrowserAccessibilityState::GetInstance()->EnableAccessibility();
 
   AutomationManagerAura* manager = AutomationManagerAura::GetInstance();
-  manager->Enable(browser()->profile());
+  manager->Enable();
   auto* tree = manager->current_tree_.get();
 
   ui_test_utils::NavigateToURL(
@@ -143,7 +143,7 @@
 IN_PROC_BROWSER_TEST_F(AutomationManagerAuraBrowserTest,
                        TransientFocusChangesAreSuppressed) {
   AutomationManagerAura* manager = AutomationManagerAura::GetInstance();
-  manager->Enable(browser()->profile());
+  manager->Enable();
 
   views::Widget* widget = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 67e22c3..b5ce30cb 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -243,7 +243,7 @@
 
 void ChromeAutofillClient::ConfirmSaveCreditCardLocally(
     const CreditCard& card,
-    const base::Closure& callback) {
+    base::OnceClosure callback) {
 #if defined(OS_ANDROID)
   InfoBarService::FromWebContents(web_contents())
       ->AddInfoBar(CreateSaveCardInfoBarMobile(
@@ -251,14 +251,14 @@
               false, card, std::unique_ptr<base::DictionaryValue>(nullptr),
               /*upload_save_card_callback=*/
               base::OnceCallback<void(const base::string16&)>(),
-              /*local_save_card_callback=*/callback, GetPrefs())));
+              /*local_save_card_callback=*/std::move(callback), GetPrefs())));
 #else
   // Do lazy initialization of SaveCardBubbleControllerImpl.
   autofill::SaveCardBubbleControllerImpl::CreateForWebContents(
       web_contents());
   autofill::SaveCardBubbleControllerImpl* controller =
       autofill::SaveCardBubbleControllerImpl::FromWebContents(web_contents());
-  controller->ShowBubbleForLocalSave(card, callback);
+  controller->ShowBubbleForLocalSave(card, std::move(callback));
 #endif
 }
 
@@ -307,8 +307,8 @@
 }
 
 void ChromeAutofillClient::LoadRiskData(
-    const base::Callback<void(const std::string&)>& callback) {
-  ::autofill::LoadRiskData(0, web_contents(), callback);
+    base::OnceCallback<void(const std::string&)> callback) {
+  ::autofill::LoadRiskData(0, web_contents(), std::move(callback));
 }
 
 bool ChromeAutofillClient::HasCreditCardScanFeature() {
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index fc31651..907a3ab 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -72,7 +72,7 @@
   void ConfirmSaveAutofillProfile(const AutofillProfile& profile,
                                   base::OnceClosure callback) override;
   void ConfirmSaveCreditCardLocally(const CreditCard& card,
-                                    const base::Closure& callback) override;
+                                    base::OnceClosure callback) override;
   void ConfirmSaveCreditCardToCloud(
       const CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
@@ -81,7 +81,7 @@
   void ConfirmCreditCardFillAssist(const CreditCard& card,
                                    const base::Closure& callback) override;
   void LoadRiskData(
-      const base::Callback<void(const std::string&)>& callback) override;
+      base::OnceCallback<void(const std::string&)> callback) override;
   bool HasCreditCardScanFeature() override;
   void ScanCreditCard(const CreditCardScanCallback& callback) override;
   void ShowAutofillPopup(
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
index ec40074b..eefda91 100644
--- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
@@ -43,7 +43,9 @@
 
   if (!LegalMessageLine::Parse(*legal_message, &legal_message_lines_,
                                /*escape_apostrophes=*/true)) {
-    // TODO(crbug/867194): Add metric.
+    AutofillMetrics::LogLocalCardMigrationDialogOfferMetric(
+        AutofillMetrics::
+            LOCAL_CARD_MIGRATION_DIALOG_NOT_SHOWN_INVALID_LEGAL_MESSAGE);
     return;
   }
 
@@ -52,6 +54,10 @@
   migratable_credit_cards_ = migratable_credit_cards;
   view_state_ = LocalCardMigrationDialogState::kOffered;
   local_card_migration_dialog_->ShowDialog();
+  dialog_is_visible_duration_timer_ = base::ElapsedTimer();
+
+  AutofillMetrics::LogLocalCardMigrationDialogOfferMetric(
+      AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_SHOWN);
 }
 
 LocalCardMigrationDialogState
@@ -71,12 +77,21 @@
 
 void LocalCardMigrationDialogControllerImpl::OnSaveButtonClicked(
     const std::vector<std::string>& selected_cards_guids) {
-  // TODO(crbug.com/867194): Add metrics.
+  AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric(
+      dialog_is_visible_duration_timer_.Elapsed(), selected_cards_guids.size(),
+      migratable_credit_cards_.size(),
+      AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED);
+
   std::move(start_migrating_cards_callback_).Run(selected_cards_guids);
 }
 
 void LocalCardMigrationDialogControllerImpl::OnCancelButtonClicked() {
-  // TODO(crbug.com/867194): Add metrics.
+  AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric(
+      dialog_is_visible_duration_timer_.Elapsed(), 0,
+      migratable_credit_cards_.size(),
+      AutofillMetrics::
+          LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED);
+
   start_migrating_cards_callback_.Reset();
 }
 
@@ -89,6 +104,13 @@
       ui::PAGE_TRANSITION_LINK, /*is_renderer_initiated=*/false));
 }
 
+void LocalCardMigrationDialogControllerImpl::OnLegalMessageLinkClicked() {
+  AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric(
+      dialog_is_visible_duration_timer_.Elapsed(), 0,
+      migratable_credit_cards_.size(),
+      AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_LEGAL_MESSAGE_CLICKED);
+}
+
 void LocalCardMigrationDialogControllerImpl::OnDialogClosed() {
   if (local_card_migration_dialog_)
     local_card_migration_dialog_ = nullptr;
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
index a534222..f12ecdc3 100644
--- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/timer/elapsed_timer.h"
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/ui/local_card_migration_dialog_controller.h"
 #include "content/public/browser/web_contents_user_data.h"
@@ -41,6 +42,7 @@
       const std::vector<std::string>& selected_cards_guids) override;
   void OnCancelButtonClicked() override;
   void OnViewCardsButtonClicked() override;
+  void OnLegalMessageLinkClicked() override;
   void OnDialogClosed() override;
 
  protected:
@@ -68,6 +70,10 @@
   // LocalCardMigrationDialogView.
   std::vector<MigratableCreditCard> migratable_credit_cards_;
 
+  // Timer used to measure the amount of time that the local card migration
+  // dialog is visible to users.
+  base::ElapsedTimer dialog_is_visible_duration_timer_;
+
   DISALLOW_COPY_AND_ASSIGN(LocalCardMigrationDialogControllerImpl);
 };
 
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
index 2e4acce..364ba27d 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
@@ -61,7 +61,7 @@
 
 void SaveCardBubbleControllerImpl::ShowBubbleForLocalSave(
     const CreditCard& card,
-    const base::Closure& save_card_callback) {
+    base::OnceClosure save_card_callback) {
   // Don't show the bubble if it's already visible.
   if (save_card_bubble_view_)
     return;
@@ -79,7 +79,7 @@
       GetSecurityLevel());
 
   card_ = card;
-  local_save_card_callback_ = save_card_callback;
+  local_save_card_callback_ = std::move(save_card_callback);
   current_bubble_type_ = BubbleType::LOCAL_SAVE;
   ShowBubble();
 }
@@ -314,8 +314,7 @@
       can_animate_ = base::FeatureList::IsEnabled(
           features::kAutofillSaveCardSignInAfterLocalSave);
 
-      local_save_card_callback_.Run();
-      local_save_card_callback_.Reset();
+      std::move(local_save_card_callback_).Run();
       break;
     case BubbleType::MANAGE_CARDS:
       AutofillMetrics::LogManageCardsPromptMetric(
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
index c7f9a56..3792743 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
@@ -36,9 +36,8 @@
   // Sets up the controller for local save and shows the bubble.
   // |save_card_callback| will be invoked if and when the Save button is
   // pressed.
-  // TODO(crbug.com/852562): Migrate this to BindOnce/OnceClosure.
   void ShowBubbleForLocalSave(const CreditCard& card,
-                              const base::Closure& save_card_callback);
+                              base::OnceClosure save_card_callback);
 
   // Sets up the controller for upload and shows the bubble.
   // |save_card_callback| will be invoked if and when the Save button is
@@ -158,7 +157,7 @@
   // Callback to run if user presses Save button in the local save bubble. If
   // both callbacks return true for .is_null() then no bubble is available to
   // show and the icon is not visible.
-  base::Closure local_save_card_callback_;
+  base::OnceClosure local_save_card_callback_;
 
   // Governs whether the upload or local save version of the UI should be shown.
   bool is_upload_save_ = false;
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
index bceed539..061f2fe 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
@@ -114,7 +114,7 @@
     controller()->ShowBubbleForLocalSave(
         card ? CreditCard(*card)
              : autofill::test::GetCreditCard(),  // Visa by default
-        base::Bind(&LocalSaveCardCallback));
+        base::BindOnce(&LocalSaveCardCallback));
   }
 
   void ShowUploadBubble(bool should_request_name_from_user = false) {
diff --git a/chrome/browser/ui/cocoa/DEPS b/chrome/browser/ui/cocoa/DEPS
index 7a63c31..027546a 100644
--- a/chrome/browser/ui/cocoa/DEPS
+++ b/chrome/browser/ui/cocoa/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
   "+chrome/browser/ui/views",
-  "+third_party/molokocacao",  # For NSBezierPath additions.
   "+third_party/ocmock",  # For unit tests.
 ]
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 2fb2747..f5947db3 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -40,7 +40,6 @@
 #import "chrome/browser/ui/cocoa/nsmenuitem_additions.h"
 #include "chrome/browser/ui/cocoa/restart_browser.h"
 #include "chrome/browser/ui/cocoa/task_manager_mac.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/profile_chooser_constants.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index 3ffb675..5fc08776 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -47,7 +47,6 @@
 @class OverlayableContentsController;
 @class TabStripControllerCocoa;
 @class TabStripView;
-@class ToolbarController;
 
 namespace content {
 class WebContents;
@@ -70,7 +69,7 @@
   std::unique_ptr<Browser> browser_;
   NSWindow* savedRegularWindow_;
   std::unique_ptr<BrowserWindowCocoa> windowShim_;
-  base::scoped_nsobject<ToolbarController> toolbarController_;
+  std::unique_ptr<LocationBarViewMac> locationBar_;
   base::scoped_nsobject<TabStripControllerCocoa> tabStripController_;
   base::scoped_nsobject<OverlayableContentsController>
       overlayableContentsController_;
@@ -188,9 +187,6 @@
 // Access the C++ bridge between the NSWindow and the rest of Chromium.
 - (BrowserWindow*)browserWindow;
 
-// Return a weak pointer to the toolbar controller.
-- (ToolbarController*)toolbarController;
-
 // Return a weak pointer to the tab strip controller.
 - (TabStripControllerCocoa*)tabStripController;
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 679f690e..c32d730 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -55,14 +55,12 @@
 #include "chrome/browser/ui/cocoa/fullscreen_placeholder_view.h"
 #import "chrome/browser/ui/cocoa/fullscreen_window.h"
 #include "chrome/browser/ui/cocoa/l10n_util.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
-#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h"
 #import "chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
@@ -297,16 +295,8 @@
     // managing the creation of new tabs.
     [self createTabStripController];
 
-    // Create a controller for the toolbar, giving it the toolbar model object
-    // and the toolbar view from the nib. The controller will handle
-    // registering for the appropriate command state changes from the back-end.
-    // Adds the toolbar to the content area.
-    toolbarController_.reset([[ToolbarController alloc]
-        initWithCommands:browser->command_controller()
-                 profile:browser->profile()
-                 browser:browser]);
-    [[toolbarController_ toolbarView] setResizeDelegate:self];
-    [toolbarController_ setHasToolbar:[self hasToolbar] hasLocationBar:NO];
+    locationBar_.reset(new LocationBarViewMac(
+        browser_->command_controller(), browser_->profile(), browser_.get()));
 
     [self updateFullscreenCollectionBehavior];
 
@@ -378,7 +368,6 @@
   // that retains NSViewControllers and is autoreleased, so there is no way to
   // guarantee that the [super dealloc] call below will also call dealloc on the
   // controllers.
-  [toolbarController_ browserWillBeDestroyed];
   [tabStripController_ browserWillBeDestroyed];
 
   [super dealloc];
@@ -420,16 +409,12 @@
   return windowShim_.get();
 }
 
-- (ToolbarController*)toolbarController {
-  return toolbarController_.get();
-}
-
 - (TabStripControllerCocoa*)tabStripController {
   return tabStripController_.get();
 }
 
 - (LocationBarViewMac*)locationBarBridge {
-  return [toolbarController_ locationBarBridge];
+  return locationBar_.get();
 }
 
 - (NSView*)floatingBarBackingView {
@@ -810,33 +795,6 @@
   BOOL autoresizesSubviews = [chromeContentView autoresizesSubviews];
   [chromeContentView setAutoresizesSubviews:NO];
 
-  // On Yosemite the toolbar can flicker when hiding or showing the bookmarks
-  // bar. Here, |chromeContentView| is set to not autoresize its subviews during
-  // the window resize. Because |chromeContentView| is not flipped, if the
-  // window is getting shorter, the toolbar will move up within the window.
-  // Soon after, a call to layoutSubviews corrects its position. Passing NO to
-  // setFrame:display: should keep the toolbarView's intermediate position
-  // hidden, as should the prior call to disable screen updates. For some
-  // reason, neither prevents the toolbarView's intermediate position from
-  // becoming visible. Its subsequent appearance in its correct location causes
-  // the flicker. It may be that the Appkit assumes that updating the window
-  // immediately is not a big deal given that everything in it is layer-backed.
-  // Indeed, turning off layer backing for all ancestors of the toolbarView
-  // causes the flicker to go away.
-  //
-  // By shifting the toolbarView enough so that it's in its correct location
-  // immediately after the call to setFrame:display:, the toolbar will be in
-  // the right spot when the Appkit prematurely flushes the window contents to
-  // the screen. http://crbug.com/444080 .
-  if ([self hasToolbar]) {
-    NSView* toolbarView = [toolbarController_ view];
-    NSRect currentWindowFrame = [window frame];
-    NSRect toolbarViewFrame = [toolbarView frame];
-    toolbarViewFrame.origin.y += windowFrame.size.height -
-        currentWindowFrame.size.height;
-    [toolbarView setFrame:toolbarViewFrame];
-  }
-
   [window setFrame:windowFrame display:NO];
   [chromeContentView setAutoresizesSubviews:autoresizesSubviews];
   return YES;
@@ -851,7 +809,6 @@
   // If we are asked to size the bookmark
   // bar directly, its superview must be this controller's content view.
   DCHECK(view);
-  DCHECK(view == [toolbarController_ view]);
 
   // Change the height of the view and call |-layoutSubViews|. We set the height
   // here without regard to where the view is on the screen or whether it needs
@@ -878,19 +835,15 @@
 }
 
 - (void)updateToolbarWithContents:(WebContents*)tab {
-  [toolbarController_ updateToolbarWithContents:tab];
 }
 
 - (void)resetTabState:(WebContents*)tab {
-  [toolbarController_ resetTabState:tab];
 }
 
 - (void)setStarredState:(BOOL)isStarred {
-  [toolbarController_ setStarredState:isStarred];
 }
 
 - (void)setCurrentPageIsTranslated:(BOOL)on {
-  [toolbarController_ setTranslateIconLit:on];
 }
 
 - (void)onActiveTabChanged:(content::WebContents*)oldContents
@@ -902,7 +855,6 @@
 }
 
 - (void)zoomChangedForActiveTab:(BOOL)canShowBubble {
-  [toolbarController_ zoomChangedForActiveTab:canShowBubble];
 }
 
 // Accept tabs from a BrowserWindowController with the same Profile.
@@ -1015,7 +967,6 @@
 }
 
 - (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
-  [toolbarController_ setIsLoading:isLoading force:force];
 }
 
 - (void)firstResponderUpdated:(NSResponder*)responder {
@@ -1279,12 +1230,6 @@
     [[self fullscreenToolbarController]
         revealToolbarForWebContents:contents
                        inForeground:inForeground];
-
-  if (inForeground) {
-    AppToolbarButton* appMenuButton =
-        static_cast<AppToolbarButton*>([toolbarController_ appMenuButton]);
-    [appMenuButton animateIfPossibleWithDelay:YES];
-  }
 }
 
 - (void)userChangedTheme {
@@ -1405,9 +1350,7 @@
 
 // Delegate method: see |NSWindowDelegate| protocol.
 - (id)windowWillReturnFieldEditor:(NSWindow*)sender toObject:(id)obj {
-  // Ask the toolbar controller if it wants to return a custom field editor
-  // for the specific object.
-  return [toolbarController_ customFieldEditorForObject:obj];
+  return nil;
 }
 
 // (Private/TestingAPI)
@@ -1440,17 +1383,7 @@
 
 // (Private/TestingAPI)
 - (NSRect)omniboxPopupAnchorRect {
-  // Start with toolbar rect.
-  NSView* toolbarView = [toolbarController_ view];
-  NSRect anchorRect = [toolbarView frame];
-
-  // Adjust to account for height and possible bookmark bar. Compress by 1
-  // to account for the separator.
-  anchorRect.origin.y =
-      NSMaxY(anchorRect) - [toolbarController_ desiredHeightForCompression:1];
-
-  // Shift to window base coordinates.
-  return [[toolbarView superview] convertRect:anchorRect toView:nil];
+  return NSZeroRect;
 }
 
 - (BOOL)isLayoutSubviewsBlocked {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index bdf54b92..8ac73da 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -34,7 +34,6 @@
 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
@@ -178,14 +177,10 @@
 willPositionSheet:(NSWindow*)sheet
        usingRect:(NSRect)defaultSheetLocation {
   CGFloat defaultSheetY = defaultSheetLocation.origin.y;
-  if ([self hasToolbar]) {
-    defaultSheetY = NSMinY([[toolbarController_ view] frame]);
-  } else {
-    // The toolbar is not shown in popup and application modes. The sheet
-    // should be located at the top of the window, under the title of the
-    // window.
-    defaultSheetY = NSMaxY([[window contentView] frame]);
-  }
+  // The toolbar is not shown in popup and application modes. The sheet
+  // should be located at the top of the window, under the title of the
+  // window.
+  defaultSheetY = NSMaxY([[window contentView] frame]);
 
   // AppKit may shift the window up to fit the sheet on screen, but it will
   // never adjust the height of the sheet, or the origin of the sheet relative
@@ -223,8 +218,6 @@
   [self updateLayoutParameters:layout];
   [self applyLayout:layout];
 
-  [toolbarController_ setDividerOpacity:[self toolbarDividerOpacity]];
-
   // Will update the location of the permission bubble when showing/hiding the
   // top level toolbar in fullscreen.
   [self updatePermissionBubbleAnchor];
@@ -280,17 +273,6 @@
 }
 
 - (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression {
-  CGFloat newHeight =
-      [toolbarController_ desiredHeightForCompression:compression];
-  NSRect toolbarFrame = [[toolbarController_ view] frame];
-  CGFloat deltaH = newHeight - toolbarFrame.size.height;
-
-  if (deltaH == 0)
-    return;
-
-  toolbarFrame.size.height = newHeight;
-  [[toolbarController_ view] setFrame:toolbarFrame];
-  [self layoutSubviews];
 }
 
 // Fullscreen methods
@@ -824,7 +806,6 @@
   [layout setFullscreenButtonFrame:[self fullscreenButtonFrame]];
 
   [layout setHasToolbar:[self hasToolbar]];
-  [layout setToolbarHeight:NSHeight([[toolbarController_ view] bounds])];
 }
 
 - (void)applyLayout:(BrowserWindowLayout*)layout {
@@ -833,9 +814,6 @@
   if (!NSIsEmptyRect(output.tabStripLayout.frame))
     [self applyTabStripLayout:output.tabStripLayout];
 
-  if (!NSIsEmptyRect(output.toolbarFrame))
-    [[toolbarController_ view] setFrame:output.toolbarFrame];
-
   [self layoutTabContentArea:output.contentAreaFrame];
 
   if (!NSIsEmptyRect(output.fullscreenBackingBarFrame)) {
@@ -854,8 +832,6 @@
 
 - (void)updateSubviewZOrderNormal {
   base::scoped_nsobject<NSMutableArray> subviews([[NSMutableArray alloc] init]);
-  if ([toolbarController_ view])
-    [subviews addObject:[toolbarController_ view]];
   if ([self tabContentArea])
     [subviews addObject:[self tabContentArea]];
 
@@ -871,9 +847,6 @@
   if (floatingBarBackingView_)
     [subviews addObject:floatingBarBackingView_];
 
-  if ([toolbarController_ view])
-    [subviews addObject:[toolbarController_ view]];
-
   [self setContentViewSubviews:subviews];
 }
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
index 1079058..0381b49 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
 #include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/prefs/pref_service.h"
@@ -39,16 +38,11 @@
 
 @interface BrowserWindowController (ExposedForTesting)
 // Implementations are below.
-- (NSView*)toolbarView;
 - (void)dontFocusLocationBar:(BOOL)selectAll;
 @end
 
 @implementation BrowserWindowController (ExposedForTesting)
 
-- (NSView*)toolbarView {
-  return [toolbarController_ view];
-}
-
 - (void)dontFocusLocationBar:(BOOL)selectAll {
 }
 @end
@@ -170,11 +164,6 @@
 
 namespace {
 
-// Returns the frame of the view in window coordinates.
-NSRect FrameInWindowForView(NSView* view) {
-  return [[view superview] convertRect:[view frame] toView:nil];
-}
-
 // Whether the view's frame is within the bounds of the superview.
 BOOL ViewContainmentValid(NSView* view) {
   if (NSIsEmptyRect([view frame]))
@@ -210,13 +199,6 @@
 // completely fill the area under the tabstrip.
 void CheckViewPositions(BrowserWindowController* controller) {
   EXPECT_TRUE(ViewHierarchyContainmentValid([[controller window] contentView]));
-
-  NSRect tabstrip = FrameInWindowForView([controller tabStripView]);
-  NSRect toolbar = FrameInWindowForView([controller toolbarView]);
-
-  // Toolbar should start immediately under the tabstrip, but the tabstrip is
-  // not necessarily fixed with respect to the content view.
-  EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar));
 }
 
 }  // end namespace
@@ -351,7 +333,6 @@
 TEST_F(BrowserWindowControllerTest, TestResizeViews) {
   TabStripView* tabstrip = [controller_ tabStripView];
   NSView* contentView = [[tabstrip window] contentView];
-  NSView* toolbar = [controller_ toolbarView];
 
   // We need to muck with the views a bit to put us in a consistent state before
   // we start resizing.  In particular, we need to move the tab strip to be
@@ -364,14 +345,6 @@
   // Force a layout and check each view's frame.
   [controller_ layoutSubviews];
   CheckViewPositions(controller_);
-
-  // Expand the toolbar to 64px and recheck
-  [controller_ resizeView:toolbar newHeight:64];
-  CheckViewPositions(controller_);
-
-  // Shrink the infobar to 0px and toolbar to 39px and recheck
-  [controller_ resizeView:toolbar newHeight:39];
-  CheckViewPositions(controller_);
 }
 
 // By the "zoom frame", we mean what Apple calls the "standard frame".
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell.h b/chrome/browser/ui/cocoa/clickhold_button_cell.h
deleted file mode 100644
index a845b267..0000000
--- a/chrome/browser/ui/cocoa/clickhold_button_cell.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_CLICKHOLD_BUTTON_CELL_H_
-#define CHROME_BROWSER_UI_COCOA_CLICKHOLD_BUTTON_CELL_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/ui/cocoa/image_button_cell.h"
-
-// A button cell that implements "click hold" behavior after a specified delay
-// or after dragging. If click-hold is never enabled (e.g., if
-// |-setEnableClickHold:| is never called), this behaves like a normal button.
-@interface ClickHoldButtonCell : ImageButtonCell {
- @private
-  BOOL enableClickHold_;
-  BOOL enableRightClick_;
-  NSTimeInterval clickHoldTimeout_;
-  id clickHoldTarget_;                  // Weak.
-  SEL clickHoldAction_;
-  id accessibilityShowMenuTarget_;                  // Weak.
-  SEL accessibilityShowMenuAction_;
-  BOOL trackOnlyInRect_;
-  BOOL activateOnDrag_;
-}
-
-// Enable click-hold? Default: NO.
-@property(assign, nonatomic) BOOL enableClickHold;
-
-// Enable right click? Default: NO. Needs to be set for accessibility.
-@property(assign, nonatomic) BOOL enableRightClick;
-
-// Timeout is in seconds (at least 0.0, at most 5; 0.0 means that the button
-// will always have its click-hold action activated immediately on press).
-// Default: 0.25 (a guess at a Cocoa-ish value).
-@property(assign, nonatomic) NSTimeInterval clickHoldTimeout;
-
-// Track only in the frame rectangle? Default: NO.
-@property(assign, nonatomic) BOOL trackOnlyInRect;
-
-// Activate (click-hold) immediately on a sufficiently-large drag (if not,
-// always wait for timeout)? Default: YES.
-@property(assign, nonatomic) BOOL activateOnDrag;
-
-// Defines what to do when click-held (as per usual action/target).
-@property(assign, nonatomic) id clickHoldTarget;
-@property(assign, nonatomic) SEL clickHoldAction;
-
-// Defines what to do when the Show Menu accessibility action is performed.
-// (clickHoldAction should be independent from accessibilityShowMenuAction
-// since different operations, e.g. releasing vs. not releasing a mouse button,
-// may need to be performed for each occasion.)
-@property(assign, nonatomic) id accessibilityShowMenuTarget;
-@property(assign, nonatomic) SEL accessibilityShowMenuAction;
-
-@end  // @interface ClickHoldButtonCell
-
-#endif  // CHROME_BROWSER_UI_COCOA_CLICKHOLD_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell.mm b/chrome/browser/ui/cocoa/clickhold_button_cell.mm
deleted file mode 100644
index c26a7f4..0000000
--- a/chrome/browser/ui/cocoa/clickhold_button_cell.mm
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/clickhold_button_cell.h"
-
-#include "base/logging.h"
-
-// Minimum and maximum click-hold timeout.
-static const NSTimeInterval kMinTimeout = 0.0;
-static const NSTimeInterval kMaxTimeout = 5.0;
-
-// Drag distance threshold to activate click-hold; should be >= 0.
-static const CGFloat kDragDistThreshold = 2.5;
-
-// See |-resetToDefaults| (and header file) for other default values.
-
-@interface ClickHoldButtonCell (Private)
-- (void)resetToDefaults;
-- (BOOL)shouldExposeAccessibilityShowMenu;
-- (id)accessibilityAttributeValue:(NSString*)attribute;
-@end  // @interface ClickHoldButtonCell (Private)
-
-@implementation ClickHoldButtonCell
-
-@synthesize enableClickHold = enableClickHold_;
-@synthesize enableRightClick = enableRightClick_;
-@synthesize clickHoldTimeout = clickHoldTimeout_;
-@synthesize trackOnlyInRect = trackOnlyInRect_;
-@synthesize activateOnDrag = activateOnDrag_;
-@synthesize clickHoldTarget = clickHoldTarget_;
-@synthesize clickHoldAction = clickHoldAction_;
-@synthesize accessibilityShowMenuTarget = accessibilityShowMenuTarget_;
-@synthesize accessibilityShowMenuAction = accessibilityShowMenuAction_;
-
-// Overrides:
-
-+ (BOOL)prefersTrackingUntilMouseUp {
-  return NO;
-}
-
-- (id)init {
-  if ((self = [super init]))
-    [self resetToDefaults];
-  return self;
-}
-
-- (id)initWithCoder:(NSCoder*)decoder {
-  if ((self = [super initWithCoder:decoder]))
-    [self resetToDefaults];
-  return self;
-}
-
-- (id)initImageCell:(NSImage*)image {
-  if ((self = [super initImageCell:image]))
-    [self resetToDefaults];
-  return self;
-}
-
-- (id)initTextCell:(NSString*)string {
-  if ((self = [super initTextCell:string]))
-    [self resetToDefaults];
-  return self;
-}
-
-- (void)accessibilityPerformAction:(NSString*)action {
-  if ([action isEqualToString:NSAccessibilityShowMenuAction] &&
-      [self shouldExposeAccessibilityShowMenu]) {
-    NSControl* controlView = static_cast<NSControl*>([self controlView]);
-    if (controlView)
-      [controlView sendAction:accessibilityShowMenuAction_
-                           to:accessibilityShowMenuTarget_];
-    return;
-  }
-
-  [super accessibilityPerformAction:action];
-}
-
-- (BOOL)startTrackingAt:(NSPoint)startPoint
-                 inView:(NSView*)controlView {
-  return enableClickHold_ ? YES :
-                            [super startTrackingAt:startPoint
-                                            inView:controlView];
-}
-
-- (BOOL)continueTracking:(NSPoint)lastPoint
-                      at:(NSPoint)currentPoint
-                  inView:(NSView*)controlView {
-  return enableClickHold_ ? YES :
-                            [super continueTracking:lastPoint
-                                                 at:currentPoint
-                                             inView:controlView];
-}
-
-- (BOOL)trackMouse:(NSEvent*)originalEvent
-            inRect:(NSRect)cellFrame
-            ofView:(NSView*)controlView
-      untilMouseUp:(BOOL)untilMouseUp {
-  if (!enableClickHold_) {
-    return [super trackMouse:originalEvent
-                      inRect:cellFrame
-                      ofView:controlView
-                untilMouseUp:untilMouseUp];
-  }
-
-  // If doing click-hold, track the mouse ourselves.
-  NSPoint currPoint = [controlView convertPoint:[originalEvent locationInWindow]
-                                       fromView:nil];
-  NSPoint lastPoint = currPoint;
-  NSPoint firstPoint = currPoint;
-  NSTimeInterval timeout =
-      MAX(MIN(clickHoldTimeout_, kMaxTimeout), kMinTimeout);
-  NSDate* clickHoldBailTime = [NSDate dateWithTimeIntervalSinceNow:timeout];
-
-  if (![self startTrackingAt:currPoint inView:controlView])
-    return NO;
-
-  enum {
-    kContinueTrack, kStopClickHold, kStopMouseUp, kStopLeftRect, kStopNoContinue
-  } state = kContinueTrack;
-  do {
-    NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask |
-                                                   NSLeftMouseUpMask)
-                                        untilDate:clickHoldBailTime
-                                           inMode:NSEventTrackingRunLoopMode
-                                          dequeue:YES];
-    currPoint = [controlView convertPoint:[event locationInWindow]
-                                 fromView:nil];
-
-    // Time-out.
-    if (!event) {
-      state = kStopClickHold;
-
-    // Drag? (If distance meets threshold.)
-    } else if (activateOnDrag_ && ([event type] == NSLeftMouseDragged)) {
-      CGFloat dx = currPoint.x - firstPoint.x;
-      CGFloat dy = currPoint.y - firstPoint.y;
-      if ((dx*dx + dy*dy) >= (kDragDistThreshold*kDragDistThreshold))
-        state = kStopClickHold;
-
-    // Mouse up.
-    } else if ([event type] == NSLeftMouseUp) {
-      state = kStopMouseUp;
-
-    // Stop tracking if mouse left frame rectangle (if requested to do so).
-    } else if (trackOnlyInRect_ && ![controlView mouse:currPoint
-                                                inRect:cellFrame]) {
-      state = kStopLeftRect;
-
-    // Stop tracking if instructed to.
-    } else if (![self continueTracking:lastPoint
-                                    at:currPoint
-                                inView:controlView]) {
-      state = kStopNoContinue;
-    }
-
-    lastPoint = currPoint;
-  } while (state == kContinueTrack);
-
-  [self stopTracking:lastPoint
-                  at:lastPoint
-              inView:controlView
-           mouseIsUp:NO];
-
-  switch (state) {
-    case kStopClickHold:
-      if (clickHoldAction_) {
-        [static_cast<NSControl*>(controlView) sendAction:clickHoldAction_
-                                                      to:clickHoldTarget_];
-      }
-      return YES;
-
-    case kStopMouseUp:
-      if ([self action]) {
-        [static_cast<NSControl*>(controlView) sendAction:[self action]
-                                                      to:[self target]];
-      }
-      return YES;
-
-    case kStopLeftRect:
-    case kStopNoContinue:
-      return NO;
-
-    default:
-      NOTREACHED() << "Unknown terminating state!";
-  }
-
-  return NO;
-}
-
-// Accessors and mutators:
-
-- (NSArray*)accessibilityActionNames {
-  NSArray* actionNames = [super accessibilityActionNames];
-  if ([self shouldExposeAccessibilityShowMenu] &&
-      ![actionNames containsObject:NSAccessibilityShowMenuAction]) {
-    return [actionNames arrayByAddingObject:NSAccessibilityShowMenuAction];
-  }
-
-  return actionNames;
-}
-
-@end  // @implementation ClickHoldButtonCell
-
-@implementation ClickHoldButtonCell (Private)
-
-// Resets various members to defaults indicated in the header file. (Those
-// without indicated defaults are *not* touched.) Please keep the values below
-// in sync with the header file, and please be aware of side-effects on code
-// which relies on the "published" defaults.
-- (void)resetToDefaults {
-  [self setEnableClickHold:NO];
-  [self setClickHoldTimeout:0.25];
-  [self setTrackOnlyInRect:NO];
-  [self setActivateOnDrag:YES];
-}
-
-- (BOOL)shouldExposeAccessibilityShowMenu {
-  return (enableRightClick_ ||
-      (enableClickHold_ && clickHoldTimeout_ > kMinTimeout)) &&
-      accessibilityShowMenuAction_ && accessibilityShowMenuTarget_;
-}
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
-  if ([attribute isEqual:NSAccessibilityRoleAttribute] &&
-      [self clickHoldTimeout] == 0.0) {
-    // When the delay is set to zero, this button operates like a popup button
-    // from a user perspective.
-    return NSAccessibilityPopUpButtonRole;
-  }
-  return [super accessibilityAttributeValue:attribute];
-}
-
-@end  // @implementation ClickHoldButtonCell (Private)
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm b/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
deleted file mode 100644
index 276c4ce..0000000
--- a/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright (c) 2011 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 <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-@interface ClickHoldButtonCellTestTarget : NSObject {
- @private
-  BOOL didOpen_;
-}
-- (void)open;
-- (BOOL)didOpen;
-@end
-
-@implementation ClickHoldButtonCellTestTarget
-- (instancetype)init {
-  if ((self = [super init]))
-    didOpen_ = NO;
-
-  return self;
-}
-
-- (void)open {
-  didOpen_ = YES;
-}
-
-- (BOOL)didOpen {
-  return didOpen_;
-}
-@end
-
-namespace {
-
-class ClickHoldButtonCellTest : public CocoaTest {
- public:
-  ClickHoldButtonCellTest() {
-    NSRect frame = NSMakeRect(0, 0, 50, 30);
-    base::scoped_nsobject<NSButton> view(
-        [[NSButton alloc] initWithFrame:frame]);
-    view_ = view.get();
-    base::scoped_nsobject<ClickHoldButtonCell> cell(
-        [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
-    [view_ setCell:cell.get()];
-    [[test_window() contentView] addSubview:view_];
-  }
-
-  NSButton* view_;
-};
-
-TEST_VIEW(ClickHoldButtonCellTest, view_)
-
-// Test default values; make sure they are what they should be.
-TEST_F(ClickHoldButtonCellTest, Defaults) {
-  ClickHoldButtonCell* cell = static_cast<ClickHoldButtonCell*>([view_ cell]);
-  ASSERT_TRUE([cell isKindOfClass:[ClickHoldButtonCell class]]);
-
-  EXPECT_FALSE([cell enableClickHold]);
-
-  NSTimeInterval clickHoldTimeout = [cell clickHoldTimeout];
-  EXPECT_GE(clickHoldTimeout, 0.15);  // Check for a "Cocoa-ish" value.
-  EXPECT_LE(clickHoldTimeout, 0.35);
-
-  EXPECT_FALSE([cell trackOnlyInRect]);
-  EXPECT_TRUE([cell activateOnDrag]);
-}
-
-// TODO(viettrungluu): (1) Enable click-hold and figure out how to test the
-// tracking loop (i.e., |-trackMouse:...|), which is the nontrivial part.
-// (2) Test various initialization code paths (in particular, loading from nib).
-
-TEST_F(ClickHoldButtonCellTest, AccessibilityShowMenu) {
-  ClickHoldButtonCell* cell = static_cast<ClickHoldButtonCell*>([view_ cell]);
-  ASSERT_TRUE([cell isKindOfClass:[ClickHoldButtonCell class]]);
-
-  ClickHoldButtonCellTestTarget* cellTarget =
-      [[[ClickHoldButtonCellTestTarget alloc] init] autorelease];
-  ASSERT_NSNE(nil, cellTarget);
-  ASSERT_TRUE([cellTarget respondsToSelector:@selector(open)]);
-  ASSERT_FALSE([cellTarget didOpen]);
-
-  [cell setEnableClickHold:NO];
-
-  NSArray* actionNames = [cell accessibilityActionNames];
-  EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-
-  [cell setEnableClickHold:YES];
-
-  // There is no action set.
-  actionNames = [cell accessibilityActionNames];
-  EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-
-  // clickHoldAction should be independent from accessibilityShowMenuAction
-  // since different operations, e.g. releasing vs. not releasing a mouse
-  // button, may need to be performed for each occasion.
-  [cell setClickHoldAction:@selector(open)];
-  [cell setClickHoldTarget:cellTarget];
-
-  actionNames = [cell accessibilityActionNames];
-  EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-  EXPECT_FALSE([cellTarget didOpen]);
-
-  // Even when accessibilityShowMenuAction is set, no action should be available
-  // if neither enableClickHold nor enableRightClickHold are true.
-  [cell setEnableClickHold:NO];
-  [cell setAccessibilityShowMenuAction:@selector(open)];
-  [cell setAccessibilityShowMenuTarget:cellTarget];
-
-  actionNames = [cell accessibilityActionNames];
-  EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-
-  // Now the action should be available.
-  [cell setEnableClickHold:YES];
-
-  actionNames = [cell accessibilityActionNames];
-  EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-
-  [cell setEnableClickHold:NO];
-  [cell setEnableRightClick:YES];
-
-  actionNames = [cell accessibilityActionNames];
-  EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-
-  [cell accessibilityPerformAction:NSAccessibilityShowMenuAction];
-  EXPECT_TRUE([cellTarget didOpen]);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h
deleted file mode 100644
index 4365413..0000000
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_ALERT_H_
-#define CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_ALERT_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-
-// This class implements an alert that has a constrained window look and feel
-// (close button on top right, WebUI style buttons, etc...).  The alert can be
-// shown by using the window accessor and calling -[window orderFont:]. Normally
-// this would be done by ConstrainedWindowSheetController.
-@interface ConstrainedWindowAlert : NSObject {
- @private
-  base::scoped_nsobject<NSTextField> informativeTextField_;
-  base::scoped_nsobject<NSTextField> messageTextField_;
-  base::scoped_nsobject<NSButton> linkView_;
-  base::scoped_nsobject<NSView> accessoryView_;
-  base::scoped_nsobject<NSMutableArray> buttons_;
-  base::scoped_nsobject<NSButton> closeButton_;
-  base::scoped_nsobject<NSWindow> window_;
-}
-
-@property(nonatomic, copy) NSString* informativeText;
-@property(nonatomic, copy) NSString* messageText;
-@property(nonatomic, retain) NSView* accessoryView;
-@property(nonatomic, readonly) NSArray* buttons;
-@property(nonatomic, readonly) NSButton* closeButton;
-@property(nonatomic, readonly) NSWindow* window;
-
-// Default initializer.
-- (id)init;
-
-// Adds a button with the given |title|. Newly added buttons are positioned in
-// order from right to left.
-- (void)addButtonWithTitle:(NSString*)title
-             keyEquivalent:(NSString*)keyEquivalent
-                    target:(id)target
-                    action:(SEL)action;
-
-// Sets the |text|, the |target| and the |action| of a left-aligned link
-// positioned above the buttons. If |text| is empty, no link is displayed.
-- (void)setLinkText:(NSString*)text
-             target:(id)target
-             action:(SEL)action;
-
-// Lays out the controls in the alert. This should be called before the window
-// is displayed.
-- (void)layout;
-
-@end
-
-@interface ConstrainedWindowAlert (ExposedForTesting)
-@property(nonatomic, readonly) NSButton* linkView;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_ALERT_H_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm
deleted file mode 100644
index cbcdbbc2..0000000
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h"
-
-#import "base/logging.h"
-#import "chrome/browser/ui/cocoa/chrome_style.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_control_utils.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
-#import "chrome/browser/ui/cocoa/hover_close_button.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-#include "ui/base/cocoa/controls/hyperlink_button_cell.h"
-#include "ui/base/cocoa/window_size_constants.h"
-
-namespace {
-
-const CGFloat kConstrainedWindowMinWidth = 500;
-const CGFloat kConstrainedWindowButtonGap = 6;
-
-}  // namespace
-
-@interface ConstrainedWindowAlert ()
-// Position the alert buttons within the given window width.
-- (void)layoutButtonsWithWindowWidth:(CGFloat)windowWidth;
-// Resize the given text field to fit within the window and position it starting
-// at |yPos|. Returns the new value of yPos.
-- (CGFloat)layoutTextField:(NSTextField*)textField
-                      yPos:(CGFloat)yPos
-               windowWidth:(CGFloat)windowWidth;
-// If a link has been set, resizes the link to fit within the window and
-// position it starting at |yPos|. Returns the new value of yPos.
-- (CGFloat)layoutLinkAtYPos:(CGFloat)yPos
-                windowWidth:(CGFloat)windowWidth;
-// Positions the accessory view starting at yPos. Returns the new value of yPos.
-- (CGFloat)layoutAccessoryViewAtYPos:(CGFloat)yPos;
-// Update the position of the close button.
-- (void)layoutCloseButtonWithWindowWidth:(CGFloat)windowWidth
-                            windowHeight:(CGFloat)windowHeight;
-@end
-
-@implementation ConstrainedWindowAlert
-
-- (id)init {
-  if ((self = [super init])) {
-    window_.reset([[ConstrainedWindowCustomWindow alloc]
-        initWithContentRect:ui::kWindowSizeDeterminedLater]);
-    NSView* contentView = [window_ contentView];
-
-    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-
-    informativeTextField_.reset([constrained_window::CreateLabel() retain]);
-    [informativeTextField_ setSelectable:YES];
-    [informativeTextField_ setAlignment:NSNaturalTextAlignment];
-    if (@available(macOS 10.10, *)) {
-      [informativeTextField_ setLineBreakMode:NSLineBreakByWordWrapping];
-    } else {
-      [[informativeTextField_ cell] setLineBreakMode:NSLineBreakByWordWrapping];
-    }
-    [informativeTextField_
-        setFont:rb.GetFont(chrome_style::kTextFontStyle).GetNativeFont()];
-    [contentView addSubview:informativeTextField_];
-
-    messageTextField_.reset([constrained_window::CreateLabel() retain]);
-    [messageTextField_ setSelectable:YES];
-    [messageTextField_ setAlignment:NSNaturalTextAlignment];
-    if (@available(macOS 10.10, *)) {
-      [messageTextField_ setLineBreakMode:NSLineBreakByWordWrapping];
-    } else {
-      [[messageTextField_ cell] setLineBreakMode:NSLineBreakByWordWrapping];
-    }
-    [messageTextField_
-        setFont:rb.GetFont(chrome_style::kTitleFontStyle).GetNativeFont()];
-    [contentView addSubview:messageTextField_];
-
-    closeButton_.reset(
-        [[WebUIHoverCloseButton alloc] initWithFrame:NSZeroRect]);
-    [contentView addSubview:closeButton_];
-  }
-  return self;
-}
-
-- (NSString*)informativeText {
-  return [informativeTextField_ stringValue];
-}
-
-- (void)setInformativeText:(NSString*)string {
-  [informativeTextField_ setStringValue:string];
-}
-
-- (NSString*)messageText {
-  return [messageTextField_ stringValue];
-}
-
-- (void)setMessageText:(NSString*)string {
-  [messageTextField_ setStringValue:string];
-}
-
-- (void)setLinkText:(NSString*)text target:(id)target action:(SEL)action {
-  if (![text length]) {
-    [linkView_ removeFromSuperview];
-    linkView_.reset(nil);
-    return;
-  }
-
-  if (!linkView_.get()) {
-    linkView_.reset(
-        [[HyperlinkButtonCell buttonWithString:[NSString string]] retain]);
-    [[window_ contentView] addSubview:linkView_];
-  }
-
-  [linkView_ setTitle:text];
-  [linkView_ setTarget:target];
-  [linkView_ setAction:action];
-}
-
-- (NSView*)accessoryView {
-  return accessoryView_;
-}
-
-- (void)setAccessoryView:(NSView*)accessoryView {
-  [accessoryView_ removeFromSuperview];
-  accessoryView_.reset([accessoryView retain]);
-  [[window_ contentView] addSubview:accessoryView_];
-}
-
-- (NSArray*)buttons {
-  return buttons_;
-}
-
-- (NSButton*)closeButton {
-  return closeButton_;
-}
-
-- (NSWindow*)window {
-  return window_;
-}
-
-- (void)addButtonWithTitle:(NSString*)title
-             keyEquivalent:(NSString*)keyEquivalent
-                    target:(id)target
-                    action:(SEL)action {
-  if (!buttons_.get())
-    buttons_.reset([[NSMutableArray alloc] init]);
-  base::scoped_nsobject<NSButton> button(
-      [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
-  [button setTitle:title];
-  [button setKeyEquivalent:keyEquivalent];
-  [button setTarget:target];
-  [button setAction:action];
-  [buttons_ addObject:button];
-  [[window_ contentView] addSubview:button];
-}
-
-- (void)layout {
-  // Button width.
-  CGFloat buttonWidth = 0;
-  for (NSButton* button in buttons_.get()) {
-    [button sizeToFit];
-    NSSize size = [button frame].size;
-    buttonWidth += size.width;
-  }
-  if ([buttons_ count])
-    buttonWidth += ([buttons_ count] - 1) * kConstrainedWindowButtonGap;
-
-  // Window width.
-  CGFloat windowWidth = buttonWidth;
-  if (accessoryView_.get())
-    windowWidth = std::max(windowWidth, NSWidth([accessoryView_ frame]));
-  windowWidth += chrome_style::kHorizontalPadding * 2;
-  windowWidth = std::max(windowWidth, kConstrainedWindowMinWidth);
-
-  // Layout controls.
-  [self layoutButtonsWithWindowWidth:windowWidth];
-  CGFloat curY = [buttons_ count] ? NSMaxY([[buttons_ lastObject] frame])
-      : chrome_style::kClientBottomPadding;
-  CGFloat availableMessageWidth = windowWidth -
-                                  chrome_style::GetCloseButtonSize() -
-                                  kConstrainedWindowButtonGap;
-  curY = [self layoutLinkAtYPos:curY
-                    windowWidth:availableMessageWidth];
-  curY = [self layoutAccessoryViewAtYPos:curY];
-  curY = [self layoutTextField:informativeTextField_
-                          yPos:curY
-                   windowWidth:windowWidth];
-  curY = [self layoutTextField:messageTextField_
-                          yPos:curY
-                   windowWidth:availableMessageWidth];
-
-  CGFloat windowHeight = curY + chrome_style::kTitleTopPadding;
-  [self layoutCloseButtonWithWindowWidth:windowWidth
-                            windowHeight:windowHeight];
-
-  // Update window frame.
-  NSRect windowFrame = NSMakeRect(0, 0, windowWidth, windowHeight);
-  windowFrame = [window_ frameRectForContentRect:windowFrame];
-  [window_ setFrame:windowFrame display:NO];
-}
-
-- (void)layoutButtonsWithWindowWidth:(CGFloat)windowWidth {
-  // Layout first 2 button right to left.
-  CGFloat curX = windowWidth - chrome_style::kHorizontalPadding;
-  const int buttonCount = [buttons_ count];
-  for (int i = 0; i < std::min(2, buttonCount); ++i) {
-    NSButton* button = [buttons_ objectAtIndex:i];
-    NSRect rect = [button frame];
-    rect.origin.x = curX - NSWidth(rect);
-    rect.origin.y = chrome_style::kClientBottomPadding;
-    [button setFrameOrigin:rect.origin];
-    curX = NSMinX(rect) - kConstrainedWindowButtonGap;
-  }
-
-  // Layout remaining buttons left to right.
-  curX = chrome_style::kHorizontalPadding;
-  for (int i = buttonCount - 1; i >= 2; --i) {
-    NSButton* button = [buttons_ objectAtIndex:i];
-    [button setFrameOrigin:
-        NSMakePoint(curX, chrome_style::kClientBottomPadding)];
-    curX += NSMaxX([button frame]) + kConstrainedWindowButtonGap;
-  }
-}
-
-- (CGFloat)layoutTextField:(NSTextField*)textField
-                      yPos:(CGFloat)yPos
-               windowWidth:(CGFloat)windowWidth {
-  if (![[textField stringValue] length]) {
-    [textField setHidden:YES];
-    return yPos;
-  }
-
-  [textField setHidden:NO];
-  NSRect rect;
-  rect.origin.y = yPos + chrome_style::kRowPadding;
-  rect.origin.x = chrome_style::kHorizontalPadding;
-  rect.size.width = windowWidth -
-      chrome_style::kHorizontalPadding * 2;
-  rect.size.height = 1;
-  [textField setFrame:rect];
-  [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
-  return NSMaxY([textField frame]);
-}
-
-- (CGFloat)layoutLinkAtYPos:(CGFloat)yPos
-                windowWidth:(CGFloat)windowWidth {
-  if (!linkView_.get())
-    return yPos;
-
-  NSRect availableBounds = NSMakeRect(
-      0,
-      0,
-      windowWidth - chrome_style::kHorizontalPadding * 2,
-      CGFLOAT_MAX);
-  NSSize size = [[linkView_ cell] cellSizeForBounds:availableBounds];
-
-  NSRect rect;
-  rect.origin.y = yPos + chrome_style::kRowPadding;
-  rect.origin.x = chrome_style::kHorizontalPadding;
-  rect.size = size;
-  [linkView_ setFrame:rect];
-  return NSMaxY([linkView_ frame]);
-}
-
-- (CGFloat)layoutAccessoryViewAtYPos:(CGFloat)yPos {
-  if (!accessoryView_.get())
-    return yPos;
-  NSRect frame = [accessoryView_ frame];
-  frame.origin.y = yPos + chrome_style::kRowPadding;
-  frame.origin.x = chrome_style::kHorizontalPadding;
-  [accessoryView_ setFrameOrigin:frame.origin];
-  return NSMaxY(frame);
-}
-
-- (void)layoutCloseButtonWithWindowWidth:(CGFloat)windowWidth
-                            windowHeight:(CGFloat)windowHeight {
-  NSRect frame;
-  frame.size.width = chrome_style::GetCloseButtonSize();
-  frame.size.height = chrome_style::GetCloseButtonSize();
-  frame.origin.x = windowWidth -
-      chrome_style::kCloseButtonPadding - NSWidth(frame);
-  frame.origin.y = windowHeight -
-      chrome_style::kCloseButtonPadding - NSHeight(frame);
-  [closeButton_ setFrame:frame];
-}
-
-- (NSButton*)linkView {
-  return linkView_;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm
deleted file mode 100644
index 87e29ce..0000000
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h"
-
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#import "testing/gtest_mac.h"
-
-class ConstrainedWindowAlertTest : public CocoaTest {
-};
-
-@interface ConstrainedWindowAlertTestTarget : NSObject {
- @private
-  int linkClickedCount_;
-}
-@property(nonatomic, readonly) int linkClickedCount;
-
-- (void)onLinkClicked:(id)sender;
-@end
-
-@implementation ConstrainedWindowAlertTestTarget
-
-@synthesize linkClickedCount = linkClickedCount_;
-
-- (void)onLinkClicked:(id)sender {
-  ++linkClickedCount_;
-}
-
-@end
-
-// Test showing the alert.
-TEST_F(ConstrainedWindowAlertTest, Show) {
-  base::scoped_nsobject<ConstrainedWindowAlert> alert(
-      [[ConstrainedWindowAlert alloc] init]);
-  EXPECT_TRUE([alert window]);
-  EXPECT_TRUE([alert closeButton]);
-
-  [alert setMessageText:@"Message text"];
-  [alert setInformativeText:@"Informative text"];
-  [alert addButtonWithTitle:@"OK" keyEquivalent:@"" target:nil action:NULL];
-  [alert addButtonWithTitle:@"Cancel" keyEquivalent:@"" target:nil action:NULL];
-
-  [alert layout];
-  [[alert window] makeKeyAndOrderFront:nil];
-}
-
-// Test showing the alert with no buttons.
-TEST_F(ConstrainedWindowAlertTest, NoButtons) {
-  base::scoped_nsobject<ConstrainedWindowAlert> alert(
-      [[ConstrainedWindowAlert alloc] init]);
-  [alert layout];
-  [[alert window] makeKeyAndOrderFront:nil];
-}
-
-// Test adding an accessory view to an alert.
-TEST_F(ConstrainedWindowAlertTest, AccessoryView) {
-  base::scoped_nsobject<ConstrainedWindowAlert> alert(
-      [[ConstrainedWindowAlert alloc] init]);
-  [alert addButtonWithTitle:@"OK" keyEquivalent:@"" target:nil action:NULL];
-  [alert addButtonWithTitle:@"Cancel" keyEquivalent:@"" target:nil action:NULL];
-
-  NSRect view_rect = NSMakeRect(0, 0, 700, 300);
-  base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:view_rect]);
-  EXPECT_FALSE([alert accessoryView]);
-  [alert setAccessoryView:view];
-  EXPECT_NSEQ([alert accessoryView], view);
-
-  [alert layout];
-  NSRect window_rect = [[alert window] frame];
-  EXPECT_GT(NSWidth(window_rect), NSWidth(view_rect));
-  EXPECT_GT(NSHeight(window_rect), NSHeight(view_rect));
-
-  [[alert window] makeKeyAndOrderFront:nil];
-}
-
-// Test adding a link to an alert.
-TEST_F(ConstrainedWindowAlertTest, LinkView) {
-  base::scoped_nsobject<ConstrainedWindowAlert> alert(
-      [[ConstrainedWindowAlert alloc] init]);
-  base::scoped_nsobject<ConstrainedWindowAlertTestTarget> target(
-      [[ConstrainedWindowAlertTestTarget alloc] init]);
-
-  [alert layout];
-  NSRect initial_window_rect = [[alert window] frame];
-
-  EXPECT_EQ(nil, [alert linkView]);
-  NSString* linkText = @"Text of the link";
-  [alert setLinkText:linkText
-              target:target.get()
-              action:@selector(onLinkClicked:)];
-  EXPECT_EQ([linkText length], [[[alert linkView] title] length]);
-
-  [alert layout];
-  NSRect window_rect = [[alert window] frame];
-
-  EXPECT_GT(NSHeight(window_rect), NSHeight(initial_window_rect));
-
-  [[alert window] makeKeyAndOrderFront:nil];
-
-  [[alert linkView] performClick:nil];
-  EXPECT_EQ(1, [target linkClickedCount]);
-}
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h
deleted file mode 100644
index d70fea4..0000000
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_BUTTON_H_
-#define CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_BUTTON_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "ui/base/cocoa/tracking_area.h"
-
-namespace constrained_window_button {
-const CGFloat kButtonMinWidth = 72;
-}
-
-@protocol ConstrainedWindowButtonDrawableCell
-@property (nonatomic, assign) BOOL isMouseInside;
-- (BOOL)isEnabled;
-- (BOOL)isHighlighted;
-@end
-
-// A push button for use in a constrained window. Specialized constrained
-// windows that need a push button should use this class instead of NSButton.
-@interface ConstrainedWindowButton : NSButton {
- @private
-  ui::ScopedCrTrackingArea trackingArea_;
-}
-
-extern const CGFloat buttonMinWidth_;
-
-// Draws the background and shadow inside |path| with the appropriate
-// colors for |buttonState|, onto |view|.
-+ (void)DrawBackgroundAndShadowForPath:(NSBezierPath*)path
-                          withCell:(id<ConstrainedWindowButtonDrawableCell>)cell
-                            inView:(NSView*)view;
-
-// Draws the highlight inside |path|, with the color for |buttonState|,
-// onto |view|.
-+ (void)DrawInnerHighlightForPath:(NSBezierPath*)path
-                         withCell:(id<ConstrainedWindowButtonDrawableCell>)cell
-                           inView:(NSView*)view;
-
-// Draws the border along |path|, with a color according to |buttonState|,
-// onto |view|.
-+ (void)DrawBorderForPath:(NSBezierPath*)path
-                 withCell:(id<ConstrainedWindowButtonDrawableCell>)cell
-                   inView:(NSView*)view;
-@end
-
-// A button cell used by ConstrainedWindowButton.
-@interface ConstrainedWindowButtonCell :
-    NSButtonCell<ConstrainedWindowButtonDrawableCell> {
- @private
-  BOOL isMouseInside_;
-}
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm
deleted file mode 100644
index 9ea5fe9..0000000
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm
+++ /dev/null
@@ -1,290 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/molokocacao/NSBezierPath+MCAdditions.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-@interface ConstrainedWindowButton ()
-- (BOOL)isMouseReallyInside;
-@end
-
-namespace {
-
-enum ButtonState {
-  BUTTON_NORMAL,
-  BUTTON_HOVER,
-  BUTTON_PRESSED,
-  BUTTON_DISABLED,
-};
-
-const CGFloat kButtonHeight = 28;
-const CGFloat kButtonPaddingX = 14;
-
-ButtonState cellButtonState(id<ConstrainedWindowButtonDrawableCell> cell) {
-  if (!cell)
-    return BUTTON_NORMAL;
-  if (![cell isEnabled])
-    return BUTTON_DISABLED;
-  if ([cell isHighlighted])
-    return BUTTON_PRESSED;
-  if ([cell isMouseInside])
-    return BUTTON_HOVER;
-  return BUTTON_NORMAL;
-}
-
-// The functions below use hex color values to make it easier to compare
-// the code with the spec. Table of hex values are also more readable
-// then tables of NSColor constructors.
-
-NSGradient* GetButtonGradient(ButtonState button_state) {
-  const SkColor start[] = {0xFFF0F0F0, 0xFFF4F4F4, 0xFFEBEBEB, 0xFFEDEDED};
-  const SkColor end[] = {0xFFE0E0E0, 0xFFE4E4E4, 0xFFDBDBDB, 0xFFDEDEDE};
-
-  NSColor* start_color = skia::SkColorToCalibratedNSColor(start[button_state]);
-  NSColor* end_color = skia::SkColorToCalibratedNSColor(end[button_state]);
-  return [[[NSGradient alloc] initWithColorsAndLocations:
-      start_color, 0.0,
-      start_color, 0.38,
-      end_color, 1.0,
-      nil] autorelease];
-}
-
-NSShadow* GetButtonHighlight(ButtonState button_state) {
-  const SkColor color[] = {0xBFFFFFFF, 0xF2FFFFFF, 0x24000000, 0x00000000};
-
-  NSShadow* shadow = [[[NSShadow alloc] init] autorelease];
-  [shadow setShadowColor:skia::SkColorToCalibratedNSColor(color[button_state])];
-  [shadow setShadowOffset:NSMakeSize(0, -1)];
-  [shadow setShadowBlurRadius:2];
-  return shadow;
-}
-
-NSShadow* GetButtonShadow(ButtonState button_state) {
-  const SkColor color[] = {0x14000000, 0x1F000000, 0x00000000, 0x00000000};
-
-  NSShadow* shadow = [[[NSShadow alloc] init] autorelease];
-  [shadow setShadowColor:skia::SkColorToCalibratedNSColor(color[button_state])];
-  [shadow setShadowOffset:NSMakeSize(0, -1)];
-  [shadow setShadowBlurRadius:0];
-  return shadow;
-}
-
-NSColor* GetButtonBorderColor(ButtonState button_state) {
-  const SkColor color[] = {0x40000000, 0x4D000000, 0x4D000000, 0x1F000000};
-
-  return skia::SkColorToCalibratedNSColor(color[button_state]);
-}
-
-NSAttributedString* GetButtonAttributedString(
-    NSString* title,
-    NSString* key_equivalent,
-    id<ConstrainedWindowButtonDrawableCell> cell) {
-  const SkColor text_color[] = {0xFF333333, 0XFF000000, 0xFF000000, 0xFFAAAAAA};
-  // The shadow color should be 0xFFF0F0F0 but that doesn't show up so use
-  // pure white instead.
-  const SkColor shadow_color[] =
-      {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF};
-
-  base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
-  [shadow setShadowColor:
-      skia::SkColorToCalibratedNSColor(shadow_color[cellButtonState(cell)])];
-  [shadow setShadowOffset:NSMakeSize(0, -1)];
-  [shadow setShadowBlurRadius:0];
-
-  base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
-      [[NSMutableParagraphStyle alloc] init]);
-  [paragraphStyle setAlignment:NSCenterTextAlignment];
-
-  NSFont* font = nil;
-  if ([key_equivalent isEqualToString:kKeyEquivalentReturn])
-    font = [NSFont boldSystemFontOfSize:12];
-  else
-    font = [NSFont systemFontOfSize:12];
-
-  NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys:
-      font, NSFontAttributeName,
-      skia::SkColorToCalibratedNSColor(text_color[cellButtonState(cell)]),
-      NSForegroundColorAttributeName,
-      shadow.get(), NSShadowAttributeName,
-      paragraphStyle.get(), NSParagraphStyleAttributeName,
-      nil];
-  return [[[NSAttributedString alloc] initWithString:title
-                                          attributes:attributes] autorelease];
-}
-
-void DrawBackgroundAndShadow(const NSRect& frame,
-                             id<ConstrainedWindowButtonDrawableCell> cell,
-                             NSView* view) {
-  NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:frame
-                                                       xRadius:2
-                                                       yRadius:2];
-  [ConstrainedWindowButton DrawBackgroundAndShadowForPath:path
-                                                 withCell:cell
-                                                   inView:view];
-}
-
-void DrawInnerHighlight(const NSRect& frame,
-                        id<ConstrainedWindowButtonDrawableCell> cell,
-                        NSView* view) {
-  NSBezierPath* path =
-      [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 1, 1)
-                                      xRadius:2
-                                      yRadius:2];
-  [ConstrainedWindowButton DrawInnerHighlightForPath:path
-                                            withCell:cell
-                                              inView:view];
-}
-
-void DrawBorder(const NSRect& frame,
-                id<ConstrainedWindowButtonDrawableCell> cell,
-                NSView* view) {
-  NSBezierPath* path =
-      [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 0.5, 0.5)
-                                      xRadius:2
-                                      yRadius:2];
-  [ConstrainedWindowButton DrawBorderForPath:path
-                                    withCell:cell
-                                      inView:view];
-}
-
-}  // namespace
-
-@implementation ConstrainedWindowButton
-
-+ (Class)cellClass {
-  return [ConstrainedWindowButtonCell class];
-}
-
-- (void)updateTrackingAreas {
-  BOOL mouseInView = [self isMouseReallyInside];
-
-  if (trackingArea_.get())
-    [self removeTrackingArea:trackingArea_.get()];
-
-  NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
-                                  NSTrackingActiveInActiveApp |
-                                  NSTrackingInVisibleRect;
-  if (mouseInView)
-    options |= NSTrackingAssumeInside;
-
-  trackingArea_.reset([[CrTrackingArea alloc]
-                        initWithRect:NSZeroRect
-                             options:options
-                               owner:self
-                            userInfo:nil]);
-  [self addTrackingArea:trackingArea_.get()];
-  if ([[self cell] isMouseInside] != mouseInView) {
-    [[self cell] setIsMouseInside:mouseInView];
-    [self setNeedsDisplay:YES];
-  }
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
-  [[self cell] setIsMouseInside:YES];
-  [self setNeedsDisplay:YES];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
-  [[self cell] setIsMouseInside:YES];
-  [[self cell] setIsMouseInside:NO];
-  [self setNeedsDisplay:YES];
-}
-
-- (BOOL)isMouseReallyInside {
-  BOOL mouseInView = NO;
-  NSWindow* window = [self window];
-  if (window) {
-    NSPoint mousePoint = [window mouseLocationOutsideOfEventStream];
-    mousePoint = [self convertPoint:mousePoint fromView:nil];
-    mouseInView = [self mouse:mousePoint inRect:[self bounds]];
-  }
-  return mouseInView;
-}
-
-- (void)sizeToFit {
-  [super sizeToFit];
-  NSSize size = [self frame].size;
-  if (size.width < constrained_window_button::kButtonMinWidth) {
-    size.width = constrained_window_button::kButtonMinWidth;
-    [self setFrameSize:size];
-  }
-}
-
-+ (void)DrawBackgroundAndShadowForPath:(NSBezierPath*)path
-                          withCell:(id<ConstrainedWindowButtonDrawableCell>)cell
-                            inView:(NSView*)view {
-  ButtonState buttonState = cellButtonState(cell);
-  {
-    gfx::ScopedNSGraphicsContextSaveGState scopedGState;
-    [GetButtonShadow(buttonState) set];
-    [[[view window] backgroundColor] set];
-    [path fill];
-  }
-  [GetButtonGradient(buttonState) drawInBezierPath:path angle:90.0];
-}
-
-+ (void)DrawInnerHighlightForPath:(NSBezierPath*)path
-                         withCell:(id<ConstrainedWindowButtonDrawableCell>)cell
-                           inView:(NSView*)view {
-  [path fillWithInnerShadow:GetButtonHighlight(cellButtonState(cell))];
-}
-
-+ (void)DrawBorderForPath:(NSBezierPath*)path
-                 withCell:(id<ConstrainedWindowButtonDrawableCell>)cell
-                   inView:(NSView*)view {
-  if ([[[view window] firstResponder] isEqual:view])
-    [[NSColor colorWithCalibratedRed:0.30 green:0.57 blue:1.0 alpha:1.0] set];
-  else
-    [GetButtonBorderColor(cellButtonState(cell)) set];
-  [path stroke];
-}
-
-@end
-
-@implementation ConstrainedWindowButtonCell
-
-@synthesize isMouseInside = isMouseInside_;
-
-- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView*)controlView {
-  // Inset to leave room for shadow.
-  --frame.size.height;
-
-  // Background and shadow
-  DrawBackgroundAndShadow(frame, self, controlView);
-
-  // Inner highlight
-  DrawInnerHighlight(frame, self, controlView);
-
-  // Border
-  DrawBorder(frame, self, controlView);
-}
-
-- (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView*)controlView {
-  // Inset to leave room for shadow.
-  --frame.size.height;
-  NSAttributedString* title = GetButtonAttributedString(
-     [self title], [self keyEquivalent], self);
-  [self drawTitle:title withFrame:frame inView:controlView];
-}
-
-- (NSSize)cellSize {
-  NSAttributedString* title = GetButtonAttributedString(
-      [self title], [self keyEquivalent], self);
-  NSSize size = [title size];
-  size.height = std::max(size.height, kButtonHeight);
-  size.width += kButtonPaddingX * 2;
-  return size;
-}
-
-- (NSAttributedString*)getAttributedTitle {
-  return GetButtonAttributedString(
-      [self title], [self keyEquivalent], self);
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm
deleted file mode 100644
index b0e148c..0000000
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "ui/events/test/cocoa_test_event_utils.h"
-
-class ConstrainedWindowButtonTest : public CocoaTest {
- public:
-  ConstrainedWindowButtonTest() {
-    NSRect frame = NSMakeRect(0, 0, 50, 30);
-    button_.reset([[ConstrainedWindowButton alloc] initWithFrame:frame]);
-    [button_ setTitle:@"Abcdefg"];
-    [button_ sizeToFit];
-    [[test_window() contentView] addSubview:button_];
-  }
-
- protected:
-  base::scoped_nsobject<ConstrainedWindowButton> button_;
-};
-
-TEST_VIEW(ConstrainedWindowButtonTest, button_)
-
-// Test hover, mostly to ensure nothing leaks or crashes.
-TEST_F(ConstrainedWindowButtonTest, DisplayWithHover) {
-  [[button_ cell] setIsMouseInside:NO];
-  [button_ display];
-  [[button_ cell] setIsMouseInside:YES];
-  [button_ display];
-}
-
-// Test disabled, mostly to ensure nothing leaks or crashes.
-TEST_F(ConstrainedWindowButtonTest, DisplayWithDisable) {
-  [button_ setEnabled:YES];
-  [button_ display];
-  [button_ setEnabled:NO];
-  [button_ display];
-}
-
-// Test pushed, mostly to ensure nothing leaks or crashes.
-TEST_F(ConstrainedWindowButtonTest, DisplayWithPushed) {
-  [[button_ cell] setHighlighted:NO];
-  [button_ display];
-  [[button_ cell] setHighlighted:YES];
-  [button_ display];
-}
-
-// Tracking rects
-TEST_F(ConstrainedWindowButtonTest, TrackingRects) {
-  ConstrainedWindowButtonCell* cell = [button_ cell];
-  EXPECT_FALSE([cell isMouseInside]);
-
-  [button_ mouseEntered:cocoa_test_event_utils::EnterEvent()];
-  EXPECT_TRUE([cell isMouseInside]);
-  [button_ mouseExited:cocoa_test_event_utils::ExitEvent()];
-  EXPECT_FALSE([cell isMouseInside]);
-}
diff --git a/chrome/browser/ui/cocoa/create_native_web_modal_manager_cocoa.mm b/chrome/browser/ui/cocoa/create_native_web_modal_manager_cocoa.mm
deleted file mode 100644
index dcd5d83b..0000000
--- a/chrome/browser/ui/cocoa/create_native_web_modal_manager_cocoa.mm
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 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 "chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-
-namespace web_modal {
-
-SingleWebContentsDialogManager*
-WebContentsModalDialogManager::CreateNativeWebModalManager(
-    gfx::NativeWindow dialog,
-    web_modal::SingleWebContentsDialogManagerDelegate* delegate) {
-  return new SingleWebContentsDialogManagerViewsMac(dialog, delegate);
-}
-
-}  // namespace web_modal
diff --git a/chrome/browser/ui/cocoa/image_button_cell.h b/chrome/browser/ui/cocoa/image_button_cell.h
deleted file mode 100644
index 9fc9b03..0000000
--- a/chrome/browser/ui/cocoa/image_button_cell.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_IMAGE_BUTTON_CELL_H_
-#define CHROME_BROWSER_UI_COCOA_IMAGE_BUTTON_CELL_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-
-namespace ui {
-class ThemeProvider;
-}
-
-namespace image_button_cell {
-
-// Possible states
-enum ButtonState {
-  kDefaultState = 0,
-  kHoverState,
-  kPressedState,
-  kDisabledState,
-  // The same as above, but for non-main, non-key windows.
-  kDefaultStateBackground,
-  kHoverStateBackground,
-  kButtonStateCount
-};
-
-} // namespace ImageButtonCell
-
-@protocol ImageButton
-@optional
-// Sent from an ImageButtonCell to its view when the mouse enters or exits the
-// cell.
-- (void)mouseInsideStateDidChange:(BOOL)isInside;
-@end
-
-// A button cell that can disable a different image for each possible button
-// state. Images are specified by image IDs.
-@interface ImageButtonCell : NSButtonCell {
- @private
-  struct {
-    // At most one of these two fields will be non-null.
-    int imageId;
-    base::scoped_nsobject<NSImage> image;
-  } image_[image_button_cell::kButtonStateCount];
-  BOOL isMouseInside_;
-
-  // Disables the hover effect if set to true.
-  BOOL isHoverDisabled_;
-}
-
-@property(assign, nonatomic) BOOL isMouseInside;
-
-// Gets the image for the given button state. Will load from a resource pak if
-// the image was originally set using an image ID.
-- (NSImage*)imageForState:(image_button_cell::ButtonState)state
-                     view:(NSView*)controlView;
-
-// Sets the image for the given button state using an image ID.
-// The image will be lazy loaded from a resource pak -- important because
-// this is in the hot path for startup.
-- (void)setImageID:(NSInteger)imageID
-    forButtonState:(image_button_cell::ButtonState)state;
-
-// Sets the image for the given button state using an image.
-- (void)setImage:(NSImage*)image
-  forButtonState:(image_button_cell::ButtonState)state;
-
-// Gets the alpha to use to draw the button for the current window focus state.
-- (CGFloat)imageAlphaForWindowState:(NSWindow*)window;
-
-// Returns the theme provider for the given |window|; this allows subclasses to
-// pass in a different theme provider to use if appropriate.
-- (const ui::ThemeProvider*)themeProviderForWindow:(NSWindow*)window;
-
-// Draws the cell's image within |cellFrame|.
-- (void)drawImageWithFrame:(NSRect)cellFrame inView:(NSView*)controlView;
-
-// Setter for |isHoverDisabled|. If |disable| is true, set |isMouseInside_| to
-// false.
-- (void)setIsHoverDisabled:(BOOL)disable;
-
-@end
-
-#endif // CHROME_BROWSER_UI_COCOA_IMAGE_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/image_button_cell.mm b/chrome/browser/ui/cocoa/image_button_cell.mm
deleted file mode 100644
index f864db1..0000000
--- a/chrome/browser/ui/cocoa/image_button_cell.mm
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/image_button_cell.h"
-
-#include "base/logging.h"
-#include "base/mac/mac_util.h"
-#import "chrome/browser/themes/theme_service.h"
-#import "chrome/browser/ui/cocoa/rect_path_utils.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-// When the window doesn't have focus then we want to draw the button with a
-// slightly lighter color. We do this by just reducing the alpha.
-const CGFloat kImageNoFocusAlpha = 0.65;
-
-const CGFloat kHoverAnimationDuration = 0.2;  // seconds
-
-namespace {
-
-NSRect CenterImageInFrame(NSImage* image, NSRect frame) {
-  NSRect rect;
-  rect.size = [image size];
-  rect.origin.x =
-      frame.origin.x + std::round((NSWidth(frame) - NSWidth(rect)) / 2.0);
-  rect.origin.y =
-      frame.origin.y + std::round((NSHeight(frame) - NSHeight(rect)) / 2.0);
-  return rect;
-}
-}
-
-@interface ImageButtonCell (Private)
-- (void)sharedInit;
-- (image_button_cell::ButtonState)currentButtonState;
-- (NSImage*)imageForID:(NSInteger)imageID
-           controlView:(NSView*)controlView;
-- (void)animationDidProgress;
-@end
-
-@interface HoverAnimation : NSAnimation
-- (id)initWithOwner:(ImageButtonCell*)owner;
-- (void)setCurrentProgress:(NSAnimationProgress)progress;
-@end
-
-@implementation HoverAnimation {
-  ImageButtonCell* owner_;
-}
-
-- (id)initWithOwner:(ImageButtonCell*)owner {
-  if ((self = [super initWithDuration:kHoverAnimationDuration
-                       animationCurve:NSAnimationEaseInOut])) {
-    [self setAnimationBlockingMode:NSAnimationNonblocking];
-    owner_ = owner;
-  }
-  return self;
-}
-
-- (void)setCurrentProgress:(NSAnimationProgress)progress {
-  [super setCurrentProgress:progress];
-  [owner_ animationDidProgress];
-}
-
-@end
-
-@implementation ImageButtonCell {
-  NSAnimation* hoverAnimation_;
-  image_button_cell::ButtonState oldState_;
-}
-
-@synthesize isMouseInside = isMouseInside_;
-
-// For nib instantiations
-- (id)initWithCoder:(NSCoder*)decoder {
-  if ((self = [super initWithCoder:decoder])) {
-    [self sharedInit];
-  }
-  return self;
-}
-
-// For programmatic instantiations
-- (id)initTextCell:(NSString*)string {
-  if ((self = [super initTextCell:string])) {
-    [self sharedInit];
-  }
-  return self;
-}
-
-- (void)sharedInit {
-  [self setHighlightsBy:NSNoCellMask];
-
-  // We need to set this so that we can override |-mouseEntered:| and
-  // |-mouseExited:| to change the button image on hover states.
-  [self setShowsBorderOnlyWhileMouseInside:YES];
-
-  hoverAnimation_ = [[HoverAnimation alloc] initWithOwner:self];
-}
-
-- (void)dealloc {
-  [hoverAnimation_ stopAnimation];
-  [hoverAnimation_ release];
-  [super dealloc];
-}
-
-- (NSImage*)imageForState:(image_button_cell::ButtonState)state
-                     view:(NSView*)controlView{
-  if (image_[state].imageId)
-    return [self imageForID:image_[state].imageId controlView:controlView];
-  return image_[state].image;
-}
-
-- (void)drawImageWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
-  image_button_cell::ButtonState state = [self currentButtonState];
-  BOOL windowHasFocus = [[controlView window] isMainWindow] ||
-                        [[controlView window] isKeyWindow];
-  CGFloat alpha = [self imageAlphaForWindowState:[controlView window]];
-  NSImage* image = [self imageForState:state view:controlView];
-  NSImage* oldImage = nil;
-  CGFloat oldAlpha = 0.0;
-
-  if (!windowHasFocus) {
-    NSImage* defaultImage = [self
-      imageForState:image_button_cell::kDefaultStateBackground
-               view:controlView];
-    NSImage* hoverImage = [self
-      imageForState:image_button_cell::kHoverStateBackground
-               view:controlView];
-    if ([self currentButtonState] == image_button_cell::kDefaultState &&
-        defaultImage) {
-      image = defaultImage;
-      alpha = 1.0;
-    } else if ([self currentButtonState] == image_button_cell::kHoverState &&
-        hoverImage) {
-      image = hoverImage;
-      alpha = 1.0;
-    }
-  }
-
-  if ([hoverAnimation_ isAnimating]) {
-    oldImage = [self imageForState:oldState_ view:controlView];
-    oldAlpha = 1.0 - [hoverAnimation_ currentValue] * alpha;
-    alpha *= [hoverAnimation_ currentValue];
-  }
-
-  NSRect imageRect = CenterImageInFrame(image, cellFrame);
-  NSCompositingOperation op = [[controlView window] hasDarkTheme]
-                                  ? NSCompositePlusLighter
-                                  : NSCompositePlusDarker;
-
-  if (oldImage) {
-    NSRect oldImageRect = CenterImageInFrame(oldImage, cellFrame);
-    [oldImage drawInRect:oldImageRect
-                fromRect:NSZeroRect
-               operation:op
-                fraction:oldAlpha
-          respectFlipped:YES
-                   hints:nil];
-  }
-
-  [image drawInRect:imageRect
-            fromRect:NSZeroRect
-           operation:op
-            fraction:alpha
-      respectFlipped:YES
-               hints:nil];
-}
-
-- (void)setIsHoverDisabled:(BOOL)disable {
-  if (disable)
-    [self setIsMouseInside:NO];
-
-  isHoverDisabled_ = disable;
-}
-
-- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
-  [self drawImageWithFrame:cellFrame inView:controlView];
-}
-
-- (void)setImageID:(NSInteger)imageID
-    forButtonState:(image_button_cell::ButtonState)state {
-  DCHECK_GE(state, 0);
-  DCHECK_LT(state, image_button_cell::kButtonStateCount);
-
-  image_[state].image.reset();
-  image_[state].imageId = imageID;
-  [[self controlView] setNeedsDisplay:YES];
-}
-
-// Sets the image for the given button state using an image.
-- (void)setImage:(NSImage*)image
-  forButtonState:(image_button_cell::ButtonState)state {
-  DCHECK_GE(state, 0);
-  DCHECK_LT(state, image_button_cell::kButtonStateCount);
-
-  image_[state].image.reset([image retain]);
-  image_[state].imageId = 0;
-  [[self controlView] setNeedsDisplay:YES];
-}
-
-- (CGFloat)imageAlphaForWindowState:(NSWindow*)window {
-  BOOL windowHasFocus = [window isMainWindow] || [window isKeyWindow];
-  return windowHasFocus ? 1.0 : kImageNoFocusAlpha;
-}
-
-- (const ui::ThemeProvider*)themeProviderForWindow:(NSWindow*)window {
-  return [window themeProvider];
-}
-
-- (image_button_cell::ButtonState)currentButtonState {
-  bool (^has)(image_button_cell::ButtonState) =
-      ^(image_button_cell::ButtonState state) {
-          return image_[state].image || image_[state].imageId;
-      };
-  if (![self isEnabled] && has(image_button_cell::kDisabledState))
-    return image_button_cell::kDisabledState;
-  if ([self isHighlighted] && has(image_button_cell::kPressedState))
-    return image_button_cell::kPressedState;
-  if ([self isMouseInside] && has(image_button_cell::kHoverState))
-    return image_button_cell::kHoverState;
-  return image_button_cell::kDefaultState;
-}
-
-- (NSImage*)imageForID:(NSInteger)imageID
-           controlView:(NSView*)controlView {
-  if (!imageID)
-    return nil;
-
-  const ui::ThemeProvider* themeProvider =
-      [self themeProviderForWindow:[controlView window]];
-  if (!themeProvider)
-    return nil;
-
-  return themeProvider->GetNSImageNamed(imageID);
-}
-
-- (void)animationDidProgress {
-  NSView<ImageButton>* control =
-      static_cast<NSView<ImageButton>*>([self controlView]);
-  [control setNeedsDisplay:YES];
-}
-
-- (void)setIsMouseInside:(BOOL)isMouseInside {
-  if (isHoverDisabled_)
-    return;
-
-  if (isMouseInside_ != isMouseInside) {
-    oldState_ = [self currentButtonState];
-    isMouseInside_ = isMouseInside;
-    [hoverAnimation_ startAnimation];
-    NSView<ImageButton>* control =
-        static_cast<NSView<ImageButton>*>([self controlView]);
-    if ([control respondsToSelector:@selector(mouseInsideStateDidChange:)]) {
-      [control mouseInsideStateDidChange:isMouseInside];
-    }
-    [control setNeedsDisplay:YES];
-  }
-}
-
-- (void)setShowsBorderOnlyWhileMouseInside:(BOOL)show {
-  VLOG_IF(1, !show) << "setShowsBorderOnlyWhileMouseInside:NO ignored";
-}
-
-- (BOOL)showsBorderOnlyWhileMouseInside {
-  // Always returns YES so that buttons always get mouse tracking even when
-  // disabled. The reload button (and possibly others) depend on this.
-  return YES;
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
-  [self setIsMouseInside:YES];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
-  [self setIsMouseInside:NO];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/image_button_cell_unittest.mm b/chrome/browser/ui/cocoa/image_button_cell_unittest.mm
deleted file mode 100644
index 6fcc36f..0000000
--- a/chrome/browser/ui/cocoa/image_button_cell_unittest.mm
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/image_button_cell.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "chrome/grit/theme_resources.h"
-
-namespace {
-
-class ImageButtonCellTest : public CocoaTest {
- public:
-  ImageButtonCellTest() {
-    NSRect frame = NSMakeRect(0, 0, 50, 30);
-    base::scoped_nsobject<NSButton> view(
-        [[NSButton alloc] initWithFrame:frame]);
-    view_ = view.get();
-    base::scoped_nsobject<ImageButtonCell> cell(
-        [[ImageButtonCell alloc] initTextCell:@""]);
-    [view_ setCell:cell.get()];
-    [[test_window() contentView] addSubview:view_];
-  }
-
-  void SetImages() {
-    [[view_ cell] setImageID:IDR_BACK
-              forButtonState:image_button_cell::kDefaultState];
-    [[view_ cell] setImageID:IDR_BACK_H
-              forButtonState:image_button_cell::kHoverState];
-    [[view_ cell] setImageID:IDR_BACK_P
-              forButtonState:image_button_cell::kPressedState];
-    [[view_ cell] setImageID:IDR_BACK_D
-              forButtonState:image_button_cell::kDisabledState];
-  }
-
-  NSButton* view_;
-};
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(ImageButtonCellTest, DisplayWithHover) {
-  SetImages();
-  EXPECT_FALSE([[view_ cell] isMouseInside]);
-  [view_ display];
-  [[view_ cell] setIsMouseInside:YES];
-  [view_ display];
-
-  // Unset the hover image and draw.
-  [[view_ cell] setImageID:0
-            forButtonState:image_button_cell::kHoverState];
-  [view_ display];
-}
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(ImageButtonCellTest, DisplayWithPressed) {
-  SetImages();
-  EXPECT_FALSE([[view_ cell] isHighlighted]);
-  [view_ display];
-  [[view_ cell] setHighlighted:YES];
-  [view_ display];
-
-  // Unset the pressed image and draw.
-  [[view_ cell] setImageID:0
-            forButtonState:image_button_cell::kPressedState];
-  [view_ display];
-}
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(ImageButtonCellTest, DisplayWithDisabled) {
-  SetImages();
-  EXPECT_TRUE([[view_ cell] isEnabled]);
-  [view_ display];
-  [[view_ cell] setEnabled:NO];
-  [view_ display];
-
-  // Unset the disabled image and draw.
-  [[view_ cell] setImageID:0
-            forButtonState:image_button_cell::kDisabledState];
-  [view_ display];
-}
-
-TEST_F(ImageButtonCellTest, NewImageCausesDisplay) {
-  [[view_ cell] setImageID:IDR_FORWARD
-            forButtonState:image_button_cell::kDefaultState];
-  [view_ display];
-  EXPECT_FALSE([view_ needsDisplay]);
-
-  [[view_ cell] setImageID:IDR_FORWARD_D
-            forButtonState:image_button_cell::kDefaultState];
-  EXPECT_TRUE([view_ needsDisplay]);
-}
-
-} // namespace
diff --git a/chrome/browser/ui/cocoa/menu_button.h b/chrome/browser/ui/cocoa/menu_button.h
deleted file mode 100644
index 84487ff..0000000
--- a/chrome/browser/ui/cocoa/menu_button.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_MENU_BUTTON_H_
-#define CHROME_BROWSER_UI_COCOA_MENU_BUTTON_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h"
-
-// This a button which displays a user-provided menu "attached" below it upon
-// being clicked or dragged (or clicked and held). It expects a
-// |ClickHoldButtonCell| as cell.
-//
-// There are two different behaviors of this button depending on the value of
-// the |openMenuOnClick| property. If YES, the target-action mechanism will be
-// handled internally to always show the menu when clicked. This behavior is
-// used for the App menu, for example. When the property is NO, the button can
-// have a separate target-action but will open the menu when clicked and held.
-// This is used for the toolbar back/forward buttons, which have a primary
-// action and the menu as a secondary click-hold action. The default value is NO
-// so that custom actions can be hooked up in Interface Builder.
-// The click-hold behavior can be disabled entirely through the
-// |openMenuOnClickHold| property.
-@interface MenuButton : ToolbarButtonCocoa {
- @private
-  base::scoped_nsobject<NSMenu> attachedMenu_;
-  BOOL openMenuOnClick_;
-  BOOL openMenuOnRightClick_;
-  BOOL openMenuOnClickHold_;
-}
-
-// The menu to display. Note that it should have no (i.e., a blank) title and
-// that the 0-th entry should be blank (and won't be displayed). (This is
-// because we use a pulldown list, for which Cocoa uses the 0-th item as "title"
-// in the button. This might change if we ever switch to a pop-up. Our direct
-// use of the given NSMenu object means that the one can set and use NSMenu's
-// delegate as usual.)
-@property(retain, nonatomic) IBOutlet NSMenu* attachedMenu;
-
-// Whether or not to open the menu when the button is clicked. Otherwise, the
-// menu will only be opened when clicked and held, if that behavior has not
-// been disabled.
-@property(assign, nonatomic) BOOL openMenuOnClick;
-
-// Whether or not to open the menu when the right button is clicked.
-@property(assign, nonatomic) BOOL openMenuOnRightClick;
-
-// Whether the menu should open if a user clicks and holds on the button. The
-// default is YES. This does require that the user drag the mouse a small
-// distance "pull open" the menu.
-@property(assign, nonatomic) BOOL openMenuOnClickHold;
-
-// Returns the rectangle that menus are anchored at. Can be overridden by
-// subclasses, returns -bounds by default.
-- (NSRect)menuRect;
-
-@end  // @interface MenuButton
-
-// Available for subclasses.
-@interface MenuButton (Protected)
-- (void)configureCell;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_MENU_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/menu_button.mm b/chrome/browser/ui/cocoa/menu_button.mm
deleted file mode 100644
index 4bd4a99..0000000
--- a/chrome/browser/ui/cocoa/menu_button.mm
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/menu_button.h"
-
-#include "base/logging.h"
-#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
-#include "ui/base/material_design/material_design_controller.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#include "ui/base/material_design/material_design_controller.h"
-
-@interface MenuButton (Private)
-- (void)showMenu:(BOOL)isDragging;
-- (void)clickShowMenu:(id)sender;
-- (void)dragShowMenu:(id)sender;
-@end  // @interface MenuButton (Private)
-
-@implementation MenuButton
-
-@synthesize openMenuOnClick = openMenuOnClick_;
-@synthesize openMenuOnRightClick = openMenuOnRightClick_;
-@synthesize openMenuOnClickHold = openMenuOnClickHold_;
-
-// Overrides:
-
-+ (Class)cellClass {
-  return [ClickHoldButtonCell class];
-}
-
-- (id)init {
-  if ((self = [super init])) {
-    openMenuOnClickHold_ = YES;
-    [self configureCell];
-  }
-  return self;
-}
-
-- (id)initWithCoder:(NSCoder*)decoder {
-  if ((self = [super initWithCoder:decoder])) {
-    openMenuOnClickHold_ = YES;
-    [self configureCell];
-  }
-  return self;
-}
-
-- (id)initWithFrame:(NSRect)frameRect {
-  if ((self = [super initWithFrame:frameRect])) {
-    openMenuOnClickHold_ = YES;
-    [self configureCell];
-  }
-  return self;
-}
-
-- (void)dealloc {
-  self.attachedMenu = nil;
-  [super dealloc];
-}
-
-- (void)awakeFromNib {
-  [self configureCell];
-}
-
-- (void)setCell:(NSCell*)cell {
-  [super setCell:cell];
-  [self configureCell];
-}
-
-- (void)rightMouseDown:(NSEvent*)theEvent {
-  if (!openMenuOnRightClick_) {
-    [super rightMouseDown:theEvent];
-    return;
-  }
-
-  [self clickShowMenu:self];
-}
-
-// Accessors and mutators:
-
-- (NSMenu*)attachedMenu {
-  return attachedMenu_.get();
-}
-
-- (void)setAttachedMenu:(NSMenu*)menu {
-  attachedMenu_.reset([menu retain]);
-  [self configureCell];
-}
-
-- (void)setOpenMenuOnClick:(BOOL)enabled {
-  openMenuOnClick_ = enabled;
-  [self configureCell];
-}
-
-- (void)setOpenMenuOnRightClick:(BOOL)enabled {
-  openMenuOnRightClick_ = enabled;
-  [self configureCell];
-}
-
-- (void)setOpenMenuOnClickHold:(BOOL)enabled {
-  openMenuOnClickHold_ = enabled;
-  [self configureCell];
-}
-
-- (NSRect)menuRect {
-  return [self bounds];
-}
-
-@end  // @implementation MenuButton
-
-@implementation MenuButton (Private)
-
-// Synchronize the state of this class with its ClickHoldButtonCell.
-- (void)configureCell {
-  ClickHoldButtonCell* cell = [self cell];
-  DCHECK([cell isKindOfClass:[ClickHoldButtonCell class]]);
-
-  if (![self attachedMenu]) {
-    [cell setEnableClickHold:NO];
-    [cell setEnableRightClick:NO];
-    [cell setClickHoldAction:nil];
-    [cell setClickHoldTarget:nil];
-    [cell setAccessibilityShowMenuAction:nil];
-    [cell setAccessibilityShowMenuTarget:nil];
-    return;
-  }
-
-  if (openMenuOnClick_) {
-    [cell setClickHoldTimeout:0.0];  // Make menu trigger immediately.
-    [cell setAction:@selector(clickShowMenu:)];
-    [cell setTarget:self];
-  } else {
-    [cell setClickHoldTimeout:0.25];  // Default value.
-  }
-
-  // Regardless of the left-or-right click behaviors, the button needs to allow
-  // the classic click-hold-drag behavior to "pull open" the menu.
-  [cell setEnableClickHold:openMenuOnClickHold_];
-  [cell setClickHoldAction:@selector(dragShowMenu:)];
-  [cell setClickHoldTarget:self];
-
-  [cell setEnableRightClick:openMenuOnRightClick_];
-  if (!openMenuOnClick_ || openMenuOnRightClick_) {
-    [cell setAccessibilityShowMenuAction:@selector(clickShowMenu:)];
-    [cell setAccessibilityShowMenuTarget:self];
-  } else {
-    [cell setAccessibilityShowMenuAction:nil];
-    [cell setAccessibilityShowMenuTarget:nil];
-  }
-}
-
-// Actually show the menu (in the correct location). |isDragging| indicates
-// whether the mouse button is still down or not.
-- (void)showMenu:(BOOL)isDragging {
-  if (![self attachedMenu]) {
-    LOG(WARNING) << "No menu available.";
-    if (isDragging) {
-      // If we're dragging, wait for mouse up.
-      [NSApp nextEventMatchingMask:NSLeftMouseUpMask
-                         untilDate:[NSDate distantFuture]
-                            inMode:NSEventTrackingRunLoopMode
-                           dequeue:YES];
-    }
-    return;
-  }
-
-  // TODO(viettrungluu): We have some fudge factors below to make things line up
-  // (approximately). I wish I knew how to get rid of them. (Note that our view
-  // is flipped, and that frame should be in our coordinates.) The y/height is
-  // very odd, since it doesn't seem to respond to changes the way that it
-  // should. I don't understand it.
-  NSRect frame = [self menuRect];
-  frame.origin.x -= 2.0;
-  frame.size.height -= 19.0 - NSHeight(frame);
-
-  // The button's icon has a different relationship to its bounds, so have to
-  // adjust the menu location by that delta.
-  frame.origin.x -= [ToolbarController materialDesignButtonInset];
-  frame.origin.y += [ToolbarController materialDesignButtonInset];
-
-  // Make our pop-up button cell and set things up. This is, as of 10.5, the
-  // official Apple-recommended hack. Later, perhaps |-[NSMenu
-  // popUpMenuPositioningItem:atLocation:inView:]| may be a better option.
-  // However, using a pulldown has the benefit that Cocoa automatically places
-  // the menu correctly even when we're at the edge of the screen (including
-  // "dragging upwards" when the button is close to the bottom of the screen).
-  base::scoped_nsobject<NSPopUpButtonCell> popUpCell(
-      [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:YES]);
-
-  [popUpCell setMenu:[self attachedMenu]];
-  [popUpCell selectItem:nil];
-  [popUpCell attachPopUpWithFrame:frame inView:self];
-  [popUpCell performClickWithFrame:frame inView:self];
-
-  // Once the menu is dismissed send a mouseExited event if necessary. If the
-  // menu action caused the super view to resize then we won't automatically
-  // get a mouseExited event so we need to do this manually.
-  // See http://crbug.com/82456
-  if (![self cr_isMouseInView]) {
-    if ([[self cell] respondsToSelector:@selector(mouseExited:)])
-      [[self cell] mouseExited:nil];
-  }
-}
-
-// Called when the button is clicked and released. (Shouldn't happen with
-// timeout of 0, though there may be some strange pointing devices out there.)
-- (void)clickShowMenu:(id)sender {
-  // We shouldn't get here unless the menu is enabled.
-  DCHECK([self attachedMenu]);
-  [self showMenu:NO];
-}
-
-// Called when the button is clicked and dragged/held.
-- (void)dragShowMenu:(id)sender {
-  // We shouldn't get here unless the menu is enabled.
-  DCHECK([self attachedMenu]);
-  [self showMenu:YES];
-}
-
-@end  // @implementation MenuButton (Private)
diff --git a/chrome/browser/ui/cocoa/menu_button_unittest.mm b/chrome/browser/ui/cocoa/menu_button_unittest.mm
deleted file mode 100644
index e5c9c25..0000000
--- a/chrome/browser/ui/cocoa/menu_button_unittest.mm
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/menu_button.h"
-
-#import "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#import "ui/base/test/menu_test_observer.h"
-#include "ui/events/test/cocoa_test_event_utils.h"
-
-namespace {
-
-class MenuButtonTest : public CocoaTest {
- public:
-  MenuButtonTest() {
-    NSRect frame = NSMakeRect(0, 0, 50, 30);
-    base::scoped_nsobject<MenuButton> button(
-        [[MenuButton alloc] initWithFrame:frame]);
-    button_ = button;
-    base::scoped_nsobject<ClickHoldButtonCell> cell(
-        [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
-    [button_ setCell:cell];
-    [[test_window() contentView] addSubview:button_];
-  }
-
-  base::scoped_nsobject<NSMenu> CreateMenu() {
-    base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
-    [menu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0];
-    [menu insertItemWithTitle:@"foo" action:nil keyEquivalent:@"" atIndex:1];
-    [menu insertItemWithTitle:@"bar" action:nil keyEquivalent:@"" atIndex:2];
-    [menu insertItemWithTitle:@"baz" action:nil keyEquivalent:@"" atIndex:3];
-    return menu;
-  }
-
-  NSEvent* MouseEvent(NSEventType type) {
-    NSPoint location;
-    if (button_) {
-      // Offset the button's origin to ensure clicks aren't routed to the
-      // border, which may not trigger.
-      location = [button_ frame].origin;
-      location.x += 10;
-      location.y += 10;
-    } else {
-      location.x = location.y = 0;
-    }
-
-    return cocoa_test_event_utils::MouseEventAtPointInWindow(location, type,
-                                                             test_window(), 1);
-  }
-
-  MenuButton* button_;  // Weak, owned by test_window().
-};
-
-TEST_VIEW(MenuButtonTest, button_);
-
-// Test assigning a menu, again mostly to ensure nothing leaks or crashes.
-TEST_F(MenuButtonTest, MenuAssign) {
-  base::scoped_nsobject<NSMenu> menu(CreateMenu());
-  ASSERT_TRUE(menu);
-
-  [button_ setAttachedMenu:menu];
-  EXPECT_TRUE([button_ attachedMenu]);
-}
-
-TEST_F(MenuButtonTest, OpenOnClick) {
-  base::scoped_nsobject<NSMenu> menu(CreateMenu());
-  ASSERT_TRUE(menu);
-
-  base::scoped_nsobject<MenuTestObserver> observer(
-      [[MenuTestObserver alloc] initWithMenu:menu]);
-  ASSERT_TRUE(observer);
-  [observer setCloseAfterOpening:YES];
-
-  [button_ setAttachedMenu:menu];
-  [button_ setOpenMenuOnClick:YES];
-
-  EXPECT_FALSE([observer isOpen]);
-  EXPECT_FALSE([observer didOpen]);
-
-  // Should open the menu.
-  [button_ performClick:nil];
-
-  EXPECT_TRUE([observer didOpen]);
-  EXPECT_FALSE([observer isOpen]);
-}
-
-void OpenOnClickAndHold(MenuButtonTest* test, BOOL does_open_on_click_hold) {
-  base::scoped_nsobject<NSMenu> menu(test->CreateMenu());
-  ASSERT_TRUE(menu);
-
-  MenuButton* button = test->button_;
-
-  base::scoped_nsobject<MenuTestObserver> observer(
-      [[MenuTestObserver alloc] initWithMenu:menu]);
-  ASSERT_TRUE(observer);
-  [observer setCloseAfterOpening:YES];
-
-  [button setAttachedMenu:menu];
-  [button setOpenMenuOnClick:NO];
-  [button setOpenMenuOnClickHold:does_open_on_click_hold];
-
-  EXPECT_FALSE([observer isOpen]);
-  EXPECT_FALSE([observer didOpen]);
-
-  // Post a click-hold-drag event sequence in reverse. The final drag events
-  // needs to have a location that is far enough away from the initial drag
-  // point to cause the menu to open.
-  NSEvent* event = cocoa_test_event_utils::MouseEventAtPointInWindow(
-      NSMakePoint(600, 600), NSLeftMouseUp, test->test_window(), 0);
-  [NSApp postEvent:event atStart:YES];
-
-  event = cocoa_test_event_utils::MouseEventAtPointInWindow(
-      NSMakePoint(500, 500), NSLeftMouseDragged, test->test_window(), 0);
-  [NSApp postEvent:event atStart:YES];
-
-  [NSApp postEvent:test->MouseEvent(NSLeftMouseDragged) atStart:YES];
-
-  // This will cause the tracking loop to start.
-  [button mouseDown:test->MouseEvent(NSLeftMouseDown)];
-
-  EXPECT_EQ(does_open_on_click_hold, [observer didOpen]);
-  EXPECT_FALSE([observer isOpen]);
-}
-
-// Test classic Mac menu behavior.
-TEST_F(MenuButtonTest, OpenOnClickAndHold) {
-  OpenOnClickAndHold(this, YES);
-}
-
-TEST_F(MenuButtonTest, OpenOnClickAndHoldDisabled) {
-  OpenOnClickAndHold(this, NO);
-}
-
-TEST_F(MenuButtonTest, OpenOnRightClick) {
-  base::scoped_nsobject<NSMenu> menu(CreateMenu());
-  ASSERT_TRUE(menu);
-
-  base::scoped_nsobject<MenuTestObserver> observer(
-      [[MenuTestObserver alloc] initWithMenu:menu]);
-  ASSERT_TRUE(observer);
-  [observer setCloseAfterOpening:YES];
-
-  [button_ setAttachedMenu:menu];
-  [button_ setOpenMenuOnClick:YES];
-  // Right click is enabled.
-  [button_ setOpenMenuOnRightClick:YES];
-
-  EXPECT_FALSE([observer isOpen]);
-  EXPECT_FALSE([observer didOpen]);
-
-  // Should open the menu.
-  NSEvent* event = MouseEvent(NSRightMouseDown);
-  [button_ rightMouseDown:event];
-
-  EXPECT_TRUE([observer didOpen]);
-  EXPECT_FALSE([observer isOpen]);
-}
-
-TEST_F(MenuButtonTest, DontOpenOnRightClickWithoutSetRightClick) {
-  base::scoped_nsobject<NSMenu> menu(CreateMenu());
-  ASSERT_TRUE(menu);
-
-  base::scoped_nsobject<MenuTestObserver> observer(
-      [[MenuTestObserver alloc] initWithMenu:menu]);
-  ASSERT_TRUE(observer);
-  [observer setCloseAfterOpening:YES];
-
-  [button_ setAttachedMenu:menu];
-  [button_ setOpenMenuOnClick:YES];
-
-  EXPECT_FALSE([observer isOpen]);
-  EXPECT_FALSE([observer didOpen]);
-
-  // Should not open the menu.
-  NSEvent* event = MouseEvent(NSRightMouseDown);
-  [button_ rightMouseDown:event];
-
-  EXPECT_FALSE([observer didOpen]);
-  EXPECT_FALSE([observer isOpen]);
-
-  // Should open the menu in this case.
-  [button_ performClick:nil];
-
-  EXPECT_TRUE([observer didOpen]);
-  EXPECT_FALSE([observer isOpen]);
-}
-
-TEST_F(MenuButtonTest, OpenOnAccessibilityPerformAction) {
-  base::scoped_nsobject<NSMenu> menu(CreateMenu());
-  ASSERT_TRUE(menu);
-
-  base::scoped_nsobject<MenuTestObserver> observer(
-      [[MenuTestObserver alloc] initWithMenu:menu]);
-  ASSERT_TRUE(observer);
-  [observer setCloseAfterOpening:YES];
-
-  [button_ setAttachedMenu:menu];
-  NSCell* buttonCell = [button_ cell];
-
-  EXPECT_FALSE([observer isOpen]);
-  EXPECT_FALSE([observer didOpen]);
-
-  [button_ setOpenMenuOnClick:YES];
-
-  // NSAccessibilityShowMenuAction should not be available but
-  // NSAccessibilityPressAction should.
-  NSArray* actionNames = [buttonCell accessibilityActionNames];
-  EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-  EXPECT_TRUE([actionNames containsObject:NSAccessibilityPressAction]);
-
-  [button_ setOpenMenuOnClick:NO];
-
-  // NSAccessibilityPressAction should not be the one used to open the menu now.
-  actionNames = [buttonCell accessibilityActionNames];
-  EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-  EXPECT_TRUE([actionNames containsObject:NSAccessibilityPressAction]);
-
-  [buttonCell accessibilityPerformAction:NSAccessibilityShowMenuAction];
-  EXPECT_TRUE([observer didOpen]);
-  EXPECT_FALSE([observer isOpen]);
-}
-
-TEST_F(MenuButtonTest, OpenOnAccessibilityPerformActionWithSetRightClick) {
-  base::scoped_nsobject<NSMenu> menu(CreateMenu());
-  ASSERT_TRUE(menu);
-
-  base::scoped_nsobject<MenuTestObserver> observer(
-      [[MenuTestObserver alloc] initWithMenu:menu]);
-  ASSERT_TRUE(observer);
-  [observer setCloseAfterOpening:YES];
-
-  [button_ setAttachedMenu:menu];
-  NSCell* buttonCell = [button_ cell];
-
-  EXPECT_FALSE([observer isOpen]);
-  EXPECT_FALSE([observer didOpen]);
-
-  [button_ setOpenMenuOnClick:YES];
-
-  // Command to open the menu should not be available.
-  NSArray* actionNames = [buttonCell accessibilityActionNames];
-  EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-
-  [button_ setOpenMenuOnRightClick:YES];
-
-  // Command to open the menu should now become available.
-  actionNames = [buttonCell accessibilityActionNames];
-  EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-
-  [button_ setOpenMenuOnClick:NO];
-
-  // Command should still be available, even when both click + hold and right
-  // click are turned on.
-  actionNames = [buttonCell accessibilityActionNames];
-  EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]);
-
-  [buttonCell accessibilityPerformAction:NSAccessibilityShowMenuAction];
-  EXPECT_TRUE([observer didOpen]);
-  EXPECT_FALSE([observer isOpen]);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm
index a73ad31..6123359 100644
--- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm
@@ -10,7 +10,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
index 2ca85a5d..76a1d0e 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -33,7 +33,6 @@
 #include "chrome/browser/ui/browser_tabstrip.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/browser/ui/cocoa/drag_util.h"
-#import "chrome/browser/ui/cocoa/image_button_cell.h"
 #include "chrome/browser/ui/cocoa/l10n_util.h"
 #import "chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.h"
 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
diff --git a/chrome/browser/ui/cocoa/toolbar/OWNERS b/chrome/browser/ui/cocoa/toolbar/OWNERS
deleted file mode 100644
index fdbfdb1..0000000
--- a/chrome/browser/ui/cocoa/toolbar/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-avi@chromium.org
-rohitrao@chromium.org
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h
deleted file mode 100644
index 2ce1c5203..0000000
--- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_H_
-#define CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#import "chrome/browser/ui/cocoa/menu_button.h"
-#include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
-
-class AnimatedIcon;
-
-// Button for the app toolbar button.
-@interface AppToolbarButton : MenuButton {
- @private
-  AppMenuIconController::Severity severity_;
-  AppMenuIconController::IconType type_;
-
-  // Used for animating and drawing the icon.
-  std::unique_ptr<AnimatedIcon> animatedIcon_;
-
-  // Value of the kAnimatedAppMenuIcon feature's "HasDelay" param.
-  BOOL isDelayEnabled_;
-
-  // Used to delay the animation. Not used if |isDelayEnabled_| is false.
-  // We own the timer and release it when it's completed.
-  NSTimer* animationDelayTimer_;
-
-  // Set true if the timer should be disabled for testing. If it's true,
-  // the timer will still be created but the duration will be set to 0.
-  BOOL disableTimerForTesting_;
-}
-
-- (void)setSeverity:(AppMenuIconController::Severity)severity
-           iconType:(AppMenuIconController::IconType)iconType
-      shouldAnimate:(BOOL)shouldAnimate;
-
-// Animates the icon if possible. If |isDelayEnabled_| and |delay|
-// is true, then set |animationDelayTimer_| if it's not already set.
-- (void)animateIfPossibleWithDelay:(BOOL)delay;
-
-@end
-
-@interface AppToolbarButton (ExposedForTesting)
-
-// Returns |animatedIcon_|.get().
-- (AnimatedIcon*)animatedIcon;
-
-// Sets |animatedIcon_|.
-- (void)setAnimatedIcon:(AnimatedIcon*)icon;
-
-// Returns |animationDelayTimer_|.
-- (NSTimer*)animationDelayTimer;
-
-// Sets |disableTimerForTesting_|.
-- (void)setDisableTimerForTest:(BOOL)disable;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.mm b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.mm
deleted file mode 100644
index 06bacf1..0000000
--- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.mm
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h"
-
-#include "base/macros.h"
-#include "base/metrics/field_trial_params.h"
-#include "chrome/app/vector_icons/vector_icons.h"
-#import "chrome/browser/themes/theme_properties.h"
-#include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/ui/cocoa/animated_icon.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#import "chrome/browser/ui/cocoa/view_id_util.h"
-#include "chrome/common/chrome_features.h"
-#include "chrome/grit/chromium_strings.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/base/theme_provider.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-namespace {
-
-// The duration of the delay in seconds.
-constexpr NSTimeInterval kAnimationDelay = 1.5;
-
-}  // namespace.
-
-@interface AppToolbarButton ()
-- (void)commonInit;
-- (void)updateAnimatedIconColor;
-- (SkColor)vectorIconBaseColor:(BOOL)themeIsDark;
-- (void)updateAnimatedIconColor;
-- (void)animateAndResetTimer;
-@end
-
-@implementation AppToolbarButton
-
-- (instancetype)initWithFrame:(NSRect)frame {
-  if ((self = [super initWithFrame:frame])) {
-    [self commonInit];
-
-    if (base::FeatureList::IsEnabled(features::kAnimatedAppMenuIcon)) {
-      animatedIcon_.reset(new AnimatedIcon(kBrowserToolsAnimatedIcon, self));
-      [self updateAnimatedIconColor];
-
-      NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
-      [center addObserver:self
-                 selector:@selector(themeDidChangeNotification:)
-                     name:kBrowserThemeDidChangeNotification
-                   object:nil];
-
-      isDelayEnabled_ = base::GetFieldTrialParamByFeatureAsBool(
-          features::kAnimatedAppMenuIcon, "HasDelay", false);
-    }
-  }
-  return self;
-}
-
-- (void)dealloc {
-  [[NSNotificationCenter defaultCenter] removeObserver:self];
-
-  // Release the timer.
-  [animationDelayTimer_ invalidate];
-  animationDelayTimer_ = nil;
-
-  [super dealloc];
-}
-
-- (void)awakeFromNib {
-  [self commonInit];
-}
-
-- (void)viewDidMoveToWindow {
-  [super viewDidMoveToWindow];
-  [self updateAnimatedIconColor];
-}
-
-- (void)drawRect:(NSRect)frame {
-  [super drawRect:frame];
-
-  if (animatedIcon_) {
-    gfx::ScopedNSGraphicsContextSaveGState save_graphics_state;
-    NSAffineTransform* transform = [NSAffineTransform transform];
-    [transform translateXBy:-0.5 yBy:0];
-    [transform concat];
-    animatedIcon_->PaintIcon(frame);
-  }
-}
-
-- (void)commonInit {
-  view_id_util::SetID(self, VIEW_ID_APP_MENU);
-  severity_ = AppMenuIconController::Severity::NONE;
-  type_ = AppMenuIconController::IconType::NONE;
-  [self setToolTip:l10n_util::GetNSString(IDS_APPMENU_TOOLTIP)];
-}
-
-- (SkColor)vectorIconBaseColor:(BOOL)themeIsDark {
-  const ui::ThemeProvider* provider = [[self window] themeProvider];
-  return themeIsDark ? SK_ColorWHITE
-                     : (provider && provider->ShouldIncreaseContrast()
-                            ? SK_ColorBLACK
-                            : gfx::kChromeIconGrey);
-}
-
-- (void)updateAnimatedIconColor {
-  if (!animatedIcon_)
-    return;
-
-  const ui::ThemeProvider* provider = [[self window] themeProvider];
-  BOOL themeIsDark = [[self window] hasDarkTheme];
-  SkColor color = provider && provider->UsingSystemTheme()
-                      ? [self vectorIconColor:themeIsDark]
-                      : [self vectorIconBaseColor:themeIsDark];
-  animatedIcon_->set_color(color);
-}
-
-- (const gfx::VectorIcon*)vectorIcon {
-  if (animatedIcon_)
-    return nullptr;
-
-  switch (type_) {
-    case AppMenuIconController::IconType::NONE:
-      DCHECK_EQ(severity_, AppMenuIconController::Severity::NONE);
-      return &kBrowserToolsIcon;
-    case AppMenuIconController::IconType::UPGRADE_NOTIFICATION:
-      return &kBrowserToolsUpdateIcon;
-    case AppMenuIconController::IconType::GLOBAL_ERROR:
-      return &kBrowserToolsErrorIcon;
-  }
-
-  return nullptr;
-}
-
-- (SkColor)vectorIconColor:(BOOL)themeIsDark {
-  switch (severity_) {
-    case AppMenuIconController::Severity::NONE:
-      return [self vectorIconBaseColor:themeIsDark];
-      break;
-
-    case AppMenuIconController::Severity::LOW:
-      return themeIsDark ? gfx::kGoogleGreen300 : gfx::kGoogleGreen700;
-      break;
-
-    case AppMenuIconController::Severity::MEDIUM:
-      return themeIsDark ? gfx::kGoogleYellow300 : gfx::kGoogleYellow700;
-      break;
-
-    case AppMenuIconController::Severity::HIGH:
-      return themeIsDark ? gfx::kGoogleRed300 : gfx::kGoogleRed700;
-      break;
-
-    default:
-      break;
-  }
-}
-
-- (void)setSeverity:(AppMenuIconController::Severity)severity
-           iconType:(AppMenuIconController::IconType)type
-      shouldAnimate:(BOOL)shouldAnimate {
-  if (severity != severity_ || type != type_) {
-    severity_ = severity;
-    type_ = type;
-
-    [self setToolTip:severity_ == AppMenuIconController::Severity::NONE
-                         ? l10n_util::GetNSString(IDS_APPMENU_TOOLTIP)
-                         : l10n_util::GetNSString(
-                               IDS_APPMENU_TOOLTIP_UPDATE_AVAILABLE)];
-
-    if (animatedIcon_) {
-      [self updateAnimatedIconColor];
-      [self animateIfPossibleWithDelay:YES];
-    }
-    // Update the button state images with the new severity color or icon
-    // type.
-    [self resetButtonStateImages];
-  }
-}
-
-- (void)themeDidChangeNotification:(NSNotification*)aNotification {
-  [self updateAnimatedIconColor];
-}
-
-- (void)animateAndResetTimer {
-  animatedIcon_->Animate();
-
-  [animationDelayTimer_ invalidate];
-  animationDelayTimer_ = nil;
-}
-
-- (void)animateIfPossibleWithDelay:(BOOL)delay {
-  if (!animatedIcon_ || severity_ == AppMenuIconController::Severity::NONE)
-    return;
-
-  if (!isDelayEnabled_ || animatedIcon_->IsAnimating()) {
-    // The timer should be nil if the icon is already animating or
-    // the feature's "HasDelay" param is false.
-    DCHECK(!animationDelayTimer_);
-    animatedIcon_->Animate();
-    return;
-  }
-
-  // If there's no delay, fire the animation and remove the timer.
-  if (!delay) {
-    [self animateAndResetTimer];
-    return;
-  }
-
-  // Set the delay timer.
-  if (!animationDelayTimer_) {
-    NSTimeInterval delayInterval =
-        disableTimerForTesting_ ? 0 : kAnimationDelay;
-    animationDelayTimer_ =
-        [NSTimer timerWithTimeInterval:delayInterval
-                                target:self
-                              selector:@selector(animateAndResetTimer)
-                              userInfo:nil
-                               repeats:NO];
-    [[NSRunLoop currentRunLoop] addTimer:animationDelayTimer_
-                                 forMode:NSRunLoopCommonModes];
-  }
-}
-
-@end
-
-@implementation AppToolbarButton (ExposedForTest)
-
-- (AnimatedIcon*)animatedIcon {
-  return animatedIcon_.get();
-}
-
-- (void)setAnimatedIcon:(AnimatedIcon*)icon {
-  animatedIcon_.reset(icon);
-}
-
-- (NSTimer*)animationDelayTimer {
-  return animationDelayTimer_;
-}
-
-- (void)setDisableTimerForTest:(BOOL)disable {
-  disableTimerForTesting_ = disable;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h
deleted file mode 100644
index b8ffa69..0000000
--- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_CELL_H_
-#define CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_CELL_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
-
-
-// Cell for the app toolbar button. This is used to draw the app menu icon
-// and paint severity levels.
-@interface AppToolbarButtonCell : ClickHoldButtonCell {
-}
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.mm b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.mm
deleted file mode 100644
index 43c26ea..0000000
--- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.mm
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h"
-
-#include "base/macros.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#include "ui/gfx/canvas_skia_paint.h"
-#include "ui/gfx/geometry/rect.h"
-
-@interface AppToolbarButtonCell ()
-- (void)commonInit;
-@end
-
-@implementation AppToolbarButtonCell
-
-- (id)initTextCell:(NSString*)text {
-  if ((self = [super initTextCell:text])) {
-    [self commonInit];
-  }
-  return self;
-}
-
-- (id)initWithCoder:(NSCoder*)decoder {
-  if ((self = [super initWithCoder:decoder])) {
-    [self commonInit];
-  }
-  return self;
-}
-
-- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
-  gfx::CanvasSkiaPaint canvas(cellFrame, false);
-  canvas.set_composite_alpha(true);
-  canvas.SaveLayerAlpha(255 *
-                        [self imageAlphaForWindowState:[controlView window]]);
-
-  canvas.Restore();
-}
-
-- (void)commonInit {
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm
deleted file mode 100644
index 25603a3..0000000
--- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h"
-
-#include "base/macros.h"
-#include "base/test/scoped_task_environment.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-
-@interface TestAppToolbarButton : NSButton
-@end
-
-@implementation TestAppToolbarButton
-
-+ (Class)cellClass {
-  return [AppToolbarButtonCell class];
-}
-
-@end
-
-class AppToolbarButtonCellTest : public CocoaTest {
- protected:
-  AppToolbarButtonCellTest()
-      : scoped_task_environment_(
-            base::test::ScopedTaskEnvironment::MainThreadType::UI) {
-    base::scoped_nsobject<NSButton> button([[TestAppToolbarButton alloc]
-        initWithFrame:NSMakeRect(0, 0, 29, 29)]);
-    button_ = button;
-    [[test_window() contentView] addSubview:button_];
-  }
-
-  NSButton* button_;
-  base::scoped_nsobject<AppToolbarButtonCell> cell_;
-
-  // Needed for gfx::Animation.
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AppToolbarButtonCellTest);
-};
-
-TEST_VIEW(AppToolbarButtonCellTest, button_)
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_unittest.mm b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_unittest.mm
deleted file mode 100644
index 0ddb8bd..0000000
--- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_unittest.mm
+++ /dev/null
@@ -1,194 +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 "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h"
-
-#include "base/metrics/field_trial.h"
-#include "base/metrics/field_trial_param_associator.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/browser/ui/cocoa/animated_icon.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
-#include "chrome/common/chrome_features.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// Test class for AnimatedIcon. Used to check if Animate() is called.
-class TestAnimatedIcon : public AnimatedIcon {
- public:
-  TestAnimatedIcon();
-
-  // AnimatedIcon:
-  void Animate() override;
-  bool IsAnimating() const override;
-
-  // Sets |is_animating_| to false.
-  void ResetAnimatingFlag();
-
-  bool is_animating() const { return is_animating_; }
-
- private:
-  bool is_animating_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestAnimatedIcon);
-};
-
-TestAnimatedIcon::TestAnimatedIcon()
-    : AnimatedIcon(kBrowserToolsAnimatedIcon, nil), is_animating_(false) {}
-
-void TestAnimatedIcon::Animate() {
-  is_animating_ = true;
-}
-
-bool TestAnimatedIcon::IsAnimating() const {
-  return is_animating_;
-}
-
-void TestAnimatedIcon::ResetAnimatingFlag() {
-  is_animating_ = false;
-}
-
-class AppToolbarButtonTest : public CocoaTest {
- protected:
-  AppToolbarButtonTest()
-      : field_trial_list_(new base::FieldTrialList(nullptr)) {}
-
-  // Enables the Animated App Menu Icon feature and set the "HasDelay"
-  // parameter to |with_delay|.
-  void EnableFeatureList(bool with_delay) {
-    field_trial_list_.reset();
-    field_trial_list_.reset(new base::FieldTrialList(nullptr));
-
-    base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
-    const char kTrialName[] = "TrialName";
-    const char kGroupName[] = "GroupName";
-
-    std::map<std::string, std::string> params;
-    params["HasDelay"] = with_delay ? "true" : "false";
-    ASSERT_TRUE(
-        base::AssociateFieldTrialParams(kTrialName, kGroupName, params));
-    base::FieldTrial* field_trial =
-        base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
-
-    std::unique_ptr<base::FeatureList> feature_list(
-        std::make_unique<base::FeatureList>());
-    feature_list->RegisterFieldTrialOverride(
-        features::kAnimatedAppMenuIcon.name,
-        base::FeatureList::OVERRIDE_ENABLE_FEATURE, field_trial);
-    scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
-  }
-
-  // Sets the severity level of |button_|.
-  void SetSeverityLevel(AppMenuIconController::Severity level) {
-    [button_ setSeverity:level
-                iconType:AppMenuIconController::IconType::NONE
-           shouldAnimate:YES];
-  }
-
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  std::unique_ptr<base::FieldTrialList> field_trial_list_;
-
-  base::scoped_nsobject<AppToolbarButton> button_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AppToolbarButtonTest);
-};
-
-// Tests the old icon. |animatedIcon_| in |button_| should be nil.
-TEST_F(AppToolbarButtonTest, OldAppToolbarIcon) {
-  scoped_feature_list_.InitAndDisableFeature(features::kAnimatedAppMenuIcon);
-  button_.reset([[AppToolbarButton alloc] initWithFrame:NSZeroRect]);
-  EXPECT_FALSE([button_ animatedIcon]);
-}
-
-// Tests the new icon with "HasDelay" set to false.
-TEST_F(AppToolbarButtonTest, NewAppToolbarIcon_NoDelay) {
-  EnableFeatureList(false);
-  button_.reset([[AppToolbarButton alloc] initWithFrame:NSZeroRect]);
-  EXPECT_TRUE([button_ animatedIcon]);
-
-  TestAnimatedIcon* test_icon = new TestAnimatedIcon();
-  [button_ setAnimatedIcon:test_icon];
-  [button_ setDisableTimerForTest:YES];
-
-  // Icon should not animate for the NONE severity level.
-  SetSeverityLevel(AppMenuIconController::Severity::NONE);
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_FALSE(test_icon->is_animating());
-
-  test_icon->ResetAnimatingFlag();
-
-  // Icon should animate for the other severity levels.
-  // The animationDelayTimer should always be nil since "HasDelay" param of
-  // the feature is false.
-  SetSeverityLevel(AppMenuIconController::Severity::LOW);
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_TRUE(test_icon->is_animating());
-
-  test_icon->ResetAnimatingFlag();
-
-  SetSeverityLevel(AppMenuIconController::Severity::MEDIUM);
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_TRUE(test_icon->is_animating());
-
-  test_icon->ResetAnimatingFlag();
-
-  SetSeverityLevel(AppMenuIconController::Severity::HIGH);
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_TRUE(test_icon->is_animating());
-}
-
-// Tests the new icon with "HasDelay" set to true.
-TEST_F(AppToolbarButtonTest, NewAppToolbarIcon_HasDelay) {
-  EnableFeatureList(true);
-  button_.reset([[AppToolbarButton alloc] initWithFrame:NSZeroRect]);
-  EXPECT_TRUE([button_ animatedIcon]);
-
-  TestAnimatedIcon* test_icon = new TestAnimatedIcon();
-  [button_ setAnimatedIcon:test_icon];
-  [button_ setDisableTimerForTest:YES];
-
-  // Icon should not animate for the NONE severity level.
-  SetSeverityLevel(AppMenuIconController::Severity::NONE);
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_FALSE(test_icon->is_animating());
-
-  test_icon->ResetAnimatingFlag();
-
-  // Icon should try to animate for the other severity levels. Since the
-  // "HasDelay" param of the feature is true, the icon shouldn't animate.
-  // Instead, the animation delay timer should be set.
-  SetSeverityLevel(AppMenuIconController::Severity::LOW);
-  chrome::testing::NSRunLoopRunAllPending();
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_TRUE(test_icon->is_animating());
-
-  test_icon->ResetAnimatingFlag();
-
-  SetSeverityLevel(AppMenuIconController::Severity::MEDIUM);
-  chrome::testing::NSRunLoopRunAllPending();
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_TRUE(test_icon->is_animating());
-
-  test_icon->ResetAnimatingFlag();
-
-  SetSeverityLevel(AppMenuIconController::Severity::HIGH);
-  chrome::testing::NSRunLoopRunAllPending();
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_TRUE(test_icon->is_animating());
-
-  // Animate the icon without delay. The animation delay should be nil.
-  [button_ animateIfPossibleWithDelay:NO];
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_TRUE(test_icon->is_animating());
-
-  // Calling [animateIfPossibleWithDelay:YES] should re-animate the icon
-  // without delay if the icon is already animating.
-  [button_ animateIfPossibleWithDelay:YES];
-  EXPECT_FALSE([button_ animationDelayTimer]);
-  EXPECT_TRUE(test_icon->is_animating());
-}
diff --git a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h b/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h
deleted file mode 100644
index 7aa41fb..0000000
--- a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_BACK_FORWARD_MENU_CONTROLLER_H_
-#define CHROME_BROWSER_UI_COCOA_TOOLBAR_BACK_FORWARD_MENU_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/has_weak_browser_pointer.h"
-#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
-
-@class MenuButton;
-
-typedef BackForwardMenuModel::ModelType BackForwardMenuType;
-const BackForwardMenuType BACK_FORWARD_MENU_TYPE_BACK =
-    BackForwardMenuModel::ModelType::kBackward;
-const BackForwardMenuType BACK_FORWARD_MENU_TYPE_FORWARD =
-    BackForwardMenuModel::ModelType::kForward;
-
-// A class that manages the back/forward menu (and delayed-menu button, and
-// model).
-// Implement HasWeakBrowserPointer so we can clean up if the Browser is
-// destroyed.
-@interface BackForwardMenuController
-    : NSObject<NSMenuDelegate, HasWeakBrowserPointer> {
- @private
-  BackForwardMenuType type_;
-  MenuButton* button_;  // Weak; comes from nib.
-  std::unique_ptr<BackForwardMenuModel> model_;
-  base::scoped_nsobject<NSMenu> backForwardMenu_;
-}
-
-// Type (back or forwards); can only be set on initialization.
-@property(readonly, nonatomic) BackForwardMenuType type;
-
-- (id)initWithBrowser:(Browser*)browser
-            modelType:(BackForwardMenuType)type
-               button:(MenuButton*)button;
-
-@end  // @interface BackForwardMenuController
-
-#endif  // CHROME_BROWSER_UI_COCOA_TOOLBAR_BACK_FORWARD_MENU_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.mm b/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.mm
deleted file mode 100644
index 4c79dff..0000000
--- a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.mm
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "base/strings/sys_string_conversions.h"
-#import "chrome/browser/ui/cocoa/menu_button.h"
-#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
-#import "ui/events/event_utils.h"
-#include "ui/gfx/image/image.h"
-
-using base::SysUTF16ToNSString;
-
-@implementation BackForwardMenuController
-
-// Accessors and mutators:
-
-@synthesize type = type_;
-
-// Own methods:
-
-- (id)initWithBrowser:(Browser*)browser
-            modelType:(BackForwardMenuType)type
-               button:(MenuButton*)button {
-  if ((self = [super init])) {
-    type_ = type;
-    button_ = button;
-    model_.reset(new BackForwardMenuModel(browser, type_));
-    DCHECK(model_.get());
-    backForwardMenu_.reset([[NSMenu alloc] initWithTitle:@""]);
-    DCHECK(backForwardMenu_.get());
-    [backForwardMenu_ setDelegate:self];
-
-    [button_ setAttachedMenu:backForwardMenu_];
-    [button_ setOpenMenuOnClick:NO];
-  }
-  return self;
-}
-
-- (void)browserWillBeDestroyed {
-  [button_ setAttachedMenu:nil];
-  [backForwardMenu_ setDelegate:nil];
-  backForwardMenu_.reset();
-  model_.reset();
-}
-
-// Methods as delegate:
-
-// Called by backForwardMenu_ just before tracking begins.
-//TODO(viettrungluu): should we do anything for chapter stops (see model)?
-- (void)menuNeedsUpdate:(NSMenu*)menu {
-  DCHECK(menu == backForwardMenu_);
-
-  // Remove old menu items (backwards order is as good as any).
-  for (NSInteger i = [menu numberOfItems]; i > 0; i--)
-    [menu removeItemAtIndex:(i - 1)];
-
-  // 0-th item must be blank. (This is because we use a pulldown list, for which
-  // Cocoa uses the 0-th item as "title" in the button.)
-  [menu insertItemWithTitle:@""
-                     action:nil
-              keyEquivalent:@""
-                    atIndex:0];
-  for (int menuID = 0; menuID < model_->GetItemCount(); menuID++) {
-    if (model_->IsSeparator(menuID)) {
-      [menu insertItem:[NSMenuItem separatorItem]
-               atIndex:(menuID + 1)];
-    } else {
-      // Create a menu item with the right label.
-      NSMenuItem* menuItem = [[NSMenuItem alloc]
-              initWithTitle:SysUTF16ToNSString(model_->GetLabelAt(menuID))
-                     action:nil
-              keyEquivalent:@""];
-      [menuItem autorelease];
-
-      gfx::Image icon;
-      // Icon (if it has one).
-      if (model_->GetIconAt(menuID, &icon))
-        [menuItem setImage:icon.ToNSImage()];
-
-      // This will make it call our |-executeMenuItem:| method. We store the
-      // |menuID| (or |menu_id|) in the tag.
-      [menuItem setTag:menuID];
-      [menuItem setTarget:self];
-      [menuItem setAction:@selector(executeMenuItem:)];
-
-      // Put it in the menu!
-      [menu insertItem:menuItem
-               atIndex:(menuID + 1)];
-    }
-  }
-}
-
-// Action methods:
-
-- (void)executeMenuItem:(id)sender {
-  DCHECK([sender isKindOfClass:[NSMenuItem class]]);
-  int menuID = [sender tag];
-  int event_flags = ui::EventFlagsFromNative([NSApp currentEvent]);
-  model_->ActivatedAt(menuID, event_flags);
-}
-
-@end  // @implementation BackForwardMenuController
diff --git a/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h b/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h
deleted file mode 100644
index 17af843f..0000000
--- a/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_RELOAD_BUTTON_COCOA_H_
-#define CHROME_BROWSER_UI_COCOA_TOOLBAR_RELOAD_BUTTON_COCOA_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
-#import "chrome/browser/ui/cocoa/menu_button.h"
-
-// ToolbarButtonCocoa subclass which defers certain state changes when the mouse
-// is hovering over it.
-
-class CommandUpdater;
-
-@interface ReloadButtonCocoa : MenuButton<ImageButton> {
- @private
-  // Timer used when setting reload mode while the mouse is hovered.
-  NSTimer* pendingReloadTimer_;
-  base::scoped_nsobject<NSMenu> menu_;
-  CommandUpdater* commandUpdater_; // weak, set by toolbar controller.
-}
-
-// Update the tag, and the image and tooltip to match.  If |anInt|
-// matches the current tag, no action is taken.  |anInt| must be
-// either |IDC_STOP| or |IDC_RELOAD|.
-- (void)updateTag:(NSInteger)anInt;
-
-// Update the button to be a reload button or stop button depending on
-// |isLoading|.  If |force|, always sets the indicated mode.  If
-// |!force|, and the mouse is over the button, defer the transition
-// from stop button to reload button until the mouse has left the
-// button, or until |pendingReloadTimer_| fires.  This prevents an
-// inadvertent click _just_ as the state changes.
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
-
-// Changes whether reload button shows menu.
-- (void)setMenuEnabled:(BOOL)enabled;
-
-- (void)setCommandUpdater:(CommandUpdater*)commandUpdater;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TOOLBAR_RELOAD_BUTTON_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.mm
deleted file mode 100644
index a5acb2c..0000000
--- a/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.mm
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h"
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/browser/command_updater.h"
-#include "chrome/browser/global_keyboard_shortcuts_mac.h"
-#import "chrome/browser/ui/cocoa/accelerators_cocoa.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#import "chrome/browser/ui/cocoa/view_id_util.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/vector_icons/vector_icons.h"
-#include "ui/base/accelerators/platform_accelerator_cocoa.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/material_design/material_design_controller.h"
-#import "ui/events/event_utils.h"
-
-namespace {
-
-// Constant matches Windows.
-NSTimeInterval kPendingReloadTimeout = 1.35;
-
-// Contents of the Reload drop-down menu.
-const int kReloadMenuItems[]  = {
-  IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM,
-  IDS_RELOAD_MENU_HARD_RELOAD_ITEM,
-  IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM,
-};
-// Note: must have the same size as |kReloadMenuItems|.
-const int kReloadMenuCommands[]  = {
-  IDC_RELOAD,
-  IDC_RELOAD_BYPASSING_CACHE,
-  IDC_RELOAD_CLEARING_CACHE,
-};
-
-}  // namespace
-
-@interface ReloadButtonCocoa ()
-- (void)invalidatePendingReloadTimer;
-- (void)forceReloadState:(NSTimer *)timer;
-- (void)populateMenu;
-@end
-
-@implementation ReloadButtonCocoa
-
-+ (Class)cellClass {
-  return [ClickHoldButtonCell class];
-}
-
-- (id)initWithFrame:(NSRect)frameRect {
-  if ((self = [super initWithFrame:frameRect])) {
-    // Since this is not a custom view, -awakeFromNib won't be called twice.
-    [self awakeFromNib];
-  }
-  return self;
-}
-
-- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
-  // If this view is moved to a new window, reset its state.
-  [self setIsLoading:NO force:YES];
-  [super viewWillMoveToWindow:newWindow];
-}
-
-- (void)awakeFromNib {
-  // Don't allow multi-clicks, because the user probably wouldn't ever
-  // want to stop+reload or reload+stop.
-  [self setIgnoresMultiClick:YES];
-
-  [self setOpenMenuOnRightClick:YES];
-  [self setOpenMenuOnClick:NO];
-
-  menu_.reset([[NSMenu alloc] initWithTitle:@""]);
-  [self populateMenu];
-  [self setAttachedMenu:menu_];
-}
-
-- (BOOL)shouldMirrorInRTL {
-  return NO;
-}
-
-- (void)invalidatePendingReloadTimer {
-  [pendingReloadTimer_ invalidate];
-  pendingReloadTimer_ = nil;
-}
-
-- (void)updateTag:(NSInteger)anInt {
-  if ([self tag] == anInt)
-    return;
-
-  // Forcibly remove any stale tooltip which is being displayed.
-  [self removeAllToolTips];
-  [self setTag:anInt];
-
-  [self resetButtonStateImages];
-  if (anInt == IDC_RELOAD) {
-    [self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_RELOAD)];
-  } else if (anInt == IDC_STOP) {
-    [self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STOP)];
-  } else {
-    NOTREACHED();
-  }
-}
-
-- (id)accessibilityAttributeValue:(NSString *)attribute {
-  if ([attribute isEqualToString:NSAccessibilityEnabledAttribute] &&
-      pendingReloadTimer_) {
-    return [NSNumber numberWithBool:NO];
-  } else {
-    return [super accessibilityAttributeValue:attribute];
-  }
-}
-
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
-  // Can always transition to stop mode.  Only transition to reload
-  // mode if forced or if the mouse isn't hovering.  Otherwise, note
-  // that reload mode is desired and disable the button.
-  if (isLoading) {
-    [self invalidatePendingReloadTimer];
-    [self updateTag:IDC_STOP];
-  } else if (force) {
-    [self invalidatePendingReloadTimer];
-    [self updateTag:IDC_RELOAD];
-  } else if ([self tag] == IDC_STOP &&
-             !pendingReloadTimer_ &&
-             [[self cell] isMouseInside]) {
-    [self resetButtonStateImages];
-    NSImage* disabledStopImage =
-        [[self cell] imageForState:image_button_cell::kDisabledState
-                              view:self];
-    [[self cell] setImage:disabledStopImage
-        forButtonState:image_button_cell::kDefaultState];
-    [[self cell] setImage:disabledStopImage
-        forButtonState:image_button_cell::kHoverState];
-    [[self cell] setImage:disabledStopImage
-        forButtonState:image_button_cell::kPressedState];
-    pendingReloadTimer_ =
-        [NSTimer timerWithTimeInterval:kPendingReloadTimeout
-                                target:self
-                              selector:@selector(forceReloadState:)
-                              userInfo:nil
-                               repeats:NO];
-    // Must add the timer to |NSRunLoopCommonModes| because
-    // it should run in |NSEventTrackingRunLoopMode| as well as
-    // |NSDefaultRunLoopMode|.
-    [[NSRunLoop currentRunLoop] addTimer:pendingReloadTimer_
-                                 forMode:NSRunLoopCommonModes];
-  } else {
-    [self invalidatePendingReloadTimer];
-    [self updateTag:IDC_RELOAD];
-  }
-  [self setEnabled:pendingReloadTimer_ == nil];
-}
-
-- (void)setMenuEnabled:(BOOL)enabled {
-  [self setOpenMenuOnRightClick:enabled];
-  [self setOpenMenuOnClickHold:enabled];
-}
-
-- (void)setCommandUpdater:(CommandUpdater*)commandUpdater {
-  commandUpdater_ = commandUpdater;
-}
-
-- (void)forceReloadState:(NSTimer *)timer {
-  DCHECK_EQ(timer, pendingReloadTimer_);
-  [self setIsLoading:NO force:YES];
-  // Verify that |pendingReloadTimer_| is nil so it is not left dangling.
-  DCHECK(!pendingReloadTimer_);
-}
-
-- (BOOL)sendAction:(SEL)theAction to:(id)theTarget {
-  if ([self tag] == IDC_STOP) {
-    if (pendingReloadTimer_) {
-      // If |pendingReloadTimer_| then the control is currently being
-      // drawn in a disabled state, so just return. The control is NOT actually
-      // disabled, otherwise mousetracking (courtesy of the NSButtonCell)
-      // would not work.
-      return YES;
-    } else {
-      // When the stop is processed, immediately change to reload mode,
-      // even though the IPC still has to bounce off the renderer and
-      // back before the regular |-setIsLoaded:force:| will be called.
-      // [This is how views and gtk do it.]
-      BOOL ret = [super sendAction:theAction to:theTarget];
-      if (ret)
-        [self forceReloadState:pendingReloadTimer_];
-      return ret;
-    }
-  }
-
-  return [super sendAction:theAction to:theTarget];
-}
-
-- (ViewID)viewID {
-  return VIEW_ID_RELOAD_BUTTON;
-}
-
-- (const gfx::VectorIcon*)vectorIcon {
-  if ([self tag] == IDC_RELOAD) {
-    return &vector_icons::kReloadIcon;
-  } else if ([self tag] == IDC_STOP) {
-    return &kNavigateStopIcon;
-  } else {
-    NOTREACHED();
-  }
-
-  return nullptr;
-}
-
-- (void)mouseInsideStateDidChange:(BOOL)isInside {
-  [pendingReloadTimer_ fire];
-}
-
-- (void)populateMenu {
-  [menu_ setAutoenablesItems:NO];
-  // 0-th item must be blank. (This is because we use a pulldown list, for which
-  // Cocoa uses the 0-th item as "title" in the button.)
-  [menu_ addItemWithTitle:@""
-                   action:nil
-            keyEquivalent:@""];
-  for (size_t i = 0; i < arraysize(kReloadMenuItems); ++i) {
-    NSString* title = l10n_util::GetNSStringWithFixup(kReloadMenuItems[i]);
-    base::scoped_nsobject<NSMenuItem> item(
-        [[NSMenuItem alloc] initWithTitle:title
-                                   action:@selector(executeMenuItem:)
-                            keyEquivalent:@""]);
-
-    ui::Accelerator accelerator;
-    bool found = GetDefaultMacAcceleratorForCommandId(kReloadMenuCommands[i],
-                                                      &accelerator);
-    if (found) {
-      NSString* key_equivalent;
-      NSUInteger modifier_mask;
-      GetKeyEquivalentAndModifierMaskFromAccelerator(
-          accelerator, &key_equivalent, &modifier_mask);
-      [item setKeyEquivalent:key_equivalent];
-      [item setKeyEquivalentModifierMask:modifier_mask];
-    }
-
-    [item setTag:kReloadMenuCommands[i]];
-    [item setTarget:self];
-    [item setEnabled:YES];
-
-    [menu_ addItem:item];
-  }
-}
-
-// Action for menu items.
-- (void)executeMenuItem:(id)sender {
-  if (!commandUpdater_)
-    return;
-  DCHECK([sender isKindOfClass:[NSMenuItem class]]);
-  int command = [sender tag];
-  int event_flags = ui::EventFlagsFromNative([NSApp currentEvent]);
-  commandUpdater_->ExecuteCommandWithDisposition(
-      command, ui::DispositionFromEventFlags(event_flags));
-}
-
-@end  // ReloadButtonCocoa
-
-@implementation ReloadButtonCocoa (Testing)
-
-+ (void)setPendingReloadTimeout:(NSTimeInterval)seconds {
-  kPendingReloadTimeout = seconds;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/toolbar/reload_button_unittest_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/reload_button_unittest_cocoa.mm
deleted file mode 100644
index ca4ec407..0000000
--- a/chrome/browser/ui/cocoa/toolbar/reload_button_unittest_cocoa.mm
+++ /dev/null
@@ -1,311 +0,0 @@
-// Copyright (c) 2011 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 <Cocoa/Cocoa.h>
-
-#import "chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h"
-
-#include "base/mac/scoped_nsobject.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/ui/cocoa/image_button_cell.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-#import "ui/base/test/menu_test_observer.h"
-#import "ui/events/test/cocoa_test_event_utils.h"
-
-@interface ReloadButtonCocoa (TestForwardDeclares)
-+ (void)setPendingReloadTimeout:(NSTimeInterval)seconds;
-@end
-
-@implementation ReloadButtonCocoa (TestImplementation)
-- (NSMenu*)menuForTesting {
-  return menu_;
-}
-@end
-
-@interface ReloadButtonTarget : NSObject
-- (void)anAction:(id)sender;
-@end
-
-@implementation ReloadButtonTarget
-- (void)anAction:(id)sender {
-}
-@end
-
-namespace {
-
-class ReloadButtonCocoaTest : public CocoaTest {
- public:
-  ReloadButtonCocoaTest() {
-    NSRect frame = NSMakeRect(0, 0, 20, 20);
-    base::scoped_nsobject<ReloadButtonCocoa> button(
-        [[ReloadButtonCocoa alloc] initWithFrame:frame]);
-    button_ = button;
-
-    // Set things up so unit tests have a reliable baseline.
-    [button_ setTag:IDC_RELOAD];
-    [button_ awakeFromNib];
-
-    [[test_window() contentView] addSubview:button_];
-  }
-
-  bool IsMouseInside() {
-    return [[button_ cell] isMouseInside];
-  }
-
-  void MouseEnter() {
-    [[button_ cell] mouseEntered:cocoa_test_event_utils::EnterEvent()];
-  }
-
-  void MouseExit() {
-    [[button_ cell] mouseExited:cocoa_test_event_utils::ExitEvent()];
-  }
-
-  ReloadButtonCocoa* button_;  // Weak, owned by test_window().
-};
-
-TEST_VIEW(ReloadButtonCocoaTest, button_)
-
-// Test that mouse-tracking is setup and does the right thing.
-TEST_F(ReloadButtonCocoaTest, IsMouseInside) {
-  EXPECT_FALSE(IsMouseInside());
-  MouseEnter();
-  EXPECT_TRUE(IsMouseInside());
-  MouseExit();
-}
-
-// Verify that multiple clicks do not result in multiple messages to
-// the target.
-TEST_F(ReloadButtonCocoaTest, IgnoredMultiClick) {
-  base::scoped_nsobject<ReloadButtonTarget> target(
-      [[ReloadButtonTarget alloc] init]);
-  id mock_target = [OCMockObject partialMockForObject:target];
-  [button_ setTarget:mock_target];
-  [button_ setAction:@selector(anAction:)];
-
-  // Expect the action once.
-  [[mock_target expect] anAction:button_];
-
-  const std::pair<NSEvent*,NSEvent*> click_one =
-      cocoa_test_event_utils::MouseClickInView(button_, 1);
-  const std::pair<NSEvent*,NSEvent*> click_two =
-      cocoa_test_event_utils::MouseClickInView(button_, 2);
-  [NSApp postEvent:click_one.second atStart:YES];
-  [button_ mouseDown:click_one.first];
-  [NSApp postEvent:click_two.second atStart:YES];
-  [button_ mouseDown:click_two.first];
-
-  [button_ setTarget:nil];
-}
-
-TEST_F(ReloadButtonCocoaTest, UpdateTag) {
-  [button_ setTag:IDC_STOP];
-
-  [button_ updateTag:IDC_RELOAD];
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-  NSString* const reloadToolTip = [button_ toolTip];
-
-  [button_ updateTag:IDC_STOP];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-  NSString* const stopToolTip = [button_ toolTip];
-  EXPECT_NSNE(reloadToolTip, stopToolTip);
-
-  [button_ updateTag:IDC_RELOAD];
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-  EXPECT_NSEQ(reloadToolTip, [button_ toolTip]);
-}
-
-// Test that when forcing the mode, it takes effect immediately,
-// regardless of whether the mouse is hovering.
-TEST_F(ReloadButtonCocoaTest, SetIsLoadingForce) {
-  EXPECT_FALSE(IsMouseInside());
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
-  // Changes to stop immediately.
-  [button_ setIsLoading:YES force:YES];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-
-  // Changes to reload immediately.
-  [button_ setIsLoading:NO force:YES];
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
-  // Changes to stop immediately when the mouse is hovered, and
-  // doesn't change when the mouse exits.
-  MouseEnter();
-  EXPECT_TRUE(IsMouseInside());
-  [button_ setIsLoading:YES force:YES];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-  MouseExit();
-  EXPECT_FALSE(IsMouseInside());
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-
-  // Changes to reload immediately when the mouse is hovered, and
-  // doesn't change when the mouse exits.
-  MouseEnter();
-  EXPECT_TRUE(IsMouseInside());
-  [button_ setIsLoading:NO force:YES];
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-  MouseExit();
-  EXPECT_FALSE(IsMouseInside());
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-}
-
-// Test that without force, stop mode is set immediately, but reload
-// is affected by the hover status.
-TEST_F(ReloadButtonCocoaTest, SetIsLoadingNoForceUnHover) {
-  EXPECT_FALSE(IsMouseInside());
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
-  // Changes to stop immediately when the mouse is not hovering.
-  [button_ setIsLoading:YES force:NO];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-
-  // Changes to reload immediately when the mouse is not hovering.
-  [button_ setIsLoading:NO force:NO];
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
-  // Changes to stop immediately when the mouse is hovered, and
-  // doesn't change when the mouse exits.
-  MouseEnter();
-  EXPECT_TRUE(IsMouseInside());
-  [button_ setIsLoading:YES force:NO];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-  MouseExit();
-  EXPECT_FALSE(IsMouseInside());
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-
-  // Does not change to reload immediately when the mouse is hovered,
-  // changes when the mouse exits.
-  MouseEnter();
-  EXPECT_TRUE(IsMouseInside());
-  [button_ setIsLoading:NO force:NO];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-  MouseExit();
-  EXPECT_FALSE(IsMouseInside());
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-}
-
-// Test that without force, stop mode is set immediately, and reload
-// will be set after a timeout.
-// TODO(shess): Reenable, http://crbug.com/61485
-TEST_F(ReloadButtonCocoaTest, DISABLED_SetIsLoadingNoForceTimeout) {
-  // When the event loop first spins, some delayed tracking-area setup
-  // is done, which causes -mouseExited: to be called.  Spin it at
-  // least once, and dequeue any pending events.
-  // TODO(shess): It would be more reasonable to have an MockNSTimer
-  // factory for the class to use, which this code could fire
-  // directly.
-  while ([NSApp nextEventMatchingMask:NSAnyEventMask
-                            untilDate:nil
-                               inMode:NSDefaultRunLoopMode
-                              dequeue:YES]) {
-  }
-
-  const NSTimeInterval kShortTimeout = 0.1;
-  [ReloadButtonCocoa setPendingReloadTimeout:kShortTimeout];
-
-  EXPECT_FALSE(IsMouseInside());
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
-  // Move the mouse into the button and press it.
-  MouseEnter();
-  EXPECT_TRUE(IsMouseInside());
-  [button_ setIsLoading:YES force:NO];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-
-  // Does not change to reload immediately when the mouse is hovered.
-  EXPECT_TRUE(IsMouseInside());
-  [button_ setIsLoading:NO force:NO];
-  EXPECT_TRUE(IsMouseInside());
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-  EXPECT_TRUE(IsMouseInside());
-
-  // Spin event loop until the timeout passes.
-  NSDate* pastTimeout = [NSDate dateWithTimeIntervalSinceNow:2 * kShortTimeout];
-  [NSApp nextEventMatchingMask:NSAnyEventMask
-                     untilDate:pastTimeout
-                        inMode:NSDefaultRunLoopMode
-                       dequeue:NO];
-
-  // Mouse is still hovered, button is in reload mode.  If the mouse
-  // is no longer hovered, see comment at top of function.
-  EXPECT_TRUE(IsMouseInside());
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-}
-
-// Test that pressing stop after reload mode has been requested
-// doesn't forward the stop message.
-TEST_F(ReloadButtonCocoaTest, StopAfterReloadSet) {
-  base::scoped_nsobject<ReloadButtonTarget> target(
-      [[ReloadButtonTarget alloc] init]);
-  id mock_target = [OCMockObject partialMockForObject:target];
-  [button_ setTarget:mock_target];
-  [button_ setAction:@selector(anAction:)];
-
-  EXPECT_FALSE(IsMouseInside());
-
-  // Get to stop mode.
-  [button_ setIsLoading:YES force:YES];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-  EXPECT_TRUE([button_ isEnabled]);
-
-  // Expect the action once.
-  [[mock_target expect] anAction:button_];
-
-  // Clicking in stop mode should send the action and transition to
-  // reload mode.
-  const std::pair<NSEvent*,NSEvent*> click =
-      cocoa_test_event_utils::MouseClickInView(button_, 1);
-  [NSApp postEvent:click.second atStart:YES];
-  [button_ mouseDown:click.first];
-  EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-  EXPECT_TRUE([button_ isEnabled]);
-
-  // Get back to stop mode.
-  [button_ setIsLoading:YES force:YES];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-  EXPECT_TRUE([button_ isEnabled]);
-
-  // If hover prevented reload mode immediately taking effect, clicks should do
-  // nothing, because the button should be disabled.
-  MouseEnter();
-  EXPECT_TRUE(IsMouseInside());
-  [button_ setIsLoading:NO force:NO];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-  EXPECT_FALSE([button_ isEnabled]);
-  [NSApp postEvent:click.second atStart:YES];
-  [button_ mouseDown:click.first];
-  EXPECT_EQ(IDC_STOP, [button_ tag]);
-
-  [button_ setTarget:nil];
-}
-
-TEST_F(ReloadButtonCocoaTest, RightClickMenu) {
-  base::scoped_nsobject<MenuTestObserver> observer(
-      [[MenuTestObserver alloc] initWithMenu:[button_ menuForTesting]]);
-  [observer setCloseAfterOpening:YES];
-
-  // When the menu is enabled, it should open on right click only.
-  [button_ setMenuEnabled:YES];
-
-  NSEvent* event = cocoa_test_event_utils::LeftMouseDownAtPoint(NSZeroPoint);
-  [button_ performClick:event];
-  EXPECT_FALSE([observer didOpen]);
-
-  event = cocoa_test_event_utils::RightMouseDownAtPoint(NSZeroPoint);
-  [button_ rightMouseDown:event];
-  EXPECT_TRUE([observer didOpen]);
-
-  [observer setDidOpen:NO];
-
-  // If the menu is disabled, nothing should happen.
-  event = cocoa_test_event_utils::RightMouseDownAtPoint(NSZeroPoint);
-  [button_ setMenuEnabled:NO];
-  [button_ rightMouseDown:event];
-  EXPECT_FALSE([observer didOpen]);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h
deleted file mode 100644
index 4e314037..0000000
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_BUTTON_COCOA_H_
-#define CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_BUTTON_COCOA_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#import "ui/gfx/color_utils.h"
-
-namespace gfx {
-struct VectorIcon;
-}
-
-enum class ToolbarButtonImageBackgroundStyle {
-  DEFAULT,
-  HOVER,
-  HOVER_THEMED,
-  PRESSED,
-  PRESSED_THEMED,
-};
-
-// NSButton subclass which handles middle mouse clicking.
-@interface ToolbarButtonCocoa : NSButton<ThemedWindowDrawing> {
- @protected
-  // The toolbar button's image, as assigned by setImage:.
-  base::scoped_nsobject<NSImage> image_;
-
-  // YES when middle mouse clicks should be handled.
-  BOOL handleMiddleClick_;
-}
-
-// Return the size of toolbar buttons.
-+ (NSSize)toolbarButtonSize;
-// Whether or not to handle the mouse middle click events.
-@property(assign, nonatomic) BOOL handleMiddleClick;
-// Whether this button should mirror in RTL. Defaults to YES.
-@property(assign, nonatomic, readonly) BOOL shouldMirrorInRTL;
-// Override point for subclasses to return their vector icon.
-- (const gfx::VectorIcon*)vectorIcon;
-// Override point for subclasses to return their vector icon color.
-- (SkColor)vectorIconColor:(BOOL)themeIsDark;
-// When in Material Design mode, sets the images for each of the
-// ToolbarButtonCocoa's states from the specified image.
-- (void)setImage:(NSImage*)anImage;
-// Resets the images for each of the ToolbarButtonCocoa's states from its vector
-// icon id or its main image. Should only be called when in Material Design
-// mode.
-- (void)resetButtonStateImages;
-@end
-
-@interface ToolbarButtonCocoa (ExposedForTesting)
-- (BOOL)shouldHandleEvent:(NSEvent*)theEvent;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_BUTTON_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
deleted file mode 100644
index ba42b98..0000000
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
+++ /dev/null
@@ -1,399 +0,0 @@
-// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/sdk_forward_declarations.h"
-#include "chrome/app/vector_icons/vector_icons.h"
-#import "chrome/browser/ui/cocoa/image_button_cell.h"
-#import "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/view_id_util.h"
-#include "components/vector_icons/vector_icons.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/base/theme_provider.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/gfx/paint_vector_icon.h"
-
-namespace {
-
-// Toolbar buttons are 24x24 in Material Design.
-const NSRect kMDButtonBounds = NSMakeRect(0, 0, 24, 24);
-
-// The size of a toolbar button icon in Material Design. A toolbar button image
-// consists of a border and background, with a centered icon.
-const NSSize kMDButtonIconSize = NSMakeSize(16, 16);
-
-}  // namespace
-
-// An NSCustomImageRep subclass that creates the "three dots" image of the
-// Material Design browser tools icon.
-@interface BrowserToolsImageRep : NSCustomImageRep
-@property (retain, nonatomic) NSColor* fillColor;
-// NSCustomImageRep delegate method that performs the drawing.
-+ (void)drawBrowserToolsIcon:(BrowserToolsImageRep*)imageRep;
-@end
-
-@implementation BrowserToolsImageRep
-
-@synthesize fillColor = fillColor_;
-
-- (void)dealloc {
-  [fillColor_ release];
-  [super dealloc];
-}
-
-+ (void)drawBrowserToolsIcon:(BrowserToolsImageRep*)imageRep {
-  [imageRep.fillColor set];
-  NSBezierPath* dotPath =
-      [NSBezierPath bezierPathWithOvalInRect:NSMakeRect(6.5, 1.5, 3, 3)];
-  CGContextRef context = static_cast<CGContextRef>(
-      [[NSGraphicsContext currentContext] graphicsPort]);
-  // Draw the three dots by drawing |dotPath| in three different locations.
-  for (NSUInteger i = 0; i < 3; i++) {
-    [dotPath fill];
-    CGContextTranslateCTM(context, 0, 5);
-  }
-}
-
-@end
-
-// An NSCustomImageRep subclass that draws a Material Design background behind
-// and border around a centered icon image.
-@interface ToolbarButtonImageRep : NSCustomImageRep
-@property (retain, nonatomic) NSImage* icon;
-@property (assign, nonatomic) ToolbarButtonImageBackgroundStyle style;
-// NSCustomImageRep delegate method that performs the drawing.
-+ (void)drawImage:(ToolbarButtonImageRep*)imageRep;
-@end
-
-@implementation ToolbarButtonImageRep
-
-@synthesize icon = icon_;
-@synthesize style = style_;
-
-- (void)dealloc {
-  [icon_ release];
-  [super dealloc];
-}
-
-+ (void)drawImage:(ToolbarButtonImageRep*)imageRep {
-  ToolbarButtonImageBackgroundStyle displayStyle = [imageRep style];
-
-  // Non-default styles draw a background.
-  if (displayStyle != ToolbarButtonImageBackgroundStyle::DEFAULT) {
-    // Create the path used for the background fill.
-    const int kCornerRadius = 2;
-    NSBezierPath* roundedRectPath =
-        [NSBezierPath bezierPathWithRoundedRect:kMDButtonBounds
-                                        xRadius:kCornerRadius
-                                        yRadius:kCornerRadius];
-
-    // Determine the fill color.
-    NSColor* fillColor = nil;
-    const CGFloat kEightPercentAlpha = 0.08;
-    const CGFloat kTwelvePercentAlpha = 0.12;
-    const CGFloat kSixteenPercentAlpha = 0.16;
-    switch (displayStyle) {
-      case ToolbarButtonImageBackgroundStyle::HOVER:
-        fillColor = [NSColor colorWithCalibratedWhite:0
-                                                alpha:kEightPercentAlpha];
-        break;
-      case ToolbarButtonImageBackgroundStyle::HOVER_THEMED:
-        fillColor = [NSColor colorWithCalibratedWhite:1
-                                                alpha:kTwelvePercentAlpha];
-        break;
-      case ToolbarButtonImageBackgroundStyle::PRESSED:
-        fillColor = [NSColor colorWithCalibratedWhite:0
-                                                alpha:kTwelvePercentAlpha];
-        break;
-      case ToolbarButtonImageBackgroundStyle::PRESSED_THEMED:
-        fillColor = [NSColor colorWithCalibratedWhite:1
-                                                alpha:kSixteenPercentAlpha];
-        break;
-      case ToolbarButtonImageBackgroundStyle::DEFAULT:
-        NOTREACHED();
-    }
-
-    // Fill the path.
-    [fillColor set];
-    [roundedRectPath fill];
-  }
-
-  // Center the icon within the button.
-  NSSize iconSize = [imageRep.icon size];
-  CGFloat iconInset = (kMDButtonBounds.size.width - iconSize.width) / 2;
-  NSRect iconDestRect = NSInsetRect(kMDButtonBounds, iconInset, iconInset);
-  [imageRep.icon drawInRect:iconDestRect
-                   fromRect:NSZeroRect
-                  operation:NSCompositeSourceOver
-                   fraction:1];
-}
-
-@end
-
-@interface ToolbarButtonCocoa ()
-// Returns an image that draws the browser tools button icon using vector
-// commands.
-- (NSImage*)browserToolsIconForFillColor:(SkColor)fillColor;
-// Returns an button image by combining |iconImage| with the specified button
-// background.
-- (NSImage*)imageForIcon:(NSImage*)iconImage
-     withBackgroundStyle:(ToolbarButtonImageBackgroundStyle)style;
-// Implemented to set the button's icon when added to the browser window. We
-// can't set the image before this because its appearance depends upon the
-// browser window's theme.
-- (void)viewDidMoveToWindow;
-
-@end
-
-@implementation ToolbarButtonCocoa
-
-@synthesize handleMiddleClick = handleMiddleClick_;
-
-+ (NSSize)toolbarButtonSize {
-  return kMDButtonBounds.size;
-}
-
-- (void)otherMouseDown:(NSEvent*)theEvent {
-  if (![self shouldHandleEvent:theEvent]) {
-    [super otherMouseDown:theEvent];
-    return;
-  }
-
-  NSEvent* nextEvent = theEvent;
-  BOOL isInside;
-
-  // Loop until middle button is released. Also, the mouse cursor is outside of
-  // the button, the button should not be highlighted.
-  do {
-    NSPoint mouseLoc = [self convertPoint:[nextEvent locationInWindow]
-                                 fromView:nil];
-    isInside = [self mouse:mouseLoc inRect:[self bounds]];
-    [self highlight:isInside];
-    [self setState:isInside ? NSOnState : NSOffState];
-
-    NSUInteger mask = NSOtherMouseDraggedMask | NSOtherMouseUpMask;
-    nextEvent = [[self window] nextEventMatchingMask:mask];
-  } while (!([nextEvent buttonNumber] == 2 &&
-             [nextEvent type] == NSOtherMouseUp));
-
-  // Discard the events before the middle button up event.
-  // If we don't discard it, the events will be re-processed later.
-  [[self window] discardEventsMatchingMask:NSAnyEventMask
-                               beforeEvent:nextEvent];
-
-  [self highlight:NO];
-  [self setState:NSOffState];
-  if (isInside)
-    [self sendAction:[self action] to:[self target]];
-}
-
-- (BOOL)shouldHandleEvent:(NSEvent*)theEvent {
-  // |buttonNumber| is the mouse button whose action triggered theEvent.
-  // 2 corresponds to the middle mouse button.
-  return handleMiddleClick_ && [theEvent buttonNumber] == 2;
-}
-
-- (BOOL)shouldMirrorInRTL {
-  return YES;
-}
-
-- (void)drawFocusRingMask {
-  // Match the hover image's bezel.
-  [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect([self bounds], 2, 2)
-                                   xRadius:2
-                                   yRadius:2] fill];
-}
-
-- (const gfx::VectorIcon*)vectorIcon {
-  switch ([self viewID]) {
-    case VIEW_ID_BACK_BUTTON:
-      return &vector_icons::kBackArrowIcon;
-    case VIEW_ID_FORWARD_BUTTON:
-      return &vector_icons::kForwardArrowIcon;
-    case VIEW_ID_HOME_BUTTON:
-      return &kNavigateHomeIcon;
-    case VIEW_ID_APP_MENU:
-      return &kBrowserToolsIcon;
-    default:
-      break;
-  }
-
-  return nullptr;
-}
-
-- (SkColor)vectorIconColor:(BOOL)themeIsDark {
-  const ui::ThemeProvider* provider = [[self window] themeProvider];
-  return themeIsDark ? SK_ColorWHITE
-                     : (provider && provider->ShouldIncreaseContrast()
-                            ? SK_ColorBLACK
-                            : gfx::kChromeIconGrey);
-}
-
-- (NSImage*)browserToolsIconForFillColor:(SkColor)fillColor {
-  // Create a |BrowserToolsImageRep| to draw the browser tools icon using
-  // the provided fill color.
-  base::scoped_nsobject<BrowserToolsImageRep> imageRep(
-      [[BrowserToolsImageRep alloc]
-          initWithDrawSelector:@selector(drawBrowserToolsIcon:)
-                      delegate:[BrowserToolsImageRep class]]);
-  [imageRep setFillColor:skia::SkColorToSRGBNSColor(fillColor)];
-
-  // Create the image from the image rep.
-  NSImage* browserToolsIcon =
-      [[[NSImage alloc] initWithSize:kMDButtonIconSize] autorelease];
-  [browserToolsIcon setCacheMode:NSImageCacheAlways];
-  [browserToolsIcon addRepresentation:imageRep];
-
-  return browserToolsIcon;
-}
-
-- (NSImage*)imageForIcon:(NSImage*)iconImage
-     withBackgroundStyle:(ToolbarButtonImageBackgroundStyle)style {
-  // Create a |ToolbarButtonImageRep| to draw the button image using
-  // the provided icon and background style.
-  base::scoped_nsobject<ToolbarButtonImageRep> imageRep(
-      [[ToolbarButtonImageRep alloc]
-          initWithDrawSelector:@selector(drawImage:)
-                      delegate:[ToolbarButtonImageRep class]]);
-  [imageRep setIcon:iconImage];
-  [imageRep setStyle:style];
-
-  // Create the image from the image rep.
-  NSImage* image =
-      [[[NSImage alloc] initWithSize:kMDButtonBounds.size] autorelease];
-  [image setCacheMode:NSImageCacheAlways];
-  [image addRepresentation:imageRep];
-
-  return image;
-}
-
-- (NSImage*)image {
-  // setImage: stores the image in an ivar.
-  return image_.get();
-}
-
-- (void)setImage:(NSImage*)anImage {
-  // We want to set the default image as the image for kDefaultState. Setting it
-  // as the default image (via setImage:) can cause ghosting from the two
-  // default images being drawn over each other. However we also need to keep
-  // the default image around for resetButtonStateImages, so stick it in an
-  // ivar.
-  image_.reset([anImage retain]);
-  [self resetButtonStateImages];
-}
-
-- (void)resetButtonStateImages {
-  NSImage* normalIcon = nil;
-  NSImage* disabledIcon = nil;
-  BOOL isDarkTheme = NO;
-
-  const gfx::VectorIcon* icon = [self vectorIcon];
-  if (!icon) {
-    // If the button does not have a vector icon (e.g. it's an extension
-    // button), use its image. The hover, etc. images will be created using
-    // imageForIcon:withBackgroundStyle: so do the same for the default image.
-    // If we don't do this, the icon may not appear in the same place as in the
-    // other states, causing the icon to appear to shift as you mouse over the
-    // button.
-    NSImage* defaultImage =
-        [self imageForIcon:[self image]
-              withBackgroundStyle:ToolbarButtonImageBackgroundStyle::DEFAULT];
-    normalIcon = disabledIcon = defaultImage;
-  } else {
-    // Compute the normal and disabled vector icon colors.
-    isDarkTheme = [[self window] hasDarkTheme];
-    const SkColor vectorIconColor = [self vectorIconColor:isDarkTheme];
-    CGFloat normalAlpha = isDarkTheme ? 0xCC : 0xFF;
-    const SkColor normalColor = SkColorSetA(vectorIconColor, normalAlpha);
-    const SkColor disabledColor = SkColorSetA(vectorIconColor, 0x33);
-
-    // Create the normal and disabled state icons. These icons are always the
-    // same shape but use a different color.
-    if (icon == &kBrowserToolsIcon) {
-      normalIcon = [self browserToolsIconForFillColor:normalColor];
-      disabledIcon = [self browserToolsIconForFillColor:disabledColor];
-    } else {
-      BOOL shouldMirror = cocoa_l10n_util::ShouldDoExperimentalRTLLayout() &&
-                          self.shouldMirrorInRTL;
-      normalIcon = NSImageFromImageSkia(
-          gfx::CreateVectorIcon(*icon,
-                                kMDButtonIconSize.width,
-                                normalColor));
-      if (shouldMirror)
-        normalIcon = cocoa_l10n_util::FlippedImage(normalIcon);
-      // The home button has no icon for its disabled state.
-      if (icon != &vector_icons::kReloadIcon) {
-        disabledIcon = NSImageFromImageSkia(
-            gfx::CreateVectorIcon(*icon,
-                                  kMDButtonIconSize.width,
-                                  disabledColor));
-        if (shouldMirror)
-          disabledIcon = cocoa_l10n_util::FlippedImage(disabledIcon);
-      }
-    }
-  }
-
-  ImageButtonCell* theCell = base::mac::ObjCCast<ImageButtonCell>([self cell]);
-  // Set the image for the default state, which is just the icon.
-  [theCell setImage:normalIcon forButtonState:image_button_cell::kDefaultState];
-
-  // Determine the appropriate image background style for the hover and pressed
-  // states.
-  ToolbarButtonImageBackgroundStyle hoverStyle =
-      ToolbarButtonImageBackgroundStyle::HOVER;
-  ToolbarButtonImageBackgroundStyle pressedStyle =
-      ToolbarButtonImageBackgroundStyle::PRESSED;
-
-  // Use the themed style for custom themes and Incognito mode.
-  const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
-  bool incongitoMode = themeProvider && themeProvider->InIncognitoMode();
-  if (isDarkTheme || incongitoMode) {
-    hoverStyle = ToolbarButtonImageBackgroundStyle::HOVER_THEMED;
-    pressedStyle = ToolbarButtonImageBackgroundStyle::PRESSED_THEMED;
-  }
-
-  // Create and set the hover state image.
-  NSImage* hoverImage =
-      [self imageForIcon:normalIcon withBackgroundStyle:hoverStyle];
-  [theCell setImage:hoverImage
-     forButtonState:image_button_cell::kHoverState];
-
-  // Create and set the pressed state image.
-  NSImage* pressedImage =
-      [self imageForIcon:normalIcon withBackgroundStyle:pressedStyle];
-  [theCell setImage:pressedImage
-     forButtonState:image_button_cell::kPressedState];
-
-  // Set the disabled state image.
-  [theCell setImage:disabledIcon
-     forButtonState:image_button_cell::kDisabledState];
-
-  [self setNeedsDisplay:YES];
-}
-
-- (void)viewDidMoveToWindow {
-  // In Material Design we want to catch when the button is attached to its
-  // window so that we can configure its appearance based on the window's
-  // theme.
-  if ([self window]) {
-    [self resetButtonStateImages];
-  }
-}
-
-// ThemedWindowDrawing implementation.
-
-- (void)windowDidChangeTheme {
-  // Update the hover and pressed image backgrounds to match the current theme.
-  [self resetButtonStateImages];
-}
-
-- (void)windowDidChangeActive {
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm
deleted file mode 100644
index c504348e..0000000
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright (c) 2011 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 <Cocoa/Cocoa.h>
-
-#import "base/mac/scoped_nsobject.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h"
-#import "testing/gtest_mac.h"
-#import "ui/events/test/cocoa_test_event_utils.h"
-
-@interface TestableToolbarButton : ToolbarButtonCocoa {
- @private
-  NSInteger numOfClick_;
-  NSInteger lastCommand_;
-}
-
-@property(assign, nonatomic) NSInteger numOfClick;
-@property(assign, nonatomic) NSInteger lastCommand;
-
-- (id)initWithFrame:(NSRect)frame;
-- (void)doAction:(id)sender;
-@end
-
-@implementation TestableToolbarButton
-
-@synthesize numOfClick = numOfClick_;
-@synthesize lastCommand = lastCommand_;
-
-- (id)initWithFrame:(NSRect)frame {
-  if ((self = [super initWithFrame:frame])) {
-    lastCommand_ = IDC_STOP;
-  }
-  return self;
-}
-
-- (void)doAction:(id)sender {
-  lastCommand_ = [sender tag];
-  if (lastCommand_ == [self tag])
-    ++numOfClick_;
-}
-
-- (BOOL)shouldHandleEvent:(NSEvent*)theEvent {
-  return handleMiddleClick_;
-}
-
-@end
-
-namespace {
-
-class ToolbarButtonTest : public CocoaTest {
- public:
-  ToolbarButtonTest() {
-    NSRect frame = NSMakeRect(0, 0, 20, 20);
-    base::scoped_nsobject<TestableToolbarButton> button(
-        [[TestableToolbarButton alloc] initWithFrame:frame]);
-    button_ = button.get();
-
-    [button_ setTag:IDC_HOME];
-    [button_ setTarget:button_];
-    [button_ setAction:@selector(doAction:)];
-    [[test_window() contentView] addSubview:button_];
-
-    NSRect bounds = [button_ bounds];
-    NSPoint mid_point = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
-    NSPoint out_point = NSMakePoint(bounds.origin.x - 10,
-                                    bounds.origin.y - 10);
-    left_down_in_view =
-        cocoa_test_event_utils::MouseEventAtPoint(mid_point,
-                                                  NSLeftMouseDown,
-                                                  0);
-    left_up_in_view =
-        cocoa_test_event_utils::MouseEventAtPoint(mid_point,
-                                                  NSLeftMouseUp,
-                                                  0);
-    right_down_in_view =
-        cocoa_test_event_utils::MouseEventAtPoint(mid_point,
-                                                  NSRightMouseDown,
-                                                  0);
-    right_up_in_view =
-        cocoa_test_event_utils::MouseEventAtPoint(mid_point,
-                                                  NSRightMouseUp,
-                                                  0);
-    other_down_in_view =
-        cocoa_test_event_utils::MouseEventAtPoint(mid_point,
-                                                  NSOtherMouseDown,
-                                                  0);
-    other_dragged_in_view =
-        cocoa_test_event_utils::MouseEventAtPoint(mid_point,
-                                                  NSOtherMouseDragged,
-                                                  0);
-    other_up_in_view =
-        cocoa_test_event_utils::MouseEventAtPoint(mid_point,
-                                                  NSOtherMouseUp,
-                                                  0);
-    other_down_out_view =
-        cocoa_test_event_utils::MouseEventAtPoint(out_point,
-                                                  NSOtherMouseDown,
-                                                  0);
-    other_dragged_out_view =
-        cocoa_test_event_utils::MouseEventAtPoint(out_point,
-                                                  NSOtherMouseDragged,
-                                                  0);
-    other_up_out_view =
-        cocoa_test_event_utils::MouseEventAtPoint(out_point,
-                                                  NSOtherMouseUp,
-                                                  0);
-  }
-
-  TestableToolbarButton* button_;
-  NSEvent* left_down_in_view;
-  NSEvent* left_up_in_view;
-  NSEvent* right_down_in_view;
-  NSEvent* right_up_in_view;
-  NSEvent* other_down_in_view;
-  NSEvent* other_dragged_in_view;
-  NSEvent* other_up_in_view;
-  NSEvent* other_down_out_view;
-  NSEvent* other_dragged_out_view;
-  NSEvent* other_up_out_view;
-};
-
-TEST_VIEW(ToolbarButtonTest, button_)
-
-TEST_F(ToolbarButtonTest, DoesNotSwallowClicksOnNO) {
-  // Middle button being down doesn't swallow right button clicks. But
-  // ToolbarButtonCocoa doesn't handle right button events.
-  [button_ otherMouseDown:other_down_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ rightMouseDown:right_down_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ rightMouseUp:right_up_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-  [button_ otherMouseUp:other_up_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-
-  // Middle button being down doesn't swallows left button clicks.
-  [button_ otherMouseDown:other_down_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [NSApp postEvent:left_up_in_view atStart:YES];
-  [button_ mouseDown:left_down_in_view];
-  EXPECT_EQ(1, [button_ numOfClick]);
-  EXPECT_EQ(IDC_HOME, [button_ lastCommand]);
-  [button_ otherMouseUp:other_up_in_view];
-  EXPECT_EQ(1, [button_ numOfClick]);
-  EXPECT_EQ(IDC_HOME, [button_ lastCommand]);
-}
-
-TEST_F(ToolbarButtonTest, WithoutMouseDownOnNO) {
-  // Middle button mouse up without leading mouse down in the view.
-  [button_ otherMouseUp:other_up_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-
-  // Middle button mouse dragged in the view and up without leading mouse down.
-  [button_ otherMouseDragged:other_dragged_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ otherMouseUp:other_up_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-}
-
-TEST_F(ToolbarButtonTest, MouseClickOnNO) {
-  // Middle button clicking in the view.
-  [button_ otherMouseDown:other_down_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ otherMouseUp:other_up_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-
-  // Middle button clicking outside of the view.
-  [button_ otherMouseDown:other_down_out_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ otherMouseUp:other_up_out_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-}
-
-TEST_F(ToolbarButtonTest, MouseDraggingOnNO) {
-  // Middle button being down in the view and up outside of the view.
-  [button_ otherMouseDown:other_down_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ otherMouseDragged:other_dragged_out_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ otherMouseUp:other_up_out_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-
-  // Middle button being down on the button, move to outside and move on it
-  // again, then up on the button.
-  [button_ otherMouseDown:other_down_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ otherMouseDragged:other_dragged_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ otherMouseUp:other_up_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-}
-
-TEST_F(ToolbarButtonTest, WithoutMouseDownOnYES) {
-  // Enable middle button handling.
-  [button_ setHandleMiddleClick:YES];
-
-  // Middle button mouse up without leading mouse down in the view.
-  [button_ otherMouseUp:other_up_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-
-  // Middle button mouse dragged in the view and up without leading mouse down.
-  [button_ otherMouseDragged:other_dragged_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  [button_ otherMouseUp:other_up_in_view];
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-}
-
-TEST_F(ToolbarButtonTest, MouseClickInsideOnYES) {
-  // Enable middle button handling.
-  [button_ setHandleMiddleClick:YES];
-
-  // Middle button clicking in the view.
-  [NSApp postEvent:other_up_in_view atStart:YES];
-  [button_ otherMouseDown:other_down_in_view];
-
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(1, [button_ numOfClick]);
-  EXPECT_EQ(IDC_HOME, [button_ lastCommand]);
-}
-
-TEST_F(ToolbarButtonTest, MouseClickOutsideOnYES) {
-  // Enable middle button handling.
-  [button_ setHandleMiddleClick:YES];
-
-  // Middle button clicking outside of the view.
-  [NSApp postEvent:other_up_out_view atStart:YES];
-  [button_ otherMouseDown:other_down_out_view];
-
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-}
-
-TEST_F(ToolbarButtonTest, MouseDraggingOnYES) {
-  // Enable middle button handling.
-  [button_ setHandleMiddleClick:YES];
-
-  // Middle button being down in the view and up outside of the view.
-  [NSApp postEvent:other_up_out_view atStart:YES];
-  [NSApp postEvent:other_dragged_out_view atStart:YES];
-  [button_ otherMouseDown:other_down_in_view];
-
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(0, [button_ numOfClick]);
-  EXPECT_EQ(IDC_STOP, [button_ lastCommand]);
-
-  // Middle button being down on the button, move to outside and move on it
-  // again, then up on the button.
-  [NSApp postEvent:other_up_in_view atStart:YES];
-  [NSApp postEvent:other_dragged_in_view atStart:YES];
-  [NSApp postEvent:other_dragged_out_view atStart:YES];
-  [button_ otherMouseDown:other_down_in_view];
-
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(1, [button_ numOfClick]);
-  EXPECT_EQ(IDC_HOME, [button_ lastCommand]);
-}
-
-TEST_F(ToolbarButtonTest, DoesSwallowRightClickOnYES) {
-  // Enable middle button handling.
-  [button_ setHandleMiddleClick:YES];
-
-  // Middle button being down should swallow right button clicks.
-  [NSApp postEvent:other_up_in_view atStart:YES];
-  [NSApp postEvent:right_up_in_view atStart:YES];
-  [NSApp postEvent:right_down_in_view atStart:YES];
-  [button_ otherMouseDown:other_down_in_view];
-
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(1, [button_ numOfClick]);
-  EXPECT_EQ(IDC_HOME, [button_ lastCommand]);
-}
-
-TEST_F(ToolbarButtonTest, DoesSwallowLeftClickOnYES) {
-  // Enable middle button handling.
-  [button_ setHandleMiddleClick:YES];
-
-  // Middle button being down swallows left button clicks.
-  [NSApp postEvent:other_up_in_view atStart:YES];
-  [NSApp postEvent:left_up_in_view atStart:YES];
-  [NSApp postEvent:left_down_in_view atStart:YES];
-  [button_ otherMouseDown:other_down_in_view];
-
-  EXPECT_EQ(NSOffState, [button_ state]);
-  EXPECT_EQ(1, [button_ numOfClick]);
-  EXPECT_EQ(IDC_HOME, [button_ lastCommand]);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
deleted file mode 100644
index 27e38c4..0000000
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_CONTROLLER_H_
-#define CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/has_weak_browser_pointer.h"
-#import "chrome/browser/ui/cocoa/url_drop_target.h"
-#import "chrome/browser/ui/cocoa/view_resizer.h"
-#include "components/prefs/pref_member.h"
-#import "ui/base/cocoa/tracking_area.h"
-
-@class BackForwardMenuController;
-class Browser;
-class CommandUpdater;
-class LocationBarViewMac;
-@class MenuButton;
-class Profile;
-@class ReloadButtonCocoa;
-@class ToolbarButtonCocoa;
-@class ToolbarViewCocoa;
-
-namespace content {
-class WebContents;
-}
-
-namespace ToolbarControllerInternal {
-class CommandObserverBridge;
-class NotificationBridge;
-}
-
-// A controller for the toolbar in the browser window. Manages
-// updating the state for location bar and back/fwd/reload/go buttons.
-// Manages the bookmark bar and its position in the window relative to
-// the web content view.
-
-@interface ToolbarController
-    : NSViewController<URLDropTargetController, HasWeakBrowserPointer> {
- @protected
-  // The ordering is important for unit tests. If new items are added or the
-  // ordering is changed, make sure to update |-toolbarViews| and the
-  // corresponding enum in the unit tests.
-  IBOutlet MenuButton* backButton_;
-  IBOutlet MenuButton* forwardButton_;
-  IBOutlet ReloadButtonCocoa* reloadButton_;
-  IBOutlet ToolbarButtonCocoa* homeButton_;
-  IBOutlet MenuButton* appMenuButton_;
-  IBOutlet id locationBar_;
-  IBOutlet id browserActionsContainerView_;
-
- @private
-  CommandUpdater* commands_;  // weak, one per window
-  Profile* profile_;  // weak, one per window
-  Browser* browser_;  // weak, one per window
-  std::unique_ptr<ToolbarControllerInternal::CommandObserverBridge>
-      commandObserver_;
-  std::unique_ptr<LocationBarViewMac> locationBarView_;
-  base::scoped_nsobject<BackForwardMenuController> backMenuController_;
-  base::scoped_nsobject<BackForwardMenuController> forwardMenuController_;
-
-  // Used for monitoring the optional toolbar button prefs.
-  std::unique_ptr<ToolbarControllerInternal::NotificationBridge>
-      notificationBridge_;
-  BooleanPrefMember showHomeButton_;
-  BOOL hasToolbar_;  // If NO, we may have only the location bar.
-  BOOL hasLocationBar_;  // If |hasToolbar_| is YES, this must also be YES.
-  BOOL locationBarAtMinSize_; // If the location bar is at the minimum size.
-
-  // Tracking area for mouse enter/exit/moved in the toolbar.
-  ui::ScopedCrTrackingArea trackingArea_;
-
-  // We retain/release the hover button since interaction with the
-  // button may make it go away (e.g. delete menu option over a
-  // bookmark button).  Thus this variable is not weak.  The
-  // hoveredButton_ is required to have an NSCell that responds to
-  // setMouseInside:animate:.
-  NSButton* hoveredButton_;
-}
-
-// Return the inset needed to center a toolbar button's icon within the 28x28
-// design area defined by Material Design.
-+ (CGFloat)materialDesignButtonInset;
-
-// Initialize the toolbar and register for command updates. The profile is
-// needed for initializing the location bar. The browser is needed for
-// the toolbar model and back/forward menus.
-- (id)initWithCommands:(CommandUpdater*)commands
-               profile:(Profile*)profile
-               browser:(Browser*)browser;
-
-// Strongly typed controlled view.
-- (ToolbarViewCocoa*)toolbarView;
-
-// Get the C++ bridge object representing the location bar for this tab.
-- (LocationBarViewMac*)locationBarBridge;
-
-// Called by the Window delegate so we can provide a custom field editor if
-// needed.
-// Note that this may be called for objects unrelated to the toolbar.
-// returns nil if we don't want to override the custom field editor for |obj|.
-- (id)customFieldEditorForObject:(id)obj;
-
-// Called by the |locationBar_| when it has been added to its window.
-- (void)locationBarWasAddedToWindow;
-
-// Return YES if the location bar is the first responder.
-- (BOOL)locationBarHasFocus;
-
-// Make the location bar the first responder, if possible.
-- (void)focusLocationBar:(BOOL)selectAll;
-
-// Called by CommandObserverBridge when there is a state change for the given
-// command.
-- (void)enabledStateChangedForCommand:(int)command enabled:(bool)enabled;
-
-// Forces the toolbar (and transitively the location bar) to update its current
-// state.  If |tab| is non-NULL, we're switching (back?) to this tab and should
-// restore any previous location bar state (such as user editing) as well.
-- (void)updateToolbarWithContents:(content::WebContents*)tab;
-
-// Resets the state for |tab|.
-- (void)resetTabState:(content::WebContents*)tab;
-
-// Sets whether or not the current page in the frontmost tab is bookmarked.
-- (void)setStarredState:(BOOL)isStarred;
-
-// Sets whether or not the current page is translated.
-- (void)setTranslateIconLit:(BOOL)on;
-
-// Happens when the zoom for the active tab changes, the active tab switches, or
-// a new tab or browser window is created. |canShowBubble| indicates if it is
-// appropriate to show a zoom bubble for the change.
-- (void)zoomChangedForActiveTab:(BOOL)canShowBubble;
-
-// Called to update the loading state. Handles updating the go/stop
-// button state.  |force| is set if the update is due to changing
-// tabs, as opposed to the page-load finishing.  See comment in
-// reload_button_cocoa.h.
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
-
-// Allow turning off the toolbar (but we may keep the location bar without a
-// surrounding toolbar). If |toolbar| is YES, the value of |hasLocationBar| is
-// ignored. This changes the behavior of other methods, like |-view|.
-- (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar;
-
-// Point on the star icon for the bookmark bubble to be - in the
-// associated window's coordinate system.
-- (NSPoint)bookmarkBubblePoint;
-
-// Point in the window's coordinate system for bubbles attached to the app menu.
-- (NSPoint)appMenuBubblePoint;
-
-// Returns the desired toolbar height for the given compression factor.
-- (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight;
-
-// Set the opacity of the divider (the line at the bottom) *if* we have a
-// |ToolbarViewCocoa| (0 means don't show it); no-op otherwise.
-- (void)setDividerOpacity:(CGFloat)opacity;
-
-// Updates the visibility of the toolbar, with an optional animation.
-- (void)updateVisibility:(BOOL)visible withAnimation:(BOOL)animate;
-
-// Returns the app menu button.
-- (NSButton*)appMenuButton;
-
-// Returns true of the location bar is focused.
-- (BOOL)isLocationBarFocused;
-
-@end
-
-// A set of private methods used by tests, in the absence of "friends" in ObjC.
-@interface ToolbarController(PrivateTestMethods)
-// Returns an array of views in the order of the outlets above.
-- (NSArray*)toolbarViews;
-- (void)showOptionalHomeButton;
-// Return a hover button for the current event.
-- (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent;
-// Adjusts browser actions container view in response to toolbar frame changes.
-// Outside of tests, called in response to frame changed/new window
-// notifications.
-- (void)toolbarFrameChanged;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
deleted file mode 100644
index bb8a778..0000000
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ /dev/null
@@ -1,762 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
-
-#include <algorithm>
-
-#include "base/mac/bundle_locations.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#include "base/mac/sdk_forward_declarations.h"
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/command_observer.h"
-#include "chrome/browser/command_updater.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/recovery/recovery_install_global_error_factory.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/background_gradient_view.h"
-#include "chrome/browser/ui/cocoa/drag_util.h"
-#import "chrome/browser/ui/cocoa/image_button_cell.h"
-#import "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#import "chrome/browser/ui/cocoa/menu_button.h"
-#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h"
-#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h"
-#import "chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h"
-#import "chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h"
-#import "chrome/browser/ui/cocoa/view_id_util.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
-#include "chrome/browser/ui/toolbar/app_menu_model.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/omnibox/browser/autocomplete_classifier.h"
-#include "components/omnibox/browser/autocomplete_match.h"
-#include "components/omnibox/browser/omnibox_edit_model.h"
-#include "components/omnibox/browser/omnibox_view.h"
-#include "components/prefs/pref_service.h"
-#include "components/search_engines/template_url_service.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/url_formatter/url_fixer.h"
-#include "content/public/browser/web_contents.h"
-#include "third_party/metrics_proto/omnibox_event.pb.h"
-#import "ui/base/cocoa/menu_controller.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/image.h"
-
-using content::OpenURLParams;
-using content::Referrer;
-using content::WebContents;
-
-namespace {
-
-// Duration of the toolbar animation.
-const NSTimeInterval kToolBarAnimationDuration = 0.12;
-
-// The height of the location bar.
-const CGFloat kLocationBarHeight = 28;
-
-// The padding between the top of the toolbar and the top of the
-// location bar.
-const CGFloat kLocationBarPadding = 2;
-
-// The padding between elements and the edges of the toolbar.
-const CGFloat kElementPadding = 4;
-
-// Toolbar buttons are 24x24 and centered in a 28x28 space, so there is a 2pt-
-// wide inset.
-const CGFloat kButtonInset = 2;
-
-}  // namespace
-
-@interface ToolbarController()
-@property(assign, nonatomic) Browser* browser;
-// Height of the location bar. Used for animating the toolbar in and out when
-// the location bar is displayed stand-alone for bookmark apps.
-+ (CGFloat)locationBarHeight;
-// Return the amount of horizontal padding that the app menu should have on
-// each side.
-+ (CGFloat)appMenuPadding;
-- (void)cleanUp;
-- (void)addAccessibilityDescriptions;
-- (void)initCommandStatus:(CommandUpdater*)commands;
-- (void)prefChanged:(const std::string&)prefName;
-// Height of the toolbar in pixels when the bookmark bar is closed.
-- (CGFloat)baseToolbarHeight;
-- (void)toolbarFrameChanged;
-- (void)maintainMinimumLocationBarWidth;
-- (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate;
-- (void)updateAppMenuButtonSeverity:(AppMenuIconController::Severity)severity
-                           iconType:(AppMenuIconController::IconType)iconType
-                            animate:(BOOL)animate;
-@end
-
-namespace ToolbarControllerInternal {
-
-// A C++ bridge class that handles listening for updates to commands and
-// passing them back to ToolbarController. ToolbarController will create one of
-// these bridges, pass them to CommandUpdater::AddCommandObserver, and then wait
-// for update notifications, delivered via
-// -enabledStateChangedForCommand:enabled:.
-class CommandObserverBridge : public CommandObserver {
- public:
-  explicit CommandObserverBridge(ToolbarController* observer)
-      : observer_(observer) {
-    DCHECK(observer_);
-  }
-
- protected:
-  // Overridden from CommandObserver
-  void EnabledStateChangedForCommand(int command, bool enabled) override {
-    [observer_ enabledStateChangedForCommand:command enabled:enabled];
-  }
-
- private:
-  ToolbarController* observer_;  // weak, owns me
-
-  DISALLOW_COPY_AND_ASSIGN(CommandObserverBridge);
-};
-
-// A class registered for C++ notifications. This is used to detect changes in
-// preferences and upgrade available notifications. Bridges the notification
-// back to the ToolbarController.
-class NotificationBridge : public AppMenuIconController::Delegate {
- public:
-  explicit NotificationBridge(ToolbarController* controller)
-      : controller_(controller),
-        app_menu_icon_controller_([controller browser]->profile(), this) {}
-  ~NotificationBridge() override {}
-
-  void UpdateSeverity() { app_menu_icon_controller_.UpdateDelegate(); }
-
-  void UpdateSeverity(AppMenuIconController::IconType type,
-                      AppMenuIconController::Severity severity,
-                      bool animate) override {
-    [controller_ updateAppMenuButtonSeverity:severity
-                                    iconType:type
-                                     animate:animate];
-  }
-
-  void OnPreferenceChanged(const std::string& pref_name) {
-    [controller_ prefChanged:pref_name];
-  }
-
- private:
-  ToolbarController* controller_;  // weak, owns us
-
-  AppMenuIconController app_menu_icon_controller_;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationBridge);
-};
-
-}  // namespace ToolbarControllerInternal
-
-@implementation ToolbarController
-
-@synthesize browser = browser_;
-
-+ (CGFloat)locationBarHeight {
-  return kLocationBarHeight;
-}
-
-+ (CGFloat)appMenuPadding {
-  return kElementPadding;
-}
-
-+ (CGFloat)materialDesignButtonInset {
-  return kButtonInset;
-}
-
-- (id)initWithCommands:(CommandUpdater*)commands
-               profile:(Profile*)profile
-               browser:(Browser*)browser {
-  DCHECK(commands && profile);
-  if ((self = [super initWithNibName:@"Toolbar"
-                              bundle:base::mac::FrameworkBundle()])) {
-    commands_ = commands;
-    profile_ = profile;
-    browser_ = browser;
-    hasToolbar_ = YES;
-    hasLocationBar_ = YES;
-
-    // Register for notifications about state changes for the toolbar buttons
-    commandObserver_.reset(
-        new ToolbarControllerInternal::CommandObserverBridge(self));
-
-    commands->AddCommandObserver(IDC_BACK, commandObserver_.get());
-    commands->AddCommandObserver(IDC_FORWARD, commandObserver_.get());
-    commands->AddCommandObserver(IDC_RELOAD, commandObserver_.get());
-    commands->AddCommandObserver(IDC_HOME, commandObserver_.get());
-    commands->AddCommandObserver(IDC_BOOKMARK_PAGE, commandObserver_.get());
-    // NOTE: Don't remove the command observers. ToolbarController is
-    // autoreleased at about the same time as the CommandUpdater (owned by the
-    // Browser), so |commands_| may not be valid any more.
-
-    // Start global error services now so we badge the menu correctly.
-    RecoveryInstallGlobalErrorFactory::GetForProfile(profile);
-  }
-  return self;
-}
-
-// Called after the view is done loading and the outlets have been hooked up.
-// Now we can hook up bridges that rely on UI objects such as the location bar
-// and button state. -viewDidLoad is the recommended way to do this in 10.10
-// SDK. When running on 10.10 or above -awakeFromNib still works but for some
-// reason is not guaranteed to be called (http://crbug.com/526276), so implement
-// both.
-- (void)awakeFromNib {
-  [self viewDidLoadImpl];
-}
-
-- (void)viewDidLoad {
-  [self viewDidLoadImpl];
-}
-
-- (void)viewDidLoadImpl {
-  // When linking and running on 10.10+, both -awakeFromNib and -viewDidLoad may
-  // be called, don't initialize twice.
-  if (locationBarView_) {
-    DCHECK(base::mac::IsAtLeastOS10_10());
-    return;
-  }
-
-  BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
-  NSAutoresizingMaskOptions leadingButtonMask =
-      isRTL ? NSViewMinXMargin | NSViewMinYMargin
-            : NSViewMaxXMargin | NSViewMinYMargin;
-  NSAutoresizingMaskOptions trailingButtonMask =
-      isRTL ? NSViewMaxXMargin | NSViewMinYMargin
-            : NSViewMinXMargin | NSViewMinYMargin;
-
-  // Make Material Design layout adjustments to the NIB items.
-  ToolbarViewCocoa* toolbarView = [self toolbarView];
-  NSRect toolbarBounds = [toolbarView bounds];
-  NSSize toolbarButtonSize = [ToolbarButtonCocoa toolbarButtonSize];
-
-  // Set the toolbar height.
-  NSRect frame = [toolbarView frame];
-  frame.size.height = [self baseToolbarHeight];
-  [toolbarView setFrame:frame];
-
-  NSArray* leadingButtons =
-      @[ backButton_, forwardButton_, reloadButton_, homeButton_ ];
-  const CGFloat xStart = kElementPadding + kButtonInset;
-  const CGFloat xOffset = toolbarButtonSize.width + kButtonInset * 2;
-  const CGFloat yPosition =
-      NSMaxY(toolbarBounds) - kElementPadding - toolbarButtonSize.height;
-  for (NSUInteger i = 0; i < [leadingButtons count]; i++) {
-    NSButton* button = leadingButtons[i];
-    NSRect buttonFrame = [button frame];
-    buttonFrame.size = toolbarButtonSize;
-    buttonFrame.origin.y = yPosition;
-    const CGFloat xPosition = xStart + i * xOffset;
-    buttonFrame.origin.x =
-        isRTL ? NSWidth(frame) - toolbarButtonSize.width - xPosition
-              : xPosition;
-    [button setFrame:buttonFrame];
-    [button setAutoresizingMask:leadingButtonMask];
-  }
-
-  // Replace the app button from the nib with an AppToolbarButton instance for
-  // Material Design.
-  AppToolbarButton* newMenuButton =
-      [[[AppToolbarButton alloc] initWithFrame:[appMenuButton_ frame]]
-          autorelease];
-  [newMenuButton setAutoresizingMask:[appMenuButton_ autoresizingMask]];
-  [[appMenuButton_ superview] addSubview:newMenuButton];
-  [appMenuButton_ removeFromSuperview];
-  appMenuButton_ = newMenuButton;
-
-  // Adjust the menu button's position.
-  NSRect menuButtonFrame = [appMenuButton_ frame];
-  if (isRTL) {
-    menuButtonFrame.origin.x =
-        [ToolbarController appMenuPadding] + kButtonInset;
-  } else {
-    CGFloat menuButtonFrameMaxX =
-        NSMaxX(toolbarBounds) - [ToolbarController appMenuPadding];
-    menuButtonFrame.origin.x =
-        menuButtonFrameMaxX - kButtonInset - toolbarButtonSize.width;
-  }
-  menuButtonFrame.origin.y = yPosition;
-  menuButtonFrame.size = toolbarButtonSize;
-  [appMenuButton_ setFrame:menuButtonFrame];
-  [appMenuButton_ setAutoresizingMask:trailingButtonMask];
-
-  // Adjust the size and location on the location bar to take up the
-  // space between the reload and menu buttons.
-  NSRect locationBarFrame = [locationBar_ frame];
-  locationBarFrame.origin.x = isRTL
-                                  ? NSMaxX(menuButtonFrame) + kButtonInset
-                                  : NSMaxX([homeButton_ frame]) + kButtonInset;
-  if (![homeButton_ isHidden] && !isRTL) {
-    // Ensure proper spacing between the home button and location bar
-    locationBarFrame.origin.x += kElementPadding;
-  }
-  locationBarFrame.origin.y =
-      NSMaxY(toolbarBounds) - kLocationBarPadding - kLocationBarHeight;
-  CGFloat rightEdge = 0;
-  if (isRTL) {
-    rightEdge = NSMinX([homeButton_ frame]) - kButtonInset;
-    if (![homeButton_ isHidden])
-      rightEdge -= kElementPadding;
-  } else {
-    rightEdge = NSMinX(menuButtonFrame);
-  }
-  locationBarFrame.size.width = rightEdge - NSMinX(locationBarFrame);
-
-  locationBarFrame.size.height = kLocationBarHeight;
-  [locationBar_ setFrame:locationBarFrame];
-
-  notificationBridge_.reset(
-      new ToolbarControllerInternal::NotificationBridge(self));
-  notificationBridge_->UpdateSeverity();
-
-  [appMenuButton_ setOpenMenuOnClick:YES];
-
-  [backButton_ setOpenMenuOnRightClick:YES];
-  [forwardButton_ setOpenMenuOnRightClick:YES];
-
-  [backButton_ setHandleMiddleClick:YES];
-  [forwardButton_ setHandleMiddleClick:YES];
-  [reloadButton_ setHandleMiddleClick:YES];
-  [homeButton_ setHandleMiddleClick:YES];
-
-  [self initCommandStatus:commands_];
-  [reloadButton_ setCommandUpdater:commands_];
-
-  locationBarView_.reset(new LocationBarViewMac(commands_, profile_, browser_));
-
-  // Register pref observers for the optional home and page/options buttons
-  // and then add them to the toolbar based on those prefs.
-  PrefService* prefs = profile_->GetPrefs();
-  showHomeButton_.Init(
-      prefs::kShowHomeButton, prefs,
-      base::Bind(
-          &ToolbarControllerInternal::NotificationBridge::OnPreferenceChanged,
-          base::Unretained(notificationBridge_.get())));
-  [self showOptionalHomeButton];
-
-  // Create the controllers for the back/forward menus.
-  backMenuController_.reset([[BackForwardMenuController alloc]
-          initWithBrowser:browser_
-                modelType:BACK_FORWARD_MENU_TYPE_BACK
-                   button:backButton_]);
-  forwardMenuController_.reset([[BackForwardMenuController alloc]
-          initWithBrowser:browser_
-                modelType:BACK_FORWARD_MENU_TYPE_FORWARD
-                   button:forwardButton_]);
-
-  trackingArea_.reset(
-      [[CrTrackingArea alloc] initWithRect:NSZeroRect // Ignored
-                                   options:NSTrackingMouseMoved |
-                                           NSTrackingInVisibleRect |
-                                           NSTrackingMouseEnteredAndExited |
-                                           NSTrackingActiveAlways
-                                     owner:self
-                                  userInfo:nil]);
-  NSView* parentView = [self view];
-  [parentView addTrackingArea:trackingArea_.get()];
-
-  // If the user has any Browser Actions installed, the container view for them
-  // may have to be resized depending on the width of the toolbar frame.
-  [parentView setPostsFrameChangedNotifications:YES];
-  [[NSNotificationCenter defaultCenter]
-      addObserver:self
-         selector:@selector(toolbarFrameChanged)
-             name:NSViewFrameDidChangeNotification
-           object:parentView];
-
-  // Set ViewIDs for toolbar elements which don't have their dedicated class.
-  // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and
-  // |browserActionsContainerView_| are handled by themselves.
-  view_id_util::SetID(backButton_, VIEW_ID_BACK_BUTTON);
-  view_id_util::SetID(forwardButton_, VIEW_ID_FORWARD_BUTTON);
-  view_id_util::SetID(homeButton_, VIEW_ID_HOME_BUTTON);
-  view_id_util::SetID(appMenuButton_, VIEW_ID_APP_MENU);
-
-  [self addAccessibilityDescriptions];
-}
-
-- (void)dealloc {
-  [self cleanUp];
-  [super dealloc];
-}
-
-- (void)browserWillBeDestroyed {
-  // Clear resize delegate so it doesn't get called during stopAnimation, and
-  // stop any in-flight animation.
-  [[self toolbarView] setResizeDelegate:nil];
-  [[self toolbarView] stopAnimation];
-
-  // Pass this call onto other reference counted objects.
-  [backMenuController_ browserWillBeDestroyed];
-  [forwardMenuController_ browserWillBeDestroyed];
-
-  [self cleanUp];
-}
-
-- (void)cleanUp {
-  // Unset ViewIDs of toolbar elements.
-  // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and
-  // |browserActionsContainerView_| are handled by themselves.
-  view_id_util::UnsetID(backButton_);
-  view_id_util::UnsetID(forwardButton_);
-  view_id_util::UnsetID(homeButton_);
-  view_id_util::UnsetID(appMenuButton_);
-
-  // Make sure any code in the base class which assumes [self view] is
-  // the "parent" view continues to work.
-  hasToolbar_ = YES;
-  hasLocationBar_ = YES;
-
-  [[NSNotificationCenter defaultCenter] removeObserver:self];
-
-  if (trackingArea_.get()) {
-    [[self view] removeTrackingArea:trackingArea_.get()];
-    [trackingArea_.get() clearOwner];
-    trackingArea_.reset();
-  }
-
-  // Destroy owned objects that hold a weak Browser*.
-  locationBarView_.reset();
-  browser_ = nullptr;
-}
-
-- (void)addAccessibilityDescriptions {
-  // Set accessibility descriptions. http://openradar.appspot.com/7496255
-  NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_BACK);
-  [[backButton_ cell]
-      accessibilitySetOverrideValue:description
-                       forAttribute:NSAccessibilityDescriptionAttribute];
-  NSString* helpTag = l10n_util::GetNSStringWithFixup(IDS_ACCDESCRIPTION_BACK);
-  [[backButton_ cell]
-      accessibilitySetOverrideValue:helpTag
-                       forAttribute:NSAccessibilityHelpAttribute];
-
-  description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_FORWARD);
-  [[forwardButton_ cell]
-      accessibilitySetOverrideValue:description
-                       forAttribute:NSAccessibilityDescriptionAttribute];
-  helpTag = l10n_util::GetNSStringWithFixup(IDS_ACCDESCRIPTION_FORWARD);
-  [[forwardButton_ cell]
-      accessibilitySetOverrideValue:helpTag
-                       forAttribute:NSAccessibilityHelpAttribute];
-
-  description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_RELOAD);
-  [[reloadButton_ cell]
-      accessibilitySetOverrideValue:description
-                       forAttribute:NSAccessibilityDescriptionAttribute];
-  description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_HOME);
-  [[homeButton_ cell]
-      accessibilitySetOverrideValue:description
-                       forAttribute:NSAccessibilityDescriptionAttribute];
-  description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_APP);
-  [[appMenuButton_ cell]
-      accessibilitySetOverrideValue:description
-                       forAttribute:NSAccessibilityDescriptionAttribute];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
-  [[hoveredButton_ cell] setIsMouseInside:NO];
-  [hoveredButton_ release];
-  hoveredButton_ = nil;
-}
-
-- (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent {
-  NSButton* targetView = (NSButton*)[[self view]
-                                     hitTest:[theEvent locationInWindow]];
-
-  // Only interpret the view as a hoverButton_ if it's both button and has a
-  // button cell that cares.  GradientButtonCell derived cells care.
-  if (([targetView isKindOfClass:[NSButton class]]) &&
-      ([[targetView cell]
-         respondsToSelector:@selector(setIsMouseInside:)]))
-    return targetView;
-  return nil;
-}
-
-- (void)mouseMoved:(NSEvent*)theEvent {
-  NSButton* targetView = [self hoverButtonForEvent:theEvent];
-  if (hoveredButton_ != targetView) {
-    [[hoveredButton_ cell] setIsMouseInside:NO];
-    [[targetView cell] setIsMouseInside:YES];
-    [hoveredButton_ release];
-    hoveredButton_ = [targetView retain];
-  }
-}
-
-- (void)mouseEntered:(NSEvent*)event {
-  [self mouseMoved:event];
-}
-
-- (ToolbarViewCocoa*)toolbarView {
-  return base::mac::ObjCCastStrict<ToolbarViewCocoa>([self view]);
-}
-
-- (LocationBarViewMac*)locationBarBridge {
-  return locationBarView_.get();
-}
-
-- (void)locationBarWasAddedToWindow {
-}
-
-- (BOOL)locationBarHasFocus {
-  return NO;
-}
-
-- (void)focusLocationBar:(BOOL)selectAll {
-}
-
-// Called when the state for a command changes to |enabled|. Update the
-// corresponding UI element.
-- (void)enabledStateChangedForCommand:(int)command enabled:(bool)enabled {
-  NSButton* button = nil;
-  switch (command) {
-    case IDC_BACK:
-      button = backButton_;
-      break;
-    case IDC_FORWARD:
-      button = forwardButton_;
-      break;
-    case IDC_HOME:
-      button = homeButton_;
-      break;
-  }
-  [button setEnabled:enabled];
-}
-
-// Init the enabled state of the buttons on the toolbar to match the state in
-// the controller.
-- (void)initCommandStatus:(CommandUpdater*)commands {
-  [backButton_ setEnabled:commands->IsCommandEnabled(IDC_BACK) ? YES : NO];
-  [forwardButton_
-      setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO];
-  [reloadButton_ setEnabled:YES];
-  [homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO];
-}
-
-- (void)updateToolbarWithContents:(WebContents*)tab {
-  BOOL needReloadMenu = chrome::IsDebuggerAttachedToCurrentTab(browser_);
-  [reloadButton_ setMenuEnabled:needReloadMenu];
-}
-
-- (void)resetTabState:(WebContents*)tab {
-}
-
-- (void)setStarredState:(BOOL)isStarred {
-}
-
-- (void)setTranslateIconLit:(BOOL)on {
-}
-
-- (void)zoomChangedForActiveTab:(BOOL)canShowBubble {
-}
-
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
-  [reloadButton_ setIsLoading:isLoading force:force];
-}
-
-- (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar {
-  [self view];  // Force nib loading.
-
-  hasToolbar_ = toolbar;
-
-  hasLocationBar_ = NO;
-
-  // Decide whether to hide/show based on whether there's a location bar.
-  [[self view] setHidden:!toolbar];
-}
-
-- (id)customFieldEditorForObject:(id)obj {
-  return nil;
-}
-
-// Returns an array of views, ordered leading to trailing.
-- (NSArray*)toolbarViews {
-  return @[
-    backButton_, forwardButton_, reloadButton_, homeButton_, locationBar_,
-    browserActionsContainerView_, appMenuButton_
-  ];
-}
-
-// Show or hide the home button based on the pref.
-- (void)showOptionalHomeButton {
-  // Ignore this message if only showing the URL bar.
-  if (!hasToolbar_)
-    return;
-  BOOL hide = showHomeButton_.GetValue() ? NO : YES;
-  if (hide == [homeButton_ isHidden])
-    return;  // Nothing to do, view state matches pref state.
-
-  [homeButton_ setHidden:hide];
-}
-
-- (void)updateAppMenuButtonSeverity:(AppMenuIconController::Severity)severity
-                           iconType:(AppMenuIconController::IconType)iconType
-                            animate:(BOOL)animate {
-  AppToolbarButton* appMenuButton =
-      base::mac::ObjCCastStrict<AppToolbarButton>(appMenuButton_);
-  [appMenuButton setSeverity:severity iconType:iconType shouldAnimate:animate];
-}
-
-- (void)prefChanged:(const std::string&)prefName {
-  if (prefName == prefs::kShowHomeButton) {
-    [self showOptionalHomeButton];
-  }
-}
-
-- (void)updateVisibility:(BOOL)visible withAnimation:(BOOL)animate {
-  CGFloat newHeight = visible ? [ToolbarController locationBarHeight] : 0;
-
-  // Perform the animation, which will cause the BrowserWindowController to
-  // resize this view in the browser layout as required.
-  if (animate) {
-    [[self toolbarView] animateToNewHeight:newHeight
-                                  duration:kToolBarAnimationDuration];
-  } else {
-    [[self toolbarView] setHeight:newHeight];
-  }
-}
-
-- (void)maintainMinimumLocationBarWidth {
-}
-
-- (void)toolbarFrameChanged {
-}
-
-- (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate {
-}
-
-- (NSPoint)bookmarkBubblePoint {
-  return [self appMenuBubblePoint];
-}
-
-- (NSPoint)appMenuBubblePoint {
-  NSRect frame = appMenuButton_.frame;
-  NSPoint point = NSMakePoint(NSMaxX(frame), NSMinY(frame));
-  return [self.view convertPoint:point toView:nil];
-}
-
-- (CGFloat)baseToolbarHeight {
-  // Height of the toolbar in pixels when the bookmark bar is closed.
-  const CGFloat kBaseToolbarHeightNormal = 37;
-  return kBaseToolbarHeightNormal;
-}
-
-- (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight {
-  // With no toolbar, just ignore the compression.
-  if (!hasToolbar_)
-    return NSHeight([locationBar_ frame]);
-
-  return [self baseToolbarHeight] - compressByHeight;
-}
-
-- (void)setDividerOpacity:(CGFloat)opacity {
-  ToolbarViewCocoa* toolbarView = [self toolbarView];
-  [toolbarView setShowsDivider:(opacity > 0 ? YES : NO)];
-  [toolbarView setDividerOpacity:opacity];
-  [toolbarView setNeedsDisplay:YES];
-}
-
-- (NSView*)appMenuButton {
-  return appMenuButton_;
-}
-
-- (BOOL)isLocationBarFocused {
-  return NO;
-}
-
-// (URLDropTargetController protocol)
-- (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point {
-  // TODO(viettrungluu): This code is more or less copied from the code in
-  // |TabStripControllerCocoa|. I'll refactor this soon to make it common and
-  // expand its capabilities (e.g., allow text DnD).
-  if ([urls count] < 1) {
-    NOTREACHED();
-    return;
-  }
-
-  for (NSUInteger index = 0; index < [urls count]; index++) {
-    // Refactor this code.
-    // https://crbug.com/665261.
-    GURL url = url_formatter::FixupURL(
-        base::SysNSStringToUTF8([urls objectAtIndex:index]), std::string());
-
-    // If the URL isn't valid, don't bother.
-    if (!url.is_valid())
-      continue;
-
-    // Security: Sanitize text to prevent self-XSS.
-    if (url.SchemeIs(url::kJavaScriptScheme))
-      continue;
-
-    WindowOpenDisposition disposition;
-    if (index == 0)
-      disposition = WindowOpenDisposition::CURRENT_TAB;
-    else
-      disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
-
-    OpenURLParams params(url, Referrer(), disposition,
-                         ui::PAGE_TRANSITION_TYPED, false);
-    browser_->tab_strip_model()->GetActiveWebContents()->OpenURL(params);
-  }
-}
-
-// (URLDropTargetController protocol)
-- (void)dropText:(NSString*)text inView:(NSView*)view at:(NSPoint)point {
-  // TODO(viettrungluu): This code is more or less copied from the code in
-  // |TabStripControllerCocoa|. I'll refactor this soon to make it common and
-  // expand its capabilities (e.g., allow text DnD).
-
-  // If the input is plain text, classify the input and make the URL.
-  AutocompleteMatch match;
-  AutocompleteClassifierFactory::GetForProfile(browser_->profile())->Classify(
-      base::SysNSStringToUTF16(text), false, false,
-      metrics::OmniboxEventProto::BLANK, &match, NULL);
-  GURL url(match.destination_url);
-
-  // Security: Block JavaScript to prevent self-XSS.
-  if (url.SchemeIs(url::kJavaScriptScheme))
-    return;
-
-  OpenURLParams params(url, Referrer(), WindowOpenDisposition::CURRENT_TAB,
-                       ui::PAGE_TRANSITION_TYPED, false);
-  browser_->tab_strip_model()->GetActiveWebContents()->OpenURL(params);
-}
-
-// (URLDropTargetController protocol)
-- (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point {
-  // Do nothing.
-}
-
-// (URLDropTargetController protocol)
-- (void)hideDropURLsIndicatorInView:(NSView*)view {
-  // Do nothing.
-}
-
-// (URLDropTargetController protocol)
-- (BOOL)isUnsupportedDropData:(id<NSDraggingInfo>)info {
-  return drag_util::IsUnsupportedDropData(profile_, info);
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h b/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h
deleted file mode 100644
index 629ba8a5..0000000
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_VIEW_COCOA_H_
-#define CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_VIEW_COCOA_H_
-
-#import <Cocoa/Cocoa.h>
-#import "chrome/browser/ui/cocoa/animatable_view.h"
-
-// A view that handles any special rendering of the toolbar bar.  At
-// this time it only draws a gradient.  Future changes (e.g. themes)
-// may require new functionality here.
-
-@interface ToolbarViewCocoa : AnimatableView {
- @private
-  // The opacity of the divider line (at the bottom of the toolbar); used when
-  // the detached bookmark bar is morphing to the normal bar and vice versa.
-  CGFloat dividerOpacity_;
-}
-
-@property(assign, nonatomic) CGFloat dividerOpacity;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_VIEW_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm
deleted file mode 100644
index 94798c3..0000000
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h"
-
-#import "chrome/browser/ui/cocoa/view_id_util.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#include "ui/base/material_design/material_design_controller.h"
-
-@implementation ToolbarViewCocoa
-
-@synthesize dividerOpacity = dividerOpacity_;
-
-// Prevent mouse down events from moving the parent window around.
-- (BOOL)mouseDownCanMoveWindow {
-  return NO;
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
-  [self drawBackground:dirtyRect];
-}
-
-- (BOOL)accessibilityIsIgnored {
-  return NO;
-}
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
-  if ([attribute isEqual:NSAccessibilityRoleAttribute])
-    return NSAccessibilityToolbarRole;
-
-  return [super accessibilityAttributeValue:attribute];
-}
-
-- (ViewID)viewID {
-  return VIEW_ID_TOOLBAR;
-}
-
-- (BOOL)isOpaque {
-  return YES;
-}
-
-// ThemedWindowDrawing overrides.
-
-- (void)windowDidChangeActive {
-  // Need to redraw the omnibox and toolbar buttons as well.
-  [self cr_recursivelySetNeedsDisplay:YES];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm
deleted file mode 100644
index 373c596..0000000
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class ToolbarViewTest : public CocoaTest {
-};
-
-// This class only needs to do one thing: prevent mouse down events from moving
-// the parent window around.
-TEST_F(ToolbarViewTest, CanDragWindow) {
-  base::scoped_nsobject<ToolbarViewCocoa> view([[ToolbarViewCocoa alloc] init]);
-  EXPECT_FALSE([view mouseDownCanMoveWindow]);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h
deleted file mode 100644
index 4e7302e..0000000
--- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_WEB_CONTENTS_MODAL_DIALOG_MANAGER_VIEWS_MAC_H_
-#define CHROME_BROWSER_UI_COCOA_WEB_CONTENTS_MODAL_DIALOG_MANAGER_VIEWS_MAC_H_
-
-#import "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "components/web_modal/single_web_contents_dialog_manager.h"
-#include "ui/views/widget/widget_observer.h"
-
-@class NSWindow;
-@class WrappedConstrainedWindowSheet;
-
-// WebContents dialog manager for a toolkit-views dialog parented off a Cocoa
-// browser window. Most of the modality behavior is still performed by the Cocoa
-// based ConstrainedWindowSheetController. This class bridges the expectations
-// of a toolkit-views dialog to the Cocoa ConstrainedWindowSheetController.
-// Note that this is not a web_modal::ModalDialogHostObserver. This is because
-// tabs in a Cocoa browser can't be dragged off their window if they have a tab-
-// modal dialog open, so the ModalDialogHost is only used by the views plumbing
-// when creating the dialog.
-class SingleWebContentsDialogManagerViewsMac
-    : public web_modal::SingleWebContentsDialogManager,
-      public views::WidgetObserver {
- public:
-  SingleWebContentsDialogManagerViewsMac(
-      NSWindow* dialog,
-      web_modal::SingleWebContentsDialogManagerDelegate* delegate);
-
-  ~SingleWebContentsDialogManagerViewsMac() override;
-
-  // SingleWebContentsDialogManager:
-  void Show() override;
-  void Hide() override;
-  void Close() override;
-  void Focus() override;
-  void Pulse() override;
-  void HostChanged(web_modal::WebContentsModalDialogHost* new_host) override;
-  gfx::NativeWindow dialog() override;
-
-  // views::WidgetObserver:
-  void OnWidgetClosing(views::Widget* widget) override;
-  void OnWidgetDestroying(views::Widget* widget) override;
-
- private:
-  base::scoped_nsobject<WrappedConstrainedWindowSheet> sheet_;
-  // Weak. Owns this.
-  web_modal::SingleWebContentsDialogManagerDelegate* delegate_;
-  // Weak. Owned by parent window.
-  web_modal::WebContentsModalDialogHost* host_;
-
-  views::Widget* widget_;  // Weak. Deletes |this| when closing.
-
-  bool was_shown_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(SingleWebContentsDialogManagerViewsMac);
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_WEB_CONTENTS_MODAL_DIALOG_MANAGER_VIEWS_MAC_H_
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm
deleted file mode 100644
index 9ee9b0e8..0000000
--- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2015 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 "chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h"
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/mac/foundation_util.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
-#include "content/public/browser/web_contents.h"
-#include "components/web_modal/web_contents_modal_dialog_host.h"
-#import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
-#include "ui/views/widget/widget.h"
-
-// A wrapper for a views::Widget dialog to interact with a Cocoa browser's
-// ContrainedWindowSheetController. Similar to CustomConstrainedWindowSheet, but
-// since Widgets of dialog type animate themselves, and also manage their own
-// parenting, there's not much to do except position properly.
-@interface WrappedConstrainedWindowSheet : NSObject<ConstrainedWindowSheet> {
- @private
-  base::scoped_nsobject<NSWindow> customWindow_;
-}
-- (id)initWithCustomWindow:(NSWindow*)customWindow;
-@end
-
-@implementation WrappedConstrainedWindowSheet
-
-- (id)initWithCustomWindow:(NSWindow*)customWindow {
-  if ((self = [super init])) {
-    customWindow_.reset([customWindow retain]);
-  }
-  return self;
-}
-
-// ConstrainedWindowSheet implementation.
-
-- (void)showSheetForWindow:(NSWindow*)window {
-  // This is only called for the initial show, then calls go to unhideSheet.
-  // Since Widget::Show() will be called, just update the position.
-  [self updateSheetPosition];
-}
-
-- (void)closeSheetWithAnimation:(BOOL)withAnimation {
-  // Nothing to do here. Either SingleWebContentsDialogManagerViewsMac::Close()
-  // was called or Widget::Close(). Both cases ending up in OnWidgetClosing() to
-  // call [ConstrainedWindowSheetController closeSheet:], which calls this.
-  // However, the Widget is already closing in those cases.
-
-  // OnWidgetClosing() is also the _only_ trigger. The exception would be
-  // -[ConstrainedWindowSheetController onParentWindowWillClose:] which also
-  // calls closeSheetWithAnimation:, but a Widget never gets there because
-  // WebContentsModalDialogManager::CloseAllDialogs() is triggered from
-  // -[BrowserWindowController windowShouldClose:], but the notification that
-  // calls onParentWindowWillClose always happens once that has returned YES.
-
-  // So, since onParentWindowWillClose never calls this, we can assert that
-  // withAnimation is YES, otherwise there's some code path that might not be
-  // catered for.
-  DCHECK(withAnimation);
-}
-
-- (void)hideSheet {
-  // Hide the sheet window by setting the alpha to 0. This technique is used
-  // instead of -orderOut: because that may cause a Spaces change or window
-  // ordering change.
-  [customWindow_ setAlphaValue:0.0];
-  // TODO(tapted): Support child windows.
-  DCHECK_EQ(0u, [[customWindow_ childWindows] count]);
-}
-
-- (void)unhideSheet {
-  [customWindow_ setAlphaValue:1.0];
-  DCHECK_EQ(0u, [[customWindow_ childWindows] count]);
-}
-
-- (void)pulseSheet {
-  base::scoped_nsobject<NSAnimation> animation(
-      [[ConstrainedWindowAnimationPulse alloc] initWithWindow:customWindow_]);
-  [animation startAnimation];
-}
-
-- (void)makeSheetKeyAndOrderFront {
-  // If the window is not visible, do nothing. Widget::Show() is responsible for
-  // showing, and it may want to animate it.
-  if ([customWindow_ isVisible])
-    [customWindow_ makeKeyAndOrderFront:nil];
-}
-
-- (void)updateSheetPosition {
-  ConstrainedWindowSheetController* controller =
-      [ConstrainedWindowSheetController controllerForSheet:self];
-  NSPoint origin = [controller originForSheet:self
-                               withWindowSize:[customWindow_ frame].size];
-  [customWindow_ setFrameOrigin:origin];
-}
-
-- (void)resizeWithNewSize:(NSSize)size {
-  // NOOP
-}
-
-- (NSWindow*)sheetWindow {
-  return customWindow_;
-}
-
-@end
-
-SingleWebContentsDialogManagerViewsMac::SingleWebContentsDialogManagerViewsMac(
-    NSWindow* dialog,
-    web_modal::SingleWebContentsDialogManagerDelegate* delegate)
-    : delegate_(delegate), host_(nullptr) {
-  sheet_.reset(
-      [[WrappedConstrainedWindowSheet alloc] initWithCustomWindow:dialog]);
-  widget_ = views::Widget::GetWidgetForNativeWindow(dialog);
-  DCHECK(widget_);
-  widget_->AddObserver(this);
-}
-
-SingleWebContentsDialogManagerViewsMac::
-    ~SingleWebContentsDialogManagerViewsMac() {
-  DCHECK(!widget_->HasObserver(this));
-}
-
-void SingleWebContentsDialogManagerViewsMac::Show() {
-  DCHECK(host_);
-
-  NSView* parent_view = host_->GetHostView();
-  // Note that simply [parent_view window] for an inactive tab is nil. However,
-  // the following should always be non-nil for all WebContents containers.
-  NSWindow* parent_window =
-      delegate_->GetWebContents()->GetTopLevelNativeWindow();
-  // Register with the ConstrainedWindowSheetController. This ensures that, e.g.
-  // the NSView that overlays the Cocoa WebContents to intercept clicks is
-  // installed and managed.
-  [[ConstrainedWindowSheetController controllerForParentWindow:parent_window]
-          showSheet:sheet_
-      forParentView:parent_view];
-
-  if (!widget_->IsVisible()) {
-    if (was_shown_) {
-      // Disable animations when switching tabs.
-      widget_->SetVisibilityChangedAnimationsEnabled(false);
-    }
-    widget_->Show();
-    widget_->SetVisibilityChangedAnimationsEnabled(true);
-    was_shown_ = true;
-  }
-}
-
-void SingleWebContentsDialogManagerViewsMac::Hide() {
-  NSWindow* parent_window =
-      delegate_->GetWebContents()->GetTopLevelNativeWindow();
-  [[ConstrainedWindowSheetController controllerForParentWindow:parent_window]
-      hideSheet:sheet_];
-
-  widget_->Hide();
-}
-
-void SingleWebContentsDialogManagerViewsMac::Close() {
-  // When the WebContents is destroyed, WebContentsModalDialogManager
-  // ::CloseAllDialogs will call this. Close the Widget in the same manner as
-  // the dialogs so that codepaths are consistent.
-  widget_->SetVisibilityChangedAnimationsEnabled(false);
-  widget_->Close();  // Note: Synchronously calls OnWidgetClosing() below.
-}
-
-void SingleWebContentsDialogManagerViewsMac::Focus() {
-  [sheet_ makeSheetKeyAndOrderFront];
-}
-void SingleWebContentsDialogManagerViewsMac::Pulse() {
-  // Handled by ConstrainedWindowSheetController.
-}
-
-void SingleWebContentsDialogManagerViewsMac::HostChanged(
-    web_modal::WebContentsModalDialogHost* new_host) {
-  // No need to observe the host. For Cocoa, the constrained window controller
-  // will reposition the dialog when necessary. The host can also never change.
-  // Tabs showing a dialog can not be dragged off a Cocoa browser window.
-  // However, closing a tab with a dialog open will set the host back to null.
-  DCHECK_NE(!!host_, !!new_host);
-  host_ = new_host;
-}
-
-gfx::NativeWindow SingleWebContentsDialogManagerViewsMac::dialog() {
-  return [sheet_ sheetWindow];
-}
-
-// views::WidgetObserver:
-void SingleWebContentsDialogManagerViewsMac::OnWidgetClosing(
-    views::Widget* widget) {
-  DCHECK_EQ(widget, widget_);
-  widget->RemoveObserver(this);
-  [[ConstrainedWindowSheetController controllerForSheet:sheet_]
-      closeSheet:sheet_];
-  delegate_->WillClose(dialog());  // Deletes |this|.
-}
-
-void SingleWebContentsDialogManagerViewsMac::OnWidgetDestroying(
-    views::Widget* widget) {
-  // On Mac, this would only be reached if something called -[NSWindow close]
-  // on the dialog without going through Widget::Close or CloseNow(). In this
-  // case (only), OnWidgetClosing() is skipped, so invoke it here. Note: since
-  // dialogs have no titlebar, it "shouldn't" happen, but crashes in
-  // https://crbug.com/825809 suggest it can. Possibly this occurs via code
-  // injection or a third party tool.
-  OnWidgetClosing(widget);  // Deletes |this|.
-}
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac_browsertest.mm b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac_browsertest.mm
deleted file mode 100644
index 27e23fb..0000000
--- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac_browsertest.mm
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2015 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 "chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/test/test_timeouts.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/views/scoped_macviews_browser_mode.h"
-#include "components/constrained_window/constrained_window_views.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_observer.h"
-#include "ui/views/window/dialog_delegate.h"
-#include "url/gurl.h"
-
-using views::Widget;
-
-namespace {
-
-class WebContentsModalDialogManagerViewsMacTest : public InProcessBrowserTest,
-                                                  public views::WidgetObserver {
- public:
-  WebContentsModalDialogManagerViewsMacTest() {}
-
-  Widget* ShowViewsDialogOn(int web_contents_index, bool activate) {
-    if (activate)
-      browser()->tab_strip_model()->ActivateTabAt(web_contents_index, true);
-    content::WebContents* web_contents =
-        browser()->tab_strip_model()->GetWebContentsAt(web_contents_index);
-
-    DCHECK(web_contents);
-
-    // Show a dialog as a constrained window modal to the current tab.
-    Widget* widget = constrained_window::ShowWebModalDialogViews(new TestDialog,
-                                                                 web_contents);
-    widget->AddObserver(this);
-    return widget;
-  }
-
-  void WaitForClose() {
-    last_destroyed_ = nullptr;
-    base::RunLoop run_loop;
-    run_loop_ = &run_loop;
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, run_loop.QuitClosure(), TestTimeouts::action_timeout());
-    run_loop.Run();
-    run_loop_ = nullptr;
-  }
-
-  // views::WidgetObserver:
-  void OnWidgetDestroying(views::Widget* widget) override {
-    destroy_count_++;
-    widget->RemoveObserver(this);
-    last_destroyed_ = widget;
-    if (run_loop_)
-      run_loop_->Quit();
-  }
-
-  class TestDialog : public views::DialogDelegateView {
-   public:
-    TestDialog() {}
-    // WidgetDelegate:
-    ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_CHILD; }
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(TestDialog);
-  };
-
- protected:
-  int destroy_count_ = 0;
-  Widget* last_destroyed_ = nullptr;
-  base::RunLoop* run_loop_ = nullptr;
-
- private:
-  test::ScopedMacViewsBrowserMode cocoa_browser_mode_{false};
-
-  DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerViewsMacTest);
-};
-
-}  // namespace
-
-// Basic test for showing and dismissing the dialog in a single tab.
-IN_PROC_BROWSER_TEST_F(WebContentsModalDialogManagerViewsMacTest, Basic) {
-  NSArray* children = [browser()->window()->GetNativeWindow() childWindows];
-  EXPECT_EQ(0u, [children count]);
-
-  Widget* dialog = ShowViewsDialogOn(0, true);
-  EXPECT_TRUE(dialog->IsVisible());
-
-  // The browser window will get two child windows: a transparent overlay, and
-  // the views::Widget dialog. Ensure the dialog is on top.
-  children = [browser()->window()->GetNativeWindow() childWindows];
-  EXPECT_EQ(2u, [children count]);
-  EXPECT_EQ(dialog->GetNativeWindow(), [children objectAtIndex:1]);
-
-  // Toolkit-views dialogs use GetWidget()->Close() to dismiss themselves.
-  dialog->Close();
-  EXPECT_EQ(0, destroy_count_);
-  WaitForClose();
-  EXPECT_EQ(dialog, last_destroyed_);
-  EXPECT_EQ(1, destroy_count_);
-}
-
-// Test for some code injection or third party tool invoking -[NSWindow close].
-IN_PROC_BROWSER_TEST_F(WebContentsModalDialogManagerViewsMacTest, NativeClose) {
-  NSArray* children = [browser()->window()->GetNativeWindow() childWindows];
-  EXPECT_EQ(0u, [children count]);
-
-  Widget* dialog = ShowViewsDialogOn(0, true);
-  EXPECT_TRUE(dialog->IsVisible());
-
-  // Chrome code never does this, but ensure the codepaths are robust to it.
-  // Invoking this will jump to SingleWebContentsDialogManagerViewsMac::
-  // OnWidgetDestroying() without first encountering OnWidgetClosing().
-  [dialog->GetNativeWindow() close];
-
-  EXPECT_EQ(1, destroy_count_);
-  EXPECT_EQ(dialog, last_destroyed_);
-}
-
-// Test showing dialogs in two tabs, switch tabs, then close the background tab,
-// then close the browser window.
-IN_PROC_BROWSER_TEST_F(WebContentsModalDialogManagerViewsMacTest,
-                       TwoDialogsThenCloseTabs) {
-  // Add a second tab, then show a dialog on each while the tab is active.
-  AddTabAtIndex(1, GURL("about:blank"), ui::PAGE_TRANSITION_LINK);
-  Widget* dialog1 = ShowViewsDialogOn(1, true);
-  Widget* dialog0 = ShowViewsDialogOn(0, true);
-
-  // Tab 0 is active, so only |dialog0| should become visible.
-  EXPECT_TRUE(dialog0->IsVisible());
-  EXPECT_FALSE(dialog1->IsVisible());
-
-  // The inactive, second dialog will also be fully transparent.
-  EXPECT_EQ(0.0, [dialog1->GetNativeWindow() alphaValue]);
-  EXPECT_EQ(1.0, [dialog0->GetNativeWindow() alphaValue]);
-
-  // Activate the second tab, visibility should switch.
-  browser()->tab_strip_model()->ActivateTabAt(1, true);
-  EXPECT_EQ(1.0, [dialog1->GetNativeWindow() alphaValue]);
-  EXPECT_EQ(0.0, [dialog0->GetNativeWindow() alphaValue]);
-  EXPECT_FALSE(dialog0->IsVisible());
-  EXPECT_TRUE(dialog1->IsVisible());
-
-  // Close the background tab.
-  browser()->tab_strip_model()->CloseWebContentsAt(
-      0, TabStripModel::CLOSE_USER_GESTURE);
-  // Close is asynchronous, so nothing happens until a run loop is spun up.
-  EXPECT_EQ(0, destroy_count_);
-  WaitForClose();
-  EXPECT_EQ(dialog0, last_destroyed_);
-  EXPECT_EQ(1, destroy_count_);
-
-  // Close the window. But first close all tabs. Otherwise before-unload
-  // handlers have an opportunity to run, which is asynchronous.
-  browser()->tab_strip_model()->CloseAllTabs();
-  // Since the parent NSWindow goes away, close happens immediately.
-  browser()->window()->Close();
-  EXPECT_EQ(dialog1, last_destroyed_);
-  EXPECT_EQ(2, destroy_count_);
-}
-
-// Test showing in a dialog in an inactive tab. For these, the WebContentsView
-// will be detached from the view hierarchy.
-IN_PROC_BROWSER_TEST_F(WebContentsModalDialogManagerViewsMacTest,
-                       DialogInBackgroundTab) {
-  // Add a second tab. It should start active.
-  AddTabAtIndex(1, GURL("about:blank"), ui::PAGE_TRANSITION_LINK);
-  EXPECT_TRUE(browser()->tab_strip_model()->IsTabSelected(1));
-
-  // Showing shouldn't change the active tab, and the dialog shouldn't be shown
-  // at all yet.
-  Widget* dialog0 = ShowViewsDialogOn(0, false);
-  EXPECT_TRUE(browser()->tab_strip_model()->IsTabSelected(1));
-  EXPECT_FALSE(dialog0->IsVisible());
-
-  // But switching to the tab should show (and animate) it.
-  browser()->tab_strip_model()->ActivateTabAt(0, true);
-  EXPECT_TRUE(browser()->tab_strip_model()->IsTabSelected(0));
-  EXPECT_TRUE(dialog0->IsVisible());
-
-  // Leave the dialog open for a change to ensure shutdown is clean.
-}
diff --git a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc
index e27284a..aebc2a5 100644
--- a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc
+++ b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc
@@ -28,6 +28,8 @@
     ui::LinuxInputMethodContextDelegate* delegate,
     bool is_simple)
     : delegate_(delegate),
+      is_simple_(is_simple),
+      has_focus_(false),
       gtk_context_(nullptr),
       gdk_last_set_client_window_(nullptr) {
   CHECK(delegate_);
@@ -103,14 +105,23 @@
 
 void X11InputMethodContextImplGtk::Reset() {
   gtk_im_context_reset(gtk_context_);
+
+  // Some input methods may not honour the reset call.
+  // Focusing out/in the to make sure it gets reset correctly.
+  if (!is_simple_ && has_focus_) {
+    Blur();
+    Focus();
+  }
 }
 
 void X11InputMethodContextImplGtk::Focus() {
   gtk_im_context_focus_in(gtk_context_);
+  has_focus_ = true;
 }
 
 void X11InputMethodContextImplGtk::Blur() {
   gtk_im_context_focus_out(gtk_context_);
+  has_focus_ = false;
 }
 
 void X11InputMethodContextImplGtk::SetCursorLocation(const gfx::Rect& rect) {
@@ -127,6 +138,12 @@
   }
 }
 
+void X11InputMethodContextImplGtk::SetSurroundingText(
+    const base::string16& text,
+    const gfx::Range& selection_range) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
 // private:
 
 void X11InputMethodContextImplGtk::ResetXModifierKeycodesCache() {
diff --git a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h
index 83a530c..5431b643 100644
--- a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h
+++ b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h
@@ -35,6 +35,8 @@
   void Reset() override;
   void Focus() override;
   void Blur() override;
+  void SetSurroundingText(const base::string16& text,
+                          const gfx::Range& selection_range) override;
 
  private:
   // Resets the cache of X modifier keycodes.
@@ -79,6 +81,14 @@
   // A set of callback functions.  Must not be nullptr.
   ui::LinuxInputMethodContextDelegate* delegate_;
 
+  // Input method context type flag.
+  //   - true if it supports table-based input methods
+  //   - false if it supports multiple, loadable input methods
+  bool is_simple_;
+
+  // Keeps track of current focus state.
+  bool has_focus_;
+
   // IME's input GTK context.
   GtkIMContext* gtk_context_;
 
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
index 291a4054..072a727 100644
--- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
@@ -14,10 +14,13 @@
 #include "chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h"
 #include "chrome/common/chrome_features.h"
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "components/ukm/content/source_url_recorder.h"
 #include "components/url_formatter/idn_spoof_checker.h"
 #include "components/url_formatter/url_formatter.h"
 #include "content/public/browser/navigation_handle.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
 
 namespace {
 
@@ -80,14 +83,17 @@
     return;
 
   std::string matched_domain;
+  MatchType match_type;
   if (result.matching_top_domain.empty()) {
     matched_domain = GetMatchingSiteEngagementDomain(service, url);
     if (matched_domain.empty())
       return;
     RecordEvent(NavigationSuggestionEvent::kMatchSiteEngagement);
+    match_type = MatchType::kSiteEngagement;
   } else {
     matched_domain = result.matching_top_domain;
     RecordEvent(NavigationSuggestionEvent::kMatchTopSite);
+    match_type = MatchType::kTopSite;
   }
 
   DCHECK(!matched_domain.empty());
@@ -96,6 +102,14 @@
   replace_host.SetHostStr(matched_domain);
   const GURL suggested_url = url.ReplaceComponents(replace_host);
 
+  ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
+  CHECK(ukm_recorder);
+  ukm::SourceId source_id =
+      ukm::GetSourceIdForWebContentsDocument(web_contents());
+  ukm::builders::LookalikeUrl_NavigationSuggestion(source_id)
+      .SetMatchType(static_cast<int>(match_type))
+      .Record(ukm_recorder);
+
   if (kMetricsOnly.Get().empty()) {
     RecordEvent(NavigationSuggestionEvent::kInfobarShown);
     AlternateNavInfoBarDelegate::CreateForLookalikeUrlNavigation(
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h
index 967e0cd3..0b9b12d 100644
--- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h
@@ -20,7 +20,7 @@
     : public content::WebContentsObserver,
       public content::WebContentsUserData<LookalikeUrlNavigationObserver> {
  public:
-  // Used for metrics.
+  // Used for metrics. Multiple events can occur per navigation.
   enum class NavigationSuggestionEvent {
     kNone = 0,
     kInfobarShown = 1,
@@ -33,6 +33,17 @@
     kMaxValue = kMatchSiteEngagement,
   };
 
+  // Used for UKM. There is only a single MatchType per navigation.
+  enum class MatchType {
+    kNone = 0,
+    kTopSite = 1,
+    kSiteEngagement = 2,
+
+    // Append new items to the end of the list above; do not modify or replace
+    // existing values. Comment out obsolete items.
+    kMaxValue = kSiteEngagement,
+  };
+
   static const char kHistogramName[];
 
   static void CreateForWebContents(content::WebContents* web_contents);
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
index d02edd3c..699d07f 100644
--- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
@@ -19,13 +19,18 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/infobars/core/infobar.h"
 #include "components/infobars/core/infobar_delegate.h"
+#include "components/ukm/test_ukm_recorder.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "net/dns/mock_host_resolver.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_source.h"
 #include "ui/base/window_open_disposition.h"
 
 namespace {
 
+using UkmEntry = ukm::builders::LookalikeUrl_NavigationSuggestion;
+
 enum class FeatureTestState { kDisabled, kEnabledWithoutUI, kEnabledWithUI };
 
 struct SiteEngagementTestCase {
@@ -67,6 +72,7 @@
   void SetUpOnMainThread() override {
     host_resolver()->AddRule("*", "127.0.0.1");
     ASSERT_TRUE(embedded_test_server()->Start());
+    test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
   }
 
   // Sets the absolute Site Engagement |score| for the testing origin.
@@ -86,6 +92,26 @@
     ui_test_utils::NavigateToURL(&params);
   }
 
+  // Checks that UKM recorded a metric for each URL in |navigated_urls|.
+  void CheckUkm(const std::vector<GURL>& navigated_urls,
+                LookalikeUrlNavigationObserver::MatchType match_type) {
+    auto entries = test_ukm_recorder()->GetEntriesByName(UkmEntry::kEntryName);
+    ASSERT_EQ(navigated_urls.size(), entries.size());
+    int entry_count = 0;
+    for (const auto* const entry : entries) {
+      test_ukm_recorder()->ExpectEntrySourceHasUrl(entry,
+                                                   navigated_urls[entry_count]);
+      test_ukm_recorder()->ExpectEntryMetric(entry, "MatchType",
+                                             static_cast<int>(match_type));
+      entry_count++;
+    }
+  }
+
+  void CheckNoUkm() {
+    EXPECT_TRUE(
+        test_ukm_recorder()->GetEntriesByName(UkmEntry::kEntryName).empty());
+  }
+
   void TestInfobarNotShown(const GURL& navigated_url) {
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
@@ -141,8 +167,11 @@
     EXPECT_FALSE(base::ContainsValue(enumerator.urls(), navigated_url));
   }
 
+  ukm::TestUkmRecorder* test_ukm_recorder() { return test_ukm_recorder_.get(); }
+
  private:
   base::test::ScopedFeatureList feature_list_;
+  std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
 };
 
 INSTANTIATE_TEST_CASE_P(,
@@ -156,6 +185,7 @@
                        NonIdn_NoInfobar) {
   TestInfobarNotShown(
       embedded_test_server()->GetURL("google.com", "/title1.html"));
+  CheckNoUkm();
 }
 
 // Navigating to a domain whose visual representation does not look like a
@@ -164,6 +194,7 @@
                        NonTopDomainIdn_NoInfobar) {
   TestInfobarNotShown(
       embedded_test_server()->GetURL("éxample.com", "/title1.html"));
+  CheckNoUkm();
 }
 
 // Navigating to a domain whose visual representation looks like a top domain
@@ -175,8 +206,10 @@
 
   base::HistogramTester histograms;
 
-  TestInfobarShown(embedded_test_server()->GetURL(
-                       "googlé.com", "/title1.html") /* navigated */,
+  const GURL kNavigatedUrl =
+      embedded_test_server()->GetURL("googlé.com", "/title1.html");
+
+  TestInfobarShown(kNavigatedUrl,
                    embedded_test_server()->GetURL(
                        "google.com", "/title1.html") /* suggested */);
 
@@ -194,6 +227,8 @@
       LookalikeUrlNavigationObserver::kHistogramName,
       LookalikeUrlNavigationObserver::NavigationSuggestionEvent::kMatchTopSite,
       1);
+  CheckUkm({kNavigatedUrl},
+           LookalikeUrlNavigationObserver::MatchType::kTopSite);
 }
 
 // Same as TopDomainIdn_Infobar but the UI is disabled, so only checks for
@@ -204,9 +239,10 @@
     return;
 
   base::HistogramTester histograms;
+  const GURL kNavigatedUrl =
+      embedded_test_server()->GetURL("googlé.com", "/title1.html");
 
-  TestInfobarNotShown(
-      embedded_test_server()->GetURL("googlé.com", "/title1.html"));
+  TestInfobarNotShown(kNavigatedUrl);
 
   histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName,
                               1);
@@ -214,6 +250,8 @@
       LookalikeUrlNavigationObserver::kHistogramName,
       LookalikeUrlNavigationObserver::NavigationSuggestionEvent::kMatchTopSite,
       1);
+  CheckUkm({kNavigatedUrl},
+           LookalikeUrlNavigationObserver::MatchType::kTopSite);
 }
 
 // Same as TopDomainIdn_Infobar but the user has engaged with the domain before.
@@ -224,6 +262,7 @@
   const GURL url = embedded_test_server()->GetURL("googlé.com", "/title1.html");
   SetSiteEngagementScore(url, 20);
   TestInfobarNotShown(url);
+  CheckNoUkm();
 }
 
 // Navigating to a domain whose visual representation looks like a domain with a
@@ -239,11 +278,15 @@
   SetSiteEngagementScore(GURL("http://sité3.test"), 20);
   SetSiteEngagementScore(GURL("http://www.sité4.test"), 20);
 
+  std::vector<GURL> ukm_urls;
   for (const auto& test_case : kSiteEngagementTestCases) {
     base::HistogramTester histograms;
-    TestInfobarShown(
-        embedded_test_server()->GetURL(test_case.navigated, "/title1.html"),
-        embedded_test_server()->GetURL(test_case.suggested, "/title1.html"));
+    const GURL kNavigatedUrl =
+        embedded_test_server()->GetURL(test_case.navigated, "/title1.html");
+    TestInfobarShown(kNavigatedUrl, embedded_test_server()->GetURL(
+                                        test_case.suggested, "/title1.html"));
+    ukm_urls.push_back(kNavigatedUrl);
+
     histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName,
                                 3);
     histograms.ExpectBucketCount(LookalikeUrlNavigationObserver::kHistogramName,
@@ -260,6 +303,8 @@
             kMatchSiteEngagement,
         1);
   }
+  CheckUkm(ukm_urls,
+           LookalikeUrlNavigationObserver::MatchType::kSiteEngagement);
 }
 
 // Same as SiteEngagement_Infobar but the UI is disabled, so only checks for
@@ -274,10 +319,14 @@
   SetSiteEngagementScore(GURL("http://sité3.test"), 20);
   SetSiteEngagementScore(GURL("http://www.sité4.test"), 20);
 
+  std::vector<GURL> ukm_urls;
   for (const auto& test_case : kSiteEngagementTestCases) {
     base::HistogramTester histograms;
-    TestInfobarNotShown(
-        embedded_test_server()->GetURL(test_case.navigated, "/title1.html"));
+    const GURL kNavigatedUrl =
+        embedded_test_server()->GetURL(test_case.navigated, "/title1.html");
+    TestInfobarNotShown(kNavigatedUrl);
+    ukm_urls.push_back(kNavigatedUrl);
+
     histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName,
                                 1);
     histograms.ExpectBucketCount(
@@ -286,6 +335,8 @@
             kMatchSiteEngagement,
         1);
   }
+  CheckUkm(ukm_urls,
+           LookalikeUrlNavigationObserver::MatchType::kSiteEngagement);
 }
 
 // The infobar shouldn't be shown when the feature is disabled.
@@ -296,4 +347,5 @@
 
   TestInfobarNotShown(
       embedded_test_server()->GetURL("googlé.com", "/title1.html"));
+  CheckNoUkm();
 }
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
index f7e93c81..2cd1517 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
+++ b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
@@ -185,7 +185,6 @@
   }
 }
 
-// TODO(crbug/867194): Add metrics for legal message link clicking.
 void LocalCardMigrationDialogView::StyledLabelLinkClicked(
     views::StyledLabel* label,
     const gfx::Range& range,
@@ -193,6 +192,9 @@
   if (!controller_)
     return;
 
+  controller_->OnLegalMessageLinkClicked();
+  // TODO(crbug.com/867194): Should be controller's responsibility to open
+  // links.
   legal_message_container_->OnLinkClicked(label, range, web_contents_);
 }
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
index 65499f68..98f7628 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -76,13 +76,9 @@
 class DialogWaiter : public aura::EnvObserver,
                      public views::WidgetObserver {
  public:
-  DialogWaiter()
-      : dialog_created_(false),
-        dialog_(NULL) {
-    aura::Env::GetInstance()->AddObserver(this);
-  }
+  explicit DialogWaiter(aura::Env* env) : env_(env) { env_->AddObserver(this); }
 
-  ~DialogWaiter() override { aura::Env::GetInstance()->RemoveObserver(this); }
+  ~DialogWaiter() override { env_->RemoveObserver(this); }
 
   views::Widget* WaitForDialog() {
     if (dialog_created_)
@@ -116,8 +112,9 @@
     }
   }
 
-  bool dialog_created_;
-  views::Widget* dialog_;
+  aura::Env* env_;
+  bool dialog_created_ = false;
+  views::Widget* dialog_ = nullptr;
   base::Closure quit_closure_;
 
   DISALLOW_COPY_AND_ASSIGN(DialogWaiter);
@@ -1340,7 +1337,8 @@
     ASSERT_TRUE(child_menu != NULL);
 
     // Click and wait until the dialog box appears.
-    std::unique_ptr<DialogWaiter> dialog_waiter(new DialogWaiter());
+    auto dialog_waiter = std::make_unique<DialogWaiter>(
+        bb_view_->GetWidget()->GetNativeWindow()->env());
     ui_test_utils::MoveMouseToCenterAndPress(
         child_menu, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
         base::Bind(&BookmarkBarViewTest12::Step4, base::Unretained(this),
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc
index 476e0e66d..263ba71e 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -128,8 +128,7 @@
     views::View* view,
     ax::mojom::Event event_type) {
 #if defined(USE_AURA)
-  AutomationManagerAura::GetInstance()->HandleEvent(
-      GetProfileForWindow(view->GetWidget()), view, event_type);
+  AutomationManagerAura::GetInstance()->HandleEvent(view, event_type);
 #endif
 }
 
diff --git a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
index 1d006ce..1e1bf5f 100644
--- a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
+++ b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
@@ -81,12 +81,14 @@
   // well to catch 'em all.
   void OnMouseMoved(const ui::MouseEvent& event) override {
     auto pair = GetParentWidgetAndEvent(this, &event);
-    pair.widget->OnMouseEvent(&pair.event);
+    if (pair.widget)
+      pair.widget->OnMouseEvent(&pair.event);
   }
 
   void OnMouseEvent(ui::MouseEvent* event) override {
     auto pair = GetParentWidgetAndEvent(this, event);
-    pair.widget->OnMouseEvent(&pair.event);
+    if (pair.widget)
+      pair.widget->OnMouseEvent(&pair.event);
 
     // If the original event isn't marked as "handled" then it will propagate up
     // the view hierarchy and might be double-handled. https://crbug.com/870341
@@ -95,10 +97,14 @@
 
   gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override {
     auto pair = GetParentWidgetAndEvent(this, &event);
-    views::View* omnibox_view =
-        pair.widget->GetRootView()->GetEventHandlerForPoint(
-            pair.event.location());
-    return omnibox_view->GetCursor(pair.event);
+    if (pair.widget) {
+      views::View* omnibox_view =
+          pair.widget->GetRootView()->GetEventHandlerForPoint(
+              pair.event.location());
+      return omnibox_view->GetCursor(pair.event);
+    }
+
+    return nullptr;
   }
 #endif  // !USE_AURA
 };
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
index 1188e96..e6b929d5 100644
--- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
+++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
@@ -83,8 +83,8 @@
 CvcUnmaskViewController::~CvcUnmaskViewController() {}
 
 void CvcUnmaskViewController::LoadRiskData(
-    const base::Callback<void(const std::string&)>& callback) {
-  autofill::LoadRiskData(0, web_contents_, callback);
+    base::OnceCallback<void(const std::string&)> callback) {
+  autofill::LoadRiskData(0, web_contents_, std::move(callback));
 }
 
 void CvcUnmaskViewController::ShowUnmaskPrompt(
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
index 41e8c78f..77f418dd 100644
--- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
+++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
@@ -55,7 +55,7 @@
 
   // autofill::RiskDataLoader:
   void LoadRiskData(
-      const base::Callback<void(const std::string&)>& callback) override;
+      base::OnceCallback<void(const std::string&)> callback) override;
 
   // autofill::payments::FullCardRequest::UIDelegate:
   void ShowUnmaskPrompt(
diff --git a/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h b/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h
deleted file mode 100644
index 0811df2..0000000
--- a/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_GET_APP_MENU_ANCHOR_POINT_H_
-#define CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_GET_APP_MENU_ANCHOR_POINT_H_
-
-#include "ui/gfx/geometry/point.h"
-
-class Browser;
-
-// Returns the point to which bubbles should be anchored for the app menu of
-// |browser|.
-gfx::Point GetAppMenuAnchorPoint(Browser* browser);
-
-#endif  // CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_GET_APP_MENU_ANCHOR_POINT_H_
diff --git a/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.mm b/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.mm
deleted file mode 100644
index 261ccda..0000000
--- a/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.mm
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h"
-
-#import "chrome/browser/ui/browser.h"
-#import "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
-#include "ui/base/cocoa/cocoa_base_utils.h"
-#import "ui/gfx/mac/coordinate_conversion.h"
-
-gfx::Point GetAppMenuAnchorPoint(Browser* browser) {
-  NSWindow* parent_window = browser->window()->GetNativeWindow();
-  BrowserWindowController* bwc =
-      [BrowserWindowController browserWindowControllerForWindow:parent_window];
-  ToolbarController* tbc = [bwc toolbarController];
-  NSPoint ns_point = [tbc appMenuBubblePoint];
-  return gfx::ScreenPointFromNSPoint(
-      ui::ConvertPointFromWindowToScreen(parent_window, ns_point));
-}
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc
index 8c7f2bf..32e36f1 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc
@@ -36,35 +36,8 @@
 
 #if defined(OS_MACOSX)
 #include "chrome/browser/platform_util.h"
-#if BUILDFLAG(MAC_VIEWS_BROWSER)
-#include "chrome/browser/ui/views_mode_controller.h"
-#endif  // BUILDFLAG(MAC_VIEWS_BROWSER)
-#include "chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h"
 #endif  // defined(OS_MACOSX)
 
-namespace {
-
-// Returns the anchor for |browser|'s app menu, accounting for macOS running
-// with views or Cocoa.
-std::pair<views::Button*, gfx::Point> GetAnchor(Browser* browser) {
-#if defined(OS_MACOSX)
-#if BUILDFLAG(MAC_VIEWS_BROWSER)
-  if (views_mode_controller::IsViewsBrowserCocoa())
-    return std::make_pair(nullptr, GetAppMenuAnchorPoint(browser));
-#else   // BUILDFLAG(MAC_VIEWS_BROWSER)
-  return std::make_pair(nullptr, GetAppMenuAnchorPoint(browser));
-#endif  // BUILDFLAG(MAC_VIEWS_BROWSER)
-#endif  // defined(OS_MACOSX)
-#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
-  return std::make_pair(BrowserView::GetBrowserViewForBrowser(browser)
-                            ->toolbar()
-                            ->app_menu_button(),
-                        gfx::Point());
-#endif  // !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
-}
-
-}  // namespace
-
 // static
 views::Widget* RelaunchRecommendedBubbleView::ShowBubble(
     Browser* browser,
@@ -72,13 +45,12 @@
     base::RepeatingClosure on_accept) {
   DCHECK(browser);
 
-  views::Button* anchor_button;
-  gfx::Point anchor_point;
-
   // Anchor the popup to the browser's app menu.
-  std::tie(anchor_button, anchor_point) = GetAnchor(browser);
+  auto* anchor_button = BrowserView::GetBrowserViewForBrowser(browser)
+                            ->toolbar()
+                            ->app_menu_button();
   auto* bubble_view = new RelaunchRecommendedBubbleView(
-      anchor_button, anchor_point, detection_time, std::move(on_accept));
+      anchor_button, gfx::Point(), detection_time, std::move(on_accept));
   bubble_view->SetArrow(views::BubbleBorder::TOP_RIGHT);
 
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc
index eb08cdc..01d482a0 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc
@@ -121,7 +121,7 @@
 
   // Setup corresponding TouchscreenDevice object
   ui::TouchscreenDevice touchscreen =
-      ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB,
                             "Touchscreen", gfx::Size(800, 600), 1);
   touchscreen.vendor_id = kWhitelistedId;
   ws::InputDeviceClientTestApi().SetTouchscreenDevices({touchscreen});
@@ -164,7 +164,7 @@
 
   // Setup corresponding TouchscreenDevice object
   ui::TouchscreenDevice touchscreen =
-      ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+      ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB,
                             "Touchscreen", gfx::Size(800, 600), 1);
   touchscreen.vendor_id = kWhitelistedId;
   ws::InputDeviceClientTestApi().SetTouchscreenDevices({touchscreen});
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc
index 7fd0854..9cf3cf6 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc
@@ -185,7 +185,7 @@
   // Simulate an external keyboard being connected. We should assume there's a
   // Caps Lock and Meta keys now.
   input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{
-      {2, ui::INPUT_DEVICE_EXTERNAL, "external keyboard"}});
+      {2, ui::INPUT_DEVICE_USB, "external keyboard"}});
   EXPECT_TRUE(HasCapsLock());
   EXPECT_FALSE(HasDiamondKey());
   EXPECT_TRUE(HasExternalMetaKey());
@@ -194,7 +194,7 @@
   // Simulate an external Apple keyboard being connected. Now users can remap
   // the command key.
   input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{
-      {3, ui::INPUT_DEVICE_EXTERNAL, "Apple Inc. Apple Keyboard"}});
+      {3, ui::INPUT_DEVICE_USB, "Apple Inc. Apple Keyboard"}});
   EXPECT_TRUE(HasCapsLock());
   EXPECT_FALSE(HasDiamondKey());
   EXPECT_FALSE(HasExternalMetaKey());
@@ -203,8 +203,8 @@
   // Simulate two external keyboards (Apple and non-Apple) are connected at the
   // same time.
   input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{
-      {2, ui::INPUT_DEVICE_EXTERNAL, "external keyboard"},
-      {3, ui::INPUT_DEVICE_EXTERNAL, "Apple Inc. Apple Keyboard"}});
+      {2, ui::INPUT_DEVICE_USB, "external keyboard"},
+      {3, ui::INPUT_DEVICE_USB, "Apple Inc. Apple Keyboard"}});
   EXPECT_TRUE(HasCapsLock());
   EXPECT_FALSE(HasDiamondKey());
   EXPECT_TRUE(HasExternalMetaKey());
@@ -215,7 +215,7 @@
   // should show the capslock and external meta remapping.
   // https://crbug.com/834594.
   input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{
-      {4, ui::INPUT_DEVICE_EXTERNAL, "Topre Corporation Realforce 87"}});
+      {4, ui::INPUT_DEVICE_USB, "Topre Corporation Realforce 87"}});
   EXPECT_TRUE(HasCapsLock());
   EXPECT_FALSE(HasDiamondKey());
   EXPECT_TRUE(HasExternalMetaKey());
diff --git a/chrome/browser/vr/test/gl_test_environment_unittest.cc b/chrome/browser/vr/test/gl_test_environment_unittest.cc
index ee62da2..d66e7e451 100644
--- a/chrome/browser/vr/test/gl_test_environment_unittest.cc
+++ b/chrome/browser/vr/test/gl_test_environment_unittest.cc
@@ -9,7 +9,13 @@
 
 namespace vr {
 
-TEST(GlTestEnvironmentTest, InitializeAndCleanup) {
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_InitializeAndCleanup DISABLED_InitializeAndCleanup
+#else
+#define MAYBE_InitializeAndCleanup InitializeAndCleanup
+#endif
+
+TEST(GlTestEnvironmentTest, MAYBE_InitializeAndCleanup) {
   GlTestEnvironment gl_test_environment(gfx::Size(100, 100));
   EXPECT_NE(gl_test_environment.GetFrameBufferForTesting(), 0u);
   EXPECT_EQ(glGetError(), (GLenum)GL_NO_ERROR);
diff --git a/chrome/browser/vr/ui_pixeltest.cc b/chrome/browser/vr/ui_pixeltest.cc
index 64c15d3..1d4c3351 100644
--- a/chrome/browser/vr/ui_pixeltest.cc
+++ b/chrome/browser/vr/ui_pixeltest.cc
@@ -18,7 +18,13 @@
 
 }  // namespace
 
-TEST_F(UiPixelTest, DrawVrBrowsingMode) {
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_DrawVrBrowsingMode DISABLED_DrawVrBrowsingMode
+#else
+#define MAYBE_DrawVrBrowsingMode DrawVrBrowsingMode
+#endif
+
+TEST_F(UiPixelTest, MAYBE_DrawVrBrowsingMode) {
   // Set up scene.
   UiInitialState ui_initial_state;
   ui_initial_state.in_web_vr = false;
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index e5d09bd..821f504f 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -559,7 +559,7 @@
 // Enables or disables sliding (showing or hiding) the top-chrome UIs with page
 // scrolls in tablet mode.
 const base::Feature kSlideTopChromeWithPageScrolls{
-    "SlideTopChromeWithPageScrolls", base::FEATURE_DISABLED_BY_DEFAULT};
+    "SlideTopChromeWithPageScrolls", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables or disables chrome://sys-internals.
 const base::Feature kSysInternals{"SysInternals",
@@ -587,12 +587,6 @@
 // Chrome OS.
 const base::Feature kUserActivityEventLogging{"UserActivityEventLogging",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Enables or disables user activity prediction for power management on
-// Chrome OS.
-const base::Feature kUserActivityPrediction{"UserActivityPrediction",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
-
 #endif
 
 // Enables using the main HTTP cache for media files as well.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 2d0eb8ca..f137fb4 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -393,8 +393,6 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kUserActivityEventLogging;
 
-COMPONENT_EXPORT(CHROME_FEATURES)
-extern const base::Feature kUserActivityPrediction;
 #endif
 
 COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc
index 78264954..27c8c9357 100644
--- a/chrome/renderer/media/chrome_key_systems.cc
+++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -152,11 +152,11 @@
   // TODO(sandersd): Distinguish these from those that are directly supported,
   // as those may offer a higher level of protection.
   if (!supported_video_codecs.empty() || !is_secure) {
-    supported_codecs |= media::EME_CODEC_WEBM_OPUS;
-    supported_codecs |= media::EME_CODEC_WEBM_VORBIS;
-    supported_codecs |= media::EME_CODEC_MP4_FLAC;
+    supported_codecs |= media::EME_CODEC_OPUS;
+    supported_codecs |= media::EME_CODEC_VORBIS;
+    supported_codecs |= media::EME_CODEC_FLAC;
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-    supported_codecs |= media::EME_CODEC_MP4_AAC;
+    supported_codecs |= media::EME_CODEC_AAC;
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
   }
 
@@ -164,15 +164,15 @@
   for (const auto& codec : supported_video_codecs) {
     switch (codec) {
       case media::VideoCodec::kCodecVP8:
-        supported_codecs |= media::EME_CODEC_WEBM_VP8;
+        supported_codecs |= media::EME_CODEC_VP8;
         break;
       case media::VideoCodec::kCodecVP9:
-        supported_codecs |= media::EME_CODEC_WEBM_VP9;
-        supported_codecs |= media::EME_CODEC_COMMON_VP9;
+        supported_codecs |= media::EME_CODEC_LEGACY_VP9;
+        supported_codecs |= media::EME_CODEC_VP9;
         break;
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
       case media::VideoCodec::kCodecH264:
-        supported_codecs |= media::EME_CODEC_MP4_AVC1;
+        supported_codecs |= media::EME_CODEC_AVC1;
         break;
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
       default:
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index d11517d..ddc0d48 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1972,7 +1972,6 @@
         "../browser/ui/cocoa/touchbar/browser_window_touch_bar_controller_browsertest.mm",
         "../browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm",
         "../browser/ui/cocoa/view_id_util_browsertest.mm",
-        "../browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac_browsertest.mm",
 
         ## TODO(crbug/845389): Re-Enable the following, which were temporarily
         ## omitted from the build, but still in use by the Cocoa browser.
@@ -4128,11 +4127,8 @@
         "../browser/ui/cocoa/browser_window_layout_unittest.mm",
         "../browser/ui/cocoa/browser_window_utils_unittest.mm",
         "../browser/ui/cocoa/chrome_browser_window_unittest.mm",
-        "../browser/ui/cocoa/clickhold_button_cell_unittest.mm",
         "../browser/ui/cocoa/color_panel_cocoa_unittest.mm",
         "../browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm",
-        "../browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm",
-        "../browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm",
         "../browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm",
         "../browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm",
         "../browser/ui/cocoa/find_pasteboard_unittest.mm",
@@ -4145,10 +4141,8 @@
         "../browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm",
         "../browser/ui/cocoa/history_overlay_controller_unittest.mm",
         "../browser/ui/cocoa/hover_close_button_unittest.mm",
-        "../browser/ui/cocoa/image_button_cell_unittest.mm",
         "../browser/ui/cocoa/main_menu_builder_unittest.mm",
         "../browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm",
-        "../browser/ui/cocoa/menu_button_unittest.mm",
         "../browser/ui/cocoa/notifications/notification_builder_mac_unittest.mm",
         "../browser/ui/cocoa/notifications/notification_response_builder_mac_unittest.mm",
         "../browser/ui/cocoa/nsmenuitem_additions_unittest.mm",
@@ -4170,11 +4164,6 @@
         "../browser/ui/cocoa/test/run_loop_testing_unittest.mm",
         "../browser/ui/cocoa/test/styled_text_field_test_helper.h",
         "../browser/ui/cocoa/test/styled_text_field_test_helper.mm",
-        "../browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm",
-        "../browser/ui/cocoa/toolbar/app_toolbar_button_unittest.mm",
-        "../browser/ui/cocoa/toolbar/reload_button_unittest_cocoa.mm",
-        "../browser/ui/cocoa/toolbar/toolbar_button_unittest.mm",
-        "../browser/ui/cocoa/toolbar/toolbar_view_unittest.mm",
         "../browser/ui/cocoa/touchbar/browser_window_default_touch_bar_unittest.mm",
         "../browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm",
         "../browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm",
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index c4e50e8..bb93d11f 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -219,6 +219,30 @@
   return Status(kInvalidArgument, "invalid 'unhandledPromptBehavior'");
 }
 
+Status ParseTimeouts(const base::Value& option, Capabilities* capabilities) {
+  const base::DictionaryValue* timeouts;
+  if (!option.GetAsDictionary(&timeouts))
+    return Status(kInvalidArgument, "'timeouts' must be a JSON object");
+
+  std::map<std::string, Parser> parser_map;
+  parser_map["script"] =
+      base::BindRepeating(&ParseTimeDelta, &capabilities->script_timeout);
+  parser_map["pageLoad"] =
+      base::BindRepeating(&ParseTimeDelta, &capabilities->page_load_timeout);
+  parser_map["implicit"] = base::BindRepeating(
+      &ParseTimeDelta, &capabilities->implicit_wait_timeout);
+
+  for (const auto& it : timeouts->DictItems()) {
+    if (parser_map.find(it.first) == parser_map.end())
+      return Status(kInvalidArgument,
+                    "unrecognized 'timeouts' option: " + it.first);
+    Status status = parser_map[it.first].Run(it.second, capabilities);
+    if (status.IsError())
+      return Status(kInvalidArgument, "cannot parse " + it.first, status);
+  }
+  return Status(kOk);
+}
+
 Status ParseSwitches(const base::Value& option,
                      Capabilities* capabilities) {
   const base::ListValue* switches_list = NULL;
@@ -705,7 +729,7 @@
       base::BindRepeating(&ParseString, &platform_name);
   parser_map["pageLoadStrategy"] = base::BindRepeating(&ParsePageLoadStrategy);
   parser_map["proxy"] = base::BindRepeating(&ParseProxy);
-  // TODO(https://crbug.com/chromedriver/1997): Parse "timeouts".
+  parser_map["timeouts"] = base::BindRepeating(&ParseTimeouts);
   // TODO(https://crbug.com/chromedriver/2596): "unexpectedAlertBehaviour" is
   // legacy name of "unhandledPromptBehavior", remove when we stop supporting
   // legacy mode.
diff --git a/chrome/test/chromedriver/capabilities.h b/chrome/test/chromedriver/capabilities.h
index 425eeef1..ee890e27 100644
--- a/chrome/test/chromedriver/capabilities.h
+++ b/chrome/test/chromedriver/capabilities.h
@@ -20,6 +20,7 @@
 #include "chrome/test/chromedriver/chrome/devtools_http_client.h"
 #include "chrome/test/chromedriver/chrome/log.h"
 #include "chrome/test/chromedriver/net/net_util.h"
+#include "chrome/test/chromedriver/session.h"
 
 namespace base {
 class CommandLine;
@@ -119,10 +120,9 @@
 
   // Data from "proxy" capability are stored in "switches" field.
 
-  // The default values for the timeout fields came from W3C spec.
-  base::TimeDelta script_timeout = base::TimeDelta::FromSeconds(30);
-  base::TimeDelta page_load_timeout = base::TimeDelta::FromSeconds(300);
-  base::TimeDelta implicit_wait_timeout = base::TimeDelta::FromSeconds(0);
+  base::TimeDelta script_timeout = Session::kDefaultScriptTimeout;
+  base::TimeDelta page_load_timeout = Session::kDefaultPageLoadTimeout;
+  base::TimeDelta implicit_wait_timeout = Session::kDefaultImplicitWaitTimeout;
 
   std::string unhandled_prompt_behavior;
 
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py
index 5afa1605..f1d3074 100644
--- a/chrome/test/chromedriver/client/chromedriver.py
+++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -132,7 +132,7 @@
                send_w3c_capability=None, send_w3c_request=None,
                page_load_strategy=None, unexpected_alert_behaviour=None,
                devtools_events_to_log=None, accept_insecure_certs=None,
-               test_name=None):
+               timeouts=None, test_name=None):
     self._executor = command_executor.CommandExecutor(server_url)
     self.w3c_compliant = False
 
@@ -230,6 +230,9 @@
     if accept_insecure_certs is not None:
       params['acceptInsecureCerts'] = accept_insecure_certs
 
+    if timeouts is not None:
+      params['timeouts'] = timeouts
+
     if test_name is not None:
       params['goog:testName'] = test_name
 
@@ -360,6 +363,9 @@
     return self.ExecuteCommand(
         Command.FIND_ELEMENTS, {'using': strategy, 'value': target})
 
+  def GetTimeouts(self):
+    return self.ExecuteCommand(Command.GET_TIMEOUTS)
+
   def SetTimeouts(self, params):
     return self.ExecuteCommand(Command.SET_TIMEOUTS, params)
 
diff --git a/chrome/test/chromedriver/session.cc b/chrome/test/chromedriver/session.cc
index ab9eb29..30d0674c 100644
--- a/chrome/test/chromedriver/session.cc
+++ b/chrome/test/chromedriver/session.cc
@@ -29,10 +29,13 @@
       frame_id(frame_id),
       chromedriver_frame_id(chromedriver_frame_id) {}
 
+// The default timeout values came from W3C spec.
+const base::TimeDelta Session::kDefaultImplicitWaitTimeout =
+    base::TimeDelta::FromSeconds(0);
 const base::TimeDelta Session::kDefaultPageLoadTimeout =
-    base::TimeDelta::FromMinutes(5);
+    base::TimeDelta::FromSeconds(300);
 const base::TimeDelta Session::kDefaultScriptTimeout =
-    base::TimeDelta::FromMilliseconds(30000);
+    base::TimeDelta::FromSeconds(30);
 
 Session::Session(const std::string& id)
     : id(id),
@@ -43,6 +46,7 @@
       sticky_modifiers(0),
       mouse_position(0, 0),
       pressed_mouse_button(kNoneMouseButton),
+      implicit_wait(kDefaultImplicitWaitTimeout),
       page_load_timeout(kDefaultPageLoadTimeout),
       script_timeout(kDefaultScriptTimeout),
       auto_reporting_enabled(false) {}
@@ -57,6 +61,7 @@
       sticky_modifiers(0),
       mouse_position(0, 0),
       pressed_mouse_button(kNoneMouseButton),
+      implicit_wait(kDefaultImplicitWaitTimeout),
       page_load_timeout(kDefaultPageLoadTimeout),
       script_timeout(kDefaultScriptTimeout),
       auto_reporting_enabled(false) {}
diff --git a/chrome/test/chromedriver/session.h b/chrome/test/chromedriver/session.h
index 24ca85d..2a26abc1 100644
--- a/chrome/test/chromedriver/session.h
+++ b/chrome/test/chromedriver/session.h
@@ -50,6 +50,7 @@
 };
 
 struct Session {
+  static const base::TimeDelta kDefaultImplicitWaitTimeout;
   static const base::TimeDelta kDefaultPageLoadTimeout;
   static const base::TimeDelta kDefaultScriptTimeout;
 
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 3664417..ae63c03 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -269,6 +269,10 @@
 
   session->unhandled_prompt_behavior = capabilities.unhandled_prompt_behavior;
 
+  session->implicit_wait = capabilities.implicit_wait_timeout;
+  session->page_load_timeout = capabilities.page_load_timeout;
+  session->script_timeout = capabilities.script_timeout;
+
   Log::Level driver_level = Log::kWarning;
   if (capabilities.logging_prefs.count(WebDriverLog::kDriverType))
     driver_level = capabilities.logging_prefs[WebDriverLog::kDriverType];
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 2a9245a..8a68c711 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -2159,6 +2159,25 @@
 class ChromeDesiredCapabilityTest(ChromeDriverBaseTest):
   """Tests that chromedriver properly processes desired capabilities."""
 
+  def testDefaultTimeouts(self):
+    driver = self.CreateDriver()
+    timeouts = driver.GetTimeouts()
+    # Compare against defaults in W3C spec
+    self.assertEquals(timeouts['implicit'], 0)
+    self.assertEquals(timeouts['pageLoad'], 300000)
+    self.assertEquals(timeouts['script'], 30000)
+
+  def testTimeouts(self):
+    driver = self.CreateDriver(timeouts = {
+        'implicit': 123,
+        'pageLoad': 456,
+        'script':   789
+    })
+    timeouts = driver.GetTimeouts()
+    self.assertEquals(timeouts['implicit'], 123)
+    self.assertEquals(timeouts['pageLoad'], 456)
+    self.assertEquals(timeouts['script'], 789)
+
   def testUnexpectedAlertBehaviour(self):
     driver = self.CreateDriver(unexpected_alert_behaviour="accept")
     self.assertEquals("accept",
diff --git a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
index 26c4850..202ac10 100644
--- a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
+++ b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
@@ -166,6 +166,39 @@
           settings_sections_tests.TestNames.DisableMarginsByPagesPerSheet);
     });
 
+PrintPreviewPagesSettingsTest = class extends NewPrintPreviewTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://print/new/pages_settings.html';
+  }
+
+  /** @override */
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      '../settings/test_util.js',
+      'print_preview_test_utils.js',
+      'pages_settings_test.js',
+    ]);
+  }
+
+  /** @override */
+  get suiteName() {
+    return pages_settings_test.suiteName;
+  }
+};
+
+TEST_F('PrintPreviewPagesSettingsTest', 'ValidPageRanges', function() {
+  this.runMochaTest(pages_settings_test.TestNames.ValidPageRanges);
+});
+
+TEST_F('PrintPreviewPagesSettingsTest', 'InvalidPageRanges', function() {
+  this.runMochaTest(pages_settings_test.TestNames.InvalidPageRanges);
+});
+
+TEST_F('PrintPreviewPagesSettingsTest', 'NupChangesPages', function() {
+  this.runMochaTest(pages_settings_test.TestNames.NupChangesPages);
+});
+
 PrintPreviewPolicyTest = class extends NewPrintPreviewTest {
   /** @override */
   get browsePreload() {
diff --git a/chrome/test/data/webui/print_preview/pages_settings_test.js b/chrome/test/data/webui/print_preview/pages_settings_test.js
index 954fdc7..97f6cab7 100644
--- a/chrome/test/data/webui/print_preview/pages_settings_test.js
+++ b/chrome/test/data/webui/print_preview/pages_settings_test.js
@@ -68,12 +68,15 @@
       Polymer.dom.flush();
 
       const input = pagesSection.$.pageSettingsCustomInput.inputElement;
-      const readyForInput = pagesSection.$$('#custom-radio-button').checked ?
+      const pagesSelect = pagesSection.$$('select');
+      const readyForInput =
+          pagesSelect.value === pagesSection.pagesValueEnum_.CUSTOM.toString() ?
           Promise.resolve() :
-          test_util.eventToPromise('focus', input);
+          test_util.eventToPromise('process-select-change', pagesSection);
 
       // Select custom
-      pagesSection.$$('#custom-radio-button').click();
+      pagesSelect.value = pagesSection.pagesValueEnum_.CUSTOM.toString();
+      pagesSelect.dispatchEvent(new CustomEvent('change'));
       return readyForInput.then(() => {
         // Set input string
         input.value = inputString;
diff --git a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
index e82fee6..c7a351f7 100644
--- a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
+++ b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
@@ -99,36 +99,3 @@
       this.runMochaTest(
           destination_dialog_interactive_test.TestNames.FocusSearchBox);
     });
-
-PrintPreviewPagesSettingsTest = class extends PrintPreviewInteractiveUITest {
-  /** @override */
-  get browsePreload() {
-    return 'chrome://print/new/pages_settings.html';
-  }
-
-  /** @override */
-  get extraLibraries() {
-    return super.extraLibraries.concat([
-      '../settings/test_util.js',
-      'print_preview_test_utils.js',
-      'pages_settings_test.js',
-    ]);
-  }
-
-  /** @override */
-  get suiteName() {
-    return pages_settings_test.suiteName;
-  }
-};
-
-TEST_F('PrintPreviewPagesSettingsTest', 'ValidPageRanges', function() {
-  this.runMochaTest(pages_settings_test.TestNames.ValidPageRanges);
-});
-
-TEST_F('PrintPreviewPagesSettingsTest', 'InvalidPageRanges', function() {
-  this.runMochaTest(pages_settings_test.TestNames.InvalidPageRanges);
-});
-
-TEST_F('PrintPreviewPagesSettingsTest', 'NupChangesPages', function() {
-  this.runMochaTest(pages_settings_test.TestNames.NupChangesPages);
-});
diff --git a/chrome/test/data/webui/print_preview/settings_section_test.js b/chrome/test/data/webui/print_preview/settings_section_test.js
index 99d676d..7941e30 100644
--- a/chrome/test/data/webui/print_preview/settings_section_test.js
+++ b/chrome/test/data/webui/print_preview/settings_section_test.js
@@ -557,20 +557,21 @@
       assertFalse(pagesElement.hidden);
 
       // Default value is all pages. Print ticket expects this to be empty.
-      const allRadio = pagesElement.$$('#all-radio-button');
-      const customRadio = pagesElement.$$('#custom-radio-button');
+      const pagesSelect = pagesElement.$$('select');
+      const customInputCollapse = pagesElement.$$('iron-collapse');
       const pagesCrInput = pagesElement.$.pageSettingsCustomInput;
       const pagesInput = pagesCrInput.inputElement;
 
       /**
-       * @param {boolean} allChecked Whether the all pages radio button is
-       *     selected.
+       * @param {boolean} allSelected Whether the all pages option is selected.
        * @param {string} inputString The expected string in the pages input.
        * @param {boolean} valid Whether the input string is valid.
        */
-      const validateInputState = function(allChecked, inputString, valid) {
-        assertEquals(allChecked, allRadio.checked);
-        assertEquals(!allChecked, customRadio.checked);
+      const validateInputState = function(allSelected, inputString, valid) {
+        assertEquals(allSelected, !customInputCollapse.opened);
+        assertEquals(
+            allSelected,
+            pagesSelect.value === pagesElement.pagesValueEnum_.ALL.toString());
         assertEquals(inputString, pagesInput.value);
         assertEquals(valid, !pagesCrInput.invalid);
       };
@@ -580,15 +581,14 @@
       assertTrue(page.settings.pages.valid);
 
       // Set selection of pages 1 and 2.
-      customRadio.click();
+      pagesSelect.value = pagesElement.pagesValueEnum_.CUSTOM.toString();
+      pagesSelect.dispatchEvent(new CustomEvent('change'));
 
-      // Manually set |customSelected_| since focus may not work correctly on
-      // MacOS. The PageSettingsTests verify this behavior is correct on all
-      // platforms.
-      pagesElement.set('customSelected_', true);
-
-      triggerInputEvent(pagesInput, '1-2');
-      return test_util.eventToPromise('input-change', pagesElement)
+      return test_util.eventToPromise('process-select-change', pagesElement)
+          .then(function() {
+            triggerInputEvent(pagesInput, '1-2');
+            return test_util.eventToPromise('input-change', pagesElement);
+          })
           .then(function() {
             validateInputState(false, '1-2', true);
             assertEquals(1, page.settings.ranges.value.length);
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn
index 0432ad1..94d7255 100644
--- a/chromecast/base/BUILD.gn
+++ b/chromecast/base/BUILD.gn
@@ -313,7 +313,6 @@
       "$java_src_dir/org/chromium/chromecast/base/BiFunction.java",
       "$java_src_dir/org/chromium/chromecast/base/BiPredicate.java",
       "$java_src_dir/org/chromium/chromecast/base/Both.java",
-      "$java_src_dir/org/chromium/chromecast/base/CircularBuffer.java",
       "$java_src_dir/org/chromium/chromecast/base/Controller.java",
       "$java_src_dir/org/chromium/chromecast/base/Consumer.java",
       "$java_src_dir/org/chromium/chromecast/base/Function.java",
@@ -359,7 +358,6 @@
     java_files = [
       "$java_test_dir/org/chromium/chromecast/base/BothTest.java",
       "$java_test_dir/org/chromium/chromecast/base/ControllerTest.java",
-      "$java_test_dir/org/chromium/chromecast/base/CircularBufferTest.java",
       "$java_test_dir/org/chromium/chromecast/base/ItertoolsTest.java",
       "$java_test_dir/org/chromium/chromecast/base/ObservableAndTest.java",
       "$java_test_dir/org/chromium/chromecast/base/ObservableAndThenTest.java",
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/CircularBuffer.java b/chromecast/base/java/src/org/chromium/chromecast/base/CircularBuffer.java
deleted file mode 100644
index 8e0c33d..0000000
--- a/chromecast/base/java/src/org/chromium/chromecast/base/CircularBuffer.java
+++ /dev/null
@@ -1,78 +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.
-
-package org.chromium.chromecast.base;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * An Iterable object that stores up to a fixed amount of objects, and overwrites the least-recently
- * inserted object if it exceeds its capacity. Appending, removing, and iterating are all constant
- * time.
- *
- * This class is intended as a fast Iterable Deque with a fixed capacity. LinkedList generates lint
- * warnings because every item requires a heap allocation for the Node, ArrayList requires rewriting
- * the list when the head is removed, and ArrayDeque is not fixed-size.
- *
- * Currently, the only supported use case is appending items to the buffer, and then iterating the
- * buffer. Concurrent modification while iterating, or appending items after iterating, is
- * undefined behavior as of now.
- *
- * @param <T> The type that elements of the buffer should be instances of.
- */
-public class CircularBuffer<T> implements Iterable<T> {
-    private final List<T> mData;
-    private final int mSize;
-    private boolean mAtCapacity;
-    private int mHeadPosition;
-    private int mTailPosition;
-
-    public CircularBuffer(int size) {
-        mData = new ArrayList<T>(size);
-        mSize = size;
-        mAtCapacity = false;
-        mHeadPosition = 0;
-        mTailPosition = 0;
-    }
-
-    public void add(T item) {
-        if (mSize == 0) {
-            return;
-        }
-        if (mAtCapacity) {
-            mData.set(mHeadPosition, item);
-            mHeadPosition = increment(mHeadPosition);
-        } else {
-            mData.add(item);
-        }
-        mTailPosition = increment(mTailPosition);
-        if (mTailPosition == mHeadPosition) {
-            mAtCapacity = true;
-        }
-    }
-
-    @Override
-    public Iterator<T> iterator() {
-        return new Iterator<T>() {
-            @Override
-            public boolean hasNext() {
-                return mAtCapacity || mHeadPosition != mTailPosition;
-            }
-
-            @Override
-            public T next() {
-                T result = mData.get(mHeadPosition);
-                mHeadPosition = increment(mHeadPosition);
-                mAtCapacity = false;
-                return result;
-            }
-        };
-    }
-
-    private int increment(int position) {
-        return (position + 1) % mSize;
-    }
-}
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/CircularBufferTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/CircularBufferTest.java
deleted file mode 100644
index ec52b9b..0000000
--- a/chromecast/base/java/test/org/chromium/chromecast/base/CircularBufferTest.java
+++ /dev/null
@@ -1,73 +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.
-
-package org.chromium.chromecast.base;
-
-import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.emptyIterable;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.BlockJUnit4ClassRunner;
-
-/**
- * Tests for CircularBuffer.
- *
- * Currently, the only supported use case is appending items to the buffer, and then iterating the
- * buffer. Concurrent modification while iterating, or appending items after iterating, is
- * undefined behavior as of now.
- */
-@RunWith(BlockJUnit4ClassRunner.class)
-public class CircularBufferTest {
-    @Test
-    public void testBufferWithNoCapacity() {
-        CircularBuffer<String> buffer = new CircularBuffer<>(0);
-        buffer.add("a");
-        assertThat(buffer, emptyIterable());
-    }
-
-    @Test
-    public void testBufferWithPartialCapacity() {
-        CircularBuffer<String> buffer = new CircularBuffer<>(4);
-        buffer.add("a");
-        buffer.add("b");
-        buffer.add("c");
-        assertThat(buffer, contains("a", "b", "c"));
-    }
-
-    @Test
-    public void testBufferWithFullCapacity() {
-        CircularBuffer<String> buffer = new CircularBuffer<>(4);
-        buffer.add("zero");
-        buffer.add("one");
-        buffer.add("two");
-        buffer.add("three");
-        assertThat(buffer, contains("zero", "one", "two", "three"));
-    }
-
-    @Test
-    public void testBufferThatOverflowsCapacityWrapsAroundAndErasesOldestElements() {
-        CircularBuffer<String> buffer = new CircularBuffer<>(4);
-        buffer.add("1");
-        buffer.add("2");
-        buffer.add("3");
-        buffer.add("4"); // Hits capacity; subsequent additions overwrite oldest elements.
-        buffer.add("5"); // erases "1"
-        buffer.add("6"); // erases "2"
-        assertThat(buffer, contains("3", "4", "5", "6"));
-    }
-
-    @Test
-    public void testBufferThatOverflowsTwice() {
-        CircularBuffer<String> buffer = new CircularBuffer<>(2);
-        buffer.add("a");
-        buffer.add("b");
-        buffer.add("c");
-        buffer.add("d");
-        buffer.add("e");
-        // Since the capacity is 2, return the 2 most-recently added items.
-        assertThat(buffer, contains("d", "e"));
-    }
-}
diff --git a/chromecast/media/cma/backend/filter_group.cc b/chromecast/media/cma/backend/filter_group.cc
index 2e5d9934..a4be583a 100644
--- a/chromecast/media/cma/backend/filter_group.cc
+++ b/chromecast/media/cma/backend/filter_group.cc
@@ -198,6 +198,9 @@
 }
 
 int64_t FilterGroup::GetRenderingDelayMicroseconds() {
+  if (output_samples_per_second_ == 0) {
+    return 0;
+  }
   return delay_frames_ * base::Time::kMicrosecondsPerSecond /
          output_samples_per_second_;
 }
diff --git a/chromecast/renderer/media/key_systems_cast.cc b/chromecast/renderer/media/key_systems_cast.cc
index 73491048..da2796b 100644
--- a/chromecast/renderer/media/key_systems_cast.cc
+++ b/chromecast/renderer/media/key_systems_cast.cc
@@ -110,32 +110,31 @@
 
 #if BUILDFLAG(IS_CAST_USING_CMA_BACKEND)
 SupportedCodecs GetCastEmeSupportedCodecs() {
-  SupportedCodecs codecs =
-      ::media::EME_CODEC_MP4_AAC | ::media::EME_CODEC_MP4_AVC1 |
-      ::media::EME_CODEC_COMMON_VP9 | ::media::EME_CODEC_WEBM_VP8 |
-      ::media::EME_CODEC_WEBM_VP9;
+  SupportedCodecs codecs = ::media::EME_CODEC_AAC | ::media::EME_CODEC_AVC1 |
+                           ::media::EME_CODEC_VP9 | ::media::EME_CODEC_VP8 |
+                           ::media::EME_CODEC_LEGACY_VP9;
 
 #if !BUILDFLAG(DISABLE_SECURE_FLAC_OPUS_DECODING)
-  codecs |= ::media::EME_CODEC_MP4_FLAC | ::media::EME_CODEC_WEBM_OPUS;
+  codecs |= ::media::EME_CODEC_FLAC | ::media::EME_CODEC_OPUS;
 #endif  // BUILDFLAG(DISABLE_SECURE_FLAC_OPUS_DECODING)
 
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
-  codecs |= ::media::EME_CODEC_MP4_HEVC;
+  codecs |= ::media::EME_CODEC_HEVC;
 #endif  // BUILDFLAG(ENABLE_HEVC_DEMUXING)
 
 #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
-  codecs |= ::media::EME_CODEC_MP4_DV_AVC;
+  codecs |= ::media::EME_CODEC_DOLBY_VISION_AVC;
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
-  codecs |= ::media::EME_CODEC_MP4_DV_HEVC;
+  codecs |= ::media::EME_CODEC_DOLBY_VISION_HEVC;
 #endif  // BUILDFLAG(ENABLE_HEVC_DEMUXING)
 #endif  // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
 
 #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
-  codecs |= ::media::EME_CODEC_MP4_AC3 | ::media::EME_CODEC_MP4_EAC3;
+  codecs |= ::media::EME_CODEC_AC3 | ::media::EME_CODEC_EAC3;
 #endif  // BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
 
 #if BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING)
-  codecs |= ::media::EME_CODEC_MP4_MPEG_H_AUDIO;
+  codecs |= ::media::EME_CODEC_MPEG_H_AUDIO;
 #endif  // BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING)
 
   return codecs;
diff --git a/chromeos/chromeos_features.cc b/chromeos/chromeos_features.cc
index 2b8e7784..e6c444d3 100644
--- a/chromeos/chromeos_features.cc
+++ b/chromeos/chromeos_features.cc
@@ -45,6 +45,13 @@
 const base::Feature kMultiDeviceApi{"MultiDeviceApi",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables or disables user activity prediction for power management on
+// Chrome OS.
+// Defined here rather than in //chrome alongside other related features so that
+// PowerPolicyController can check it.
+const base::Feature kUserActivityPrediction{"UserActivityPrediction",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 
 }  // namespace chromeos
diff --git a/chromeos/chromeos_features.h b/chromeos/chromeos_features.h
index 9fcdab82..3b4d0f4 100644
--- a/chromeos/chromeos_features.h
+++ b/chromeos/chromeos_features.h
@@ -23,8 +23,8 @@
 CHROMEOS_EXPORT extern const base::Feature kEnableUnifiedMultiDeviceSetup;
 CHROMEOS_EXPORT extern const base::Feature kImeServiceConnectable;
 CHROMEOS_EXPORT extern const base::Feature kInstantTethering;
-
 CHROMEOS_EXPORT extern const base::Feature kMultiDeviceApi;
+CHROMEOS_EXPORT extern const base::Feature kUserActivityPrediction;
 
 }  // namespace features
 
diff --git a/chromeos/components/tether/host_scan_scheduler_impl.cc b/chromeos/components/tether/host_scan_scheduler_impl.cc
index 8fac55f..e790ab63b 100644
--- a/chromeos/components/tether/host_scan_scheduler_impl.cc
+++ b/chromeos/components/tether/host_scan_scheduler_impl.cc
@@ -138,11 +138,7 @@
   is_screen_locked_ = session_manager_->IsScreenLocked();
 
   if (is_screen_locked_) {
-    // If the screen is now locked, stop any ongoing scan. A scan during the
-    // lock screen could cause bad interactions with EasyUnlock. See
-    // https://crbug.com/763604.
-    // Note: Once the SecureChannel API is in use, the scan will no longer have
-    //       to stop.
+    // If the screen is now locked, stop any ongoing scan.
     host_scanner_->StopScan();
     if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi))
       delay_scan_after_unlock_timer_->Stop();
@@ -182,11 +178,9 @@
   if (host_scanner_->IsScanActive())
     return;
 
-  // If the SecureChannel API is not present, and the screen is locked, a host
-  // scan should not occur.  A scan during the lock screen could cause bad
-  // interactions with EasyUnlock. See https://crbug.com/763604.
-  if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi) &&
-      session_manager_->IsScreenLocked()) {
+  // If the screen is locked, a host scan should not occur.
+  if (session_manager_->IsScreenLocked()) {
+    PA_LOG(INFO) << "Skipping scan attempt because the screen is locked.";
     return;
   }
 
diff --git a/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc b/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc
index b96601b9..52e8e49 100644
--- a/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc
+++ b/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc
@@ -192,23 +192,21 @@
 
     SetMultiDeviceApiEnabled();
 
-    // Lock the screen. This should not trigger a scan.
+    // Lock the screen. This should never trigger a scan.
     SetScreenLockedState(true /* is_locked */);
     EXPECT_EQ(0u, fake_host_scanner_->num_scans_started());
     EXPECT_FALSE(mock_delay_scan_after_unlock_timer_->IsRunning());
 
-    // Try to start a scan. Regardless of screen lock state, this should cause a
-    // scan if the device is offline. The timer should not have been started.
+    // Try to start a scan. Because the screen is locked, this should not
+    // cause a scan to be started.
     host_scan_scheduler_->AttemptScanIfOffline();
-    EXPECT_EQ(is_online ? 0u : 1u, fake_host_scanner_->num_scans_started());
+    EXPECT_EQ(0u, fake_host_scanner_->num_scans_started());
     EXPECT_FALSE(mock_delay_scan_after_unlock_timer_->IsRunning());
 
-    fake_host_scanner_->StopScan();
-
     // Unlock the screen. If the device is offline, a new scan should have
     // started. The timer should be untouched.
     SetScreenLockedState(false /* is_locked */);
-    EXPECT_EQ(is_online ? 0u : 2u, fake_host_scanner_->num_scans_started());
+    EXPECT_EQ(is_online ? 0u : 1u, fake_host_scanner_->num_scans_started());
     EXPECT_FALSE(mock_delay_scan_after_unlock_timer_->IsRunning());
   }
 
diff --git a/chromeos/dbus/DEPS b/chromeos/dbus/DEPS
index 1d90fba1..840af75 100644
--- a/chromeos/dbus/DEPS
+++ b/chromeos/dbus/DEPS
@@ -3,6 +3,7 @@
 include_rules = [
   "+base",
   "+chromeos/chromeos_export.h",
+  "+chromeos/chromeos_features.h",
   "+components/account_id/account_id.h",
   "+components/device_event_log",
   "+components/policy/proto",
diff --git a/chromeos/dbus/power_policy_controller.cc b/chromeos/dbus/power_policy_controller.cc
index bc39c41..634be59 100644
--- a/chromeos/dbus/power_policy_controller.cc
+++ b/chromeos/dbus/power_policy_controller.cc
@@ -8,10 +8,12 @@
 
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "chromeos/chromeos_features.h"
 
 // Avoid some ugly line-wrapping later.
 using base::StringAppendF;
@@ -111,7 +113,8 @@
       presentation_screen_dim_delay_factor(1.0),
       user_activity_screen_dim_delay_factor(1.0),
       wait_for_initial_user_activity(false),
-      force_nonzero_brightness_for_user_activity(true) {}
+      force_nonzero_brightness_for_user_activity(true),
+      smart_dim_enabled(true) {}
 
 // static
 std::string PowerPolicyController::GetPolicyDebugString(
@@ -236,10 +239,22 @@
     prefs_policy_.set_battery_brightness_percent(
         values.battery_brightness_percent);
   }
-  prefs_policy_.set_presentation_screen_dim_delay_factor(
-      values.presentation_screen_dim_delay_factor);
-  prefs_policy_.set_user_activity_screen_dim_delay_factor(
-      values.user_activity_screen_dim_delay_factor);
+
+  // Screen-dim deferral in response to user activity predictions can
+  // interact poorly with delay scaling, resulting in the system staying
+  // awake for a long time if a prediction is wrong. See
+  // https://crbug.com/888392.
+  if (values.smart_dim_enabled &&
+      base::FeatureList::IsEnabled(features::kUserActivityPrediction)) {
+    prefs_policy_.set_presentation_screen_dim_delay_factor(1.0);
+    prefs_policy_.set_user_activity_screen_dim_delay_factor(1.0);
+  } else {
+    prefs_policy_.set_presentation_screen_dim_delay_factor(
+        values.presentation_screen_dim_delay_factor);
+    prefs_policy_.set_user_activity_screen_dim_delay_factor(
+        values.user_activity_screen_dim_delay_factor);
+  }
+
   prefs_policy_.set_wait_for_initial_user_activity(
       values.wait_for_initial_user_activity);
   prefs_policy_.set_force_nonzero_brightness_for_user_activity(
diff --git a/chromeos/dbus/power_policy_controller.h b/chromeos/dbus/power_policy_controller.h
index 38a4b572..1c55d65 100644
--- a/chromeos/dbus/power_policy_controller.h
+++ b/chromeos/dbus/power_policy_controller.h
@@ -77,6 +77,7 @@
     double user_activity_screen_dim_delay_factor;
     bool wait_for_initial_user_activity;
     bool force_nonzero_brightness_for_user_activity;
+    bool smart_dim_enabled;
   };
 
   // Returns a string describing |policy|.  Useful for tests.
diff --git a/chromeos/dbus/power_policy_controller_unittest.cc b/chromeos/dbus/power_policy_controller_unittest.cc
index f9a7c09..547035f2 100644
--- a/chromeos/dbus/power_policy_controller_unittest.cc
+++ b/chromeos/dbus/power_policy_controller_unittest.cc
@@ -7,6 +7,8 @@
 #include <memory>
 
 #include "base/message_loop/message_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "chromeos/chromeos_features.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -325,4 +327,40 @@
                 fake_power_client_->policy()));
 }
 
+TEST_F(PowerPolicyControllerTest, SmartDimEnabledExperimentEnabled) {
+  const std::map<std::string, std::string> params = {
+      {"dim_threshold", "0.651"}};
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeatureWithParameters(
+      chromeos::features::kUserActivityPrediction, params);
+
+  PowerPolicyController::PrefValues prefs;
+  policy_controller_->ApplyPrefs(prefs);
+  const power_manager::PowerManagementPolicy kDefaultPolicy =
+      fake_power_client_->policy();
+
+  // First disable smart dim model.
+  prefs.smart_dim_enabled = false;
+  prefs.presentation_screen_dim_delay_factor = 3.0;
+  prefs.user_activity_screen_dim_delay_factor = 2.0;
+  policy_controller_->ApplyPrefs(prefs);
+
+  power_manager::PowerManagementPolicy expected_policy = kDefaultPolicy;
+  expected_policy.set_presentation_screen_dim_delay_factor(3.0);
+  expected_policy.set_user_activity_screen_dim_delay_factor(2.0);
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy),
+            PowerPolicyController::GetPolicyDebugString(
+                fake_power_client_->policy()));
+
+  // Then enable smart dim model.
+  prefs.smart_dim_enabled = true;
+  policy_controller_->ApplyPrefs(prefs);
+
+  expected_policy.set_presentation_screen_dim_delay_factor(1.0);
+  expected_policy.set_user_activity_screen_dim_delay_factor(1.0);
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy),
+            PowerPolicyController::GetPolicyDebugString(
+                fake_power_client_->policy()));
+}
+
 }  // namespace chromeos
diff --git a/components/autofill/content/browser/risk/fingerprint.cc b/components/autofill/content/browser/risk/fingerprint.cc
index e6fd910..f12c1b09 100644
--- a/components/autofill/content/browser/risk/fingerprint.cc
+++ b/components/autofill/content/browser/risk/fingerprint.cc
@@ -194,7 +194,7 @@
       const std::string& app_locale,
       const std::string& user_agent,
       const base::TimeDelta& timeout,
-      const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback,
+      base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback,
       service_manager::Connector* connector);
 
  private:
@@ -249,7 +249,7 @@
   base::OneShotTimer timeout_timer_;
 
   // The callback that will be called once all the data is available.
-  base::Callback<void(std::unique_ptr<Fingerprint>)> callback_;
+  base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback_;
 
   // For invalidating asynchronous callbacks that might arrive after |this|
   // instance is destroyed.
@@ -270,7 +270,7 @@
     const std::string& app_locale,
     const std::string& user_agent,
     const base::TimeDelta& timeout,
-    const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback,
+    base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback,
     service_manager::Connector* connector)
     : gpu_data_manager_(content::GpuDataManager::GetInstance()),
       gpu_observer_(this),
@@ -285,7 +285,7 @@
       user_agent_(user_agent),
       install_time_(install_time),
       waiting_on_plugins_(true),
-      callback_(callback),
+      callback_(std::move(callback)),
       weak_ptr_factory_(this) {
   DCHECK(!install_time_.is_null());
 
@@ -437,7 +437,7 @@
   metadata->set_obfuscated_gaia_id(obfuscated_gaia_id_);
   metadata->set_fingerprinter_version(kFingerprinterVersion);
 
-  callback_.Run(std::move(fingerprint));
+  std::move(callback_).Run(std::move(fingerprint));
 }
 
 }  // namespace
@@ -456,14 +456,14 @@
     const std::string& app_locale,
     const std::string& user_agent,
     const base::TimeDelta& timeout,
-    const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback,
+    base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback,
     service_manager::Connector* connector) {
   // Begin loading all of the data that we need to load asynchronously.
   // This class is responsible for freeing its own memory.
   new FingerprintDataLoader(obfuscated_gaia_id, window_bounds, content_bounds,
                             screen_info, version, charset, accept_languages,
                             install_time, app_locale, user_agent, timeout,
-                            callback, connector);
+                            std::move(callback), connector);
 }
 
 }  // namespace internal
@@ -478,7 +478,7 @@
     const base::Time& install_time,
     const std::string& app_locale,
     const std::string& user_agent,
-    const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback,
+    base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback,
     service_manager::Connector* connector) {
   gfx::Rect content_bounds = web_contents->GetContainerBounds();
 
@@ -491,7 +491,8 @@
   internal::GetFingerprintInternal(
       obfuscated_gaia_id, window_bounds, content_bounds, screen_info, version,
       charset, accept_languages, install_time, app_locale, user_agent,
-      base::TimeDelta::FromSeconds(kTimeoutSeconds), callback, connector);
+      base::TimeDelta::FromSeconds(kTimeoutSeconds), std::move(callback),
+      connector);
 }
 
 }  // namespace risk
diff --git a/components/autofill/content/browser/risk/fingerprint.h b/components/autofill/content/browser/risk/fingerprint.h
index 7b45019d..235cca8 100644
--- a/components/autofill/content/browser/risk/fingerprint.h
+++ b/components/autofill/content/browser/risk/fingerprint.h
@@ -59,7 +59,7 @@
     const base::Time& install_time,
     const std::string& app_locale,
     const std::string& user_agent,
-    const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback,
+    const base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback,
     service_manager::Connector* connector);
 
 }  // namespace risk
diff --git a/components/autofill/content/browser/risk/fingerprint_browsertest.cc b/components/autofill/content/browser/risk/fingerprint_browsertest.cc
index 24ddc8af..3c461f2b 100644
--- a/components/autofill/content/browser/risk/fingerprint_browsertest.cc
+++ b/components/autofill/content/browser/risk/fingerprint_browsertest.cc
@@ -46,7 +46,7 @@
     const std::string& app_locale,
     const std::string& user_agent,
     const base::TimeDelta& timeout,
-    const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback,
+    base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback,
     service_manager::Connector* connector);
 
 }  // namespace internal
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index 50d1e2b..a981f74 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -157,7 +157,7 @@
   // Runs |callback| if the |card| should be imported as personal data.
   // |metric_logger| can be used to log user actions.
   virtual void ConfirmSaveCreditCardLocally(const CreditCard& card,
-                                            const base::Closure& callback) = 0;
+                                            base::OnceClosure callback) = 0;
 
   // Runs |callback| if the |card| should be uploaded to Payments. Displays the
   // contents of |legal_message| to the user. Displays a cardholder name
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc
index 7094f20..86b8544 100644
--- a/components/autofill/core/browser/autofill_metrics.cc
+++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -851,6 +851,45 @@
 }
 
 // static
+void AutofillMetrics::LogLocalCardMigrationDialogOfferMetric(
+    LocalCardMigrationDialogOfferMetric metric) {
+  DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS);
+  std::string histogram_name = "Autofill.LocalCardMigrationDialogOffer";
+  base::UmaHistogramEnumeration(histogram_name, metric,
+                                NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS);
+}
+
+// static
+void AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric(
+    const base::TimeDelta& duration,
+    const int selected,
+    const int total,
+    LocalCardMigrationDialogUserInteractionMetric metric) {
+  DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS);
+  base::UmaHistogramEnumeration(
+      "Autofill.LocalCardMigrationDialogUserInteraction", metric,
+      NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS);
+  std::string suffix;
+  switch (metric) {
+    case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED:
+      suffix = "Accepted";
+      break;
+    case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED:
+      suffix = "Denied";
+      break;
+    default:
+      return;
+  }
+  base::UmaHistogramLongTimes("Autofill.LocalCardMigrationDialogActiveDuration",
+                              duration);
+  base::UmaHistogramLongTimes(
+      "Autofill.LocalCardMigrationDialogActiveDuration." + suffix, duration);
+  UMA_HISTOGRAM_PERCENTAGE(
+      "Autofill.LocalCardMigrationDialogUserSelectionPercentage",
+      100 * selected / total);
+}
+
+// static
 void AutofillMetrics::LogLocalCardMigrationPromptMetric(
     LocalCardMigrationOrigin local_card_migration_origin,
     LocalCardMigrationPromptMetric metric) {
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h
index 4ed3244..20eb82a8 100644
--- a/components/autofill/core/browser/autofill_metrics.h
+++ b/components/autofill/core/browser/autofill_metrics.h
@@ -443,6 +443,26 @@
     NUM_LOCAL_CARD_MIGRATION_BUBBLE_USER_INTERACTION_METRICS,
   };
 
+  // Metrics to track events when local card migration dialog is offered.
+  enum LocalCardMigrationDialogOfferMetric {
+    // The dialog is shown to the user.
+    LOCAL_CARD_MIGRATION_DIALOG_SHOWN = 0,
+    // The dialog is not shown due to legal message being invalid.
+    LOCAL_CARD_MIGRATION_DIALOG_NOT_SHOWN_INVALID_LEGAL_MESSAGE = 1,
+    NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS,
+  };
+
+  // Metrics to track user interactions with the dialog.
+  enum LocalCardMigrationDialogUserInteractionMetric {
+    // The user explicitly accepts the offer by clicking the save button.
+    LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED = 0,
+    // The user explicitly denies the offer by clicking the cancel button.
+    LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED = 1,
+    // The user clicks the legal message.
+    LOCAL_CARD_MIGRATION_DIALOG_LEGAL_MESSAGE_CLICKED = 2,
+    NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS,
+  };
+
   // These metrics are logged for each local card migration origin. These are
   // used to derive the conversion rate for each triggering source.
   enum LocalCardMigrationPromptMetric {
@@ -886,6 +906,13 @@
   static void LogLocalCardMigrationBubbleUserInteractionMetric(
       LocalCardMigrationBubbleUserInteractionMetric metric,
       bool is_reshow);
+  static void LogLocalCardMigrationDialogOfferMetric(
+      LocalCardMigrationDialogOfferMetric metric);
+  static void LogLocalCardMigrationDialogUserInteractionMetric(
+      const base::TimeDelta& duration,
+      const int selected,
+      const int total,
+      LocalCardMigrationDialogUserInteractionMetric metric);
   static void LogLocalCardMigrationPromptMetric(
       LocalCardMigrationOrigin local_card_migration_origin,
       LocalCardMigrationPromptMetric metric);
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
index 098480b..0ab21701 100644
--- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
+++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -31,12 +31,12 @@
     const CreditCard& card,
     std::unique_ptr<base::DictionaryValue> legal_message,
     base::OnceCallback<void(const base::string16&)> upload_save_card_callback,
-    base::Closure local_save_card_callback,
+    base::OnceClosure local_save_card_callback,
     PrefService* pref_service)
     : ConfirmInfoBarDelegate(),
       upload_(upload),
       upload_save_card_callback_(std::move(upload_save_card_callback)),
-      local_save_card_callback_(local_save_card_callback),
+      local_save_card_callback_(std::move(local_save_card_callback)),
       pref_service_(pref_service),
       had_user_interaction_(false),
       issuer_icon_id_(CreditCard::IconResourceId(card.network())),
@@ -155,12 +155,10 @@
 }
 
 bool AutofillSaveCardInfoBarDelegateMobile::Accept() {
-  if (upload_) {
+  if (upload_)
     std::move(upload_save_card_callback_).Run(base::string16());
-  } else {
-    local_save_card_callback_.Run();
-    local_save_card_callback_.Reset();
-  }
+  else
+    std::move(local_save_card_callback_).Run();
   LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED);
   return true;
 }
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
index 8295b749..0b61d2df 100644
--- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
+++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
@@ -33,7 +33,7 @@
       const CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
       base::OnceCallback<void(const base::string16&)> upload_save_card_callback,
-      base::Closure local_save_card_callback,
+      base::OnceClosure local_save_card_callback,
       PrefService* pref_service);
 
   ~AutofillSaveCardInfoBarDelegateMobile() override;
@@ -80,7 +80,7 @@
 
   // The callback to save the credit card locally to the device if |upload_| is
   // false and the user accepts the infobar.
-  base::Closure local_save_card_callback_;
+  base::OnceClosure local_save_card_callback_;
 
   // Weak reference to read & write |kAutofillAcceptSaveCreditCardPromptState|,
   PrefService* pref_service_;
diff --git a/components/autofill/core/browser/credit_card_save_manager.cc b/components/autofill/core/browser/credit_card_save_manager.cc
index 78bb7095..f9ffa7df 100644
--- a/components/autofill/core/browser/credit_card_save_manager.cc
+++ b/components/autofill/core/browser/credit_card_save_manager.cc
@@ -88,9 +88,10 @@
   if (observer_for_testing_)
     observer_for_testing_->OnOfferLocalSave();
   client_->ConfirmSaveCreditCardLocally(
-      card, base::Bind(base::IgnoreResult(
-                           &PersonalDataManager::OnAcceptedLocalCreditCardSave),
-                       base::Unretained(personal_data_manager_), card));
+      card,
+      base::BindOnce(base::IgnoreResult(
+                         &PersonalDataManager::OnAcceptedLocalCreditCardSave),
+                     base::Unretained(personal_data_manager_), card));
 }
 
 void CreditCardSaveManager::AttemptToOfferCardUploadSave(
@@ -263,8 +264,8 @@
         base::BindOnce(&CreditCardSaveManager::OnUserDidAcceptUpload,
                        weak_ptr_factory_.GetWeakPtr()));
     client_->LoadRiskData(
-        base::Bind(&CreditCardSaveManager::OnDidGetUploadRiskData,
-                   weak_ptr_factory_.GetWeakPtr()));
+        base::BindOnce(&CreditCardSaveManager::OnDidGetUploadRiskData,
+                       weak_ptr_factory_.GetWeakPtr()));
     upload_decision_metrics_ |= AutofillMetrics::UPLOAD_OFFERED;
     AutofillMetrics::LogUploadOfferedCardOriginMetric(
         uploading_local_card_ ? AutofillMetrics::OFFERING_UPLOAD_OF_LOCAL_CARD
diff --git a/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
index cb73604..308acee 100644
--- a/components/autofill/core/browser/credit_card_save_manager_unittest.cc
+++ b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -92,7 +92,7 @@
   ~MockAutofillClient() override {}
 
   MOCK_METHOD2(ConfirmSaveCreditCardLocally,
-               void(const CreditCard& card, const base::Closure& callback));
+               void(const CreditCard& card, base::OnceClosure callback));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
diff --git a/components/autofill/core/browser/proto/server.proto b/components/autofill/core/browser/proto/server.proto
index 39cb0de..9389048 100644
--- a/components/autofill/core/browser/proto/server.proto
+++ b/components/autofill/core/browser/proto/server.proto
@@ -179,11 +179,16 @@
 
 // This message contains information about the field types in a single form.
 // It is sent by the toolbar to contribute to the field type statistics.
-// Next available id: 34
+// Next available id: 35
 message AutofillUploadContents {
   required string client_version = 1;
   required fixed64 form_signature = 2;
 
+  // The secondary form signature is calculated based on field types instead of
+  // names and is used if the primary one is unstable, i.e. the field names
+  // change on every page load.
+  optional fixed64 secondary_form_signature = 34;
+
   // True if the autofill feature was used to fill this form, false otherwise.
   required bool autofill_used = 3;
 
diff --git a/components/autofill/core/browser/risk_data_loader.h b/components/autofill/core/browser/risk_data_loader.h
index be3def3..2b8468bb 100644
--- a/components/autofill/core/browser/risk_data_loader.h
+++ b/components/autofill/core/browser/risk_data_loader.h
@@ -15,7 +15,7 @@
  public:
   // Gathers risk data and provides it to |callback|.
   virtual void LoadRiskData(
-      const base::Callback<void(const std::string&)>& callback) = 0;
+      base::OnceCallback<void(const std::string&)> callback) = 0;
 
  protected:
   virtual ~RiskDataLoader() {}
diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc
index 6512f11..ff83670 100644
--- a/components/autofill/core/browser/test_autofill_client.cc
+++ b/components/autofill/core/browser/test_autofill_client.cc
@@ -100,8 +100,7 @@
 
 void TestAutofillClient::ConfirmSaveCreditCardLocally(
     const CreditCard& card,
-    const base::Closure& callback) {
-}
+    base::OnceClosure callback) {}
 
 void TestAutofillClient::ConfirmSaveCreditCardToCloud(
     const CreditCard& card,
@@ -118,8 +117,8 @@
 }
 
 void TestAutofillClient::LoadRiskData(
-    const base::Callback<void(const std::string&)>& callback) {
-  callback.Run("some risk data");
+    base::OnceCallback<void(const std::string&)> callback) {
+  std::move(callback).Run("some risk data");
 }
 
 bool TestAutofillClient::HasCreditCardScanFeature() {
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h
index 19c8b3a..fccf5e3 100644
--- a/components/autofill/core/browser/test_autofill_client.h
+++ b/components/autofill/core/browser/test_autofill_client.h
@@ -51,7 +51,7 @@
   void ConfirmSaveAutofillProfile(const AutofillProfile& profile,
                                   base::OnceClosure callback) override;
   void ConfirmSaveCreditCardLocally(const CreditCard& card,
-                                    const base::Closure& callback) override;
+                                    base::OnceClosure callback) override;
   void ConfirmSaveCreditCardToCloud(
       const CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
@@ -60,7 +60,7 @@
   void ConfirmCreditCardFillAssist(const CreditCard& card,
                                    const base::Closure& callback) override;
   void LoadRiskData(
-      const base::Callback<void(const std::string&)>& callback) override;
+      base::OnceCallback<void(const std::string&)> callback) override;
   bool HasCreditCardScanFeature() override;
   void ScanCreditCard(const CreditCardScanCallback& callback) override;
   void ShowAutofillPopup(
diff --git a/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h b/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h
index 75d014d..4696d2606 100644
--- a/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h
+++ b/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h
@@ -31,6 +31,7 @@
       const std::vector<std::string>& selected_cards_guids) = 0;
   virtual void OnCancelButtonClicked() = 0;
   virtual void OnViewCardsButtonClicked() = 0;
+  virtual void OnLegalMessageLinkClicked() = 0;
   virtual void OnDialogClosed() = 0;
 
  private:
diff --git a/components/blacklist/README.md b/components/blacklist/README.md
index f83cc36..d08198a 100644
--- a/components/blacklist/README.md
+++ b/components/blacklist/README.md
@@ -1,36 +1,8 @@
 # Blacklist component #
 
 The goal of the blacklist component is to provide various blacklists that allow
-different policies for features to consume. Below are various types of blacklist
-included within the component.
-
-## Bloom filter blacklist ##
-The Bloom filter blacklist allows blocking specific strings (hosts) based on a
-probabilistic data structure that represents a host as a hashed value.
-Collisions are possible (false positive matches), and the consumer is
-responsible for determining what action to take when a match occurs. The
-implementation uses MurmurHash3 in coordination with wherever (i.e., the server
-that ships it) the bloom filter is generated.
-
-### Expected behavior ###
-The consumer needs to supply a Bloom filter, the number of times to hash the
-string, and the number of bits that the Bloom filter occupies. Calling Contains,
-will inform the consumer whether the string is included in the Bloom filter, and
-these should be considered strings that are not allowed to be used for the
-consumer feature.
-
-### Host filter ###
-HostFilter uses an internal Bloom filter to blacklist host names. It uses the
-Bloom filter to store blacklisted host name suffixes. Given a URL, HostFilter
-will check the URL's host name for any blacklisted host suffixes. The host
-filter will look for matching sub-domains and the full domain in the Bloom
-filter, and will treat any match as a blacklisted host. For instance, a host
-like a.b.c.d.e.chromium.org would match any of the following if they appeared in
-the Bloom filter: a.b.c.d.e.chromium.org, chromium.org, e.chromium.org,
-d.e.chromium.org, c.d.e.chromium.org. Note that b.c.d.e.chromium.org is not
-included, as the default implementation checks the full host, and four other
-sub-domains, looking at the most granular to least granular. Hosts with top
-level domains of more than 6 characters are not supported.
+different policies for features to consume. Currently, the only implemented
+blacklist is the opt out blacklist.
 
 ## Opt out blacklist ##
 The opt out blacklist makes decisions based on user history actions. Each user
diff --git a/components/cdm/browser/cdm_message_filter_android.cc b/components/cdm/browser/cdm_message_filter_android.cc
index d43d766..7a986ed8 100644
--- a/components/cdm/browser/cdm_message_filter_android.cc
+++ b/components/cdm/browser/cdm_message_filter_android.cc
@@ -37,19 +37,19 @@
 };
 
 const CodecInfo<media::VideoCodec> kVideoCodecsToQuery[] = {
-    {media::EME_CODEC_WEBM_VP8, media::kCodecVP8, "video/webm"},
-    {media::EME_CODEC_WEBM_VP9, media::kCodecVP9, "video/webm"},
-    {media::EME_CODEC_COMMON_VP9, media::kCodecVP9, "video/webm"},
-    {media::EME_CODEC_COMMON_VP9, media::kCodecVP9, "video/mp4"},
+    {media::EME_CODEC_VP8, media::kCodecVP8, "video/webm"},
+    {media::EME_CODEC_LEGACY_VP9, media::kCodecVP9, "video/webm"},
+    {media::EME_CODEC_VP9, media::kCodecVP9, "video/webm"},
+    {media::EME_CODEC_VP9, media::kCodecVP9, "video/mp4"},
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-    {media::EME_CODEC_MP4_AVC1, media::kCodecH264, "video/mp4"},
+    {media::EME_CODEC_AVC1, media::kCodecH264, "video/mp4"},
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
-    {media::EME_CODEC_MP4_HEVC, media::kCodecHEVC, "video/mp4"},
+    {media::EME_CODEC_HEVC, media::kCodecHEVC, "video/mp4"},
 #endif
 #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
-    {media::EME_CODEC_MP4_DV_AVC, media::kCodecDolbyVision, "video/mp4"},
+    {media::EME_CODEC_DOLBY_VISION_AVC, media::kCodecDolbyVision, "video/mp4"},
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
-    {media::EME_CODEC_MP4_DV_HEVC, media::kCodecDolbyVision, "video/mp4"},
+    {media::EME_CODEC_DOLBY_VISION_HEVC, media::kCodecDolbyVision, "video/mp4"},
 #endif
 #endif
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -58,12 +58,12 @@
 const CodecInfo<media::AudioCodec> kAudioCodecsToQuery[] = {
     // FLAC is not supported. See https://crbug.com/747050 for details.
     // Vorbis is not supported. See http://crbug.com/710924 for details.
-    {media::EME_CODEC_WEBM_OPUS, media::kCodecOpus, "video/webm"},
+    {media::EME_CODEC_OPUS, media::kCodecOpus, "video/webm"},
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-    {media::EME_CODEC_MP4_AAC, media::kCodecAAC, "video/mp4"},
+    {media::EME_CODEC_AAC, media::kCodecAAC, "video/mp4"},
 #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
-    {media::EME_CODEC_MP4_AC3, media::kCodecAC3, "video/mp4"},
-    {media::EME_CODEC_MP4_EAC3, media::kCodecEAC3, "video/mp4"},
+    {media::EME_CODEC_AC3, media::kCodecAC3, "video/mp4"},
+    {media::EME_CODEC_EAC3, media::kCodecEAC3, "video/mp4"},
 #endif
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 };
diff --git a/components/constrained_window/BUILD.gn b/components/constrained_window/BUILD.gn
index de9893a..33ae96c 100644
--- a/components/constrained_window/BUILD.gn
+++ b/components/constrained_window/BUILD.gn
@@ -14,17 +14,9 @@
     "native_web_contents_modal_dialog_manager_views.h",
     "native_web_contents_modal_dialog_manager_views_mac.h",
     "native_web_contents_modal_dialog_manager_views_mac.mm",
+    "show_modal_dialog_views.cc",
   ]
 
-  if (is_mac) {
-    sources += [ "show_modal_dialog_cocoa.cc" ]
-    if (mac_views_browser) {
-      sources += [ "show_modal_dialog_views.cc" ]
-    }
-  } else {
-    sources += [ "show_modal_dialog_views.cc" ]
-  }
-
   deps = [
     "//components/guest_view/browser",
     "//components/web_modal",
@@ -52,10 +44,6 @@
     "constrained_window_views_unittest.cc",
   ]
 
-  if (is_mac) {
-    sources += [ "test_create_native_web_modal_manager_cocoa.cc" ]
-  }
-
   deps = [
     ":constrained_window",
     "//components/web_modal:test_support",
diff --git a/components/constrained_window/show_modal_dialog_cocoa.cc b/components/constrained_window/show_modal_dialog_cocoa.cc
deleted file mode 100644
index 33b3da1..0000000
--- a/components/constrained_window/show_modal_dialog_cocoa.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-
-#include "components/constrained_window/constrained_window_views.h"
-#include "components/web_modal/single_web_contents_dialog_manager.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/ui_features.h"
-#include "ui/gfx/native_widget_types.h"
-
-// TODO(patricialor): This is a layering violation and should be deleted.
-// Currently it's needed because on Cocoa, the dialog needs to be shown with a
-// SingleWebContentsDialogManagerViewsMac, which depends on things inside
-// chrome/browser/ui/cocoa/constrained_window/* and thus can't be moved out into
-// components/constrained_window/*. Instead, to get this to work, the
-// CreateNativeWebModalManager() method is declared in the web_modal component,
-// but defined outside of that in c/b/u/cocoa/.
-
-namespace constrained_window {
-
-void ShowModalDialogCocoa(gfx::NativeWindow dialog,
-                          content::WebContents* initiator_web_contents) {
-  web_modal::WebContentsModalDialogManager* manager =
-      web_modal::WebContentsModalDialogManager::FromWebContents(
-          initiator_web_contents);
-  std::unique_ptr<web_modal::SingleWebContentsDialogManager> dialog_manager(
-      web_modal::WebContentsModalDialogManager::CreateNativeWebModalManager(
-          dialog, manager));
-  manager->ShowDialogWithManager(dialog, std::move(dialog_manager));
-}
-
-#if !BUILDFLAG(MAC_VIEWS_BROWSER)
-void ShowModalDialog(gfx::NativeWindow dialog,
-                     content::WebContents* initiator_web_contents) {
-  ShowModalDialogCocoa(dialog, initiator_web_contents);
-}
-#endif
-
-}  // namespace constrained_window
diff --git a/components/constrained_window/show_modal_dialog_views.cc b/components/constrained_window/show_modal_dialog_views.cc
index 5f7e2c8..e1f3819 100644
--- a/components/constrained_window/show_modal_dialog_views.cc
+++ b/components/constrained_window/show_modal_dialog_views.cc
@@ -10,17 +10,12 @@
 #include "components/web_modal/single_web_contents_dialog_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/web_contents.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace constrained_window {
 
 void ShowModalDialog(gfx::NativeWindow dialog,
                      content::WebContents* web_contents) {
-#if defined(OS_MACOSX)
-  if (features::IsViewsBrowserCocoa())
-    return ShowModalDialogCocoa(dialog, web_contents);
-#endif
   web_modal::WebContentsModalDialogManager* manager =
       web_modal::WebContentsModalDialogManager::FromWebContents(web_contents);
   DCHECK(manager);
diff --git a/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc b/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc
deleted file mode 100644
index 931dfe45..0000000
--- a/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-
-namespace web_modal {
-
-SingleWebContentsDialogManager*
-WebContentsModalDialogManager::CreateNativeWebModalManager(
-    gfx::NativeWindow dialog,
-    web_modal::SingleWebContentsDialogManagerDelegate* delegate) {
-  return nullptr;
-}
-
-}  // namespace web_modal
diff --git a/components/exo/gaming_seat_unittest.cc b/components/exo/gaming_seat_unittest.cc
index 4411b68..922adcb3 100644
--- a/components/exo/gaming_seat_unittest.cc
+++ b/components/exo/gaming_seat_unittest.cc
@@ -58,7 +58,7 @@
     std::vector<ui::InputDevice> gamepad_devices;
     for (auto& id : gamepad_device_ids) {
       gamepad_devices.push_back(ui::InputDevice(
-          id, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "gamepad"));
+          id, ui::InputDeviceType::INPUT_DEVICE_USB, "gamepad"));
     }
     ui::GamepadProviderOzone::GetInstance()->DispatchGamepadDevicesUpdated(
         gamepad_devices);
diff --git a/components/exo/keyboard_unittest.cc b/components/exo/keyboard_unittest.cc
index 8b216339..13627079 100644
--- a/components/exo/keyboard_unittest.cc
+++ b/components/exo/keyboard_unittest.cc
@@ -306,8 +306,8 @@
       ui::DeviceDataManager::GetInstance();
   ASSERT_TRUE(device_data_manager != nullptr);
   // Make sure that DeviceDataManager has one external keyboard.
-  const std::vector<ui::InputDevice> keyboards{ui::InputDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard")};
+  const std::vector<ui::InputDevice> keyboards{
+      ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")};
   device_data_manager->OnKeyboardDevicesUpdated(keyboards);
 
   ash::TabletModeController* tablet_mode_controller =
diff --git a/components/heap_profiling/test_driver.cc b/components/heap_profiling/test_driver.cc
index a070690..592467a 100644
--- a/components/heap_profiling/test_driver.cc
+++ b/components/heap_profiling/test_driver.cc
@@ -901,7 +901,8 @@
   if (IsRecordingAllAllocations()) {
     if (should_validate_dumps) {
       result = ValidateDump(heaps_v2, kMallocAllocSize * kMallocAllocCount,
-                            kMallocAllocCount, "malloc", kMallocTypeTag,
+                            kMallocAllocCount, "malloc",
+                            HasPseudoFrames() ? kMallocTypeTag : nullptr,
                             HasPseudoFrames() ? kMallocEvent : "", thread_name);
       if (!result) {
         LOG(ERROR) << "Failed to validate malloc fixed allocations";
diff --git a/components/services/heap_profiling/public/cpp/allocator_shim.cc b/components/services/heap_profiling/public/cpp/allocator_shim.cc
index 5841f51..ef76601 100644
--- a/components/services/heap_profiling/public/cpp/allocator_shim.cc
+++ b/components/services/heap_profiling/public/cpp/allocator_shim.cc
@@ -735,8 +735,7 @@
       break;
     case mojom::StackMode::NATIVE_WITH_THREAD_NAMES:
     case mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES:
-      // This would track task contexts only.
-      AllocationContextTracker::SetCaptureMode(CaptureMode::NATIVE_STACK);
+      AllocationContextTracker::SetCaptureMode(CaptureMode::DISABLED);
       break;
   }
 
@@ -792,8 +791,7 @@
     *context = allocation_context.type_name;
 }
 
-void SerializeFramesFromBacktrace(FrameSerializer* serializer,
-                                  const char** context) {
+void SerializeFramesFromBacktrace(FrameSerializer* serializer) {
   // Skip 3 top frames related to the profiler itself, e.g.:
   //   base::debug::StackTrace::StackTrace
   //   heap_profiling::RecordAndSendAlloc
@@ -826,13 +824,6 @@
     const char* thread_name = GetOrSetThreadName();
     serializer->AddCString(thread_name);
   }
-
-  if (!*context) {
-    const auto* tracker =
-        AllocationContextTracker::GetInstanceForCurrentThread();
-    if (tracker)
-      *context = tracker->TaskContext();
-  }
 }
 
 void AllocatorShimLogAlloc(AllocatorType type,
@@ -904,7 +895,7 @@
       capture_mode == CaptureMode::MIXED_STACK) {
     SerializeFramesFromAllocationContext(&serializer, &context);
   } else {
-    SerializeFramesFromBacktrace(&serializer, &context);
+    SerializeFramesFromBacktrace(&serializer);
   }
 
   size_t context_len = context ? strnlen(context, kMaxContextLen) : 0;
diff --git a/components/web_modal/web_contents_modal_dialog_manager.cc b/components/web_modal/web_contents_modal_dialog_manager.cc
index 3ce19d1..4669249e 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.cc
+++ b/components/web_modal/web_contents_modal_dialog_manager.cc
@@ -106,6 +106,10 @@
 // then set the block state. Advantage: could restrict some of the
 // WCMDM delegate methods, then, and pass them behind the scenes.
 void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked) {
+  if (blocked == web_contents_is_blocked_)
+    return;
+  web_contents_is_blocked_ = blocked;
+
   WebContents* contents = web_contents();
   if (!contents) {
     // The WebContents has already disconnected.
@@ -124,6 +128,7 @@
   while (!child_dialogs_.empty()) {
     child_dialogs_.front().manager->Close();
   }
+  BlockWebContentsInteraction(false);
 
   closing_all_dialogs_ = false;
 }
diff --git a/components/web_modal/web_contents_modal_dialog_manager.h b/components/web_modal/web_contents_modal_dialog_manager.h
index 5a646b8..844003c 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.h
+++ b/components/web_modal/web_contents_modal_dialog_manager.h
@@ -30,14 +30,6 @@
   WebContentsModalDialogManagerDelegate* delegate() const { return delegate_; }
   void SetDelegate(WebContentsModalDialogManagerDelegate* d);
 
-#if defined(OS_MACOSX)
-  // Note: This method is not defined inside components/web_modal/ as its
-  // definition (needed for Cocoa builds) depends on chrome/browser/ui/cocoa/.
-  static SingleWebContentsDialogManager* CreateNativeWebModalManager(
-      gfx::NativeWindow dialog,
-      SingleWebContentsDialogManagerDelegate* native_delegate);
-#endif
-
   // Allow clients to supply their own native dialog manager. Suitable for
   // bubble clients.
   void ShowDialogWithManager(
@@ -117,6 +109,9 @@
   // True while closing the dialogs on WebContents close.
   bool closing_all_dialogs_;
 
+  // True if the WebContents is blocked.
+  bool web_contents_is_blocked_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManager);
 };
 
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 3a5dd45c..b5d3af0 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -290,6 +290,12 @@
 
 // http:/crbug.com/889013
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+                       DISABLED_AccessibilityEventsCaretHide) {
+  RunEventTest(FILE_PATH_LITERAL("caret-hide.html"));
+}
+
+// http:/crbug.com/889013
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
                        DISABLED_AccessibilityEventsCaretMove) {
   RunEventTest(FILE_PATH_LITERAL("caret-move.html"));
 }
diff --git a/content/browser/fileapi/README.md b/content/browser/fileapi/README.md
new file mode 100644
index 0000000..4707361
--- /dev/null
+++ b/content/browser/fileapi/README.md
@@ -0,0 +1,23 @@
+# FileSystem API
+
+This directory contains part of the browser side implementation of various
+filesystem related APIs.
+
+## Related directories
+
+[`//storage/browser/fileapi/`](../../../storage/browser/fileapi) contains the
+rest of the browser side implementation, while
+[`blink/renderer/modules/filesystem`](../../../third_party/blink/renderer/modules/filesystem)
+contains the renderer side implementation and
+[`blink/public/mojom/filesystem`](../../../third_party/blink/public/mojom/filesystem)
+contains the mojom interfaces for these APIs.
+
+## In this directory
+
+[`FileSystemManagerImpl`](file_system_manager_impl.h) is the main entry point
+for calls from the renderer, it mostly redirects incoming mojom calls to a
+`storage::FileSystemContext` instance.
+
+[`FileSystemChooser`](file_system_chooser.h) uses ui::SelectFileDialog to show
+a file or directory picker, and is responsible for granting a process the right
+permissions for actually accessing the files that were selected.
diff --git a/content/browser/fileapi/file_system_chooser.cc b/content/browser/fileapi/file_system_chooser.cc
index 0c8ae67..9b62430 100644
--- a/content/browser/fileapi/file_system_chooser.cc
+++ b/content/browser/fileapi/file_system_chooser.cc
@@ -5,6 +5,8 @@
 #include "content/browser/fileapi/file_system_chooser.h"
 
 #include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/task/post_task.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/content_browser_client.h"
@@ -19,20 +21,37 @@
 void FileSystemChooser::CreateAndShow(
     int render_process_id,
     int frame_id,
+    blink::mojom::ChooseFileSystemEntryType type,
     ResultCallback callback,
     scoped_refptr<base::TaskRunner> callback_runner) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   RenderFrameHost* rfh = RenderFrameHost::FromID(render_process_id, frame_id);
   WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
-  auto* listener = new FileSystemChooser(render_process_id, std::move(callback),
-                                         std::move(callback_runner));
+  auto* listener = new FileSystemChooser(
+      render_process_id, type, std::move(callback), std::move(callback_runner));
   listener->dialog_ = ui::SelectFileDialog::Create(
       listener,
       GetContentClient()->browser()->CreateSelectFilePolicy(web_contents));
   // TODO(https://crbug.com/878581): Better/more specific options to pass to
   //     SelectFile.
+  ui::SelectFileDialog::Type dialog_type = ui::SelectFileDialog::SELECT_NONE;
+  switch (type) {
+    case blink::mojom::ChooseFileSystemEntryType::kOpenFile:
+      dialog_type = ui::SelectFileDialog::SELECT_OPEN_FILE;
+      break;
+    case blink::mojom::ChooseFileSystemEntryType::kOpenMultipleFiles:
+      dialog_type = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE;
+      break;
+    case blink::mojom::ChooseFileSystemEntryType::kSaveFile:
+      dialog_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
+      break;
+    case blink::mojom::ChooseFileSystemEntryType::kOpenDirectory:
+      dialog_type = ui::SelectFileDialog::SELECT_FOLDER;
+      break;
+  }
+  DCHECK_NE(dialog_type, ui::SelectFileDialog::SELECT_NONE);
   listener->dialog_->SelectFile(
-      ui::SelectFileDialog::SELECT_OPEN_FILE, /*title=*/base::string16(),
+      dialog_type, /*title=*/base::string16(),
       /*default_path=*/base::FilePath(), /*file_types=*/nullptr,
       /*file_type_index=*/0,
       /*default_extension=*/base::FilePath::StringType(),
@@ -42,11 +61,13 @@
 
 FileSystemChooser::FileSystemChooser(
     int render_process_id,
+    blink::mojom::ChooseFileSystemEntryType type,
     ResultCallback callback,
     scoped_refptr<base::TaskRunner> callback_runner)
     : render_process_id_(render_process_id),
       callback_(std::move(callback)),
-      callback_runner_(std::move(callback_runner)) {}
+      callback_runner_(std::move(callback_runner)),
+      type_(type) {}
 
 FileSystemChooser::~FileSystemChooser() {
   if (dialog_)
@@ -73,21 +94,72 @@
   for (const auto& path : files) {
     auto entry = blink::mojom::FileSystemEntry::New();
     entry->file_system_id = isolated_context->RegisterFileSystemForPath(
-        storage::kFileSystemTypeNativeForPlatformApp, std::string(), path,
+        storage::kFileSystemTypeNativeLocal, std::string(), path,
         &entry->base_name);
 
-    // TODO(https://crbug.com/878585): Determine if we always want to grant
-    //     write permission.
     security_policy->GrantReadFileSystem(render_process_id_,
                                          entry->file_system_id);
-    security_policy->GrantWriteFileSystem(render_process_id_,
-                                          entry->file_system_id);
-    security_policy->GrantDeleteFromFileSystem(render_process_id_,
-                                               entry->file_system_id);
+    // TODO(https://crbug.com/878585): Don't grant write/modify permissions
+    // unless a website already has the appropriate permissions.
+    if (type_ == blink::mojom::ChooseFileSystemEntryType::kOpenDirectory) {
+      // Only grant Create permissions if we're opening a directory. And
+      // just granting Create permissions on top of Write and Delete does not
+      // actually grant the same permissions as calling this method.
+      security_policy->GrantCreateReadWriteFileSystem(render_process_id_,
+                                                      entry->file_system_id);
+    } else {
+      security_policy->GrantWriteFileSystem(render_process_id_,
+                                            entry->file_system_id);
+      security_policy->GrantDeleteFromFileSystem(render_process_id_,
+                                                 entry->file_system_id);
+    }
 
     result.push_back(std::move(entry));
   }
 
+  if (type_ == blink::mojom::ChooseFileSystemEntryType::kSaveFile) {
+    // Create files if they don't yet exist.
+    // TODO(mek): If we change FileSystemFileHandle to be able to represent a
+    // file that doesn't exist on disk, we should be able to get rid of this
+    // step and make the whole API slightly more robust.
+    base::PostTaskWithTraits(
+        FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
+        base::BindOnce(
+            [](const std::vector<base::FilePath>& files,
+               std::vector<blink::mojom::FileSystemEntryPtr> result,
+               scoped_refptr<base::TaskRunner> callback_runner,
+               ResultCallback callback) {
+              for (const auto& path : files) {
+                // Checking if a path exists, and then creating it if it doesn't
+                // is of course racy, but external applications could just as
+                // well be deleting the entire directory, or similar problematic
+                // cases, so no matter what we do there are always going to be
+                // race conditions and websites will just have to deal with any
+                // method being able to fail in unexpected ways.
+                if (base::PathExists(path))
+                  continue;
+                int creation_flags =
+                    base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ;
+                base::File file(path, creation_flags);
+
+                if (!file.IsValid()) {
+                  callback_runner->PostTask(
+                      FROM_HERE,
+                      base::BindOnce(
+                          std::move(callback), base::File::FILE_ERROR_FAILED,
+                          std::vector<blink::mojom::FileSystemEntryPtr>()));
+                  return;
+                }
+              }
+              callback_runner->PostTask(
+                  FROM_HERE,
+                  base::BindOnce(std::move(callback), base::File::FILE_OK,
+                                 std::move(result)));
+            },
+            files, std::move(result), callback_runner_, std::move(callback_)));
+    delete this;
+    return;
+  }
   callback_runner_->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback_), base::File::FILE_OK,
                                 std::move(result)));
diff --git a/content/browser/fileapi/file_system_chooser.h b/content/browser/fileapi/file_system_chooser.h
index 2283a6725..d2f24d8 100644
--- a/content/browser/fileapi/file_system_chooser.h
+++ b/content/browser/fileapi/file_system_chooser.h
@@ -25,10 +25,12 @@
 
   static void CreateAndShow(int render_process_id,
                             int frame_id,
+                            blink::mojom::ChooseFileSystemEntryType type,
                             ResultCallback callback,
                             scoped_refptr<base::TaskRunner> callback_runner);
 
   FileSystemChooser(int render_process_id,
+                    blink::mojom::ChooseFileSystemEntryType type,
                     ResultCallback callback,
                     scoped_refptr<base::TaskRunner> callback_runner);
 
@@ -46,6 +48,7 @@
   int render_process_id_;
   ResultCallback callback_;
   scoped_refptr<base::TaskRunner> callback_runner_;
+  blink::mojom::ChooseFileSystemEntryType type_;
 
   scoped_refptr<ui::SelectFileDialog> dialog_;
 };
diff --git a/content/browser/fileapi/file_system_chooser_browsertest.cc b/content/browser/fileapi/file_system_chooser_browsertest.cc
new file mode 100644
index 0000000..97cfcd3
--- /dev/null
+++ b/content/browser/fileapi/file_system_chooser_browsertest.cc
@@ -0,0 +1,267 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "third_party/blink/public/common/features.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+#include "ui/shell_dialogs/select_file_dialog_factory.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+
+namespace content {
+
+namespace {
+
+struct SelectFileDialogParams {
+  ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_NONE;
+};
+
+// A fake ui::SelectFileDialog, which will cancel the file selection instead of
+// selecting a file.
+class CancellingSelectFileDialog : public ui::SelectFileDialog {
+ public:
+  CancellingSelectFileDialog(Listener* listener,
+                             std::unique_ptr<ui::SelectFilePolicy> policy)
+      : ui::SelectFileDialog(listener, std::move(policy)) {}
+
+ protected:
+  void SelectFileImpl(Type type,
+                      const base::string16& title,
+                      const base::FilePath& default_path,
+                      const FileTypeInfo* file_types,
+                      int file_type_index,
+                      const base::FilePath::StringType& default_extension,
+                      gfx::NativeWindow owning_window,
+                      void* params) override {
+    listener_->FileSelectionCanceled(params);
+  }
+
+  bool IsRunning(gfx::NativeWindow owning_window) const override {
+    return false;
+  }
+  void ListenerDestroyed() override {}
+  bool HasMultipleFileTypeChoicesImpl() override { return false; }
+
+ private:
+  ~CancellingSelectFileDialog() override = default;
+};
+
+class CancellingSelectFileDialogFactory : public ui::SelectFileDialogFactory {
+ public:
+  CancellingSelectFileDialogFactory() {}
+
+  ui::SelectFileDialog* Create(
+      ui::SelectFileDialog::Listener* listener,
+      std::unique_ptr<ui::SelectFilePolicy> policy) override {
+    return new CancellingSelectFileDialog(listener, std::move(policy));
+  }
+};
+
+// A fake ui::SelectFileDialog, which will select one or more pre-determined
+// files.
+class FakeSelectFileDialog : public ui::SelectFileDialog {
+ public:
+  FakeSelectFileDialog(std::vector<base::FilePath> result,
+                       SelectFileDialogParams* out_params,
+                       Listener* listener,
+                       std::unique_ptr<ui::SelectFilePolicy> policy)
+      : ui::SelectFileDialog(listener, std::move(policy)),
+        result_(std::move(result)),
+        out_params_(out_params) {}
+
+ protected:
+  void SelectFileImpl(Type type,
+                      const base::string16& title,
+                      const base::FilePath& default_path,
+                      const FileTypeInfo* file_types,
+                      int file_type_index,
+                      const base::FilePath::StringType& default_extension,
+                      gfx::NativeWindow owning_window,
+                      void* params) override {
+    if (out_params_) {
+      out_params_->type = type;
+    }
+    if (result_.size() == 1)
+      listener_->FileSelected(result_[0], 0, params);
+    else
+      listener_->MultiFilesSelected(result_, params);
+  }
+
+  bool IsRunning(gfx::NativeWindow owning_window) const override {
+    return false;
+  }
+  void ListenerDestroyed() override {}
+  bool HasMultipleFileTypeChoicesImpl() override { return false; }
+
+ private:
+  ~FakeSelectFileDialog() override = default;
+  std::vector<base::FilePath> result_;
+  SelectFileDialogParams* out_params_;
+};
+
+class FakeSelectFileDialogFactory : public ui::SelectFileDialogFactory {
+ public:
+  explicit FakeSelectFileDialogFactory(std::vector<base::FilePath> result,
+                                       SelectFileDialogParams* out_params)
+      : result_(std::move(result)), out_params_(out_params) {}
+
+  ui::SelectFileDialog* Create(
+      ui::SelectFileDialog::Listener* listener,
+      std::unique_ptr<ui::SelectFilePolicy> policy) override {
+    return new FakeSelectFileDialog(result_, out_params_, listener,
+                                    std::move(policy));
+  }
+
+ private:
+  std::vector<base::FilePath> result_;
+  SelectFileDialogParams* out_params_;
+};
+
+}  // namespace
+
+// This browser test implements end-to-end tests for the chooseFileSystemEntry
+// API.
+class FileSystemChooserBrowserTest : public ContentBrowserTest {
+ public:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    scoped_feature_list_.InitAndEnableFeature(
+        blink::features::kWritableFilesAPI);
+    ContentBrowserTest::SetUp();
+  }
+
+  void TearDown() override {
+    ContentBrowserTest::TearDown();
+    ASSERT_TRUE(temp_dir_.Delete());
+    ui::SelectFileDialog::SetFactory(nullptr);
+  }
+
+  base::FilePath CreateTestFile(const std::string& contents) {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    base::FilePath result;
+    EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &result));
+    EXPECT_EQ(int{contents.size()},
+              base::WriteFile(result, contents.data(), contents.size()));
+    return result;
+  }
+
+  base::FilePath CreateTestDir() {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    base::FilePath result;
+    EXPECT_TRUE(base::CreateTemporaryDirInDir(
+        temp_dir_.GetPath(), FILE_PATH_LITERAL("test"), &result));
+    return result;
+  }
+
+ protected:
+  const std::string kBlankHtml = "<!DOCTYPE html><html><body>";
+  const GURL kTestUrl = GURL("https://foobar.com/");
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  base::ScopedTempDir temp_dir_;
+};
+
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, CancelDialog) {
+  ui::SelectFileDialog::SetFactory(new CancellingSelectFileDialogFactory);
+  LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl);
+  auto result = EvalJs(shell(), "self.chooseFileSystemEntries()");
+  EXPECT_TRUE(result.error.find("AbortError") != std::string::npos)
+      << result.error;
+}
+
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenFile) {
+  const std::string file_contents = "hello world!";
+  const base::FilePath test_file = CreateTestFile(file_contents);
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(
+      new FakeSelectFileDialogFactory({test_file}, &dialog_params));
+  LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl);
+  EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let e = await self.chooseFileSystemEntries();"
+                   "  self.selected_entry = e;"
+                   "  return e.name; })()"));
+  EXPECT_EQ(ui::SelectFileDialog::SELECT_OPEN_FILE, dialog_params.type);
+  EXPECT_EQ(
+      file_contents,
+      EvalJs(shell(),
+             "(async () => { const file = await self.selected_entry.getFile(); "
+             "return await new Response(file).text(); })()"));
+}
+
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, SaveFile) {
+  const std::string file_contents = "file contents to write";
+  const base::FilePath test_file = CreateTestFile("");
+  {
+    // Delete file, since SaveFile should be able to deal with non-existing
+    // files.
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    ASSERT_TRUE(base::DeleteFile(test_file, false));
+  }
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(
+      new FakeSelectFileDialogFactory({test_file}, &dialog_params));
+  LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl);
+  EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let e = await self.chooseFileSystemEntries("
+                   "      {type: 'saveFile'});"
+                   "  self.entry = e;"
+                   "  return e.name; })()"));
+  EXPECT_EQ(ui::SelectFileDialog::SELECT_SAVEAS_FILE, dialog_params.type);
+  EXPECT_EQ(int{file_contents.size()},
+            EvalJs(shell(),
+                   JsReplace("(async () => {"
+                             "  const w = await self.entry.createWriter();"
+                             "  await w.write(0, new Blob([$1]));"
+                             "  return (await self.entry.getFile()).size; })()",
+                             file_contents)));
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    std::string read_contents;
+    EXPECT_TRUE(base::ReadFileToString(test_file, &read_contents));
+    EXPECT_EQ(file_contents, read_contents);
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenMultipleFiles) {
+  const base::FilePath test_file1 = CreateTestFile("file1");
+  const base::FilePath test_file2 = CreateTestFile("file2");
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(new FakeSelectFileDialogFactory(
+      {test_file1, test_file2}, &dialog_params));
+  LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl);
+  EXPECT_EQ(ListValueOf(test_file1.BaseName().AsUTF8Unsafe(),
+                        test_file2.BaseName().AsUTF8Unsafe()),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let e = await self.chooseFileSystemEntries("
+                   "      {multiple: true});"
+                   "  return e.map(x => x.name); })()"));
+  EXPECT_EQ(ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE, dialog_params.type);
+}
+
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenDirectory) {
+  base::FilePath test_dir = CreateTestDir();
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(
+      new FakeSelectFileDialogFactory({test_dir}, &dialog_params));
+  LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl);
+  EXPECT_EQ(test_dir.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let e = await self.chooseFileSystemEntries("
+                   "      {type: 'openDirectory'});"
+                   "  self.selected_entry = e;"
+                   "  return e.name; })()"));
+  EXPECT_EQ(ui::SelectFileDialog::SELECT_FOLDER, dialog_params.type);
+}
+
+}  // namespace content
\ No newline at end of file
diff --git a/content/browser/fileapi/file_system_manager_impl.cc b/content/browser/fileapi/file_system_manager_impl.cc
index 29f1d2d..91d5202 100644
--- a/content/browser/fileapi/file_system_manager_impl.cc
+++ b/content/browser/fileapi/file_system_manager_impl.cc
@@ -592,7 +592,9 @@
   std::move(callback).Run(base::File::FILE_OK, std::move(writer));
 }
 
-void FileSystemManagerImpl::ChooseEntry(ChooseEntryCallback callback) {
+void FileSystemManagerImpl::ChooseEntry(
+    blink::mojom::ChooseFileSystemEntryType type,
+    ChooseEntryCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (!base::FeatureList::IsEnabled(blink::features::kWritableFilesAPI)) {
     bindings_.ReportBadMessage("FSMI_WRITABLE_FILES_DISABLED");
@@ -602,7 +604,7 @@
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::UI},
       base::BindOnce(
-          &FileSystemChooser::CreateAndShow, process_id_, frame_id_,
+          &FileSystemChooser::CreateAndShow, process_id_, frame_id_, type,
           std::move(callback),
           base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO})));
 }
diff --git a/content/browser/fileapi/file_system_manager_impl.h b/content/browser/fileapi/file_system_manager_impl.h
index e92c5e46..4fe924e 100644
--- a/content/browser/fileapi/file_system_manager_impl.h
+++ b/content/browser/fileapi/file_system_manager_impl.h
@@ -125,7 +125,8 @@
                        GetPlatformPathCallback callback) override;
   void CreateWriter(const GURL& file_path,
                     CreateWriterCallback callback) override;
-  void ChooseEntry(ChooseEntryCallback callback) override;
+  void ChooseEntry(blink::mojom::ChooseFileSystemEntryType type,
+                   ChooseEntryCallback callback) override;
 
  private:
   class FileSystemCancellableOperationImpl;
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 020f0d12..34a7d12 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -130,6 +130,7 @@
   void DidPresentCompositorFrame(
       uint32_t frame_token,
       const gfx::PresentationFeedback& feedback) override {}
+  void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override {}
 
   // LayerTreeHostSingleThreadClient implementation.
   void DidSubmitCompositorFrame() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 286904c..1cad17bc 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -392,8 +392,6 @@
   bool Animate(base::TimeTicks frame_time);
   void RequestDisallowInterceptTouchEvent();
 
-  bool SyncCompositorOnMessageReceived(const IPC::Message& message);
-
   void ComputeEventLatencyOSTouchHistograms(const ui::MotionEvent& event);
 
   void CreateOverscrollControllerIfPossible();
diff --git a/content/browser/scheduler/browser_task_executor.cc b/content/browser/scheduler/browser_task_executor.cc
index 0b7d514..e966424 100644
--- a/content/browser/scheduler/browser_task_executor.cc
+++ b/content/browser/scheduler/browser_task_executor.cc
@@ -17,8 +17,8 @@
 // BrowserThread. BrowserThreadTaskRunners are vended by
 // base::Create*TaskRunnerWithTraits({BrowserThread::UI/IO}).
 //
-// TODO(gab): Consider replacing this with direct calls to task runners
-// |BrowserThreadImpl::GetTaskRunnerForThread()| -- only works if none are
+// TODO(gab): Consider replacing this with direct calls to task runners obtained
+// via |BrowserThreadImpl::GetTaskRunnerForThread()| -- only works if none are
 // requested before starting the threads.
 class BrowserThreadTaskRunner : public base::SingleThreadTaskRunner {
  public:
diff --git a/content/renderer/gpu/layer_tree_view.cc b/content/renderer/gpu/layer_tree_view.cc
index b471c15..1690631 100644
--- a/content/renderer/gpu/layer_tree_view.cc
+++ b/content/renderer/gpu/layer_tree_view.cc
@@ -673,6 +673,10 @@
   }
 }
 
+void LayerTreeView::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) {
+  delegate_->RecordEndOfFrameMetrics(frame_begin_time);
+}
+
 void LayerTreeView::RequestScheduleAnimation() {
   delegate_->RequestScheduleAnimation();
 }
diff --git a/content/renderer/gpu/layer_tree_view.h b/content/renderer/gpu/layer_tree_view.h
index 644d239..820d1a2 100644
--- a/content/renderer/gpu/layer_tree_view.h
+++ b/content/renderer/gpu/layer_tree_view.h
@@ -197,6 +197,7 @@
   void DidPresentCompositorFrame(
       uint32_t frame_token,
       const gfx::PresentationFeedback& feedback) override;
+  void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override;
 
   // cc::LayerTreeHostSingleThreadClient implementation.
   void RequestScheduleAnimation() override;
diff --git a/content/renderer/gpu/layer_tree_view_delegate.h b/content/renderer/gpu/layer_tree_view_delegate.h
index 0f13c9d..d28c056 100644
--- a/content/renderer/gpu/layer_tree_view_delegate.h
+++ b/content/renderer/gpu/layer_tree_view_delegate.h
@@ -69,6 +69,12 @@
   // will be displayed.
   virtual void DidReceiveCompositorFrameAck() = 0;
 
+  // Requests that a UMA and UKM metric be recorded for the total frame time.
+  // Call this as soon as the total frame time becomes known for a given frame.
+  // For example, ProxyMain::BeginMainFrame calls it immediately before aborting
+  // or committing a frame (at the same time Tracing measurements are taken).
+  virtual void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) = 0;
+
   // Indicates whether the LayerTreeView is about to close.
   virtual bool IsClosing() const = 0;
 
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 77f9bd6..21f16fa 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1099,6 +1099,13 @@
   }
 }
 
+void RenderWidget::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) {
+  if (!GetWebWidget())
+    return;
+
+  GetWebWidget()->RecordEndOfFrameMetrics(frame_begin_time);
+}
+
 void RenderWidget::WillBeginCompositorFrame() {
   TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame");
 
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 5a3c9a8..7bb9097 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -272,6 +272,7 @@
   void DidCommitCompositorFrame() override;
   void DidCompletePageScaleAnimation() override;
   void DidReceiveCompositorFrameAck() override;
+  void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override;
   bool IsClosing() const override;
   void RequestScheduleAnimation() override;
   void UpdateVisualState() override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index f99c8790..c003c79 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -757,6 +757,7 @@
     # These tests have incorrect threading (https://crbug.com/860547).
     #"../browser/fileapi/file_system_url_loader_factory_browsertest.cc",
 
+    "../browser/fileapi/file_system_chooser_browsertest.cc",
     "../browser/fileapi/fileapi_browsertest.cc",
     "../browser/find_request_manager_browsertest.cc",
     "../browser/font_unique_name_lookup/font_unique_name_browsertest.cc",
diff --git a/content/test/data/accessibility/event/caret-hide-expected-win.txt b/content/test/data/accessibility/event/caret-hide-expected-win.txt
new file mode 100644
index 0000000..632f1d8b
--- /dev/null
+++ b/content/test/data/accessibility/event/caret-hide-expected-win.txt
@@ -0,0 +1,7 @@
+EVENT_OBJECT_FOCUS on <input#btn> role=ROLE_SYSTEM_PUSHBUTTON name="Submit" FOCUSED,FOCUSABLE
+EVENT_OBJECT_FOCUS on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
+EVENT_OBJECT_HIDE role=ROLE_SYSTEM_CARET INVISIBLE window_class=Chrome_WidgetWin_0
+EVENT_OBJECT_LOCATIONCHANGE role=ROLE_SYSTEM_CARET  window_class=Chrome_WidgetWin_0
+EVENT_OBJECT_SHOW role=ROLE_SYSTEM_CARET  window_class=Chrome_WidgetWin_0
+EVENT_OBJECT_VALUECHANGE on <input#in1> role=ROLE_SYSTEM_TEXT value="end" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
+IA2_EVENT_TEXT_CARET_MOVED on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/caret-hide.html b/content/test/data/accessibility/event/caret-hide.html
new file mode 100644
index 0000000..0845f54b
--- /dev/null
+++ b/content/test/data/accessibility/event/caret-hide.html
@@ -0,0 +1,25 @@
+<!--
+@RUN-UNTIL-EVENT:EVENT_OBJECT_VALUECHANGE
+@WIN-DENY:IA2_EVENT_TEXT_INSERTED*
+@WIN-DENY:IA2_EVENT_TEXT_REMOVED*
+-->
+<!DOCTYPE html>
+<html>
+<body>
+<input id="in1" type="text" value="abcde">
+<input id="btn" type="submit">
+<script>
+  function go() {
+    const inp = document.getElementById('in1');
+    inp.focus();
+    inp.setSelectionRange(0, 0);
+    setTimeout(() => {
+      document.getElementById('btn').focus();
+      setTimeout(() => {
+        inp.value = 'end'; // Trigger test end.
+      }, 50);
+    }, 50);
+}
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/content/test/stub_layer_tree_view_delegate.h b/content/test/stub_layer_tree_view_delegate.h
index 65dc3b5..83bba53 100644
--- a/content/test/stub_layer_tree_view_delegate.h
+++ b/content/test/stub_layer_tree_view_delegate.h
@@ -20,6 +20,7 @@
   void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel,
                                          bool has_scrolled_by_touch) override {}
   void BeginMainFrame(base::TimeTicks frame_time) override {}
+  void RecordEndOfFrameMetrics(base::TimeTicks) override {}
   void RequestNewLayerTreeFrameSink(
       LayerTreeFrameSinkCallback callback) override;
   void DidCommitAndDrawCompositorFrame() override {}
diff --git a/device/gamepad/raw_input_gamepad_device_win.cc b/device/gamepad/raw_input_gamepad_device_win.cc
index d434c8d7..c124bfe 100644
--- a/device/gamepad/raw_input_gamepad_device_win.cc
+++ b/device/gamepad/raw_input_gamepad_device_win.cc
@@ -31,9 +31,24 @@
 const uint32_t kHomeUsageNumber = 0x0223;
 const uint32_t kBackUsageNumber = 0x0224;
 
-// Blacklisted vendor IDs.
+// Vendor IDs.
 const uint32_t kVendorOculus = 0x2833;
 const uint32_t kVendorBlue = 0xb58e;
+const uint32_t kVendorMicrosoft = 0x045e;
+
+// Product IDs.
+const uint32_t kProductSurfacePro2017Keyboard = 0x0922;
+
+struct VendorProductPair {
+  const uint16_t vendor;
+  const uint16_t product;
+} kFilteredDevices[] = {
+    // The Surface Pro 2017's detachable keyboard is a composite device with
+    // several HID sub-devices. Filter out the keyboard's device ID to avoid
+    // treating these sub-devices as gamepads.
+    {kVendorMicrosoft, kProductSurfacePro2017Keyboard},
+};
+const size_t kFilteredDevicesLen = base::size(kFilteredDevices);
 
 // The fetcher will collect all HID usages from the Button usage page and any
 // additional usages listed below.
@@ -216,10 +231,26 @@
   if (vendor_id_ == kVendorOculus || vendor_id_ == kVendorBlue)
     return false;
 
+  for (size_t i = 0; i < kFilteredDevicesLen; ++i) {
+    const auto& filter = kFilteredDevices[i];
+    if (vendor_id_ == filter.vendor && product_id_ == filter.product)
+      return false;
+  }
+
   // Fetch the device's |name_| (RIDI_DEVICENAME).
   if (!QueryDeviceName())
     return false;
 
+  // From the name we can guess at the bus type. PCI HID devices have "VEN" and
+  // "DEV" instead of "VID" and "PID". PCI HID devices are typically not
+  // gamepads and are ignored.
+  // Example PCI device name: \\?\HID#VEN_1234&DEV_ABCD
+  // TODO(crbug/881539): Potentially allow PCI HID devices to be enumerated, but
+  // prefer known gamepads when there is contention.
+  std::wstring pci_prefix = L"\\\\?\\HID#VEN_";
+  if (!name_.compare(0, pci_prefix.size(), pci_prefix))
+    return false;
+
   // Fetch the human-friendly |product_string_|, if available.
   if (!QueryProductString())
     product_string_ = L"Unknown Gamepad";
diff --git a/device/usb/usb_device_handle_usbfs.cc b/device/usb/usb_device_handle_usbfs.cc
index afbd070..1ebe96b 100644
--- a/device/usb/usb_device_handle_usbfs.cc
+++ b/device/usb/usb_device_handle_usbfs.cc
@@ -19,7 +19,7 @@
 #include "base/posix/eintr_wrapper.h"
 #include "base/sequence_checker.h"
 #include "base/stl_util.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/device_event_log/device_event_log.h"
 #include "device/usb/usb_device_linux.h"
@@ -211,7 +211,6 @@
 }
 
 void UsbDeviceHandleUsbfs::FileThreadHelper::Start() {
-  base::AssertBlockingAllowed();
   sequence_checker_.DetachFromSequence();
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
@@ -234,6 +233,7 @@
     ResultCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   int rc = HANDLE_EINTR(
       ioctl(fd_.get(), USBDEVFS_SETCONFIGURATION, &configuration_value));
   if (rc)
@@ -249,6 +249,7 @@
     ResultCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   int rc = HANDLE_EINTR(
       ioctl(fd_.get(), USBDEVFS_RELEASEINTERFACE, &interface_number));
   if (rc) {
@@ -272,6 +273,8 @@
   usbdevfs_setinterface cmd = {0};
   cmd.interface = interface_number;
   cmd.altsetting = alternate_setting;
+
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SETINTERFACE, &cmd));
   if (rc) {
     USB_PLOG(DEBUG) << "Failed to set interface " << interface_number
@@ -285,6 +288,7 @@
     ResultCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   // TODO(reillyg): libusb releases interfaces before and then reclaims
   // interfaces after a reset. We should probably do this too or document that
   // callers have to call ClaimInterface as well.
@@ -301,6 +305,7 @@
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   int tmp_endpoint = endpoint_address;
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_CLEAR_HALT, &tmp_endpoint));
   if (rc) {
     USB_PLOG(DEBUG) << "Failed to clear the stall condition on endpoint "
@@ -313,6 +318,7 @@
 void UsbDeviceHandleUsbfs::FileThreadHelper::DiscardUrb(Transfer* transfer) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_DISCARDURB, &transfer->urb));
 
   task_runner_->PostTask(FROM_HERE,
@@ -327,6 +333,8 @@
   std::vector<usbdevfs_urb*> urbs;
   urbs.reserve(MAX_URBS_PER_EVENT);
   for (size_t i = 0; i < MAX_URBS_PER_EVENT; ++i) {
+    base::ScopedBlockingCall scoped_blocking_call(
+        base::BlockingType::MAY_BLOCK);
     usbdevfs_urb* urb;
     int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_REAPURBNDELAY, &urb));
     if (rc) {
diff --git a/device/usb/usb_device_impl.cc b/device/usb/usb_device_impl.cc
index ab734eab..e7e3f86 100644
--- a/device/usb/usb_device_impl.cc
+++ b/device/usb/usb_device_impl.cc
@@ -15,7 +15,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "components/device_event_log/device_event_log.h"
@@ -101,7 +101,7 @@
     OpenCallback callback,
     scoped_refptr<base::TaskRunner> task_runner,
     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   libusb_device_handle* handle = nullptr;
   const int rv = libusb_open(platform_device(), &handle);
   if (LIBUSB_SUCCESS == rv) {
diff --git a/device/usb/usb_service_linux.cc b/device/usb/usb_service_linux.cc
index a3423257..b876dff7 100644
--- a/device/usb/usb_service_linux.cc
+++ b/device/usb/usb_service_linux.cc
@@ -20,8 +20,8 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "components/device_event_log/device_event_log.h"
 #include "device/udev_linux/udev_watcher.h"
@@ -102,7 +102,7 @@
 // static
 void UsbServiceLinux::FileThreadHelper::Start() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   // Initializing udev for device enumeration and monitoring may fail. In that
   // case this service will continue to exist but no devices will be found.
@@ -117,6 +117,8 @@
 void UsbServiceLinux::FileThreadHelper::OnDeviceAdded(
     ScopedUdevDevicePtr device) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
+
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   const char* subsystem = udev_device_get_subsystem(device.get());
   if (!subsystem || strcmp(subsystem, "usb") != 0)
     return;
@@ -176,6 +178,8 @@
 void UsbServiceLinux::FileThreadHelper::OnDeviceRemoved(
     ScopedUdevDevicePtr device) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
+
   const char* device_path = udev_device_get_devnode(device.get());
   if (device_path) {
     task_runner_->PostTask(
diff --git a/docs/README.md b/docs/README.md
index 7a36442..ffe325ae 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -48,6 +48,8 @@
     (on a Linux host)
 *   [Cast for Android Build Instructions](android_cast_build_instructions.md) -
     Cast for Android (on a Linux host)
+*   [Fuchsia Build Instructions](fuchsia_build_instructions.md) - Fuchsia target
+    (on a Linux host)
 *   [iOS Build Instructions](ios/build_instructions.md) - iOS target (on a MacOS
     host)
 *   [Chrome OS Build Instructions](chromeos_build_instructions.md) - Chrome OS
diff --git a/docs/fuchsia_build_instructions.md b/docs/fuchsia_build_instructions.md
index a137bc0..539d0d0a 100644
--- a/docs/fuchsia_build_instructions.md
+++ b/docs/fuchsia_build_instructions.md
@@ -3,7 +3,7 @@
 ***Note that the Fuchsia port is in the early stages, and things are likely to
 frequently be broken. Try #cr-fuchsia on Freenode if something seems awry.***
 
-There are instructions for other platforms linked from the 
+There are instructions for other platforms linked from the
 [get the code](get_the_code.md) page.
 
 ## System requirements
@@ -49,9 +49,6 @@
 $ fetch --nohooks chromium
 ```
 
-If you don't want the full repo history, you can save a lot of time by
-adding the `--no-history` flag to `fetch`.
-
 Expect the command to take 30 minutes on even a fast connection, and many
 hours on slower ones.
 
@@ -74,8 +71,14 @@
 Note that this should be added as a top-level statement in the `.gclient` file,
 not an entry inside the `solutions` dict.
 
-You will then need to re-run `gclient runhooks`. This makes sure the Fuchsia SDK
-is available in third\_party and keeps it up to date.
+You will then need to run:
+
+```shell
+$ gclient runhooks
+```
+
+This makes sure the Fuchsia SDK is available in third\_party and keeps it up to
+date.
 
 The remaining instructions assume you have switched to the `src` directory:
 
@@ -83,6 +86,25 @@
 $ cd src
 ```
 
+### Update your checkout
+
+To update an existing checkout, you can run
+
+```shell
+$ git rebase-update
+$ gclient sync
+```
+
+The first command updates the primary Chromium source repository and rebases
+any of your local branches on top of tip-of-tree (aka the Git branch
+`origin/master`). If you don't want to use this script, you can also just use
+`git pull` or other common Git commands to update the repo.
+
+The second command syncs dependencies to the appropriate versions and re-runs
+hooks as needed. `gclient sync` updates dependencies to the versions specified
+in `DEPS`, so any time that file is modified (pulling, changing branches, etc.)
+`gclient sync` should be run.
+
 ## (Mac-only) Download additional required Clang binaries
 
 Go to [this page](https://chrome-infra-packages.appspot.com/p/fuchsia/clang/mac-amd64/+/)
@@ -136,9 +158,3 @@
 script.
 
 The run script also symbolizes backtraces.
-
-A useful alias (for "Build And Run Filtered") is:
-```shell
-alias barf='ninja -C out/fuchsia net_unittests -j1000 && out/fuchsia/bin/run_net_unittests --test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.net_unittests.filter'
-```
-to build and run only the tests that are not excluded/known-failing on the bot.
diff --git a/docs/get_the_code.md b/docs/get_the_code.md
index e4bb6e35..a25bce6 100644
--- a/docs/get_the_code.md
+++ b/docs/get_the_code.md
@@ -12,6 +12,7 @@
 * [Android](android_build_instructions.md)
 * [Android Cast](android_cast_build_instructions.md)
 * [Chrome OS](chromeos_build_instructions.md)
+* [Fuchsia](fuchsia_build_instructions.md)
 * [iOS](ios/build_instructions.md)
 * [Linux](linux_build_instructions.md)
 * [Linux Cast](linux_cast_build_instructions.md)
diff --git a/extensions/common/extension_builder.cc b/extensions/common/extension_builder.cc
index 37b4de0..c948cda1 100644
--- a/extensions/common/extension_builder.cc
+++ b/extensions/common/extension_builder.cc
@@ -30,10 +30,10 @@
 
   std::unique_ptr<base::DictionaryValue> GetValue() const {
     DictionaryBuilder manifest;
-    manifest.Set("name", name)
-        .Set("manifest_version", 2)
-        .Set("version", version.value_or("0.1"))
-        .Set("description", "some description");
+    manifest.Set(manifest_keys::kName, name)
+        .Set(manifest_keys::kManifestVersion, 2)
+        .Set(manifest_keys::kVersion, version.value_or("0.1"))
+        .Set(manifest_keys::kDescription, "some description");
 
     switch (type) {
       case Type::EXTENSION:
@@ -52,7 +52,7 @@
       ListBuilder permissions_builder;
       for (const std::string& permission : permissions)
         permissions_builder.Append(permission);
-      manifest.Set("permissions", permissions_builder.Build());
+      manifest.Set(manifest_keys::kPermissions, permissions_builder.Build());
     }
 
     if (action) {
@@ -92,11 +92,12 @@
           matches.Append(match);
         scripts_value.Append(
             DictionaryBuilder()
-                .Set("js", ListBuilder().Append(script.first).Build())
-                .Set("matches", matches.Build())
+                .Set(manifest_keys::kJs,
+                     ListBuilder().Append(script.first).Build())
+                .Set(manifest_keys::kMatches, matches.Build())
                 .Build());
       }
-      manifest.Set("content_scripts", scripts_value.Build());
+      manifest.Set(manifest_keys::kContentScripts, scripts_value.Build());
     }
 
     std::unique_ptr<base::DictionaryValue> result = manifest.Build();
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 875ff26..5737483f6 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -446,7 +446,7 @@
   LoggingNativeHandler* logging = new LoggingNativeHandler(context);
   logging->Initialize();
   context->AddInvalidationObserver(
-      base::Bind(&NativeHandler::Invalidate, base::Owned(logging)));
+      base::BindOnce(&NativeHandler::Invalidate, base::Owned(logging)));
 
   // Execute the main function with its dependencies passed in as arguments.
   v8::Local<v8::Value> args[] = {
diff --git a/extensions/renderer/event_bindings.cc b/extensions/renderer/event_bindings.cc
index 8d75bc61..588932fb 100644
--- a/extensions/renderer/event_bindings.cc
+++ b/extensions/renderer/event_bindings.cc
@@ -83,7 +83,7 @@
   // It's safe to use base::Unretained here because |context| will always
   // outlive us.
   context->AddInvalidationObserver(
-      base::Bind(&EventBindings::OnInvalidated, base::Unretained(this)));
+      base::BindOnce(&EventBindings::OnInvalidated, base::Unretained(this)));
 }
 
 EventBindings::~EventBindings() {}
diff --git a/extensions/renderer/gc_callback.cc b/extensions/renderer/gc_callback.cc
index 330e8a7..bc24a8a 100644
--- a/extensions/renderer/gc_callback.cc
+++ b/extensions/renderer/gc_callback.cc
@@ -42,8 +42,8 @@
   if (!v8_callback.IsEmpty())
     v8_callback_.Reset(context->isolate(), v8_callback);
   object_.SetWeak(this, OnObjectGC, v8::WeakCallbackType::kParameter);
-  context->AddInvalidationObserver(base::Bind(&GCCallback::OnContextInvalidated,
-                                              weak_ptr_factory_.GetWeakPtr()));
+  context->AddInvalidationObserver(base::BindOnce(
+      &GCCallback::OnContextInvalidated, weak_ptr_factory_.GetWeakPtr()));
 }
 
 GCCallback::~GCCallback() {}
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc
index 69feec88..7ee5528 100644
--- a/extensions/renderer/script_context.cc
+++ b/extensions/renderer/script_context.cc
@@ -138,10 +138,10 @@
 
   // Swap |invalidate_observers_| to a local variable to clear it, and to make
   // sure it's not mutated as we iterate.
-  std::vector<base::Closure> observers;
+  std::vector<base::OnceClosure> observers;
   observers.swap(invalidate_observers_);
-  for (const base::Closure& observer : observers) {
-    observer.Run();
+  for (base::OnceClosure& observer : observers) {
+    std::move(observer).Run();
   }
   DCHECK(invalidate_observers_.empty())
       << "Invalidation observers cannot be added during invalidation";
@@ -149,9 +149,9 @@
   v8_context_.Reset();
 }
 
-void ScriptContext::AddInvalidationObserver(const base::Closure& observer) {
+void ScriptContext::AddInvalidationObserver(base::OnceClosure observer) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  invalidate_observers_.push_back(observer);
+  invalidate_observers_.push_back(std::move(observer));
 }
 
 const std::string& ScriptContext::GetExtensionID() const {
diff --git a/extensions/renderer/script_context.h b/extensions/renderer/script_context.h
index 84e2bf6..f2ac3b89 100644
--- a/extensions/renderer/script_context.h
+++ b/extensions/renderer/script_context.h
@@ -70,7 +70,7 @@
 
   // Registers |observer| to be run when this context is invalidated. Closures
   // are run immediately when Invalidate() is called, not in a message loop.
-  void AddInvalidationObserver(const base::Closure& observer);
+  void AddInvalidationObserver(base::OnceClosure observer);
 
   // Returns true if this context is still valid, false if it isn't.
   // A context becomes invalid via Invalidate().
@@ -277,9 +277,9 @@
   // The set of capabilities granted to this context by extensions.
   APIPermissionSet content_capabilities_;
 
-  // A list of base::Closure instances as an observer interface for
+  // A list of base::OnceClosure instances as an observer interface for
   // invalidation.
-  std::vector<base::Closure> invalidate_observers_;
+  std::vector<base::OnceClosure> invalidate_observers_;
 
   v8::Isolate* isolate_;
 
diff --git a/extensions/renderer/wake_event_page.cc b/extensions/renderer/wake_event_page.cc
index ea449213..731afcfd 100644
--- a/extensions/renderer/wake_event_page.cc
+++ b/extensions/renderer/wake_event_page.cc
@@ -46,7 +46,7 @@
         weak_ptr_factory_(this) {
     // Delete self on invalidation. base::Unretained because by definition this
     // can't be deleted before it's deleted.
-    context->AddInvalidationObserver(base::Bind(
+    context->AddInvalidationObserver(base::BindOnce(
         &WakeEventPageNativeHandler::DeleteSelf, base::Unretained(this)));
   }
 
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 2b712b3..1f3829a 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -89,6 +89,7 @@
 
 base::AtomicSequenceNumber g_next_route_id;
 base::AtomicSequenceNumber g_next_image_id;
+base::AtomicSequenceNumber g_next_transfer_buffer_id;
 
 CommandBufferId NextCommandBufferId() {
   return CommandBufferIdFromChannelAndRoute(kInProcessCommandBufferClientId,
@@ -934,7 +935,7 @@
     size_t size,
     int32_t* id) {
   scoped_refptr<Buffer> buffer = MakeMemoryBuffer(size);
-  *id = ++next_transfer_buffer_id_;
+  *id = g_next_transfer_buffer_id.GetNext() + 1;
   ScheduleGpuTask(
       base::BindOnce(&InProcessCommandBuffer::RegisterTransferBufferOnGpuThread,
                      gpu_thread_weak_ptr_factory_.GetWeakPtr(), *id, buffer));
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index 3561538..43ca25b 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -330,7 +330,6 @@
   int32_t last_put_offset_ = -1;
   Capabilities capabilities_;
   GpuMemoryBufferManager* gpu_memory_buffer_manager_ = nullptr;
-  int32_t  next_transfer_buffer_id_ = 1;
   uint64_t next_fence_sync_release_ = 1;
   uint64_t flushed_fence_sync_release_ = 0;
   std::vector<SyncToken> next_flush_sync_token_fences_;
diff --git a/gpu/ipc/service/direct_composition_surface_win.cc b/gpu/ipc/service/direct_composition_surface_win.cc
index 846a7702..b5afb09 100644
--- a/gpu/ipc/service/direct_composition_surface_win.cc
+++ b/gpu/ipc/service/direct_composition_surface_win.cc
@@ -23,6 +23,7 @@
 #include "gpu/ipc/service/gpu_channel_manager_delegate.h"
 #include "ui/display/display_switches.h"
 #include "ui/gfx/color_space_win.h"
+#include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/transform.h"
@@ -319,12 +320,10 @@
     Microsoft::WRL::ComPtr<IDCompositionSurface> surface;
     uint64_t dcomp_surface_serial = 0;
 
-    gfx::Rect bounds;
-    float swap_chain_scale_x = 0.0f;
-    float swap_chain_scale_y = 0.0f;
     bool is_clipped = false;
     gfx::Rect clip_rect;
     gfx::Transform transform;
+    gfx::Point offset;
   };
 
   // These functions return true if the visual tree was changed.
@@ -336,12 +335,15 @@
                                  const ui::DCRendererLayerParams& params);
   bool UpdateVisualClip(VisualInfo* visual_info,
                         const ui::DCRendererLayerParams& params);
+  bool UpdateVisualTransform(VisualInfo* visual_info,
+                             const gfx::Transform& video_transform,
+                             const gfx::Point& offset);
 
   void CalculateVideoSwapChainParameters(
       const ui::DCRendererLayerParams& params,
-      gfx::Rect* video_visual_bounds_rect,
-      gfx::Size* video_input_size,
-      gfx::Size* video_swap_chain_size) const;
+      gfx::Size* video_swap_chain_size,
+      gfx::Transform* video_visual_transform,
+      gfx::Point* video_visual_offset) const;
 
   DirectCompositionSurfaceWin* surface_;
   std::vector<std::unique_ptr<ui::DCRendererLayerParams>> pending_overlays_;
@@ -1008,12 +1010,13 @@
     visual_info->surface.Reset();
   }
 
-  gfx::Rect bounds_rect;
-  gfx::Size video_input_size;
+  gfx::Size video_input_size = gfx::ToCeiledSize(params.contents_rect.size());
   gfx::Size swap_chain_size;
+  gfx::Transform video_transform;
+  gfx::Point video_offset;
 
-  CalculateVideoSwapChainParameters(params, &bounds_rect, &video_input_size,
-                                    &swap_chain_size);
+  CalculateVideoSwapChainParameters(params, &swap_chain_size, &video_transform,
+                                    &video_offset);
 
   Microsoft::WRL::ComPtr<IDCompositionVisual2> dc_visual =
       visual_info->content_visual;
@@ -1049,58 +1052,28 @@
     changed = true;
   }
 
-  // This is the scale from the swapchain size to the size of the contents
-  // onscreen.
-  float swap_chain_scale_x =
-      bounds_rect.width() * 1.0f / swap_chain_size.width();
-  float swap_chain_scale_y =
-      bounds_rect.height() * 1.0f / swap_chain_size.height();
-
-  // This visual's transform changed.
-  if (swap_chain_scale_x != visual_info->swap_chain_scale_x ||
-      swap_chain_scale_y != visual_info->swap_chain_scale_y ||
-      params.transform != visual_info->transform ||
-      bounds_rect != visual_info->bounds) {
-    visual_info->swap_chain_scale_x = swap_chain_scale_x;
-    visual_info->swap_chain_scale_y = swap_chain_scale_y;
-    visual_info->transform = params.transform;
-    visual_info->bounds = bounds_rect;
-
-    gfx::Transform final_transform = params.transform;
-    gfx::Transform scale_transform;
-    scale_transform.Scale(swap_chain_scale_x, swap_chain_scale_y);
-    final_transform.PreconcatTransform(scale_transform);
-    final_transform.Transpose();
-
-    dc_visual->SetOffsetX(bounds_rect.x());
-    dc_visual->SetOffsetY(bounds_rect.y());
-    Microsoft::WRL::ComPtr<IDCompositionMatrixTransform> dcomp_transform;
-    dcomp_device_->CreateMatrixTransform(dcomp_transform.GetAddressOf());
-    DCHECK(dcomp_transform);
-    D2D_MATRIX_3X2_F d2d_matrix = {{{final_transform.matrix().get(0, 0),
-                                     final_transform.matrix().get(0, 1),
-                                     final_transform.matrix().get(1, 0),
-                                     final_transform.matrix().get(1, 1),
-                                     final_transform.matrix().get(3, 0),
-                                     final_transform.matrix().get(3, 1)}}};
-    dcomp_transform->SetMatrix(d2d_matrix);
-    dc_visual->SetTransform(dcomp_transform.Get());
+  if (UpdateVisualTransform(visual_info, video_transform, video_offset)) {
     changed = true;
   }
+
   return changed;
 }
 
 void DCLayerTree::CalculateVideoSwapChainParameters(
     const ui::DCRendererLayerParams& params,
-    gfx::Rect* video_visual_bounds_rect,
-    gfx::Size* video_input_size,
-    gfx::Size* video_swap_chain_size) const {
+    gfx::Size* video_swap_chain_size,
+    gfx::Transform* video_visual_transform,
+    gfx::Point* video_visual_offset) const {
   // Swap chain size is the minimum of the on-screen size and the source
   // size so the video processor can do the minimal amount of work and
   // the overlay has to read the minimal amount of data.
   // DWM is also less likely to promote a surface to an overlay if it's
   // much larger than its area on-screen.
-  gfx::Rect bounds_rect = params.rect;
+
+  // display_rect is the rect on screen
+  gfx::RectF transformed_rect = gfx::RectF(params.rect);
+  params.transform.TransformRect(&transformed_rect);
+  gfx::Rect display_rect = gfx::ToEnclosingRect(transformed_rect);
 
   if (workarounds().disable_larger_than_screen_overlays &&
       !g_overlay_monitor_size.IsEmpty()) {
@@ -1115,34 +1088,86 @@
     // TODO(jbauman): Remove when http://crbug.com/668278 is fixed.
     const int kOversizeMargin = 3;
 
-    if ((bounds_rect.x() >= 0) &&
-        (bounds_rect.width() > g_overlay_monitor_size.width()) &&
-        (bounds_rect.width() <=
+    if ((display_rect.x() >= 0) &&
+        (display_rect.width() > g_overlay_monitor_size.width()) &&
+        (display_rect.width() <=
          g_overlay_monitor_size.width() + kOversizeMargin)) {
-      bounds_rect.set_width(g_overlay_monitor_size.width());
+      display_rect.set_width(g_overlay_monitor_size.width());
     }
 
-    if ((bounds_rect.y() >= 0) &&
-        (bounds_rect.height() > g_overlay_monitor_size.height()) &&
-        (bounds_rect.height() <=
+    if ((display_rect.y() >= 0) &&
+        (display_rect.height() > g_overlay_monitor_size.height()) &&
+        (display_rect.height() <=
          g_overlay_monitor_size.height() + kOversizeMargin)) {
-      bounds_rect.set_height(g_overlay_monitor_size.height());
+      display_rect.set_height(g_overlay_monitor_size.height());
     }
   }
 
-  gfx::Size ceiled_input_size = gfx::ToCeiledSize(params.contents_rect.size());
-  gfx::Size swap_chain_size = bounds_rect.size();
+  // Downscaling doesn't work on Intel display HW, and so DWM will perform
+  // an extra BLT to avoid HW downscaling. This prevents the use of hardware
+  // overlays especially for protected video.
+  gfx::Size swap_chain_size = display_rect.size();
 
-  if (g_supports_scaled_overlays)
+  if (g_supports_scaled_overlays) {
+    gfx::Size ceiled_input_size =
+        gfx::ToCeiledSize(params.contents_rect.size());
     swap_chain_size.SetToMin(ceiled_input_size);
+  }
 
   // YUV surfaces must have an even width.
   if (swap_chain_size.width() % 2 == 1)
     swap_chain_size.set_width(swap_chain_size.width() + 1);
 
-  *video_visual_bounds_rect = bounds_rect;
-  *video_input_size = ceiled_input_size;
+  // Update the transform matrix. It will be used in dc_visual->SetTransform()
+  // This is the scale from the swapchain size to the size of the contents
+  // onscreen.
+  float swap_chain_scale_x =
+      params.rect.width() * 1.0f / swap_chain_size.width();
+  float swap_chain_scale_y =
+      params.rect.height() * 1.0f / swap_chain_size.height();
+  gfx::Transform transform = params.transform;
+  gfx::Transform scale_transform;
+  scale_transform.Scale(swap_chain_scale_x, swap_chain_scale_y);
+  transform.PreconcatTransform(scale_transform);
+  transform.Transpose();
+
+  // Offset relative to its parent, used in dc_visual->SetOffsetX()
+  // TODO(magchen): We should consider recalculating offset when it's non-zero.
+  // Have not seen non-zero params.rect.x() and y() so far.
+  gfx::Point offset(params.rect.x(), params.rect.y());
+
   *video_swap_chain_size = swap_chain_size;
+  *video_visual_transform = transform;
+  *video_visual_offset = offset;
+}
+
+bool DCLayerTree::UpdateVisualTransform(VisualInfo* visual_info,
+                                        const gfx::Transform& transform,
+                                        const gfx::Point& offset) {
+  bool changed = false;
+
+  // This visual's transform changed.
+  if (transform != visual_info->transform || offset != visual_info->offset) {
+    visual_info->transform = transform;
+    visual_info->offset = offset;
+
+    Microsoft::WRL::ComPtr<IDCompositionVisual2> dc_visual =
+        visual_info->content_visual;
+    dc_visual->SetOffsetX(offset.x());
+    dc_visual->SetOffsetY(offset.y());
+    Microsoft::WRL::ComPtr<IDCompositionMatrixTransform> dcomp_transform;
+    dcomp_device_->CreateMatrixTransform(dcomp_transform.GetAddressOf());
+    DCHECK(dcomp_transform);
+    D2D_MATRIX_3X2_F d2d_matrix = {
+        {{transform.matrix().get(0, 0), transform.matrix().get(0, 1),
+          transform.matrix().get(1, 0), transform.matrix().get(1, 1),
+          transform.matrix().get(3, 0), transform.matrix().get(3, 1)}}};
+    dcomp_transform->SetMatrix(d2d_matrix);
+    dc_visual->SetTransform(dcomp_transform.Get());
+    changed = true;
+  }
+
+  return changed;
 }
 
 bool DCLayerTree::UpdateVisualForBackbuffer(
@@ -1167,12 +1192,11 @@
     changed = true;
   }
 
-  gfx::Rect bounds_rect = params.rect;
-  if (visual_info->bounds != bounds_rect ||
-      !visual_info->transform.IsIdentity()) {
-    dc_visual->SetOffsetX(bounds_rect.x());
-    dc_visual->SetOffsetY(bounds_rect.y());
-    visual_info->bounds = bounds_rect;
+  gfx::Point offset = params.rect.origin();
+  if (visual_info->offset != offset || !visual_info->transform.IsIdentity()) {
+    dc_visual->SetOffsetX(offset.x());
+    dc_visual->SetOffsetY(offset.y());
+    visual_info->offset = offset;
     dc_visual->SetTransform(nullptr);
     visual_info->transform = gfx::Transform();
     changed = true;
@@ -1327,8 +1351,9 @@
 }
 
 // static
-void DirectCompositionSurfaceWin::EnableScaledOverlaysForTesting() {
-  g_supports_scaled_overlays = true;
+void DirectCompositionSurfaceWin::SetScaledOverlaysSupportedForTesting(
+    bool value) {
+  g_supports_scaled_overlays = value;
 }
 
 // static
diff --git a/gpu/ipc/service/direct_composition_surface_win.h b/gpu/ipc/service/direct_composition_surface_win.h
index bc61dacd..f03d17a7 100644
--- a/gpu/ipc/service/direct_composition_surface_win.h
+++ b/gpu/ipc/service/direct_composition_surface_win.h
@@ -50,7 +50,7 @@
   // displays.  Tearing is only used if vsync is also disabled via command line.
   static bool IsSwapChainTearingSupported();
 
-  static void EnableScaledOverlaysForTesting();
+  static void SetScaledOverlaysSupportedForTesting(bool value);
 
   bool InitializeNativeWindow();
 
diff --git a/gpu/ipc/service/direct_composition_surface_win_unittest.cc b/gpu/ipc/service/direct_composition_surface_win_unittest.cc
index 0410f6d..5ce3fc40 100644
--- a/gpu/ipc/service/direct_composition_surface_win_unittest.cc
+++ b/gpu/ipc/service/direct_composition_surface_win_unittest.cc
@@ -401,6 +401,155 @@
   DestroySurface(std::move(surface));
 }
 
+// Ensure the swapchain size is set to the correct size if HW overlay scaling
+// is support - swapchain should be the minimum of the decoded
+// video buffer size and the onscreen video size
+TEST(DirectCompositionSurfaceTest, SwapchainSizeWithScaledOverlays) {
+  if (!CheckIfDCSupported())
+    return;
+
+  TestImageTransportSurfaceDelegate delegate;
+  scoped_refptr<DirectCompositionSurfaceWin> surface(
+      new DirectCompositionSurfaceWin(nullptr, delegate.AsWeakPtr(),
+                                      ui::GetHiddenWindow()));
+  EXPECT_TRUE(surface->Initialize());
+
+  scoped_refptr<gl::GLContext> context =
+      gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs());
+  EXPECT_TRUE(context->MakeCurrent(surface.get()));
+
+  surface->SetEnableDCLayers(true);
+
+  Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
+      gl::QueryD3D11DeviceObjectFromANGLE();
+
+  gfx::Size texture_size(64, 64);
+  Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
+      CreateNV12Texture(d3d11_device, texture_size, false);
+
+  scoped_refptr<gl::GLImageDXGI> image_dxgi(
+      new gl::GLImageDXGI(texture_size, nullptr));
+  image_dxgi->SetTexture(texture, 0);
+  image_dxgi->SetColorSpace(gfx::ColorSpace::CreateREC709());
+
+  // HW supports scaled overlays
+  // The input texture size is maller than the window size.
+  surface->SetScaledOverlaysSupportedForTesting(true);
+  gfx::Size window_size(100, 100);
+  ui::DCRendererLayerParams params(
+      false, gfx::Rect(), 1, gfx::Transform(),
+      std::vector<scoped_refptr<gl::GLImage>>{image_dxgi},
+      gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(window_size), 0, 0, 1.0, 0,
+      false);
+
+  surface->ScheduleDCLayer(params);
+  EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing()));
+  Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
+      surface->GetLayerSwapChainForTesting(1);
+  ASSERT_TRUE(swap_chain);
+
+  DXGI_SWAP_CHAIN_DESC Desc;
+  EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc(&Desc)));
+  EXPECT_EQ((int)Desc.BufferDesc.Width, texture_size.width());
+  EXPECT_EQ((int)Desc.BufferDesc.Height, texture_size.height());
+
+  // The input texture size is bigger than the window size.
+  window_size = gfx::Size(32, 48);
+  ui::DCRendererLayerParams params2(
+      false, gfx::Rect(), 1, gfx::Transform(),
+      std::vector<scoped_refptr<gl::GLImage>>{image_dxgi},
+      gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(window_size), 0, 0, 1.0, 0,
+      false);
+
+  surface->ScheduleDCLayer(params2);
+  EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing()));
+
+  Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 =
+      surface->GetLayerSwapChainForTesting(1);
+  ASSERT_TRUE(swap_chain2);
+
+  EXPECT_TRUE(SUCCEEDED(swap_chain2->GetDesc(&Desc)));
+  EXPECT_EQ((int)Desc.BufferDesc.Width, window_size.width());
+  EXPECT_EQ((int)Desc.BufferDesc.Height, window_size.height());
+
+  context = nullptr;
+  DestroySurface(std::move(surface));
+}
+
+// Ensure the swapchain size is set to the correct size if HW overlay scaling
+// is not support - swapchain should be the onscreen video size
+TEST(DirectCompositionSurfaceTest, SwapchainSizeWithoutScaledOverlays) {
+  if (!CheckIfDCSupported())
+    return;
+
+  TestImageTransportSurfaceDelegate delegate;
+  scoped_refptr<DirectCompositionSurfaceWin> surface(
+      new DirectCompositionSurfaceWin(nullptr, delegate.AsWeakPtr(),
+                                      ui::GetHiddenWindow()));
+  EXPECT_TRUE(surface->Initialize());
+
+  scoped_refptr<gl::GLContext> context =
+      gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs());
+  EXPECT_TRUE(context->MakeCurrent(surface.get()));
+
+  surface->SetEnableDCLayers(true);
+
+  Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
+      gl::QueryD3D11DeviceObjectFromANGLE();
+
+  gfx::Size texture_size(80, 80);
+  Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
+      CreateNV12Texture(d3d11_device, texture_size, false);
+
+  scoped_refptr<gl::GLImageDXGI> image_dxgi(
+      new gl::GLImageDXGI(texture_size, nullptr));
+  image_dxgi->SetTexture(texture, 0);
+  image_dxgi->SetColorSpace(gfx::ColorSpace::CreateREC709());
+
+  // HW doesn't support scaled overlays
+  // The input texture size is bigger than the window size.
+  surface->SetScaledOverlaysSupportedForTesting(false);
+  gfx::Size window_size(42, 42);
+  ui::DCRendererLayerParams params(
+      false, gfx::Rect(), 1, gfx::Transform(),
+      std::vector<scoped_refptr<gl::GLImage>>{image_dxgi},
+      gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(window_size), 0, 0, 1.0, 0,
+      false);
+
+  surface->ScheduleDCLayer(params);
+  EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing()));
+  Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
+      surface->GetLayerSwapChainForTesting(1);
+  ASSERT_TRUE(swap_chain);
+
+  DXGI_SWAP_CHAIN_DESC Desc;
+  EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc(&Desc)));
+  EXPECT_EQ((int)Desc.BufferDesc.Width, window_size.width());
+  EXPECT_EQ((int)Desc.BufferDesc.Height, window_size.height());
+
+  // The input texture size is smaller than the window size.
+  window_size = gfx::Size(124, 136);
+  ui::DCRendererLayerParams params2(
+      false, gfx::Rect(), 1, gfx::Transform(),
+      std::vector<scoped_refptr<gl::GLImage>>{image_dxgi},
+      gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(window_size), 0, 0, 1.0, 0,
+      false);
+
+  surface->ScheduleDCLayer(params2);
+  EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing()));
+
+  Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 =
+      surface->GetLayerSwapChainForTesting(1);
+  ASSERT_TRUE(swap_chain2);
+
+  EXPECT_TRUE(SUCCEEDED(swap_chain2->GetDesc(&Desc)));
+  EXPECT_EQ((int)Desc.BufferDesc.Width, window_size.width());
+  EXPECT_EQ((int)Desc.BufferDesc.Height, window_size.height());
+
+  context = nullptr;
+  DestroySurface(std::move(surface));
+}
+
 SkColor ReadBackWindowPixel(HWND window, const gfx::Point& point) {
   base::win::ScopedCreateDC mem_hdc(::CreateCompatibleDC(nullptr));
   void* bits = nullptr;
@@ -751,7 +900,7 @@
   InitializeSurface();
   // Swap chain size is overridden to content rect size only if scaled overlays
   // are supported.
-  DirectCompositionSurfaceWin::EnableScaledOverlaysForTesting();
+  DirectCompositionSurfaceWin::SetScaledOverlaysSupportedForTesting(true);
   surface_->SetEnableDCLayers(true);
 
   gfx::Size window_size(100, 100);
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
index 6d7bd9f7..334be37 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
@@ -65,7 +65,7 @@
   void ConfirmSaveAutofillProfile(const AutofillProfile& profile,
                                   base::OnceClosure callback) override;
   void ConfirmSaveCreditCardLocally(const CreditCard& card,
-                                    const base::Closure& callback) override;
+                                    base::OnceClosure callback) override;
   void ConfirmSaveCreditCardToCloud(
       const CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
@@ -74,7 +74,7 @@
   void ConfirmCreditCardFillAssist(const CreditCard& card,
                                    const base::Closure& callback) override;
   void LoadRiskData(
-      const base::Callback<void(const std::string&)>& callback) override;
+      base::OnceCallback<void(const std::string&)> callback) override;
   bool HasCreditCardScanFeature() override;
   void ScanCreditCard(const CreditCardScanCallback& callback) override;
   void ShowAutofillPopup(
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
index 470bd5b..b22fddc 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
@@ -161,13 +161,13 @@
 
 void ChromeAutofillClientIOS::ConfirmSaveCreditCardLocally(
     const CreditCard& card,
-    const base::Closure& callback) {
+    base::OnceClosure callback) {
   infobar_manager_->AddInfoBar(CreateSaveCardInfoBarMobile(
       std::make_unique<AutofillSaveCardInfoBarDelegateMobile>(
           false, card, std::unique_ptr<base::DictionaryValue>(nullptr),
           /*upload_save_card_callback=*/
           base::OnceCallback<void(const base::string16&)>(),
-          /*local_save_card_callback=*/callback, GetPrefs())));
+          /*local_save_card_callback=*/std::move(callback), GetPrefs())));
 }
 
 void ChromeAutofillClientIOS::ShowLocalCardMigrationDialog(
@@ -214,8 +214,8 @@
 }
 
 void ChromeAutofillClientIOS::LoadRiskData(
-    const base::Callback<void(const std::string&)>& callback) {
-  callback.Run(ios::GetChromeBrowserProvider()->GetRiskData());
+    base::OnceCallback<void(const std::string&)> callback) {
+  std::move(callback).Run(ios::GetChromeBrowserProvider()->GetRiskData());
 }
 
 bool ChromeAutofillClientIOS::HasCreditCardScanFeature() {
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 6e57b50..b8c17fc5 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -5126,14 +5126,30 @@
   CGFloat newPageOffset = 0;
   UIView* newPage = nil;
   CGFloat offset = 0;
-  GURL tabURL = tab.webState->GetLastCommittedURL();
   // Toolbar snapshot is only used for the UIRefresh animation.
   UIView* toolbarSnapshot;
-  // Vislble URL should be more correct here than last committed, but for
-  // safety, limiting the scope only to WKBasedNavigationManager, which needs
-  // it to correctly animate NTP. See https://crbug.com/819606.
-  if (web::GetWebClient()->IsSlimNavigationManagerEnabled())
+
+  GURL tabURL = tab.webState->GetLastCommittedURL();
+  BOOL expectingPageLoad = NO;
+  if (_browserState && !_isShutdown) {
+    WebStateListWebUsageEnabler* webUsageEnabler =
+        WebStateListWebUsageEnablerFactory::GetInstance()->GetForBrowserState(
+            _browserState);
+    expectingPageLoad = webUsageEnabler->IsWebUsageEnabled() &&
+                        webUsageEnabler->TriggersInitialLoad();
+  }
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled() ||
+      expectingPageLoad) {
+    // The visible URL is more correct here.  However, the last committed URL
+    // has been used historically, and it's unclear if there are unintended side
+    // effects from from using the visible URL in all situations.  In order to
+    // mitigate the risk from using the visible URL, additional checks are used
+    // here to only update the URL for known conditions in which the last-
+    // committed URL is incorrect.
+    // TODO(crbug.com/880262): Update to use visible URL for all new tabs.
     tabURL = tab.webState->GetVisibleURL();
+  }
+
   if (tabURL == kChromeUINewTabURL && !_isOffTheRecord &&
       ![self canShowTabStrip]) {
     offset = 0;
diff --git a/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm
index fd5b1ae..4ddaebb 100644
--- a/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm
@@ -138,6 +138,12 @@
   [self addChildViewController:self.appBarViewController];
   ConfigureAppBarViewControllerWithCardStyle(self.appBarViewController);
   self.appBarViewController.headerView.trackingScrollView = self.tableView;
+  // Match the width of the parent view.
+  CGRect frame = self.appBarViewController.view.frame;
+  frame.origin.x = 0;
+  frame.size.width =
+      self.appBarViewController.parentViewController.view.bounds.size.width;
+  self.appBarViewController.view.frame = frame;
   [self.view addSubview:self.appBarViewController.view];
   [self.appBarViewController didMoveToParentViewController:self];
 }
diff --git a/ios/web/navigation/navigation_item_storage_builder.mm b/ios/web/navigation/navigation_item_storage_builder.mm
index 2efd08a..899f58c6 100644
--- a/ios/web/navigation/navigation_item_storage_builder.mm
+++ b/ios/web/navigation/navigation_item_storage_builder.mm
@@ -46,6 +46,8 @@
   item->page_display_state_ = navigation_item_storage.displayState;
   item->should_skip_repost_form_confirmation_ =
       navigation_item_storage.shouldSkipRepostFormConfirmation;
+  // Use reload transition type to avoid incorrect increase for typed count.
+  item->transition_type_ = ui::PAGE_TRANSITION_RELOAD;
   item->user_agent_type_ = navigation_item_storage.userAgentType;
   item->post_data_ = navigation_item_storage.POSTData;
   item->http_request_headers_ =
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm
index b2aab579..bede7a971 100644
--- a/ios/web/web_state/web_state_observer_inttest.mm
+++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -490,10 +490,9 @@
   EXPECT_NE(0, *nav_id);
   EXPECT_EQ(url, (*context)->GetUrl());
   EXPECT_TRUE((*context)->HasUserGesture());
-  // Transition type is not restored (crbug.com/888011).
   ui::PageTransition actual_transition = (*context)->GetPageTransition();
-  EXPECT_TRUE(PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_LINK,
-                                       actual_transition))
+  EXPECT_TRUE(PageTransitionCoreTypeIs(
+      ui::PageTransition::PAGE_TRANSITION_RELOAD, actual_transition))
       << "Got unexpected transition: " << actual_transition;
   EXPECT_FALSE((*context)->IsSameDocument());
   EXPECT_FALSE((*context)->HasCommitted());
@@ -526,10 +525,9 @@
   EXPECT_EQ(*nav_id, (*context)->GetNavigationId());
   EXPECT_EQ(url, (*context)->GetUrl());
   EXPECT_TRUE((*context)->HasUserGesture());
-  // Transition type is not restored (crbug.com/888011).
   ui::PageTransition actual_transition = (*context)->GetPageTransition();
-  EXPECT_TRUE(PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_LINK,
-                                       actual_transition))
+  EXPECT_TRUE(PageTransitionCoreTypeIs(
+      ui::PageTransition::PAGE_TRANSITION_RELOAD, actual_transition))
       << "Got unexpected transition: " << actual_transition;
   EXPECT_FALSE((*context)->IsSameDocument());
   EXPECT_TRUE((*context)->HasCommitted());
diff --git a/ios/web_view/internal/autofill/cwv_autofill_client_ios_bridge.h b/ios/web_view/internal/autofill/cwv_autofill_client_ios_bridge.h
index d9ecc63..9d7bde75 100644
--- a/ios/web_view/internal/autofill/cwv_autofill_client_ios_bridge.h
+++ b/ios/web_view/internal/autofill/cwv_autofill_client_ios_bridge.h
@@ -21,7 +21,7 @@
 
 // Bridge for AutofillClient's method |ConfirmSaveCreditCardLocally|.
 - (void)confirmSaveCreditCardLocally:(const autofill::CreditCard&)creditCard
-                            callback:(const base::RepeatingClosure&)callback;
+                            callback:(base::OnceClosure)callback;
 
 // Bridge for AutofillClient's method |ShowUnmaskPrompt|.
 - (void)
diff --git a/ios/web_view/internal/autofill/cwv_autofill_controller.mm b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
index 37d5265..bbc581c 100644
--- a/ios/web_view/internal/autofill/cwv_autofill_controller.mm
+++ b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
@@ -305,20 +305,18 @@
 }
 
 - (void)confirmSaveCreditCardLocally:(const autofill::CreditCard&)creditCard
-                            callback:(const base::RepeatingClosure&)callback {
+                            callback:(base::OnceClosure)callback {
   if ([_delegate respondsToSelector:@selector
                  (autofillController:decidePolicyForLocalStorageOfCreditCard
                                        :decisionHandler:)]) {
     CWVCreditCard* card = [[CWVCreditCard alloc] initWithCreditCard:creditCard];
-    __block base::RepeatingClosure scopedCallback = callback;
+    __block base::OnceClosure scopedCallback = std::move(callback);
     [_delegate autofillController:self
         decidePolicyForLocalStorageOfCreditCard:card
                                 decisionHandler:^(CWVStoragePolicy policy) {
                                   if (policy == CWVStoragePolicyAllow) {
-                                    if (scopedCallback) {
-                                      scopedCallback.Run();
-                                      scopedCallback.Reset();
-                                    }
+                                    if (scopedCallback)
+                                      std::move(scopedCallback).Run();
                                   }
                                 }];
   }
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
index 54e9e51..9afdfcf 100644
--- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
+++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
@@ -58,7 +58,7 @@
   void ConfirmSaveAutofillProfile(const AutofillProfile& profile,
                                   base::OnceClosure callback) override;
   void ConfirmSaveCreditCardLocally(const CreditCard& card,
-                                    const base::Closure& callback) override;
+                                    base::OnceClosure callback) override;
   void ConfirmSaveCreditCardToCloud(
       const CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
@@ -67,7 +67,7 @@
   void ConfirmCreditCardFillAssist(const CreditCard& card,
                                    const base::Closure& callback) override;
   void LoadRiskData(
-      const base::Callback<void(const std::string&)>& callback) override;
+      base::OnceCallback<void(const std::string&)> callback) override;
   bool HasCreditCardScanFeature() override;
   void ScanCreditCard(const CreditCardScanCallback& callback) override;
   void ShowAutofillPopup(
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
index 425288c..9577f35 100644
--- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
+++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
@@ -113,8 +113,8 @@
 
 void WebViewAutofillClientIOS::ConfirmSaveCreditCardLocally(
     const CreditCard& card,
-    const base::RepeatingClosure& callback) {
-  [bridge_ confirmSaveCreditCardLocally:card callback:callback];
+    base::OnceClosure callback) {
+  [bridge_ confirmSaveCreditCardLocally:card callback:std::move(callback)];
 }
 
 void WebViewAutofillClientIOS::ConfirmSaveCreditCardToCloud(
@@ -128,7 +128,7 @@
     const base::Closure& callback) {}
 
 void WebViewAutofillClientIOS::LoadRiskData(
-    const base::Callback<void(const std::string&)>& callback) {}
+    base::OnceCallback<void(const std::string&)> callback) {}
 
 bool WebViewAutofillClientIOS::HasCreditCardScanFeature() {
   return false;
diff --git a/media/base/eme_constants.h b/media/base/eme_constants.h
index a7b85a0..0da02be 100644
--- a/media/base/eme_constants.h
+++ b/media/base/eme_constants.h
@@ -18,26 +18,23 @@
 
 // Defines bitmask values that specify codecs used in Encrypted Media Extension
 // (EME). Each value represents a codec within a specific container.
-//
-// TODO(yucliu): Remove container name from the enum. See crbug.com/724362 for
-// more details.
 enum EmeCodec : uint32_t {
   EME_CODEC_NONE = 0,
-  EME_CODEC_WEBM_OPUS = 1 << 0,
-  EME_CODEC_WEBM_VORBIS = 1 << 1,
-  EME_CODEC_WEBM_VP8 = 1 << 2,
-  EME_CODEC_WEBM_VP9 = 1 << 3,
-  EME_CODEC_MP4_AAC = 1 << 4,
+  EME_CODEC_OPUS = 1 << 0,
+  EME_CODEC_VORBIS = 1 << 1,
+  EME_CODEC_VP8 = 1 << 2,
+  EME_CODEC_LEGACY_VP9 = 1 << 3,
+  EME_CODEC_AAC = 1 << 4,
   // AVC1 is shared by MP4 and MP2T.
-  EME_CODEC_MP4_AVC1 = 1 << 5,
-  EME_CODEC_COMMON_VP9 = 1 << 6,
-  EME_CODEC_MP4_HEVC = 1 << 7,
-  EME_CODEC_MP4_DV_AVC = 1 << 8,
-  EME_CODEC_MP4_DV_HEVC = 1 << 9,
-  EME_CODEC_MP4_AC3 = 1 << 10,
-  EME_CODEC_MP4_EAC3 = 1 << 11,
-  EME_CODEC_MP4_MPEG_H_AUDIO = 1 << 12,
-  EME_CODEC_MP4_FLAC = 1 << 13,
+  EME_CODEC_AVC1 = 1 << 5,
+  EME_CODEC_VP9 = 1 << 6,  // New multi-part VP9 for WebM and MP4.
+  EME_CODEC_HEVC = 1 << 7,
+  EME_CODEC_DOLBY_VISION_AVC = 1 << 8,
+  EME_CODEC_DOLBY_VISION_HEVC = 1 << 9,
+  EME_CODEC_AC3 = 1 << 10,
+  EME_CODEC_EAC3 = 1 << 11,
+  EME_CODEC_MPEG_H_AUDIO = 1 << 12,
+  EME_CODEC_FLAC = 1 << 13,
 };
 
 // *_ALL values should only be used for masking, do not use them to specify
@@ -46,30 +43,31 @@
 using SupportedCodecs = uint32_t;
 
 constexpr SupportedCodecs GetMp4AudioCodecs() {
-  SupportedCodecs codecs = EME_CODEC_MP4_FLAC;
+  SupportedCodecs codecs = EME_CODEC_FLAC;
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-  codecs |= EME_CODEC_MP4_AAC;
+  codecs |= EME_CODEC_AAC;
 #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
-  codecs |= EME_CODEC_MP4_AC3 | EME_CODEC_MP4_EAC3;
+  codecs |= EME_CODEC_AC3 | EME_CODEC_EAC3;
 #endif  // BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
 #if BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING)
-  codecs |= EME_CODEC_MP4_MPEG_H_AUDIO;
+  codecs |= EME_CODEC_MPEG_H_AUDIO;
 #endif  // BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING)
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
   return codecs;
 }
 
 constexpr SupportedCodecs GetMp4VideoCodecs() {
-  SupportedCodecs codecs = EME_CODEC_COMMON_VP9;
+  // VP9 is supported in MP4, but legacy VP9 is not.
+  SupportedCodecs codecs = EME_CODEC_VP9;
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-  codecs |= EME_CODEC_MP4_AVC1;
+  codecs |= EME_CODEC_AVC1;
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
-  codecs |= EME_CODEC_MP4_HEVC;
+  codecs |= EME_CODEC_HEVC;
 #endif  // BUILDFLAG(ENABLE_HEVC_DEMUXING)
 #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
-  codecs |= EME_CODEC_MP4_DV_AVC;
+  codecs |= EME_CODEC_DOLBY_VISION_AVC;
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
-  codecs |= EME_CODEC_MP4_DV_HEVC;
+  codecs |= EME_CODEC_DOLBY_VISION_HEVC;
 #endif  // BUILDFLAG(ENABLE_HEVC_DEMUXING)
 #endif  // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -77,10 +75,11 @@
 }
 
 constexpr SupportedCodecs EME_CODEC_WEBM_AUDIO_ALL =
-    EME_CODEC_WEBM_OPUS | EME_CODEC_WEBM_VORBIS;
+    EME_CODEC_OPUS | EME_CODEC_VORBIS;
 
+// Both VP9 and legacy VP9 are supported in WebM.
 constexpr SupportedCodecs EME_CODEC_WEBM_VIDEO_ALL =
-    EME_CODEC_WEBM_VP8 | EME_CODEC_WEBM_VP9 | EME_CODEC_COMMON_VP9;
+    EME_CODEC_VP8 | EME_CODEC_LEGACY_VP9 | EME_CODEC_VP9;
 
 constexpr SupportedCodecs EME_CODEC_WEBM_ALL =
     EME_CODEC_WEBM_AUDIO_ALL | EME_CODEC_WEBM_VIDEO_ALL;
@@ -102,7 +101,7 @@
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
-constexpr SupportedCodecs EME_CODEC_MP2T_VIDEO_ALL = EME_CODEC_MP4_AVC1;
+constexpr SupportedCodecs EME_CODEC_MP2T_VIDEO_ALL = EME_CODEC_AVC1;
 static_assert(
     (EME_CODEC_MP2T_VIDEO_ALL & EME_CODEC_VIDEO_ALL) ==
         EME_CODEC_MP2T_VIDEO_ALL,
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc
index c62d06e..9cf3dd8 100644
--- a/media/base/key_systems.cc
+++ b/media/base/key_systems.cc
@@ -58,35 +58,35 @@
 
 // Mapping between codec names and enum values.
 static const NameToCodec kCodecMap[] = {
-    {"opus", EME_CODEC_WEBM_OPUS},      // Opus.
-    {"vorbis", EME_CODEC_WEBM_VORBIS},  // Vorbis.
-    {"vp8", EME_CODEC_WEBM_VP8},        // VP8.
-    {"vp8.0", EME_CODEC_WEBM_VP8},      // VP8.
-    {"vp9", EME_CODEC_WEBM_VP9},        // VP9.
-    {"vp9.0", EME_CODEC_WEBM_VP9},      // VP9.
-    {"vp09", EME_CODEC_COMMON_VP9},     // New multi-part VP9 for WebM and MP4.
-    {"flac", EME_CODEC_MP4_FLAC},       // FLAC.
+    {"opus", EME_CODEC_OPUS},         // Opus.
+    {"vorbis", EME_CODEC_VORBIS},     // Vorbis.
+    {"vp8", EME_CODEC_VP8},           // VP8.
+    {"vp8.0", EME_CODEC_VP8},         // VP8.
+    {"vp9", EME_CODEC_LEGACY_VP9},    // VP9.
+    {"vp9.0", EME_CODEC_LEGACY_VP9},  // VP9.
+    {"vp09", EME_CODEC_VP9},          // New multi-part VP9 for WebM and MP4.
+    {"flac", EME_CODEC_FLAC},         // FLAC.
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-    {"mp4a", EME_CODEC_MP4_AAC},  // AAC.
+    {"mp4a", EME_CODEC_AAC},  // AAC.
 #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
-    {"ac-3", EME_CODEC_MP4_AC3},   // AC3.
-    {"ec-3", EME_CODEC_MP4_EAC3},  // EAC3.
+    {"ac-3", EME_CODEC_AC3},   // AC3.
+    {"ec-3", EME_CODEC_EAC3},  // EAC3.
 #endif
 #if BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING)
-    {"mhm1", EME_CODEC_MP4_MPEG_H_AUDIO},  // MPEG-H Audio.
+    {"mhm1", EME_CODEC_MPEG_H_AUDIO},  // MPEG-H Audio.
 #endif
-    {"avc1", EME_CODEC_MP4_AVC1},  // AVC1 for MP4 and MP2T
-    {"avc3", EME_CODEC_MP4_AVC1},  // AVC3 for MP4 and MP2T
+    {"avc1", EME_CODEC_AVC1},  // AVC1 for MP4 and MP2T
+    {"avc3", EME_CODEC_AVC1},  // AVC3 for MP4 and MP2T
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
-    {"hev1", EME_CODEC_MP4_HEVC},  // HEV1.
-    {"hvc1", EME_CODEC_MP4_HEVC},  // HVC1.
+    {"hev1", EME_CODEC_HEVC},  // HEV1.
+    {"hvc1", EME_CODEC_HEVC},  // HVC1.
 #endif
 #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
-    {"dva1", EME_CODEC_MP4_DV_AVC},  // DolbyVision AVC
-    {"dvav", EME_CODEC_MP4_DV_AVC},  // DolbyVision AVC
+    {"dva1", EME_CODEC_DOLBY_VISION_AVC},  // DolbyVision AVC
+    {"dvav", EME_CODEC_DOLBY_VISION_AVC},  // DolbyVision AVC
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
-    {"dvh1", EME_CODEC_MP4_DV_HEVC},  // DolbyVision HEVC
-    {"dvhe", EME_CODEC_MP4_DV_HEVC},  // DolbyVision HEVC
+    {"dvh1", EME_CODEC_DOLBY_VISION_HEVC},  // DolbyVision HEVC
+    {"dvhe", EME_CODEC_DOLBY_VISION_HEVC},  // DolbyVision HEVC
 #endif
 #endif
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 18e6c5a..6d9f018 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -349,6 +349,11 @@
 const base::Feature kHardwareSecureDecryption{
     "HardwareSecureDecryption", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Limits number of media tags loading in parallel to 6. This speeds up
+// preloading of any media that requires multiple requests to preload.
+const base::Feature kLimitParallelMediaPreloading{
+    "LimitParallelMediaPreloading", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables low-delay video rendering in media pipeline on "live" stream.
 const base::Feature kLowDelayVideoRenderingOnLiveStream{
     "low-delay-video-rendering-on-live-stream",
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index ebb96a8f3..c0220d36 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -101,17 +101,16 @@
 MEDIA_EXPORT extern const base::Feature kAutoplayIgnoreWebAudio;
 MEDIA_EXPORT extern const base::Feature kAutoplaySoundSettings;
 MEDIA_EXPORT extern const base::Feature kAv1Decoder;
-MEDIA_EXPORT extern const base::Feature kBackgroundVideoPauseOptimization;
 MEDIA_EXPORT extern const base::Feature kBackgroundSrcVideoTrackOptimization;
-MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoder;
+MEDIA_EXPORT extern const base::Feature kBackgroundVideoPauseOptimization;
 MEDIA_EXPORT extern const base::Feature kD3D11EncryptedMedia;
 MEDIA_EXPORT extern const base::Feature kD3D11VP9Decoder;
+MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoder;
 MEDIA_EXPORT extern const base::Feature kExternalClearKeyForTesting;
 MEDIA_EXPORT extern const base::Feature kHardwareSecureDecryption;
+MEDIA_EXPORT extern const base::Feature kLimitParallelMediaPreloading;
 MEDIA_EXPORT extern const base::Feature kLowDelayVideoRenderingOnLiveStream;
 MEDIA_EXPORT extern const base::Feature kMediaCastOverlayButton;
-MEDIA_EXPORT extern const base::Feature kRecordMediaEngagementScores;
-MEDIA_EXPORT extern const base::Feature kRecordWebAudioEngagement;
 MEDIA_EXPORT extern const base::Feature kMediaEngagementBypassAutoplayPolicies;
 MEDIA_EXPORT extern const base::Feature kMemoryPressureBasedSourceBufferGC;
 MEDIA_EXPORT extern const base::Feature kMojoVideoDecoder;
@@ -124,19 +123,22 @@
 MEDIA_EXPORT extern const base::Feature kPictureInPicture;
 MEDIA_EXPORT extern const base::Feature kPreloadMediaEngagementData;
 MEDIA_EXPORT extern const base::Feature kPreloadMetadataLazyLoad;
-MEDIA_EXPORT extern const base::Feature kResumeBackgroundVideo;
+MEDIA_EXPORT extern const base::Feature kPreloadMetadataSuspend;
 MEDIA_EXPORT extern const base::Feature kRTCVideoDecoderAdapter;
+MEDIA_EXPORT extern const base::Feature kRecordMediaEngagementScores;
+MEDIA_EXPORT extern const base::Feature kRecordWebAudioEngagement;
+MEDIA_EXPORT extern const base::Feature kResumeBackgroundVideo;
 MEDIA_EXPORT extern const base::Feature kSpecCompliantCanPlayThrough;
+MEDIA_EXPORT extern const base::Feature kUnifiedAutoplay;
 MEDIA_EXPORT extern const base::Feature kUseAndroidOverlay;
 MEDIA_EXPORT extern const base::Feature kUseAndroidOverlayAggressively;
+MEDIA_EXPORT extern const base::Feature kUseModernMediaControls;
 MEDIA_EXPORT extern const base::Feature kUseNewMediaCache;
 MEDIA_EXPORT extern const base::Feature kUseR16Texture;
-MEDIA_EXPORT extern const base::Feature kVaapiVP8Encoder;
-MEDIA_EXPORT extern const base::Feature kVideoBlitColorAccuracy;
-MEDIA_EXPORT extern const base::Feature kUnifiedAutoplay;
 MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideo;
 MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideoMS;
-MEDIA_EXPORT extern const base::Feature kUseModernMediaControls;
+MEDIA_EXPORT extern const base::Feature kVaapiVP8Encoder;
+MEDIA_EXPORT extern const base::Feature kVideoBlitColorAccuracy;
 
 #if defined(OS_ANDROID)
 MEDIA_EXPORT extern const base::Feature kMediaControlsExpandGesture;
diff --git a/media/blink/multibuffer_data_source.cc b/media/blink/multibuffer_data_source.cc
index 3d6a8ffb..69198c9 100644
--- a/media/blink/multibuffer_data_source.cc
+++ b/media/blink/multibuffer_data_source.cc
@@ -120,7 +120,7 @@
 
 MultibufferDataSource::MultibufferDataSource(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-    scoped_refptr<UrlData> url_data,
+    scoped_refptr<UrlData> url_data_arg,
     MediaLog* media_log,
     BufferedDataSourceHost* host,
     const DownloadingCB& downloading_cb)
@@ -129,7 +129,6 @@
       loading_(false),
       failed_(false),
       render_task_runner_(task_runner),
-      url_data_(std::move(url_data)),
       stop_signal_received_(false),
       media_has_played_(false),
       single_origin_(true),
@@ -141,13 +140,14 @@
       host_(host),
       downloading_cb_(downloading_cb),
       weak_factory_(this) {
+  url_data_and_loading_state_.SetUrlData(std::move(url_data_arg));
   weak_ptr_ = weak_factory_.GetWeakPtr();
   DCHECK(host_);
   DCHECK(downloading_cb_);
   DCHECK(render_task_runner_->BelongsToCurrentThread());
-  DCHECK(url_data_);
-  url_data_->Use();
-  url_data_->OnRedirect(
+  DCHECK(url_data());
+  url_data()->Use();
+  url_data()->OnRedirect(
       base::Bind(&MultibufferDataSource::OnRedirect, weak_ptr_));
 }
 
@@ -160,7 +160,7 @@
 }
 
 bool MultibufferDataSource::assume_fully_buffered() {
-  return !url_data_->url().SchemeIsHTTPOrHTTPS();
+  return !url_data()->url().SchemeIsHTTPOrHTTPS();
 }
 
 void MultibufferDataSource::SetReader(MultiBufferReader* reader) {
@@ -174,7 +174,7 @@
   DCHECK(render_task_runner_->BelongsToCurrentThread());
 
   SetReader(new MultiBufferReader(
-      url_data_->multibuffer(), first_byte_position, last_byte_position,
+      url_data()->multibuffer(), first_byte_position, last_byte_position,
       base::Bind(&MultibufferDataSource::ProgressCallback, weak_ptr_)));
   reader_->SetIsClientAudioElement(is_client_audio_element_);
   UpdateBufferSizes();
@@ -187,7 +187,7 @@
   lock_.AssertAcquired();
 
   reader_.reset(new MultiBufferReader(
-      url_data_->multibuffer(), first_byte_position, last_byte_position,
+      url_data()->multibuffer(), first_byte_position, last_byte_position,
       base::Bind(&MultibufferDataSource::ProgressCallback, weak_ptr_)));
   UpdateBufferSizes();
 }
@@ -199,6 +199,8 @@
 
   init_cb_ = init_cb;
 
+  url_data_and_loading_state_.SetLoadingState(
+      UrlData::UrlDataWithLoadingState::LoadingState::kPreload);
   CreateResourceLoader(0, kPositionNotSpecified);
 
   // We're not allowed to call Wait() if data is already available.
@@ -236,14 +238,14 @@
     StopLoader();
     return;
   }
-  if (url_data_->url().GetOrigin() != destination->url().GetOrigin()) {
+  if (url_data()->url().GetOrigin() != destination->url().GetOrigin()) {
     single_origin_ = false;
   }
   SetReader(nullptr);
-  url_data_ = destination;
+  url_data_and_loading_state_.SetUrlData(std::move(destination));
 
-  if (url_data_) {
-    url_data_->OnRedirect(
+  if (url_data()) {
+    url_data()->OnRedirect(
         base::Bind(&MultibufferDataSource::OnRedirect, weak_ptr_));
 
     if (init_cb_) {
@@ -285,7 +287,7 @@
 }
 
 bool MultibufferDataSource::DidPassCORSAccessCheck() const {
-  if (url_data_->cors_mode() == UrlData::CORS_UNSPECIFIED)
+  if (url_data()->cors_mode() == UrlData::CORS_UNSPECIFIED)
     return false;
 
   // If init_cb is set, we know initialization is not finished yet.
@@ -297,7 +299,7 @@
 }
 
 bool MultibufferDataSource::DidGetOpaqueResponseViaServiceWorker() const {
-  return url_data_->has_opaque_data();
+  return url_data()->has_opaque_data();
 
   // TODO(falken): Do we need to do something about |init_cb_| like
   // in DidPassCORSAccessCheck()?
@@ -320,6 +322,8 @@
   cancel_on_defer_ = false;
   // Once we start playing, we need preloading.
   preload_ = AUTO;
+  url_data_and_loading_state_.SetLoadingState(
+      UrlData::UrlDataWithLoadingState::LoadingState::kHasPlayed);
   UpdateBufferSizes();
 }
 
@@ -355,6 +359,8 @@
 
 void MultibufferDataSource::OnBufferingHaveEnough(bool always_cancel) {
   DCHECK(render_task_runner_->BelongsToCurrentThread());
+  url_data_and_loading_state_.SetLoadingState(
+      UrlData::UrlDataWithLoadingState::LoadingState::kIdle);
   if (reader_ && (always_cancel || (preload_ == METADATA &&
                                     !media_has_played_ && !IsStreaming()))) {
     cancel_on_defer_ = true;
@@ -374,12 +380,12 @@
 
 int64_t MultibufferDataSource::GetMemoryUsage() const {
   // TODO(hubbe): Make more accurate when url_data_ is shared.
-  return base::checked_cast<int64_t>(url_data_->CachedSize())
-         << url_data_->multibuffer()->block_size_shift();
+  return base::checked_cast<int64_t>(url_data()->CachedSize())
+         << url_data()->multibuffer()->block_size_shift();
 }
 
 GURL MultibufferDataSource::GetUrlAfterRedirects() const {
-  return url_data_->url();
+  return url_data()->url();
 }
 
 void MultibufferDataSource::Read(int64_t position,
@@ -509,7 +515,7 @@
   if (read_op_)
     return;
 
-  url_data_->AddBytesRead(bytes_read_);
+  url_data()->AddBytesRead(bytes_read_);
   bytes_read_ = 0;
 
   if (reader_) {
@@ -585,18 +591,18 @@
 
   // All responses must be successful. Resources that are assumed to be fully
   // buffered must have a known content length.
-  bool success = reader_ && reader_->Available() > 0 && url_data_ &&
+  bool success = reader_ && reader_->Available() > 0 && url_data() &&
                  (!assume_fully_buffered() ||
-                  url_data_->length() != kPositionNotSpecified);
+                  url_data()->length() != kPositionNotSpecified);
 
   if (success) {
     {
       base::AutoLock auto_lock(lock_);
-      total_bytes_ = url_data_->length();
+      total_bytes_ = url_data()->length();
     }
     streaming_ =
         !assume_fully_buffered() && (total_bytes_ == kPositionNotSpecified ||
-                                     !url_data_->range_supported());
+                                     !url_data()->range_supported());
 
     media_log_->SetDoubleProperty("total_bytes",
                                   static_cast<double>(total_bytes_));
@@ -624,7 +630,7 @@
     media_log_->SetBooleanProperty("passed_cors_access_check",
                                    DidPassCORSAccessCheck());
     media_log_->SetBooleanProperty("range_header_supported",
-                                   url_data_->range_supported());
+                                   url_data()->range_supported());
   }
 
   render_task_runner_->PostTask(FROM_HERE,
@@ -728,7 +734,7 @@
   // Increase buffering slowly at a rate of 10% of data downloaded so
   // far, maxing out at the preload size.
   int64_t extra_buffer = std::min(
-      preload, url_data_->BytesReadFromCache() * kSlowPreloadPercentage / 100);
+      preload, url_data()->BytesReadFromCache() * kSlowPreloadPercentage / 100);
 
   // Add extra buffer to preload.
   preload += extra_buffer;
@@ -756,14 +762,14 @@
                    extra_buffer * 3,
                preload_high + pin_backward + extra_buffer);
 
-  if (url_data_->FullyCached() ||
-      (url_data_->length() != kPositionNotSpecified &&
-       url_data_->length() < kDefaultPinSize)) {
+  if (url_data()->FullyCached() ||
+      (url_data()->length() != kPositionNotSpecified &&
+       url_data()->length() < kDefaultPinSize)) {
     // We just make pin_forwards/backwards big enough to encompass the
     // whole file regardless of where we are, with some extra margins.
-    pin_forward = std::max(pin_forward, url_data_->length() * 2);
-    pin_backward = std::max(pin_backward, url_data_->length() * 2);
-    buffer_size = url_data_->length();
+    pin_forward = std::max(pin_forward, url_data()->length() * 2);
+    pin_backward = std::max(pin_backward, url_data()->length() * 2);
+    buffer_size = url_data()->length();
   }
 
   reader_->SetMaxBuffer(buffer_size);
diff --git a/media/blink/multibuffer_data_source.h b/media/blink/multibuffer_data_source.h
index 43d1140c..19d61eb 100644
--- a/media/blink/multibuffer_data_source.h
+++ b/media/blink/multibuffer_data_source.h
@@ -123,6 +123,8 @@
   }
 
  protected:
+  UrlData* url_data() const { return url_data_and_loading_state_.url_data(); }
+
   void OnRedirect(const scoped_refptr<UrlData>& destination);
 
   // A factory method to create a BufferedResourceLoader based on the read
@@ -211,7 +213,7 @@
   const scoped_refptr<base::SingleThreadTaskRunner> render_task_runner_;
 
   // URL of the resource requested.
-  scoped_refptr<UrlData> url_data_;
+  UrlData::UrlDataWithLoadingState url_data_and_loading_state_;
 
   // A resource reader for the media resource.
   std::unique_ptr<MultiBufferReader> reader_;
diff --git a/media/blink/multibuffer_data_source_unittest.cc b/media/blink/multibuffer_data_source_unittest.cc
index 89793c79..284a75df 100644
--- a/media/blink/multibuffer_data_source_unittest.cc
+++ b/media/blink/multibuffer_data_source_unittest.cc
@@ -9,7 +9,9 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "media/base/media_log.h"
+#include "media/base/media_switches.h"
 #include "media/base/mock_filters.h"
 #include "media/base/test_helpers.h"
 #include "media/blink/buffered_data_source_host_impl.h"
@@ -153,6 +155,8 @@
     return last_url_data_;
   }
 
+  size_t load_queue_size() { return loading_queue_.size(); }
+
  private:
   scoped_refptr<TestUrlData> last_url_data_;
 };
@@ -186,7 +190,7 @@
 
   bool downloading() { return downloading_; }
   void set_downloading(bool downloading) { downloading_ = downloading; }
-  bool range_supported() { return url_data_->range_supported(); }
+  bool range_supported() { return url_data()->range_supported(); }
   void CallSeekTask() { SeekTask(); }
 
  private:
@@ -442,7 +446,7 @@
   }
   double data_source_playback_rate() { return data_source_->playback_rate_; }
   bool is_local_source() { return data_source_->assume_fully_buffered(); }
-  scoped_refptr<UrlData> url_data() { return data_source_->url_data_; }
+  scoped_refptr<UrlData> url_data() { return data_source_->url_data(); }
   void set_might_be_reused_from_cache_in_future(bool value) {
     url_data()->set_cacheable(value);
   }
@@ -1747,4 +1751,43 @@
   Stop();
 }
 
+TEST_F(MultibufferDataSourceTest, LoadLimitTest) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitFromCommandLine(kLimitParallelMediaPreloading.name, "");
+
+  StrictMock<MockBufferedDataSourceHost> hosts[7];
+  std::vector<std::unique_ptr<MockMultibufferDataSource>> sources;
+  for (size_t i = 0; i < base::size(hosts); i++) {
+    sources.push_back(std::make_unique<MockMultibufferDataSource>(
+        base::ThreadTaskRunnerHandle::Get(),
+        url_index_->GetByUrl(
+            GURL(std::string(kHttpUrl) + "?" + base::IntToString(i)),
+            UrlData::CORS_UNSPECIFIED),
+        &hosts[i]));
+    sources[i]->SetPreload(preload_);
+    sources[i]->Initialize(base::Bind(&MultibufferDataSourceTest::OnInitialize,
+                                      base::Unretained(this)));
+  }
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1UL, url_index_->load_queue_size());
+}
+
+TEST_F(MultibufferDataSourceTest, LoadLimitTestNoLimit) {
+  StrictMock<MockBufferedDataSourceHost> hosts[7];
+  std::vector<std::unique_ptr<MockMultibufferDataSource>> sources;
+  for (size_t i = 0; i < base::size(hosts); i++) {
+    sources.push_back(std::make_unique<MockMultibufferDataSource>(
+        base::ThreadTaskRunnerHandle::Get(),
+        url_index_->GetByUrl(
+            GURL(std::string(kHttpUrl) + "?" + base::IntToString(i)),
+            UrlData::CORS_UNSPECIFIED),
+        &hosts[i]));
+    sources[i]->SetPreload(preload_);
+    sources[i]->Initialize(base::Bind(&MultibufferDataSourceTest::OnInitialize,
+                                      base::Unretained(this)));
+  }
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(0UL, url_index_->load_queue_size());
+}
+
 }  // namespace media
diff --git a/media/blink/new_session_cdm_result_promise.cc b/media/blink/new_session_cdm_result_promise.cc
index a6ab3f6..e8c2300 100644
--- a/media/blink/new_session_cdm_result_promise.cc
+++ b/media/blink/new_session_cdm_result_promise.cc
@@ -68,6 +68,8 @@
 }
 
 void NewSessionCdmResultPromise::resolve(const std::string& session_id) {
+  DVLOG(1) << __func__ << ": session_id = " << session_id;
+
   // |new_session_created_cb_| uses a WeakPtr<> and may not do anything
   // if the session object has been destroyed.
   SessionInitStatus status = SessionInitStatus::UNKNOWN_STATUS;
@@ -93,6 +95,9 @@
 void NewSessionCdmResultPromise::reject(CdmPromise::Exception exception_code,
                                         uint32_t system_code,
                                         const std::string& error_message) {
+  DVLOG(1) << __func__ << ": system_code = " << system_code
+           << ", error_message = " << error_message;
+
   MarkPromiseSettled();
   ReportCdmResultUMA(uma_name_,
                      ConvertCdmExceptionToResultForUMA(exception_code));
diff --git a/media/blink/resource_multibuffer_data_provider.cc b/media/blink/resource_multibuffer_data_provider.cc
index 221fca59..cfb35c21 100644
--- a/media/blink/resource_multibuffer_data_provider.cc
+++ b/media/blink/resource_multibuffer_data_provider.cc
@@ -80,11 +80,11 @@
   }
 
   // Prepare the request.
-  WebURLRequest request(url_data_->url());
-  request.SetRequestContext(is_client_audio_element_
-                                ? WebURLRequest::kRequestContextAudio
-                                : WebURLRequest::kRequestContextVideo);
-  request.SetHTTPHeaderField(
+  auto request = std::make_unique<WebURLRequest>(url_data_->url());
+  request->SetRequestContext(is_client_audio_element_
+                                 ? WebURLRequest::kRequestContextAudio
+                                 : WebURLRequest::kRequestContextVideo);
+  request->SetHTTPHeaderField(
       WebString::FromUTF8(net::HttpRequestHeaders::kRange),
       WebString::FromUTF8(
           net::HttpByteRange::RightUnbounded(byte_pos()).GetHeaderValue()));
@@ -94,8 +94,8 @@
     // This lets the data reduction proxy know that we don't have anything
     // previously cached data for this resource. We can only send it if this is
     // the first request for this resource.
-    request.SetHTTPHeaderField(WebString::FromUTF8("chrome-proxy"),
-                               WebString::FromUTF8("frfr"));
+    request->SetHTTPHeaderField(WebString::FromUTF8("chrome-proxy"),
+                                WebString::FromUTF8("frfr"));
   }
 
   // We would like to send an if-match header with the request to
@@ -105,7 +105,7 @@
   // along the way. See crbug/504194 and crbug/689989 for more information.
 
   // Disable compression, compression for audio/video doesn't make sense...
-  request.SetHTTPHeaderField(
+  request->SetHTTPHeaderField(
       WebString::FromUTF8(net::HttpRequestHeaders::kAcceptEncoding),
       WebString::FromUTF8("identity;q=1, *;q=0"));
 
@@ -117,15 +117,24 @@
     options.preflight_policy =
         network::mojom::CORSPreflightPolicy::kPreventPreflight;
 
-    request.SetFetchRequestMode(network::mojom::FetchRequestMode::kCORS);
+    request->SetFetchRequestMode(network::mojom::FetchRequestMode::kCORS);
     if (url_data_->cors_mode() != UrlData::CORS_USE_CREDENTIALS) {
-      request.SetFetchCredentialsMode(
+      request->SetFetchCredentialsMode(
           network::mojom::FetchCredentialsMode::kSameOrigin);
     }
   }
+
   active_loader_ =
       url_data_->url_index()->fetch_context()->CreateUrlLoader(options);
-  active_loader_->LoadAsynchronously(request, this);
+
+  url_data_->WaitToLoad(
+      base::BindOnce(&ResourceMultiBufferDataProvider::StartLoading,
+                     weak_factory_.GetWeakPtr(), std::move(request)));
+}
+
+void ResourceMultiBufferDataProvider::StartLoading(
+    std::unique_ptr<WebURLRequest> request) {
+  active_loader_->LoadAsynchronously(*request, this);
 }
 
 /////////////////////////////////////////////////////////////////////////////
diff --git a/media/blink/resource_multibuffer_data_provider.h b/media/blink/resource_multibuffer_data_provider.h
index 1260e70..68f360a 100644
--- a/media/blink/resource_multibuffer_data_provider.h
+++ b/media/blink/resource_multibuffer_data_provider.h
@@ -70,6 +70,10 @@
   // Callback used when we're asked to fetch data after the end of the file.
   void Terminate();
 
+  // At the end of Start(), we potentially wait for other loaders to
+  // finish, when they do a callback calls this function.
+  void StartLoading(std::unique_ptr<blink::WebURLRequest> request);
+
   // Parse a Content-Range header into its component pieces and return true if
   // each of the expected elements was found & parsed correctly.
   // |*instance_size| may be set to kPositionNotSpecified if the range ends in
diff --git a/media/blink/url_index.cc b/media/blink/url_index.cc
index be61b169..6968b19cd 100644
--- a/media/blink/url_index.cc
+++ b/media/blink/url_index.cc
@@ -8,11 +8,13 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/location.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "media/base/media_switches.h"
 #include "media/blink/resource_multibuffer_data_provider.h"
 
 namespace media {
@@ -20,6 +22,18 @@
 const int kBlockSizeShift = 15;  // 1<<15 == 32kb
 const int kUrlMappingTimeoutSeconds = 300;
 
+// Max number of resource preloading in parallel.
+const size_t kMaxParallelPreload = 6;
+
+namespace {
+// Helper function, return max parallel preloads.
+size_t GetMaxParallelPreload() {
+  if (base::FeatureList::IsEnabled(media::kLimitParallelMediaPreloading))
+    return kMaxParallelPreload;
+  return std::numeric_limits<size_t>::max();
+}
+};  // namespace
+
 ResourceMultiBuffer::ResourceMultiBuffer(UrlData* url_data, int block_shift)
     : MultiBuffer(block_shift, url_data->url_index_->lru_),
       url_data_(url_data) {}
@@ -60,6 +74,8 @@
                           BytesReadFromCache() >> 10);
   UMA_HISTOGRAM_MEMORY_KB("Media.BytesReadFromNetwork",
                           BytesReadFromNetwork() >> 10);
+  DCHECK_EQ(0, playing_);
+  DCHECK_EQ(0, preloading_);
 }
 
 std::pair<GURL, UrlData::CORSMode> UrlData::key() const {
@@ -210,6 +226,124 @@
   return multibuffer()->map().size();
 }
 
+UrlData::UrlDataWithLoadingState::UrlDataWithLoadingState() {}
+UrlData::UrlDataWithLoadingState::~UrlDataWithLoadingState() {
+  SetLoadingState(LoadingState::kIdle);
+}
+
+void UrlData::UrlDataWithLoadingState::SetLoadingState(
+    LoadingState loading_state) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!url_data_)
+    return;
+  // Note that we increase loading state first and decrease afterwards to avoid
+  // having the loading/playing counts go to zero temporarily.
+  url_data_->IncreaseLoadersInState(loading_state);
+  url_data_->DecreaseLoadersInState(loading_state_);
+  loading_state_ = loading_state;
+}
+
+void UrlData::UrlDataWithLoadingState::SetUrlData(
+    scoped_refptr<UrlData> url_data) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Note that we increase loading state first and decrease afterwards to avoid
+  // having the loading/playing counts go to zero temporarily.
+  if (url_data)
+    url_data->IncreaseLoadersInState(loading_state_);
+  if (url_data_)
+    url_data_->DecreaseLoadersInState(loading_state_);
+  url_data_ = std::move(url_data);
+}
+
+bool UrlData::IsPreloading() const {
+  return preloading_ > 0 && playing_ == 0;
+}
+
+void UrlData::IncreaseLoadersInState(
+    UrlDataWithLoadingState::LoadingState state) {
+  switch (state) {
+    case UrlDataWithLoadingState::LoadingState::kIdle:
+      break;
+    case UrlDataWithLoadingState::LoadingState::kPreload:
+      preloading_++;
+      break;
+    case UrlDataWithLoadingState::LoadingState::kHasPlayed:
+      playing_++;
+      if (playing_ == 1)
+        url_index_->RemoveLoading(this);
+      break;
+  }
+}
+
+void UrlData::DecreaseLoadersInState(
+    UrlDataWithLoadingState::LoadingState state) {
+  switch (state) {
+    case UrlDataWithLoadingState::LoadingState::kIdle:
+      return;
+    case UrlDataWithLoadingState::LoadingState::kPreload:
+      preloading_--;
+      DCHECK_GE(preloading_, 0);
+      break;
+    case UrlDataWithLoadingState::LoadingState::kHasPlayed:
+      playing_--;
+      DCHECK_GE(playing_, 0);
+      break;
+  }
+  if (preloading_ == 0 && playing_ == 0)
+    url_index_->RemoveLoading(this);
+}
+
+void UrlData::WaitToLoad(base::OnceClosure cb) {
+  // We only limit and queue preloading requests.
+  if (!IsPreloading()) {
+    std::move(cb).Run();
+  } else {
+    waiting_load_callbacks_.emplace_back(std::move(cb));
+    if (waiting_load_callbacks_.size() == 1)
+      url_index_->WaitToLoad(this);
+  }
+}
+
+void UrlData::LoadNow() {
+  // Move the callbacks into local variables in case
+  // any of the callbacks decide to call WaitToLoad().
+  std::vector<base::OnceClosure> waiting_load_callbacks;
+  std::swap(waiting_load_callbacks, waiting_load_callbacks_);
+  for (auto& i : waiting_load_callbacks)
+    std::move(i).Run();
+}
+
+
+void UrlIndex::WaitToLoad(UrlData* url_data) {
+  if (loading_.find(url_data) != loading_.end()) {
+    // Already loading
+    url_data->LoadNow();
+    return;
+  }
+  if (loading_.size() < GetMaxParallelPreload()) {
+    loading_.insert(url_data);
+    url_data->LoadNow();
+    return;
+  }
+  loading_queue_.push_back(url_data);
+}
+
+void UrlIndex::RemoveLoading(UrlData* url_data) {
+  auto i = loading_.find(url_data);
+  if (i == loading_.end())
+    return;
+  loading_.erase(i);
+  while (loading_.size() < GetMaxParallelPreload() && !loading_queue_.empty()) {
+    auto url_data = loading_queue_.front();
+    loading_queue_.pop_front();
+    if (url_data->IsPreloading()) {
+      WaitToLoad(url_data.get());
+    } else {
+      url_data->LoadNow();
+    }
+  }
+}
+
 UrlIndex::UrlIndex(ResourceFetchContext* fetch_context)
     : UrlIndex(fetch_context, kBlockSizeShift) {}
 
@@ -236,6 +370,8 @@
   auto i = indexed_data_.find(url_data->key());
   if (i != indexed_data_.end() && i->second == url_data)
     indexed_data_.erase(i);
+
+  RemoveLoading(url_data.get());
 }
 
 scoped_refptr<UrlData> UrlIndex::GetByUrl(const GURL& gurl,
diff --git a/media/blink/url_index.h b/media/blink/url_index.h
index 2ebaad1..77ea0e4d 100644
--- a/media/blink/url_index.h
+++ b/media/blink/url_index.h
@@ -28,6 +28,7 @@
 
 class ResourceFetchContext;
 class UrlData;
+class UrlIndexTest;
 
 // A multibuffer for loading media resources which knows
 // how to create MultiBufferDataProviders to load data
@@ -60,6 +61,31 @@
   enum CORSMode { CORS_UNSPECIFIED, CORS_ANONYMOUS, CORS_USE_CREDENTIALS };
   typedef std::pair<GURL, CORSMode> KeyType;
 
+  // UrlData keeps track of how many clients are preloading or
+  // playing from this resource. This class encapsulates the
+  // adding and removing of counts to guarantee that the counts
+  // are accurate. Clients who wish to change the loading
+  // counts need to have one of these, assign an UrlData to it
+  // and call SetLoadingState() to releflect what the client is
+  // currently doing.
+  class MEDIA_BLINK_EXPORT UrlDataWithLoadingState {
+   public:
+    UrlDataWithLoadingState();
+    ~UrlDataWithLoadingState();
+
+    enum class LoadingState { kIdle, kPreload, kHasPlayed };
+
+    void SetLoadingState(LoadingState loading_state);
+    void SetUrlData(scoped_refptr<UrlData> url_data);
+    UrlData* url_data() const { return url_data_.get(); }
+
+   private:
+    LoadingState loading_state_ = LoadingState::kIdle;
+    scoped_refptr<UrlData> url_data_;
+    SEQUENCE_CHECKER(sequence_checker_);
+    DISALLOW_COPY_AND_ASSIGN(UrlDataWithLoadingState);
+  };
+
   // Accessors
   const GURL& url() const { return url_; }
 
@@ -149,6 +175,10 @@
   void AddBytesReadFromNetwork(int64_t b) { bytes_read_from_network_ += b; }
   int64_t BytesReadFromNetwork() const { return bytes_read_from_network_; }
 
+  // Call |cb| when it's ok to start preloading an URL.
+  // Note that |cb| may be called directly from inside this function.
+  void WaitToLoad(base::OnceClosure cb);
+
  protected:
   UrlData(const GURL& url, CORSMode cors_mode, UrlIndex* url_index);
   virtual ~UrlData();
@@ -156,11 +186,28 @@
  private:
   friend class ResourceMultiBuffer;
   friend class UrlIndex;
+  friend class UrlIndexTest;
   friend class base::RefCounted<UrlData>;
 
+  // Returns true if one or more clients are prelaoding and no clients
+  // are currently playing.
+  bool IsPreloading() const;
+
+  // Called by url_index when it's time to fire callbacks sent to WaitToLoad().
+  void LoadNow();
+
   void OnEmpty();
   void MergeFrom(const scoped_refptr<UrlData>& other);
 
+  // These two are called from UrlDataWithLoadingState to
+  // increase and decrease |playing_| and |preloading_|.
+  // They will also call the UrlIndex and and tell it to
+  // de-queue other resources waiting to load as needed.
+  void IncreaseLoadersInState(
+      UrlDataWithLoadingState::LoadingState loading_state);
+  void DecreaseLoadersInState(
+      UrlDataWithLoadingState::LoadingState loading_state);
+
   // Url we represent, note that there may be multiple UrlData for
   // the same url.
   const GURL url_;
@@ -215,6 +262,14 @@
   ResourceMultiBuffer multibuffer_;
   std::vector<RedirectCB> redirect_callbacks_;
 
+  // Number of data sources that are currently preloading this url.
+  int preloading_ = 0;
+
+  // Number of data sources that are playing this url.
+  int playing_ = 0;
+
+  std::vector<base::OnceClosure> waiting_load_callbacks_;
+
   base::ThreadChecker thread_checker_;
   DISALLOW_COPY_AND_ASSIGN(UrlData);
 };
@@ -256,11 +311,21 @@
   ResourceFetchContext* fetch_context() const { return fetch_context_; }
   int block_shift() const { return block_shift_; }
 
- private:
+  // Protected rather than private for testing.
+ protected:
   friend class UrlData;
   friend class ResourceMultiBuffer;
+  friend class UrlIndexTest;
   void RemoveUrlData(const scoped_refptr<UrlData>& url_data);
 
+  // Call url_data->LoadNow() when it's ok to start preloading.
+  // Note that LoadNow may be called immediately.
+  void WaitToLoad(UrlData* url_data);
+
+  // Let us know that |url_data| is done preloading. If other resources
+  // are waiting, we will let one of them know it's ok to load now.
+  void RemoveLoading(UrlData* url_data);
+
   // Virtual so we can override it in tests.
   virtual scoped_refptr<UrlData> NewUrlData(const GURL& url,
                                             UrlData::CORSMode cors_mode);
@@ -277,6 +342,9 @@
   // Currently only changed for testing purposes.
   const int block_shift_;
 
+  std::set<UrlData*> loading_;
+  std::deque<scoped_refptr<UrlData>> loading_queue_;
+
   base::MemoryPressureListener memory_pressure_listener_;
 };
 
diff --git a/media/blink/url_index_unittest.cc b/media/blink/url_index_unittest.cc
index 9a309cb..cf84153 100644
--- a/media/blink/url_index_unittest.cc
+++ b/media/blink/url_index_unittest.cc
@@ -8,7 +8,10 @@
 #include <string>
 
 #include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/scoped_feature_list.h"
+#include "media/base/media_switches.h"
 #include "media/blink/url_index.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -26,6 +29,15 @@
     return ret;
   }
 
+  void AddToLoadQueue(UrlData* url_data, base::OnceClosure cb) {
+    url_data->waiting_load_callbacks_.emplace_back(std::move(cb));
+    url_index_.loading_queue_.push_back(url_data);
+  }
+
+  void AddToLoading(UrlData* url_data) {
+    url_index_.loading_.insert(url_data);
+  }
+
   UrlIndex url_index_;
 };
 
@@ -153,4 +165,27 @@
   EXPECT_EQ(b, GetByUrl(url, UrlData::CORS_UNSPECIFIED));
 }
 
+namespace {
+void SetBoolWhenCalled(bool* b) {
+  *b = true;
+}
+};  // namespace
+
+TEST_F(UrlIndexTest, SetLoadingState) {
+  bool called = false;
+  GURL url_a("http://foo.bar.com");
+  scoped_refptr<UrlData> a = GetByUrl(url_a, UrlData::CORS_UNSPECIFIED);
+  AddToLoadQueue(a.get(), base::BindOnce(&SetBoolWhenCalled, &called));
+  UrlData::UrlDataWithLoadingState url_data_with_loading_state;
+  url_data_with_loading_state.SetUrlData(a);
+  EXPECT_FALSE(called);
+  url_data_with_loading_state.SetLoadingState(
+      UrlData::UrlDataWithLoadingState::LoadingState::kPreload);
+  AddToLoading(a.get());
+  EXPECT_FALSE(called);
+  url_data_with_loading_state.SetLoadingState(
+      UrlData::UrlDataWithLoadingState::LoadingState::kHasPlayed);
+  EXPECT_TRUE(called);
+}
+
 }  // namespace media
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc
index 02c4981..61c3e4b 100644
--- a/media/cdm/cdm_adapter.cc
+++ b/media/cdm/cdm_adapter.cc
@@ -659,6 +659,7 @@
 void CdmAdapter::SetServerCertificate(
     const std::vector<uint8_t>& certificate,
     std::unique_ptr<SimpleCdmPromise> promise) {
+  DVLOG(2) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   if (certificate.size() < limits::kMinCertificateLength ||
@@ -677,9 +678,12 @@
     HdcpVersion min_hdcp_version,
     std::unique_ptr<KeyStatusCdmPromise> promise) {
   DCHECK(task_runner_->BelongsToCurrentThread());
+
   uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
+  DVLOG(2) << __func__ << ": promise_id = " << promise_id;
   if (!cdm_->GetStatusForPolicy(promise_id,
                                 ToCdmHdcpVersion(min_hdcp_version))) {
+    DVLOG(1) << __func__ << ": GetStatusForPolicy not supported";
     cdm_promise_adapter_.RejectPromise(
         promise_id, CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0,
         "GetStatusForPolicy not supported.");
@@ -694,6 +698,8 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
+  DVLOG(2) << __func__ << ": promise_id = " << promise_id;
+
   cdm_->CreateSessionAndGenerateRequest(
       promise_id, ToCdmSessionType(session_type),
       ToCdmInitDataType(init_data_type), init_data.data(), init_data.size());
@@ -705,6 +711,9 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
+  DVLOG(2) << __func__ << ": session_id = " << session_id
+           << ", promise_id = " << promise_id;
+
   cdm_->LoadSession(promise_id, ToCdmSessionType(session_type),
                     session_id.data(), session_id.size());
 }
@@ -717,6 +726,9 @@
   DCHECK(!response.empty());
 
   uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
+  DVLOG(2) << __func__ << ": session_id = " << session_id
+           << ", promise_id = " << promise_id;
+
   cdm_->UpdateSession(promise_id, session_id.data(), session_id.size(),
                       response.data(), response.size());
 }
@@ -727,6 +739,9 @@
   DCHECK(!session_id.empty());
 
   uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
+  DVLOG(2) << __func__ << ": session_id = " << session_id
+           << ", promise_id = " << promise_id;
+
   cdm_->CloseSession(promise_id, session_id.data(), session_id.size());
 }
 
@@ -736,6 +751,9 @@
   DCHECK(!session_id.empty());
 
   uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
+  DVLOG(2) << __func__ << ": session_id = " << session_id
+           << ", promise_id = " << promise_id;
+
   cdm_->RemoveSession(promise_id, session_id.data(), session_id.size());
 }
 
@@ -758,19 +776,24 @@
   // TODO(xhwang): Fix External Clear Key key system to be able to set
   // |use_hw_secure_codecs| so that we don't have to check both.
   // TODO(xhwang): Update this logic to support transcryption.
-  if (cdm_config_.use_hw_secure_codecs || cdm_proxy_created_)
+  if (cdm_config_.use_hw_secure_codecs || cdm_proxy_created_) {
+    DVLOG(2) << __func__ << ": GetDecryptor() returns null";
     return nullptr;
+  }
 
   return this;
 }
 
 int CdmAdapter::GetCdmId() const {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  return helper_->GetCdmProxyCdmId();
+  int cdm_id = helper_->GetCdmProxyCdmId();
+  DVLOG(2) << __func__ << ": cdm_id = " << cdm_id;
+  return cdm_id;
 }
 
 void CdmAdapter::RegisterNewKeyCB(StreamType stream_type,
                                   const NewKeyCB& key_added_cb) {
+  DVLOG(3) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   switch (stream_type) {
     case kAudio:
@@ -821,6 +844,7 @@
 
 void CdmAdapter::InitializeAudioDecoder(const AudioDecoderConfig& config,
                                         const DecoderInitCB& init_cb) {
+  DVLOG(2) << __func__ << ": " << config.AsHumanReadableString();
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(!audio_init_cb_);
 
@@ -847,6 +871,7 @@
 
 void CdmAdapter::InitializeVideoDecoder(const VideoDecoderConfig& config,
                                         const DecoderInitCB& init_cb) {
+  DVLOG(2) << __func__ << ": " << config.AsHumanReadableString();
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(!video_init_cb_);
 
@@ -940,7 +965,9 @@
 }
 
 void CdmAdapter::ResetDecoder(StreamType stream_type) {
+  DVLOG(2) << __func__ << ": stream_type = " << stream_type;
   DCHECK(task_runner_->BelongsToCurrentThread());
+
   cdm_->ResetDecoder(ToCdmStreamType(stream_type));
 }
 
@@ -985,12 +1012,15 @@
 
 void CdmAdapter::OnResolveKeyStatusPromise(uint32_t promise_id,
                                            cdm::KeyStatus key_status) {
+  DVLOG(2) << __func__ << ": promise_id = " << promise_id
+           << ", key_status = " << key_status;
   DCHECK(task_runner_->BelongsToCurrentThread());
   cdm_promise_adapter_.ResolvePromise(promise_id,
                                       ToCdmKeyInformationKeyStatus(key_status));
 }
 
 void CdmAdapter::OnResolvePromise(uint32_t promise_id) {
+  DVLOG(2) << __func__ << ": promise_id = " << promise_id;
   DCHECK(task_runner_->BelongsToCurrentThread());
   cdm_promise_adapter_.ResolvePromise(promise_id);
 }
@@ -998,6 +1028,7 @@
 void CdmAdapter::OnResolveNewSessionPromise(uint32_t promise_id,
                                             const char* session_id,
                                             uint32_t session_id_size) {
+  DVLOG(2) << __func__ << ": promise_id = " << promise_id;
   DCHECK(task_runner_->BelongsToCurrentThread());
   cdm_promise_adapter_.ResolvePromise(promise_id,
                                       std::string(session_id, session_id_size));
@@ -1008,6 +1039,11 @@
                                  uint32_t system_code,
                                  const char* error_message,
                                  uint32_t error_message_size) {
+  std::string error_message_str(error_message, error_message_size);
+  DVLOG(2) << __func__ << ": promise_id = " << promise_id
+           << ", exception = " << exception << ", system_code = " << system_code
+           << ", error_message = " << error_message_str;
+
   // This is the central place for library CDM promise rejection. Cannot report
   // this in more generic classes like CdmPromise or CdmPromiseAdapter because
   // they may be used multiple times in one promise chain that involves IPC.
@@ -1021,9 +1057,9 @@
   }
 
   DCHECK(task_runner_->BelongsToCurrentThread());
-  cdm_promise_adapter_.RejectPromise(
-      promise_id, ToMediaExceptionType(exception), system_code,
-      std::string(error_message, error_message_size));
+  cdm_promise_adapter_.RejectPromise(promise_id,
+                                     ToMediaExceptionType(exception),
+                                     system_code, error_message_str);
 }
 
 void CdmAdapter::OnSessionMessage(const char* session_id,
@@ -1031,11 +1067,13 @@
                                   cdm::MessageType message_type,
                                   const char* message,
                                   uint32_t message_size) {
+  std::string session_id_str(session_id, session_id_size);
+  DVLOG(2) << __func__ << ": session_id = " << session_id_str;
   DCHECK(task_runner_->BelongsToCurrentThread());
+
   const uint8_t* message_ptr = reinterpret_cast<const uint8_t*>(message);
   session_message_cb_.Run(
-      std::string(session_id, session_id_size),
-      ToMediaMessageType(message_type),
+      session_id_str, ToMediaMessageType(message_type),
       std::vector<uint8_t>(message_ptr, message_ptr + message_size));
 }
 
@@ -1044,6 +1082,8 @@
                                      bool has_additional_usable_key,
                                      const cdm::KeyInformation* keys_info,
                                      uint32_t keys_info_count) {
+  std::string session_id_str(session_id, session_id_size);
+  DVLOG(2) << __func__ << ": session_id = " << session_id_str;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   CdmKeysInfo keys;
@@ -1064,16 +1104,19 @@
       new_video_key_cb_.Run();
   }
 
-  session_keys_change_cb_.Run(std::string(session_id, session_id_size),
-                              has_additional_usable_key, std::move(keys));
+  session_keys_change_cb_.Run(session_id_str, has_additional_usable_key,
+                              std::move(keys));
 }
 
 void CdmAdapter::OnExpirationChange(const char* session_id,
                                     uint32_t session_id_size,
                                     cdm::Time new_expiry_time) {
+  std::string session_id_str(session_id, session_id_size);
+  DVLOG(2) << __func__ << ": session_id = " << session_id_str
+           << ", new_expiry_time = " << new_expiry_time;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  session_expiration_update_cb_.Run(std::string(session_id, session_id_size),
+  session_expiration_update_cb_.Run(session_id_str,
                                     base::Time::FromDoubleT(new_expiry_time));
 }
 
@@ -1247,6 +1290,9 @@
 }
 
 void CdmAdapter::RequestStorageId(uint32_t version) {
+  DVLOG(2) << __func__ << ": version = " << version;
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
   if (!cdm_config_.allow_persistent_state ||
       !(version == kCurrentStorageIdVersion ||
         version == kRequestLatestStorageIdVersion)) {
diff --git a/mojo/core/ports/message_queue.cc b/mojo/core/ports/message_queue.cc
index 074b35a..0abb713 100644
--- a/mojo/core/ports/message_queue.cc
+++ b/mojo/core/ports/message_queue.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "mojo/core/ports/message_filter.h"
 
@@ -53,6 +54,16 @@
   total_queued_bytes_ -= (*message)->GetSizeIfSerialized();
   heap_.pop_back();
 
+  // We keep the capacity of |heap_| in check so that a large batch of incoming
+  // messages doesn't permanently wreck available memory. The choice of interval
+  // here is somewhat arbitrary.
+  constexpr size_t kHeapMinimumShrinkSize = 16;
+  constexpr size_t kHeapShrinkInterval = 512;
+  if (UNLIKELY(heap_.size() > kHeapMinimumShrinkSize &&
+               heap_.size() % kHeapShrinkInterval == 0)) {
+    heap_.shrink_to_fit();
+  }
+
   next_sequence_num_++;
 }
 
diff --git a/pdf/BUILD.gn b/pdf/BUILD.gn
index ee973f4..044f882 100644
--- a/pdf/BUILD.gn
+++ b/pdf/BUILD.gn
@@ -110,7 +110,18 @@
     }
   }
 
+  source_set("pdf_test_utils") {
+    testonly = true
+    sources = [
+      "test/test_client.cc",
+      "test/test_client.h",
+      "test/test_document_loader.cc",
+      "test/test_document_loader.h",
+    ]
+  }
+
   test("pdf_unittests") {
+    testonly = true
     sources = [
       "chunk_stream_unittest.cc",
       "document_loader_impl_unittest.cc",
@@ -121,6 +132,7 @@
 
     deps = [
       ":pdf",
+      ":pdf_test_utils",
       "//base",
       "//base/test:test_support",
       "//ppapi/c",
@@ -139,6 +151,9 @@
       sources += [
         "pdfium/findtext_unittest.cc",
         "pdfium/pdfium_engine_exports_unittest.cc",
+        "pdfium/pdfium_print_unittest.cc",
+        "pdfium/pdfium_test_base.cc",
+        "pdfium/pdfium_test_base.h",
       ]
       include_dirs = [ "//third_party/pdfium" ]
 
diff --git a/pdf/pdfium/findtext_unittest.cc b/pdf/pdfium/findtext_unittest.cc
index 068c62a..af3e34ea 100644
--- a/pdf/pdfium/findtext_unittest.cc
+++ b/pdf/pdfium/findtext_unittest.cc
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/files/file_util.h"
 #include "base/optional.h"
-#include "base/path_service.h"
-#include "pdf/document_loader.h"
 #include "pdf/pdfium/pdfium_engine.h"
-#include "pdf/url_loader_wrapper.h"
+#include "pdf/pdfium/pdfium_test_base.h"
+#include "pdf/test/test_client.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
 
 using testing::InSequence;
 using testing::_;
@@ -18,82 +15,15 @@
 
 namespace {
 
-class TestDocumentLoader : public DocumentLoader {
+class FindTextTestClient : public TestClient {
  public:
-  TestDocumentLoader(Client* client, const base::FilePath::StringType& pdf_name)
-      : client_(client) {
-    base::FilePath pdf_path;
-    CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &pdf_path));
-    pdf_path = pdf_path.Append(FILE_PATH_LITERAL("pdf"))
-                   .Append(FILE_PATH_LITERAL("test"))
-                   .Append(FILE_PATH_LITERAL("data"))
-                   .Append(pdf_name);
-    CHECK(base::ReadFileToString(pdf_path, &pdf_data_));
-  }
-  ~TestDocumentLoader() override = default;
-
-  // DocumentLoader:
-  bool Init(std::unique_ptr<URLLoaderWrapper> loader,
-            const std::string& url) override {
-    NOTREACHED();
-    return false;
-  }
-
-  bool GetBlock(uint32_t position, uint32_t size, void* buf) const override {
-    if (!IsDataAvailable(position, size))
-      return false;
-
-    memcpy(buf, pdf_data_.data() + position, size);
-    return true;
-  }
-
-  bool IsDataAvailable(uint32_t position, uint32_t size) const override {
-    return position < pdf_data_.size() && size <= pdf_data_.size() &&
-           position + size <= pdf_data_.size();
-  }
-
-  void RequestData(uint32_t position, uint32_t size) override {
-    client_->OnDocumentComplete();
-  }
-
-  bool IsDocumentComplete() const override { return true; }
-
-  uint32_t GetDocumentSize() const override { return pdf_data_.size(); }
-
-  uint32_t BytesReceived() const override { return pdf_data_.size(); }
-
- private:
-  Client* const client_;
-  std::string pdf_data_;
-};
-
-const base::FilePath::CharType* g_test_pdf_name;
-
-std::unique_ptr<DocumentLoader> CreateTestDocumentLoader(
-    DocumentLoader::Client* client) {
-  return std::make_unique<TestDocumentLoader>(client, g_test_pdf_name);
-}
-
-class TestClient : public PDFEngine::Client {
- public:
-  TestClient() = default;
-  ~TestClient() override = default;
+  FindTextTestClient() = default;
+  ~FindTextTestClient() override = default;
 
   // PDFEngine::Client:
   MOCK_METHOD2(NotifyNumberOfFindResultsChanged, void(int, bool));
   MOCK_METHOD1(NotifySelectedFindResultChanged, void((int)));
 
-  bool Confirm(const std::string& message) override { return false; }
-
-  std::string Prompt(const std::string& question,
-                     const std::string& default_answer) override {
-    return std::string();
-  }
-
-  std::string GetURL() override { return std::string(); }
-
-  pp::URLLoader CreateURLLoader() override { return pp::URLLoader(); }
-
   std::vector<SearchStringResult> SearchString(const base::char16* string,
                                                const base::char16* term,
                                                bool case_sensitive) override {
@@ -118,59 +48,18 @@
     return results;
   }
 
-  pp::Instance* GetPluginInstance() override { return nullptr; }
-
-  bool IsPrintPreview() override { return false; }
-
-  uint32_t GetBackgroundColor() override { return 0; }
-
-  float GetToolbarHeightInScreenCoords() override { return 0; }
-
  private:
-  DISALLOW_COPY_AND_ASSIGN(TestClient);
+  DISALLOW_COPY_AND_ASSIGN(FindTextTestClient);
 };
 
 }  // namespace
 
-class FindTextTest : public testing::Test {
- public:
-  FindTextTest() = default;
-  ~FindTextTest() override = default;
-
- protected:
-  void SetUp() override {
-    InitializePDFium();
-  }
-
-  void TearDown() override {
-    PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(nullptr);
-    g_test_pdf_name = nullptr;
-    FPDF_DestroyLibrary();
-  }
-
-  void InitializePDFium() {
-    FPDF_LIBRARY_CONFIG config;
-    config.version = 2;
-    config.m_pUserFontPaths = nullptr;
-    config.m_pIsolate = nullptr;
-    config.m_v8EmbedderSlot = 0;
-    FPDF_InitLibraryWithConfig(&config);
-  }
-
-  void SetDocumentForTest(const base::FilePath::CharType* test_pdf_name) {
-    g_test_pdf_name = test_pdf_name;
-    PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(
-        &CreateTestDocumentLoader);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FindTextTest);
-};
+using FindTextTest = PDFiumTestBase;
 
 TEST_F(FindTextTest, FindText) {
   SetDocumentForTest(FILE_PATH_LITERAL("hello_world2.pdf"));
   pp::URLLoader dummy_loader;
-  TestClient client;
+  FindTextTestClient client;
   PDFiumEngine engine(&client, true);
   ASSERT_TRUE(engine.New("https://chromium.org/dummy.pdf", ""));
   ASSERT_TRUE(engine.HandleDocumentLoad(dummy_loader));
@@ -191,7 +80,7 @@
 TEST_F(FindTextTest, FindHyphenatedText) {
   SetDocumentForTest(FILE_PATH_LITERAL("spanner.pdf"));
   pp::URLLoader dummy_loader;
-  TestClient client;
+  FindTextTestClient client;
   PDFiumEngine engine(&client, true);
   ASSERT_TRUE(engine.New("https://chromium.org/dummy.pdf", ""));
   ASSERT_TRUE(engine.HandleDocumentLoad(dummy_loader));
@@ -208,4 +97,5 @@
 
   engine.StartFind("application", /*case_sensitive=*/true);
 }
+
 }  // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_print_unittest.cc b/pdf/pdfium/pdfium_print_unittest.cc
new file mode 100644
index 0000000..2cb4372
--- /dev/null
+++ b/pdf/pdfium/pdfium_print_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "pdf/pdfium/pdfium_print.h"
+
+#include "base/stl_util.h"
+#include "ppapi/c/dev/ppp_printing_dev.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_pdf {
+
+using testing::ElementsAre;
+
+TEST(PDFiumPrintTest, GetPageNumbersFromPrintPageNumberRange) {
+  std::vector<uint32_t> page_numbers;
+
+  {
+    PP_PrintPageNumberRange_Dev page_ranges[] = {{0, 2}};
+    page_numbers = PDFiumPrint::GetPageNumbersFromPrintPageNumberRange(
+        &page_ranges[0], base::size(page_ranges));
+    EXPECT_THAT(page_numbers, ElementsAre(0, 1, 2));
+  }
+  {
+    PP_PrintPageNumberRange_Dev page_ranges[] = {{0, 0}, {2, 2}, {4, 5}};
+    page_numbers = PDFiumPrint::GetPageNumbersFromPrintPageNumberRange(
+        &page_ranges[0], base::size(page_ranges));
+    EXPECT_THAT(page_numbers, ElementsAre(0, 2, 4, 5));
+  }
+}
+
+}  // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_test_base.cc b/pdf/pdfium/pdfium_test_base.cc
new file mode 100644
index 0000000..87f4706
--- /dev/null
+++ b/pdf/pdfium/pdfium_test_base.cc
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "pdf/pdfium/pdfium_test_base.h"
+
+#include <memory>
+
+#include "pdf/pdfium/pdfium_engine.h"
+#include "pdf/test/test_document_loader.h"
+
+namespace chrome_pdf {
+
+namespace {
+
+const base::FilePath::CharType* g_test_pdf_name;
+
+std::unique_ptr<DocumentLoader> CreateTestDocumentLoader(
+    DocumentLoader::Client* client) {
+  return std::make_unique<TestDocumentLoader>(client, g_test_pdf_name);
+}
+
+}  // namespace
+
+PDFiumTestBase::PDFiumTestBase() = default;
+
+PDFiumTestBase::~PDFiumTestBase() = default;
+
+void PDFiumTestBase::SetUp() {
+  InitializePDFium();
+}
+
+void PDFiumTestBase::TearDown() {
+  PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(nullptr);
+  g_test_pdf_name = nullptr;
+  FPDF_DestroyLibrary();
+}
+
+void PDFiumTestBase::SetDocumentForTest(
+    const base::FilePath::CharType* pdf_name) {
+  DCHECK(!g_test_pdf_name);
+  g_test_pdf_name = pdf_name;
+  PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(
+      &CreateTestDocumentLoader);
+}
+
+void PDFiumTestBase::InitializePDFium() {
+  FPDF_LIBRARY_CONFIG config;
+  config.version = 2;
+  config.m_pUserFontPaths = nullptr;
+  config.m_pIsolate = nullptr;
+  config.m_v8EmbedderSlot = 0;
+  FPDF_InitLibraryWithConfig(&config);
+}
+
+}  // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_test_base.h b/pdf/pdfium/pdfium_test_base.h
new file mode 100644
index 0000000..90a1447
--- /dev/null
+++ b/pdf/pdfium/pdfium_test_base.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PDF_PDFIUM_PDFIUM_TEST_BASE_H_
+#define PDF_PDFIUM_PDFIUM_TEST_BASE_H_
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_pdf {
+
+class PDFiumTestBase : public testing::Test {
+ public:
+  PDFiumTestBase();
+  ~PDFiumTestBase() override;
+
+ protected:
+  // testing::Test:
+  void SetUp() override;
+  void TearDown() override;
+
+  // Sets the PDF to load for a test. This must be called for tests that use
+  // TestDocumentLoader. See TestDocumentLoader for more info.
+  void SetDocumentForTest(const base::FilePath::CharType* pdf_name);
+
+ private:
+  void InitializePDFium();
+
+  DISALLOW_COPY_AND_ASSIGN(PDFiumTestBase);
+};
+
+}  // namespace chrome_pdf
+
+#endif  // PDF_PDFIUM_PDFIUM_TEST_BASE_H_
diff --git a/pdf/test/test_client.cc b/pdf/test/test_client.cc
new file mode 100644
index 0000000..c3f7118
--- /dev/null
+++ b/pdf/test/test_client.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "pdf/test/test_client.h"
+
+namespace chrome_pdf {
+
+TestClient::TestClient() = default;
+
+TestClient::~TestClient() = default;
+
+bool TestClient::Confirm(const std::string& message) {
+  return false;
+}
+
+std::string TestClient::Prompt(const std::string& question,
+                               const std::string& default_answer) {
+  return std::string();
+}
+
+std::string TestClient::GetURL() {
+  return std::string();
+}
+
+pp::URLLoader TestClient::CreateURLLoader() {
+  return pp::URLLoader();
+}
+
+pp::Instance* TestClient::GetPluginInstance() {
+  return nullptr;
+}
+
+bool TestClient::IsPrintPreview() {
+  return false;
+}
+
+uint32_t TestClient::GetBackgroundColor() {
+  return 0;
+}
+
+float TestClient::GetToolbarHeightInScreenCoords() {
+  return 0;
+}
+
+}  // namespace chrome_pdf
diff --git a/pdf/test/test_client.h b/pdf/test/test_client.h
new file mode 100644
index 0000000..0540879
--- /dev/null
+++ b/pdf/test/test_client.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PDF_TEST_TEST_CLIENT_H_
+#define PDF_TEST_TEST_CLIENT_H_
+
+#include <string>
+
+#include "pdf/pdf_engine.h"
+
+namespace chrome_pdf {
+
+class TestClient : public PDFEngine::Client {
+ public:
+  TestClient();
+  ~TestClient() override;
+
+  // PDFEngine::Client:
+  bool Confirm(const std::string& message) override;
+  std::string Prompt(const std::string& question,
+                     const std::string& default_answer) override;
+  std::string GetURL() override;
+  pp::URLLoader CreateURLLoader() override;
+  pp::Instance* GetPluginInstance() override;
+  bool IsPrintPreview() override;
+  uint32_t GetBackgroundColor() override;
+  float GetToolbarHeightInScreenCoords() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestClient);
+};
+
+}  // namespace chrome_pdf
+
+#endif  // PDF_TEST_TEST_CLIENT_H_
diff --git a/pdf/test/test_document_loader.cc b/pdf/test/test_document_loader.cc
new file mode 100644
index 0000000..6a7bc5c
--- /dev/null
+++ b/pdf/test/test_document_loader.cc
@@ -0,0 +1,68 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "pdf/test/test_document_loader.h"
+
+#include "base/base_paths.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "pdf/url_loader_wrapper.h"
+
+namespace chrome_pdf {
+
+TestDocumentLoader::TestDocumentLoader(
+    Client* client,
+    const base::FilePath::StringType& pdf_name)
+    : client_(client) {
+  base::FilePath pdf_path;
+  CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &pdf_path));
+  pdf_path = pdf_path.Append(FILE_PATH_LITERAL("pdf"))
+                 .Append(FILE_PATH_LITERAL("test"))
+                 .Append(FILE_PATH_LITERAL("data"))
+                 .Append(pdf_name);
+  CHECK(base::ReadFileToString(pdf_path, &pdf_data_));
+}
+
+TestDocumentLoader::~TestDocumentLoader() = default;
+
+bool TestDocumentLoader::Init(std::unique_ptr<URLLoaderWrapper> loader,
+                              const std::string& url) {
+  NOTREACHED();
+  return false;
+}
+
+bool TestDocumentLoader::GetBlock(uint32_t position,
+                                  uint32_t size,
+                                  void* buf) const {
+  if (!IsDataAvailable(position, size))
+    return false;
+
+  memcpy(buf, pdf_data_.data() + position, size);
+  return true;
+}
+
+bool TestDocumentLoader::IsDataAvailable(uint32_t position,
+                                         uint32_t size) const {
+  return position < pdf_data_.size() && size <= pdf_data_.size() &&
+         position + size <= pdf_data_.size();
+}
+
+void TestDocumentLoader::RequestData(uint32_t position, uint32_t size) {
+  client_->OnDocumentComplete();
+}
+
+bool TestDocumentLoader::IsDocumentComplete() const {
+  return true;
+}
+
+uint32_t TestDocumentLoader::GetDocumentSize() const {
+  return pdf_data_.size();
+}
+
+uint32_t TestDocumentLoader::BytesReceived() const {
+  return pdf_data_.size();
+}
+
+}  // namespace chrome_pdf
diff --git a/pdf/test/test_document_loader.h b/pdf/test/test_document_loader.h
new file mode 100644
index 0000000..4068c9da
--- /dev/null
+++ b/pdf/test/test_document_loader.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PDF_TEST_TEST_DOCUMENT_LOADER_H_
+#define PDF_TEST_TEST_DOCUMENT_LOADER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "pdf/document_loader.h"
+
+namespace chrome_pdf {
+
+// Loads test PDFs from pdf/test/data.
+class TestDocumentLoader : public DocumentLoader {
+ public:
+  // |pdf_name| is the base name for a PDF file.
+  TestDocumentLoader(Client* client,
+                     const base::FilePath::StringType& pdf_name);
+  ~TestDocumentLoader() override;
+
+  // DocumentLoader:
+  bool Init(std::unique_ptr<URLLoaderWrapper> loader,
+            const std::string& url) override;
+  bool GetBlock(uint32_t position, uint32_t size, void* buf) const override;
+  bool IsDataAvailable(uint32_t position, uint32_t size) const override;
+  void RequestData(uint32_t position, uint32_t size) override;
+  bool IsDocumentComplete() const override;
+  uint32_t GetDocumentSize() const override;
+  uint32_t BytesReceived() const override;
+
+ private:
+  Client* const client_;
+  std::string pdf_data_;
+};
+
+}  // namespace chrome_pdf
+
+#endif  // PDF_TEST_TEST_DOCUMENT_LOADER_H_
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index f609019..1594e7e 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -868,14 +868,14 @@
     // since the concern is the effect that entering suspend mode has on
     // sockets. See https://crbug.com/651120.
     if (pending_write_)
-      CompletePendingWrite();
+      CompletePendingWrite(url_request_->status().is_success());
     NotifyCompleted(url_request_->status().ToNetError());
     // |this| will have been deleted.
     return;
   }
 
   if (complete_read) {
-    CompletePendingWrite();
+    CompletePendingWrite(true /* success */);
   }
   if (completed_synchronously) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -1012,9 +1012,18 @@
   response_ = nullptr;
 }
 
-void URLLoader::CompletePendingWrite() {
-  response_body_stream_ =
-      pending_write_->Complete(pending_write_buffer_offset_);
+void URLLoader::CompletePendingWrite(bool success) {
+  if (success) {
+    // The write can only be completed immediately in case of a success, since
+    // doing so invalidates memory of any attached NetToMojoIOBuffer's; but in
+    // case of an abort, particularly one caused by a suspend, the failure may
+    // be delivered to URLLoader while the disk_cache layer is still hanging on
+    // to the now-invalid IOBuffer in some worker thread trying to commit it to
+    // disk.  In case of an error, this will have to wait till everything is
+    // destroyed.
+    response_body_stream_ =
+        pending_write_->Complete(pending_write_buffer_offset_);
+  }
   total_written_bytes_ += pending_write_buffer_offset_;
   pending_write_ = nullptr;
   pending_write_buffer_offset_ = 0;
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
index cf4c5af..1b14cd7 100644
--- a/services/network/url_loader.h
+++ b/services/network/url_loader.h
@@ -142,7 +142,7 @@
   void OnResponseBodyStreamReady(MojoResult result);
   void DeleteSelf();
   void SendResponseToClient();
-  void CompletePendingWrite();
+  void CompletePendingWrite(bool success);
   void SetRawResponseHeaders(scoped_refptr<const net::HttpResponseHeaders>);
   void SendUploadProgress(const net::UploadProgress& progress);
   void OnUploadProgressACK();
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 320a91e..2db1d9b 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -268,6 +268,68 @@
   DISALLOW_COPY_AND_ASSIGN(EternalSyncReadsInterceptor);
 };
 
+// Simulates handing over things to the disk to write before returning to the
+// caller.
+class URLRequestSimulatedCacheJob : public net::URLRequestJob {
+ public:
+  // If |fill_entire_buffer| is true, each read fills the entire read buffer at
+  // once. Otherwise, one byte is read at a time.
+  URLRequestSimulatedCacheJob(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate,
+      scoped_refptr<net::IOBuffer>* simulated_cache_dest)
+      : URLRequestJob(request, network_delegate),
+        simulated_cache_dest_(simulated_cache_dest),
+        weak_factory_(this) {}
+
+  // net::URLRequestJob implementation:
+  void Start() override {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&URLRequestSimulatedCacheJob::StartAsync,
+                                  weak_factory_.GetWeakPtr()));
+  }
+
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override {
+    DCHECK_GT(buf_size, 0);
+
+    // Pretend this is the entire network stack, which has sent the buffer
+    // to some worker thread to be written to disk.
+    memset(buf->data(), 'a', buf_size);
+    *simulated_cache_dest_ = buf;
+
+    // The network stack will not report the read result until the write
+    // completes.
+    return net::ERR_IO_PENDING;
+  }
+
+ private:
+  ~URLRequestSimulatedCacheJob() override {}
+  void StartAsync() { NotifyHeadersComplete(); }
+
+  scoped_refptr<net::IOBuffer>* simulated_cache_dest_;
+  base::WeakPtrFactory<URLRequestSimulatedCacheJob> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(URLRequestSimulatedCacheJob);
+};
+
+class SimulatedCacheInterceptor : public net::URLRequestInterceptor {
+ public:
+  explicit SimulatedCacheInterceptor(
+      scoped_refptr<net::IOBuffer>* simulated_cache_dest)
+      : simulated_cache_dest_(simulated_cache_dest) {}
+
+  net::URLRequestJob* MaybeInterceptRequest(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override {
+    return new URLRequestSimulatedCacheJob(request, network_delegate,
+                                           simulated_cache_dest_);
+  }
+
+ private:
+  scoped_refptr<net::IOBuffer>* simulated_cache_dest_;
+  DISALLOW_COPY_AND_ASSIGN(SimulatedCacheInterceptor);
+};
+
 class RequestInterceptor : public net::URLRequestInterceptor {
  public:
   using InterceptCallback = base::Callback<void(net::URLRequest*)>;
@@ -1988,6 +2050,54 @@
   unowned_power_monitor_source->Resume();
 }
 
+TEST_F(URLLoaderTest, EnterSuspendDiskCacheWriteQueued) {
+  // Test to make sure that fetch abort on suspend doesn't yank out the backing
+  // for IOBuffer for an issued disk_cache Write.
+
+  GURL url("http://www.example.com");
+  scoped_refptr<net::IOBuffer> simulated_cache_dest;
+  net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+      url, std::make_unique<SimulatedCacheInterceptor>(&simulated_cache_dest));
+
+  std::unique_ptr<TestPowerMonitorSource> power_monitor_source =
+      std::make_unique<TestPowerMonitorSource>();
+  TestPowerMonitorSource* unowned_power_monitor_source =
+      power_monitor_source.get();
+  base::PowerMonitor power_monitor(std::move(power_monitor_source));
+
+  ResourceRequest request = CreateResourceRequest("GET", url);
+
+  base::RunLoop delete_run_loop;
+  mojom::URLLoaderPtr loader;
+  std::unique_ptr<URLLoader> url_loader;
+  mojom::URLLoaderFactoryParams params;
+  params.process_id = mojom::kBrowserProcessId;
+  params.is_corb_enabled = false;
+  url_loader = std::make_unique<URLLoader>(
+      context(), nullptr /* network_service_client */,
+      DeleteLoaderCallback(&delete_run_loop, &url_loader),
+      mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request, false,
+      client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
+      0 /* request_id */, resource_scheduler_client(), nullptr,
+      nullptr /* network_usage_accumulator */);
+
+  // Spin until the job has produced a (simulated) cache write.
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(simulated_cache_dest);
+
+  unowned_power_monitor_source->Suspend();
+
+  client()->RunUntilComplete();
+
+  EXPECT_EQ(net::ERR_ABORTED, client()->completion_status().error_code);
+  delete_run_loop.Run();
+
+  unowned_power_monitor_source->Resume();
+
+  // The "cache write" should still have data available.
+  EXPECT_EQ('a', simulated_cache_dest->data()[0]);
+}
+
 class FakeSSLPrivateKeyImpl : public network::mojom::SSLPrivateKey {
  public:
   explicit FakeSSLPrivateKeyImpl(
diff --git a/services/ws/input_devices/input_device_unittests.cc b/services/ws/input_devices/input_device_unittests.cc
index ad2c3f5..a45f806 100644
--- a/services/ws/input_devices/input_device_unittests.cc
+++ b/services/ws/input_devices/input_device_unittests.cc
@@ -128,8 +128,8 @@
 
 TEST_F(InputDeviceTest, AddDeviceAfterComplete) {
   const ui::InputDevice keyboard1(100, ui::INPUT_DEVICE_INTERNAL, "Keyboard1");
-  const ui::InputDevice keyboard2(200, ui::INPUT_DEVICE_EXTERNAL, "Keyboard2");
-  const ui::InputDevice mouse(300, ui::INPUT_DEVICE_EXTERNAL, "Mouse");
+  const ui::InputDevice keyboard2(200, ui::INPUT_DEVICE_USB, "Keyboard2");
+  const ui::InputDevice mouse(300, ui::INPUT_DEVICE_USB, "Mouse");
 
   TestInputDeviceClient client;
   AddClientAsObserver(&client);
diff --git a/storage/browser/fileapi/README.md b/storage/browser/fileapi/README.md
new file mode 100644
index 0000000..ced2bcfe
--- /dev/null
+++ b/storage/browser/fileapi/README.md
@@ -0,0 +1,15 @@
+# FileSystem API
+
+This directory contains part of the browser side implementation of various
+filesystem related APIs, as well as interfaces to treat various types of native
+and non-native filesystems mostly the same without having to worry about the
+underlying implementation.
+
+## Related directories
+
+[`//content/browser/fileapi/`](../../../content/browser/fileapi) contains the
+rest of the browser side implementation, while
+[`blink/renderer/modules/filesystem`](../../../third_party/blink/renderer/modules/filesystem)
+contains the renderer side implementation and
+[`blink/public/mojom/filesystem`](../../../third_party/blink/public/mojom/filesystem)
+contains the mojom interfaces for these APIs.
diff --git a/testing/buildbot/filters/webui_polymer2_browser_tests.filter b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
index e6117fb..17a8ff0 100644
--- a/testing/buildbot/filters/webui_polymer2_browser_tests.filter
+++ b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
@@ -288,6 +288,7 @@
 PrintPreviewModelTest.*
 PrintPreviewNewDestinationSearchTest.*
 PrintPreviewNumberSettingsSectionTest.*
+PrintPreviewPagesSettingsTest.*
 PrintPreviewPolicyTest.*
 PrintPreviewPreviewGenerationTest.*
 PrintPreviewPrintButtonTest.*
diff --git a/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter b/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter
index e8f5f670..4d638837 100644
--- a/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter
+++ b/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter
@@ -15,5 +15,4 @@
 MaterialHistoryFocusTest.All
 PrintPreviewDestinationDialogInteractiveTest.FocusSearchBox
 PrintPreviewPrintHeaderInteractiveTest.FocusPrintOnReady
-PrintPreviewPagesSettingsTest.*
 SettingsUIBrowserTest.All
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py
index f5a8cb0..d2e11b0 100755
--- a/testing/buildbot/generate_buildbot_json.py
+++ b/testing/buildbot/generate_buildbot_json.py
@@ -557,7 +557,7 @@
         result, test_name, tester_name, tester_config, waterfall)
     return result
 
-  def substitute_gpu_args(self, tester_config, args):
+  def substitute_gpu_args(self, tester_config, swarming_config, args):
     substitutions = {
       # Any machine in waterfalls.pyl which desires to run GPU tests
       # must provide the os_type key.
@@ -565,7 +565,7 @@
       'gpu_vendor_id': '0',
       'gpu_device_id': '0',
     }
-    dimension_set = tester_config['swarming']['dimension_sets'][0]
+    dimension_set = swarming_config['dimension_sets'][0]
     if 'gpu' in dimension_set:
       # First remove the driver version, then split into vendor and device.
       gpu = dimension_set['gpu']
@@ -610,7 +610,7 @@
       '--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc',
     ] + args
     result['args'] = self.maybe_fixup_args_array(self.substitute_gpu_args(
-      tester_config, args))
+      tester_config, result['swarming'], args))
     return result
 
   def get_test_generator_map(self):
@@ -729,7 +729,13 @@
     if not 'swarming_mixins' in test:
       return test
 
-    must_be_list(test['swarming_mixins'], 'test', test['test'])
+    test_name = test.get('name')
+    if not test_name:
+      test_name = test.get('test')
+    if not test_name: # pragma: no cover
+      # Not the best name, but we should say something.
+      test_name = str(test)
+    must_be_list(test['swarming_mixins'], 'test', test_name)
     for mixin in test['swarming_mixins']:
       valid_mixin(mixin)
       test = self.apply_swarming_mixin(self.swarming_mixins[mixin], test)
diff --git a/testing/buildbot/generate_buildbot_json_unittest.py b/testing/buildbot/generate_buildbot_json_unittest.py
index 2c32627..bc22253 100755
--- a/testing/buildbot/generate_buildbot_json_unittest.py
+++ b/testing/buildbot/generate_buildbot_json_unittest.py
@@ -162,6 +162,24 @@
 ]
 """
 
+FOO_GPU_TELEMETRY_TEST_DIMENSIONS_WATERFALL = """\
+[
+  {
+    'name': 'chromium.test',
+    'machines': {
+      'Fake Tester': {
+        'swarming_mixins': ['dimension_mixin'],
+        'os_type': 'win',
+        'browser_config': 'release',
+        'test_suites': {
+          'gpu_telemetry_tests': 'foo_tests',
+        },
+      },
+    },
+  },
+]
+"""
+
 # Swarming mixins must be a list, a single string is not allowed.
 FOO_GTESTS_INVALID_LIST_MIXIN_WATERFALL = """\
 [
@@ -1466,6 +1484,41 @@
 }
 """
 
+GPU_DIMENSIONS_WATERFALL_OUTPUT = """\
+{
+  "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {},
+  "AAAAA2 See generate_buildbot_json.py to make changes": {},
+  "Fake Tester": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "foo_test",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "foo_test",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "iama": "mixin",
+              "integrity": "high"
+            }
+          ],
+          "expiration": 120,
+          "idempotent": false,
+          "value": "test"
+        }
+      }
+    ]
+  }
+}
+"""
+
 LUCI_MILO_CFG = """\
 consoles {
   builders {
@@ -2178,6 +2231,16 @@
     fbb.check_output_file_consistency(verbose=True)
     self.assertFalse(fbb.printed_lines)
 
+  def test_swarming_mixins_dimension_gpu(self):
+    fbb = FakeBBGen(FOO_GPU_TELEMETRY_TEST_DIMENSIONS_WATERFALL,
+                    FOO_TEST_SUITE_WITH_MIXIN,
+                    EMPTY_PYL_FILE,
+                    SWARMING_MIXINS,
+                    LUCI_MILO_CFG)
+    fbb.files['chromium.test.json'] = GPU_DIMENSIONS_WATERFALL_OUTPUT
+    fbb.check_output_file_consistency(verbose=True)
+    self.assertFalse(fbb.printed_lines)
+
   def test_swarming_mixins_unreferenced(self):
     fbb = FakeBBGen(FOO_GTESTS_WATERFALL,
                     FOO_TEST_SUITE_WITH_MIXIN,
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index b1f2470d..d70ae81 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -1917,3 +1917,4 @@
 # Tests that work only when LazyImageLoading feature is enabled.
 crbug.com/846170 http/tests/lazyload/lazy.html [ WontFix ]
 crbug.com/846170 http/tests/lazyload/attribute.html [ WontFix ]
+crbug.com/846170 http/tests/lazyload/fixed-dimension.html [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index e06ff7c1..7017ec0 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -4818,7 +4818,7 @@
 
 # Sheriff 2018-06-07
 crbug.com/850395 virtual/gpu/fast/canvas/canvas-filter-stroke-paint-pattern.html [ Pass Failure ]
-crbug.com/850358 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Pass Failure ]
+crbug.com/850358 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Pass Failure Timeout ]
 crbug.com/849978 http/tests/devtools/elements/styles-4/stylesheet-source-url-comment.js [ Pass Failure ]
 
 # Sheriff 2018-06-08
@@ -5234,3 +5234,6 @@
 # Sheriff 2018-09-24
 crbug.com/888634 external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure ]
 crbug.com/888634 virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure ]
+
+# Sheriff 2018-09-25
+crbug.com/888609 [ Mac ] http/tests/devtools/coverage/gutter-css.js [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-fieldset-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-fieldset-001.html
new file mode 100644
index 0000000..f924247
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-fieldset-001.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on fieldset</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-fieldset-001-ref.html">
+<meta name=assert content="Size containment does apply to fieldsets, thus their size is the same than if they don't have contents.">
+<style>
+fieldset {
+  contain: size;
+  display: inline-block;
+  color: transparent;
+  border: none;
+  padding: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a small space, and then the word "after".</p>
+before<fieldset><legend>legend</legend></fieldset>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-fieldset-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-fieldset-001-ref.html
new file mode 100644
index 0000000..85f5c73
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-fieldset-001-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Reference file</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+fieldset {
+  display: inline-block;
+  color: transparent;
+  border: none;
+  padding: 0;
+}
+</style>
+
+<p>This test passes if it has the same output as the reference. You see the word "before", a small space, and then the word "after".</p>
+before<fieldset></fieldset>after
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
similarity index 83%
rename from third_party/WebKit/LayoutTests/platform/win/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
rename to third_party/WebKit/LayoutTests/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
index 35c73a83..d7cfc19 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
@@ -1,326 +1,326 @@
 This is a testharness.js-based test.
-Found 324 tests; 168 PASS, 156 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 324 tests; 180 PASS, 144 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is
 PASS horizontal-tb ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
+PASS horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels
+PASS horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels
 PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
+PASS horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained
 PASS horizontal-tb ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is
 PASS horizontal-tb ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
+PASS horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels
+PASS horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels
 PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
+PASS horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained
 PASS horizontal-tb ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is
 PASS horizontal-tb ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px"
-FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px"
+FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 PASS horizontal-tb ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL horizontal-tb ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
 PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is
 PASS horizontal-tb ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px"
-FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px"
+FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 PASS horizontal-tb ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL horizontal-tb ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
 PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is
 PASS horizontal-tb ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px"
+FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 FAIL horizontal-tb ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL horizontal-tb ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL horizontal-tb ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
 PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is
 PASS horizontal-tb ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px"
+FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 FAIL horizontal-tb ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL horizontal-tb ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL horizontal-tb ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
 PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is
 PASS horizontal-tb rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
+PASS horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels
+PASS horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels
 PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
+PASS horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained
 PASS horizontal-tb rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is
 PASS horizontal-tb rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
+PASS horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels
+PASS horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels
 PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
+PASS horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained
 PASS horizontal-tb rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is
 PASS horizontal-tb rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px"
-FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px"
+FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 PASS horizontal-tb rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL horizontal-tb rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
 PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is
 PASS horizontal-tb rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px"
-FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px"
+FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 PASS horizontal-tb rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL horizontal-tb rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
 PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is
 PASS horizontal-tb rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px"
+FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 FAIL horizontal-tb rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL horizontal-tb rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL horizontal-tb rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
 PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is
 PASS horizontal-tb rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px"
+FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 FAIL horizontal-tb rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL horizontal-tb rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL horizontal-tb rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
 PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is
 PASS vertical-lr ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-lr ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
 PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is
 PASS vertical-lr ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-lr ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
 PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is
 PASS vertical-lr ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is
 PASS vertical-lr ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is
 PASS vertical-lr ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-lr ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-lr ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 PASS vertical-lr ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is
 PASS vertical-lr ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-lr ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-lr ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 PASS vertical-lr ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is
 PASS vertical-lr rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-lr rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
 PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is
 PASS vertical-lr rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-lr rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
 PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is
 PASS vertical-lr rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is
 PASS vertical-lr rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is
 PASS vertical-lr rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-lr rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-lr rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 PASS vertical-lr rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is
 PASS vertical-lr rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-lr rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-lr rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 PASS vertical-lr rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is
 PASS vertical-rl ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-rl ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
 PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is
 PASS vertical-rl ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-rl ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
 PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is
 PASS vertical-rl ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-rl ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
 PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is
 PASS vertical-rl ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-rl ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
 PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is
 PASS vertical-rl ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-rl ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-rl ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-rl ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is
 PASS vertical-rl ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-rl ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-rl ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-rl ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is
 PASS vertical-rl rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-rl rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
 PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is
 PASS vertical-rl rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-rl rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
 PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is
 PASS vertical-rl rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-rl rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
 PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is
 PASS vertical-rl rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 FAIL vertical-rl rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
 PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is
 PASS vertical-rl rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-rl rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-rl rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-rl rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is
 PASS vertical-rl rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-rl rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-rl rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-rl rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/picture-in-picture/request-picture-in-picture.html b/third_party/WebKit/LayoutTests/external/wpt/picture-in-picture/request-picture-in-picture.html
index a0c3217..403d416c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/picture-in-picture/request-picture-in-picture.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/picture-in-picture/request-picture-in-picture.html
@@ -9,8 +9,8 @@
 <script>
 promise_test(async t => {
   const video = await loadVideo();
-  return requestPictureInPictureWithTrustedClick(video);
-}, 'request Picture-in-Picture resolves on user click');
+  return promise_rejects(t, 'NotAllowedError', video.requestPictureInPicture());
+}, 'request Picture-in-Picture requires a user gesture');
 
 promise_test(t => {
   const video = document.createElement('video');
@@ -31,6 +31,6 @@
 
 promise_test(async t => {
   const video = await loadVideo();
-  return promise_rejects(t, 'NotAllowedError', video.requestPictureInPicture());
-}, 'request Picture-in-Picture requires a user gesture');
+  return requestPictureInPictureWithTrustedClick(video);
+}, 'request Picture-in-Picture resolves on user click');
 </script>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
index d6d27674..5b930a3 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
@@ -1,326 +1,326 @@
 This is a testharness.js-based test.
-Found 324 tests; 180 PASS, 144 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 324 tests; 192 PASS, 132 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is
 PASS horizontal-tb ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
+PASS horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels
+PASS horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels
 PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
+PASS horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained
 PASS horizontal-tb ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is
 PASS horizontal-tb ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
+PASS horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels
+PASS horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels
 PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
+PASS horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained
 PASS horizontal-tb ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is
 PASS horizontal-tb ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
+FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 PASS horizontal-tb ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is
 PASS horizontal-tb ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
+FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 PASS horizontal-tb ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is
 PASS horizontal-tb ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
+FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 FAIL horizontal-tb ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL horizontal-tb ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL horizontal-tb ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is
 PASS horizontal-tb ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
+FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 FAIL horizontal-tb ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL horizontal-tb ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL horizontal-tb ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is
 PASS horizontal-tb rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
+PASS horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels
+PASS horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels
 PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
+PASS horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained
 PASS horizontal-tb rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is
 PASS horizontal-tb rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
+PASS horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels
+PASS horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels
 PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
+PASS horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained
 PASS horizontal-tb rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is
 PASS horizontal-tb rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
+FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 PASS horizontal-tb rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is
 PASS horizontal-tb rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
+FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 PASS horizontal-tb rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS horizontal-tb rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
 PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is
 PASS horizontal-tb rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
+FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 FAIL horizontal-tb rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL horizontal-tb rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL horizontal-tb rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is
 PASS horizontal-tb rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
+FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px"
+FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px"
 PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
+FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px"
 FAIL horizontal-tb rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL horizontal-tb rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL horizontal-tb rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is
 PASS vertical-lr ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is
 PASS vertical-lr ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is
 PASS vertical-lr ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is
 PASS vertical-lr ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is
 PASS vertical-lr ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-lr ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-lr ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-lr ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is
 PASS vertical-lr ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-lr ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-lr ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-lr ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is
 PASS vertical-lr rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is
 PASS vertical-lr rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is
 PASS vertical-lr rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is
 PASS vertical-lr rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-lr rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-lr rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is
 PASS vertical-lr rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-lr rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-lr rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-lr rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is
 PASS vertical-lr rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-lr rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-lr rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-lr rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is
 PASS vertical-rl ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is
 PASS vertical-rl ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is
 PASS vertical-rl ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is
 PASS vertical-rl ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-rl ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is
 PASS vertical-rl ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-rl ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-rl ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-rl ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is
 PASS vertical-rl ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-rl ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-rl ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-rl ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is
 PASS vertical-rl rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is
 PASS vertical-rl rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
+FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
+FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is
 PASS vertical-rl rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
 PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is
 PASS vertical-rl rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 PASS vertical-rl rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
 PASS vertical-rl rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
 PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is
 PASS vertical-rl rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-rl rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-rl rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-rl rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
 PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is
 PASS vertical-rl rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
+FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px"
+FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px"
 PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
+FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px"
 FAIL vertical-rl rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
 FAIL vertical-rl rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
 FAIL vertical-rl rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/will-change/composited-layers-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/will-change/composited-layers-expected.txt
index affc440..b13515b6 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/will-change/composited-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/will-change/composited-layers-expected.txt
@@ -10,7 +10,6 @@
       "name": "LayoutBlockFlow DIV id='willChangeOpacity' class='shouldComposite'",
       "position": [12, 42],
       "bounds": [30, 30],
-      "contentsOpaque": true,
       "backgroundColor": "#008000"
     },
     {
@@ -52,7 +51,6 @@
       "name": "LayoutBlockFlow DIV id='willChangeCombinationThatComposites' class='shouldComposite'",
       "position": [12, 416],
       "bounds": [30, 30],
-      "contentsOpaque": true,
       "backgroundColor": "#008000"
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt
new file mode 100644
index 0000000..02ea3eb2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt
@@ -0,0 +1,40 @@
+Tests that console artifacts can be expanded, collapsed via keyboard.
+
+
+Running: testExpandingTraces
+Evaluating: console.warn("warning")
+Message count: 1
+
+Force selecting index 0
+Viewport virtual selection: 0
+Is trace expanded: NO
+
+ArrowRight:
+Viewport virtual selection: 0
+Is trace expanded: YES
+
+ArrowLeft:
+Viewport virtual selection: 0
+Is trace expanded: NO
+
+Running: testExpandingGroups
+Evaluating: console.group("group"); console.log("log child");
+Message count: 2
+
+Force selecting index 0
+Viewport virtual selection: 0
+Is group expanded: YES
+console-key-expand.js:27 group
+console-key-expand.js:27 log child
+
+ArrowLeft:
+Viewport virtual selection: 0
+Is group expanded: NO
+console-key-expand.js:27 group
+
+ArrowRight:
+Viewport virtual selection: 0
+Is group expanded: YES
+console-key-expand.js:27 group
+console-key-expand.js:27 log child
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js
new file mode 100644
index 0000000..4ac46ed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js
@@ -0,0 +1,92 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests that console artifacts can be expanded, collapsed via keyboard.\n`);
+  await TestRunner.loadModule('console_test_runner');
+  await TestRunner.showPanel('console');
+  ConsoleTestRunner.fixConsoleViewportDimensions(600, 200);
+  await ConsoleTestRunner.waitUntilConsoleEditorLoaded();
+
+  const consoleView = Console.ConsoleView.instance();
+  const viewport = consoleView._viewport;
+  const prompt = consoleView._prompt;
+
+  TestRunner.runTestSuite([
+    async function testExpandingTraces(next) {
+      await clearAndLog(`console.warn("warning")`);
+      forceSelect(0);
+
+      dumpFocus();
+      press('ArrowRight');
+      dumpFocus();
+      press('ArrowLeft');
+      dumpFocus();
+
+      next();
+    },
+
+    async function testExpandingGroups(next) {
+      await clearAndLog(`console.group("group"); console.log("log child");`, 2);
+      forceSelect(0);
+
+      dumpFocus();
+      ConsoleTestRunner.dumpConsoleMessages();
+      press('ArrowLeft');
+      dumpFocus();
+      ConsoleTestRunner.dumpConsoleMessages();
+      press('ArrowRight');
+      dumpFocus();
+      ConsoleTestRunner.dumpConsoleMessages();
+
+      next();
+    },
+  ]);
+
+
+  // Utilities.
+  async function clearAndLog(expression, expectedCount = 1) {
+    consoleView._consoleCleared();
+    TestRunner.addResult(`Evaluating: ${expression}`);
+    await TestRunner.evaluateInPagePromise(expression);
+    await ConsoleTestRunner.waitForConsoleMessagesPromise(expectedCount);
+    await ConsoleTestRunner.waitForPendingViewportUpdates();
+  }
+
+  function forceSelect(index) {
+    TestRunner.addResult(`\nForce selecting index ${index}`);
+    viewport._virtualSelectedIndex = index;
+    viewport._contentElement.focus();
+    viewport._updateFocusedItem();
+  }
+
+  function press(key) {
+    TestRunner.addResult(`\n${key}:`);
+    eventSender.keyDown(key);
+  }
+
+  function dumpFocus() {
+    const firstMessage = consoleView._visibleViewMessages[0];
+    const hasTrace = !!firstMessage.element().querySelector('.console-message-stack-trace-toggle');
+    const hasHiddenStackTrace = firstMessage.element().querySelector('.console-message-stack-trace-wrapper > div.hidden');
+    const hasCollapsedObject = firstMessage.element().querySelector('.console-view-object-properties-section.hidden');
+    const hasExpandedObject = firstMessage.element().querySelector('.console-view-object-properties-section:not(.hidden)');
+
+    TestRunner.addResult(`Viewport virtual selection: ${viewport._virtualSelectedIndex}`);
+
+    if (hasCollapsedObject) {
+      TestRunner.addResult(`Has object: collapsed`);
+    } else if (hasExpandedObject) {
+      TestRunner.addResult(`Has object: expanded`);
+    }
+
+    if (hasTrace) {
+      TestRunner.addResult(`Is trace expanded: ${!hasHiddenStackTrace ? 'YES' : 'NO'}`);
+    }
+    if (firstMessage instanceof Console.ConsoleGroupViewMessage) {
+      const expanded = !firstMessage.collapsed();
+      TestRunner.addResult(`Is group expanded: ${expanded ? 'YES' : 'NO'}`);
+    }
+  }
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits-expected.txt
index cec1d3e..5ecfdc22 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits-expected.txt
@@ -5,7 +5,8 @@
 --------------
 await 0
 was processed:
-(async () => {return (await 0)})()
+(async () => {return (await 0)
+})()
 --------------
 async function foo() { await 0; }
 was ignored.
@@ -21,61 +22,98 @@
 --------------
 var a = await 1
 was processed:
-(async () => {void (a = await 1)})()
+(async () => {void (a = await 1)
+})()
 --------------
 let a = await 1
 was processed:
-(async () => {void (a = await 1)})()
+(async () => {void (a = await 1)
+})()
 --------------
 const a = await 1
 was processed:
-(async () => {void (a = await 1)})()
+(async () => {void (a = await 1)
+})()
 --------------
 for (var i = 0; i < 1; ++i) { await i }
 was processed:
-(async () => {for (void (i = 0); i < 1; ++i) { await i }})()
+(async () => {for (void (i = 0); i < 1; ++i) { await i }
+})()
 --------------
 for (let i = 0; i < 1; ++i) { await i }
 was processed:
-(async () => {for (let i = 0; i < 1; ++i) { await i }})()
+(async () => {for (let i = 0; i < 1; ++i) { await i }
+})()
 --------------
 var {a} = {a:1}, [b] = [1], {c:{d}} = {c:{d: await 1}}
 was processed:
-(async () => {void ( ({a} = {a:1}), ([b] = [1]), ({c:{d}} = {c:{d: await 1}}))})()
+(async () => {void ( ({a} = {a:1}), ([b] = [1]), ({c:{d}} = {c:{d: await 1}}))
+})()
 --------------
 console.log(`${(await {a:1}).a}`)
 was processed:
-(async () => {return (console.log(`${(await {a:1}).a}`))})()
+(async () => {return (console.log(`${(await {a:1}).a}`))
+})()
 --------------
 await 0;function foo() {}
 was processed:
-(async () => {await 0;foo=function foo() {}})()
+(async () => {await 0;foo=function foo() {}
+})()
 --------------
 await 0;class Foo {}
 was processed:
-(async () => {await 0;Foo=class Foo {}})()
+(async () => {await 0;Foo=class Foo {}
+})()
 --------------
 if (await true) { function foo() {} }
 was processed:
-(async () => {if (await true) { foo=function foo() {} }})()
+(async () => {if (await true) { foo=function foo() {} }
+})()
 --------------
 if (await true) { class Foo{} }
 was processed:
-(async () => {if (await true) { class Foo{} }})()
+(async () => {if (await true) { class Foo{} }
+})()
 --------------
 if (await true) { var a = 1; }
 was processed:
-(async () => {if (await true) { void (a = 1); }})()
+(async () => {if (await true) { void (a = 1); }
+})()
 --------------
 if (await true) { let a = 1; }
 was processed:
-(async () => {if (await true) { let a = 1; }})()
+(async () => {if (await true) { let a = 1; }
+})()
 --------------
 var a = await 1; let b = 2; const c = 3;
 was processed:
-(async () => {void (a = await 1); void (b = 2); void (c = 3);})()
+(async () => {void (a = await 1); void (b = 2); void (c = 3);
+})()
 --------------
 let o = await 1, p
 was processed:
-(async () => {void ( (o = await 1), (p=undefined))})()
+(async () => {void ( (o = await 1), (p=undefined))
+})()
+--------------
+for await (const number of asyncRandomNumbers()) {}
+was processed:
+(async () => {for await (const number of asyncRandomNumbers()) {}
+})()
+--------------
+[...(await fetch('url', { method: 'HEAD' })).headers.entries()]
+was processed:
+(async () => {return ([...(await fetch('url', { method: 'HEAD' })).headers.entries()])
+})()
+--------------
+await 1
+//hello
+was processed:
+(async () => {return (await 1)
+//hello
+})()
+--------------
+var {a = await new Promise(resolve => resolve({a:123}))} = {a : 3}
+was processed:
+(async () => {void ({a = await new Promise(resolve => resolve({a:123}))} = {a : 3})
+})()
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits.js b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits.js
index 76c11dac..805bf57 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits.js
@@ -20,7 +20,11 @@
     'if (await true) { var a = 1; }',
     'if (await true) { let a = 1; }',
     'var a = await 1; let b = 2; const c = 3;',
-    'let o = await 1, p'
+    'let o = await 1, p',
+    'for await (const number of asyncRandomNumbers()) {}',
+    '[...(await fetch(\'url\', { method: \'HEAD\' })).headers.entries()]',
+    'await 1\n//hello',
+    'var {a = await new Promise(resolve => resolve({a:123}))} = {a : 3}'
   ];
 
   await TestRunner.loadModule("formatter");
diff --git a/third_party/WebKit/LayoutTests/http/tests/lazyload/fixed-dimension.html b/third_party/WebKit/LayoutTests/http/tests/lazyload/fixed-dimension.html
new file mode 100644
index 0000000..184ed2f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/lazyload/fixed-dimension.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="placeholder.js"></script>
+
+<body>
+  <div style="height:10000px;"></div>
+  <img id="fixed_dimension_img" src='../loading/resources/base-image1.png' width="10" height="10">
+  <img id="large_dimension_img" src='../loading/resources/base-image2.png' width="100" height="100">
+  <img id="percent_dimension_img" src='../loading/resources/base-image3.png' width="10%" height="10%">
+  <img id="fixed_width_only_img" src='../loading/resources/dup-image1.png' width="10">
+  <img id="fixed_height_only_img" src='../loading/resources/dup-image2.png' height="10">
+</body>
+
+<script>
+  async_test(function(t) {
+    window.addEventListener("load", t.step_func_done());
+  }, "Test that document load event is fired");
+
+  async_test(function(t) {
+    var fixed_dimension_img = document.getElementById("fixed_dimension_img");
+    fixed_dimension_img.addEventListener("load",
+      t.step_func_done(function() {
+        assert_true(is_image_fully_loaded(fixed_dimension_img));
+      }));
+  }, "Test that small <img> with fixed height and width is loaded, and not a placeholder");
+
+  async_test(function(t) {
+    var large_dimension_img = document.getElementById("large_dimension_img");
+    var percent_dimension_img = document.getElementById("percent_dimension_img");
+    var fixed_width_only_img = document.getElementById("fixed_width_only_img");
+    var fixed_height_only_img = document.getElementById("fixed_height_only_img");
+    window.addEventListener("load", t.step_func_done(function() {
+      assert_false(is_image_fully_loaded(large_dimension_img));
+      assert_false(is_image_fully_loaded(percent_dimension_img));
+      assert_false(is_image_fully_loaded(fixed_width_only_img));
+      assert_false(is_image_fully_loaded(fixed_height_only_img));
+    }));
+    large_dimension_img.addEventListener("load",
+      t.unreached_func("Load event should not be fired for below viewport image with large fixed dimension"));
+    percent_dimension_img.addEventListener("load",
+      t.unreached_func("Load event should not be fired for below viewport image with percentage dimension"));
+    fixed_width_only_img.addEventListener("load",
+      t.unreached_func("Load event should not be fired for below viewport image with only fixed width"));
+    fixed_height_only_img.addEventListener("load",
+      t.unreached_func("Load event should not be fired for below viewport image with only fixed height"));
+  }, "Test that <img> with non fixed height and width below the viewport is loaded as placeholder");
+</script>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world-expected.txt
new file mode 100644
index 0000000..ff925137
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world-expected.txt
@@ -0,0 +1,14 @@
+Tests that Page.addScriptToEvaluateOnNewDocument is executed in the given world
+Adding scripts
+world#0
+message from 0
+world#1
+message from 1
+world#2
+message from 2
+world#3
+message from 3
+world#4
+message from 4
+Removing scripts
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world.js
new file mode 100644
index 0000000..436034f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world.js
@@ -0,0 +1,33 @@
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startBlank(
+      'Tests that Page.addScriptToEvaluateOnNewDocument is executed in the given world');
+  dp.Runtime.enable();
+  dp.Page.enable();
+
+  const scriptIds = [];
+  dp.Runtime.onConsoleAPICalled(msg => testRunner.log(msg.params.args[0].value));
+  dp.Runtime.onExecutionContextCreated(msg => {
+    if (msg.params.context.name.includes('world'))
+      testRunner.log(msg.params.context.name);
+  });
+
+  testRunner.log('Adding scripts');
+  for (let i = 0; i < 5; ++i) {
+    const result = await dp.Page.addScriptToEvaluateOnNewDocument({source: `
+      console.log('message from ${i}');`, worldName: `world#${i}`});
+    scriptIds.push(result.result.identifier);
+  }
+
+  await session.navigate('../resources/blank.html');
+
+  testRunner.log('Removing scripts');
+  for (let identifier of scriptIds) {
+    const response = await dp.Page.removeScriptToEvaluateOnNewDocument({identifier});
+    if (!response.result)
+      testRunner.log('Failed script removal');
+  }
+
+  await session.navigate('../resources/blank.html');
+
+  testRunner.completeTest();
+})
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load-expected.txt
index 1d2fb125..bed3d35 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load-expected.txt
@@ -1,17 +1,9 @@
 Tests that Page.addScriptToEvaluateOnLoad is executed in the order of addition
+Adding scripts
 message from 0
 message from 1
 message from 2
 message from 3
 message from 4
-message from 5
-message from 6
-message from 7
-message from 8
-message from 9
-message from 10
-message from 11
-message from 12
-message from 13
-message from 14
+Removing scripts
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load.js
index 024683c7..7cd3114 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load.js
@@ -4,13 +4,27 @@
   dp.Runtime.enable();
   dp.Page.enable();
 
+  const scriptIds = [];
   dp.Runtime.onConsoleAPICalled(msg => testRunner.log(msg.params.args[0].value));
 
-  for (let i = 0; i < 15; ++i) {
-    await dp.Page.addScriptToEvaluateOnNewDocument({source: `
+  testRunner.log('Adding scripts');
+  for (let i = 0; i < 5; ++i) {
+    const result = await dp.Page.addScriptToEvaluateOnNewDocument({source: `
       console.log('message from ${i}');
     `});
+    scriptIds.push(result.result.identifier);
   }
+
   await session.navigate('../resources/blank.html');
+
+  testRunner.log('Removing scripts');
+  for (let identifier of scriptIds) {
+    const response = await dp.Page.removeScriptToEvaluateOnNewDocument({identifier});
+    if (!response.result)
+      testRunner.log('Failed script removal');
+  }
+
+  await session.navigate('../resources/blank.html');
+
   testRunner.completeTest();
 })
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
deleted file mode 100644
index 23e57a1..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
+++ /dev/null
@@ -1,328 +0,0 @@
-This is a testharness.js-based test.
-Found 324 tests; 168 PASS, 156 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is
-PASS horizontal-tb ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
-PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
-PASS horizontal-tb ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
-PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is
-PASS horizontal-tb ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
-PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
-PASS horizontal-tb ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
-PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is
-PASS horizontal-tb ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-PASS horizontal-tb ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL horizontal-tb ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is
-PASS horizontal-tb ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-PASS horizontal-tb ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL horizontal-tb ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
-PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is
-PASS horizontal-tb ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is
-PASS horizontal-tb ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
-PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is
-PASS horizontal-tb rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
-PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
-PASS horizontal-tb rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
-PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is
-PASS horizontal-tb rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
-PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
-PASS horizontal-tb rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
-PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is
-PASS horizontal-tb rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-PASS horizontal-tb rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL horizontal-tb rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is
-PASS horizontal-tb rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-PASS horizontal-tb rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL horizontal-tb rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
-PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is
-PASS horizontal-tb rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is
-PASS horizontal-tb rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
-PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is
-PASS vertical-lr ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-lr ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-lr ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is
-PASS vertical-lr ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-lr ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-lr ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
-PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is
-PASS vertical-lr ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-lr ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is
-PASS vertical-lr ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-lr ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is
-PASS vertical-lr ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-lr ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-lr ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-PASS vertical-lr ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is
-PASS vertical-lr ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-lr ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-lr ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-PASS vertical-lr ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is
-PASS vertical-lr rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-lr rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-lr rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is
-PASS vertical-lr rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-lr rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-lr rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
-PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is
-PASS vertical-lr rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-lr rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is
-PASS vertical-lr rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-lr rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is
-PASS vertical-lr rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-lr rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-lr rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-PASS vertical-lr rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is
-PASS vertical-lr rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-lr rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-lr rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-PASS vertical-lr rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value
-PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is
-PASS vertical-rl ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-rl ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is
-PASS vertical-rl ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-rl ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
-PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is
-PASS vertical-rl ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-rl ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
-PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is
-PASS vertical-rl ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-rl ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
-PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is
-PASS vertical-rl ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-rl ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-rl ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL vertical-rl ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
-PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is
-PASS vertical-rl ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-rl ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-rl ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL vertical-rl ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
-PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is
-PASS vertical-rl rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-rl rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is
-PASS vertical-rl rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-rl rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
-PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is
-PASS vertical-rl rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-rl rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
-PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is
-PASS vertical-rl rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-rl rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
-PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is
-PASS vertical-rl rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-rl rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-rl rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL vertical-rl rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
-PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is
-PASS vertical-rl rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-rl rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-rl rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL vertical-rl rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index c240aad9..954d9c3d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index cd081b8..a835d920 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index cd081b8..a835d920 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 141a09f..62388e37 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 09e6437e..60c33430 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 248bfac..5adb1a56 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
deleted file mode 100644
index 23e57a1..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
+++ /dev/null
@@ -1,328 +0,0 @@
-This is a testharness.js-based test.
-Found 324 tests; 168 PASS, 156 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is
-PASS horizontal-tb ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
-PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
-PASS horizontal-tb ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
-PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is
-PASS horizontal-tb ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
-PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
-PASS horizontal-tb ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
-PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is
-PASS horizontal-tb ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-PASS horizontal-tb ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL horizontal-tb ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is
-PASS horizontal-tb ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-PASS horizontal-tb ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL horizontal-tb ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
-PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is
-PASS horizontal-tb ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL horizontal-tb ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is
-PASS horizontal-tb ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL horizontal-tb ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
-PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is
-PASS horizontal-tb rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
-PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
-PASS horizontal-tb rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value
-PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is
-PASS horizontal-tb rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px"
-FAIL horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px"
-PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px"
-PASS horizontal-tb rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value
-PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is
-PASS horizontal-tb rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-PASS horizontal-tb rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL horizontal-tb rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is
-PASS horizontal-tb rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-PASS horizontal-tb rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS horizontal-tb rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL horizontal-tb rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
-PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is
-PASS horizontal-tb rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL horizontal-tb rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is
-PASS horizontal-tb rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px"
-PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL horizontal-tb rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px"
-PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is
-PASS vertical-lr ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-lr ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-lr ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is
-PASS vertical-lr ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-lr ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-lr ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
-PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is
-PASS vertical-lr ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-lr ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is
-PASS vertical-lr ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-lr ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS vertical-lr ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is
-PASS vertical-lr ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-lr ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-lr ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-PASS vertical-lr ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is
-PASS vertical-lr ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-lr ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-lr ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-PASS vertical-lr ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is
-PASS vertical-lr rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-lr rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-lr rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is
-PASS vertical-lr rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-lr rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-lr rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
-PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is
-PASS vertical-lr rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-lr rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is
-PASS vertical-lr rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-lr rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-PASS vertical-lr rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is
-PASS vertical-lr rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-lr rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-lr rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-PASS vertical-lr rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value
-PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is
-PASS vertical-lr rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-lr rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-lr rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-PASS vertical-lr rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value
-PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is
-PASS vertical-rl ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-rl ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is
-PASS vertical-rl ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-rl ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
-PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is
-PASS vertical-rl ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-rl ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
-PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is
-PASS vertical-rl ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-rl ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
-PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is
-PASS vertical-rl ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-rl ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-rl ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL vertical-rl ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
-PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is
-PASS vertical-rl ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-rl ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-rl ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL vertical-rl ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
-PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is
-PASS vertical-rl rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-rl rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px"
-PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is
-PASS vertical-rl rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px"
-FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px"
-PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px"
-PASS vertical-rl rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px"
-PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is
-PASS vertical-rl rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-rl rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
-PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is
-PASS vertical-rl rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-PASS vertical-rl rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value
-PASS vertical-rl rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value
-FAIL vertical-rl rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px"
-PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is
-PASS vertical-rl rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-rl rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-rl rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL vertical-rl rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
-PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is
-PASS vertical-rl rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels
-FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px"
-FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px"
-PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained
-FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px"
-FAIL vertical-rl rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px"
-FAIL vertical-rl rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px"
-FAIL vertical-rl rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
new file mode 100644
index 0000000..954d9c3d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 8a49d59..e8a89cc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
new file mode 100644
index 0000000..a835d920
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 33a04bb..c898f21d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index c389808..412ad62 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index c389808..412ad62 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
deleted file mode 100644
index 3c308d6..0000000
--- a/third_party/WebKit/LayoutTests/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
deleted file mode 100644
index a29dedd3..0000000
--- a/third_party/WebKit/LayoutTests/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 3077647..e322d6f 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -67,10 +67,16 @@
 #endif
 };
 
-// Freeze non-timer task queues in background, after allowed grace time. Launch
-// bug: https://crbug.com/822954. "stop" is a legacy name.
-const base::Feature kStopNonTimersInBackground{
-    "stop-non-timers-in-background", base::FEATURE_DISABLED_BY_DEFAULT};
+// Freeze non-timer task queues in background, after allowed grace time.
+// "stop" is a legacy name.
+const base::Feature kStopNonTimersInBackground {
+  "stop-non-timers-in-background",
+#if defined(OS_ANDROID)
+      base::FEATURE_ENABLED_BY_DEFAULT
+#else
+      base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
 
 // Writable files and native filesystem access. https://crbug.com/853326
 const base::Feature kWritableFilesAPI{"WritableFilesAPI",
diff --git a/third_party/blink/public/mojom/filesystem/file_system.mojom b/third_party/blink/public/mojom/filesystem/file_system.mojom
index d33a4ee..d372a8d 100644
--- a/third_party/blink/public/mojom/filesystem/file_system.mojom
+++ b/third_party/blink/public/mojom/filesystem/file_system.mojom
@@ -72,6 +72,13 @@
   DidReceiveSnapshotFile();
 };
 
+enum ChooseFileSystemEntryType {
+  kOpenFile,
+  kOpenMultipleFiles,
+  kSaveFile,
+  kOpenDirectory
+};
+
 // Interface provided by the browser to the renderer to carry out filesystem
 // operations. All [Sync] methods should only be called synchronously on worker
 // threads (and asynchronously otherwise).
@@ -219,7 +226,7 @@
   // success.
   // TODO(https://crbug.com/878581): Add more options to this method to support
   //     multiple files, directories, "open" vs "save" dialogs, etc.
-  ChooseEntry() =>
+  ChooseEntry(ChooseFileSystemEntryType type) =>
       (mojo_base.mojom.FileError error_code,
        array<FileSystemEntry> entries);
 };
diff --git a/third_party/blink/public/web/web_widget.h b/third_party/blink/public/web/web_widget.h
index 069c531..025c15bf 100644
--- a/third_party/blink/public/web/web_widget.h
+++ b/third_party/blink/public/web/web_widget.h
@@ -84,9 +84,13 @@
 
   // Called to update imperative animation state. This should be called before
   // paint, although the client can rate-limit these calls.
-  // |lastFrameTimeMonotonic| is in seconds.
+  // |last_frame_time| is in seconds.
   virtual void BeginFrame(base::TimeTicks last_frame_time) {}
 
+  // Called when a main frame time metric should be emitted, along with
+  // any metrics that depend upon the main frame total time.
+  virtual void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) {}
+
   // Called to run through the entire set of document lifecycle phases needed
   // to render a frame of the web widget. This MUST be called before Paint,
   // and it may result in calls to WebWidgetClient::didInvalidateRect.
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
index f74801ce..4252f4a 100644
--- a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
+++ b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -54,7 +54,7 @@
     const PropertyRegistry* registry,
     const Document& document)
     : registry_(registry) {
-  allow_all_animations_ = document.GetFrame()->DeprecatedIsFeatureEnabled(
+  allow_all_animations_ = document.IsFeatureEnabled(
       blink::mojom::FeaturePolicyFeature::kAnimations);
 }
 
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 7be10e9..58813ca 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -140,6 +140,7 @@
 #include "third_party/blink/renderer/core/frame/dom_timer.h"
 #include "third_party/blink/renderer/core/frame/dom_visual_viewport.h"
 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
+#include "third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h"
 #include "third_party/blink/renderer/core/frame/frame_console.h"
 #include "third_party/blink/renderer/core/frame/history.h"
 #include "third_party/blink/renderer/core/frame/intervention.h"
@@ -148,6 +149,8 @@
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/performance_monitor.h"
+#include "third_party/blink/renderer/core/frame/report.h"
+#include "third_party/blink/renderer/core/frame/reporting_context.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/frame/viewport_data.h"
@@ -6217,9 +6220,8 @@
   if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
     return true;
   }
-  if (!frame_ || frame_->DeprecatedIsFeatureEnabled(
-                     mojom::FeaturePolicyFeature::kDocumentWrite,
-                     ReportOptions::kReportOnFailure)) {
+  if (!frame_ || IsFeatureEnabled(mojom::FeaturePolicyFeature::kDocumentWrite,
+                                  ReportOptions::kReportOnFailure)) {
     return true;
   }
 
@@ -7604,6 +7606,30 @@
   return *lazy_load_image_observer_;
 }
 
+void Document::ReportFeaturePolicyViolation(
+    mojom::FeaturePolicyFeature feature) const {
+  if (!RuntimeEnabledFeatures::FeaturePolicyReportingEnabled())
+    return;
+  if (!GetFrame())
+    return;
+  const String& feature_name = GetNameForFeature(feature);
+  FeaturePolicyViolationReportBody* body = new FeaturePolicyViolationReportBody(
+      feature_name, "Feature policy violation", SourceLocation::Capture());
+  Report* report = new Report("feature-policy", Url().GetString(), body);
+  ReportingContext::From(this)->QueueReport(report);
+
+  bool is_null;
+  int line_number = body->lineNumber(is_null);
+  line_number = is_null ? 0 : line_number;
+  int column_number = body->columnNumber(is_null);
+  column_number = is_null ? 0 : column_number;
+
+  // Send the feature policy violation report to the Reporting API.
+  GetFrame()->GetReportingService()->QueueFeaturePolicyViolationReport(
+      Url(), feature_name, "Feature policy violation", body->sourceFile(),
+      line_number, column_number);
+}
+
 template class CORE_TEMPLATE_EXPORT Supplement<Document>;
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index f724fb37..bf0c2368 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1466,6 +1466,8 @@
     return agent_cluster_id_;
   }
 
+  void ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature) const override;
+
  protected:
   Document(const DocumentInit&, DocumentClassFlags = kDefaultDocumentClass);
 
diff --git a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
index 0222c99e..db7462a 100644
--- a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
+++ b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
@@ -145,7 +145,7 @@
       UseCounter::Count(node_->GetDocument(),
                         WebFeature::kPerformanceEventTimingConstructor);
       eventTiming = std::make_unique<EventTiming>(frame->DomWindow());
-      eventTiming->WillDispatchEvent(event_);
+      eventTiming->WillDispatchEvent(*event_);
     }
   }
   event_->GetEventPath().EnsureWindowEventContext();
@@ -197,7 +197,7 @@
   DispatchEventPostProcess(activation_target,
                            pre_dispatch_event_handler_result);
   if (eventTiming)
-    eventTiming->DidDispatchEvent(event_);
+    eventTiming->DidDispatchEvent(*event_);
 
   return EventTarget::GetDispatchEventResult(*event_);
 }
diff --git a/third_party/blink/renderer/core/execution_context/security_context.cc b/third_party/blink/renderer/core/execution_context/security_context.cc
index 1ec0c65..6b0cafc9 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.cc
+++ b/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -120,4 +120,17 @@
   feature_policy_->SetHeaderPolicy(parsed_header);
 }
 
+bool SecurityContext::IsFeatureEnabled(mojom::FeaturePolicyFeature feature,
+                                       ReportOptions report_on_failure) const {
+  // The policy should always be initialized before checking it to ensure we
+  // properly inherit the parent policy.
+  DCHECK(feature_policy_);
+
+  if (feature_policy_->IsFeatureEnabled(feature))
+    return true;
+  if (report_on_failure == ReportOptions::kReportOnFailure)
+    ReportFeaturePolicyViolation(feature);
+  return false;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/execution_context/security_context.h b/third_party/blink/renderer/core/execution_context/security_context.h
index 195a58d..f5c4ae9 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.h
+++ b/third_party/blink/renderer/core/execution_context/security_context.h
@@ -29,6 +29,7 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
+#include "third_party/blink/public/common/feature_policy/feature_policy.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/frame/sandbox_flags.h"
@@ -47,6 +48,10 @@
 
 using ParsedFeaturePolicy = std::vector<ParsedFeaturePolicyDeclaration>;
 
+// Whether to report policy violations when checking whether a feature is
+// enabled.
+enum class ReportOptions { kReportOnFailure, kDoNotReport };
+
 namespace mojom {
 enum class IPAddressSpace : int32_t;
 }
@@ -123,6 +128,16 @@
                                const ParsedFeaturePolicy& container_policy,
                                const FeaturePolicy* parent_feature_policy);
 
+  // Tests whether the policy-controlled feature is enabled in this frame.
+  // Optionally sends a report to any registered reporting observers or
+  // Report-To endpoints, via ReportFeaturePolicyViolation(), if the feature is
+  // disabled.
+  bool IsFeatureEnabled(
+      mojom::FeaturePolicyFeature,
+      ReportOptions report_on_failure = ReportOptions::kDoNotReport) const;
+  virtual void ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature) const {
+  }
+
   // Apply the sandbox flag. In addition, if the origin is not already opaque,
   // the origin is updated to a newly created unique opaque origin, setting the
   // potentially trustworthy bit from |is_potentially_trustworthy|.
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index f23aeb9f..c6c7154 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1570,6 +1570,14 @@
   PageWidgetDelegate::Animate(*page_, last_frame_time);
 }
 
+void WebViewImpl::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) {
+  if (!MainFrameImpl())
+    return;
+
+  MainFrameImpl()->GetFrame()->View()->RecordEndOfFrameMetrics(
+      frame_begin_time);
+}
+
 void WebViewImpl::UpdateLifecycle(LifecycleUpdate requested_update) {
   TRACE_EVENT0("blink", "WebViewImpl::updateAllLifecyclePhases");
   if (!MainFrameImpl())
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index 42be0ae..b1399b1 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -116,6 +116,7 @@
 
   void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) override;
   void BeginFrame(base::TimeTicks last_frame_time) override;
+  void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override;
 
   void UpdateLifecycle(LifecycleUpdate requested_update) override;
   void UpdateAllLifecyclePhasesAndCompositeForTesting() override;
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn
index 8b0e7cc..3bd04766 100644
--- a/third_party/blink/renderer/core/frame/BUILD.gn
+++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -88,6 +88,8 @@
     "local_frame.cc",
     "local_frame.h",
     "local_frame_client.h",
+    "local_frame_ukm_aggregator.cc",
+    "local_frame_ukm_aggregator.h",
     "local_frame_view.cc",
     "local_frame_view.h",
     "location.cc",
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index 2ecc05c..c5a5b1b 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -746,7 +746,7 @@
     return;
 
   // If the feature is allowed, don't log a warning.
-  if (frame->DeprecatedIsFeatureEnabled(feature))
+  if (document.IsFeatureEnabled(feature))
     return;
 
   // If the feature is disabled, log a warning but only if the request is from a
diff --git a/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc b/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc
index 5fd0ecc..75ede52 100644
--- a/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc
+++ b/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc
@@ -93,12 +93,10 @@
 
 bool DeviceSingleWindowEventController::CheckPolicyFeatures(
     const Vector<mojom::FeaturePolicyFeature>& features) const {
-  LocalFrame* frame = GetDocument().GetFrame();
-  if (!frame)
-    return false;
+  const Document& document = GetDocument();
   return std::all_of(features.begin(), features.end(),
-                     [frame](mojom::FeaturePolicyFeature feature) {
-                       return frame->DeprecatedIsFeatureEnabled(feature);
+                     [&document](mojom::FeaturePolicyFeature feature) {
+                       return document.IsFeatureEnabled(feature);
                      });
 }
 
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc
index 6e74b71..6d0f0ea 100644
--- a/third_party/blink/renderer/core/frame/frame.cc
+++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -256,18 +256,15 @@
              : UserGestureIndicator::ConsumeUserGesture();
 }
 
+bool Frame::DeprecatedIsFeatureEnabled(
+    mojom::FeaturePolicyFeature feature) const {
+  return GetSecurityContext()->IsFeatureEnabled(feature,
+                                                ReportOptions::kDoNotReport);
+}
+
 bool Frame::DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature feature,
                                        ReportOptions report_on_failure) const {
-  FeaturePolicy* feature_policy = GetSecurityContext()->GetFeaturePolicy();
-  // The policy should always be initialized before checking it to ensure we
-  // properly inherit the parent policy.
-  DCHECK(feature_policy);
-
-  if (feature_policy->IsFeatureEnabled(feature))
-    return true;
-  if (report_on_failure == ReportOptions::kReportOnFailure)
-    DeprecatedReportFeaturePolicyViolation(feature);
-  return false;
+  return GetSecurityContext()->IsFeatureEnabled(feature, report_on_failure);
 }
 
 void Frame::SetOwner(FrameOwner* owner) {
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h
index 9e2e1bf..ac602f8 100644
--- a/third_party/blink/renderer/core/frame/frame.h
+++ b/third_party/blink/renderer/core/frame/frame.h
@@ -64,6 +64,7 @@
 class Settings;
 class WindowProxy;
 class WindowProxyManager;
+enum class ReportOptions;
 struct FrameLoadRequest;
 
 enum class FrameDetachType { kRemove, kSwap };
@@ -71,9 +72,6 @@
 // Status of user gesture.
 enum class UserGestureStatus { kActive, kNone };
 
-// Whether to report policy violations when checking whether a feature is
-// enabled.
-enum class ReportOptions { kReportOnFailure, kDoNotReport };
 
 // Frame is the base class of LocalFrame and RemoteFrame and should only contain
 // functionality shared between both. In particular, any method related to
@@ -231,9 +229,9 @@
   // Report-To endpoints, via ReportFeaturePolicyViolation(), if the feature is
   // disabled.
   // TODO(iclelland): Replace these with methods on SecurityContext/Document
-  bool DeprecatedIsFeatureEnabled(
-      mojom::FeaturePolicyFeature,
-      ReportOptions report_on_failure = ReportOptions::kDoNotReport) const;
+  bool DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature) const;
+  bool DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature,
+                                  ReportOptions report_on_failure) const;
   virtual void DeprecatedReportFeaturePolicyViolation(
       mojom::FeaturePolicyFeature) const {}
 
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 345caf6..c46f76f 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -62,7 +62,6 @@
 #include "third_party/blink/renderer/core/frame/ad_tracker.h"
 #include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
-#include "third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h"
 #include "third_party/blink/renderer/core/frame/frame_console.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -1443,25 +1442,7 @@
 
 void LocalFrame::DeprecatedReportFeaturePolicyViolation(
     mojom::FeaturePolicyFeature feature) const {
-  if (!RuntimeEnabledFeatures::FeaturePolicyReportingEnabled())
-    return;
-  const String& feature_name = GetNameForFeature(feature);
-  FeaturePolicyViolationReportBody* body = new FeaturePolicyViolationReportBody(
-      feature_name, "Feature policy violation", SourceLocation::Capture());
-  Report* report =
-      new Report("feature-policy", GetDocument()->Url().GetString(), body);
-  ReportingContext::From(GetDocument())->QueueReport(report);
-
-  bool is_null;
-  int line_number = body->lineNumber(is_null);
-  line_number = is_null ? 0 : line_number;
-  int column_number = body->columnNumber(is_null);
-  column_number = is_null ? 0 : column_number;
-
-  // Send the feature policy violation report to the Reporting API.
-  GetReportingService()->QueueFeaturePolicyViolationReport(
-      GetDocument()->Url(), feature_name, "Feature policy violation",
-      body->sourceFile(), line_number, column_number);
+  GetSecurityContext()->ReportFeaturePolicyViolation(feature);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index ef70673..f83a473d 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -376,6 +376,8 @@
   void DeprecatedReportFeaturePolicyViolation(
       mojom::FeaturePolicyFeature) const override;
 
+  const mojom::blink::ReportingServiceProxyPtr& GetReportingService() const;
+
  private:
   friend class FrameNavigationDisabler;
 
@@ -411,8 +413,6 @@
   ukm::UkmRecorder* GetUkmRecorder() override;
   ukm::SourceId GetUkmSourceId() override;
 
-  const mojom::blink::ReportingServiceProxyPtr& GetReportingService() const;
-
   std::unique_ptr<FrameScheduler> frame_scheduler_;
 
   // Holds all PauseSubresourceLoadingHandles allowing either |this| to delete
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
new file mode 100644
index 0000000..d967442
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
@@ -0,0 +1,230 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
+
+#include "services/metrics/public/cpp/ukm_entry_builder.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "third_party/blink/renderer/platform/histogram.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/time.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::ScopedUkmHierarchicalTimer(
+    LocalFrameUkmAggregator* aggregator,
+    size_t metric_index)
+    : aggregator_(aggregator),
+      metric_index_(metric_index),
+      start_time_(CurrentTimeTicks()) {}
+
+LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::ScopedUkmHierarchicalTimer(
+    ScopedUkmHierarchicalTimer&& other)
+    : aggregator_(other.aggregator_),
+      metric_index_(other.metric_index_),
+      start_time_(other.start_time_) {
+  other.aggregator_ = nullptr;
+}
+
+LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::
+    ~ScopedUkmHierarchicalTimer() {
+  if (aggregator_ && base::TimeTicks::IsHighResolution()) {
+    aggregator_->RecordSample(metric_index_, start_time_, CurrentTimeTicks());
+  }
+}
+
+LocalFrameUkmAggregator::LocalFrameUkmAggregator(int64_t source_id,
+                                                 ukm::UkmRecorder* recorder)
+    : source_id_(source_id),
+      recorder_(recorder),
+      event_name_("Blink.UpdateTime"),
+      event_frequency_(TimeDelta::FromSeconds(30)),
+      last_flushed_time_(CurrentTimeTicks()) {
+  // Record average and worst case for the primary metric.
+  primary_metric_.worst_case_metric_name = "MainFrame.WorstCase";
+  primary_metric_.average_metric_name = "MainFrame.Average";
+
+  // Define the UMA for the primary metric.
+  primary_metric_.uma_counter.reset(
+      new CustomCountHistogram("Blink.MainFrame.UpdateTime", 0, 10000000, 50));
+
+  // Set up the substrings to create the UMA names
+  const String uma_preamble = "Blink.";
+  const String uma_postscript = ".UpdateTime";
+  const String uma_ratio_preamble = "Blink.MainFrame.";
+  const String uma_ratio_postscript = "Ratio";
+
+  // Set up sub-strings for the bucketed UMA metrics
+  Vector<String> threshold_substrings;
+  if (!bucket_thresholds_.size()) {
+    threshold_substrings.push_back(".All");
+  } else {
+    threshold_substrings.push_back(
+        String::Format(".LessThan%lums",
+                       (unsigned long)bucket_thresholds_[0].InMilliseconds()));
+    for (wtf_size_t i = 1; i < bucket_thresholds_.size(); ++i) {
+      threshold_substrings.push_back(String::Format(
+          ".%lumsTo%lums",
+          (unsigned long)bucket_thresholds_[i - 1].InMilliseconds(),
+          (unsigned long)bucket_thresholds_[i].InMilliseconds()));
+    }
+    threshold_substrings.push_back(String::Format(
+        ".MoreThan%lums",
+        (unsigned long)bucket_thresholds_[bucket_thresholds_.size() - 1]
+            .InMilliseconds()));
+  }
+
+  // Populate all the sub-metrics.
+  absolute_metric_records_.ReserveInitialCapacity(kCount);
+  ratio_metric_records_.ReserveInitialCapacity(kCount);
+  for (unsigned i = 0; i < (unsigned)kCount; ++i) {
+    const auto& metric_name = metric_strings_[i];
+
+    // Absolute records report the absolute time for each metric, both
+    // average and worst case. They have an associated UMA too that we
+    // own and allocate here.
+    auto& absolute_record = absolute_metric_records_.emplace_back();
+    absolute_record.worst_case_metric_name = metric_name;
+    absolute_record.worst_case_metric_name.append(".WorstCase");
+    absolute_record.average_metric_name = metric_name;
+    absolute_record.average_metric_name.append(".Average");
+    auto uma_name = uma_preamble;
+    uma_name.append(metric_name);
+    uma_name.append(uma_postscript);
+    absolute_record.uma_counter.reset(
+        new CustomCountHistogram(uma_name.Utf8().data(), 0, 10000000, 50));
+
+    // Ratio records report the ratio of each metric to the primary metric,
+    // average and worst case. UMA counters are also associated with the
+    // ratios and we allocate and own them here.
+    auto& ratio_record = ratio_metric_records_.emplace_back();
+    ratio_record.worst_case_metric_name = metric_name;
+    ratio_record.worst_case_metric_name.append(".WorstCaseRatio");
+    ratio_record.average_metric_name = metric_name;
+    ratio_record.average_metric_name.append(".AverageRatio");
+    for (auto bucket_substring : threshold_substrings) {
+      String uma_name = uma_ratio_preamble;
+      uma_name.append(metric_name);
+      uma_name.append(uma_ratio_postscript);
+      uma_name.append(bucket_substring);
+      ratio_record.uma_counters_per_bucket.push_back(
+          std::make_unique<CustomCountHistogram>(uma_name.Utf8().data(), 0,
+                                                 10000000, 50));
+    }
+  }
+}
+
+LocalFrameUkmAggregator::~LocalFrameUkmAggregator() {
+  Flush(TimeTicks());
+}
+
+LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer
+LocalFrameUkmAggregator::GetScopedTimer(size_t metric_index) {
+  return ScopedUkmHierarchicalTimer(this, metric_index);
+}
+
+void LocalFrameUkmAggregator::RecordSample(size_t metric_index,
+                                           TimeTicks start,
+                                           TimeTicks end) {
+  TimeDelta duration = end - start;
+
+  // Append the duration to the appropriate metrics record.
+  DCHECK_LT(metric_index, absolute_metric_records_.size());
+  auto& record = absolute_metric_records_[metric_index];
+  if (duration > record.worst_case_duration)
+    record.worst_case_duration = duration;
+  record.total_duration += duration;
+  ++record.sample_count;
+
+  // Record the UMA
+  record.uma_counter->CountMicroseconds(duration);
+
+  // Just record the duration for ratios. We compute the ratio later
+  // when we know the frame time.
+  ratio_metric_records_[metric_index].interval_duration += duration;
+}
+
+void LocalFrameUkmAggregator::RecordPrimarySample(TimeTicks start,
+                                                  TimeTicks end) {
+  FlushIfNeeded(end);
+
+  TimeDelta duration = end - start;
+
+  // Record UMA
+  primary_metric_.uma_counter->CountMicroseconds(duration);
+
+  if (duration.is_zero())
+    return;
+
+  // Record primary time information
+  if (duration > primary_metric_.worst_case_duration)
+    primary_metric_.worst_case_duration = duration;
+  primary_metric_.total_duration += duration;
+  ++primary_metric_.sample_count;
+
+  // Compute all the dependent metrics, after finding which bucket we're in
+  // for UMA data.
+  size_t bucket_index = bucket_thresholds_.size();
+  for (size_t i = 0; i < bucket_index; ++i) {
+    if (duration < bucket_thresholds_[i]) {
+      bucket_index = i;
+    }
+  }
+
+  for (auto& record : ratio_metric_records_) {
+    double ratio =
+        record.interval_duration.InMicrosecondsF() / duration.InMicrosecondsF();
+    if (ratio > record.worst_case_ratio)
+      record.worst_case_ratio = ratio;
+    record.total_ratio += ratio;
+    ++record.sample_count;
+    record.uma_counters_per_bucket[bucket_index]->Count(floor(ratio * 100.0));
+    record.interval_duration = TimeDelta();
+  }
+
+  has_data_ = true;
+}
+
+void LocalFrameUkmAggregator::FlushIfNeeded(TimeTicks current_time) {
+  if (current_time >= last_flushed_time_ + event_frequency_)
+    Flush(current_time);
+}
+
+void LocalFrameUkmAggregator::Flush(TimeTicks current_time) {
+  last_flushed_time_ = current_time;
+  if (!has_data_)
+    return;
+  DCHECK(primary_metric_.sample_count);
+
+  ukm::UkmEntryBuilder builder(source_id_, event_name_.Utf8().data());
+  builder.SetMetric(primary_metric_.worst_case_metric_name.Utf8().data(),
+                    primary_metric_.worst_case_duration.InMicroseconds());
+  builder.SetMetric(primary_metric_.average_metric_name.Utf8().data(),
+                    primary_metric_.total_duration.InMicroseconds() /
+                        static_cast<int64_t>(primary_metric_.sample_count));
+  for (auto& record : absolute_metric_records_) {
+    if (record.sample_count == 0)
+      continue;
+    builder.SetMetric(record.worst_case_metric_name.Utf8().data(),
+                      record.worst_case_duration.InMicroseconds());
+    builder.SetMetric(record.average_metric_name.Utf8().data(),
+                      record.total_duration.InMicroseconds() /
+                          static_cast<int64_t>(record.sample_count));
+  }
+  for (auto& record : ratio_metric_records_) {
+    if (record.sample_count == 0)
+      continue;
+    builder.SetMetric(record.worst_case_metric_name.Utf8().data(),
+                      record.worst_case_ratio);
+    builder.SetMetric(
+        record.average_metric_name.Utf8().data(),
+        record.total_ratio / static_cast<float>(record.sample_count));
+    record.reset();
+  }
+  builder.Record(recorder_);
+  has_data_ = false;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
new file mode 100644
index 0000000..546b61a5
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
@@ -0,0 +1,216 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_FRAME_UKM_AGGREGATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_FRAME_UKM_AGGREGATOR_H_
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/time.h"
+
+namespace ukm {
+class UkmRecorder;
+}
+
+namespace blink {
+class CustomCountHistogram;
+
+// This class aggregaties and records time based UKM and UMA metrics
+// for LocalFrameView. The simplest way to use it is via the
+// SCOPED_UMA_AND_UKM_HIERARCHICAL_TIMER macro in LocalFrameView combined
+// with LocalFrameView::RecordEndOfFrameMetrics.
+//
+// It takes the following constructor parameters:
+// - source_id: UKM Source ID associated with the events.
+// - recorder: UkmRecorder which will handle the events
+//
+// The aggregator manages all of the UKM and UMA names for LocalFrameView.
+// It constructs and takes ownership the UMA counters when constructed
+// itself. We do this to localize all UMA and UKM metrics in one place, so
+// that adding a metric is localized to the cc file of this class, protected
+// from errors that might arise when adding names in multiple places.
+//
+// After the aggregator is created, one can create ScopedUkmHierarchicalTimer
+// objects that will measure the time, in microseconds, from creation until
+// the object is destroyed for sub-metrics. When destroyed, it will record
+// a sample into the aggregator and the current frame's accumulated time for
+// that metric, and report UMA values.
+//
+// See the MetricNames enum below for the set of metrics recorded. Add an
+// entry to that enum to add a new metric.
+//
+// When the primary timed execution completes, this aggregator stores the
+// primary time and computes metrics that depend on it. The results are
+// aggregated.  UMA metrics are updated at this time. A UKM event is
+// generated in one of two situations:
+//  - If a sample is added that lies in the next event frequency interval (this
+//    will generate an event for the previous interval)
+//  - If the aggregator is destroyed (this will generate an event for any
+//    remaining samples in the aggregator)
+//
+// Note that no event is generated if there were no primary samples in an
+// interval.
+//
+// Sample usage (see also SCOPED_UMA_AND_UKM_HIERARCHICAL_TIMER):
+//   std::unique_ptr<UkmHierarchicalTimeAggregator> aggregator(
+//      new UkmHierarchicalTimeAggregator(
+//              GetSourceId(),
+//              GetUkmRecorder());
+//
+//   ...
+//   {
+//     auto timer =
+//         aggregator->GetScopedTimer(static_cast<size_t>(
+//             LocalFrameUkmAggregator::MetricNames::kMetric2));
+//     ...
+//   }
+//   // At this point an sample for kMetric2 is recorded.
+//   ...
+//   // When the primary time completes
+//   aggregator->RecordPrimaryMetric(time_delta);
+//   // This records a primary sample and the sub-metrics that depend on it.
+//   // It may generate an event.
+//   ...
+//   // Destroying an aggregator will generate an event as well if there were
+//   // samples.
+//   aggregator.reset();
+//
+// In the example above, the event name is "my_event". It will measure 14
+// metrics:
+//   "primary_metric.Average", "primary_metric.WorstCase",
+//   "sub_metric1.Average", "sub_metric1.WorstCase",
+//   "sub_metric2.Average", "sub_metric2.WorstCase",
+//   "sub_metric3.Average", "sub_metric3.WorstCase"
+//   "sub_metric1.AverageRatio", "sub_metric1.WorstCaseRatio",
+//   "sub_metric2.AverageRatio", "sub_metric2.WorstCaseRatio",
+//   "sub_metric3.AverageRatio", "sub_metric3.WorstCaseRation"
+//
+// It will report 13 UMA values:
+//   "primary_uma_counter",
+//   "sub_uma_metric1", "sub_uma_metric2", "sub_uma_metric3",
+//   "sub_uma_ratio1.LessThan1ms", "sub_uma_ratio1.1msTo5ms",
+//   "sub_uma_ratio1.MoreThan5ms", "sub_uma_ratio2.LessThan1ms",
+//   "sub_uma_ratio2.1msTo5ms", "sub_uma_ratio2.MoreThan5ms",
+//   "sub_uma_ratio3.LessThan1ms", "sub_uma_ratio3.1msTo5ms",
+//   "sub_uma_ratio3.MoreThan5ms"
+//
+// Note that these have to be specified in the appropriate ukm.xml file
+// and histograms.xml file. Runtime errors indicate missing or mis-named
+// metrics.
+//
+// If the source_id/recorder changes then a new
+// UkmHierarchicalTimeAggregator has to be created.
+class LocalFrameUkmAggregator {
+ public:
+  // Changing these values requires changing the names of metrics specified
+  // below. For every metric name added here, add an entry in the
+  // metric_strings_ array below.
+  enum {
+    kCompositing,
+    kCompositingCommit,
+    kIntersectionObservation,
+    kPaint,
+    kPrePaint,
+    kStyleAndLayout,
+    kCount
+  };
+
+ private:
+  // Add an entry in this arrray every time a new metric is added.
+  const String metric_strings_[kCount] = {
+      "Compositing", "CompositingCommit", "IntersectionObservation",
+      "Paint",       "PrePaint",          "StyleAndLayout"};
+
+  // Modify this array if the UMA ratio metrics should be bucketed in a
+  // different way.
+  const Vector<TimeDelta> bucket_thresholds_ = {TimeDelta::FromMilliseconds(1),
+                                                TimeDelta::FromMilliseconds(5)};
+
+ public:
+  // This class will start a timer upon creation, which will end when the
+  // object is destroyed. Upon destruction it will record a sample into the
+  // aggregator that created the scoped timer. It will also record an event
+  // into the histogram counter.
+  class ScopedUkmHierarchicalTimer {
+   public:
+    ScopedUkmHierarchicalTimer(ScopedUkmHierarchicalTimer&&);
+    ~ScopedUkmHierarchicalTimer();
+
+   private:
+    friend class LocalFrameUkmAggregator;
+
+    ScopedUkmHierarchicalTimer(LocalFrameUkmAggregator*, size_t metric_index);
+
+    LocalFrameUkmAggregator* aggregator_;
+    const size_t metric_index_;
+    const TimeTicks start_time_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedUkmHierarchicalTimer);
+  };
+
+  LocalFrameUkmAggregator(int64_t source_id, ukm::UkmRecorder*);
+  ~LocalFrameUkmAggregator();
+
+  // Create a scoped timer with the index of the metric. Note the index must
+  // correspond to the matching index in metric_names.
+  ScopedUkmHierarchicalTimer GetScopedTimer(size_t metric_index);
+
+  // Record a primary sample, that also computes the ratios for the
+  // sub-metrics and may generate an event.
+  void RecordPrimarySample(TimeTicks start, TimeTicks end);
+
+ private:
+  struct AbsoluteMetricRecord {
+    String worst_case_metric_name;
+    String average_metric_name;
+    std::unique_ptr<CustomCountHistogram> uma_counter;
+    TimeDelta total_duration;
+    TimeDelta worst_case_duration;
+    size_t sample_count = 0u;
+
+    void reset() {
+      total_duration = TimeDelta();
+      worst_case_duration = TimeDelta();
+      sample_count = 0u;
+    }
+  };
+
+  struct RatioMetricRecord {
+    String worst_case_metric_name;
+    String average_metric_name;
+    Vector<std::unique_ptr<CustomCountHistogram>> uma_counters_per_bucket;
+    TimeDelta interval_duration;
+    double total_ratio;
+    double worst_case_ratio;
+    size_t sample_count;
+
+    void reset() {
+      interval_duration = TimeDelta();
+      total_ratio = 0;
+      worst_case_ratio = 0;
+      sample_count = 0u;
+    }
+  };
+
+  void RecordSample(size_t metric_index, TimeTicks start, TimeTicks end);
+  void FlushIfNeeded(TimeTicks current_time);
+  void Flush(TimeTicks current_time);
+
+  const int64_t source_id_;
+  ukm::UkmRecorder* const recorder_;
+  const String event_name_;
+  const TimeDelta event_frequency_;
+  AbsoluteMetricRecord primary_metric_;
+  Vector<AbsoluteMetricRecord> absolute_metric_records_;
+  Vector<RatioMetricRecord> ratio_metric_records_;
+  TimeTicks last_flushed_time_;
+
+  bool has_data_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalFrameUkmAggregator);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_FRAME_UKM_AGGREGATOR_H_
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 3101fa06..7f5033b 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -55,6 +55,7 @@
 #include "third_party/blink/renderer/core/frame/link_highlights.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
+#include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
 #include "third_party/blink/renderer/core/frame/location.h"
 #include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h"
 #include "third_party/blink/renderer/core/frame/remote_frame.h"
@@ -141,7 +142,6 @@
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 #include "third_party/blink/renderer/platform/scroll/scroll_alignment.h"
 #include "third_party/blink/renderer/platform/transforms/transform_state.h"
-#include "third_party/blink/renderer/platform/ukm_time_aggregator.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
@@ -170,37 +170,23 @@
 constexpr size_t kCssFragmentIdentifierPrefixLength =
     base::size(kCssFragmentIdentifierPrefix);
 
-// Changing these values requires changing the names generated in
-// EnsureUkmTimeAggregator().
-enum class UkmMetricNames {
-  kCompositing,
-  kCompositingCommit,
-  kIntersectionObservation,
-  kPaint,
-  kPrePaint,
-  kStyleAndLayout,
-  kCount
-};
-
 }  // namespace
 
-// Defines an UMA and a UKM, recorded in microseconds equal to the duration of
-// the current lexical scope after declaration of the macro. Example usage:
+// Defines a UKM that is part of a hierarchical ukm, recorded in
+// microseconds equal to the duration of the current lexical scope after
+// declaration of the macro. Example usage:
 //
 // void LocalFrameView::DoExpensiveThing() {
-//   SCOPED_UMA_AND_UKM_TIMER(UmaName, kUkmEnumName);
+//   SCOPED_UMA_AND_UKM_TIMER(kUkmEnumName);
 //   // Do computation of expensive thing
 //
 // }
 //
-// |uma_name| should be the full name of an UMA defined
-// in histograms.xml. |ukm_enum| should be an entry in UkmMetricNames
-// (which in turn come from ukm.xml).
-#define SCOPED_UMA_AND_UKM_TIMER(uma_name, ukm_enum)                    \
-  DEFINE_STATIC_LOCAL_IMPL(CustomCountHistogram, scoped_uma_counter,    \
-                           (uma_name, 0, 10000000, 50), false);         \
-  auto scoped_ukm_uma_timer = EnsureUkmTimeAggregator().GetScopedTimer( \
-      static_cast<size_t>(ukm_enum), &scoped_uma_counter);
+// |ukm_enum| should be an entry in LocalFrameUkmAggregator's enum of
+// metric names (which in turn corresponds to names in from ukm.xml).
+#define SCOPED_UMA_AND_UKM_TIMER(ukm_enum) \
+  auto scoped_ukm_hierarchical_timer =     \
+      EnsureUkmAggregator().GetScopedTimer(static_cast<size_t>(ukm_enum));
 
 using namespace HTMLNames;
 
@@ -407,7 +393,7 @@
 
   ClearPrintContext();
 
-  ukm_time_aggregator_.reset();
+  ukm_aggregator_.reset();
   jank_tracker_->Dispose();
 
 #if DCHECK_IS_ON()
@@ -2263,6 +2249,11 @@
       DocumentLifecycle::kLayoutClean);
 }
 
+void LocalFrameView::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) {
+  LocalFrameUkmAggregator& ukm_aggregator = EnsureUkmAggregator();
+  ukm_aggregator.RecordPrimarySample(frame_begin_time, CurrentTimeTicks());
+}
+
 void LocalFrameView::ScheduleVisualUpdateForPaintInvalidationIfNeeded() {
   LocalFrame& local_frame_root = GetFrame().LocalFrameRoot();
   if (local_frame_root.View()->current_update_lifecycle_phases_target_state_ <
@@ -2415,8 +2406,7 @@
   if (target_state == DocumentLifecycle::kPaintClean) {
     TRACE_EVENT0("blink,benchmark",
                  "LocalFrameView::UpdateViewportIntersectionsForSubtree");
-    SCOPED_UMA_AND_UKM_TIMER("Blink.IntersectionObservation.UpdateTime",
-                             UkmMetricNames::kIntersectionObservation);
+    SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kIntersectionObservation);
     UpdateViewportIntersectionsForSubtree();
   }
 
@@ -2533,8 +2523,7 @@
   DCHECK(layout_view);
 
   if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
-    SCOPED_UMA_AND_UKM_TIMER("Blink.Compositing.UpdateTime",
-                             UkmMetricNames::kCompositing);
+    SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kCompositing);
     layout_view->Compositor()->UpdateIfNeededRecursive(target_state);
   } else {
     ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
@@ -2578,8 +2567,7 @@
   });
 
   {
-    SCOPED_UMA_AND_UKM_TIMER("Blink.PrePaint.UpdateTime",
-                             UkmMetricNames::kPrePaint);
+    SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kPrePaint);
 
     PrePaintTreeWalk().WalkTree(*this);
   }
@@ -2794,7 +2782,7 @@
 
 void LocalFrameView::PaintTree() {
   TRACE_EVENT0("blink,benchmark", "LocalFrameView::paintTree");
-  SCOPED_UMA_AND_UKM_TIMER("Blink.Paint.UpdateTime", UkmMetricNames::kPaint);
+  SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kPaint);
 
   DCHECK(GetFrame().IsLocalRoot());
 
@@ -2934,8 +2922,7 @@
         paint_artifact_compositor_->RootLayer(), &GetFrame());
   }
 
-  SCOPED_UMA_AND_UKM_TIMER("Blink.CompositingCommit.UpdateTime",
-                           UkmMetricNames::kCompositingCommit);
+  SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kCompositingCommit);
 
   paint_artifact_compositor_->Update(
       paint_controller_->GetPaintArtifactShared(), composited_element_ids,
@@ -2951,8 +2938,7 @@
 }
 
 void LocalFrameView::UpdateStyleAndLayoutIfNeededRecursive() {
-  SCOPED_UMA_AND_UKM_TIMER("Blink.StyleAndLayout.UpdateTime",
-                           UkmMetricNames::kStyleAndLayout);
+  SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kStyleAndLayout);
   UpdateStyleAndLayoutIfNeededRecursiveInternal();
 }
 
@@ -4443,18 +4429,13 @@
       std::max<float>(1.0, GetChromeClient()->WindowToViewportScalar(1)));
 }
 
-UkmTimeAggregator& LocalFrameView::EnsureUkmTimeAggregator() {
-  if (!ukm_time_aggregator_) {
-    ukm_time_aggregator_.reset(new UkmTimeAggregator(
-        "Blink.UpdateTime", frame_->GetDocument()->UkmSourceID(),
-        frame_->GetDocument()->UkmRecorder(),
-        // Note that changing the order or values of the following vector
-        // requires changing the UkmMetricNames enum.
-        {"Compositing", "CompositingCommit", "IntersectionObservation", "Paint",
-         "PrePaint", "StyleAndLayout"},
-        TimeDelta::FromSeconds(30)));
+LocalFrameUkmAggregator& LocalFrameView::EnsureUkmAggregator() {
+  if (!ukm_aggregator_) {
+    ukm_aggregator_.reset(
+        new LocalFrameUkmAggregator(frame_->GetDocument()->UkmSourceID(),
+                                    frame_->GetDocument()->UkmRecorder()));
   }
-  return *ukm_time_aggregator_;
+  return *ukm_aggregator_;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h
index 75ef8d7..ee208c45 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.h
+++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -86,7 +86,7 @@
 class ScrollingCoordinatorContext;
 class TracedValue;
 class TransformState;
-class UkmTimeAggregator;
+class LocalFrameUkmAggregator;
 class WebPluginContainerImpl;
 struct AnnotatedRegionValue;
 struct IntrinsicSizingInfo;
@@ -349,6 +349,9 @@
   // desired state.
   bool UpdateLifecycleToLayoutClean();
 
+  // Record any UMA and UKM metrics that depend on the end of a main frame.
+  void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time);
+
   void ScheduleVisualUpdateForPaintInvalidationIfNeeded();
 
   bool InvalidateViewportConstrainedObjects();
@@ -824,7 +827,7 @@
 
   void LayoutFromRootObject(LayoutObject& root);
 
-  UkmTimeAggregator& EnsureUkmTimeAggregator();
+  LocalFrameUkmAggregator& EnsureUkmAggregator();
 
   LayoutSize size_;
 
@@ -959,7 +962,7 @@
 
   MainThreadScrollingReasons main_thread_scrolling_reasons_;
 
-  std::unique_ptr<UkmTimeAggregator> ukm_time_aggregator_;
+  std::unique_ptr<LocalFrameUkmAggregator> ukm_aggregator_;
 
   Member<PrintContext> print_context_;
 
diff --git a/third_party/blink/renderer/core/frame/reporting_context.h b/third_party/blink/renderer/core/frame/reporting_context.h
index c60b9d77..9332439b 100644
--- a/third_party/blink/renderer/core/frame/reporting_context.h
+++ b/third_party/blink/renderer/core/frame/reporting_context.h
@@ -29,6 +29,9 @@
   // Returns the ReportingContext for an ExecutionContext. If one does not
   // already exist for the given context, one is created.
   static ReportingContext* From(ExecutionContext*);
+  static ReportingContext* From(const ExecutionContext* context) {
+    return ReportingContext::From(const_cast<ExecutionContext*>(context));
+  }
 
   // Queues a report in all registered observers.
   void QueueReport(Report*);
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
index 16207dde..27558a3 100644
--- a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
+++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
@@ -38,32 +38,37 @@
 }
 
 void WebViewFrameWidget::Resize(const WebSize& size) {
-  return web_view_->Resize(size);
+  web_view_->Resize(size);
 }
 
 void WebViewFrameWidget::ResizeVisualViewport(const WebSize& size) {
-  return web_view_->ResizeVisualViewport(size);
+  web_view_->ResizeVisualViewport(size);
 }
 
 void WebViewFrameWidget::DidEnterFullscreen() {
-  return web_view_->DidEnterFullscreen();
+  web_view_->DidEnterFullscreen();
 }
 
 void WebViewFrameWidget::DidExitFullscreen() {
-  return web_view_->DidExitFullscreen();
+  web_view_->DidExitFullscreen();
 }
 
 void WebViewFrameWidget::SetSuppressFrameRequestsWorkaroundFor704763Only(
     bool suppress_frame_requests) {
-  return web_view_->SetSuppressFrameRequestsWorkaroundFor704763Only(
+  web_view_->SetSuppressFrameRequestsWorkaroundFor704763Only(
       suppress_frame_requests);
 }
 void WebViewFrameWidget::BeginFrame(base::TimeTicks last_frame_time) {
-  return web_view_->BeginFrame(last_frame_time);
+  web_view_->BeginFrame(last_frame_time);
+}
+
+void WebViewFrameWidget::RecordEndOfFrameMetrics(
+    base::TimeTicks frame_begin_time) {
+  web_view_->RecordEndOfFrameMetrics(frame_begin_time);
 }
 
 void WebViewFrameWidget::UpdateLifecycle(LifecycleUpdate requested_update) {
-  return web_view_->UpdateLifecycle(requested_update);
+  web_view_->UpdateLifecycle(requested_update);
 }
 
 void WebViewFrameWidget::UpdateAllLifecyclePhasesAndCompositeForTesting() {
@@ -72,20 +77,20 @@
 
 void WebViewFrameWidget::PaintContent(cc::PaintCanvas* canvas,
                                       const WebRect& view_port) {
-  return web_view_->PaintContent(canvas, view_port);
+  web_view_->PaintContent(canvas, view_port);
 }
 
 void WebViewFrameWidget::LayoutAndPaintAsync(base::OnceClosure callback) {
-  return web_view_->LayoutAndPaintAsync(std::move(callback));
+  web_view_->LayoutAndPaintAsync(std::move(callback));
 }
 
 void WebViewFrameWidget::CompositeAndReadbackAsync(
     base::OnceCallback<void(const SkBitmap&)> callback) {
-  return web_view_->CompositeAndReadbackAsync(std::move(callback));
+  web_view_->CompositeAndReadbackAsync(std::move(callback));
 }
 
 void WebViewFrameWidget::ThemeChanged() {
-  return web_view_->ThemeChanged();
+  web_view_->ThemeChanged();
 }
 
 WebInputEventResult WebViewFrameWidget::HandleInputEvent(
@@ -98,7 +103,7 @@
 }
 
 void WebViewFrameWidget::SetCursorVisibilityState(bool is_visible) {
-  return web_view_->SetCursorVisibilityState(is_visible);
+  web_view_->SetCursorVisibilityState(is_visible);
 }
 
 void WebViewFrameWidget::ApplyViewportDeltas(
@@ -107,24 +112,24 @@
     const WebFloatSize& elastic_overscroll_delta,
     float scale_factor,
     float browser_controls_shown_ratio_delta) {
-  return web_view_->ApplyViewportDeltas(
-      visual_viewport_delta, layout_viewport_delta, elastic_overscroll_delta,
-      scale_factor, browser_controls_shown_ratio_delta);
+  web_view_->ApplyViewportDeltas(visual_viewport_delta, layout_viewport_delta,
+                                 elastic_overscroll_delta, scale_factor,
+                                 browser_controls_shown_ratio_delta);
 }
 
 void WebViewFrameWidget::RecordWheelAndTouchScrollingCount(
     bool has_scrolled_by_wheel,
     bool has_scrolled_by_touch) {
-  return web_view_->RecordWheelAndTouchScrollingCount(has_scrolled_by_wheel,
-                                                      has_scrolled_by_touch);
+  web_view_->RecordWheelAndTouchScrollingCount(has_scrolled_by_wheel,
+                                               has_scrolled_by_touch);
 }
 
 void WebViewFrameWidget::MouseCaptureLost() {
-  return web_view_->MouseCaptureLost();
+  web_view_->MouseCaptureLost();
 }
 
 void WebViewFrameWidget::SetFocus(bool enable) {
-  return web_view_->SetFocus(enable);
+  web_view_->SetFocus(enable);
 }
 
 bool WebViewFrameWidget::SelectionBounds(WebRect& anchor,
@@ -137,7 +142,7 @@
 }
 
 void WebViewFrameWidget::WillCloseLayerTreeView() {
-  return web_view_->WillCloseLayerTreeView();
+  web_view_->WillCloseLayerTreeView();
 }
 
 SkColor WebViewFrameWidget::BackgroundColor() const {
@@ -152,12 +157,12 @@
     cc::BrowserControlsState constraints,
     cc::BrowserControlsState current,
     bool animate) {
-  return web_view_->UpdateBrowserControlsState(constraints, current, animate);
+  web_view_->UpdateBrowserControlsState(constraints, current, animate);
 }
 
 void WebViewFrameWidget::SetVisibilityState(
     mojom::PageVisibilityState visibility_state) {
-  return web_view_->SetVisibilityState(visibility_state, false);
+  web_view_->SetVisibilityState(visibility_state, false);
 }
 
 void WebViewFrameWidget::SetBackgroundColorOverride(SkColor color) {
@@ -165,7 +170,7 @@
 }
 
 void WebViewFrameWidget::ClearBackgroundColorOverride() {
-  return web_view_->ClearBackgroundColorOverride();
+  web_view_->ClearBackgroundColorOverride();
 }
 
 void WebViewFrameWidget::SetBaseBackgroundColorOverride(SkColor color) {
@@ -173,7 +178,7 @@
 }
 
 void WebViewFrameWidget::ClearBaseBackgroundColorOverride() {
-  return web_view_->ClearBaseBackgroundColorOverride();
+  web_view_->ClearBaseBackgroundColorOverride();
 }
 
 void WebViewFrameWidget::SetBaseBackgroundColor(SkColor color) {
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.h b/third_party/blink/renderer/core/frame/web_view_frame_widget.h
index 16ee4b60..1659cf7e 100644
--- a/third_party/blink/renderer/core/frame/web_view_frame_widget.h
+++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.h
@@ -48,6 +48,7 @@
   void DidExitFullscreen() override;
   void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) final;
   void BeginFrame(base::TimeTicks last_frame_time) override;
+  void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override;
   void UpdateLifecycle(LifecycleUpdate requested_update) override;
   void UpdateAllLifecyclePhasesAndCompositeForTesting() override;
   void PaintContent(cc::PaintCanvas*, const WebRect& view_port) override;
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
index c9c29c2..f3c1555 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
@@ -39,6 +39,7 @@
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/viewport_data.h"
 #include "third_party/blink/renderer/core/html/cross_origin_attribute.h"
+#include "third_party/blink/renderer/core/html/html_dimension.h"
 #include "third_party/blink/renderer/core/html/html_image_element.h"
 #include "third_party/blink/renderer/core/html/html_meta_element.h"
 #include "third_party/blink/renderer/core/html/link_rel_attribute.h"
@@ -115,6 +116,15 @@
   return media_query_evaluator.Eval(*media_queries);
 }
 
+static bool IsDimensionSmallAndAbsoluteForLazyLoad(
+    const String& attribute_value) {
+  // Minimum height or width of the image to start lazyloading.
+  const unsigned kMinDimensionToLazyLoad = 10;
+  HTMLDimension dimension;
+  return ParseDimensionValue(attribute_value, dimension) &&
+         dimension.IsAbsolute() && dimension.Value() <= kMinDimensionToLazyLoad;
+}
+
 class TokenPreloadScanner::StartTagScanner {
   STACK_ALLOCATED();
 
@@ -144,6 +154,8 @@
         integrity_attr_set_(false),
         integrity_features_(features),
         lazyload_attr_set_to_off_(false),
+        width_attr_small_absolute_(false),
+        height_attr_small_absolute_(false),
         scanner_type_(scanner_type) {
     if (Match(tag_impl_, imgTag) || Match(tag_impl_, sourceTag)) {
       source_size_ = SizesAttributeParser(media_values_, String()).length();
@@ -273,7 +285,11 @@
     request->SetNonce(nonce_);
     request->SetCharset(Charset());
     request->SetDefer(defer_);
-    request->SetIsLazyloadAttrOff(lazyload_attr_set_to_off_);
+
+    if (lazyload_attr_set_to_off_ ||
+        (width_attr_small_absolute_ && height_attr_small_absolute_)) {
+      request->SetIsLazyloadImageDisabled(true);
+    }
 
     // The only link tags that should keep the integrity metadata are
     // stylesheets until crbug.com/677022 is resolved.
@@ -343,6 +359,16 @@
                RuntimeEnabledFeatures::LazyImageLoadingEnabled() &&
                EqualIgnoringASCIICase(attribute_value, "off")) {
       lazyload_attr_set_to_off_ = true;
+    } else if (!width_attr_small_absolute_ &&
+               Match(attribute_name, widthAttr) &&
+               RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
+      width_attr_small_absolute_ =
+          IsDimensionSmallAndAbsoluteForLazyLoad(attribute_value);
+    } else if (!height_attr_small_absolute_ &&
+               Match(attribute_name, heightAttr) &&
+               RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
+      height_attr_small_absolute_ =
+          IsDimensionSmallAndAbsoluteForLazyLoad(attribute_value);
     }
   }
 
@@ -637,6 +663,8 @@
   IntegrityMetadataSet integrity_metadata_;
   SubresourceIntegrity::IntegrityFeatures integrity_features_;
   bool lazyload_attr_set_to_off_;
+  bool width_attr_small_absolute_;
+  bool height_attr_small_absolute_;
   TokenPreloadScanner::ScannerType scanner_type_;
 };
 
diff --git a/third_party/blink/renderer/core/html/parser/preload_request.cc b/third_party/blink/renderer/core/html/parser/preload_request.cc
index d7c894a1..359310e5 100644
--- a/third_party/blink/renderer/core/html/parser/preload_request.cc
+++ b/third_party/blink/renderer/core/html/parser/preload_request.cc
@@ -105,7 +105,8 @@
     if (const auto* frame = document->Loader()->GetFrame()) {
       if (frame->IsClientLoFiAllowed(params.GetResourceRequest())) {
         params.SetClientLoFiPlaceholder();
-      } else if (!is_lazyload_attr_off_ && frame->IsLazyLoadingImageAllowed()) {
+      } else if (!is_lazyload_image_disabled_ &&
+                 frame->IsLazyLoadingImageAllowed()) {
         params.SetAllowImagePlaceholder();
       }
     }
diff --git a/third_party/blink/renderer/core/html/parser/preload_request.h b/third_party/blink/renderer/core/html/parser/preload_request.h
index 28152a6..0bd0956 100644
--- a/third_party/blink/renderer/core/html/parser/preload_request.h
+++ b/third_party/blink/renderer/core/html/parser/preload_request.h
@@ -121,8 +121,8 @@
     return is_image_set_ == ResourceFetcher::kImageIsImageSet;
   }
 
-  void SetIsLazyloadAttrOff(bool is_lazyload_attr_off) {
-    is_lazyload_attr_off_ = is_lazyload_attr_off;
+  void SetIsLazyloadImageDisabled(bool is_lazyload_image_disable) {
+    is_lazyload_image_disabled_ = is_lazyload_image_disable;
   }
 
  private:
@@ -153,7 +153,7 @@
         referrer_source_(referrer_source),
         from_insertion_scanner_(false),
         is_image_set_(is_image_set),
-        is_lazyload_attr_off_(false) {}
+        is_lazyload_image_disabled_(false) {}
 
   KURL CompleteURL(Document*);
 
@@ -176,7 +176,7 @@
   IntegrityMetadataSet integrity_metadata_;
   bool from_insertion_scanner_;
   ResourceFetcher::IsImageSet is_image_set_;
-  bool is_lazyload_attr_off_;
+  bool is_lazyload_image_disabled_;
 };
 
 typedef Vector<std::unique_ptr<PreloadRequest>> PreloadRequestStream;
diff --git a/third_party/blink/renderer/core/html/track/cue_timeline.h b/third_party/blink/renderer/core/html/track/cue_timeline.h
index c7579cd..18869dd4 100644
--- a/third_party/blink/renderer/core/html/track/cue_timeline.h
+++ b/third_party/blink/renderer/core/html/track/cue_timeline.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/html/track/text_track_cue.h"
 #include "third_party/blink/renderer/core/html/track/vtt/vtt_cue.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/pod_interval_tree.h"
+#include "third_party/blink/renderer/platform/wtf/pod_interval_tree.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -22,7 +22,7 @@
 // safe because CueTimeline and TextTrackCue are guaranteed to die at the same
 // time when the owner HTMLMediaElement dies. Thus the raw TextTrackCue* cannot
 // become stale pointers.
-typedef PODIntervalTree<double, TextTrackCue*> CueIntervalTree;
+typedef WTF::PODIntervalTree<double, TextTrackCue*> CueIntervalTree;
 typedef CueIntervalTree::IntervalType CueInterval;
 typedef Vector<CueInterval> CueList;
 
@@ -82,19 +82,18 @@
   Member<CueTimeline> cue_timeline_;
 };
 
+}  // namespace blink
+
+namespace WTF {
 #ifndef NDEBUG
 // Template specializations required by PodIntervalTree in debug mode.
 template <>
-struct ValueToString<double> {
-  static String ToString(const double value) { return String::Number(value); }
-};
-
-template <>
-struct ValueToString<TextTrackCue*> {
-  static String ToString(TextTrackCue* const& cue) { return cue->ToString(); }
+struct ValueToString<blink::TextTrackCue*> {
+  static String ToString(blink::TextTrackCue* const& cue) {
+    return cue->ToString();
+  }
 };
 #endif
-
-}  // namespace blink
+}
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_TRACK_CUE_TIMELINE_H_
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.cc b/third_party/blink/renderer/core/input/mouse_event_manager.cc
index a158527..7f030d4 100644
--- a/third_party/blink/renderer/core/input/mouse_event_manager.cc
+++ b/third_party/blink/renderer/core/input/mouse_event_manager.cc
@@ -614,7 +614,7 @@
   if (RuntimeEnabledFeatures::NoHoverAfterLayoutChangeEnabled() &&
       update_hover_reason ==
           MouseEventManager::UpdateHoverReason::kLayoutOrStyleChanged) {
-    frame_->GetEventHandler().ScheduleCursorUpdate();
+    frame_->LocalFrameRoot().GetEventHandler().ScheduleCursorUpdate();
     return;
   }
 
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index a5a10da7..4d09e6d 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -4870,6 +4870,10 @@
   command addScriptToEvaluateOnNewDocument
     parameters
       string source
+      # If specified, creates an isolated world with the given name and evaluates given script in it.
+      # This world name will be used as the ExecutionContextDescription::name when the corresponding
+      # event is emitted.
+      experimental optional string worldName
     returns
       # Identifier of the added script.
       ScriptIdentifier identifier
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
index 2d55dfb5..d90a3946 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -70,6 +70,8 @@
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
+#include "third_party/blink/renderer/platform/json/json_parser.h"
+#include "third_party/blink/renderer/platform/json/json_values.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
@@ -548,23 +550,29 @@
   return Response::OK();
 }
 
-Response InspectorPageAgent::addScriptToEvaluateOnLoad(const String& source,
-                                                       String* identifier) {
+Response InspectorPageAgent::addScriptToEvaluateOnNewDocument(
+    const String& source,
+    Maybe<String> world_name,
+    String* identifier) {
   std::vector<WTF::String> keys = scripts_to_evaluate_on_load_.Keys();
   auto result = std::max_element(
       keys.begin(), keys.end(), [](const WTF::String& a, const WTF::String& b) {
         return Decimal::FromString(a) < Decimal::FromString(b);
       });
   if (result == keys.end()) {
-    scripts_to_evaluate_on_load_.Set(String::Number(1), source);
+    *identifier = String::Number(1);
   } else {
-    scripts_to_evaluate_on_load_.Set(
-        String::Number(Decimal::FromString(*result).ToDouble() + 1), source);
+    *identifier = String::Number(Decimal::FromString(*result).ToDouble() + 1);
   }
+
+  std::unique_ptr<JSONObject> script = JSONObject::Create();
+  script->SetString("source", source);
+  script->SetString("world_name", world_name.fromMaybe(""));
+  scripts_to_evaluate_on_load_.Set(*identifier, script->ToJSONString());
   return Response::OK();
 }
 
-Response InspectorPageAgent::removeScriptToEvaluateOnLoad(
+Response InspectorPageAgent::removeScriptToEvaluateOnNewDocument(
     const String& identifier) {
   if (scripts_to_evaluate_on_load_.Get(identifier).IsNull())
     return Response::Error("Script not found");
@@ -572,15 +580,15 @@
   return Response::OK();
 }
 
-Response InspectorPageAgent::addScriptToEvaluateOnNewDocument(
-    const String& source,
-    String* identifier) {
-  return addScriptToEvaluateOnLoad(source, identifier);
+Response InspectorPageAgent::addScriptToEvaluateOnLoad(const String& source,
+                                                       String* identifier) {
+  return addScriptToEvaluateOnNewDocument(source, Maybe<String>(""),
+                                          identifier);
 }
 
-Response InspectorPageAgent::removeScriptToEvaluateOnNewDocument(
+Response InspectorPageAgent::removeScriptToEvaluateOnLoad(
     const String& identifier) {
-  return removeScriptToEvaluateOnLoad(identifier);
+  return removeScriptToEvaluateOnNewDocument(identifier);
 }
 
 Response InspectorPageAgent::setLifecycleEventsEnabled(bool enabled) {
@@ -843,10 +851,45 @@
               return Decimal::FromString(a) < Decimal::FromString(b);
             });
 
+  HashMap<String, int> world_id_by_name;
   for (const WTF::String& key : keys) {
-    const WTF::String& script = scripts_to_evaluate_on_load_.Get(key);
-    frame->GetScriptController().ExecuteScriptInMainWorld(script);
+    const String script = scripts_to_evaluate_on_load_.Get(key);
+    std::unique_ptr<JSONObject> object = JSONObject::From(ParseJSON(script));
+    String source;
+    DCHECK(object->GetString("source", &source));
+    String world_name;
+    DCHECK(object->GetString("world_name", &world_name));
+
+    if (world_name.IsEmpty()) {
+      frame->GetScriptController().ExecuteScriptInMainWorld(source);
+      continue;
+    }
+
+    auto it = world_id_by_name.find(world_name);
+    int world_id = 0;
+    if (it != world_id_by_name.end()) {
+      world_id = it->value;
+    } else {
+      scoped_refptr<DOMWrapperWorld> world =
+          frame->GetScriptController().CreateNewInspectorIsolatedWorld(
+              world_name);
+      if (!world)
+        continue;
+      world_id = world->GetWorldId();
+      world_id_by_name.Set(world_name, world_id);
+
+      scoped_refptr<SecurityOrigin> security_origin =
+          frame->GetSecurityContext()->GetSecurityOrigin()->IsolatedCopy();
+      security_origin->GrantUniversalAccess();
+      DOMWrapperWorld::SetIsolatedWorldSecurityOrigin(world_id,
+                                                      security_origin);
+    }
+
+    v8::HandleScope handle_scope(V8PerIsolateData::MainThreadIsolate());
+    frame->GetScriptController().ExecuteScriptInIsolatedWorld(
+        world_id, source, KURL(), kNotSharableCrossOrigin);
   }
+
   if (!script_to_evaluate_on_load_once_.IsEmpty()) {
     frame->GetScriptController().ExecuteScriptInMainWorld(
         script_to_evaluate_on_load_once_);
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
index 7348b4d..f099ed6 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
@@ -115,6 +115,7 @@
       const String& identifier) override;
   protocol::Response addScriptToEvaluateOnNewDocument(
       const String& source,
+      Maybe<String> world_name,
       String* identifier) override;
   protocol::Response removeScriptToEvaluateOnNewDocument(
       const String& identifier) override;
diff --git a/third_party/blink/renderer/core/layout/floating_objects.cc b/third_party/blink/renderer/core/layout/floating_objects.cc
index befe3dd..2395bd9a 100644
--- a/third_party/blink/renderer/core/layout/floating_objects.cc
+++ b/third_party/blink/renderer/core/layout/floating_objects.cc
@@ -323,7 +323,7 @@
 
 FloatingObjects::FloatingObjects(const LayoutBlockFlow* layout_object,
                                  bool horizontal_writing_mode)
-    : placed_floats_tree_(kUninitializedTree),
+    : placed_floats_tree_(WTF::kUninitializedTree),
       left_objects_count_(0),
       right_objects_count_(0),
       horizontal_writing_mode_(horizontal_writing_mode),
@@ -760,14 +760,18 @@
   return false;
 }
 
+}  // namespace blink
+
+namespace WTF {
 #ifndef NDEBUG
 // These helpers are only used by the PODIntervalTree for debugging purposes.
-String ValueToString<LayoutUnit>::ToString(const LayoutUnit value) {
+String ValueToString<blink::LayoutUnit>::ToString(
+    const blink::LayoutUnit value) {
   return String::Number(value.ToFloat());
 }
 
-String ValueToString<FloatingObject*>::ToString(
-    const FloatingObject* floating_object) {
+String ValueToString<blink::FloatingObject*>::ToString(
+    const blink::FloatingObject* floating_object) {
   return String::Format("%p (%gx%g %gx%g)", floating_object,
                         floating_object->FrameRect().X().ToFloat(),
                         floating_object->FrameRect().Y().ToFloat(),
@@ -775,5 +779,4 @@
                         floating_object->FrameRect().MaxY().ToFloat());
 }
 #endif
-
-}  // namespace blink
+}  // namespace WTF
diff --git a/third_party/blink/renderer/core/layout/floating_objects.h b/third_party/blink/renderer/core/layout/floating_objects.h
index 52afcd2..0eaa0ded 100644
--- a/third_party/blink/renderer/core/layout/floating_objects.h
+++ b/third_party/blink/renderer/core/layout/floating_objects.h
@@ -28,9 +28,10 @@
 #include <memory>
 #include "base/macros.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
-#include "third_party/blink/renderer/platform/pod_free_list_arena.h"
-#include "third_party/blink/renderer/platform/pod_interval_tree.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/list_hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/pod_free_list_arena.h"
+#include "third_party/blink/renderer/platform/wtf/pod_interval_tree.h"
 
 namespace blink {
 
@@ -45,7 +46,7 @@
 #ifndef NDEBUG
   // Used by the PODIntervalTree for debugging the FloatingObject.
   template <class>
-  friend struct ValueToString;
+  friend struct WTF::ValueToString;
 #endif
 
   // Note that Type uses bits so you can use FloatLeftRight as a mask to query
@@ -186,9 +187,10 @@
                     FloatingObjectHashFunctions>
     FloatingObjectSet;
 typedef FloatingObjectSet::const_iterator FloatingObjectSetIterator;
-typedef PODInterval<LayoutUnit, FloatingObject*> FloatingObjectInterval;
-typedef PODIntervalTree<LayoutUnit, FloatingObject*> FloatingObjectTree;
-typedef PODFreeListArena<PODRedBlackTree<FloatingObjectInterval>::Node>
+typedef WTF::PODInterval<LayoutUnit, FloatingObject*> FloatingObjectInterval;
+typedef WTF::PODIntervalTree<LayoutUnit, FloatingObject*> FloatingObjectTree;
+typedef WTF::PODFreeListArena<
+    WTF::PODRedBlackTree<FloatingObjectInterval>::Node>
     IntervalArena;
 typedef HashMap<LayoutBox*, std::unique_ptr<FloatingObject>>
     LayoutBoxToFloatInfoMap;
@@ -279,18 +281,20 @@
   DISALLOW_COPY_AND_ASSIGN(FloatingObjects);
 };
 
+}  // namespace blink
+
+namespace WTF {
 #ifndef NDEBUG
 // These structures are used by PODIntervalTree for debugging purposes.
 template <>
-struct ValueToString<LayoutUnit> {
-  static String ToString(const LayoutUnit value);
+struct ValueToString<blink::LayoutUnit> {
+  static String ToString(const blink::LayoutUnit value);
 };
 template <>
-struct ValueToString<FloatingObject*> {
-  static String ToString(const FloatingObject*);
+struct ValueToString<blink::FloatingObject*> {
+  static String ToString(const blink::FloatingObject*);
 };
 #endif
-
-}  // namespace blink
+}  // namespace WTF
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_FLOATING_OBJECTS_H_
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index a978ab44..fc2c1af 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2113,7 +2113,7 @@
 
   LayoutBoxModelObject* cb = ToLayoutBoxModelObject(Container());
   LayoutUnit height = ContainingBlockLogicalHeightForPositioned(cb);
-  if (StyleRef().GetPosition() != EPosition::kAbsolute)
+  if (IsInFlowPositioned())
     height -= cb->PaddingLogicalHeight();
   return height;
 }
diff --git a/third_party/blink/renderer/core/layout/layout_fieldset.cc b/third_party/blink/renderer/core/layout/layout_fieldset.cc
index d4089429..9209773 100644
--- a/third_party/blink/renderer/core/layout/layout_fieldset.cc
+++ b/third_party/blink/renderer/core/layout/layout_fieldset.cc
@@ -37,6 +37,10 @@
 
 void LayoutFieldset::ComputePreferredLogicalWidths() {
   LayoutBlockFlow::ComputePreferredLogicalWidths();
+  // Size-contained elements don't consider their contents for preferred sizing.
+  if (ShouldApplySizeContainment())
+    return;
+
   if (LayoutBox* legend = FindInFlowLegend()) {
     int legend_min_width = legend->MinPreferredLogicalWidth().ToInt();
 
diff --git a/third_party/blink/renderer/core/layout/layout_flow_thread.h b/third_party/blink/renderer/core/layout/layout_flow_thread.h
index 7a4c1d1..08d9403 100644
--- a/third_party/blink/renderer/core/layout/layout_flow_thread.h
+++ b/third_party/blink/renderer/core/layout/layout_flow_thread.h
@@ -191,8 +191,9 @@
 
   LayoutMultiColumnSetList multi_column_set_list_;
 
-  typedef PODInterval<LayoutUnit, LayoutMultiColumnSet*> MultiColumnSetInterval;
-  typedef PODIntervalTree<LayoutUnit, LayoutMultiColumnSet*>
+  typedef WTF::PODInterval<LayoutUnit, LayoutMultiColumnSet*>
+      MultiColumnSetInterval;
+  typedef WTF::PODIntervalTree<LayoutUnit, LayoutMultiColumnSet*>
       MultiColumnSetIntervalTree;
 
   class MultiColumnSetSearchAdapter {
@@ -219,16 +220,18 @@
 
 DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutFlowThread, IsLayoutFlowThread());
 
+}  // namespace blink
+
+namespace WTF {
 // These structures are used by PODIntervalTree for debugging.
 #ifndef NDEBUG
 template <>
-struct ValueToString<LayoutMultiColumnSet*> {
-  static String ToString(const LayoutMultiColumnSet* value) {
+struct ValueToString<blink::LayoutMultiColumnSet*> {
+  static String ToString(const blink::LayoutMultiColumnSet* value) {
     return String::Format("%p", value);
   }
 };
 #endif
-
-}  // namespace blink
+}  // namespace WTF
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_FLOW_THREAD_H_
diff --git a/third_party/blink/renderer/core/layout/layout_view.h b/third_party/blink/renderer/core/layout/layout_view.h
index 26deb9f..cf85e07 100644
--- a/third_party/blink/renderer/core/layout/layout_view.h
+++ b/third_party/blink/renderer/core/layout/layout_view.h
@@ -30,7 +30,6 @@
 #include "third_party/blink/renderer/core/layout/layout_state.h"
 #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/pod_free_list_arena.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc
index 5fdaf34..f7550a5 100644
--- a/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/html/cross_origin_attribute.h"
+#include "third_party/blink/renderer/core/html/html_dimension.h"
 #include "third_party/blink/renderer/core/html/html_image_element.h"
 #include "third_party/blink/renderer/core/html/lazy_load_image_observer.h"
 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
@@ -61,6 +62,47 @@
 
 namespace blink {
 
+namespace {
+
+bool GetAbsoluteDimensionValue(const AtomicString& attribute_value,
+                               double* value) {
+  HTMLDimension dimension;
+  if (ParseDimensionValue(attribute_value, dimension) &&
+      dimension.IsAbsolute()) {
+    *value = dimension.Value();
+    return true;
+  }
+  return false;
+}
+
+bool IsLazyLoadingImageAllowed(const LocalFrame* frame,
+                               HTMLImageElement* html_image) {
+  // Minimum width or height attribute of the image to start lazyloading.
+  const unsigned kMinDimensionToLazyLoad = 10;
+
+  // Do not lazyload image elements created from javascript.
+  if (!html_image->ElementCreatedByParser())
+    return false;
+
+  if (EqualIgnoringASCIICase(
+          html_image->FastGetAttribute(HTMLNames::lazyloadAttr), "off"))
+    return false;
+
+  // Avoid lazyloading if width and height attributes are small. This
+  // heuristic helps avoid double fetching tracking pixels.
+  double width, height;
+  if (GetAbsoluteDimensionValue(html_image->getAttribute(HTMLNames::widthAttr),
+                                &width) &&
+      GetAbsoluteDimensionValue(html_image->getAttribute(HTMLNames::heightAttr),
+                                &height) &&
+      width <= kMinDimensionToLazyLoad && height <= kMinDimensionToLazyLoad) {
+    return false;
+  }
+  return frame->IsLazyLoadingImageAllowed();
+}
+
+}  // namespace
+
 static ImageLoader::BypassMainWorldBehavior ShouldBypassMainWorldCSP(
     ImageLoader* loader) {
   DCHECK(loader);
@@ -451,10 +493,7 @@
       if (frame->IsClientLoFiAllowed(params.GetResourceRequest())) {
         params.SetClientLoFiPlaceholder();
       } else if (auto* html_image = ToHTMLImageElementOrNull(GetElement())) {
-        if (html_image->ElementCreatedByParser() &&
-            !EqualIgnoringASCIICase(
-                html_image->FastGetAttribute(HTMLNames::lazyloadAttr), "off") &&
-            frame->IsLazyLoadingImageAllowed()) {
+        if (IsLazyLoadingImageAllowed(frame, html_image)) {
           params.SetAllowImagePlaceholder();
           lazy_image_load_state_ = LazyImageLoadState::kDeferred;
         }
diff --git a/third_party/blink/renderer/core/loader/interactive_detector.h b/third_party/blink/renderer/core/loader/interactive_detector.h
index 0347110..ce88419 100644
--- a/third_party/blink/renderer/core/loader/interactive_detector.h
+++ b/third_party/blink/renderer/core/loader/interactive_detector.h
@@ -15,9 +15,9 @@
 #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/pod_interval.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/timer.h"
+#include "third_party/blink/renderer/platform/wtf/pod_interval.h"
 
 namespace blink {
 
@@ -140,8 +140,8 @@
   };
 
   // Stores sufficiently long quiet windows on main thread and network.
-  std::vector<PODInterval<TimeTicks>> main_thread_quiet_windows_;
-  std::vector<PODInterval<TimeTicks>> network_quiet_windows_;
+  std::vector<WTF::PODInterval<TimeTicks>> main_thread_quiet_windows_;
+  std::vector<WTF::PODInterval<TimeTicks>> network_quiet_windows_;
 
   // Start times of currently active main thread and network quiet windows.
   // Null TimeTicks values indicate main thread or network is not quiet at the
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
index 0eaab63..6f5f27e 100644
--- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
+++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
@@ -24,9 +24,6 @@
 
 }  // namespace
 
-constexpr TimeDelta FirstMeaningfulPaintDetector::kNetwork2QuietWindowTimeout;
-constexpr TimeDelta FirstMeaningfulPaintDetector::kNetwork0QuietWindowTimeout;
-
 FirstMeaningfulPaintDetector& FirstMeaningfulPaintDetector::From(
     Document& document) {
   return PaintTiming::From(document).GetFirstMeaningfulPaintDetector();
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
index 8c1c48d7..43af429 100644
--- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
+++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
@@ -57,13 +57,6 @@
     kDeferFirstContentfulPaintNotSet
   };
 
-  // The page is n-quiet if there are no more than n active network requests for
-  // this duration of time.
-  static constexpr TimeDelta kNetwork2QuietWindowTimeout =
-      TimeDelta::FromSecondsD(0.5);
-  static constexpr TimeDelta kNetwork0QuietWindowTimeout =
-      TimeDelta::FromSecondsD(0.5);
-
   Document* GetDocument();
   int ActiveConnections();
   void ReportHistograms();
@@ -80,8 +73,6 @@
   TimeTicks provisional_first_meaningful_paint_swap_;
   double max_significance_so_far_ = 0.0;
   double accumulated_significance_while_having_blank_text_ = 0.0;
-  TimeDelta network2_quiet_window_timeout_ = kNetwork2QuietWindowTimeout;
-  TimeDelta network0_quiet_window_timeout_ = kNetwork0QuietWindowTimeout;
   unsigned prev_layout_object_count_ = 0;
   bool seen_first_meaningful_paint_candidate_ = false;
   bool network0_quiet_reached_ = false;
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
index a4bd180..888ceb2 100644
--- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
+++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
@@ -103,13 +103,6 @@
  protected:
   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
       platform_;
-
-  TimeDelta GetNetwork0QuietWindowTimeout() {
-    return FirstMeaningfulPaintDetector::kNetwork0QuietWindowTimeout;
-  }
-  TimeDelta GetNetwork2QuietWindowTimeout() {
-    return FirstMeaningfulPaintDetector::kNetwork2QuietWindowTimeout;
-  }
 };
 
 TEST_F(FirstMeaningfulPaintDetectorTest, NoFirstPaint) {
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 1db6d50..9a2f9ce7 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -689,8 +689,7 @@
   if (blend_mode != SkBlendMode::kSrcOver)
     return true;
 
-  float opacity = style.Opacity();
-  if (opacity != 1.0f)
+  if (style.Opacity() != 1.0f || style.HasWillChangeOpacityHint())
     return true;
 
   if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(style))
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 196a6985..de451e17 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -6302,4 +6302,24 @@
       inner_properties->StickyTranslation()->GetStickyConstraint().is_sticky);
 }
 
+TEST_P(PaintPropertyTreeBuilderTest, WillChangeOpacityInducesAnEffectNode) {
+  SetBodyInnerHTML(R"HTML(
+    <style>.transluscent { opacity: 0.5; }</style>
+    <div id="div" style="width:10px; height:10px; will-change: opacity;"></div>
+  )HTML");
+
+  const auto* properties = PaintPropertiesForElement("div");
+  ASSERT_TRUE(properties);
+  ASSERT_TRUE(properties->Effect());
+  EXPECT_FLOAT_EQ(properties->Effect()->Opacity(), 1.f);
+
+  auto* div = GetDocument().getElementById("div");
+  div->setAttribute(HTMLNames::classAttr, "transluscent");
+  GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+  EXPECT_FALSE(ToLayoutBox(div->GetLayoutObject())->Layer()->NeedsRepaint());
+
+  ASSERT_TRUE(properties->Effect());
+  EXPECT_FLOAT_EQ(properties->Effect()->Opacity(), 0.5f);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/replaced_painter.cc b/third_party/blink/renderer/core/paint/replaced_painter.cc
index 71ca4b9..e9e153f70 100644
--- a/third_party/blink/renderer/core/paint/replaced_painter.cc
+++ b/third_party/blink/renderer/core/paint/replaced_painter.cc
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/core/paint/rounded_inner_rect_clipper.h"
 #include "third_party/blink/renderer/core/paint/scoped_paint_state.h"
 #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
 #include "third_party/blink/renderer/core/paint/selection_painting_utils.h"
diff --git a/third_party/blink/renderer/core/timing/event_timing.cc b/third_party/blink/renderer/core/timing/event_timing.cc
index 5918016..589c2fa 100644
--- a/third_party/blink/renderer/core/timing/event_timing.cc
+++ b/third_party/blink/renderer/core/timing/event_timing.cc
@@ -17,15 +17,15 @@
   performance_ = DOMWindowPerformance::performance(*window);
 }
 
-bool EventTiming::ShouldReportForEventTiming(const Event* event) const {
-  return (event->IsMouseEvent() || event->IsPointerEvent() ||
-          event->IsTouchEvent() || event->IsKeyboardEvent() ||
-          event->IsWheelEvent() || event->IsInputEvent() ||
-          event->IsCompositionEvent()) &&
-         event->isTrusted();
+bool EventTiming::ShouldReportForEventTiming(const Event& event) const {
+  return (event.IsMouseEvent() || event.IsPointerEvent() ||
+          event.IsTouchEvent() || event.IsKeyboardEvent() ||
+          event.IsWheelEvent() || event.IsInputEvent() ||
+          event.IsCompositionEvent()) &&
+         event.isTrusted();
 }
 
-void EventTiming::WillDispatchEvent(const Event* event) {
+void EventTiming::WillDispatchEvent(const Event& event) {
   // Assume each event can be dispatched only once.
   DCHECK(!finished_will_dispatch_event_);
   if (!performance_ || !ShouldReportForEventTiming(event))
@@ -43,21 +43,20 @@
   }
 }
 
-void EventTiming::DidDispatchEvent(const Event* event) {
+void EventTiming::DidDispatchEvent(const Event& event) {
   if (!finished_will_dispatch_event_ ||
-      (!event->executedListenerOrDefaultAction() && !event->DefaultHandled())) {
+      (!event.executedListenerOrDefaultAction() && !event.DefaultHandled())) {
     return;
   }
 
   TimeTicks start_time;
-  if (event->IsPointerEvent())
-    start_time = ToPointerEvent(event)->OldestPlatformTimeStamp();
+  if (event.IsPointerEvent())
+    start_time = ToPointerEvent(&event)->OldestPlatformTimeStamp();
   else
-    start_time = event->PlatformTimeStamp();
+    start_time = event.PlatformTimeStamp();
 
-  performance_->RegisterEventTiming(event->type(), start_time,
-                                    processing_start_, CurrentTimeTicks(),
-                                    event->cancelable());
+  performance_->RegisterEventTiming(event.type(), start_time, processing_start_,
+                                    CurrentTimeTicks(), event.cancelable());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/timing/event_timing.h b/third_party/blink/renderer/core/timing/event_timing.h
index 21216c94..59bacd8 100644
--- a/third_party/blink/renderer/core/timing/event_timing.h
+++ b/third_party/blink/renderer/core/timing/event_timing.h
@@ -22,11 +22,11 @@
  public:
   explicit EventTiming(LocalDOMWindow*);
 
-  void WillDispatchEvent(const Event*);
-  void DidDispatchEvent(const Event*);
+  void WillDispatchEvent(const Event&);
+  void DidDispatchEvent(const Event&);
 
  private:
-  bool ShouldReportForEventTiming(const Event* event) const;
+  bool ShouldReportForEventTiming(const Event& event) const;
   // The time the first event handler or default action started to execute.
   TimeTicks processing_start_;
   bool finished_will_dispatch_event_ = false;
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index cf2477e..85abc9d 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -746,9 +746,8 @@
 
   if (!async_) {
     if (GetExecutionContext()->IsDocument() &&
-        !GetDocument()->GetFrame()->DeprecatedIsFeatureEnabled(
-            mojom::FeaturePolicyFeature::kSyncXHR,
-            ReportOptions::kReportOnFailure)) {
+        !GetDocument()->IsFeatureEnabled(mojom::FeaturePolicyFeature::kSyncXHR,
+                                         ReportOptions::kReportOnFailure)) {
       LogConsoleError(GetExecutionContext(),
                       "Synchronous requests are disabled by Feature Policy.");
       HandleNetworkError();
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
index 5cbd9bf2..21f7e5751 100644
--- a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
+++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
@@ -629,7 +629,8 @@
         return new Console.ConsoleCommandResult(message, this._linkifier, this._badgePool, nestingLevel);
       case SDK.ConsoleMessage.MessageType.StartGroupCollapsed:
       case SDK.ConsoleMessage.MessageType.StartGroup:
-        return new Console.ConsoleGroupViewMessage(message, this._linkifier, this._badgePool, nestingLevel);
+        return new Console.ConsoleGroupViewMessage(
+            message, this._linkifier, this._badgePool, nestingLevel, this._updateMessageList.bind(this));
       default:
         return new Console.ConsoleViewMessage(message, this._linkifier, this._badgePool, nestingLevel);
     }
@@ -869,13 +870,6 @@
         this.focus();
       }
     }
-    // TODO: fix this.
-    const groupMessage = event.target.enclosingNodeOrSelfWithClass('console-group-title');
-    if (!groupMessage)
-      return;
-    const consoleGroupViewMessage = groupMessage.message;
-    consoleGroupViewMessage.setCollapsed(!consoleGroupViewMessage.collapsed());
-    this._updateMessageList();
   }
 
   /**
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
index dff95d6..22236b1 100644
--- a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
+++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
@@ -52,6 +52,9 @@
     this._searchRegex = null;
     /** @type {?UI.Icon} */
     this._messageLevelIcon = null;
+    this._traceExpanded = false;
+    /** @type {?function(boolean)} */
+    this._expandTrace = null;
   }
 
   /**
@@ -377,30 +380,28 @@
         this._message.runtimeModel().target(), this._linkifier, this._message.stackTrace);
     stackTraceElement.appendChild(stackTracePreview);
     stackTraceElement.classList.add('hidden');
-
-    /**
-     * @param {boolean} expand
-     */
-    function expandStackTrace(expand) {
+    this._expandTrace = expand => {
       icon.setIconType(expand ? 'smallicon-triangle-down' : 'smallicon-triangle-right');
       stackTraceElement.classList.toggle('hidden', !expand);
-    }
+      this._traceExpanded = expand;
+    };
 
     /**
+     * @this {!Console.ConsoleViewMessage}
      * @param {?Event} event
      */
     function toggleStackTrace(event) {
       if (UI.isEditing() || contentElement.hasSelection())
         return;
-      expandStackTrace(stackTraceElement.classList.contains('hidden'));
+      this._expandTrace(stackTraceElement.classList.contains('hidden'));
       event.consume();
     }
 
-    clickableElement.addEventListener('click', toggleStackTrace, false);
+    clickableElement.addEventListener('click', toggleStackTrace.bind(this), false);
     if (this._message.type === SDK.ConsoleMessage.MessageType.Trace)
-      expandStackTrace(true);
+      this._expandTrace(true);
 
-    toggleElement._expandStackTraceForTest = expandStackTrace.bind(null, true);
+    toggleElement._expandStackTraceForTest = this._expandTrace.bind(this, true);
     return toggleElement;
   }
 
@@ -1034,6 +1035,31 @@
   }
 
   /**
+   * @param {!Event} event
+   */
+  _onKeyDown(event) {
+    if (UI.isEditing() || !this._element.hasFocus() || this._element.hasSelection())
+      return;
+    if (this.maybeHandleOnKeyDown(event))
+      event.consume(true);
+  }
+
+  /**
+   * @protected
+   * @param {!Event} event
+   */
+  maybeHandleOnKeyDown(event) {
+    // Handle trace expansion.
+    if (this._expandTrace) {
+      if ((event.key === 'ArrowLeft' && this._traceExpanded) || (event.key === 'ArrowRight' && !this._traceExpanded)) {
+        this._expandTrace(!this._traceExpanded);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
    * @return {!Element}
    */
   contentElement() {
@@ -1072,8 +1098,10 @@
       return this._element;
 
     this._element = createElement('div');
-    if (Runtime.experiments.isEnabled('consoleKeyboardNavigation'))
+    if (Runtime.experiments.isEnabled('consoleKeyboardNavigation')) {
       this._element.tabIndex = -1;
+      this._element.addEventListener('keydown', this._onKeyDown.bind(this));
+    }
     this.updateMessageElement();
     return this._element;
   }
@@ -1496,22 +1524,25 @@
    * @param {!Components.Linkifier} linkifier
    * @param {!ProductRegistry.BadgePool} badgePool
    * @param {number} nestingLevel
+   * @param {function()} onToggle
    */
-  constructor(consoleMessage, linkifier, badgePool, nestingLevel) {
+  constructor(consoleMessage, linkifier, badgePool, nestingLevel, onToggle) {
     console.assert(consoleMessage.isGroupStartMessage());
     super(consoleMessage, linkifier, badgePool, nestingLevel);
     this._collapsed = consoleMessage.type === SDK.ConsoleMessage.MessageType.StartGroupCollapsed;
     /** @type {?UI.Icon} */
     this._expandGroupIcon = null;
+    this._onToggle = onToggle;
   }
 
   /**
    * @param {boolean} collapsed
    */
-  setCollapsed(collapsed) {
+  _setCollapsed(collapsed) {
     this._collapsed = collapsed;
     if (this._expandGroupIcon)
       this._expandGroupIcon.setIconType(this._collapsed ? 'smallicon-triangle-right' : 'smallicon-triangle-down');
+    this._onToggle.call(null);
   }
 
   /**
@@ -1523,19 +1554,32 @@
 
   /**
    * @override
+   * @param {!Event} event
+   */
+  maybeHandleOnKeyDown(event) {
+    if ((event.key === 'ArrowLeft' && !this._collapsed) || (event.key === 'ArrowRight' && this._collapsed)) {
+      this._setCollapsed(!this._collapsed);
+      return true;
+    }
+    return super.maybeHandleOnKeyDown(event);
+  }
+
+  /**
+   * @override
    * @return {!Element}
    */
   toMessageElement() {
     if (!this._element) {
       super.toMessageElement();
-      this._expandGroupIcon = UI.Icon.create('', 'expand-group-icon');
+      const iconType = this._collapsed ? 'smallicon-triangle-right' : 'smallicon-triangle-down';
+      this._expandGroupIcon = UI.Icon.create(iconType, 'expand-group-icon');
       // Intercept focus to avoid highlight on click.
       this._contentElement.tabIndex = -1;
       if (this._repeatCountElement)
         this._repeatCountElement.insertBefore(this._expandGroupIcon, this._repeatCountElement.firstChild);
       else
         this._element.insertBefore(this._expandGroupIcon, this._contentElement);
-      this.setCollapsed(this._collapsed);
+      this._element.addEventListener('click', () => this._setCollapsed(!this._collapsed));
     }
     return this._element;
   }
diff --git a/third_party/blink/renderer/devtools/front_end/console/consoleView.css b/third_party/blink/renderer/devtools/front_end/console/consoleView.css
index 6116572..58ba943 100644
--- a/third_party/blink/renderer/devtools/front_end/console/consoleView.css
+++ b/third_party/blink/renderer/devtools/front_end/console/consoleView.css
@@ -271,6 +271,7 @@
     border-right: 1px solid #a5a5a5;
     position: relative;
     margin-bottom: -1px;
+    margin-top: -1px;
 }
 
 .console-message-wrapper:last-child .nesting-level-marker::before,
diff --git a/third_party/blink/renderer/devtools/front_end/externs.js b/third_party/blink/renderer/devtools/front_end/externs.js
index 52658203..6f7fcbc3 100644
--- a/third_party/blink/renderer/devtools/front_end/externs.js
+++ b/third_party/blink/renderer/devtools/front_end/externs.js
@@ -714,13 +714,6 @@
   /**
    * @param {string} text
    * @param {Object.<string, boolean>} options
-   * @return {!ESTree.Node}
-   */
-  parse_dammit: function(text, options) {},
-
-  /**
-   * @param {string} text
-   * @param {Object.<string, boolean>} options
    * @return {!Acorn.Tokenizer}
    */
   tokenizer: function(text, options) {},
@@ -737,6 +730,15 @@
   }
 };
 
+acorn.loose = {};
+
+/**
+ * @param {string} text
+ * @param {Object.<string, boolean>} options
+ * @return {!ESTree.Node}
+ */
+acorn.loose.parse = function(text, options) {};
+
 const Acorn = {};
 /**
  * @constructor
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/ESTreeWalker.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/ESTreeWalker.js
index b33d334..6116972 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/ESTreeWalker.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/ESTreeWalker.js
@@ -96,6 +96,7 @@
   'ArrayPattern': ['elements'],
   'ArrowFunctionExpression': ['params', 'body'],
   'AssignmentExpression': ['left', 'right'],
+  'AssignmentPattern': ['left', 'right'],
   'BinaryExpression': ['left', 'right'],
   'BlockStatement': ['body'],
   'BreakStatement': ['label'],
@@ -130,6 +131,7 @@
   'Property': ['key', 'value'],
   'ReturnStatement': ['argument'],
   'SequenceExpression': ['expressions'],
+  'SpreadElement': ['argument'],
   'Super': [],
   'SwitchCase': ['test', 'consequent'],
   'SwitchStatement': ['discriminant', 'cases'],
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
index 064e04c..d192c24 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
@@ -151,11 +151,11 @@
  * @param {string} content
  */
 FormatterWorker.preprocessTopLevelAwaitExpressions = function(content) {
-  let wrapped = '(async () => {' + content + '})()';
+  let wrapped = '(async () => {' + content + '\n})()';
   let root;
   let body;
   try {
-    root = acorn.parse(wrapped, {ecmaVersion: 9});
+    root = acorn.parse(wrapped, {ecmaVersion: 10});
     body = root.body[0].expression.callee.body;
   } catch (e) {
     postMessage('');
@@ -185,6 +185,10 @@
     AwaitExpression(node) {
       containsAwait = true;
     }
+    ForOfStatement(node) {
+      if (node.await)
+        containsAwait = true;
+    }
     ReturnStatement(node) {
       containsReturn = true;
     }
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js
index 7648a92..7c45d38 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js
@@ -13,7 +13,7 @@
   try {
     ast = acorn.parse(content, {ranges: false, ecmaVersion: 8});
   } catch (e) {
-    ast = acorn.parse_dammit(content, {ranges: false, ecmaVersion: 8});
+    ast = acorn.loose.parse(content, {ranges: false, ecmaVersion: 8});
   }
 
   const textCursor = new TextUtils.TextCursor(content.computeLineEndings());
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn.js
index b8e0efe..189c222 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn.js
@@ -34,8 +34,8 @@
 // code point above 128.
 // Generated by `bin/generate-identifier-regex.js`.
 
-var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u08a0-\u08b4\u08b6-\u08bd\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312e\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fea\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
-var nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d4-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf7-\u1cf9\u1dc0-\u1df9\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f";
+var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u08a0-\u08b4\u08b6-\u08bd\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fef\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7b9\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
+var nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d3-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf7-\u1cf9\u1dc0-\u1df9\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f";
 
 var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
 var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
@@ -49,10 +49,10 @@
 // generated by bin/generate-identifier-regex.js
 
 // eslint-disable-next-line comma-spacing
-var astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,26,45,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,785,52,76,44,33,24,27,35,42,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,25,391,63,32,0,257,0,11,39,8,0,22,0,12,39,3,3,55,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,698,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,881,68,12,0,67,12,65,1,31,6124,20,754,9486,286,82,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,15,7472,3104,541];
+var astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,477,28,11,0,9,21,190,52,76,44,33,24,27,35,30,0,12,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,26,230,43,117,63,32,0,257,0,11,39,8,0,22,0,12,39,3,3,20,0,35,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,270,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,689,63,129,68,12,0,67,12,65,1,31,6129,15,754,9486,286,82,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,15,7472,3104,541];
 
 // eslint-disable-next-line comma-spacing
-var astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,1306,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,52,0,13,2,49,13,10,2,4,9,83,11,7,0,161,11,6,9,7,3,57,0,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,87,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,423,9,280,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,19719,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239];
+var astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,525,10,176,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,4,9,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,280,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239];
 
 // This has a complexity linear to the value of the code. The
 // assumption is that looking up astral identifier characters is
@@ -251,8 +251,8 @@
 var lineBreak = /\r\n?|\n|\u2028|\u2029/;
 var lineBreakG = new RegExp(lineBreak.source, "g");
 
-function isNewLine(code) {
-  return code === 10 || code === 13 || code === 0x2028 || code === 0x2029
+function isNewLine(code, ecma2019String) {
+  return code === 10 || code === 13 || (!ecma2019String && (code === 0x2028 || code === 0x2029))
 }
 
 var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/;
@@ -314,11 +314,12 @@
 // the parser process. These options are recognized:
 
 var defaultOptions = {
-  // `ecmaVersion` indicates the ECMAScript version to parse. Must
-  // be either 3, 5, 6 (2015), 7 (2016), or 8 (2017). This influences support
-  // for strict mode, the set of reserved words, and support for
-  // new syntax features. The default is 7.
-  ecmaVersion: 7,
+  // `ecmaVersion` indicates the ECMAScript version to parse. Must be
+  // either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018), or 10
+  // (2019). This influences support for strict mode, the set of
+  // reserved words, and support for new syntax features. The default
+  // is 9.
+  ecmaVersion: 9,
   // `sourceType` indicates the mode the code should be parsed in.
   // Can be either `"script"` or `"module"`. This influences global
   // strict mode and parsing of `import` and `export` declarations.
@@ -343,6 +344,9 @@
   // When enabled, import/export statements are not constrained to
   // appearing at the top of the program.
   allowImportExportEverywhere: false,
+  // When enabled, await identifiers are allowed to appear at the top-level scope,
+  // but they are still not allowed in non-async functions.
+  allowAwaitOutsideFunction: false,
   // When enabled, hashbang directive in the beginning of file
   // is allowed and treated as a line comment.
   allowHashBang: false,
@@ -391,8 +395,7 @@
   directSourceFile: null,
   // When enabled, parenthesized expressions are represented by
   // (non-standard) ParenthesizedExpression nodes
-  preserveParens: false,
-  plugins: {}
+  preserveParens: false
 };
 
 // Interpret and default an options object
@@ -435,8 +438,26 @@
   }
 }
 
-// Registered plugins
-var plugins = {};
+// Each scope gets a bitset that may contain these flags
+var SCOPE_TOP = 1;
+var SCOPE_FUNCTION = 2;
+var SCOPE_VAR = SCOPE_TOP | SCOPE_FUNCTION;
+var SCOPE_ASYNC = 4;
+var SCOPE_GENERATOR = 8;
+var SCOPE_ARROW = 16;
+var SCOPE_SIMPLE_CATCH = 32;
+
+function functionFlags(async, generator) {
+  return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0)
+}
+
+// Used in checkLVal and declareName to determine the type of a binding
+var BIND_NONE = 0;
+var BIND_VAR = 1;
+var BIND_LEXICAL = 2;
+var BIND_FUNCTION = 3;
+var BIND_SIMPLE_CATCH = 4;
+var BIND_OUTSIDE = 5; // Special case for function names as bound inside the function
 
 function keywordRegexp(words) {
   return new RegExp("^(?:" + words.replace(/ /g, "|") + ")$")
@@ -450,7 +471,7 @@
   if (!options.allowReserved) {
     for (var v = options.ecmaVersion;; v--)
       { if (reserved = reservedWords[v]) { break } }
-    if (options.sourceType == "module") { reserved += " await"; }
+    if (options.sourceType === "module") { reserved += " await"; }
   }
   this.reservedWords = keywordRegexp(reserved);
   var reservedStrict = (reserved ? reserved + " " : "") + reservedWords.strict;
@@ -463,9 +484,6 @@
   // escape sequences must not be interpreted as keywords.
   this.containsEsc = false;
 
-  // Load plugins
-  this.loadPlugins(options.plugins);
-
   // Set up token state
 
   // The current position of the tokenizer in the input.
@@ -506,8 +524,6 @@
   // Used to signify the start of a potential arrow function
   this.potentialArrowAt = -1;
 
-  // Flags to track whether we are in a function, a generator, an async function.
-  this.inFunction = this.inGenerator = this.inAsync = false;
   // Positions to delayed-check that yield/await does not exist in default parameters.
   this.yieldPos = this.awaitPos = 0;
   // Labels in scope.
@@ -519,29 +535,13 @@
 
   // Scope tracking for duplicate variable names (see scope.js)
   this.scopeStack = [];
-  this.enterFunctionScope();
+  this.enterScope(SCOPE_TOP);
 
   // For RegExp validation
   this.regexpState = null;
 };
 
-// DEPRECATED Kept for backwards compatibility until 3.0 in case a plugin uses them
-Parser.prototype.isKeyword = function isKeyword (word) { return this.keywords.test(word) };
-Parser.prototype.isReservedWord = function isReservedWord (word) { return this.reservedWords.test(word) };
-
-Parser.prototype.extend = function extend (name, f) {
-  this[name] = f(this[name]);
-};
-
-Parser.prototype.loadPlugins = function loadPlugins (pluginConfigs) {
-    var this$1 = this;
-
-  for (var name in pluginConfigs) {
-    var plugin = plugins[name];
-    if (!plugin) { throw new Error("Plugin '" + name + "' not found") }
-    plugin(this$1, pluginConfigs[name]);
-  }
-};
+var prototypeAccessors = { inFunction: { configurable: true },inGenerator: { configurable: true },inAsync: { configurable: true } };
 
 Parser.prototype.parse = function parse () {
   var node = this.options.program || this.startNode();
@@ -549,6 +549,35 @@
   return this.parseTopLevel(node)
 };
 
+prototypeAccessors.inFunction.get = function () { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 };
+prototypeAccessors.inGenerator.get = function () { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 };
+prototypeAccessors.inAsync.get = function () { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 };
+
+Parser.extend = function extend () {
+    var plugins = [], len = arguments.length;
+    while ( len-- ) plugins[ len ] = arguments[ len ];
+
+  var cls = this;
+  for (var i = 0; i < plugins.length; i++) { cls = plugins[i](cls); }
+  return cls
+};
+
+Parser.parse = function parse (input, options) {
+  return new this(options, input).parse()
+};
+
+Parser.parseExpressionAt = function parseExpressionAt (input, pos, options) {
+  var parser = new this(options, input, pos);
+  parser.nextToken();
+  return parser.parseExpression()
+};
+
+Parser.tokenizer = function tokenizer (input, options) {
+  return new this(options, input)
+};
+
+Object.defineProperties( Parser.prototype, prototypeAccessors );
+
 var pp = Parser.prototype;
 
 // ## Parser utilities
@@ -562,7 +591,7 @@
     start += skipWhiteSpace.exec(this$1.input)[0].length;
     var match = literal.exec(this$1.input.slice(start));
     if (!match) { return false }
-    if ((match[1] || match[2]) == "use strict") { return true }
+    if ((match[1] || match[2]) === "use strict") { return true }
     start += match[0].length;
   }
 };
@@ -623,7 +652,7 @@
 };
 
 pp.afterTrailingComma = function(tokType, notNext) {
-  if (this.type == tokType) {
+  if (this.type === tokType) {
     if (this.options.onTrailingComma)
       { this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc); }
     if (!notNext)
@@ -701,7 +730,7 @@
   var exports = {};
   if (!node.body) { node.body = []; }
   while (this.type !== types.eof) {
-    var stmt = this$1.parseStatement(true, true, exports);
+    var stmt = this$1.parseStatement(null, true, exports);
     node.body.push(stmt);
   }
   this.adaptDirectivePrologue(node.body);
@@ -720,7 +749,7 @@
   skipWhiteSpace.lastIndex = this.pos;
   var skip = skipWhiteSpace.exec(this.input);
   var next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next);
-  if (nextCh === 91 || nextCh == 123) { return true } // '{' and '['
+  if (nextCh === 91 || nextCh === 123) { return true } // '{' and '['
   if (isIdentifierStart(nextCh, true)) {
     var pos = next + 1;
     while (isIdentifierChar(this.input.charCodeAt(pos), true)) { ++pos; }
@@ -742,7 +771,7 @@
   var next = this.pos + skip[0].length;
   return !lineBreak.test(this.input.slice(this.pos, next)) &&
     this.input.slice(next, next + 8) === "function" &&
-    (next + 8 == this.input.length || !isIdentifierChar(this.input.charAt(next + 8)))
+    (next + 8 === this.input.length || !isIdentifierChar(this.input.charAt(next + 8)))
 };
 
 // Parse a single statement.
@@ -752,7 +781,7 @@
 // `if (foo) /blah/.exec(foo)`, where looking at the previous token
 // does not help.
 
-pp$1.parseStatement = function(declaration, topLevel, exports) {
+pp$1.parseStatement = function(context, topLevel, exports) {
   var starttype = this.type, node = this.startNode(), kind;
 
   if (this.isLet()) {
@@ -770,10 +799,10 @@
   case types._do: return this.parseDoStatement(node)
   case types._for: return this.parseForStatement(node)
   case types._function:
-    if (!declaration && this.options.ecmaVersion >= 6) { this.unexpected(); }
-    return this.parseFunctionStatement(node, false)
+    if ((context && (this.strict || context !== "if")) && this.options.ecmaVersion >= 6) { this.unexpected(); }
+    return this.parseFunctionStatement(node, false, !context)
   case types._class:
-    if (!declaration) { this.unexpected(); }
+    if (context) { this.unexpected(); }
     return this.parseClass(node, true)
   case types._if: return this.parseIfStatement(node)
   case types._return: return this.parseReturnStatement(node)
@@ -782,11 +811,11 @@
   case types._try: return this.parseTryStatement(node)
   case types._const: case types._var:
     kind = kind || this.value;
-    if (!declaration && kind != "var") { this.unexpected(); }
+    if (context && kind !== "var") { this.unexpected(); }
     return this.parseVarStatement(node, kind)
   case types._while: return this.parseWhileStatement(node)
   case types._with: return this.parseWithStatement(node)
-  case types.braceL: return this.parseBlock()
+  case types.braceL: return this.parseBlock(true, node)
   case types.semi: return this.parseEmptyStatement(node)
   case types._export:
   case types._import:
@@ -805,14 +834,14 @@
     // Identifier node, we switch to interpreting it as a label.
   default:
     if (this.isAsyncFunction()) {
-      if (!declaration) { this.unexpected(); }
+      if (context) { this.unexpected(); }
       this.next();
-      return this.parseFunctionStatement(node, true)
+      return this.parseFunctionStatement(node, true, !context)
     }
 
     var maybeName = this.value, expr = this.parseExpression();
     if (starttype === types.name && expr.type === "Identifier" && this.eat(types.colon))
-      { return this.parseLabeledStatement(node, maybeName, expr) }
+      { return this.parseLabeledStatement(node, maybeName, expr, context) }
     else { return this.parseExpressionStatement(node, expr) }
   }
 };
@@ -820,7 +849,7 @@
 pp$1.parseBreakContinueStatement = function(node, keyword) {
   var this$1 = this;
 
-  var isBreak = keyword == "break";
+  var isBreak = keyword === "break";
   this.next();
   if (this.eat(types.semi) || this.insertSemicolon()) { node.label = null; }
   else if (this.type !== types.name) { this.unexpected(); }
@@ -852,7 +881,7 @@
 pp$1.parseDoStatement = function(node) {
   this.next();
   this.labels.push(loopLabel);
-  node.body = this.parseStatement(false);
+  node.body = this.parseStatement("do");
   this.labels.pop();
   this.expect(types._while);
   node.test = this.parseParenExpression();
@@ -873,9 +902,9 @@
 
 pp$1.parseForStatement = function(node) {
   this.next();
-  var awaitAt = (this.options.ecmaVersion >= 9 && this.inAsync && this.eatContextual("await")) ? this.lastTokStart : -1;
+  var awaitAt = (this.options.ecmaVersion >= 9 && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction)) && this.eatContextual("await")) ? this.lastTokStart : -1;
   this.labels.push(loopLabel);
-  this.enterLexicalScope();
+  this.enterScope(0);
   this.expect(types.parenL);
   if (this.type === types.semi) {
     if (awaitAt > -1) { this.unexpected(awaitAt); }
@@ -917,17 +946,17 @@
   return this.parseFor(node, init)
 };
 
-pp$1.parseFunctionStatement = function(node, isAsync) {
+pp$1.parseFunctionStatement = function(node, isAsync, declarationPosition) {
   this.next();
-  return this.parseFunction(node, true, false, isAsync)
+  return this.parseFunction(node, FUNC_STATEMENT | (declarationPosition ? 0 : FUNC_HANGING_STATEMENT), false, isAsync)
 };
 
 pp$1.parseIfStatement = function(node) {
   this.next();
   node.test = this.parseParenExpression();
   // allow function declarations in branches, but only in non-strict mode
-  node.consequent = this.parseStatement(!this.strict && this.type == types._function);
-  node.alternate = this.eat(types._else) ? this.parseStatement(!this.strict && this.type == types._function) : null;
+  node.consequent = this.parseStatement("if");
+  node.alternate = this.eat(types._else) ? this.parseStatement("if") : null;
   return this.finishNode(node, "IfStatement")
 };
 
@@ -953,14 +982,14 @@
   node.cases = [];
   this.expect(types.braceL);
   this.labels.push(switchLabel);
-  this.enterLexicalScope();
+  this.enterScope(0);
 
   // Statements under must be grouped (by label) in SwitchCase
   // nodes. `cur` is used to keep the node that we are currently
   // adding statements to.
 
   var cur;
-  for (var sawDefault = false; this.type != types.braceR;) {
+  for (var sawDefault = false; this.type !== types.braceR;) {
     if (this$1.type === types._case || this$1.type === types._default) {
       var isCase = this$1.type === types._case;
       if (cur) { this$1.finishNode(cur, "SwitchCase"); }
@@ -977,10 +1006,10 @@
       this$1.expect(types.colon);
     } else {
       if (!cur) { this$1.unexpected(); }
-      cur.consequent.push(this$1.parseStatement(true));
+      cur.consequent.push(this$1.parseStatement(null));
     }
   }
-  this.exitLexicalScope();
+  this.exitScope();
   if (cur) { this.finishNode(cur, "SwitchCase"); }
   this.next(); // Closing brace
   this.labels.pop();
@@ -1007,13 +1036,19 @@
   if (this.type === types._catch) {
     var clause = this.startNode();
     this.next();
-    this.expect(types.parenL);
-    clause.param = this.parseBindingAtom();
-    this.enterLexicalScope();
-    this.checkLVal(clause.param, "let");
-    this.expect(types.parenR);
+    if (this.eat(types.parenL)) {
+      clause.param = this.parseBindingAtom();
+      var simple = clause.param.type === "Identifier";
+      this.enterScope(simple ? SCOPE_SIMPLE_CATCH : 0);
+      this.checkLVal(clause.param, simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL);
+      this.expect(types.parenR);
+    } else {
+      if (this.options.ecmaVersion < 10) { this.unexpected(); }
+      clause.param = null;
+      this.enterScope(0);
+    }
     clause.body = this.parseBlock(false);
-    this.exitLexicalScope();
+    this.exitScope();
     node.handler = this.finishNode(clause, "CatchClause");
   }
   node.finalizer = this.eat(types._finally) ? this.parseBlock() : null;
@@ -1033,7 +1068,7 @@
   this.next();
   node.test = this.parseParenExpression();
   this.labels.push(loopLabel);
-  node.body = this.parseStatement(false);
+  node.body = this.parseStatement("while");
   this.labels.pop();
   return this.finishNode(node, "WhileStatement")
 };
@@ -1042,7 +1077,7 @@
   if (this.strict) { this.raise(this.start, "'with' in strict mode"); }
   this.next();
   node.object = this.parseParenExpression();
-  node.body = this.parseStatement(false);
+  node.body = this.parseStatement("with");
   return this.finishNode(node, "WithStatement")
 };
 
@@ -1051,7 +1086,7 @@
   return this.finishNode(node, "EmptyStatement")
 };
 
-pp$1.parseLabeledStatement = function(node, maybeName, expr) {
+pp$1.parseLabeledStatement = function(node, maybeName, expr, context) {
   var this$1 = this;
 
   for (var i$1 = 0, list = this$1.labels; i$1 < list.length; i$1 += 1)
@@ -1064,17 +1099,17 @@
   var kind = this.type.isLoop ? "loop" : this.type === types._switch ? "switch" : null;
   for (var i = this.labels.length - 1; i >= 0; i--) {
     var label$1 = this$1.labels[i];
-    if (label$1.statementStart == node.start) {
+    if (label$1.statementStart === node.start) {
       // Update information about previous labels on this node
       label$1.statementStart = this$1.start;
       label$1.kind = kind;
     } else { break }
   }
   this.labels.push({name: maybeName, kind: kind, statementStart: this.start});
-  node.body = this.parseStatement(true);
-  if (node.body.type == "ClassDeclaration" ||
-      node.body.type == "VariableDeclaration" && node.body.kind != "var" ||
-      node.body.type == "FunctionDeclaration" && (this.strict || node.body.generator))
+  node.body = this.parseStatement(context);
+  if (node.body.type === "ClassDeclaration" ||
+      node.body.type === "VariableDeclaration" && node.body.kind !== "var" ||
+      node.body.type === "FunctionDeclaration" && (this.strict || node.body.generator || node.body.async))
     { this.raiseRecoverable(node.body.start, "Invalid labeled declaration"); }
   this.labels.pop();
   node.label = expr;
@@ -1091,23 +1126,19 @@
 // strict"` declarations when `allowStrict` is true (used for
 // function bodies).
 
-pp$1.parseBlock = function(createNewLexicalScope) {
+pp$1.parseBlock = function(createNewLexicalScope, node) {
   var this$1 = this;
   if ( createNewLexicalScope === void 0 ) createNewLexicalScope = true;
+  if ( node === void 0 ) node = this.startNode();
 
-  var node = this.startNode();
   node.body = [];
   this.expect(types.braceL);
-  if (createNewLexicalScope) {
-    this.enterLexicalScope();
-  }
+  if (createNewLexicalScope) { this.enterScope(0); }
   while (!this.eat(types.braceR)) {
-    var stmt = this$1.parseStatement(true);
+    var stmt = this$1.parseStatement(null);
     node.body.push(stmt);
   }
-  if (createNewLexicalScope) {
-    this.exitLexicalScope();
-  }
+  if (createNewLexicalScope) { this.exitScope(); }
   return this.finishNode(node, "BlockStatement")
 };
 
@@ -1122,8 +1153,8 @@
   this.expect(types.semi);
   node.update = this.type === types.parenR ? null : this.parseExpression();
   this.expect(types.parenR);
-  this.exitLexicalScope();
-  node.body = this.parseStatement(false);
+  this.exitScope();
+  node.body = this.parseStatement("for");
   this.labels.pop();
   return this.finishNode(node, "ForStatement")
 };
@@ -1134,17 +1165,17 @@
 pp$1.parseForIn = function(node, init) {
   var type = this.type === types._in ? "ForInStatement" : "ForOfStatement";
   this.next();
-  if (type == "ForInStatement") {
+  if (type === "ForInStatement") {
     if (init.type === "AssignmentPattern" ||
       (init.type === "VariableDeclaration" && init.declarations[0].init != null &&
        (this.strict || init.declarations[0].id.type !== "Identifier")))
       { this.raise(init.start, "Invalid assignment in for-in loop head"); }
   }
   node.left = init;
-  node.right = type == "ForInStatement" ? this.parseExpression() : this.parseMaybeAssign();
+  node.right = type === "ForInStatement" ? this.parseExpression() : this.parseMaybeAssign();
   this.expect(types.parenR);
-  this.exitLexicalScope();
-  node.body = this.parseStatement(false);
+  this.exitScope();
+  node.body = this.parseStatement("for");
   this.labels.pop();
   return this.finishNode(node, type)
 };
@@ -1163,7 +1194,7 @@
       decl.init = this$1.parseMaybeAssign(isFor);
     } else if (kind === "const" && !(this$1.type === types._in || (this$1.options.ecmaVersion >= 6 && this$1.isContextual("of")))) {
       this$1.unexpected();
-    } else if (decl.id.type != "Identifier" && !(isFor && (this$1.type === types._in || this$1.isContextual("of")))) {
+    } else if (decl.id.type !== "Identifier" && !(isFor && (this$1.type === types._in || this$1.isContextual("of")))) {
       this$1.raise(this$1.lastTokEnd, "Complex binding patterns require an initialization value");
     } else {
       decl.init = null;
@@ -1176,47 +1207,43 @@
 
 pp$1.parseVarId = function(decl, kind) {
   decl.id = this.parseBindingAtom(kind);
-  this.checkLVal(decl.id, kind, false);
+  this.checkLVal(decl.id, kind === "var" ? BIND_VAR : BIND_LEXICAL, false);
 };
 
+var FUNC_STATEMENT = 1;
+var FUNC_HANGING_STATEMENT = 2;
+var FUNC_NULLABLE_ID = 4;
+
 // Parse a function declaration or literal (depending on the
 // `isStatement` parameter).
 
-pp$1.parseFunction = function(node, isStatement, allowExpressionBody, isAsync) {
+pp$1.parseFunction = function(node, statement, allowExpressionBody, isAsync) {
   this.initFunction(node);
   if (this.options.ecmaVersion >= 9 || this.options.ecmaVersion >= 6 && !isAsync)
     { node.generator = this.eat(types.star); }
   if (this.options.ecmaVersion >= 8)
     { node.async = !!isAsync; }
 
-  if (isStatement) {
-    node.id = isStatement === "nullableID" && this.type != types.name ? null : this.parseIdent();
-    if (node.id) {
-      this.checkLVal(node.id, "var");
-    }
+  if (statement & FUNC_STATEMENT) {
+    node.id = (statement & FUNC_NULLABLE_ID) && this.type !== types.name ? null : this.parseIdent();
+    if (node.id && !(statement & FUNC_HANGING_STATEMENT))
+      { this.checkLVal(node.id, this.inModule && !this.inFunction ? BIND_LEXICAL : BIND_FUNCTION); }
   }
 
-  var oldInGen = this.inGenerator, oldInAsync = this.inAsync,
-      oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction;
-  this.inGenerator = node.generator;
-  this.inAsync = node.async;
+  var oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos;
   this.yieldPos = 0;
   this.awaitPos = 0;
-  this.inFunction = true;
-  this.enterFunctionScope();
+  this.enterScope(functionFlags(node.async, node.generator));
 
-  if (!isStatement)
-    { node.id = this.type == types.name ? this.parseIdent() : null; }
+  if (!(statement & FUNC_STATEMENT))
+    { node.id = this.type === types.name ? this.parseIdent() : null; }
 
   this.parseFunctionParams(node);
   this.parseFunctionBody(node, allowExpressionBody);
 
-  this.inGenerator = oldInGen;
-  this.inAsync = oldInAsync;
   this.yieldPos = oldYieldPos;
   this.awaitPos = oldAwaitPos;
-  this.inFunction = oldInFunc;
-  return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression")
+  return this.finishNode(node, (statement & FUNC_STATEMENT) ? "FunctionDeclaration" : "FunctionExpression")
 };
 
 pp$1.parseFunctionParams = function(node) {
@@ -1240,17 +1267,20 @@
   classBody.body = [];
   this.expect(types.braceL);
   while (!this.eat(types.braceR)) {
-    var member = this$1.parseClassMember(classBody);
-    if (member && member.type === "MethodDefinition" && member.kind === "constructor") {
-      if (hadConstructor) { this$1.raise(member.start, "Duplicate constructor in the same class"); }
-      hadConstructor = true;
+    var element = this$1.parseClassElement();
+    if (element) {
+      classBody.body.push(element);
+      if (element.type === "MethodDefinition" && element.kind === "constructor") {
+        if (hadConstructor) { this$1.raise(element.start, "Duplicate constructor in the same class"); }
+        hadConstructor = true;
+      }
     }
   }
   node.body = this.finishNode(classBody, "ClassBody");
   return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression")
 };
 
-pp$1.parseClassMember = function(classBody) {
+pp$1.parseClassElement = function() {
   var this$1 = this;
 
   if (this.eat(types.semi)) { return null }
@@ -1295,7 +1325,7 @@
   } else if (method.static && key.type === "Identifier" && key.name === "prototype") {
     this.raise(key.start, "Classes may not have a static property named prototype");
   }
-  this.parseClassMethod(classBody, method, isGenerator, isAsync);
+  this.parseClassMethod(method, isGenerator, isAsync);
   if (method.kind === "get" && method.value.params.length !== 0)
     { this.raiseRecoverable(method.value.start, "getter should have no params"); }
   if (method.kind === "set" && method.value.params.length !== 1)
@@ -1305,9 +1335,9 @@
   return method
 };
 
-pp$1.parseClassMethod = function(classBody, method, isGenerator, isAsync) {
+pp$1.parseClassMethod = function(method, isGenerator, isAsync) {
   method.value = this.parseMethod(isGenerator, isAsync);
-  classBody.body.push(this.finishNode(method, "MethodDefinition"));
+  return this.finishNode(method, "MethodDefinition")
 };
 
 pp$1.parseClassId = function(node, isStatement) {
@@ -1339,7 +1369,7 @@
       var fNode = this.startNode();
       this.next();
       if (isAsync) { this.next(); }
-      node.declaration = this.parseFunction(fNode, "nullableID", false, isAsync);
+      node.declaration = this.parseFunction(fNode, FUNC_STATEMENT | FUNC_NULLABLE_ID, false, isAsync, true);
     } else if (this.type === types._class) {
       var cNode = this.startNode();
       node.declaration = this.parseClass(cNode, "nullableID");
@@ -1351,7 +1381,7 @@
   }
   // export var|const|let|function|class ...
   if (this.shouldParseExportStatement()) {
-    node.declaration = this.parseStatement(true);
+    node.declaration = this.parseStatement(null);
     if (node.declaration.type === "VariableDeclaration")
       { this.checkVariableExport(exports, node.declaration.declarations); }
     else
@@ -1390,28 +1420,28 @@
   var this$1 = this;
 
   var type = pat.type;
-  if (type == "Identifier")
+  if (type === "Identifier")
     { this.checkExport(exports, pat.name, pat.start); }
-  else if (type == "ObjectPattern")
+  else if (type === "ObjectPattern")
     { for (var i = 0, list = pat.properties; i < list.length; i += 1)
       {
         var prop = list[i];
 
         this$1.checkPatternExport(exports, prop);
       } }
-  else if (type == "ArrayPattern")
+  else if (type === "ArrayPattern")
     { for (var i$1 = 0, list$1 = pat.elements; i$1 < list$1.length; i$1 += 1) {
       var elt = list$1[i$1];
 
         if (elt) { this$1.checkPatternExport(exports, elt); }
     } }
-  else if (type == "Property")
+  else if (type === "Property")
     { this.checkPatternExport(exports, pat.value); }
-  else if (type == "AssignmentPattern")
+  else if (type === "AssignmentPattern")
     { this.checkPatternExport(exports, pat.left); }
-  else if (type == "RestElement")
+  else if (type === "RestElement")
     { this.checkPatternExport(exports, pat.argument); }
-  else if (type == "ParenthesizedExpression")
+  else if (type === "ParenthesizedExpression")
     { this.checkPatternExport(exports, pat.expression); }
 };
 
@@ -1486,7 +1516,7 @@
     // import defaultObj, { x, y as z } from '...'
     var node = this.startNode();
     node.local = this.parseIdent();
-    this.checkLVal(node.local, "let");
+    this.checkLVal(node.local, BIND_LEXICAL);
     nodes.push(this.finishNode(node, "ImportDefaultSpecifier"));
     if (!this.eat(types.comma)) { return nodes }
   }
@@ -1495,7 +1525,7 @@
     this.next();
     this.expectContextual("as");
     node$1.local = this.parseIdent();
-    this.checkLVal(node$1.local, "let");
+    this.checkLVal(node$1.local, BIND_LEXICAL);
     nodes.push(this.finishNode(node$1, "ImportNamespaceSpecifier"));
     return nodes
   }
@@ -1514,7 +1544,7 @@
       this$1.checkUnreserved(node$2.imported);
       node$2.local = node$2.imported;
     }
-    this$1.checkLVal(node$2.local, "let");
+    this$1.checkLVal(node$2.local, BIND_LEXICAL);
     nodes.push(this$1.finishNode(node$2, "ImportSpecifier"));
   }
   return nodes
@@ -1578,7 +1608,7 @@
       break
 
     case "Property":
-      // AssignmentProperty has type == "Property"
+      // AssignmentProperty has type === "Property"
       if (node.kind !== "init") { this.raise(node.key.start, "Object pattern can't contain getter or setter"); }
       this.toAssignable(node.value, isBinding);
       break
@@ -1729,6 +1759,7 @@
 
 pp$2.checkLVal = function(expr, bindingType, checkClashes) {
   var this$1 = this;
+  if ( bindingType === void 0 ) bindingType = BIND_NONE;
 
   switch (expr.type) {
   case "Identifier":
@@ -1739,19 +1770,7 @@
         { this.raiseRecoverable(expr.start, "Argument name clash"); }
       checkClashes[expr.name] = true;
     }
-    if (bindingType && bindingType !== "none") {
-      if (
-        bindingType === "var" && !this.canDeclareVarName(expr.name) ||
-        bindingType !== "var" && !this.canDeclareLexicalName(expr.name)
-      ) {
-        this.raiseRecoverable(expr.start, ("Identifier '" + (expr.name) + "' has already been declared"));
-      }
-      if (bindingType === "var") {
-        this.declareVarName(expr.name);
-      } else {
-        this.declareLexicalName(expr.name);
-      }
-    }
+    if (bindingType !== BIND_NONE && bindingType !== BIND_OUTSIDE) { this.declareName(expr.name, bindingType, expr.start); }
     break
 
   case "MemberExpression":
@@ -1768,7 +1787,7 @@
     break
 
   case "Property":
-    // AssignmentProperty has type == "Property"
+    // AssignmentProperty has type === "Property"
     this.checkLVal(expr.value, bindingType, checkClashes);
     break
 
@@ -1900,7 +1919,12 @@
 // operators like `+=`.
 
 pp$3.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) {
-  if (this.inGenerator && this.isContextual("yield")) { return this.parseYield() }
+  if (this.isContextual("yield")) {
+    if (this.inGenerator) { return this.parseYield() }
+    // The tokenizer will assume an expression is allowed after
+    // `yield`, but this isn't that kind of yield
+    else { this.exprAllowed = false; }
+  }
 
   var ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1;
   if (refDestructuringErrors) {
@@ -1913,7 +1937,7 @@
   }
 
   var startPos = this.start, startLoc = this.startLoc;
-  if (this.type == types.parenL || this.type == types.name)
+  if (this.type === types.parenL || this.type === types.name)
     { this.potentialArrowAt = this.start; }
   var left = this.parseMaybeConditional(noIn, refDestructuringErrors);
   if (afterLeftParse) { left = afterLeftParse.call(this, left, startPos, startLoc); }
@@ -1958,7 +1982,7 @@
   var startPos = this.start, startLoc = this.startLoc;
   var expr = this.parseMaybeUnary(refDestructuringErrors, false);
   if (this.checkExpressionErrors(refDestructuringErrors)) { return expr }
-  return expr.start == startPos && expr.type === "ArrowFunctionExpression" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn)
+  return expr.start === startPos && expr.type === "ArrowFunctionExpression" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn)
 };
 
 // Parse binary operators with the operator precedence parsing
@@ -1997,7 +2021,7 @@
   var this$1 = this;
 
   var startPos = this.start, startLoc = this.startLoc, expr;
-  if (this.inAsync && this.isContextual("await")) {
+  if (this.isContextual("await") && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction))) {
     expr = this.parseAwait();
     sawUnary = true;
   } else if (this.type.prefix) {
@@ -2052,7 +2076,7 @@
   var this$1 = this;
 
   var maybeAsyncArrow = this.options.ecmaVersion >= 8 && base.type === "Identifier" && base.name === "async" &&
-      this.lastTokEnd == base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === "async";
+      this.lastTokEnd === base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === "async";
   for (var computed = (void 0);;) {
     if ((computed = this$1.eat(types.bracketL)) || this$1.eat(types.dot)) {
       var node = this$1.startNodeAt(startPos, startLoc);
@@ -2097,7 +2121,7 @@
 // or `{}`.
 
 pp$3.parseExprAtom = function(refDestructuringErrors) {
-  var node, canBeArrow = this.potentialArrowAt == this.start;
+  var node, canBeArrow = this.potentialArrowAt === this.start;
   switch (this.type) {
   case types._super:
     if (!this.inFunction)
@@ -2123,7 +2147,7 @@
     var startPos = this.start, startLoc = this.startLoc, containsEsc = this.containsEsc;
     var id = this.parseIdent(this.type !== types.name);
     if (this.options.ecmaVersion >= 8 && !containsEsc && id.name === "async" && !this.canInsertSemicolon() && this.eat(types._function))
-      { return this.parseFunction(this.startNodeAt(startPos, startLoc), false, false, true) }
+      { return this.parseFunction(this.startNodeAt(startPos, startLoc), 0, false, true) }
     if (canBeArrow && !this.canInsertSemicolon()) {
       if (this.eat(types.arrow))
         { return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false) }
@@ -2174,7 +2198,7 @@
   case types._function:
     node = this.startNode();
     this.next();
-    return this.parseFunction(node, false)
+    return this.parseFunction(node, 0)
 
   case types._class:
     return this.parseClass(this.startNode(), false)
@@ -2293,7 +2317,7 @@
     node.property = this.parseIdent(true);
     if (node.property.name !== "target" || containsEsc)
       { this.raiseRecoverable(node.property.start, "The only valid meta property for new is new.target"); }
-    if (!this.inFunction)
+    if (!this.inNonArrowFunction())
       { this.raiseRecoverable(node.start, "new.target can only be used in functions"); }
     return this.finishNode(node, "MetaProperty")
   }
@@ -2340,6 +2364,7 @@
   var curElt = this.parseTemplateElement({isTagged: isTagged});
   node.quasis = [curElt];
   while (!curElt.tail) {
+    if (this$1.type === types.eof) { this$1.raise(this$1.pos, "Unterminated template literal"); }
     this$1.expect(types.dollarBraceL);
     node.expressions.push(this$1.parseExpression());
     this$1.expect(types.braceR);
@@ -2442,7 +2467,7 @@
   } else if (!isPattern && !containsEsc &&
              this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" &&
              (prop.key.name === "get" || prop.key.name === "set") &&
-             (this.type != types.comma && this.type != types.braceR)) {
+             (this.type !== types.comma && this.type !== types.braceR)) {
     if (isGenerator || isAsync) { this.unexpected(); }
     prop.kind = prop.key.name;
     this.parsePropertyName(prop);
@@ -2492,19 +2517,14 @@
 
 pp$3.initFunction = function(node) {
   node.id = null;
-  if (this.options.ecmaVersion >= 6) {
-    node.generator = false;
-    node.expression = false;
-  }
-  if (this.options.ecmaVersion >= 8)
-    { node.async = false; }
+  if (this.options.ecmaVersion >= 6) { node.generator = node.expression = false; }
+  if (this.options.ecmaVersion >= 8) { node.async = false; }
 };
 
 // Parse object or class method.
 
 pp$3.parseMethod = function(isGenerator, isAsync) {
-  var node = this.startNode(), oldInGen = this.inGenerator, oldInAsync = this.inAsync,
-      oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction;
+  var node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos;
 
   this.initFunction(node);
   if (this.options.ecmaVersion >= 6)
@@ -2512,51 +2532,37 @@
   if (this.options.ecmaVersion >= 8)
     { node.async = !!isAsync; }
 
-  this.inGenerator = node.generator;
-  this.inAsync = node.async;
   this.yieldPos = 0;
   this.awaitPos = 0;
-  this.inFunction = true;
-  this.enterFunctionScope();
+  this.enterScope(functionFlags(isAsync, node.generator));
 
   this.expect(types.parenL);
   node.params = this.parseBindingList(types.parenR, false, this.options.ecmaVersion >= 8);
   this.checkYieldAwaitInDefaultParams();
   this.parseFunctionBody(node, false);
 
-  this.inGenerator = oldInGen;
-  this.inAsync = oldInAsync;
   this.yieldPos = oldYieldPos;
   this.awaitPos = oldAwaitPos;
-  this.inFunction = oldInFunc;
   return this.finishNode(node, "FunctionExpression")
 };
 
 // Parse arrow function expression with given parameters.
 
 pp$3.parseArrowExpression = function(node, params, isAsync) {
-  var oldInGen = this.inGenerator, oldInAsync = this.inAsync,
-      oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction;
+  var oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos;
 
-  this.enterFunctionScope();
+  this.enterScope(functionFlags(isAsync, false) | SCOPE_ARROW);
   this.initFunction(node);
-  if (this.options.ecmaVersion >= 8)
-    { node.async = !!isAsync; }
+  if (this.options.ecmaVersion >= 8) { node.async = !!isAsync; }
 
-  this.inGenerator = false;
-  this.inAsync = node.async;
   this.yieldPos = 0;
   this.awaitPos = 0;
-  this.inFunction = true;
 
   node.params = this.toAssignableList(params, true);
   this.parseFunctionBody(node, true);
 
-  this.inGenerator = oldInGen;
-  this.inAsync = oldInAsync;
   this.yieldPos = oldYieldPos;
   this.awaitPos = oldAwaitPos;
-  this.inFunction = oldInFunc;
   return this.finishNode(node, "ArrowFunctionExpression")
 };
 
@@ -2594,12 +2600,10 @@
     this.adaptDirectivePrologue(node.body.body);
     this.labels = oldLabels;
   }
-  this.exitFunctionScope();
+  this.exitScope();
 
-  if (this.strict && node.id) {
-    // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval'
-    this.checkLVal(node.id, "none");
-  }
+  // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval'
+  if (this.strict && node.id) { this.checkLVal(node.id, BIND_OUTSIDE); }
   this.strict = oldStrict;
 };
 
@@ -2624,7 +2628,7 @@
     {
     var param = list[i];
 
-    this$1.checkLVal(param, "var", allowDuplicates ? null : nameHash);
+    this$1.checkLVal(param, BIND_VAR, allowDuplicates ? null : nameHash);
   }
 };
 
@@ -2668,10 +2672,10 @@
     { this.raiseRecoverable(start, "Can not use 'yield' as identifier inside a generator"); }
   if (this.inAsync && name === "await")
     { this.raiseRecoverable(start, "Can not use 'await' as identifier inside an async function"); }
-  if (this.isKeyword(name))
+  if (this.keywords.test(name))
     { this.raise(start, ("Unexpected keyword '" + name + "'")); }
   if (this.options.ecmaVersion < 6 &&
-    this.input.slice(start, end).indexOf("\\") != -1) { return }
+    this.input.slice(start, end).indexOf("\\") !== -1) { return }
   var re = this.strict ? this.reservedWordsStrict : this.reservedWords;
   if (re.test(name)) {
     if (!this.inAsync && name === "await")
@@ -2686,7 +2690,7 @@
 
 pp$3.parseIdent = function(liberal, isBinding) {
   var node = this.startNode();
-  if (liberal && this.options.allowReserved == "never") { liberal = false; }
+  if (liberal && this.options.allowReserved === "never") { liberal = false; }
   if (this.type === types.name) {
     node.name = this.value;
   } else if (this.type.keyword) {
@@ -2716,7 +2720,7 @@
 
   var node = this.startNode();
   this.next();
-  if (this.type == types.semi || this.canInsertSemicolon() || (this.type != types.star && !this.type.startsExpr)) {
+  if (this.type === types.semi || this.canInsertSemicolon() || (this.type !== types.star && !this.type.startsExpr)) {
     node.delegate = false;
     node.argument = null;
   } else {
@@ -2761,79 +2765,69 @@
 
 var pp$5 = Parser.prototype;
 
-// Object.assign polyfill
-var assign = Object.assign || function(target) {
-  var sources = [], len = arguments.length - 1;
-  while ( len-- > 0 ) sources[ len ] = arguments[ len + 1 ];
-
-  for (var i = 0, list = sources; i < list.length; i += 1) {
-    var source = list[i];
-
-    for (var key in source) {
-      if (has(source, key)) {
-        target[key] = source[key];
-      }
-    }
-  }
-  return target
+var Scope = function Scope(flags) {
+  this.flags = flags;
+  // A list of var-declared names in the current lexical scope
+  this.var = [];
+  // A list of lexically-declared names in the current lexical scope
+  this.lexical = [];
 };
 
 // The functions in this module keep track of declared variables in the current scope in order to detect duplicate variable names.
 
-pp$5.enterFunctionScope = function() {
-  // var: a hash of var-declared names in the current lexical scope
-  // lexical: a hash of lexically-declared names in the current lexical scope
-  // childVar: a hash of var-declared names in all child lexical scopes of the current lexical scope (within the current function scope)
-  // parentLexical: a hash of lexically-declared names in all parent lexical scopes of the current lexical scope (within the current function scope)
-  this.scopeStack.push({var: {}, lexical: {}, childVar: {}, parentLexical: {}});
+pp$5.enterScope = function(flags) {
+  this.scopeStack.push(new Scope(flags));
 };
 
-pp$5.exitFunctionScope = function() {
+pp$5.exitScope = function() {
   this.scopeStack.pop();
 };
 
-pp$5.enterLexicalScope = function() {
-  var parentScope = this.scopeStack[this.scopeStack.length - 1];
-  var childScope = {var: {}, lexical: {}, childVar: {}, parentLexical: {}};
+pp$5.declareName = function(name, bindingType, pos) {
+  var this$1 = this;
 
-  this.scopeStack.push(childScope);
-  assign(childScope.parentLexical, parentScope.lexical, parentScope.parentLexical);
+  var redeclared = false;
+  if (bindingType === BIND_LEXICAL) {
+    var scope = this.currentScope();
+    redeclared = scope.lexical.indexOf(name) > -1 || scope.var.indexOf(name) > -1;
+    scope.lexical.push(name);
+  } else if (bindingType === BIND_SIMPLE_CATCH) {
+    var scope$1 = this.currentScope();
+    scope$1.lexical.push(name);
+  } else if (bindingType === BIND_FUNCTION) {
+    var scope$2 = this.currentScope();
+    redeclared = scope$2.lexical.indexOf(name) > -1;
+    scope$2.var.push(name);
+  } else {
+    for (var i = this.scopeStack.length - 1; i >= 0; --i) {
+      var scope$3 = this$1.scopeStack[i];
+      if (scope$3.lexical.indexOf(name) > -1 && !(scope$3.flags & SCOPE_SIMPLE_CATCH) && scope$3.lexical[0] === name) { redeclared = true; }
+      scope$3.var.push(name);
+      if (scope$3.flags & SCOPE_VAR) { break }
+    }
+  }
+  if (redeclared) { this.raiseRecoverable(pos, ("Identifier '" + name + "' has already been declared")); }
 };
 
-pp$5.exitLexicalScope = function() {
-  var childScope = this.scopeStack.pop();
-  var parentScope = this.scopeStack[this.scopeStack.length - 1];
-
-  assign(parentScope.childVar, childScope.var, childScope.childVar);
+pp$5.currentScope = function() {
+  return this.scopeStack[this.scopeStack.length - 1]
 };
 
-/**
- * A name can be declared with `var` if there are no variables with the same name declared with `let`/`const`
- * in the current lexical scope or any of the parent lexical scopes in this function.
- */
-pp$5.canDeclareVarName = function(name) {
-  var currentScope = this.scopeStack[this.scopeStack.length - 1];
+pp$5.currentVarScope = function() {
+  var this$1 = this;
 
-  return !has(currentScope.lexical, name) && !has(currentScope.parentLexical, name)
+  for (var i = this.scopeStack.length - 1;; i--) {
+    var scope = this$1.scopeStack[i];
+    if (scope.flags & SCOPE_VAR) { return scope }
+  }
 };
 
-/**
- * A name can be declared with `let`/`const` if there are no variables with the same name declared with `let`/`const`
- * in the current scope, and there are no variables with the same name declared with `var` in the current scope or in
- * any child lexical scopes in this function.
- */
-pp$5.canDeclareLexicalName = function(name) {
-  var currentScope = this.scopeStack[this.scopeStack.length - 1];
+pp$5.inNonArrowFunction = function() {
+  var this$1 = this;
 
-  return !has(currentScope.lexical, name) && !has(currentScope.var, name) && !has(currentScope.childVar, name)
-};
-
-pp$5.declareVarName = function(name) {
-  this.scopeStack[this.scopeStack.length - 1].var[name] = true;
-};
-
-pp$5.declareLexicalName = function(name) {
-  this.scopeStack[this.scopeStack.length - 1].lexical[name] = true;
+  for (var i = this.scopeStack.length - 1; i >= 0; i--)
+    { if (this$1.scopeStack[i].flags & SCOPE_FUNCTION && !(this$1.scopeStack[i].flags & SCOPE_ARROW)) { return true } }
+  return false
 };
 
 var Node = function Node(parser, pos, loc) {
@@ -2923,13 +2917,13 @@
   // The check for `tt.name && exprAllowed` detects whether we are
   // after a `yield` or `of` construct. See the `updateContext` for
   // `tt.name`.
-  if (prevType === types._return || prevType == types.name && this.exprAllowed)
+  if (prevType === types._return || prevType === types.name && this.exprAllowed)
     { return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) }
-  if (prevType === types._else || prevType === types.semi || prevType === types.eof || prevType === types.parenR || prevType == types.arrow)
+  if (prevType === types._else || prevType === types.semi || prevType === types.eof || prevType === types.parenR || prevType === types.arrow)
     { return true }
-  if (prevType == types.braceL)
+  if (prevType === types.braceL)
     { return parent === types$1.b_stat }
-  if (prevType == types._var || prevType == types.name)
+  if (prevType === types._var || prevType === types.name)
     { return false }
   return !this.exprAllowed
 };
@@ -2947,7 +2941,7 @@
 
 pp$7.updateContext = function(prevType) {
   var update, type = this.type;
-  if (type.keyword && prevType == types.dot)
+  if (type.keyword && prevType === types.dot)
     { this.exprAllowed = false; }
   else if (update = type.updateContext)
     { update.call(this, prevType); }
@@ -2958,7 +2952,7 @@
 // Token-specific context update code
 
 types.parenR.updateContext = types.braceR.updateContext = function() {
-  if (this.context.length == 1) {
+  if (this.context.length === 1) {
     this.exprAllowed = true;
     return
   }
@@ -3007,7 +3001,7 @@
 };
 
 types.star.updateContext = function(prevType) {
-  if (prevType == types._function) {
+  if (prevType === types._function) {
     var index = this.context.length - 1;
     if (this.context[index] === types$1.f_expr)
       { this.context[index] = types$1.f_expr_gen; }
@@ -3019,9 +3013,9 @@
 
 types.name.updateContext = function(prevType) {
   var allowed = false;
-  if (this.options.ecmaVersion >= 6) {
-    if (this.value == "of" && !this.exprAllowed ||
-        this.value == "yield" && this.inGeneratorContext())
+  if (this.options.ecmaVersion >= 6 && prevType !== types.dot) {
+    if (this.value === "of" && !this.exprAllowed ||
+        this.value === "yield" && this.inGeneratorContext())
       { allowed = true; }
   }
   this.exprAllowed = allowed;
@@ -3590,7 +3584,7 @@
 
   for (var i = 0; i < flags.length; i++) {
     var flag = flags.charAt(i);
-    if (validFlags.indexOf(flag) == -1) {
+    if (validFlags.indexOf(flag) === -1) {
       this$1.raise(state.start, "Invalid regular expression flag");
     }
     if (flags.indexOf(flag, i + 1) > -1) {
@@ -4756,7 +4750,7 @@
   var tokentype = code === 42 ? types.star : types.modulo;
 
   // exponentiation operator ** and **=
-  if (this.options.ecmaVersion >= 7 && code == 42 && next === 42) {
+  if (this.options.ecmaVersion >= 7 && code === 42 && next === 42) {
     ++size;
     tokentype = types.starstar;
     next = this.input.charCodeAt(this.pos + 2);
@@ -4782,7 +4776,7 @@
 pp$8.readToken_plus_min = function(code) { // '+-'
   var next = this.input.charCodeAt(this.pos + 1);
   if (next === code) {
-    if (next == 45 && !this.inModule && this.input.charCodeAt(this.pos + 2) == 62 &&
+    if (next === 45 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 62 &&
         (this.lastTokEnd === 0 || lineBreak.test(this.input.slice(this.lastTokEnd, this.pos)))) {
       // A `-->` line comment
       this.skipLineComment(3);
@@ -4803,8 +4797,8 @@
     if (this.input.charCodeAt(this.pos + size) === 61) { return this.finishOp(types.assign, size + 1) }
     return this.finishOp(types.bitShift, size)
   }
-  if (next == 33 && code == 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) == 45 &&
-      this.input.charCodeAt(this.pos + 3) == 45) {
+  if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 &&
+      this.input.charCodeAt(this.pos + 3) === 45) {
     // `<!--`, an XML-style comment that should be interpreted as a line comment
     this.skipLineComment(4);
     this.skipSpace();
@@ -5038,7 +5032,7 @@
       out += this$1.readEscapedChar(false);
       chunkStart = this$1.pos;
     } else {
-      if (isNewLine(ch)) { this$1.raise(this$1.start, "Unterminated string constant"); }
+      if (isNewLine(ch, this$1.options.ecmaVersion >= 10)) { this$1.raise(this$1.start, "Unterminated string constant"); }
       ++this$1.pos;
     }
   }
@@ -5174,7 +5168,7 @@
       }
       this.pos += octalStr.length - 1;
       ch = this.input.charCodeAt(this.pos);
-      if ((octalStr !== "0" || ch == 56 || ch == 57) && (this.strict || inTemplate)) {
+      if ((octalStr !== "0" || ch === 56 || ch === 57) && (this.strict || inTemplate)) {
         this.invalidStringToken(
           this.pos - 1 - octalStr.length,
           inTemplate
@@ -5217,7 +5211,7 @@
       this$1.containsEsc = true;
       word += this$1.input.slice(chunkStart, this$1.pos);
       var escStart = this$1.pos;
-      if (this$1.input.charCodeAt(++this$1.pos) != 117) // "u"
+      if (this$1.input.charCodeAt(++this$1.pos) !== 117) // "u"
         { this$1.invalidStringToken(this$1.pos, "Expecting Unicode escape sequence \\uXXXX"); }
       ++this$1.pos;
       var esc = this$1.readCodePoint();
@@ -5260,14 +5254,9 @@
 //
 // [ghbt]: https://github.com/acornjs/acorn/issues
 //
-// This file defines the main parser interface. The library also comes
-// with a [error-tolerant parser][dammit] and an
-// [abstract syntax tree walker][walk], defined in other files.
-//
-// [dammit]: acorn_loose.js
 // [walk]: util/walk.js
 
-var version = "5.5.3";
+var version = "6.0.1";
 
 // The main exported interface (under `self.acorn` when in the
 // browser) is a `parse` function that takes a code string and
@@ -5277,7 +5266,7 @@
 // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
 
 function parse(input, options) {
-  return new Parser(options, input).parse()
+  return Parser.parse(input, options)
 }
 
 // This function tries to parse a single expression at a given
@@ -5285,35 +5274,21 @@
 // that embed JavaScript expressions.
 
 function parseExpressionAt(input, pos, options) {
-  var p = new Parser(options, input, pos);
-  p.nextToken();
-  return p.parseExpression()
+  return Parser.parseExpressionAt(input, pos, options)
 }
 
 // Acorn is organized as a tokenizer and a recursive-descent parser.
 // The `tokenizer` export provides an interface to the tokenizer.
 
 function tokenizer(input, options) {
-  return new Parser(options, input)
-}
-
-// This is a terrible kludge to support the existing, pre-ES6
-// interface where the loose parser module retroactively adds exports
-// to this module.
- // eslint-disable-line camelcase
-function addLooseExports(parse, Parser$$1, plugins$$1) {
-  exports.parse_dammit = parse; // eslint-disable-line camelcase
-  exports.LooseParser = Parser$$1;
-  exports.pluginsLoose = plugins$$1;
+  return Parser.tokenizer(input, options)
 }
 
 exports.version = version;
 exports.parse = parse;
 exports.parseExpressionAt = parseExpressionAt;
 exports.tokenizer = tokenizer;
-exports.addLooseExports = addLooseExports;
 exports.Parser = Parser;
-exports.plugins = plugins;
 exports.defaultOptions = defaultOptions;
 exports.Position = Position;
 exports.SourceLocation = SourceLocation;
@@ -5335,3 +5310,4 @@
 Object.defineProperty(exports, '__esModule', { value: true });
 
 })));
+// clang-format on
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn_loose.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn_loose.js
index 6f372da..5038bc17 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn_loose.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn_loose.js
@@ -1,37 +1,36 @@
 // clang-format off
 (function (global, factory) {
-  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./acorn')) :
-  typeof define === 'function' && define.amd ? define(['exports', './acorn'], factory) :
-  (factory((global.acorn = global.acorn || {}, global.acorn.loose = global.acorn.loose || {}),global.acorn));
-}(this, (function (exports,__acorn) { 'use strict';
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('acorn')) :
+  typeof define === 'function' && define.amd ? define(['exports', 'acorn'], factory) :
+  (factory((global.acorn = global.acorn || {}, global.acorn.loose = {}),global.acorn));
+}(this, (function (exports,acorn) { 'use strict';
 
-// Registered plugins
-var pluginsLoose = {}
+function noop() {}
 
 var LooseParser = function LooseParser(input, options) {
   if ( options === void 0 ) options = {};
 
-  this.toks = __acorn.tokenizer(input, options)
-  this.options = this.toks.options
-  this.input = this.toks.input
-  this.tok = this.last = {type: __acorn.tokTypes.eof, start: 0, end: 0}
+  this.toks = this.constructor.BaseParser.tokenizer(input, options);
+  this.options = this.toks.options;
+  this.input = this.toks.input;
+  this.tok = this.last = {type: acorn.tokTypes.eof, start: 0, end: 0};
+  this.tok.validateRegExpFlags = noop;
+  this.tok.validateRegExpPattern = noop;
   if (this.options.locations) {
-    var here = this.toks.curPosition()
-    this.tok.loc = new __acorn.SourceLocation(this.toks, here, here)
+    var here = this.toks.curPosition();
+    this.tok.loc = new acorn.SourceLocation(this.toks, here, here);
   }
-  this.ahead = [] // Tokens ahead
-  this.context = [] // Indentation contexted
-  this.curIndent = 0
-  this.curLineStart = 0
-  this.nextLineStart = this.lineEnd(this.curLineStart) + 1
-  this.inAsync = false
-  // Load plugins
-  this.options.pluginsLoose = options.pluginsLoose || {}
-  this.loadPlugins(this.options.pluginsLoose)
+  this.ahead = []; // Tokens ahead
+  this.context = []; // Indentation contexted
+  this.curIndent = 0;
+  this.curLineStart = 0;
+  this.nextLineStart = this.lineEnd(this.curLineStart) + 1;
+  this.inAsync = false;
+  this.inFunction = false;
 };
 
 LooseParser.prototype.startNode = function startNode () {
-  return new __acorn.Node(this.toks, this.tok.start, this.options.locations ? this.tok.loc.start : null)
+  return new acorn.Node(this.toks, this.tok.start, this.options.locations ? this.tok.loc.start : null)
 };
 
 LooseParser.prototype.storeCurrentPos = function storeCurrentPos () {
@@ -40,49 +39,49 @@
 
 LooseParser.prototype.startNodeAt = function startNodeAt (pos) {
   if (this.options.locations) {
-    return new __acorn.Node(this.toks, pos[0], pos[1])
+    return new acorn.Node(this.toks, pos[0], pos[1])
   } else {
-    return new __acorn.Node(this.toks, pos)
+    return new acorn.Node(this.toks, pos)
   }
 };
 
 LooseParser.prototype.finishNode = function finishNode (node, type) {
-  node.type = type
-  node.end = this.last.end
+  node.type = type;
+  node.end = this.last.end;
   if (this.options.locations)
-    node.loc.end = this.last.loc.end
+    { node.loc.end = this.last.loc.end; }
   if (this.options.ranges)
-    node.range[1] = this.last.end
+    { node.range[1] = this.last.end; }
   return node
 };
 
 LooseParser.prototype.dummyNode = function dummyNode (type) {
-  var dummy = this.startNode()
-  dummy.type = type
-  dummy.end = dummy.start
+  var dummy = this.startNode();
+  dummy.type = type;
+  dummy.end = dummy.start;
   if (this.options.locations)
-    dummy.loc.end = dummy.loc.start
+    { dummy.loc.end = dummy.loc.start; }
   if (this.options.ranges)
-    dummy.range[1] = dummy.start
-  this.last = {type: __acorn.tokTypes.name, start: dummy.start, end: dummy.start, loc: dummy.loc}
+    { dummy.range[1] = dummy.start; }
+  this.last = {type: acorn.tokTypes.name, start: dummy.start, end: dummy.start, loc: dummy.loc};
   return dummy
 };
 
 LooseParser.prototype.dummyIdent = function dummyIdent () {
-  var dummy = this.dummyNode("Identifier")
-  dummy.name = "✖"
+  var dummy = this.dummyNode("Identifier");
+  dummy.name = "✖";
   return dummy
 };
 
 LooseParser.prototype.dummyString = function dummyString () {
-  var dummy = this.dummyNode("Literal")
-  dummy.value = dummy.raw = "✖"
+  var dummy = this.dummyNode("Literal");
+  dummy.value = dummy.raw = "✖";
   return dummy
 };
 
 LooseParser.prototype.eat = function eat (type) {
   if (this.tok.type === type) {
-    this.next()
+    this.next();
     return true
   } else {
     return false
@@ -90,44 +89,44 @@
 };
 
 LooseParser.prototype.isContextual = function isContextual (name) {
-  return this.tok.type === __acorn.tokTypes.name && this.tok.value === name
+  return this.tok.type === acorn.tokTypes.name && this.tok.value === name
 };
 
 LooseParser.prototype.eatContextual = function eatContextual (name) {
-  return this.tok.value === name && this.eat(__acorn.tokTypes.name)
+  return this.tok.value === name && this.eat(acorn.tokTypes.name)
 };
 
 LooseParser.prototype.canInsertSemicolon = function canInsertSemicolon () {
-  return this.tok.type === __acorn.tokTypes.eof || this.tok.type === __acorn.tokTypes.braceR ||
-    __acorn.lineBreak.test(this.input.slice(this.last.end, this.tok.start))
+  return this.tok.type === acorn.tokTypes.eof || this.tok.type === acorn.tokTypes.braceR ||
+    acorn.lineBreak.test(this.input.slice(this.last.end, this.tok.start))
 };
 
 LooseParser.prototype.semicolon = function semicolon () {
-  return this.eat(__acorn.tokTypes.semi)
+  return this.eat(acorn.tokTypes.semi)
 };
 
 LooseParser.prototype.expect = function expect (type) {
     var this$1 = this;
 
-  if (this.eat(type)) return true
+  if (this.eat(type)) { return true }
   for (var i = 1; i <= 2; i++) {
-    if (this$1.lookAhead(i).type == type) {
-      for (var j = 0; j < i; j++) this$1.next()
+    if (this$1.lookAhead(i).type === type) {
+      for (var j = 0; j < i; j++) { this$1.next(); }
       return true
     }
   }
 };
 
 LooseParser.prototype.pushCx = function pushCx () {
-  this.context.push(this.curIndent)
+  this.context.push(this.curIndent);
 };
 
 LooseParser.prototype.popCx = function popCx () {
-  this.curIndent = this.context.pop()
+  this.curIndent = this.context.pop();
 };
 
 LooseParser.prototype.lineEnd = function lineEnd (pos) {
-  while (pos < this.input.length && !__acorn.isNewLine(this.input.charCodeAt(pos))) ++pos
+  while (pos < this.input.length && !acorn.isNewLine(this.input.charCodeAt(pos))) { ++pos; }
   return pos
 };
 
@@ -135,16 +134,16 @@
     var this$1 = this;
 
   for (var count = 0;; ++pos) {
-    var ch = this$1.input.charCodeAt(pos)
-    if (ch === 32) ++count
-    else if (ch === 9) count += this$1.options.tabSize
-    else return count
+    var ch = this$1.input.charCodeAt(pos);
+    if (ch === 32) { ++count; }
+    else if (ch === 9) { count += this$1.options.tabSize; }
+    else { return count }
   }
 };
 
 LooseParser.prototype.closes = function closes (closeTok, indent, line, blockHeuristic) {
-  if (this.tok.type === closeTok || this.tok.type === __acorn.tokTypes.eof) return true
-  return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() &&
+  if (this.tok.type === closeTok || this.tok.type === acorn.tokTypes.eof) { return true }
+  return line !== this.curLineStart && this.curIndent < indent && this.tokenStartsLine() &&
     (!blockHeuristic || this.nextLineStart >= this.input.length ||
      this.indentationAfter(this.nextLineStart) < indent)
 };
@@ -153,1068 +152,1110 @@
     var this$1 = this;
 
   for (var p = this.tok.start - 1; p >= this.curLineStart; --p) {
-    var ch = this$1.input.charCodeAt(p)
-    if (ch !== 9 && ch !== 32) return false
+    var ch = this$1.input.charCodeAt(p);
+    if (ch !== 9 && ch !== 32) { return false }
   }
   return true
 };
 
 LooseParser.prototype.extend = function extend (name, f) {
-  this[name] = f(this[name])
+  this[name] = f(this[name]);
 };
 
-LooseParser.prototype.loadPlugins = function loadPlugins (pluginConfigs) {
-    var this$1 = this;
-
-  for (var name in pluginConfigs) {
-    var plugin = pluginsLoose[name]
-    if (!plugin) throw new Error("Plugin '" + name + "' not found")
-    plugin(this$1, pluginConfigs[name])
-  }
+LooseParser.prototype.parse = function parse () {
+  this.next();
+  return this.parseTopLevel()
 };
 
-var lp = LooseParser.prototype
+LooseParser.extend = function extend () {
+    var plugins = [], len = arguments.length;
+    while ( len-- ) plugins[ len ] = arguments[ len ];
+
+  var cls = this;
+  for (var i = 0; i < plugins.length; i++) { cls = plugins[i](cls); }
+  return cls
+};
+
+LooseParser.parse = function parse (input, options) {
+  return new this(input, options).parse()
+};
+
+// Allows plugins to extend the base parser / tokenizer used
+LooseParser.BaseParser = acorn.Parser;
+
+var lp = LooseParser.prototype;
 
 function isSpace(ch) {
-  return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || __acorn.isNewLine(ch)
+  return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || acorn.isNewLine(ch)
 }
 
 lp.next = function() {
   var this$1 = this;
 
-  this.last = this.tok
+  this.last = this.tok;
   if (this.ahead.length)
-    this.tok = this.ahead.shift()
+    { this.tok = this.ahead.shift(); }
   else
-    this.tok = this.readToken()
+    { this.tok = this.readToken(); }
 
   if (this.tok.start >= this.nextLineStart) {
     while (this.tok.start >= this.nextLineStart) {
-      this$1.curLineStart = this$1.nextLineStart
-      this$1.nextLineStart = this$1.lineEnd(this$1.curLineStart) + 1
+      this$1.curLineStart = this$1.nextLineStart;
+      this$1.nextLineStart = this$1.lineEnd(this$1.curLineStart) + 1;
     }
-    this.curIndent = this.indentationAfter(this.curLineStart)
+    this.curIndent = this.indentationAfter(this.curLineStart);
   }
-}
+};
 
 lp.readToken = function() {
   var this$1 = this;
 
   for (;;) {
     try {
-      this$1.toks.next()
-      if (this$1.toks.type === __acorn.tokTypes.dot &&
+      this$1.toks.next();
+      if (this$1.toks.type === acorn.tokTypes.dot &&
           this$1.input.substr(this$1.toks.end, 1) === "." &&
           this$1.options.ecmaVersion >= 6) {
-        this$1.toks.end++
-        this$1.toks.type = __acorn.tokTypes.ellipsis
+        this$1.toks.end++;
+        this$1.toks.type = acorn.tokTypes.ellipsis;
       }
-      return new __acorn.Token(this$1.toks)
+      return new acorn.Token(this$1.toks)
     } catch (e) {
-      if (!(e instanceof SyntaxError)) throw e
+      if (!(e instanceof SyntaxError)) { throw e }
 
       // Try to skip some text, based on the error message, and then continue
-      var msg = e.message, pos = e.raisedAt, replace = true
+      var msg = e.message, pos = e.raisedAt, replace = true;
       if (/unterminated/i.test(msg)) {
-        pos = this$1.lineEnd(e.pos + 1)
+        pos = this$1.lineEnd(e.pos + 1);
         if (/string/.test(msg)) {
-          replace = {start: e.pos, end: pos, type: __acorn.tokTypes.string, value: this$1.input.slice(e.pos + 1, pos)}
+          replace = {start: e.pos, end: pos, type: acorn.tokTypes.string, value: this$1.input.slice(e.pos + 1, pos)};
         } else if (/regular expr/i.test(msg)) {
-          var re = this$1.input.slice(e.pos, pos)
-          try { re = new RegExp(re) } catch (e) { /* ignore compilation error due to new syntax */ }
-          replace = {start: e.pos, end: pos, type: __acorn.tokTypes.regexp, value: re}
+          var re = this$1.input.slice(e.pos, pos);
+          try { re = new RegExp(re); } catch (e) { /* ignore compilation error due to new syntax */ }
+          replace = {start: e.pos, end: pos, type: acorn.tokTypes.regexp, value: re};
         } else if (/template/.test(msg)) {
           replace = {
             start: e.pos,
             end: pos,
-            type: __acorn.tokTypes.template,
+            type: acorn.tokTypes.template,
             value: this$1.input.slice(e.pos, pos)
-          }
+          };
         } else {
-          replace = false
+          replace = false;
         }
       } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number|expected number in radix/i.test(msg)) {
-        while (pos < this.input.length && !isSpace(this.input.charCodeAt(pos))) ++pos
+        while (pos < this.input.length && !isSpace(this.input.charCodeAt(pos))) { ++pos; }
       } else if (/character escape|expected hexadecimal/i.test(msg)) {
         while (pos < this.input.length) {
-          var ch = this$1.input.charCodeAt(pos++)
-          if (ch === 34 || ch === 39 || __acorn.isNewLine(ch)) break
+          var ch = this$1.input.charCodeAt(pos++);
+          if (ch === 34 || ch === 39 || acorn.isNewLine(ch)) { break }
         }
       } else if (/unexpected character/i.test(msg)) {
-        pos++
-        replace = false
+        pos++;
+        replace = false;
       } else if (/regular expression/i.test(msg)) {
-        replace = true
+        replace = true;
       } else {
         throw e
       }
-      this$1.resetTo(pos)
-      if (replace === true) replace = {start: pos, end: pos, type: __acorn.tokTypes.name, value: "✖"}
+      this$1.resetTo(pos);
+      if (replace === true) { replace = {start: pos, end: pos, type: acorn.tokTypes.name, value: "✖"}; }
       if (replace) {
         if (this$1.options.locations)
-          replace.loc = new __acorn.SourceLocation(
+          { replace.loc = new acorn.SourceLocation(
             this$1.toks,
-            __acorn.getLineInfo(this$1.input, replace.start),
-            __acorn.getLineInfo(this$1.input, replace.end))
+            acorn.getLineInfo(this$1.input, replace.start),
+            acorn.getLineInfo(this$1.input, replace.end)); }
         return replace
       }
     }
   }
-}
+};
 
 lp.resetTo = function(pos) {
   var this$1 = this;
 
-  this.toks.pos = pos
-  var ch = this.input.charAt(pos - 1)
+  this.toks.pos = pos;
+  var ch = this.input.charAt(pos - 1);
   this.toks.exprAllowed = !ch || /[[{(,;:?/*=+\-~!|&%^<>]/.test(ch) ||
     /[enwfd]/.test(ch) &&
-    /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(this.input.slice(pos - 10, pos))
+    /\b(case|else|return|throw|new|in|(instance|type)?of|delete|void)$/.test(this.input.slice(pos - 10, pos));
 
   if (this.options.locations) {
-    this.toks.curLine = 1
-    this.toks.lineStart = __acorn.lineBreakG.lastIndex = 0
-    var match
-    while ((match = __acorn.lineBreakG.exec(this.input)) && match.index < pos) {
-      ++this$1.toks.curLine
-      this$1.toks.lineStart = match.index + match[0].length
+    this.toks.curLine = 1;
+    this.toks.lineStart = acorn.lineBreakG.lastIndex = 0;
+    var match;
+    while ((match = acorn.lineBreakG.exec(this.input)) && match.index < pos) {
+      ++this$1.toks.curLine;
+      this$1.toks.lineStart = match.index + match[0].length;
     }
   }
-}
+};
 
 lp.lookAhead = function(n) {
   var this$1 = this;
 
   while (n > this.ahead.length)
-    this$1.ahead.push(this$1.readToken())
+    { this$1.ahead.push(this$1.readToken()); }
   return this.ahead[n - 1]
-}
+};
 
-function isDummy(node) { return node.name == "✖" }
+function isDummy(node) { return node.name === "✖" }
 
-var lp$1 = LooseParser.prototype
+var lp$1 = LooseParser.prototype;
 
 lp$1.parseTopLevel = function() {
   var this$1 = this;
 
-  var node = this.startNodeAt(this.options.locations ? [0, __acorn.getLineInfo(this.input, 0)] : 0)
-  node.body = []
-  while (this.tok.type !== __acorn.tokTypes.eof) node.body.push(this$1.parseStatement())
-  this.last = this.tok
+  var node = this.startNodeAt(this.options.locations ? [0, acorn.getLineInfo(this.input, 0)] : 0);
+  node.body = [];
+  while (this.tok.type !== acorn.tokTypes.eof) { node.body.push(this$1.parseStatement()); }
+  this.toks.adaptDirectivePrologue(node.body);
+  this.last = this.tok;
   if (this.options.ecmaVersion >= 6) {
-    node.sourceType = this.options.sourceType
+    node.sourceType = this.options.sourceType;
   }
   return this.finishNode(node, "Program")
-}
+};
 
 lp$1.parseStatement = function() {
   var this$1 = this;
 
-  var starttype = this.tok.type, node = this.startNode(), kind
+  var starttype = this.tok.type, node = this.startNode(), kind;
 
   if (this.toks.isLet()) {
-    starttype = __acorn.tokTypes._var
-    kind = "let"
+    starttype = acorn.tokTypes._var;
+    kind = "let";
   }
 
   switch (starttype) {
-  case __acorn.tokTypes._break: case __acorn.tokTypes._continue:
-    this.next()
-    var isBreak = starttype === __acorn.tokTypes._break
+  case acorn.tokTypes._break: case acorn.tokTypes._continue:
+    this.next();
+    var isBreak = starttype === acorn.tokTypes._break;
     if (this.semicolon() || this.canInsertSemicolon()) {
-      node.label = null
+      node.label = null;
     } else {
-      node.label = this.tok.type === __acorn.tokTypes.name ? this.parseIdent() : null
-      this.semicolon()
+      node.label = this.tok.type === acorn.tokTypes.name ? this.parseIdent() : null;
+      this.semicolon();
     }
     return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement")
 
-  case __acorn.tokTypes._debugger:
-    this.next()
-    this.semicolon()
+  case acorn.tokTypes._debugger:
+    this.next();
+    this.semicolon();
     return this.finishNode(node, "DebuggerStatement")
 
-  case __acorn.tokTypes._do:
-    this.next()
-    node.body = this.parseStatement()
-    node.test = this.eat(__acorn.tokTypes._while) ? this.parseParenExpression() : this.dummyIdent()
-    this.semicolon()
+  case acorn.tokTypes._do:
+    this.next();
+    node.body = this.parseStatement();
+    node.test = this.eat(acorn.tokTypes._while) ? this.parseParenExpression() : this.dummyIdent();
+    this.semicolon();
     return this.finishNode(node, "DoWhileStatement")
 
-  case __acorn.tokTypes._for:
-    this.next()
-    this.pushCx()
-    this.expect(__acorn.tokTypes.parenL)
-    if (this.tok.type === __acorn.tokTypes.semi) return this.parseFor(node, null)
-    var isLet = this.toks.isLet()
-    if (isLet || this.tok.type === __acorn.tokTypes._var || this.tok.type === __acorn.tokTypes._const) {
-      var init$1 = this.parseVar(true, isLet ? "let" : this.tok.value)
-      if (init$1.declarations.length === 1 && (this.tok.type === __acorn.tokTypes._in || this.isContextual("of"))) {
+  case acorn.tokTypes._for:
+    this.next(); // `for` keyword
+    var isAwait = this.options.ecmaVersion >= 9 && this.inAsync && this.eatContextual("await");
+
+    this.pushCx();
+    this.expect(acorn.tokTypes.parenL);
+    if (this.tok.type === acorn.tokTypes.semi) { return this.parseFor(node, null) }
+    var isLet = this.toks.isLet();
+    if (isLet || this.tok.type === acorn.tokTypes._var || this.tok.type === acorn.tokTypes._const) {
+      var init$1 = this.parseVar(this.startNode(), true, isLet ? "let" : this.tok.value);
+      if (init$1.declarations.length === 1 && (this.tok.type === acorn.tokTypes._in || this.isContextual("of"))) {
+        if (this.options.ecmaVersion >= 9 && this.tok.type !== acorn.tokTypes._in) {
+          node.await = isAwait;
+        }
         return this.parseForIn(node, init$1)
       }
       return this.parseFor(node, init$1)
     }
-    var init = this.parseExpression(true)
-    if (this.tok.type === __acorn.tokTypes._in || this.isContextual("of"))
+    var init = this.parseExpression(true);
+    if (this.tok.type === acorn.tokTypes._in || this.isContextual("of")) {
+      if (this.options.ecmaVersion >= 9 && this.tok.type !== acorn.tokTypes._in) {
+        node.await = isAwait;
+      }
       return this.parseForIn(node, this.toAssignable(init))
+    }
     return this.parseFor(node, init)
 
-  case __acorn.tokTypes._function:
-    this.next()
+  case acorn.tokTypes._function:
+    this.next();
     return this.parseFunction(node, true)
 
-  case __acorn.tokTypes._if:
-    this.next()
-    node.test = this.parseParenExpression()
-    node.consequent = this.parseStatement()
-    node.alternate = this.eat(__acorn.tokTypes._else) ? this.parseStatement() : null
+  case acorn.tokTypes._if:
+    this.next();
+    node.test = this.parseParenExpression();
+    node.consequent = this.parseStatement();
+    node.alternate = this.eat(acorn.tokTypes._else) ? this.parseStatement() : null;
     return this.finishNode(node, "IfStatement")
 
-  case __acorn.tokTypes._return:
-    this.next()
-    if (this.eat(__acorn.tokTypes.semi) || this.canInsertSemicolon()) node.argument = null
-    else { node.argument = this.parseExpression(); this.semicolon() }
+  case acorn.tokTypes._return:
+    this.next();
+    if (this.eat(acorn.tokTypes.semi) || this.canInsertSemicolon()) { node.argument = null; }
+    else { node.argument = this.parseExpression(); this.semicolon(); }
     return this.finishNode(node, "ReturnStatement")
 
-  case __acorn.tokTypes._switch:
-    var blockIndent = this.curIndent, line = this.curLineStart
-    this.next()
-    node.discriminant = this.parseParenExpression()
-    node.cases = []
-    this.pushCx()
-    this.expect(__acorn.tokTypes.braceL)
+  case acorn.tokTypes._switch:
+    var blockIndent = this.curIndent, line = this.curLineStart;
+    this.next();
+    node.discriminant = this.parseParenExpression();
+    node.cases = [];
+    this.pushCx();
+    this.expect(acorn.tokTypes.braceL);
 
-    var cur
-    while (!this.closes(__acorn.tokTypes.braceR, blockIndent, line, true)) {
-      if (this$1.tok.type === __acorn.tokTypes._case || this$1.tok.type === __acorn.tokTypes._default) {
-        var isCase = this$1.tok.type === __acorn.tokTypes._case
-        if (cur) this$1.finishNode(cur, "SwitchCase")
-        node.cases.push(cur = this$1.startNode())
-        cur.consequent = []
-        this$1.next()
-        if (isCase) cur.test = this$1.parseExpression()
-        else cur.test = null
-        this$1.expect(__acorn.tokTypes.colon)
+    var cur;
+    while (!this.closes(acorn.tokTypes.braceR, blockIndent, line, true)) {
+      if (this$1.tok.type === acorn.tokTypes._case || this$1.tok.type === acorn.tokTypes._default) {
+        var isCase = this$1.tok.type === acorn.tokTypes._case;
+        if (cur) { this$1.finishNode(cur, "SwitchCase"); }
+        node.cases.push(cur = this$1.startNode());
+        cur.consequent = [];
+        this$1.next();
+        if (isCase) { cur.test = this$1.parseExpression(); }
+        else { cur.test = null; }
+        this$1.expect(acorn.tokTypes.colon);
       } else {
         if (!cur) {
-          node.cases.push(cur = this$1.startNode())
-          cur.consequent = []
-          cur.test = null
+          node.cases.push(cur = this$1.startNode());
+          cur.consequent = [];
+          cur.test = null;
         }
-        cur.consequent.push(this$1.parseStatement())
+        cur.consequent.push(this$1.parseStatement());
       }
     }
-    if (cur) this.finishNode(cur, "SwitchCase")
-    this.popCx()
-    this.eat(__acorn.tokTypes.braceR)
+    if (cur) { this.finishNode(cur, "SwitchCase"); }
+    this.popCx();
+    this.eat(acorn.tokTypes.braceR);
     return this.finishNode(node, "SwitchStatement")
 
-  case __acorn.tokTypes._throw:
-    this.next()
-    node.argument = this.parseExpression()
-    this.semicolon()
+  case acorn.tokTypes._throw:
+    this.next();
+    node.argument = this.parseExpression();
+    this.semicolon();
     return this.finishNode(node, "ThrowStatement")
 
-  case __acorn.tokTypes._try:
-    this.next()
-    node.block = this.parseBlock()
-    node.handler = null
-    if (this.tok.type === __acorn.tokTypes._catch) {
-      var clause = this.startNode()
-      this.next()
-      this.expect(__acorn.tokTypes.parenL)
-      clause.param = this.toAssignable(this.parseExprAtom(), true)
-      this.expect(__acorn.tokTypes.parenR)
-      clause.body = this.parseBlock()
-      node.handler = this.finishNode(clause, "CatchClause")
+  case acorn.tokTypes._try:
+    this.next();
+    node.block = this.parseBlock();
+    node.handler = null;
+    if (this.tok.type === acorn.tokTypes._catch) {
+      var clause = this.startNode();
+      this.next();
+      if (this.eat(acorn.tokTypes.parenL)) {
+        clause.param = this.toAssignable(this.parseExprAtom(), true);
+        this.expect(acorn.tokTypes.parenR);
+      } else {
+        clause.param = null;
+      }
+      clause.body = this.parseBlock();
+      node.handler = this.finishNode(clause, "CatchClause");
     }
-    node.finalizer = this.eat(__acorn.tokTypes._finally) ? this.parseBlock() : null
-    if (!node.handler && !node.finalizer) return node.block
+    node.finalizer = this.eat(acorn.tokTypes._finally) ? this.parseBlock() : null;
+    if (!node.handler && !node.finalizer) { return node.block }
     return this.finishNode(node, "TryStatement")
 
-  case __acorn.tokTypes._var:
-  case __acorn.tokTypes._const:
-    return this.parseVar(false, kind || this.tok.value)
+  case acorn.tokTypes._var:
+  case acorn.tokTypes._const:
+    return this.parseVar(node, false, kind || this.tok.value)
 
-  case __acorn.tokTypes._while:
-    this.next()
-    node.test = this.parseParenExpression()
-    node.body = this.parseStatement()
+  case acorn.tokTypes._while:
+    this.next();
+    node.test = this.parseParenExpression();
+    node.body = this.parseStatement();
     return this.finishNode(node, "WhileStatement")
 
-  case __acorn.tokTypes._with:
-    this.next()
-    node.object = this.parseParenExpression()
-    node.body = this.parseStatement()
+  case acorn.tokTypes._with:
+    this.next();
+    node.object = this.parseParenExpression();
+    node.body = this.parseStatement();
     return this.finishNode(node, "WithStatement")
 
-  case __acorn.tokTypes.braceL:
+  case acorn.tokTypes.braceL:
     return this.parseBlock()
 
-  case __acorn.tokTypes.semi:
-    this.next()
+  case acorn.tokTypes.semi:
+    this.next();
     return this.finishNode(node, "EmptyStatement")
 
-  case __acorn.tokTypes._class:
+  case acorn.tokTypes._class:
     return this.parseClass(true)
 
-  case __acorn.tokTypes._import:
+  case acorn.tokTypes._import:
     return this.parseImport()
 
-  case __acorn.tokTypes._export:
+  case acorn.tokTypes._export:
     return this.parseExport()
 
   default:
     if (this.toks.isAsyncFunction()) {
-      this.next()
-      this.next()
+      this.next();
+      this.next();
       return this.parseFunction(node, true, true)
     }
-    var expr = this.parseExpression()
+    var expr = this.parseExpression();
     if (isDummy(expr)) {
-      this.next()
-      if (this.tok.type === __acorn.tokTypes.eof) return this.finishNode(node, "EmptyStatement")
+      this.next();
+      if (this.tok.type === acorn.tokTypes.eof) { return this.finishNode(node, "EmptyStatement") }
       return this.parseStatement()
-    } else if (starttype === __acorn.tokTypes.name && expr.type === "Identifier" && this.eat(__acorn.tokTypes.colon)) {
-      node.body = this.parseStatement()
-      node.label = expr
+    } else if (starttype === acorn.tokTypes.name && expr.type === "Identifier" && this.eat(acorn.tokTypes.colon)) {
+      node.body = this.parseStatement();
+      node.label = expr;
       return this.finishNode(node, "LabeledStatement")
     } else {
-      node.expression = expr
-      this.semicolon()
+      node.expression = expr;
+      this.semicolon();
       return this.finishNode(node, "ExpressionStatement")
     }
   }
-}
+};
 
 lp$1.parseBlock = function() {
   var this$1 = this;
 
-  var node = this.startNode()
-  this.pushCx()
-  this.expect(__acorn.tokTypes.braceL)
-  var blockIndent = this.curIndent, line = this.curLineStart
-  node.body = []
-  while (!this.closes(__acorn.tokTypes.braceR, blockIndent, line, true))
-    node.body.push(this$1.parseStatement())
-  this.popCx()
-  this.eat(__acorn.tokTypes.braceR)
+  var node = this.startNode();
+  this.pushCx();
+  this.expect(acorn.tokTypes.braceL);
+  var blockIndent = this.curIndent, line = this.curLineStart;
+  node.body = [];
+  while (!this.closes(acorn.tokTypes.braceR, blockIndent, line, true))
+    { node.body.push(this$1.parseStatement()); }
+  this.popCx();
+  this.eat(acorn.tokTypes.braceR);
   return this.finishNode(node, "BlockStatement")
-}
+};
 
 lp$1.parseFor = function(node, init) {
-  node.init = init
-  node.test = node.update = null
-  if (this.eat(__acorn.tokTypes.semi) && this.tok.type !== __acorn.tokTypes.semi) node.test = this.parseExpression()
-  if (this.eat(__acorn.tokTypes.semi) && this.tok.type !== __acorn.tokTypes.parenR) node.update = this.parseExpression()
-  this.popCx()
-  this.expect(__acorn.tokTypes.parenR)
-  node.body = this.parseStatement()
+  node.init = init;
+  node.test = node.update = null;
+  if (this.eat(acorn.tokTypes.semi) && this.tok.type !== acorn.tokTypes.semi) { node.test = this.parseExpression(); }
+  if (this.eat(acorn.tokTypes.semi) && this.tok.type !== acorn.tokTypes.parenR) { node.update = this.parseExpression(); }
+  this.popCx();
+  this.expect(acorn.tokTypes.parenR);
+  node.body = this.parseStatement();
   return this.finishNode(node, "ForStatement")
-}
+};
 
 lp$1.parseForIn = function(node, init) {
-  var type = this.tok.type === __acorn.tokTypes._in ? "ForInStatement" : "ForOfStatement"
-  this.next()
-  node.left = init
-  node.right = this.parseExpression()
-  this.popCx()
-  this.expect(__acorn.tokTypes.parenR)
-  node.body = this.parseStatement()
+  var type = this.tok.type === acorn.tokTypes._in ? "ForInStatement" : "ForOfStatement";
+  this.next();
+  node.left = init;
+  node.right = this.parseExpression();
+  this.popCx();
+  this.expect(acorn.tokTypes.parenR);
+  node.body = this.parseStatement();
   return this.finishNode(node, type)
-}
+};
 
-lp$1.parseVar = function(noIn, kind) {
+lp$1.parseVar = function(node, noIn, kind) {
   var this$1 = this;
 
-  var node = this.startNode()
-  node.kind = kind
-  this.next()
-  node.declarations = []
+  node.kind = kind;
+  this.next();
+  node.declarations = [];
   do {
-    var decl = this$1.startNode()
-    decl.id = this$1.options.ecmaVersion >= 6 ? this$1.toAssignable(this$1.parseExprAtom(), true) : this$1.parseIdent()
-    decl.init = this$1.eat(__acorn.tokTypes.eq) ? this$1.parseMaybeAssign(noIn) : null
-    node.declarations.push(this$1.finishNode(decl, "VariableDeclarator"))
-  } while (this.eat(__acorn.tokTypes.comma))
+    var decl = this$1.startNode();
+    decl.id = this$1.options.ecmaVersion >= 6 ? this$1.toAssignable(this$1.parseExprAtom(), true) : this$1.parseIdent();
+    decl.init = this$1.eat(acorn.tokTypes.eq) ? this$1.parseMaybeAssign(noIn) : null;
+    node.declarations.push(this$1.finishNode(decl, "VariableDeclarator"));
+  } while (this.eat(acorn.tokTypes.comma))
   if (!node.declarations.length) {
-    var decl$1 = this.startNode()
-    decl$1.id = this.dummyIdent()
-    node.declarations.push(this.finishNode(decl$1, "VariableDeclarator"))
+    var decl$1 = this.startNode();
+    decl$1.id = this.dummyIdent();
+    node.declarations.push(this.finishNode(decl$1, "VariableDeclarator"));
   }
-  if (!noIn) this.semicolon()
+  if (!noIn) { this.semicolon(); }
   return this.finishNode(node, "VariableDeclaration")
-}
+};
 
 lp$1.parseClass = function(isStatement) {
   var this$1 = this;
 
-  var node = this.startNode()
-  this.next()
-  if (this.tok.type === __acorn.tokTypes.name) node.id = this.parseIdent()
-  else if (isStatement === true) node.id = this.dummyIdent()
-  else node.id = null
-  node.superClass = this.eat(__acorn.tokTypes._extends) ? this.parseExpression() : null
-  node.body = this.startNode()
-  node.body.body = []
-  this.pushCx()
-  var indent = this.curIndent + 1, line = this.curLineStart
-  this.eat(__acorn.tokTypes.braceL)
-  if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart }
-  while (!this.closes(__acorn.tokTypes.braceR, indent, line)) {
-    if (this$1.semicolon()) continue
-    var method = this$1.startNode(), isGenerator, isAsync
+  var node = this.startNode();
+  this.next();
+  if (this.tok.type === acorn.tokTypes.name) { node.id = this.parseIdent(); }
+  else if (isStatement === true) { node.id = this.dummyIdent(); }
+  else { node.id = null; }
+  node.superClass = this.eat(acorn.tokTypes._extends) ? this.parseExpression() : null;
+  node.body = this.startNode();
+  node.body.body = [];
+  this.pushCx();
+  var indent = this.curIndent + 1, line = this.curLineStart;
+  this.eat(acorn.tokTypes.braceL);
+  if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart; }
+  while (!this.closes(acorn.tokTypes.braceR, indent, line)) {
+    if (this$1.semicolon()) { continue }
+    var method = this$1.startNode(), isGenerator = (void 0), isAsync = (void 0);
     if (this$1.options.ecmaVersion >= 6) {
-      method.static = false
-      isGenerator = this$1.eat(__acorn.tokTypes.star)
+      method.static = false;
+      isGenerator = this$1.eat(acorn.tokTypes.star);
     }
-    this$1.parsePropertyName(method)
-    if (isDummy(method.key)) { if (isDummy(this$1.parseMaybeAssign())) this$1.next(); this$1.eat(__acorn.tokTypes.comma); continue }
+    this$1.parsePropertyName(method);
+    if (isDummy(method.key)) { if (isDummy(this$1.parseMaybeAssign())) { this$1.next(); } this$1.eat(acorn.tokTypes.comma); continue }
     if (method.key.type === "Identifier" && !method.computed && method.key.name === "static" &&
-        (this$1.tok.type != __acorn.tokTypes.parenL && this$1.tok.type != __acorn.tokTypes.braceL)) {
-      method.static = true
-      isGenerator = this$1.eat(__acorn.tokTypes.star)
-      this$1.parsePropertyName(method)
+        (this$1.tok.type !== acorn.tokTypes.parenL && this$1.tok.type !== acorn.tokTypes.braceL)) {
+      method.static = true;
+      isGenerator = this$1.eat(acorn.tokTypes.star);
+      this$1.parsePropertyName(method);
     } else {
-      method.static = false
+      method.static = false;
     }
     if (!method.computed &&
-        method.key.type === "Identifier" && method.key.name === "async" && this$1.tok.type !== __acorn.tokTypes.parenL &&
+        method.key.type === "Identifier" && method.key.name === "async" && this$1.tok.type !== acorn.tokTypes.parenL &&
         !this$1.canInsertSemicolon()) {
-      this$1.parsePropertyName(method)
-      isAsync = true
+      isAsync = true;
+      isGenerator = this$1.options.ecmaVersion >= 9 && this$1.eat(acorn.tokTypes.star);
+      this$1.parsePropertyName(method);
     } else {
-      isAsync = false
+      isAsync = false;
     }
     if (this$1.options.ecmaVersion >= 5 && method.key.type === "Identifier" &&
         !method.computed && (method.key.name === "get" || method.key.name === "set") &&
-        this$1.tok.type !== __acorn.tokTypes.parenL && this$1.tok.type !== __acorn.tokTypes.braceL) {
-      method.kind = method.key.name
-      this$1.parsePropertyName(method)
-      method.value = this$1.parseMethod(false)
+        this$1.tok.type !== acorn.tokTypes.parenL && this$1.tok.type !== acorn.tokTypes.braceL) {
+      method.kind = method.key.name;
+      this$1.parsePropertyName(method);
+      method.value = this$1.parseMethod(false);
     } else {
       if (!method.computed && !method.static && !isGenerator && !isAsync && (
         method.key.type === "Identifier" && method.key.name === "constructor" ||
           method.key.type === "Literal" && method.key.value === "constructor")) {
-        method.kind = "constructor"
+        method.kind = "constructor";
       } else {
-        method.kind = "method"
+        method.kind = "method";
       }
-      method.value = this$1.parseMethod(isGenerator, isAsync)
+      method.value = this$1.parseMethod(isGenerator, isAsync);
     }
-    node.body.body.push(this$1.finishNode(method, "MethodDefinition"))
+    node.body.body.push(this$1.finishNode(method, "MethodDefinition"));
   }
-  this.popCx()
-  if (!this.eat(__acorn.tokTypes.braceR)) {
+  this.popCx();
+  if (!this.eat(acorn.tokTypes.braceR)) {
     // If there is no closing brace, make the node span to the start
     // of the next token (this is useful for Tern)
-    this.last.end = this.tok.start
-    if (this.options.locations) this.last.loc.end = this.tok.loc.start
+    this.last.end = this.tok.start;
+    if (this.options.locations) { this.last.loc.end = this.tok.loc.start; }
   }
-  this.semicolon()
-  this.finishNode(node.body, "ClassBody")
+  this.semicolon();
+  this.finishNode(node.body, "ClassBody");
   return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression")
-}
+};
 
 lp$1.parseFunction = function(node, isStatement, isAsync) {
-  var oldInAsync = this.inAsync
-  this.initFunction(node)
+  var oldInAsync = this.inAsync, oldInFunction = this.inFunction;
+  this.initFunction(node);
   if (this.options.ecmaVersion >= 6) {
-    node.generator = this.eat(__acorn.tokTypes.star)
+    node.generator = this.eat(acorn.tokTypes.star);
   }
   if (this.options.ecmaVersion >= 8) {
-    node.async = !!isAsync
+    node.async = !!isAsync;
   }
-  if (this.tok.type === __acorn.tokTypes.name) node.id = this.parseIdent()
-  else if (isStatement === true) node.id = this.dummyIdent()
-  this.inAsync = node.async
-  node.params = this.parseFunctionParams()
-  node.body = this.parseBlock()
-  this.inAsync = oldInAsync
+  if (this.tok.type === acorn.tokTypes.name) { node.id = this.parseIdent(); }
+  else if (isStatement === true) { node.id = this.dummyIdent(); }
+  this.inAsync = node.async;
+  this.inFunction = true;
+  node.params = this.parseFunctionParams();
+  node.body = this.parseBlock();
+  this.toks.adaptDirectivePrologue(node.body.body);
+  this.inAsync = oldInAsync;
+  this.inFunction = oldInFunction;
   return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression")
-}
+};
 
 lp$1.parseExport = function() {
-  var node = this.startNode()
-  this.next()
-  if (this.eat(__acorn.tokTypes.star)) {
-    node.source = this.eatContextual("from") ? this.parseExprAtom() : this.dummyString()
+  var node = this.startNode();
+  this.next();
+  if (this.eat(acorn.tokTypes.star)) {
+    node.source = this.eatContextual("from") ? this.parseExprAtom() : this.dummyString();
     return this.finishNode(node, "ExportAllDeclaration")
   }
-  if (this.eat(__acorn.tokTypes._default)) {
+  if (this.eat(acorn.tokTypes._default)) {
     // export default (function foo() {}) // This is FunctionExpression.
-    var isAsync
-    if (this.tok.type === __acorn.tokTypes._function || (isAsync = this.toks.isAsyncFunction())) {
-      var fNode = this.startNode()
-      this.next()
-      if (isAsync) this.next()
-      node.declaration = this.parseFunction(fNode, "nullableID", isAsync)
-    } else if (this.tok.type === __acorn.tokTypes._class) {
-      node.declaration = this.parseClass("nullableID")
+    var isAsync;
+    if (this.tok.type === acorn.tokTypes._function || (isAsync = this.toks.isAsyncFunction())) {
+      var fNode = this.startNode();
+      this.next();
+      if (isAsync) { this.next(); }
+      node.declaration = this.parseFunction(fNode, "nullableID", isAsync);
+    } else if (this.tok.type === acorn.tokTypes._class) {
+      node.declaration = this.parseClass("nullableID");
     } else {
-      node.declaration = this.parseMaybeAssign()
-      this.semicolon()
+      node.declaration = this.parseMaybeAssign();
+      this.semicolon();
     }
     return this.finishNode(node, "ExportDefaultDeclaration")
   }
   if (this.tok.type.keyword || this.toks.isLet() || this.toks.isAsyncFunction()) {
-    node.declaration = this.parseStatement()
-    node.specifiers = []
-    node.source = null
+    node.declaration = this.parseStatement();
+    node.specifiers = [];
+    node.source = null;
   } else {
-    node.declaration = null
-    node.specifiers = this.parseExportSpecifierList()
-    node.source = this.eatContextual("from") ? this.parseExprAtom() : null
-    this.semicolon()
+    node.declaration = null;
+    node.specifiers = this.parseExportSpecifierList();
+    node.source = this.eatContextual("from") ? this.parseExprAtom() : null;
+    this.semicolon();
   }
   return this.finishNode(node, "ExportNamedDeclaration")
-}
+};
 
 lp$1.parseImport = function() {
-  var node = this.startNode()
-  this.next()
-  if (this.tok.type === __acorn.tokTypes.string) {
-    node.specifiers = []
-    node.source = this.parseExprAtom()
-    node.kind = ""
+  var node = this.startNode();
+  this.next();
+  if (this.tok.type === acorn.tokTypes.string) {
+    node.specifiers = [];
+    node.source = this.parseExprAtom();
   } else {
-    var elt
-    if (this.tok.type === __acorn.tokTypes.name && this.tok.value !== "from") {
-      elt = this.startNode()
-      elt.local = this.parseIdent()
-      this.finishNode(elt, "ImportDefaultSpecifier")
-      this.eat(__acorn.tokTypes.comma)
+    var elt;
+    if (this.tok.type === acorn.tokTypes.name && this.tok.value !== "from") {
+      elt = this.startNode();
+      elt.local = this.parseIdent();
+      this.finishNode(elt, "ImportDefaultSpecifier");
+      this.eat(acorn.tokTypes.comma);
     }
-    node.specifiers = this.parseImportSpecifierList()
-    node.source = this.eatContextual("from") && this.tok.type == __acorn.tokTypes.string ? this.parseExprAtom() : this.dummyString()
-    if (elt) node.specifiers.unshift(elt)
+    node.specifiers = this.parseImportSpecifiers();
+    node.source = this.eatContextual("from") && this.tok.type === acorn.tokTypes.string ? this.parseExprAtom() : this.dummyString();
+    if (elt) { node.specifiers.unshift(elt); }
   }
-  this.semicolon()
+  this.semicolon();
   return this.finishNode(node, "ImportDeclaration")
-}
+};
 
-lp$1.parseImportSpecifierList = function() {
+lp$1.parseImportSpecifiers = function() {
   var this$1 = this;
 
-  var elts = []
-  if (this.tok.type === __acorn.tokTypes.star) {
-    var elt = this.startNode()
-    this.next()
-    elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent()
-    elts.push(this.finishNode(elt, "ImportNamespaceSpecifier"))
+  var elts = [];
+  if (this.tok.type === acorn.tokTypes.star) {
+    var elt = this.startNode();
+    this.next();
+    elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent();
+    elts.push(this.finishNode(elt, "ImportNamespaceSpecifier"));
   } else {
-    var indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart
-    this.pushCx()
-    this.eat(__acorn.tokTypes.braceL)
-    if (this.curLineStart > continuedLine) continuedLine = this.curLineStart
-    while (!this.closes(__acorn.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) {
-      var elt$1 = this$1.startNode()
-      if (this$1.eat(__acorn.tokTypes.star)) {
-        elt$1.local = this$1.eatContextual("as") ? this$1.parseIdent() : this$1.dummyIdent()
-        this$1.finishNode(elt$1, "ImportNamespaceSpecifier")
+    var indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart;
+    this.pushCx();
+    this.eat(acorn.tokTypes.braceL);
+    if (this.curLineStart > continuedLine) { continuedLine = this.curLineStart; }
+    while (!this.closes(acorn.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) {
+      var elt$1 = this$1.startNode();
+      if (this$1.eat(acorn.tokTypes.star)) {
+        elt$1.local = this$1.eatContextual("as") ? this$1.parseIdent() : this$1.dummyIdent();
+        this$1.finishNode(elt$1, "ImportNamespaceSpecifier");
       } else {
-        if (this$1.isContextual("from")) break
-        elt$1.imported = this$1.parseIdent()
-        if (isDummy(elt$1.imported)) break
-        elt$1.local = this$1.eatContextual("as") ? this$1.parseIdent() : elt$1.imported
-        this$1.finishNode(elt$1, "ImportSpecifier")
+        if (this$1.isContextual("from")) { break }
+        elt$1.imported = this$1.parseIdent();
+        if (isDummy(elt$1.imported)) { break }
+        elt$1.local = this$1.eatContextual("as") ? this$1.parseIdent() : elt$1.imported;
+        this$1.finishNode(elt$1, "ImportSpecifier");
       }
-      elts.push(elt$1)
-      this$1.eat(__acorn.tokTypes.comma)
+      elts.push(elt$1);
+      this$1.eat(acorn.tokTypes.comma);
     }
-    this.eat(__acorn.tokTypes.braceR)
-    this.popCx()
+    this.eat(acorn.tokTypes.braceR);
+    this.popCx();
   }
   return elts
-}
+};
 
 lp$1.parseExportSpecifierList = function() {
   var this$1 = this;
 
-  var elts = []
-  var indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart
-  this.pushCx()
-  this.eat(__acorn.tokTypes.braceL)
-  if (this.curLineStart > continuedLine) continuedLine = this.curLineStart
-  while (!this.closes(__acorn.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) {
-    if (this$1.isContextual("from")) break
-    var elt = this$1.startNode()
-    elt.local = this$1.parseIdent()
-    if (isDummy(elt.local)) break
-    elt.exported = this$1.eatContextual("as") ? this$1.parseIdent() : elt.local
-    this$1.finishNode(elt, "ExportSpecifier")
-    elts.push(elt)
-    this$1.eat(__acorn.tokTypes.comma)
+  var elts = [];
+  var indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart;
+  this.pushCx();
+  this.eat(acorn.tokTypes.braceL);
+  if (this.curLineStart > continuedLine) { continuedLine = this.curLineStart; }
+  while (!this.closes(acorn.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) {
+    if (this$1.isContextual("from")) { break }
+    var elt = this$1.startNode();
+    elt.local = this$1.parseIdent();
+    if (isDummy(elt.local)) { break }
+    elt.exported = this$1.eatContextual("as") ? this$1.parseIdent() : elt.local;
+    this$1.finishNode(elt, "ExportSpecifier");
+    elts.push(elt);
+    this$1.eat(acorn.tokTypes.comma);
   }
-  this.eat(__acorn.tokTypes.braceR)
-  this.popCx()
+  this.eat(acorn.tokTypes.braceR);
+  this.popCx();
   return elts
-}
+};
 
-var lp$2 = LooseParser.prototype
+var lp$2 = LooseParser.prototype;
 
 lp$2.checkLVal = function(expr) {
-  if (!expr) return expr
+  if (!expr) { return expr }
   switch (expr.type) {
   case "Identifier":
   case "MemberExpression":
     return expr
 
   case "ParenthesizedExpression":
-    expr.expression = this.checkLVal(expr.expression)
+    expr.expression = this.checkLVal(expr.expression);
     return expr
 
   default:
     return this.dummyIdent()
   }
-}
+};
 
 lp$2.parseExpression = function(noIn) {
   var this$1 = this;
 
-  var start = this.storeCurrentPos()
-  var expr = this.parseMaybeAssign(noIn)
-  if (this.tok.type === __acorn.tokTypes.comma) {
-    var node = this.startNodeAt(start)
-    node.expressions = [expr]
-    while (this.eat(__acorn.tokTypes.comma)) node.expressions.push(this$1.parseMaybeAssign(noIn))
+  var start = this.storeCurrentPos();
+  var expr = this.parseMaybeAssign(noIn);
+  if (this.tok.type === acorn.tokTypes.comma) {
+    var node = this.startNodeAt(start);
+    node.expressions = [expr];
+    while (this.eat(acorn.tokTypes.comma)) { node.expressions.push(this$1.parseMaybeAssign(noIn)); }
     return this.finishNode(node, "SequenceExpression")
   }
   return expr
-}
+};
 
 lp$2.parseParenExpression = function() {
-  this.pushCx()
-  this.expect(__acorn.tokTypes.parenL)
-  var val = this.parseExpression()
-  this.popCx()
-  this.expect(__acorn.tokTypes.parenR)
+  this.pushCx();
+  this.expect(acorn.tokTypes.parenL);
+  var val = this.parseExpression();
+  this.popCx();
+  this.expect(acorn.tokTypes.parenR);
   return val
-}
+};
 
 lp$2.parseMaybeAssign = function(noIn) {
   if (this.toks.isContextual("yield")) {
-    var node = this.startNode()
-    this.next()
-    if (this.semicolon() || this.canInsertSemicolon() || (this.tok.type != __acorn.tokTypes.star && !this.tok.type.startsExpr)) {
-      node.delegate = false
-      node.argument = null
+    var node = this.startNode();
+    this.next();
+    if (this.semicolon() || this.canInsertSemicolon() || (this.tok.type !== acorn.tokTypes.star && !this.tok.type.startsExpr)) {
+      node.delegate = false;
+      node.argument = null;
     } else {
-      node.delegate = this.eat(__acorn.tokTypes.star)
-      node.argument = this.parseMaybeAssign()
+      node.delegate = this.eat(acorn.tokTypes.star);
+      node.argument = this.parseMaybeAssign();
     }
     return this.finishNode(node, "YieldExpression")
   }
 
-  var start = this.storeCurrentPos()
-  var left = this.parseMaybeConditional(noIn)
+  var start = this.storeCurrentPos();
+  var left = this.parseMaybeConditional(noIn);
   if (this.tok.type.isAssign) {
-    var node$1 = this.startNodeAt(start)
-    node$1.operator = this.tok.value
-    node$1.left = this.tok.type === __acorn.tokTypes.eq ? this.toAssignable(left) : this.checkLVal(left)
-    this.next()
-    node$1.right = this.parseMaybeAssign(noIn)
+    var node$1 = this.startNodeAt(start);
+    node$1.operator = this.tok.value;
+    node$1.left = this.tok.type === acorn.tokTypes.eq ? this.toAssignable(left) : this.checkLVal(left);
+    this.next();
+    node$1.right = this.parseMaybeAssign(noIn);
     return this.finishNode(node$1, "AssignmentExpression")
   }
   return left
-}
+};
 
 lp$2.parseMaybeConditional = function(noIn) {
-  var start = this.storeCurrentPos()
-  var expr = this.parseExprOps(noIn)
-  if (this.eat(__acorn.tokTypes.question)) {
-    var node = this.startNodeAt(start)
-    node.test = expr
-    node.consequent = this.parseMaybeAssign()
-    node.alternate = this.expect(__acorn.tokTypes.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent()
+  var start = this.storeCurrentPos();
+  var expr = this.parseExprOps(noIn);
+  if (this.eat(acorn.tokTypes.question)) {
+    var node = this.startNodeAt(start);
+    node.test = expr;
+    node.consequent = this.parseMaybeAssign();
+    node.alternate = this.expect(acorn.tokTypes.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent();
     return this.finishNode(node, "ConditionalExpression")
   }
   return expr
-}
+};
 
 lp$2.parseExprOps = function(noIn) {
-  var start = this.storeCurrentPos()
-  var indent = this.curIndent, line = this.curLineStart
+  var start = this.storeCurrentPos();
+  var indent = this.curIndent, line = this.curLineStart;
   return this.parseExprOp(this.parseMaybeUnary(false), start, -1, noIn, indent, line)
-}
+};
 
 lp$2.parseExprOp = function(left, start, minPrec, noIn, indent, line) {
-  if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) return left
-  var prec = this.tok.type.binop
-  if (prec != null && (!noIn || this.tok.type !== __acorn.tokTypes._in)) {
+  if (this.curLineStart !== line && this.curIndent < indent && this.tokenStartsLine()) { return left }
+  var prec = this.tok.type.binop;
+  if (prec != null && (!noIn || this.tok.type !== acorn.tokTypes._in)) {
     if (prec > minPrec) {
-      var node = this.startNodeAt(start)
-      node.left = left
-      node.operator = this.tok.value
-      this.next()
-      if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) {
-        node.right = this.dummyIdent()
+      var node = this.startNodeAt(start);
+      node.left = left;
+      node.operator = this.tok.value;
+      this.next();
+      if (this.curLineStart !== line && this.curIndent < indent && this.tokenStartsLine()) {
+        node.right = this.dummyIdent();
       } else {
-        var rightStart = this.storeCurrentPos()
-        node.right = this.parseExprOp(this.parseMaybeUnary(false), rightStart, prec, noIn, indent, line)
+        var rightStart = this.storeCurrentPos();
+        node.right = this.parseExprOp(this.parseMaybeUnary(false), rightStart, prec, noIn, indent, line);
       }
-      this.finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression")
+      this.finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression");
       return this.parseExprOp(node, start, minPrec, noIn, indent, line)
     }
   }
   return left
-}
+};
 
 lp$2.parseMaybeUnary = function(sawUnary) {
   var this$1 = this;
 
-  var start = this.storeCurrentPos(), expr
-  if (this.options.ecmaVersion >= 8 && this.inAsync && this.toks.isContextual("await")) {
-    expr = this.parseAwait()
-    sawUnary = true
+  var start = this.storeCurrentPos(), expr;
+  if (this.options.ecmaVersion >= 8 && this.toks.isContextual("await") &&
+    (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction))
+  ) {
+    expr = this.parseAwait();
+    sawUnary = true;
   } else if (this.tok.type.prefix) {
-    var node = this.startNode(), update = this.tok.type === __acorn.tokTypes.incDec
-    if (!update) sawUnary = true
-    node.operator = this.tok.value
-    node.prefix = true
-    this.next()
-    node.argument = this.parseMaybeUnary(true)
-    if (update) node.argument = this.checkLVal(node.argument)
-    expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression")
-  } else if (this.tok.type === __acorn.tokTypes.ellipsis) {
-    var node$1 = this.startNode()
-    this.next()
-    node$1.argument = this.parseMaybeUnary(sawUnary)
-    expr = this.finishNode(node$1, "SpreadElement")
+    var node = this.startNode(), update = this.tok.type === acorn.tokTypes.incDec;
+    if (!update) { sawUnary = true; }
+    node.operator = this.tok.value;
+    node.prefix = true;
+    this.next();
+    node.argument = this.parseMaybeUnary(true);
+    if (update) { node.argument = this.checkLVal(node.argument); }
+    expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
+  } else if (this.tok.type === acorn.tokTypes.ellipsis) {
+    var node$1 = this.startNode();
+    this.next();
+    node$1.argument = this.parseMaybeUnary(sawUnary);
+    expr = this.finishNode(node$1, "SpreadElement");
   } else {
-    expr = this.parseExprSubscripts()
+    expr = this.parseExprSubscripts();
     while (this.tok.type.postfix && !this.canInsertSemicolon()) {
-      var node$2 = this$1.startNodeAt(start)
-      node$2.operator = this$1.tok.value
-      node$2.prefix = false
-      node$2.argument = this$1.checkLVal(expr)
-      this$1.next()
-      expr = this$1.finishNode(node$2, "UpdateExpression")
+      var node$2 = this$1.startNodeAt(start);
+      node$2.operator = this$1.tok.value;
+      node$2.prefix = false;
+      node$2.argument = this$1.checkLVal(expr);
+      this$1.next();
+      expr = this$1.finishNode(node$2, "UpdateExpression");
     }
   }
 
-  if (!sawUnary && this.eat(__acorn.tokTypes.starstar)) {
-    var node$3 = this.startNodeAt(start)
-    node$3.operator = "**"
-    node$3.left = expr
-    node$3.right = this.parseMaybeUnary(false)
+  if (!sawUnary && this.eat(acorn.tokTypes.starstar)) {
+    var node$3 = this.startNodeAt(start);
+    node$3.operator = "**";
+    node$3.left = expr;
+    node$3.right = this.parseMaybeUnary(false);
     return this.finishNode(node$3, "BinaryExpression")
   }
 
   return expr
-}
+};
 
 lp$2.parseExprSubscripts = function() {
-  var start = this.storeCurrentPos()
+  var start = this.storeCurrentPos();
   return this.parseSubscripts(this.parseExprAtom(), start, false, this.curIndent, this.curLineStart)
-}
+};
 
 lp$2.parseSubscripts = function(base, start, noCalls, startIndent, line) {
   var this$1 = this;
 
   for (;;) {
-    if (this$1.curLineStart != line && this$1.curIndent <= startIndent && this$1.tokenStartsLine()) {
-      if (this$1.tok.type == __acorn.tokTypes.dot && this$1.curIndent == startIndent)
-        --startIndent
+    if (this$1.curLineStart !== line && this$1.curIndent <= startIndent && this$1.tokenStartsLine()) {
+      if (this$1.tok.type === acorn.tokTypes.dot && this$1.curIndent === startIndent)
+        { --startIndent; }
       else
-        return base
+        { return base }
     }
 
-    var maybeAsyncArrow = base.type === "Identifier" && base.name === "async" && !this$1.canInsertSemicolon()
+    var maybeAsyncArrow = base.type === "Identifier" && base.name === "async" && !this$1.canInsertSemicolon();
 
-    if (this$1.eat(__acorn.tokTypes.dot)) {
-      var node = this$1.startNodeAt(start)
-      node.object = base
-      if (this$1.curLineStart != line && this$1.curIndent <= startIndent && this$1.tokenStartsLine())
-        node.property = this$1.dummyIdent()
+    if (this$1.eat(acorn.tokTypes.dot)) {
+      var node = this$1.startNodeAt(start);
+      node.object = base;
+      if (this$1.curLineStart !== line && this$1.curIndent <= startIndent && this$1.tokenStartsLine())
+        { node.property = this$1.dummyIdent(); }
       else
-        node.property = this$1.parsePropertyAccessor() || this$1.dummyIdent()
-      node.computed = false
-      base = this$1.finishNode(node, "MemberExpression")
-    } else if (this$1.tok.type == __acorn.tokTypes.bracketL) {
-      this$1.pushCx()
-      this$1.next()
-      var node$1 = this$1.startNodeAt(start)
-      node$1.object = base
-      node$1.property = this$1.parseExpression()
-      node$1.computed = true
-      this$1.popCx()
-      this$1.expect(__acorn.tokTypes.bracketR)
-      base = this$1.finishNode(node$1, "MemberExpression")
-    } else if (!noCalls && this$1.tok.type == __acorn.tokTypes.parenL) {
-      var exprList = this$1.parseExprList(__acorn.tokTypes.parenR)
-      if (maybeAsyncArrow && this$1.eat(__acorn.tokTypes.arrow))
-        return this$1.parseArrowExpression(this$1.startNodeAt(start), exprList, true)
-      var node$2 = this$1.startNodeAt(start)
-      node$2.callee = base
-      node$2.arguments = exprList
-      base = this$1.finishNode(node$2, "CallExpression")
-    } else if (this$1.tok.type == __acorn.tokTypes.backQuote) {
-      var node$3 = this$1.startNodeAt(start)
-      node$3.tag = base
-      node$3.quasi = this$1.parseTemplate()
-      base = this$1.finishNode(node$3, "TaggedTemplateExpression")
+        { node.property = this$1.parsePropertyAccessor() || this$1.dummyIdent(); }
+      node.computed = false;
+      base = this$1.finishNode(node, "MemberExpression");
+    } else if (this$1.tok.type === acorn.tokTypes.bracketL) {
+      this$1.pushCx();
+      this$1.next();
+      var node$1 = this$1.startNodeAt(start);
+      node$1.object = base;
+      node$1.property = this$1.parseExpression();
+      node$1.computed = true;
+      this$1.popCx();
+      this$1.expect(acorn.tokTypes.bracketR);
+      base = this$1.finishNode(node$1, "MemberExpression");
+    } else if (!noCalls && this$1.tok.type === acorn.tokTypes.parenL) {
+      var exprList = this$1.parseExprList(acorn.tokTypes.parenR);
+      if (maybeAsyncArrow && this$1.eat(acorn.tokTypes.arrow))
+        { return this$1.parseArrowExpression(this$1.startNodeAt(start), exprList, true) }
+      var node$2 = this$1.startNodeAt(start);
+      node$2.callee = base;
+      node$2.arguments = exprList;
+      base = this$1.finishNode(node$2, "CallExpression");
+    } else if (this$1.tok.type === acorn.tokTypes.backQuote) {
+      var node$3 = this$1.startNodeAt(start);
+      node$3.tag = base;
+      node$3.quasi = this$1.parseTemplate();
+      base = this$1.finishNode(node$3, "TaggedTemplateExpression");
     } else {
       return base
     }
   }
-}
+};
 
 lp$2.parseExprAtom = function() {
-  var node
+  var node;
   switch (this.tok.type) {
-  case __acorn.tokTypes._this:
-  case __acorn.tokTypes._super:
-    var type = this.tok.type === __acorn.tokTypes._this ? "ThisExpression" : "Super"
-    node = this.startNode()
-    this.next()
+  case acorn.tokTypes._this:
+  case acorn.tokTypes._super:
+    var type = this.tok.type === acorn.tokTypes._this ? "ThisExpression" : "Super";
+    node = this.startNode();
+    this.next();
     return this.finishNode(node, type)
 
-  case __acorn.tokTypes.name:
-    var start = this.storeCurrentPos()
-    var id = this.parseIdent()
-    var isAsync = false
+  case acorn.tokTypes.name:
+    var start = this.storeCurrentPos();
+    var id = this.parseIdent();
+    var isAsync = false;
     if (id.name === "async" && !this.canInsertSemicolon()) {
-      if (this.eat(__acorn.tokTypes._function))
-        return this.parseFunction(this.startNodeAt(start), false, true)
-      if (this.tok.type === __acorn.tokTypes.name) {
-        id = this.parseIdent()
-        isAsync = true
+      if (this.eat(acorn.tokTypes._function))
+        { return this.parseFunction(this.startNodeAt(start), false, true) }
+      if (this.tok.type === acorn.tokTypes.name) {
+        id = this.parseIdent();
+        isAsync = true;
       }
     }
-    return this.eat(__acorn.tokTypes.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id], isAsync) : id
+    return this.eat(acorn.tokTypes.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id], isAsync) : id
 
-  case __acorn.tokTypes.regexp:
-    node = this.startNode()
-    var val = this.tok.value
-    node.regex = {pattern: val.pattern, flags: val.flags}
-    node.value = val.value
-    node.raw = this.input.slice(this.tok.start, this.tok.end)
-    this.next()
+  case acorn.tokTypes.regexp:
+    node = this.startNode();
+    var val = this.tok.value;
+    node.regex = {pattern: val.pattern, flags: val.flags};
+    node.value = val.value;
+    node.raw = this.input.slice(this.tok.start, this.tok.end);
+    this.next();
     return this.finishNode(node, "Literal")
 
-  case __acorn.tokTypes.num: case __acorn.tokTypes.string:
-    node = this.startNode()
-    node.value = this.tok.value
-    node.raw = this.input.slice(this.tok.start, this.tok.end)
-    this.next()
+  case acorn.tokTypes.num: case acorn.tokTypes.string:
+    node = this.startNode();
+    node.value = this.tok.value;
+    node.raw = this.input.slice(this.tok.start, this.tok.end);
+    this.next();
     return this.finishNode(node, "Literal")
 
-  case __acorn.tokTypes._null: case __acorn.tokTypes._true: case __acorn.tokTypes._false:
-    node = this.startNode()
-    node.value = this.tok.type === __acorn.tokTypes._null ? null : this.tok.type === __acorn.tokTypes._true
-    node.raw = this.tok.type.keyword
-    this.next()
+  case acorn.tokTypes._null: case acorn.tokTypes._true: case acorn.tokTypes._false:
+    node = this.startNode();
+    node.value = this.tok.type === acorn.tokTypes._null ? null : this.tok.type === acorn.tokTypes._true;
+    node.raw = this.tok.type.keyword;
+    this.next();
     return this.finishNode(node, "Literal")
 
-  case __acorn.tokTypes.parenL:
-    var parenStart = this.storeCurrentPos()
-    this.next()
-    var inner = this.parseExpression()
-    this.expect(__acorn.tokTypes.parenR)
-    if (this.eat(__acorn.tokTypes.arrow)) {
+  case acorn.tokTypes.parenL:
+    var parenStart = this.storeCurrentPos();
+    this.next();
+    var inner = this.parseExpression();
+    this.expect(acorn.tokTypes.parenR);
+    if (this.eat(acorn.tokTypes.arrow)) {
       // (a,)=>a // SequenceExpression makes dummy in the last hole. Drop the dummy.
-      var params = inner.expressions || [inner]
+      var params = inner.expressions || [inner];
       if (params.length && isDummy(params[params.length - 1]))
-        params.pop()
+        { params.pop(); }
       return this.parseArrowExpression(this.startNodeAt(parenStart), params)
     }
     if (this.options.preserveParens) {
-      var par = this.startNodeAt(parenStart)
-      par.expression = inner
-      inner = this.finishNode(par, "ParenthesizedExpression")
+      var par = this.startNodeAt(parenStart);
+      par.expression = inner;
+      inner = this.finishNode(par, "ParenthesizedExpression");
     }
     return inner
 
-  case __acorn.tokTypes.bracketL:
-    node = this.startNode()
-    node.elements = this.parseExprList(__acorn.tokTypes.bracketR, true)
+  case acorn.tokTypes.bracketL:
+    node = this.startNode();
+    node.elements = this.parseExprList(acorn.tokTypes.bracketR, true);
     return this.finishNode(node, "ArrayExpression")
 
-  case __acorn.tokTypes.braceL:
+  case acorn.tokTypes.braceL:
     return this.parseObj()
 
-  case __acorn.tokTypes._class:
+  case acorn.tokTypes._class:
     return this.parseClass(false)
 
-  case __acorn.tokTypes._function:
-    node = this.startNode()
-    this.next()
+  case acorn.tokTypes._function:
+    node = this.startNode();
+    this.next();
     return this.parseFunction(node, false)
 
-  case __acorn.tokTypes._new:
+  case acorn.tokTypes._new:
     return this.parseNew()
 
-  case __acorn.tokTypes.backQuote:
+  case acorn.tokTypes.backQuote:
     return this.parseTemplate()
 
   default:
     return this.dummyIdent()
   }
-}
+};
 
 lp$2.parseNew = function() {
-  var node = this.startNode(), startIndent = this.curIndent, line = this.curLineStart
-  var meta = this.parseIdent(true)
-  if (this.options.ecmaVersion >= 6 && this.eat(__acorn.tokTypes.dot)) {
-    node.meta = meta
-    node.property = this.parseIdent(true)
+  var node = this.startNode(), startIndent = this.curIndent, line = this.curLineStart;
+  var meta = this.parseIdent(true);
+  if (this.options.ecmaVersion >= 6 && this.eat(acorn.tokTypes.dot)) {
+    node.meta = meta;
+    node.property = this.parseIdent(true);
     return this.finishNode(node, "MetaProperty")
   }
-  var start = this.storeCurrentPos()
-  node.callee = this.parseSubscripts(this.parseExprAtom(), start, true, startIndent, line)
-  if (this.tok.type == __acorn.tokTypes.parenL) {
-    node.arguments = this.parseExprList(__acorn.tokTypes.parenR)
+  var start = this.storeCurrentPos();
+  node.callee = this.parseSubscripts(this.parseExprAtom(), start, true, startIndent, line);
+  if (this.tok.type === acorn.tokTypes.parenL) {
+    node.arguments = this.parseExprList(acorn.tokTypes.parenR);
   } else {
-    node.arguments = []
+    node.arguments = [];
   }
   return this.finishNode(node, "NewExpression")
-}
+};
 
 lp$2.parseTemplateElement = function() {
-  var elem = this.startNode()
-  elem.value = {
-    raw: this.input.slice(this.tok.start, this.tok.end).replace(/\r\n?/g, "\n"),
-    cooked: this.tok.value
+  var elem = this.startNode();
+
+  // The loose parser accepts invalid unicode escapes even in untagged templates.
+  if (this.tok.type === acorn.tokTypes.invalidTemplate) {
+    elem.value = {
+      raw: this.tok.value,
+      cooked: null
+    };
+  } else {
+    elem.value = {
+      raw: this.input.slice(this.tok.start, this.tok.end).replace(/\r\n?/g, "\n"),
+      cooked: this.tok.value
+    };
   }
-  this.next()
-  elem.tail = this.tok.type === __acorn.tokTypes.backQuote
+  this.next();
+  elem.tail = this.tok.type === acorn.tokTypes.backQuote;
   return this.finishNode(elem, "TemplateElement")
-}
+};
 
 lp$2.parseTemplate = function() {
   var this$1 = this;
 
-  var node = this.startNode()
-  this.next()
-  node.expressions = []
-  var curElt = this.parseTemplateElement()
-  node.quasis = [curElt]
+  var node = this.startNode();
+  this.next();
+  node.expressions = [];
+  var curElt = this.parseTemplateElement();
+  node.quasis = [curElt];
   while (!curElt.tail) {
-    this$1.next()
-    node.expressions.push(this$1.parseExpression())
-    if (this$1.expect(__acorn.tokTypes.braceR)) {
-      curElt = this$1.parseTemplateElement()
+    this$1.next();
+    node.expressions.push(this$1.parseExpression());
+    if (this$1.expect(acorn.tokTypes.braceR)) {
+      curElt = this$1.parseTemplateElement();
     } else {
-      curElt = this$1.startNode()
-      curElt.value = {cooked: "", raw: ""}
-      curElt.tail = true
-      this$1.finishNode(curElt, "TemplateElement")
+      curElt = this$1.startNode();
+      curElt.value = {cooked: "", raw: ""};
+      curElt.tail = true;
+      this$1.finishNode(curElt, "TemplateElement");
     }
-    node.quasis.push(curElt)
+    node.quasis.push(curElt);
   }
-  this.expect(__acorn.tokTypes.backQuote)
+  this.expect(acorn.tokTypes.backQuote);
   return this.finishNode(node, "TemplateLiteral")
-}
+};
 
 lp$2.parseObj = function() {
   var this$1 = this;
 
-  var node = this.startNode()
-  node.properties = []
-  this.pushCx()
-  var indent = this.curIndent + 1, line = this.curLineStart
-  this.eat(__acorn.tokTypes.braceL)
-  if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart }
-  while (!this.closes(__acorn.tokTypes.braceR, indent, line)) {
-    var prop = this$1.startNode(), isGenerator, isAsync, start
+  var node = this.startNode();
+  node.properties = [];
+  this.pushCx();
+  var indent = this.curIndent + 1, line = this.curLineStart;
+  this.eat(acorn.tokTypes.braceL);
+  if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart; }
+  while (!this.closes(acorn.tokTypes.braceR, indent, line)) {
+    var prop = this$1.startNode(), isGenerator = (void 0), isAsync = (void 0), start = (void 0);
+    if (this$1.options.ecmaVersion >= 9 && this$1.eat(acorn.tokTypes.ellipsis)) {
+      prop.argument = this$1.parseMaybeAssign();
+      node.properties.push(this$1.finishNode(prop, "SpreadElement"));
+      this$1.eat(acorn.tokTypes.comma);
+      continue
+    }
     if (this$1.options.ecmaVersion >= 6) {
-      start = this$1.storeCurrentPos()
-      prop.method = false
-      prop.shorthand = false
-      isGenerator = this$1.eat(__acorn.tokTypes.star)
+      start = this$1.storeCurrentPos();
+      prop.method = false;
+      prop.shorthand = false;
+      isGenerator = this$1.eat(acorn.tokTypes.star);
     }
-    this$1.parsePropertyName(prop)
-    if (!prop.computed &&
-        prop.key.type === "Identifier" && prop.key.name === "async" && this$1.tok.type !== __acorn.tokTypes.parenL &&
-        this$1.tok.type !== __acorn.tokTypes.colon && !this$1.canInsertSemicolon()) {
-      this$1.parsePropertyName(prop)
-      isAsync = true
+    this$1.parsePropertyName(prop);
+    if (this$1.toks.isAsyncProp(prop)) {
+      isAsync = true;
+      isGenerator = this$1.options.ecmaVersion >= 9 && this$1.eat(acorn.tokTypes.star);
+      this$1.parsePropertyName(prop);
     } else {
-      isAsync = false
+      isAsync = false;
     }
-    if (isDummy(prop.key)) { if (isDummy(this$1.parseMaybeAssign())) this$1.next(); this$1.eat(__acorn.tokTypes.comma); continue }
-    if (this$1.eat(__acorn.tokTypes.colon)) {
-      prop.kind = "init"
-      prop.value = this$1.parseMaybeAssign()
-    } else if (this$1.options.ecmaVersion >= 6 && (this$1.tok.type === __acorn.tokTypes.parenL || this$1.tok.type === __acorn.tokTypes.braceL)) {
-      prop.kind = "init"
-      prop.method = true
-      prop.value = this$1.parseMethod(isGenerator, isAsync)
+    if (isDummy(prop.key)) { if (isDummy(this$1.parseMaybeAssign())) { this$1.next(); } this$1.eat(acorn.tokTypes.comma); continue }
+    if (this$1.eat(acorn.tokTypes.colon)) {
+      prop.kind = "init";
+      prop.value = this$1.parseMaybeAssign();
+    } else if (this$1.options.ecmaVersion >= 6 && (this$1.tok.type === acorn.tokTypes.parenL || this$1.tok.type === acorn.tokTypes.braceL)) {
+      prop.kind = "init";
+      prop.method = true;
+      prop.value = this$1.parseMethod(isGenerator, isAsync);
     } else if (this$1.options.ecmaVersion >= 5 && prop.key.type === "Identifier" &&
                !prop.computed && (prop.key.name === "get" || prop.key.name === "set") &&
-               (this$1.tok.type != __acorn.tokTypes.comma && this$1.tok.type != __acorn.tokTypes.braceR)) {
-      prop.kind = prop.key.name
-      this$1.parsePropertyName(prop)
-      prop.value = this$1.parseMethod(false)
+               (this$1.tok.type !== acorn.tokTypes.comma && this$1.tok.type !== acorn.tokTypes.braceR && this$1.tok.type !== acorn.tokTypes.eq)) {
+      prop.kind = prop.key.name;
+      this$1.parsePropertyName(prop);
+      prop.value = this$1.parseMethod(false);
     } else {
-      prop.kind = "init"
+      prop.kind = "init";
       if (this$1.options.ecmaVersion >= 6) {
-        if (this$1.eat(__acorn.tokTypes.eq)) {
-          var assign = this$1.startNodeAt(start)
-          assign.operator = "="
-          assign.left = prop.key
-          assign.right = this$1.parseMaybeAssign()
-          prop.value = this$1.finishNode(assign, "AssignmentExpression")
+        if (this$1.eat(acorn.tokTypes.eq)) {
+          var assign = this$1.startNodeAt(start);
+          assign.operator = "=";
+          assign.left = prop.key;
+          assign.right = this$1.parseMaybeAssign();
+          prop.value = this$1.finishNode(assign, "AssignmentExpression");
         } else {
-          prop.value = prop.key
+          prop.value = prop.key;
         }
       } else {
-        prop.value = this$1.dummyIdent()
+        prop.value = this$1.dummyIdent();
       }
-      prop.shorthand = true
+      prop.shorthand = true;
     }
-    node.properties.push(this$1.finishNode(prop, "Property"))
-    this$1.eat(__acorn.tokTypes.comma)
+    node.properties.push(this$1.finishNode(prop, "Property"));
+    this$1.eat(acorn.tokTypes.comma);
   }
-  this.popCx()
-  if (!this.eat(__acorn.tokTypes.braceR)) {
+  this.popCx();
+  if (!this.eat(acorn.tokTypes.braceR)) {
     // If there is no closing brace, make the node span to the start
     // of the next token (this is useful for Tern)
-    this.last.end = this.tok.start
-    if (this.options.locations) this.last.loc.end = this.tok.loc.start
+    this.last.end = this.tok.start;
+    if (this.options.locations) { this.last.loc.end = this.tok.loc.start; }
   }
   return this.finishNode(node, "ObjectExpression")
-}
+};
 
 lp$2.parsePropertyName = function(prop) {
   if (this.options.ecmaVersion >= 6) {
-    if (this.eat(__acorn.tokTypes.bracketL)) {
-      prop.computed = true
-      prop.key = this.parseExpression()
-      this.expect(__acorn.tokTypes.bracketR)
+    if (this.eat(acorn.tokTypes.bracketL)) {
+      prop.computed = true;
+      prop.key = this.parseExpression();
+      this.expect(acorn.tokTypes.bracketR);
       return
     } else {
-      prop.computed = false
+      prop.computed = false;
     }
   }
-  var key = (this.tok.type === __acorn.tokTypes.num || this.tok.type === __acorn.tokTypes.string) ? this.parseExprAtom() : this.parseIdent()
-  prop.key = key || this.dummyIdent()
-}
+  var key = (this.tok.type === acorn.tokTypes.num || this.tok.type === acorn.tokTypes.string) ? this.parseExprAtom() : this.parseIdent();
+  prop.key = key || this.dummyIdent();
+};
 
 lp$2.parsePropertyAccessor = function() {
-  if (this.tok.type === __acorn.tokTypes.name || this.tok.type.keyword) return this.parseIdent()
-}
+  if (this.tok.type === acorn.tokTypes.name || this.tok.type.keyword) { return this.parseIdent() }
+};
 
 lp$2.parseIdent = function() {
-  var name = this.tok.type === __acorn.tokTypes.name ? this.tok.value : this.tok.type.keyword
-  if (!name) return this.dummyIdent()
-  var node = this.startNode()
-  this.next()
-  node.name = name
+  var name = this.tok.type === acorn.tokTypes.name ? this.tok.value : this.tok.type.keyword;
+  if (!name) { return this.dummyIdent() }
+  var node = this.startNode();
+  this.next();
+  node.name = name;
   return this.finishNode(node, "Identifier")
-}
+};
 
 lp$2.initFunction = function(node) {
-  node.id = null
-  node.params = []
+  node.id = null;
+  node.params = [];
   if (this.options.ecmaVersion >= 6) {
-    node.generator = false
-    node.expression = false
+    node.generator = false;
+    node.expression = false;
   }
   if (this.options.ecmaVersion >= 8)
-    node.async = false
-}
+    { node.async = false; }
+};
 
 // Convert existing expression atom to assignable pattern
 // if possible.
@@ -1222,117 +1263,135 @@
 lp$2.toAssignable = function(node, binding) {
   var this$1 = this;
 
-  if (!node || node.type == "Identifier" || (node.type == "MemberExpression" && !binding)) {
+  if (!node || node.type === "Identifier" || (node.type === "MemberExpression" && !binding)) {
     // Okay
-  } else if (node.type == "ParenthesizedExpression") {
-    node.expression = this.toAssignable(node.expression, binding)
+  } else if (node.type === "ParenthesizedExpression") {
+    this.toAssignable(node.expression, binding);
   } else if (this.options.ecmaVersion < 6) {
     return this.dummyIdent()
-  } else if (node.type == "ObjectExpression") {
-    node.type = "ObjectPattern"
-    var props = node.properties
-    for (var i = 0; i < props.length; i++)
-      props[i].value = this$1.toAssignable(props[i].value, binding)
-  } else if (node.type == "ArrayExpression") {
-    node.type = "ArrayPattern"
-    this.toAssignableList(node.elements, binding)
-  } else if (node.type == "SpreadElement") {
-    node.type = "RestElement"
-    node.argument = this.toAssignable(node.argument, binding)
-  } else if (node.type == "AssignmentExpression") {
-    node.type = "AssignmentPattern"
-    delete node.operator
+  } else if (node.type === "ObjectExpression") {
+    node.type = "ObjectPattern";
+    for (var i = 0, list = node.properties; i < list.length; i += 1)
+      {
+      var prop = list[i];
+
+      this$1.toAssignable(prop, binding);
+    }
+  } else if (node.type === "ArrayExpression") {
+    node.type = "ArrayPattern";
+    this.toAssignableList(node.elements, binding);
+  } else if (node.type === "Property") {
+    this.toAssignable(node.value, binding);
+  } else if (node.type === "SpreadElement") {
+    node.type = "RestElement";
+    this.toAssignable(node.argument, binding);
+  } else if (node.type === "AssignmentExpression") {
+    node.type = "AssignmentPattern";
+    delete node.operator;
   } else {
     return this.dummyIdent()
   }
   return node
-}
+};
 
 lp$2.toAssignableList = function(exprList, binding) {
   var this$1 = this;
 
-  for (var i = 0; i < exprList.length; i++)
-    exprList[i] = this$1.toAssignable(exprList[i], binding)
+  for (var i = 0, list = exprList; i < list.length; i += 1)
+    {
+    var expr = list[i];
+
+    this$1.toAssignable(expr, binding);
+  }
   return exprList
-}
+};
 
 lp$2.parseFunctionParams = function(params) {
-  params = this.parseExprList(__acorn.tokTypes.parenR)
+  params = this.parseExprList(acorn.tokTypes.parenR);
   return this.toAssignableList(params, true)
-}
+};
 
 lp$2.parseMethod = function(isGenerator, isAsync) {
-  var node = this.startNode(), oldInAsync = this.inAsync
-  this.initFunction(node)
+  var node = this.startNode(), oldInAsync = this.inAsync, oldInFunction = this.inFunction;
+  this.initFunction(node);
   if (this.options.ecmaVersion >= 6)
-    node.generator = !!isGenerator
+    { node.generator = !!isGenerator; }
   if (this.options.ecmaVersion >= 8)
-    node.async = !!isAsync
-  this.inAsync = node.async
-  node.params = this.parseFunctionParams()
-  node.expression = this.options.ecmaVersion >= 6 && this.tok.type !== __acorn.tokTypes.braceL
-  node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock()
-  this.inAsync = oldInAsync
+    { node.async = !!isAsync; }
+  this.inAsync = node.async;
+  this.inFunction = true;
+  node.params = this.parseFunctionParams();
+  node.body = this.parseBlock();
+  this.toks.adaptDirectivePrologue(node.body.body);
+  this.inAsync = oldInAsync;
+  this.inFunction = oldInFunction;
   return this.finishNode(node, "FunctionExpression")
-}
+};
 
 lp$2.parseArrowExpression = function(node, params, isAsync) {
-  var oldInAsync = this.inAsync
-  this.initFunction(node)
+  var oldInAsync = this.inAsync, oldInFunction = this.inFunction;
+  this.initFunction(node);
   if (this.options.ecmaVersion >= 8)
-    node.async = !!isAsync
-  this.inAsync = node.async
-  node.params = this.toAssignableList(params, true)
-  node.expression = this.tok.type !== __acorn.tokTypes.braceL
-  node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock()
-  this.inAsync = oldInAsync
+    { node.async = !!isAsync; }
+  this.inAsync = node.async;
+  this.inFunction = true;
+  node.params = this.toAssignableList(params, true);
+  node.expression = this.tok.type !== acorn.tokTypes.braceL;
+  if (node.expression) {
+    node.body = this.parseMaybeAssign();
+  } else {
+    node.body = this.parseBlock();
+    this.toks.adaptDirectivePrologue(node.body.body);
+  }
+  this.inAsync = oldInAsync;
+  this.inFunction = oldInFunction;
   return this.finishNode(node, "ArrowFunctionExpression")
-}
+};
 
 lp$2.parseExprList = function(close, allowEmpty) {
   var this$1 = this;
 
-  this.pushCx()
-  var indent = this.curIndent, line = this.curLineStart, elts = []
-  this.next() // Opening bracket
+  this.pushCx();
+  var indent = this.curIndent, line = this.curLineStart, elts = [];
+  this.next(); // Opening bracket
   while (!this.closes(close, indent + 1, line)) {
-    if (this$1.eat(__acorn.tokTypes.comma)) {
-      elts.push(allowEmpty ? null : this$1.dummyIdent())
+    if (this$1.eat(acorn.tokTypes.comma)) {
+      elts.push(allowEmpty ? null : this$1.dummyIdent());
       continue
     }
-    var elt = this$1.parseMaybeAssign()
+    var elt = this$1.parseMaybeAssign();
     if (isDummy(elt)) {
-      if (this$1.closes(close, indent, line)) break
-      this$1.next()
+      if (this$1.closes(close, indent, line)) { break }
+      this$1.next();
     } else {
-      elts.push(elt)
+      elts.push(elt);
     }
-    this$1.eat(__acorn.tokTypes.comma)
+    this$1.eat(acorn.tokTypes.comma);
   }
-  this.popCx()
+  this.popCx();
   if (!this.eat(close)) {
     // If there is no closing brace, make the node span to the start
     // of the next token (this is useful for Tern)
-    this.last.end = this.tok.start
-    if (this.options.locations) this.last.loc.end = this.tok.loc.start
+    this.last.end = this.tok.start;
+    if (this.options.locations) { this.last.loc.end = this.tok.loc.start; }
   }
   return elts
-}
+};
 
 lp$2.parseAwait = function() {
-  var node = this.startNode()
-  this.next()
-  node.argument = this.parseMaybeUnary()
+  var node = this.startNode();
+  this.next();
+  node.argument = this.parseMaybeUnary();
   return this.finishNode(node, "AwaitExpression")
-}
+};
 
 // Acorn: Loose parser
 //
-// This module provides an alternative parser (`parse_dammit`) that
-// exposes that same interface as `parse`, but will try to parse
-// anything as JavaScript, repairing syntax error the best it can.
-// There are circumstances in which it will raise an error and give
-// up, but they are very rare. The resulting AST will be a mostly
+// This module provides an alternative parser that exposes that same
+// interface as the main module's `parse` function, but will try to
+// parse anything as JavaScript, repairing syntax error the best it
+// can. There are circumstances in which it will raise an error and
+// give up, but they are very rare. The resulting AST will be a mostly
 // valid JavaScript AST (as per the [Mozilla parser API][api], except
 // that:
 //
@@ -1347,9 +1406,9 @@
 // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
 //
 // The expected use for this is to *first* try `acorn.parse`, and only
-// if that fails switch to `parse_dammit`. The loose parser might
-// parse badly indented code incorrectly, so **don't** use it as
-// your default parser.
+// if that fails switch to the loose parser. The loose parser might
+// parse badly indented code incorrectly, so **don't** use it as your
+// default parser.
 //
 // Quite a lot of acorn.js is duplicated here. The alternative was to
 // add a *lot* of extra cruft to that file, making it less readable
@@ -1357,20 +1416,14 @@
 // invasive changes and simplifications without creating a complicated
 // tangle.
 
-__acorn.defaultOptions.tabSize = 4
+acorn.defaultOptions.tabSize = 4;
 
-// eslint-disable-next-line camelcase
-function parse_dammit(input, options) {
-  var p = new LooseParser(input, options)
-  p.next()
-  return p.parseTopLevel()
+function parse(input, options) {
+  return LooseParser.parse(input, options)
 }
 
-__acorn.addLooseExports(parse_dammit, LooseParser, pluginsLoose)
-
-exports.parse_dammit = parse_dammit;
+exports.parse = parse;
 exports.LooseParser = LooseParser;
-exports.pluginsLoose = pluginsLoose;
 
 Object.defineProperty(exports, '__esModule', { value: true });
 
diff --git a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
index 6bdb1ba..96a85b3 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
+++ b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -302,8 +302,7 @@
   ExecutionContext* execution_context = ExecutionContext::From(script_state);
   Document* document = ToDocument(execution_context);
 
-  if (!document->GetFrame() ||
-      !document->GetFrame()->DeprecatedIsFeatureEnabled(
+  if (!document->IsFeatureEnabled(
           mojom::FeaturePolicyFeature::kEncryptedMedia)) {
     UseCounter::Count(document,
                       WebFeature::kEncryptedMediaDisabledByFeaturePolicy);
diff --git a/third_party/blink/renderer/modules/filesystem/README.md b/third_party/blink/renderer/modules/filesystem/README.md
new file mode 100644
index 0000000..6e3f3df
--- /dev/null
+++ b/third_party/blink/renderer/modules/filesystem/README.md
@@ -0,0 +1,74 @@
+# FileSystem API
+
+This directory contains the renderer side implementation of various filesystem
+related APIs.
+
+## Related directories
+
+[`//storage/browser/fileapi/`](../../../storage/browser/fileapi) contains part
+of the browser side implementation, while
+[`//content/browser/fileapi/`](../../../content/browser/fileapi) contains the
+rest of the browser side implementation and
+[`blink/public/mojom/filesystem`](../../../third_party/blink/public/mojom/filesystem)
+contains the mojom interfaces for these APIs.
+
+## APIs In this directory
+
+### File and Directory Entries API
+
+First of all this directory contains the implementation of the
+[Entries API](https://wicg.github.io/entries-api). This API consists of
+types to expose read-only access to file and directory entries to the web,
+primarily used by drag-and-drop and `<input type=file>`. Our implementation
+doesn't match the interface names of the spec, but otherwise should be pretty
+close to the spec.
+
+TODO(mek): More details
+
+### File API: Directories and FileSystem
+
+Secondly this directory contains the implementation of something similar to the
+deprecated [w3c file-system-api](https://www.w3.org/TR/2012/WD-file-system-api-20120417/).
+This API is very similar to the previous Entries API, but it also adds support
+for writing and modifying to files and directories, as well as a way to get
+access to a origin scoped sandboxed filesystem.
+
+TODO(mek): More details
+
+### Writable Files
+
+Finally this directory contains the implementation of the new and still under
+development [Writable Files API](https://github.com/WICG/writable-files/blob/master/EXPLAINER.md).
+This API is mostly implemented on top of the same backend as the previous two
+APIs, but hopes to eventually replace both of those, while also adding new
+functionality.
+
+It consists of the following parts:
+
+ * `FileSystemBaseHandle`, `FileSystemFileHandle` and `FileSystemDirectoryHandle`:
+   these interfaces mimic the old `Entry` interfaces (and inherit from `EntryBase`
+   to share as much of the implementation as possible), but expose a more modern
+   promisified API.
+
+ * `getSystemDirectory`: An entry point (exposed via `FileSystemDirectoryHandle`)
+   that today only gives access to the same sandboxed filesystem as what was
+   available through the old API. In the future this could get extended to add
+   support for other directories as well.
+
+ * `FileSystemWriter`: a more modern API with similar functionality to the
+   old `FileWriter` API. The implementation of this actually does make use of
+   a different mojom interface than the old API. But since the functionality is
+   mostly the same, hopefully we will be able to migrate the old implementation
+   to the new mojom API as well.
+
+ * `chooseFileSystemEntries`: An entry point, currently on `window`, that lets
+   a website pop-up a file picker, prompting the user to select one or more
+   files or directories, to which the website than gets access.
+
+Since the `Handle` interfaces are based on the implementation of the `Entry`
+interfaces, internally and across IPC these are still represented by
+`filesystem://` URLs. Hopefully in the future we will be able to change this and
+turn it into a more capabilities based API (where having a mojo handle gives you
+access to specific files or directories), as with the current implementation it
+is very hard to properly support transferring handles to other processes via
+postMessage (which is something we do want to support in the future).
diff --git a/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl b/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl
new file mode 100644
index 0000000..8e50e6f
--- /dev/null
+++ b/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl
@@ -0,0 +1,11 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md
+enum ChooseFileSystemEntriesType { "openFile", "saveFile", "openDirectory" };
+
+dictionary ChooseFileSystemEntriesOptions {
+    ChooseFileSystemEntriesType type = "openFile";
+    boolean multiple = false;
+};
diff --git a/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc b/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc
index f3bcda2..049e3dd 100644
--- a/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc
+++ b/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc
@@ -135,7 +135,8 @@
 
 ScriptPromise DOMWindowFileSystem::chooseFileSystemEntries(
     ScriptState* script_state,
-    LocalDOMWindow& window) {
+    LocalDOMWindow& window,
+    const ChooseFileSystemEntriesOptions& options) {
   if (!window.IsCurrentlyDisplayedInFrame()) {
     return ScriptPromise::RejectWithDOMException(
         script_state, DOMException::Create(DOMExceptionCode::kAbortError));
@@ -157,7 +158,7 @@
 
   auto* resolver = ScriptPromiseResolver::Create(script_state);
   ScriptPromise result = resolver->Promise();
-  LocalFileSystem::From(*document)->ChooseEntry(resolver);
+  LocalFileSystem::From(*document)->ChooseEntry(resolver, options);
   return result;
 }
 
diff --git a/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h b/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h
index a12e3be..8d4264d 100644
--- a/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h
+++ b/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h
@@ -32,6 +32,7 @@
 
 namespace blink {
 
+class ChooseFileSystemEntriesOptions;
 class LocalDOMWindow;
 class ScriptPromise;
 class ScriptState;
@@ -60,7 +61,10 @@
     kPersistent,
   };
 
-  static ScriptPromise chooseFileSystemEntries(ScriptState*, LocalDOMWindow&);
+  static ScriptPromise chooseFileSystemEntries(
+      ScriptState*,
+      LocalDOMWindow&,
+      const ChooseFileSystemEntriesOptions&);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
index ec80085..1a26eeb 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
+++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
@@ -436,18 +436,20 @@
 }
 
 void FileSystemDispatcher::ChooseEntry(
+    mojom::blink::ChooseFileSystemEntryType type,
     std::unique_ptr<ChooseEntryCallbacks> callbacks) {
-  GetFileSystemManager().ChooseEntry(WTF::Bind(
-      [](std::unique_ptr<ChooseEntryCallbacks> callbacks,
-         base::File::Error result,
-         Vector<mojom::blink::FileSystemEntryPtr> entries) {
-        if (result != base::File::FILE_OK) {
-          callbacks->OnError(result);
-        } else {
-          callbacks->OnSuccess(std::move(entries));
-        }
-      },
-      std::move(callbacks)));
+  GetFileSystemManager().ChooseEntry(
+      type, WTF::Bind(
+                [](std::unique_ptr<ChooseEntryCallbacks> callbacks,
+                   base::File::Error result,
+                   Vector<mojom::blink::FileSystemEntryPtr> entries) {
+                  if (result != base::File::FILE_OK) {
+                    callbacks->OnError(result);
+                  } else {
+                    callbacks->OnSuccess(std::move(entries));
+                  }
+                },
+                std::move(callbacks)));
 }
 
 mojom::blink::FileSystemManager& FileSystemDispatcher::GetFileSystemManager() {
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
index d8a899a..bbee2b8 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
+++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
@@ -143,7 +143,8 @@
 
   using ChooseEntryCallbacks =
       WebCallbacks<Vector<mojom::blink::FileSystemEntryPtr>, base::File::Error>;
-  void ChooseEntry(std::unique_ptr<ChooseEntryCallbacks> callbacks);
+  void ChooseEntry(mojom::blink::ChooseFileSystemEntryType,
+                   std::unique_ptr<ChooseEntryCallbacks> callbacks);
 
  private:
   class WriteListener;
diff --git a/third_party/blink/renderer/modules/filesystem/local_file_system.cc b/third_party/blink/renderer/modules/filesystem/local_file_system.cc
index 29c34b3..1c2b1ed3 100644
--- a/third_party/blink/renderer/modules/filesystem/local_file_system.cc
+++ b/third_party/blink/renderer/modules/filesystem/local_file_system.cc
@@ -43,6 +43,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.h"
 #include "third_party/blink/renderer/modules/filesystem/directory_entry.h"
 #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h"
 #include "third_party/blink/renderer/modules/filesystem/file_system_client.h"
@@ -119,12 +120,13 @@
     : public WebCallbacks<Vector<mojom::blink::FileSystemEntryPtr>,
                           base::File::Error> {
  public:
-  ChooseEntryCallbacks(ScriptPromiseResolver* resolver, bool return_multiple)
-      : resolver_(resolver), return_multiple_(return_multiple) {}
+  ChooseEntryCallbacks(ScriptPromiseResolver* resolver,
+                       const ChooseFileSystemEntriesOptions& options)
+      : resolver_(resolver), options_(options) {}
 
   void OnSuccess(Vector<mojom::blink::FileSystemEntryPtr> entries) override {
     ScriptState::Scope scope(resolver_->GetScriptState());
-    if (return_multiple_) {
+    if (options_.multiple()) {
       Vector<ScriptPromise> result;
       result.ReserveInitialCapacity(entries.size());
       for (const auto& entry : entries)
@@ -151,19 +153,43 @@
         resolver_->GetExecutionContext(), entry->file_system_id);
     // TODO(mek): Try to create handle directly rather than having to do more
     // IPCs to get the actual entries.
-    fs->GetFile(fs->root(), entry->base_name, FileSystemFlags(),
-                new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver),
-                new PromiseErrorCallback(new_resolver));
+    if (options_.type() == "openDirectory") {
+      fs->GetDirectory(
+          fs->root(), entry->base_name, FileSystemFlags(),
+          new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver),
+          new PromiseErrorCallback(new_resolver));
+    } else {
+      fs->GetFile(fs->root(), entry->base_name, FileSystemFlags(),
+                  new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver),
+                  new PromiseErrorCallback(new_resolver));
+    }
     return result;
   }
 
   Persistent<ScriptPromiseResolver> resolver_;
-  bool return_multiple_;
+  ChooseFileSystemEntriesOptions options_;
 };
 
+mojom::blink::ChooseFileSystemEntryType ConvertChooserType(const String& input,
+                                                           bool multiple) {
+  if (input == "openFile") {
+    return multiple
+               ? mojom::blink::ChooseFileSystemEntryType::kOpenMultipleFiles
+               : mojom::blink::ChooseFileSystemEntryType::kOpenFile;
+  }
+  if (input == "saveFile")
+    return mojom::blink::ChooseFileSystemEntryType::kSaveFile;
+  if (input == "openDirectory")
+    return mojom::blink::ChooseFileSystemEntryType::kOpenDirectory;
+  NOTREACHED();
+  return mojom::blink::ChooseFileSystemEntryType::kOpenFile;
+}
+
 }  // namespace
 
-void LocalFileSystem::ChooseEntry(ScriptPromiseResolver* resolver) {
+void LocalFileSystem::ChooseEntry(
+    ScriptPromiseResolver* resolver,
+    const ChooseFileSystemEntriesOptions& options) {
   if (!base::FeatureList::IsEnabled(blink::features::kWritableFilesAPI)) {
     resolver->Reject(
         FileError::CreateDOMException(base::File::FILE_ERROR_ABORT));
@@ -171,7 +197,8 @@
   }
 
   FileSystemDispatcher::From(resolver->GetExecutionContext())
-      .ChooseEntry(std::make_unique<ChooseEntryCallbacks>(resolver, false));
+      .ChooseEntry(ConvertChooserType(options.type(), options.multiple()),
+                   std::make_unique<ChooseEntryCallbacks>(resolver, options));
 }
 
 void LocalFileSystem::RequestFileSystemAccessInternal(
diff --git a/third_party/blink/renderer/modules/filesystem/local_file_system.h b/third_party/blink/renderer/modules/filesystem/local_file_system.h
index b137d0e9..5a4a6fa 100644
--- a/third_party/blink/renderer/modules/filesystem/local_file_system.h
+++ b/third_party/blink/renderer/modules/filesystem/local_file_system.h
@@ -45,6 +45,7 @@
 
 class AsyncFileSystemCallbacks;
 class CallbackWrapper;
+class ChooseFileSystemEntriesOptions;
 class FileSystemClient;
 class ExecutionContext;
 class KURL;
@@ -76,7 +77,8 @@
                          std::unique_ptr<AsyncFileSystemCallbacks>,
                          SynchronousType sync_type);
 
-  void ChooseEntry(ScriptPromiseResolver*);
+  void ChooseEntry(ScriptPromiseResolver*,
+                   const ChooseFileSystemEntriesOptions& options);
 
   FileSystemClient& Client() const { return *client_; }
 
diff --git a/third_party/blink/renderer/modules/filesystem/window_file_system.idl b/third_party/blink/renderer/modules/filesystem/window_file_system.idl
index 3259df9f..ed10797d 100644
--- a/third_party/blink/renderer/modules/filesystem/window_file_system.idl
+++ b/third_party/blink/renderer/modules/filesystem/window_file_system.idl
@@ -41,5 +41,6 @@
     // https://github.com/WICG/writable-files/blob/master/EXPLAINER.md
     // TODO(crbug.com/878581): This needs some kind of options dictionary.
     [RuntimeEnabled=WritableFiles, CallWith=ScriptState, SecureContext]
-    Promise<(FileSystemBaseHandle or sequence<FileSystemBaseHandle>)> chooseFileSystemEntries();
+    Promise<(FileSystemBaseHandle or sequence<FileSystemBaseHandle>)>
+        chooseFileSystemEntries(optional ChooseFileSystemEntriesOptions options);
 };
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation.cc b/third_party/blink/renderer/modules/geolocation/geolocation.cc
index c0eda1e..d170d78 100644
--- a/third_party/blink/renderer/modules/geolocation/geolocation.cc
+++ b/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -224,7 +224,7 @@
     return;
   }
 
-  if (!GetFrame()->DeprecatedIsFeatureEnabled(
+  if (!GetDocument()->IsFeatureEnabled(
           mojom::FeaturePolicyFeature::kGeolocation,
           ReportOptions::kReportOnFailure)) {
     UseCounter::Count(GetDocument(),
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
index 09a493d..051df45 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -492,17 +492,15 @@
 
     // Feature policy deprecation messages.
     if (Audio()) {
-      if (!document->GetFrame()->DeprecatedIsFeatureEnabled(
-              mojom::FeaturePolicyFeature::kMicrophone,
-              ReportOptions::kReportOnFailure)) {
+      if (!document->IsFeatureEnabled(mojom::FeaturePolicyFeature::kMicrophone,
+                                      ReportOptions::kReportOnFailure)) {
         UseCounter::Count(
             document, WebFeature::kMicrophoneDisabledByFeaturePolicyEstimate);
       }
     }
     if (Video()) {
-      if (!document->GetFrame()->DeprecatedIsFeatureEnabled(
-              mojom::FeaturePolicyFeature::kCamera,
-              ReportOptions::kReportOnFailure)) {
+      if (!document->IsFeatureEnabled(mojom::FeaturePolicyFeature::kCamera,
+                                      ReportOptions::kReportOnFailure)) {
         UseCounter::Count(document,
                           WebFeature::kCameraDisabledByFeaturePolicyEstimate);
       }
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 928eb865..63c25f79 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -524,6 +524,7 @@
           "encryptedmedia/media_key_system_configuration.idl",
           "encryptedmedia/media_key_system_media_capability.idl",
           "eventsource/event_source_init.idl",
+          "filesystem/choose_file_system_entries_options.idl",
           "filesystem/file_system_directory_iterator_entry.idl",
           "filesystem/file_system_flags.idl",
           "filesystem/file_system_get_directory_options.idl",
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index ed942e0e..f6cb9237 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -54,7 +54,7 @@
   // If document is not allowed to use the policy-controlled feature named
   // "picture-in-picture", return kDisabledByFeaturePolicy status.
   if (RuntimeEnabledFeatures::PictureInPictureAPIEnabled() &&
-      !frame->DeprecatedIsFeatureEnabled(
+      !GetSupplementable()->IsFeatureEnabled(
           blink::mojom::FeaturePolicyFeature::kPictureInPicture)) {
     return Status::kDisabledByFeaturePolicy;
   }
diff --git a/third_party/blink/renderer/modules/sensor/sensor.cc b/third_party/blink/renderer/modules/sensor/sensor.cc
index 2c96cf8..1a7a8a9c 100644
--- a/third_party/blink/renderer/modules/sensor/sensor.cc
+++ b/third_party/blink/renderer/modules/sensor/sensor.cc
@@ -22,11 +22,11 @@
 namespace {
 const double kWaitingIntervalThreshold = 0.01;
 
-bool AreFeaturesEnabled(LocalFrame* frame,
+bool AreFeaturesEnabled(Document* document,
                         const Vector<mojom::FeaturePolicyFeature>& features) {
   return std::all_of(features.begin(), features.end(),
-                     [frame](mojom::FeaturePolicyFeature feature) {
-                       return frame->DeprecatedIsFeatureEnabled(feature);
+                     [document](mojom::FeaturePolicyFeature feature) {
+                       return document->IsFeatureEnabled(feature);
                      });
 }
 
@@ -45,9 +45,9 @@
   // [SecureContext] in idl.
   DCHECK(execution_context->IsSecureContext());
   DCHECK(!features.IsEmpty());
-  LocalFrame* frame = ToDocument(execution_context)->GetFrame();
+  Document* document = ToDocument(execution_context);
 
-  if (!frame || !AreFeaturesEnabled(frame, features)) {
+  if (!AreFeaturesEnabled(document, features)) {
     exception_state.ThrowSecurityError(
         "Access to sensor features is disallowed by feature policy");
     return;
diff --git a/third_party/blink/renderer/modules/vr/navigator_vr.cc b/third_party/blink/renderer/modules/vr/navigator_vr.cc
index 01dae7eb..02bfb83c 100644
--- a/third_party/blink/renderer/modules/vr/navigator_vr.cc
+++ b/third_party/blink/renderer/modules/vr/navigator_vr.cc
@@ -144,8 +144,8 @@
         script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
                                            kNotAssociatedWithDocumentMessage));
   }
-  if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr,
-                                         ReportOptions::kReportOnFailure)) {
+  if (!GetDocument()->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr,
+                                       ReportOptions::kReportOnFailure)) {
     return ScriptPromise::RejectWithDOMException(
         script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
                                            kFeaturePolicyBlockedMessage));
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
index 3c9f39d..335177b 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
@@ -119,9 +119,6 @@
   }
 
   GetDeferredTaskHandler().ContextWillBeDestroyed();
-  DCHECK(!active_source_nodes_.size());
-  DCHECK(!is_resolving_resume_promises_);
-  DCHECK(!resume_resolvers_.size());
 }
 
 void BaseAudioContext::Initialize() {
@@ -179,6 +176,10 @@
   listener_->WaitForHRTFDatabaseLoaderThreadCompletion();
 
   Clear();
+
+  DCHECK(!is_resolving_resume_promises_);
+  DCHECK_EQ(resume_resolvers_.size(), 0u);
+  DCHECK_EQ(active_source_nodes_.size(), 0u);
 }
 
 void BaseAudioContext::ContextDestroyed(ExecutionContext*) {
diff --git a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
index 21ff4de..0b9d4e2b 100644
--- a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
+++ b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
@@ -102,9 +102,8 @@
   UseCounter::CountCrossOriginIframe(
       document, WebFeature::kRequestMIDIAccessIframe_ObscuredByFootprinting);
 
-  if (!document.GetFrame()->DeprecatedIsFeatureEnabled(
-          mojom::FeaturePolicyFeature::kMidiFeature,
-          ReportOptions::kReportOnFailure)) {
+  if (!document.IsFeatureEnabled(mojom::FeaturePolicyFeature::kMidiFeature,
+                                 ReportOptions::kReportOnFailure)) {
     UseCounter::Count(document, WebFeature::kMidiDisabledByFeaturePolicy);
     document.AddConsoleMessage(ConsoleMessage::Create(
         kJSMessageSource, kWarningMessageLevel, kFeaturePolicyConsoleWarning));
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc
index 8cb4dbb..6f6fd97 100644
--- a/third_party/blink/renderer/modules/xr/xr.cc
+++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -73,9 +73,10 @@
     did_log_requestDevice_ = true;
   }
 
-  if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr,
-                                         ReportOptions::kReportOnFailure)) {
-    // Only allow the call to be made if the appropraite feature policy is in
+  if (!frame->GetDocument()->IsFeatureEnabled(
+          mojom::FeaturePolicyFeature::kWebVr,
+          ReportOptions::kReportOnFailure)) {
+    // Only allow the call to be made if the appropriate feature policy is in
     // place.
     return ScriptPromise::RejectWithDOMException(
         script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index ac1e91f..8b05ed3 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1228,11 +1228,6 @@
     "plugins/plugin_data.h",
     "plugins/plugin_script_forbidden_scope.cc",
     "plugins/plugin_script_forbidden_scope.h",
-    "pod_arena.h",
-    "pod_free_list_arena.h",
-    "pod_interval.h",
-    "pod_interval_tree.h",
-    "pod_red_black_tree.h",
     "prerender.cc",
     "prerender.h",
     "prerender_client.h",
@@ -1360,8 +1355,6 @@
     "transforms/transformation_matrix.h",
     "transforms/translate_transform_operation.cc",
     "transforms/translate_transform_operation.h",
-    "ukm_time_aggregator.cc",
-    "ukm_time_aggregator.h",
     "uuid.cc",
     "uuid.h",
     "waitable_event.cc",
@@ -1776,14 +1769,7 @@
     "mojo/kurl_security_origin_test.cc",
     "mojo/string16_mojom_traits_test.cc",
     "plugins/plugin_data_test.cc",
-    "pod_arena_test.cc",
-    "pod_free_list_arena_test.cc",
-    "pod_interval_tree_test.cc",
-    "pod_red_black_tree_test.cc",
     "shared_buffer_test.cc",
-    "testing/arena_test_helpers.h",
-    "testing/tree_test_helpers.cc",
-    "testing/tree_test_helpers.h",
     "text/bidi_resolver_test.cc",
     "text/bidi_test_harness.h",
     "text/capitalize_test.cc",
@@ -1807,7 +1793,6 @@
     "transforms/rotation_test.cc",
     "transforms/transform_operations_test.cc",
     "transforms/transformation_matrix_test.cc",
-    "ukm_time_aggregator_test.cc",
     "uuid_test.cc",
     "web_icon_sizes_parser_test.cc",
     "web_screen_info_test.cc",
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index ec6ee21b..19b7b58 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -1150,13 +1150,13 @@
   Vector<Glyph, 256> glyphs(num_glyphs);
   for (unsigned i = 0; i < num_glyphs; i++)
     glyphs[i] = run.glyph_data_[i].glyph;
-  Vector<FloatRect, 256> bounds_list(num_glyphs);
+  Vector<SkRect, 256> bounds_list(num_glyphs);
   current_font_data.BoundsForGlyphs(glyphs, &bounds_list);
 
   GlyphBoundsAccumulator bounds(width_);
   for (unsigned i = 0; i < num_glyphs; i++) {
     const HarfBuzzRunGlyphData& glyph_data = run.glyph_data_[i];
-    bounds.Unite<is_horizontal_run>(glyph_data, bounds_list[i]);
+    bounds.Unite<is_horizontal_run>(glyph_data, FloatRect(bounds_list[i]));
     bounds.origin += glyph_data.advance;
   }
 #endif
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
index 811beb0..520dad1 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.cc
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
@@ -354,18 +354,15 @@
   return FloatRect(bounds);
 }
 
-void SimpleFontData::BoundsForGlyphs(const Vector<Glyph, 256> glyphs,
-                                     Vector<FloatRect, 256>* bounds) const {
+void SimpleFontData::BoundsForGlyphs(const Vector<Glyph, 256>& glyphs,
+                                     Vector<SkRect, 256>* bounds) const {
   DCHECK_EQ(glyphs.size(), bounds->size());
 
   if (!platform_data_.size())
     return;
 
-  Vector<SkRect, 256> skia_bounds(glyphs.size());
-  SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyphs(glyphs, skia_bounds.data());
-
-  for (unsigned i = 0; i < skia_bounds.size(); i++)
-    (*bounds)[i] = FloatRect(skia_bounds[i]);
+  DCHECK_EQ(bounds->size(), glyphs.size());
+  SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyphs(glyphs, bounds->data());
 }
 
 float SimpleFontData::PlatformWidthForGlyph(Glyph glyph) const {
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.h b/third_party/blink/renderer/platform/fonts/simple_font_data.h
index ea751f5..cc4a85d2 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.h
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.h
@@ -112,7 +112,7 @@
   }
 
   FloatRect BoundsForGlyph(Glyph) const;
-  void BoundsForGlyphs(const Vector<Glyph, 256>, Vector<FloatRect, 256>*) const;
+  void BoundsForGlyphs(const Vector<Glyph, 256>&, Vector<SkRect, 256>*) const;
   FloatRect PlatformBoundsForGlyph(Glyph) const;
   float WidthForGlyph(Glyph) const;
   float PlatformWidthForGlyph(Glyph) const;
diff --git a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
index 9d7f4b5..77ec6209 100644
--- a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
+++ b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
@@ -110,7 +110,7 @@
   }
 }
 
-void SkiaTextMetrics::GetSkiaBoundsForGlyphs(const Vector<Glyph, 256> glyphs,
+void SkiaTextMetrics::GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>& glyphs,
                                              SkRect* bounds) {
 #if defined(OS_MACOSX)
   for (unsigned i = 0; i < glyphs.size(); i++) {
diff --git a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
index bd9c0a3..787d8af 100644
--- a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
+++ b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
@@ -26,7 +26,7 @@
   void GetGlyphExtentsForHarfBuzz(hb_codepoint_t, hb_glyph_extents_t*);
 
   void GetSkiaBoundsForGlyph(Glyph, SkRect* bounds);
-  void GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>, SkRect*);
+  void GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>&, SkRect*);
   float GetSkiaWidthForGlyph(Glyph);
 
   static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value);
diff --git a/third_party/blink/renderer/platform/fonts/skia/sktypeface_factory.cc b/third_party/blink/renderer/platform/fonts/skia/sktypeface_factory.cc
index aa54588..c6a2daf 100644
--- a/third_party/blink/renderer/platform/fonts/skia/sktypeface_factory.cc
+++ b/third_party/blink/renderer/platform/fonts/skia/sktypeface_factory.cc
@@ -15,7 +15,8 @@
 sk_sp<SkTypeface> SkTypeface_Factory::FromFontConfigInterfaceIdAndTtcIndex(
     int config_id,
     int ttc_index) {
-#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(OS_WIN)
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(OS_WIN) && \
+    !defined(OS_FUCHSIA)
   sk_sp<SkFontConfigInterface> fci(SkFontConfigInterface::RefGlobal());
   SkFontConfigInterface::FontIdentity font_identity;
   font_identity.fID = config_id;
diff --git a/third_party/blink/renderer/platform/geometry/DEPS b/third_party/blink/renderer/platform/geometry/DEPS
index 3d15f40..9b2fc5f 100644
--- a/third_party/blink/renderer/platform/geometry/DEPS
+++ b/third_party/blink/renderer/platform/geometry/DEPS
@@ -10,7 +10,6 @@
     "+third_party/blink/renderer/platform/json",
     "+third_party/blink/renderer/platform/layout_unit.h",
     "+third_party/blink/renderer/platform/platform_export.h",
-    "+third_party/blink/renderer/platform/pod_interval_tree.h",
     "+third_party/blink/renderer/platform/wtf",
     "+ui/gfx/geometry",
 ]
diff --git a/third_party/blink/renderer/platform/geometry/float_polygon.h b/third_party/blink/renderer/platform/geometry/float_polygon.h
index 3fa1003..6a5150c 100644
--- a/third_party/blink/renderer/platform/geometry/float_polygon.h
+++ b/third_party/blink/renderer/platform/geometry/float_polygon.h
@@ -32,20 +32,14 @@
 
 #include "third_party/blink/renderer/platform/geometry/float_point.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
-#include "third_party/blink/renderer/platform/pod_interval_tree.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/pod_interval_tree.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
 class FloatPolygonEdge;
 
-// This class is used by PODIntervalTree for debugging.
-#ifndef NDEBUG
-template <class>
-struct ValueToString;
-#endif
-
 class PLATFORM_EXPORT FloatPolygon {
   USING_FAST_MALLOC(FloatPolygon);
   WTF_MAKE_NONCOPYABLE(FloatPolygon);
@@ -68,8 +62,8 @@
   bool IsEmpty() const { return empty_; }
 
  private:
-  typedef PODInterval<float, FloatPolygonEdge*> EdgeInterval;
-  typedef PODIntervalTree<float, FloatPolygonEdge*> EdgeIntervalTree;
+  typedef WTF::PODInterval<float, FloatPolygonEdge*> EdgeInterval;
+  typedef WTF::PODIntervalTree<float, FloatPolygonEdge*> EdgeIntervalTree;
 
   Vector<FloatPoint> vertices_;
   FloatRect bounding_box_;
@@ -138,25 +132,21 @@
   const FloatPolygon* polygon_;
 };
 
+}  // namespace blink
+
+namespace WTF {
 // These structures are used by PODIntervalTree for debugging.
 #ifndef NDEBUG
 template <>
-struct ValueToString<float> {
+struct ValueToString<blink::FloatPolygonEdge*> {
   STATIC_ONLY(ValueToString);
-  static String ToString(const float value) { return String::Number(value); }
-};
-
-template <>
-struct ValueToString<FloatPolygonEdge*> {
-  STATIC_ONLY(ValueToString);
-  static String ToString(const FloatPolygonEdge* edge) {
+  static String ToString(const blink::FloatPolygonEdge* edge) {
     return String::Format("%p (%f,%f %f,%f)", edge, edge->Vertex1().X(),
                           edge->Vertex1().Y(), edge->Vertex2().X(),
                           edge->Vertex2().Y());
   }
 };
 #endif
-
-}  // namespace blink
+}  // namespace WTF
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_FLOAT_POLYGON_H_
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
index 4e7fab98..a9855ee1 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -160,6 +160,14 @@
                                {}) {}
 };
 
+class FrameSchedulerImplStopNonTimersInBackgroundDisabledTest
+    : public FrameSchedulerImplTest {
+ public:
+  FrameSchedulerImplStopNonTimersInBackgroundDisabledTest()
+      : FrameSchedulerImplTest({},
+                               {blink::features::kStopNonTimersInBackground}) {}
+};
+
 namespace {
 
 class MockLifecycleObserver final : public FrameScheduler::Observer {
@@ -391,7 +399,8 @@
   EXPECT_EQ(5, counter);
 }
 
-TEST_F(FrameSchedulerImplTest, PageFreezeAndUnfreezeFlagDisabled) {
+TEST_F(FrameSchedulerImplStopNonTimersInBackgroundDisabledTest,
+       PageFreezeAndUnfreezeFlagDisabled) {
   int counter = 0;
   LoadingTaskQueue()->task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
@@ -1612,6 +1621,8 @@
 };
 
 TEST_F(ThrottleableAndFreezableTaskTypesTest, QueueTraitsFromFieldTrialParams) {
+  if (base::FeatureList::IsEnabled(blink::features::kStopNonTimersInBackground))
+    return;
   // These tests will start to fail if the default task queues or queue traits
   // change for these task types.
 
@@ -1627,7 +1638,6 @@
       task_queue->GetQueueTraits(),
       MainThreadTaskQueue::QueueTraits().SetCanBeFrozen(true).SetCanBePaused(
           true));
-
   task_queue = GetTaskQueue(TaskType::kDatabaseAccess);
   EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits()
                                               .SetCanBeThrottled(true)
@@ -1669,6 +1679,9 @@
 };
 
 TEST_F(FreezableOnlyTaskTypesTest, QueueTraitsFromFieldTrialParams) {
+  if (base::FeatureList::IsEnabled(blink::features::kStopNonTimersInBackground))
+    return;
+
   // These tests will start to fail if the default task queues or queue traits
   // change for these task types.
 
@@ -1726,6 +1739,9 @@
 };
 
 TEST_F(ThrottleableOnlyTaskTypesTest, QueueTraitsFromFieldTrialParams) {
+  if (base::FeatureList::IsEnabled(blink::features::kStopNonTimersInBackground))
+    return;
+
   // These tests will start to fail if the default task queues or queue traits
   // change for these task types.
 
diff --git a/third_party/blink/renderer/platform/testing/DEPS b/third_party/blink/renderer/platform/testing/DEPS
index a5014603..86347437 100644
--- a/third_party/blink/renderer/platform/testing/DEPS
+++ b/third_party/blink/renderer/platform/testing/DEPS
@@ -31,7 +31,6 @@
     "+third_party/blink/renderer/platform/loader",
     "+third_party/blink/renderer/platform/network",
     "+third_party/blink/renderer/platform/platform_export.h",
-    "+third_party/blink/renderer/platform/pod_arena.h",
     "+third_party/blink/renderer/platform/runtime_enabled_features.h",
     "+third_party/blink/renderer/platform/scheduler",
     "+third_party/blink/renderer/platform/scroll",
diff --git a/third_party/blink/renderer/platform/wtf/BUILD.gn b/third_party/blink/renderer/platform/wtf/BUILD.gn
index 6b95b50..1ea11b0 100644
--- a/third_party/blink/renderer/platform/wtf/BUILD.gn
+++ b/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -113,6 +113,11 @@
     "math_extras.h",
     "noncopyable.h",
     "not_found.h",
+    "pod_arena.h",
+    "pod_free_list_arena.h",
+    "pod_interval.h",
+    "pod_interval_tree.h",
+    "pod_red_black_tree.h",
     "ref_counted.h",
     "ref_vector.h",
     "retain_ptr.h",
@@ -320,6 +325,13 @@
     "hash_set_test.cc",
     "list_hash_set_test.cc",
     "math_extras_test.cc",
+    "pod_arena_test.cc",
+    "pod_arena_test_helpers.h",
+    "pod_free_list_arena_test.cc",
+    "pod_interval_tree_test.cc",
+    "pod_red_black_tree_test.cc",
+    "pod_tree_test_helpers.cc",
+    "pod_tree_test_helpers.h",
     "saturated_arithmetic_test.cc",
     "scoped_logger_test.cc",
     "string_hasher_test.cc",
diff --git a/third_party/blink/renderer/platform/pod_arena.h b/third_party/blink/renderer/platform/wtf/pod_arena.h
similarity index 96%
rename from third_party/blink/renderer/platform/pod_arena.h
rename to third_party/blink/renderer/platform/wtf/pod_arena.h
index 75a08c1d..173c979 100644
--- a/third_party/blink/renderer/platform/pod_arena.h
+++ b/third_party/blink/renderer/platform/wtf/pod_arena.h
@@ -23,8 +23,8 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_ARENA_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_ARENA_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_H_
 
 #include <stdint.h>
 #include <memory>
@@ -37,7 +37,7 @@
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
-namespace blink {
+namespace WTF {
 
 // An arena which allocates only Plain Old Data (POD), or classes and
 // structs bottoming out in Plain Old Data. NOTE: the constructors of
@@ -191,6 +191,6 @@
   Vector<std::unique_ptr<Chunk>> chunks_;
 };
 
-}  // namespace blink
+}  // namespace WTF
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_ARENA_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_H_
diff --git a/third_party/blink/renderer/platform/pod_arena_test.cc b/third_party/blink/renderer/platform/wtf/pod_arena_test.cc
similarity index 95%
rename from third_party/blink/renderer/platform/pod_arena_test.cc
rename to third_party/blink/renderer/platform/wtf/pod_arena_test.cc
index c1f07840..a9c2d51 100644
--- a/third_party/blink/renderer/platform/pod_arena_test.cc
+++ b/third_party/blink/renderer/platform/wtf/pod_arena_test.cc
@@ -23,14 +23,14 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "third_party/blink/renderer/platform/pod_arena.h"
+#include "third_party/blink/renderer/platform/wtf/pod_arena.h"
 
 #include <algorithm>
 #include "base/memory/scoped_refptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/testing/arena_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h"
 
-namespace blink {
+namespace WTF {
 
 using ArenaTestHelpers::TrackedAllocator;
 
@@ -93,4 +93,4 @@
   }
 }
 
-}  // namespace blink
+}  // namespace WTF
diff --git a/third_party/blink/renderer/platform/testing/arena_test_helpers.h b/third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h
similarity index 89%
rename from third_party/blink/renderer/platform/testing/arena_test_helpers.h
rename to third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h
index 4d2cb5e3..09ed3f1 100644
--- a/third_party/blink/renderer/platform/testing/arena_test_helpers.h
+++ b/third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h
@@ -23,16 +23,16 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_ARENA_TEST_HELPERS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_ARENA_TEST_HELPERS_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_TEST_HELPERS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_TEST_HELPERS_H_
 
-#include "third_party/blink/renderer/platform/pod_arena.h"
 #include "third_party/blink/renderer/platform/wtf/not_found.h"
+#include "third_party/blink/renderer/platform/wtf/pod_arena.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 #include <gtest/gtest.h>
 
-namespace blink {
+namespace WTF {
 namespace ArenaTestHelpers {
 
 // An allocator for the PODArena which tracks the regions which have
@@ -66,6 +66,6 @@
 };
 
 }  // namespace ArenaTestHelpers
-}  // namespace blink
+}  // namespace WTF
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_ARENA_TEST_HELPERS_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_TEST_HELPERS_H_
diff --git a/third_party/blink/renderer/platform/pod_free_list_arena.h b/third_party/blink/renderer/platform/wtf/pod_free_list_arena.h
similarity index 94%
rename from third_party/blink/renderer/platform/pod_free_list_arena.h
rename to third_party/blink/renderer/platform/wtf/pod_free_list_arena.h
index 3cab486..ff1b1e8 100644
--- a/third_party/blink/renderer/platform/pod_free_list_arena.h
+++ b/third_party/blink/renderer/platform/wtf/pod_free_list_arena.h
@@ -23,14 +23,14 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_FREE_LIST_ARENA_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_FREE_LIST_ARENA_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_FREE_LIST_ARENA_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_FREE_LIST_ARENA_H_
 
-#include "third_party/blink/renderer/platform/pod_arena.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/pod_arena.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 
-namespace blink {
+namespace WTF {
 
 template <class T>
 class PODFreeListArena : public RefCounted<PODFreeListArena<T>> {
@@ -123,6 +123,6 @@
   friend class PODFreeListArenaTest;
 };
 
-}  // namespace blink
+}  // namespace WTF
 
 #endif
diff --git a/third_party/blink/renderer/platform/pod_free_list_arena_test.cc b/third_party/blink/renderer/platform/wtf/pod_free_list_arena_test.cc
similarity index 96%
rename from third_party/blink/renderer/platform/pod_free_list_arena_test.cc
rename to third_party/blink/renderer/platform/wtf/pod_free_list_arena_test.cc
index 69fee78..94fc4a4 100644
--- a/third_party/blink/renderer/platform/pod_free_list_arena_test.cc
+++ b/third_party/blink/renderer/platform/wtf/pod_free_list_arena_test.cc
@@ -23,14 +23,14 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "third_party/blink/renderer/platform/pod_free_list_arena.h"
+#include "third_party/blink/renderer/platform/wtf/pod_free_list_arena.h"
 
 #include "base/memory/scoped_refptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/testing/arena_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
-namespace blink {
+namespace WTF {
 
 using ArenaTestHelpers::TrackedAllocator;
 
@@ -163,4 +163,4 @@
   }
 }
 
-}  // namespace blink
+}  // namespace WTF
diff --git a/third_party/blink/renderer/platform/pod_interval.h b/third_party/blink/renderer/platform/wtf/pod_interval.h
similarity index 86%
rename from third_party/blink/renderer/platform/pod_interval.h
rename to third_party/blink/renderer/platform/wtf/pod_interval.h
index b96a68c8..b4e2585 100644
--- a/third_party/blink/renderer/platform/pod_interval.h
+++ b/third_party/blink/renderer/platform/wtf/pod_interval.h
@@ -23,15 +23,16 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_H_
 
-#include "third_party/blink/renderer/platform/heap/handle.h"
 #ifndef NDEBUG
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #endif
 
-namespace blink {
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+namespace WTF {
 
 // Class representing a closed interval which can hold an arbitrary
 // Plain Old Datatype (POD) as its endpoints and a piece of user
@@ -71,8 +72,6 @@
 // Note that this class requires a copy constructor and assignment
 // operator in order to be stored in the red-black tree.
 
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-
 #ifndef NDEBUG
 template <class T>
 struct ValueToString;
@@ -143,11 +142,31 @@
  private:
   T low_;
   T high_;
-  GC_PLUGIN_IGNORE("crbug.com/513116")
+// https://crbug.com/513116.
+#if defined(__clang__)
+  __attribute__((annotate("blink_gc_plugin_ignore"))) UserData data_;
+#else
   UserData data_;
+#endif
   T max_high_;
 };
 
-}  // namespace blink
+#ifndef NDEBUG
+template <>
+struct ValueToString<float> {
+  STATIC_ONLY(ValueToString);
+  static String ToString(const float value) { return String::Number(value); }
+};
+template <>
+struct ValueToString<double> {
+  static String ToString(const double value) { return String::Number(value); }
+};
+template <>
+struct ValueToString<int> {
+  static String ToString(const int& value) { return String::Number(value); }
+};
+#endif
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_H_
+}  // namespace WTF
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_H_
diff --git a/third_party/blink/renderer/platform/pod_interval_tree.h b/third_party/blink/renderer/platform/wtf/pod_interval_tree.h
similarity index 94%
rename from third_party/blink/renderer/platform/pod_interval_tree.h
rename to third_party/blink/renderer/platform/wtf/pod_interval_tree.h
index ad4e865..f0bbacd 100644
--- a/third_party/blink/renderer/platform/pod_interval_tree.h
+++ b/third_party/blink/renderer/platform/wtf/pod_interval_tree.h
@@ -23,17 +23,17 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_TREE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_TREE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_TREE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_TREE_H_
 
-#include "third_party/blink/renderer/platform/pod_arena.h"
-#include "third_party/blink/renderer/platform/pod_interval.h"
-#include "third_party/blink/renderer/platform/pod_red_black_tree.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/noncopyable.h"
+#include "third_party/blink/renderer/platform/wtf/pod_arena.h"
+#include "third_party/blink/renderer/platform/wtf/pod_interval.h"
+#include "third_party/blink/renderer/platform/wtf/pod_red_black_tree.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
-namespace blink {
+namespace WTF {
 
 #ifndef NDEBUG
 template <class T>
@@ -253,6 +253,6 @@
 };
 #endif
 
-}  // namespace blink
+}  // namespace WTF
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_TREE_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_TREE_H_
diff --git a/third_party/blink/renderer/platform/pod_interval_tree_test.cc b/third_party/blink/renderer/platform/wtf/pod_interval_tree_test.cc
similarity index 96%
rename from third_party/blink/renderer/platform/pod_interval_tree_test.cc
rename to third_party/blink/renderer/platform/wtf/pod_interval_tree_test.cc
index ad20eb0..22cc18b 100644
--- a/third_party/blink/renderer/platform/pod_interval_tree_test.cc
+++ b/third_party/blink/renderer/platform/wtf/pod_interval_tree_test.cc
@@ -25,15 +25,14 @@
 
 // Tests for the interval tree class.
 
-#include "third_party/blink/renderer/platform/pod_interval_tree.h"
+#include "third_party/blink/renderer/platform/wtf/pod_interval_tree.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/geometry/float_polygon.h"
-#include "third_party/blink/renderer/platform/testing/tree_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
-namespace blink {
+namespace WTF {
 
 using TreeTestHelpers::InitRandom;
 using TreeTestHelpers::NextRandom;
@@ -196,13 +195,6 @@
 // in release builds.
 // #define DEBUG_INSERTION_AND_DELETION_TEST
 
-#ifndef NDEBUG
-template <>
-struct ValueToString<int> {
-  static String ToString(const int& value) { return String::Number(value); }
-};
-#endif
-
 namespace {
 
 void TreeInsertionAndDeletionTest(int32_t seed, int tree_size) {
@@ -342,4 +334,4 @@
   ASSERT_TRUE(tree.CheckInvariants());
 }
 
-}  // namespace blink
+}  // namespace WTF
diff --git a/third_party/blink/renderer/platform/pod_red_black_tree.h b/third_party/blink/renderer/platform/wtf/pod_red_black_tree.h
similarity index 98%
rename from third_party/blink/renderer/platform/pod_red_black_tree.h
rename to third_party/blink/renderer/platform/wtf/pod_red_black_tree.h
index 6de3b42..9b845352 100644
--- a/third_party/blink/renderer/platform/pod_red_black_tree.h
+++ b/third_party/blink/renderer/platform/wtf/pod_red_black_tree.h
@@ -69,21 +69,21 @@
 // The design of this red-black tree comes from Cormen, Leiserson,
 // and Rivest, _Introduction to Algorithms_, MIT Press, 1990.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_RED_BLACK_TREE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_RED_BLACK_TREE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_RED_BLACK_TREE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_RED_BLACK_TREE_H_
 
 #include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/platform/pod_free_list_arena.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/noncopyable.h"
+#include "third_party/blink/renderer/platform/wtf/pod_free_list_arena.h"
 #ifndef NDEBUG
 #include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #endif
 
-namespace blink {
+namespace WTF {
 
 #ifndef NDEBUG
 template <class T>
@@ -794,6 +794,6 @@
 #endif
 };
 
-}  // namespace blink
+}  // namespace WTF
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_RED_BLACK_TREE_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_RED_BLACK_TREE_H_
diff --git a/third_party/blink/renderer/platform/pod_red_black_tree_test.cc b/third_party/blink/renderer/platform/wtf/pod_red_black_tree_test.cc
similarity index 96%
rename from third_party/blink/renderer/platform/pod_red_black_tree_test.cc
rename to third_party/blink/renderer/platform/wtf/pod_red_black_tree_test.cc
index cb2ad97..a583998 100644
--- a/third_party/blink/renderer/platform/pod_red_black_tree_test.cc
+++ b/third_party/blink/renderer/platform/wtf/pod_red_black_tree_test.cc
@@ -25,14 +25,14 @@
 
 // Tests for the red-black tree class.
 
-#include "third_party/blink/renderer/platform/pod_red_black_tree.h"
+#include "third_party/blink/renderer/platform/wtf/pod_red_black_tree.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/testing/arena_test_helpers.h"
-#include "third_party/blink/renderer/platform/testing/tree_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
-namespace blink {
+namespace WTF {
 
 using ArenaTestHelpers::TrackedAllocator;
 using TreeTestHelpers::InitRandom;
@@ -193,4 +193,4 @@
   InsertionAndDeletionTest(12311, 100);
 }
 
-}  // namespace blink
+}  // namespace WTF
diff --git a/third_party/blink/renderer/platform/testing/tree_test_helpers.cc b/third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.cc
similarity index 93%
rename from third_party/blink/renderer/platform/testing/tree_test_helpers.cc
rename to third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.cc
index b3c7089..0d96775 100644
--- a/third_party/blink/renderer/platform/testing/tree_test_helpers.cc
+++ b/third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.cc
@@ -23,11 +23,11 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "third_party/blink/renderer/platform/testing/tree_test_helpers.h"
+#include "third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h"
 
 #include <cstdlib>
 
-namespace blink {
+namespace WTF {
 namespace TreeTestHelpers {
 
 void InitRandom(const int32_t seed) {
@@ -40,4 +40,4 @@
 }
 
 }  // namespace TreeTestHelpers
-}  // namespace blink
+}  // namespace WTF
diff --git a/third_party/blink/renderer/platform/testing/tree_test_helpers.h b/third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h
similarity index 89%
rename from third_party/blink/renderer/platform/testing/tree_test_helpers.h
rename to third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h
index 0192b08..1bf0fa6 100644
--- a/third_party/blink/renderer/platform/testing/tree_test_helpers.h
+++ b/third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h
@@ -28,12 +28,12 @@
 //
 // These are **not** thread safe!
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_TREE_TEST_HELPERS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_TREE_TEST_HELPERS_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_TREE_TEST_HELPERS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_TREE_TEST_HELPERS_H_
 
 #include <stdint.h>
 
-namespace blink {
+namespace WTF {
 namespace TreeTestHelpers {
 
 // Initializes the pseudo-random number generator with a specific seed.
@@ -45,6 +45,6 @@
 int32_t NextRandom(const int32_t maximum_value);
 
 }  // namespace TreeTestHelpers
-}  // namespace blink
+}  // namespace WTF
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_TREE_TEST_HELPERS_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_TREE_TEST_HELPERS_H_
diff --git a/third_party/molokocacao/BUILD.gn b/third_party/molokocacao/BUILD.gn
deleted file mode 100644
index 9b660f59..0000000
--- a/third_party/molokocacao/BUILD.gn
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("molokocacao") {
-  sources = [
-    "NSBezierPath+MCAdditions.h",
-    "NSBezierPath+MCAdditions.m",
-  ]
-
-  deps = [
-    "//third_party/google_toolbox_for_mac",
-  ]
-
-  libs = [ "AppKit.framework" ]
-}
diff --git a/third_party/molokocacao/LICENSE b/third_party/molokocacao/LICENSE
deleted file mode 100644
index 6133156..0000000
--- a/third_party/molokocacao/LICENSE
+++ /dev/null
@@ -1,23 +0,0 @@
-Copyright 2008 MolokoCacao
-All rights reserved
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted providing that the following conditions 
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/molokocacao/NSBezierPath+MCAdditions.h b/third_party/molokocacao/NSBezierPath+MCAdditions.h
deleted file mode 100644
index f56660f..0000000
--- a/third_party/molokocacao/NSBezierPath+MCAdditions.h
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-//  NSBezierPath+MCAdditions.h
-//
-//  Created by Sean Patrick O'Brien on 4/1/08.
-//  Copyright 2008 MolokoCacao. All rights reserved.
-//
-
-#ifndef THIRD_PARTY_MOLOKOCACAO_NSBEZIERPATH_MCADDITIONS_H_
-#define THIRD_PARTY_MOLOKOCACAO_NSBEZIERPATH_MCADDITIONS_H_
-
-#import <Cocoa/Cocoa.h>
-
-@interface NSBezierPath (MCAdditions)
-
-+ (NSBezierPath*)bezierPathWithCGPath:(CGPathRef)pathRef;
-
-- (NSBezierPath*)pathWithStrokeWidth:(CGFloat)strokeWidth;
-
-- (void)fillWithInnerShadow:(NSShadow *)shadow;
-- (void)drawBlurWithColor:(NSColor*)color radius:(CGFloat)radius;
-
-- (void)strokeInside;
-- (void)strokeInsideWithinRect:(NSRect)clipRect;
-
-@end
-
-#endif  // THIRD_PARTY_MOLOKOCACAO_NSBEZIERPATH_MCADDITIONS_H_
diff --git a/third_party/molokocacao/NSBezierPath+MCAdditions.m b/third_party/molokocacao/NSBezierPath+MCAdditions.m
deleted file mode 100644
index 3b006ed..0000000
--- a/third_party/molokocacao/NSBezierPath+MCAdditions.m
+++ /dev/null
@@ -1,190 +0,0 @@
-//
-//  NSBezierPath+MCAdditions.m
-//
-//  Created by Sean Patrick O'Brien on 4/1/08.
-//  Copyright 2008 MolokoCacao. All rights reserved.
-//
-
-#import "NSBezierPath+MCAdditions.h"
-
-#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSBezierPath+CGPath.h"
-
-// remove/comment out this line of you don't want to use undocumented functions
-#define MCBEZIER_USE_PRIVATE_FUNCTION
-
-#ifdef MCBEZIER_USE_PRIVATE_FUNCTION
-extern CGPathRef CGContextCopyPath(CGContextRef context);
-#endif
-
-static void CGPathCallback(void *info, const CGPathElement *element)
-{
-	NSBezierPath *path = info;
-	CGPoint *points = element->points;
-
-	switch (element->type) {
-		case kCGPathElementMoveToPoint:
-		{
-			[path moveToPoint:NSMakePoint(points[0].x, points[0].y)];
-			break;
-		}
-		case kCGPathElementAddLineToPoint:
-		{
-			[path lineToPoint:NSMakePoint(points[0].x, points[0].y)];
-			break;
-		}
-		case kCGPathElementAddQuadCurveToPoint:
-		{
-			// NOTE: This is untested.
-			NSPoint currentPoint = [path currentPoint];
-			NSPoint interpolatedPoint = NSMakePoint((currentPoint.x + 2*points[0].x) / 3, (currentPoint.y + 2*points[0].y) / 3);
-			[path curveToPoint:NSMakePoint(points[1].x, points[1].y) controlPoint1:interpolatedPoint controlPoint2:interpolatedPoint];
-			break;
-		}
-		case kCGPathElementAddCurveToPoint:
-		{
-			[path curveToPoint:NSMakePoint(points[2].x, points[2].y) controlPoint1:NSMakePoint(points[0].x, points[0].y) controlPoint2:NSMakePoint(points[1].x, points[1].y)];
-			break;
-		}
-		case kCGPathElementCloseSubpath:
-		{
-			[path closePath];
-			break;
-		}
-	}
-}
-
-@implementation NSBezierPath (MCAdditions)
-
-+ (NSBezierPath *)bezierPathWithCGPath:(CGPathRef)pathRef
-{
-	NSBezierPath *path = [NSBezierPath bezierPath];
-	CGPathApply(pathRef, path, CGPathCallback);
-	
-	return path;
-}
-
-- (NSBezierPath *)pathWithStrokeWidth:(CGFloat)strokeWidth
-{
-#ifdef MCBEZIER_USE_PRIVATE_FUNCTION
-	NSBezierPath *path = [self copy];
-	CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
-	CGPathRef pathRef = [path gtm_CGPath];
-	[path release];
-	
-	CGContextSaveGState(context);
-		
-	CGContextBeginPath(context);
-	CGContextAddPath(context, pathRef);
-	CGContextSetLineWidth(context, strokeWidth);
-	CGContextReplacePathWithStrokedPath(context);
-	CGPathRef strokedPathRef = CGContextCopyPath(context);
-	CGContextBeginPath(context);
-	NSBezierPath *strokedPath = [NSBezierPath bezierPathWithCGPath:strokedPathRef];
-	
-	CGContextRestoreGState(context);
-	
-	CFRelease(pathRef);
-	CFRelease(strokedPathRef);
-	
-	return strokedPath;
-#else
-	return nil;
-#endif  // MCBEZIER_USE_PRIVATE_FUNCTION
-}
-
-- (void)fillWithInnerShadow:(NSShadow *)shadow
-{
-	[NSGraphicsContext saveGraphicsState];
-	
-	NSSize offset = shadow.shadowOffset;
-	NSSize originalOffset = offset;
-	CGFloat radius = shadow.shadowBlurRadius;
-	NSRect bounds = NSInsetRect(self.bounds, -(ABS(offset.width) + radius), -(ABS(offset.height) + radius));
-
-	// The context's user transform isn't automatically applied to shadow offsets.
-        offset.height += bounds.size.height;
-	shadow.shadowOffset = offset;
-	NSAffineTransform *transform = [NSAffineTransform transform];
-	if ([[NSGraphicsContext currentContext] isFlipped])
-		[transform translateXBy:0 yBy:bounds.size.height];
-	else
-		[transform translateXBy:0 yBy:-bounds.size.height];
-	
-	NSBezierPath *drawingPath = [NSBezierPath bezierPathWithRect:bounds];
-	[drawingPath setWindingRule:NSEvenOddWindingRule];
-	[drawingPath appendBezierPath:self];
-	[drawingPath transformUsingAffineTransform:transform];
-	
-	[self addClip];
-	[shadow set];
-	[[NSColor blackColor] set];
-	[drawingPath fill];
-	
-	shadow.shadowOffset = originalOffset;
-	
-	[NSGraphicsContext restoreGraphicsState];
-}
-
-- (void)drawBlurWithColor:(NSColor *)color radius:(CGFloat)radius
-{
-	NSRect bounds = NSInsetRect(self.bounds, -radius, -radius);
-	NSShadow *shadow = [[NSShadow alloc] init];
-	shadow.shadowOffset = NSMakeSize(0, bounds.size.height);
-	shadow.shadowBlurRadius = radius;
-	shadow.shadowColor = color;
-	NSBezierPath *path = [self copy];
-	NSAffineTransform *transform = [NSAffineTransform transform];
-	if ([[NSGraphicsContext currentContext] isFlipped])
-		[transform translateXBy:0 yBy:bounds.size.height];
-	else
-		[transform translateXBy:0 yBy:-bounds.size.height];
-	[path transformUsingAffineTransform:transform];
-	
-	[NSGraphicsContext saveGraphicsState];
-	
-	[shadow set];
-	[[NSColor blackColor] set];
-	NSRectClip(bounds);
-	[path fill];
-	
-	[NSGraphicsContext restoreGraphicsState];
-	
-	[path release];
-	[shadow release];
-}
-
-// Credit for the next two methods goes to Matt Gemmell
-- (void)strokeInside
-{
-    /* Stroke within path using no additional clipping rectangle. */
-    [self strokeInsideWithinRect:NSZeroRect];
-}
-
-- (void)strokeInsideWithinRect:(NSRect)clipRect
-{
-    NSGraphicsContext *thisContext = [NSGraphicsContext currentContext];
-    float lineWidth = [self lineWidth];
-    
-    /* Save the current graphics context. */
-    [thisContext saveGraphicsState];
-    
-    /* Double the stroke width, since -stroke centers strokes on paths. */
-    [self setLineWidth:(lineWidth * 2.0)];
-    
-    /* Clip drawing to this path; draw nothing outwith the path. */
-    [self setClip];
-    
-    /* Further clip drawing to clipRect, usually the view's frame. */
-    if (clipRect.size.width > 0.0 && clipRect.size.height > 0.0) {
-        [NSBezierPath clipRect:clipRect];
-    }
-    
-    /* Stroke the path. */
-    [self stroke];
-    
-    /* Restore the previous graphics context. */
-    [thisContext restoreGraphicsState];
-    [self setLineWidth:lineWidth];
-}
-
-@end
diff --git a/third_party/molokocacao/README.chromium b/third_party/molokocacao/README.chromium
deleted file mode 100644
index 235c82a5..0000000
--- a/third_party/molokocacao/README.chromium
+++ /dev/null
@@ -1,15 +0,0 @@
-Name: NSBezierPath additions from Sean Patrick O'Brien
-Short Name: NSBezierPath
-URL: http://www.seanpatrickobrien.com/journal/posts/3
-Source URL: http://www.seanpatrickobrien.com/downloads/track/?path=%2Ftutorials%2F1%2FExampleButton.zip
-Version: 1.0
-License: BSD
-Security critical: YES
-
-Description:
-Additions to NSBezierPath to make certain operations more convenient (inner
-shadows on paths, for example).
-
-Local Modifications:
- - Added LICENSE file based on email correspondence with Sean.
- - Added header guards.
diff --git a/tools/licenses.py b/tools/licenses.py
index e75bc891..f9c1ed5 100755
--- a/tools/licenses.py
+++ b/tools/licenses.py
@@ -306,7 +306,6 @@
     os.path.join('third_party', 'lss'),
     os.path.join('third_party', 'lzma_sdk'),
     os.path.join('third_party', 'mesa'),
-    os.path.join('third_party', 'molokocacao'),
     os.path.join('third_party', 'motemplate'),
     os.path.join('third_party', 'mozc'),
     os.path.join('third_party', 'mozilla'),
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 00f565b..f672dcec 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2866,6 +2866,17 @@
   <int value="3" label="User navigated away from page while bubble hidden"/>
 </enum>
 
+<enum name="AutofillLocalCardMigrationDialogOffer">
+  <int value="0" label="Shown"/>
+  <int value="1" label="Not shown due to legal message being invalid"/>
+</enum>
+
+<enum name="AutofillLocalCardMigrationDialogUserInteraction">
+  <int value="0" label="User explicitly accepted dialog"/>
+  <int value="1" label="User explicitly denied dialog"/>
+  <int value="2" label="User clicked legal message link"/>
+</enum>
+
 <enum name="AutofillMacAddressBook">
   <int value="0" label="Showed popup entry"/>
   <int value="1" label="Selected popup entry"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index a9cb875..88aabe2 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -6881,6 +6881,37 @@
   <summary>Record how bubble is closed by different user interactions.</summary>
 </histogram>
 
+<histogram name="Autofill.LocalCardMigrationDialogActiveDuration" units="ms">
+  <owner>siyua@chromium.org</owner>
+  <summary>
+    Record duration of the local card migration dialog being visible to users.
+  </summary>
+</histogram>
+
+<histogram name="Autofill.LocalCardMigrationDialogOffer"
+    enum="AutofillLocalCardMigrationDialogOffer">
+  <owner>siyua@chromium.org</owner>
+  <summary>
+    Record events related to showing the local card migration dialog.
+  </summary>
+</histogram>
+
+<histogram name="Autofill.LocalCardMigrationDialogUserInteraction"
+    enum="AutofillLocalCardMigrationDialogUserInteraction">
+  <owner>siyua@chromium.org</owner>
+  <summary>
+    Record user interactions related to local card migration dialog.
+  </summary>
+</histogram>
+
+<histogram name="Autofill.LocalCardMigrationDialogUserSelectionPercentage"
+    units="%">
+  <owner>siyua@chromium.org</owner>
+  <summary>
+    Record the percentage of cards selected by the user in the migration dialog.
+  </summary>
+</histogram>
+
 <histogram name="Autofill.LocalCardMigrationOrigin"
     enum="LocalCardMigrationPrompt">
   <owner>jiahuiguo@chromium.org</owner>
@@ -9081,6 +9112,77 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="Blink.MainFrame.CompositingCommitRatio" units="%">
+  <owner>paint-dev@chromium.org</owner>
+<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" -->
+
+  <summary>
+    The percentage of time between a BeginMainFrame and paint results commit in
+    Blink that is used for committing paint results to the compositor.
+  </summary>
+</histogram>
+
+<histogram base="true" name="Blink.MainFrame.CompositingRatio" units="%">
+  <owner>paint-dev@chromium.org</owner>
+<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" -->
+
+  <summary>
+    The percentage of time between a BeginMainFrame and paint results commit in
+    Blink that is used for computing Compositing.
+  </summary>
+</histogram>
+
+=
+<histogram base="true" name="Blink.MainFrame.IntersectionRatio" units="%">
+  <owner>paint-dev@chromium.org</owner>
+<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" -->
+
+  <summary>
+    The percentage of time between a BeginMainFrame and paint results commit in
+    Blink that is used for computing Intersection Observations.
+  </summary>
+</histogram>
+
+<histogram base="true" name="Blink.MainFrame.PaintRatio" units="%">
+  <owner>paint-dev@chromium.org</owner>
+<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" -->
+
+  <summary>
+    The percentage of time between a BeginMainFrame and paint results commit in
+    Blink that is used for computing Paint.
+  </summary>
+</histogram>
+
+<histogram base="true" name="Blink.MainFrame.PrePaintRatio" units="%">
+  <owner>paint-dev@chromium.org</owner>
+<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" -->
+
+  <summary>
+    The percentage of time between a BeginMainFrame and paint results commit in
+    Blink that is used for computing PrePaint.
+  </summary>
+</histogram>
+
+<histogram base="true" name="Blink.MainFrame.StyleAndLayoutRatio" units="%">
+  <owner>paint-dev@chromium.org</owner>
+<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" -->
+
+  <summary>
+    The percentage of time between a BeginMainFrame and paint results commit in
+    Blink that is used for computing Style and Layout.
+  </summary>
+</histogram>
+
+<histogram name="Blink.MainFrame.UpdateTime" units="microseconds">
+  <owner>paint-dev@chromium.org</owner>
+  <summary>
+    Time between a BeginMainFrame and paint results commit in Blink.
+
+    This histogram will not record metrics on machines with low-resolution
+    clocks.
+  </summary>
+</histogram>
+
 <histogram name="Blink.MediaDocument.DownloadButton"
     enum="MediaDocumentDownloadButtonType">
   <obsolete>
@@ -107678,6 +107780,36 @@
   </summary>
 </histogram>
 
+<histogram name="Tabs.Tasks.DuplicatedTab.DuplicatedTabCount" units="tabs"
+    expires_after="2019-01-01">
+  <owner>yusufo@chromium.org</owner>
+  <owner>wychen@chromium.org</owner>
+  <summary>
+    During tab restoration, a tab is considered as a duplicated tab when it has
+    an identical url with another restored tab.
+
+    This histogram records the number of duplicated tabs on a cold start after
+    all tabs are restored. The possible range for this number is from 0 to total
+    number of restored tabs minus 1. In other words, this number is equals to
+    total number of restored tabs minus the number of unique URLs.
+  </summary>
+</histogram>
+
+<histogram name="Tabs.Tasks.DuplicatedTab.DuplicatedTabRatio" units="%"
+    expires_after="2019-01-01">
+  <owner>yusufo@chromium.org</owner>
+  <owner>wychen@chromium.org</owner>
+  <summary>
+    During tab restoration, a tab is considered as a duplicated tab when it has
+    an identical url with another restored tab.
+
+    This histogram records the ratio of duplicated tabs to the total number of
+    tabs on a cold start after all tabs are restored. This ratio will never
+    reach 100%, since the highest possible number of duplicated tabs is total
+    number of restored tabs minus 1.
+  </summary>
+</histogram>
+
 <histogram name="Tabs.Tasks.HubAndSpokeNavigationUsage" units="spokes"
     expires_after="2019-01-01">
 <!-- Name completed by histogram_suffixes name="HubAndSpokeNavigationUsageType" -->
@@ -120690,6 +120822,16 @@
   <affected-histogram name="Autofill.LocalCardMigrationBubbleUserInteraction"/>
 </histogram_suffixes>
 
+<histogram_suffixes
+    name="AutofillLocalCardMigrationDialogDurationWithCloseEvent" separator=".">
+  <suffix name="Accepted"
+      label="The dialog was closed due to the user clicking the save button."/>
+  <suffix name="Denied"
+      label="The dialog was closed due to the user clicking the cancel
+             button."/>
+  <affected-histogram name="Autofill.LocalCardMigrationDialogActiveDuration"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="AutofillLocalCardMigrationOrigin" separator=".">
   <suffix name="SettingsPage" label="Trigger from settings page"/>
   <suffix name="UseOfLocalCard"
@@ -121030,6 +121172,18 @@
       name="Blink.LazyLoad.CrossOriginFrames.InitialDeferralAction"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" separator=".">
+  <suffix name="1msTo5ms" label="Ratio when main frame between 1ms and 5ms."/>
+  <suffix name="LessThan1ms" label="Ratio when main frame shorter than 1ms."/>
+  <suffix name="MoreThan5ms" label="Ratio when main frame longer than 5ms."/>
+  <affected-histogram name="Blink.MainFrame.CompositingCommitRatio"/>
+  <affected-histogram name="Blink.MainFrame.CompositingRatio"/>
+  <affected-histogram name="Blink.MainFrame.IntersectionRatio"/>
+  <affected-histogram name="Blink.MainFrame.PaintRatio"/>
+  <affected-histogram name="Blink.MainFrame.PrePaintRatio"/>
+  <affected-histogram name="Blink.MainFrame.StyleAndLayoutRatio"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="BlinkVisibleLoadTimeSuffixes" separator=".">
   <suffix name="2G" label="2G effective connection type"/>
   <suffix name="3G" label="3G effective connection type"/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index dbfb430..a9878e6f 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -547,11 +547,11 @@
 </event>
 
 <event name="Blink.UpdateTime">
-  <owner>vmpstr@chromium.org</owner>
+  <owner>schenney@chromium.org</owner>
   <summary>
     Metrics that measure various update times in Blink. This includes paint,
-    compositing, and layout update times. The metrics are recorded once per
-    second and at the destruction of the local frame root.
+    compositing, and layout update times. The metrics are recorded once per 30
+    seconds and at the destruction of the local frame root.
   </summary>
   <metric name="Compositing.Average">
     <summary>
@@ -559,34 +559,87 @@
       event period.
     </summary>
   </metric>
+  <metric name="Compositing.AverageRatio">
+    <summary>
+      The average over frames within the sample window of the ratio of time
+      taken in the compositing phase to the total time for the main frame. An
+      int in the range [0,100].
+    </summary>
+  </metric>
   <metric name="Compositing.WorstCase">
     <summary>
       The longest single time taken by the compositing phase in microseconds in
       the event period.
     </summary>
   </metric>
+  <metric name="Compositing.WorstCaseRatio">
+    <summary>
+      The highest proportion of a frame ever used by the compositing phase
+      within the sample window. An int in the range [0,100].
+    </summary>
+  </metric>
   <metric name="CompositingCommit.Average">
     <summary>
       The average time taken by the compositing commit at the end of the blink
       lifecycle, in microseconds in the event period.
     </summary>
   </metric>
+  <metric name="CompositingCommit.AverageRatio">
+    <summary>
+      The average over frames within the sample window of the ratio of time
+      taken by the compositing commit at the end of the blink lifecycle to the
+      total time for the main frame. An int in the range [0,100].
+    </summary>
+  </metric>
   <metric name="CompositingCommit.WorstCase">
     <summary>
       The longest single time taken by the compositing commit at the end of the
       blink lifecycle, in microseconds in the event period.
     </summary>
   </metric>
+  <metric name="CompositingCommit.WorstCaseRatio">
+    <summary>
+      The highest proportion of a frame ever taken by the compositing commit at
+      the end of the blink lifecycle to the total time for the main frame. An
+      int in the range [0,100].
+    </summary>
+  </metric>
   <metric name="IntersectionObservation.Average">
     <summary>
       The average time taken to compute IntersectionObserver observations in
       microseconds in the event period.
     </summary>
   </metric>
+  <metric name="IntersectionObservation.AverageRatio">
+    <summary>
+      The average over frames within the sample window of the ratio of time
+      taken compute IntersectionObserver observations to the total time for the
+      main frame. An int in the range [0,100].
+    </summary>
+  </metric>
   <metric name="IntersectionObservation.WorstCase">
     <summary>
-      The longest single time taken by to compute IntersectionObserver
-      observations in microseconds in the event period.
+      The longest single time taken to compute IntersectionObserver observations
+      in microseconds in the event period.
+    </summary>
+  </metric>
+  <metric name="IntersectionObservation.WorstCaseRatio">
+    <summary>
+      The highest proportion of a frame ever taken to compute
+      IntersectionObserver observations within the sample window. An int in the
+      range [0,100].
+    </summary>
+  </metric>
+  <metric name="MainFrame.Average">
+    <summary>
+      The average time between a BeginMainFrame and the commit of paint results,
+      in microseconds.
+    </summary>
+  </metric>
+  <metric name="MainFrame.WorstCase">
+    <summary>
+      The longest single time between a BeginMainFrame and the commit of paint
+      results, in microseconds.
     </summary>
   </metric>
   <metric name="Paint.Average">
@@ -595,36 +648,75 @@
       period.
     </summary>
   </metric>
+  <metric name="Paint.AverageRatio">
+    <summary>
+      The average over frames within the sample window of the ratio of time
+      taken in the paint phase to the total time for the main frame. An int in
+      the range [0,100].
+    </summary>
+  </metric>
   <metric name="Paint.WorstCase">
     <summary>
       The longest single time taken by the paint phase in microseconds in the
       event period.
     </summary>
   </metric>
+  <metric name="Paint.WorstCaseRatio">
+    <summary>
+      The highest proportion of a frame ever used by the paint phase within the
+      sample window. An int in the range [0,100].
+    </summary>
+  </metric>
   <metric name="PrePaint.Average">
     <summary>
       The average time taken by the pre-paint phase in microseconds in the event
       period.
     </summary>
   </metric>
+  <metric name="PrePaint.AverageRatio">
+    <summary>
+      The average over frames within the sample window of the ratio of time
+      taken in the pre-paint phase to the total time for the main frame. An int
+      in the range [0,100].
+    </summary>
+  </metric>
   <metric name="PrePaint.WorstCase">
     <summary>
       The longest single time taken by the pre-paint phase in microseconds in
       the event period.
     </summary>
   </metric>
+  <metric name="PrePaint.WorstCaseRatio">
+    <summary>
+      The highest proportion of a frame ever used by the pre-paint phase within
+      the sample window. An int in the range [0,100].
+    </summary>
+  </metric>
   <metric name="StyleAndLayout.Average">
     <summary>
       The average time taken by the style and layout phases in microseconds in
       the event period.
     </summary>
   </metric>
+  <metric name="StyleAndLayout.AverageRatio">
+    <summary>
+      The average over frames within the sample window of the ratio of time
+      taken to update style and layout to the total time for the main frame. An
+      int in the range [0,100].
+    </summary>
+  </metric>
   <metric name="StyleAndLayout.WorstCase">
     <summary>
       The longest single time taken by the style and layout phases in
       microseconds in the event period.
     </summary>
   </metric>
+  <metric name="StyleAndLayout.WorstCaseRatio">
+    <summary>
+      The highest proportion of a frame ever used to compute style and layout
+      within the sample window. An int in the range [0,100].
+    </summary>
+  </metric>
 </event>
 
 <event name="Blink.UseCounter">
@@ -1478,6 +1570,21 @@
   </metric>
 </event>
 
+<event name="LookalikeUrl.NavigationSuggestion" singular="True">
+  <owner>meacer@chromium.org</owner>
+  <owner>cthomp@chromium.org</owner>
+  <summary>
+    Metrics recorded when a navigated URL's domain name is visually similar to a
+    popular domain or a domain that the user engaged with.
+  </summary>
+  <metric name="MatchType">
+    <summary>
+      An enum value representing the type of the match (popular domain, engaged
+      domain, etc.). The enum is defined in |LookalikeUrlNavigationObserver|.
+    </summary>
+  </metric>
+</event>
+
 <event name="Media.Autoplay.Attempt">
   <owner>mlamouri@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
@@ -2845,6 +2952,12 @@
       provisional navigations.
     </summary>
   </metric>
+  <metric name="Net.HttpResponseCode">
+    <summary>
+      The HTTP response code (e.g., 200, 404, etc.) associated with the main
+      frame page load.
+    </summary>
+  </metric>
   <metric name="Net.HttpRttEstimate.OnNavigationStart">
     <summary>
       The HTTP round trip time estimate for this page load, at the time the
diff --git a/ui/accelerated_widget_mac/display_link_mac.cc b/ui/accelerated_widget_mac/display_link_mac.cc
index a209810..81de0b1 100644
--- a/ui/accelerated_widget_mac/display_link_mac.cc
+++ b/ui/accelerated_widget_mac/display_link_mac.cc
@@ -31,6 +31,36 @@
 
 namespace ui {
 
+using DisplayLinkMap = std::map<CGDirectDisplayID, DisplayLinkMac*>;
+
+namespace {
+
+// The task runner to post tasks to from the display link thread. Note that this
+// is initialized with the very first DisplayLinkMac instance, and is never
+// changed (even, e.g, in tests that re-initialize the main thread task runner).
+// https://885329
+scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner() {
+  static scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      base::ThreadTaskRunnerHandle::Get();
+  return task_runner;
+}
+
+// Each display link instance consumes a non-negligible number of cycles, so
+// make all display links on the same screen share the same object.
+//
+// Note that this is a weak map, holding non-owning pointers to the
+// DisplayLinkMac objects. DisplayLinkMac is a ref-counted class, and is
+// jointly owned by the various callers that got a copy by calling
+// GetForDisplay().
+//
+// ** This map may only be accessed from the main thread. **
+DisplayLinkMap& GetAllDisplayLinks() {
+  static base::NoDestructor<DisplayLinkMap> all_display_links;
+  return *all_display_links;
+}
+
+}  // namespace
+
 // static
 scoped_refptr<DisplayLinkMac> DisplayLinkMac::GetForDisplay(
     CGDirectDisplayID display_id) {
@@ -193,21 +223,6 @@
 }
 
 // static
-DisplayLinkMac::DisplayLinkMap& DisplayLinkMac::GetAllDisplayLinks() {
-  DCHECK_EQ(base::ThreadTaskRunnerHandle::Get(), GetMainThreadTaskRunner());
-  static base::NoDestructor<DisplayLinkMac::DisplayLinkMap> all_display_links;
-  return *all_display_links;
-}
-
-// static
-scoped_refptr<base::SingleThreadTaskRunner>
-DisplayLinkMac::GetMainThreadTaskRunner() {
-  static scoped_refptr<base::SingleThreadTaskRunner> task_runner =
-      base::ThreadTaskRunnerHandle::Get();
-  return task_runner;
-}
-
-// static
 CVReturn DisplayLinkMac::DisplayLinkCallback(
     CVDisplayLinkRef display_link,
     const CVTimeStamp* now,
diff --git a/ui/accelerated_widget_mac/display_link_mac.h b/ui/accelerated_widget_mac/display_link_mac.h
index 2fce897..b552163 100644
--- a/ui/accelerated_widget_mac/display_link_mac.h
+++ b/ui/accelerated_widget_mac/display_link_mac.h
@@ -14,10 +14,6 @@
 #include "base/time/time.h"
 #include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace ui {
 
 class ACCELERATED_WIDGET_MAC_EXPORT DisplayLinkMac
@@ -52,20 +48,6 @@
   // Processes the display link callback.
   void UpdateVSyncParameters(const CVTimeStamp& time);
 
-  // Each display link instance consumes a non-negligible number of cycles, so
-  // make all display links on the same screen share the same object. This map
-  // must only be changed from the main thread.
-  //
-  // Note that this is a weak map, holding non-owning pointers to the
-  // DisplayLinkMac objects. DisplayLinkMac is a ref-counted class, and is
-  // jointly owned by the various callers that got a copy by calling
-  // GetForDisplay().
-  using DisplayLinkMap = std::map<CGDirectDisplayID, DisplayLinkMac*>;
-  static DisplayLinkMap& GetAllDisplayLinks();
-
-  // The task runner to post tasks to from the display link thread.
-  static scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner();
-
   // Called by the system on the display link thread, and posts a call to
   // DoUpdateVSyncParameters() to the UI thread.
   static CVReturn DisplayLinkCallback(
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 8cb1b77..90158da 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -905,7 +905,7 @@
       "ime/win/tsf_text_store_unittest.cc",
     ]
     if (is_linux && use_aura && !is_chromeos) {
-      if (use_x11) {
+      if (use_x11 || use_ozone) {
         sources += [ "ime/input_method_auralinux_unittest.cc" ]
       } else {
         sources += [ "ime/input_method_minimal_unittest.cc" ]
diff --git a/ui/base/ime/input_method_auralinux.cc b/ui/base/ime/input_method_auralinux.cc
index 6997920..90a806a 100644
--- a/ui/base/ime/input_method_auralinux.cc
+++ b/ui/base/ime/input_method_auralinux.cc
@@ -275,6 +275,14 @@
   NotifyTextInputCaretBoundsChanged(client);
   context_->SetCursorLocation(GetTextInputClient()->GetCaretBounds());
 
+  gfx::Range text_range, selection_range;
+  base::string16 text;
+  if (client->GetTextRange(&text_range) &&
+      client->GetTextFromRange(text_range, &text) &&
+      client->GetSelectionRange(&selection_range)) {
+    context_->SetSurroundingText(text, selection_range);
+  }
+
   if (!IsTextInputTypeNone() && text_input_type_ != TEXT_INPUT_TYPE_PASSWORD &&
       GetEngine())
     GetEngine()->SetCompositionBounds(GetCompositionBounds(client));
@@ -307,13 +315,6 @@
   context_->Reset();
   context_simple_->Reset();
 
-  // Some input methods may not honour the reset call. Focusing out/in the
-  // |context_| to make sure it gets reset correctly.
-  if (text_input_type_ != TEXT_INPUT_TYPE_NONE) {
-    context_->Blur();
-    context_->Focus();
-  }
-
   composition_ = CompositionText();
   result_text_.clear();
   is_sync_mode_ = false;
@@ -353,6 +354,14 @@
   }
 }
 
+void InputMethodAuraLinux::OnDeleteSurroundingText(int32_t index,
+                                                   uint32_t length) {
+  if (GetTextInputClient() && composition_.text.empty()) {
+    uint32_t before = index >= 0 ? 0U : static_cast<uint32_t>(-1 * index);
+    GetTextInputClient()->ExtendSelectionAndDelete(before, length - before);
+  }
+}
+
 void InputMethodAuraLinux::OnPreeditChanged(
     const CompositionText& composition_text) {
   if (IgnoringNonKeyInput() || IsTextInputTypeNone())
diff --git a/ui/base/ime/input_method_auralinux.h b/ui/base/ime/input_method_auralinux.h
index ef4985b..8963ab9 100644
--- a/ui/base/ime/input_method_auralinux.h
+++ b/ui/base/ime/input_method_auralinux.h
@@ -35,6 +35,7 @@
 
   // Overriden from ui::LinuxInputMethodContextDelegate
   void OnCommit(const base::string16& text) override;
+  void OnDeleteSurroundingText(int32_t index, uint32_t length) override;
   void OnPreeditChanged(const CompositionText& composition_text) override;
   void OnPreeditEnd() override;
   void OnPreeditStart() override {}
diff --git a/ui/base/ime/input_method_auralinux_unittest.cc b/ui/base/ime/input_method_auralinux_unittest.cc
index 7424f5f..23e6be6 100644
--- a/ui/base/ime/input_method_auralinux_unittest.cc
+++ b/ui/base/ime/input_method_auralinux_unittest.cc
@@ -125,6 +125,19 @@
     cursor_position_ = rect;
   }
 
+  void SetSurroundingText(const base::string16& text,
+                          const gfx::Range& selection_range) override {
+    TestResult::GetInstance()->RecordAction(
+        base::ASCIIToUTF16("surroundingtext:") + text);
+
+    std::stringstream rs;
+    rs << "selectionrangestart:" << selection_range.start();
+    std::stringstream re;
+    re << "selectionrangeend:" << selection_range.end();
+    TestResult::GetInstance()->RecordAction(base::ASCIIToUTF16(rs.str()));
+    TestResult::GetInstance()->RecordAction(base::ASCIIToUTF16(re.str()));
+  };
+
  private:
   LinuxInputMethodContextDelegate* delegate_;
   std::vector<base::string16> actions_;
@@ -187,6 +200,9 @@
       : DummyTextInputClient(text_input_type){};
 
   base::string16 composition_text;
+  gfx::Range text_range;
+  gfx::Range selection_range;
+  base::string16 surrounding_text;
 
  protected:
   void SetCompositionText(const CompositionText& composition) override {
@@ -229,6 +245,22 @@
     TestResult::GetInstance()->RecordAction(base::ASCIIToUTF16("keypress:") +
                                             base::ASCIIToUTF16(ss.str()));
   }
+
+  bool GetTextRange(gfx::Range* range) const override {
+    *range = text_range;
+    return true;
+  }
+  bool GetSelectionRange(gfx::Range* range) const override {
+    *range = selection_range;
+    return true;
+  }
+  bool GetTextFromRange(const gfx::Range& range,
+                        base::string16* text) const override {
+    if (surrounding_text.empty())
+      return false;
+    *text = surrounding_text.substr(range.GetMin(), range.length());
+    return true;
+  }
 };
 
 class InputMethodAuraLinuxTest : public testing::Test {
@@ -760,5 +792,59 @@
   test_result_->Verify();
 }
 
+TEST_F(InputMethodAuraLinuxTest, SurroundingText_NoSelectionTest) {
+  std::unique_ptr<TextInputClientForTesting> client(
+      new TextInputClientForTesting(TEXT_INPUT_TYPE_TEXT));
+  input_method_auralinux_->SetFocusedTextInputClient(client.get());
+  input_method_auralinux_->OnTextInputTypeChanged(client.get());
+
+  client->surrounding_text = base::ASCIIToUTF16("abcdef");
+  client->text_range = gfx::Range(0, 6);
+  client->selection_range = gfx::Range(3, 3);
+
+  input_method_auralinux_->OnCaretBoundsChanged(client.get());
+
+  test_result_->ExpectAction("surroundingtext:abcdef");
+  test_result_->ExpectAction("selectionrangestart:3");
+  test_result_->ExpectAction("selectionrangeend:3");
+  test_result_->Verify();
+}
+
+TEST_F(InputMethodAuraLinuxTest, SurroundingText_SelectionTest) {
+  std::unique_ptr<TextInputClientForTesting> client(
+      new TextInputClientForTesting(TEXT_INPUT_TYPE_TEXT));
+  input_method_auralinux_->SetFocusedTextInputClient(client.get());
+  input_method_auralinux_->OnTextInputTypeChanged(client.get());
+
+  client->surrounding_text = base::ASCIIToUTF16("abcdef");
+  client->text_range = gfx::Range(0, 6);
+  client->selection_range = gfx::Range(2, 5);
+
+  input_method_auralinux_->OnCaretBoundsChanged(client.get());
+
+  test_result_->ExpectAction("surroundingtext:abcdef");
+  test_result_->ExpectAction("selectionrangestart:2");
+  test_result_->ExpectAction("selectionrangeend:5");
+  test_result_->Verify();
+}
+
+TEST_F(InputMethodAuraLinuxTest, SurroundingText_PartialText) {
+  std::unique_ptr<TextInputClientForTesting> client(
+      new TextInputClientForTesting(TEXT_INPUT_TYPE_TEXT));
+  input_method_auralinux_->SetFocusedTextInputClient(client.get());
+  input_method_auralinux_->OnTextInputTypeChanged(client.get());
+
+  client->surrounding_text = base::ASCIIToUTF16("abcdefghij");
+  client->text_range = gfx::Range(5, 10);
+  client->selection_range = gfx::Range(7, 9);
+
+  input_method_auralinux_->OnCaretBoundsChanged(client.get());
+
+  test_result_->ExpectAction("surroundingtext:fghij");
+  test_result_->ExpectAction("selectionrangestart:7");
+  test_result_->ExpectAction("selectionrangeend:9");
+  test_result_->Verify();
+}
+
 }  // namespace
 }  // namespace ui
diff --git a/ui/base/ime/input_method_factory.cc b/ui/base/ime/input_method_factory.cc
index 5a7a623..2cd9b79 100644
--- a/ui/base/ime/input_method_factory.cc
+++ b/ui/base/ime/input_method_factory.cc
@@ -20,7 +20,7 @@
 #include "ui/base/ime/input_method_mac.h"
 #elif defined(OS_FUCHSIA)
 #include "ui/base/ime/input_method_fuchsia.h"
-#elif defined(USE_AURA) && defined(USE_X11)
+#elif defined(USE_AURA) && (defined(USE_X11) || defined(USE_OZONE))
 #include "ui/base/ime/input_method_auralinux.h"
 #else
 #include "ui/base/ime/input_method_minimal.h"
@@ -66,7 +66,7 @@
   return std::make_unique<InputMethodMac>(delegate);
 #elif defined(OS_FUCHSIA)
   return std::make_unique<InputMethodFuchsia>(delegate);
-#elif defined(USE_AURA) && defined(USE_X11)
+#elif defined(USE_AURA) && (defined(USE_X11) || defined(USE_OZONE))
   return std::make_unique<InputMethodAuraLinux>(delegate);
 #else
   return std::make_unique<InputMethodMinimal>(delegate);
diff --git a/ui/base/ime/input_method_win_imm32.cc b/ui/base/ime/input_method_win_imm32.cc
index 162cf77..723408b 100644
--- a/ui/base/ime/input_method_win_imm32.cc
+++ b/ui/base/ime/input_method_win_imm32.cc
@@ -89,6 +89,7 @@
 
 void InputMethodWinImm32::OnTextInputTypeChanged(
     const TextInputClient* client) {
+  InputMethodBase::OnTextInputTypeChanged(client);
   if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
     return;
   imm32_manager_.CancelIME(toplevel_window_handle_);
diff --git a/ui/base/ime/input_method_win_tsf.cc b/ui/base/ime/input_method_win_tsf.cc
index 5e723f1..0bc1842 100644
--- a/ui/base/ime/input_method_win_tsf.cc
+++ b/ui/base/ime/input_method_win_tsf.cc
@@ -79,6 +79,7 @@
 }
 
 void InputMethodWinTSF::OnTextInputTypeChanged(const TextInputClient* client) {
+  InputMethodBase::OnTextInputTypeChanged(client);
   if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
     return;
   ui::TSFBridge::GetInstance()->CancelComposition();
diff --git a/ui/base/ime/linux/fake_input_method_context.cc b/ui/base/ime/linux/fake_input_method_context.cc
index 5053aa1..c6c04798 100644
--- a/ui/base/ime/linux/fake_input_method_context.cc
+++ b/ui/base/ime/linux/fake_input_method_context.cc
@@ -27,4 +27,9 @@
 void FakeInputMethodContext::SetCursorLocation(const gfx::Rect& rect) {
 }
 
+void FakeInputMethodContext::SetSurroundingText(
+    const base::string16& text,
+    const gfx::Range& selection_range) {
+}
+
 }  // namespace ui
diff --git a/ui/base/ime/linux/fake_input_method_context.h b/ui/base/ime/linux/fake_input_method_context.h
index ec9ac7e4..0fd8fdf5 100644
--- a/ui/base/ime/linux/fake_input_method_context.h
+++ b/ui/base/ime/linux/fake_input_method_context.h
@@ -21,6 +21,8 @@
   void Focus() override;
   void Blur() override;
   void SetCursorLocation(const gfx::Rect& rect) override;
+  void SetSurroundingText(const base::string16& text,
+                          const gfx::Range& selection_range) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeInputMethodContext);
diff --git a/ui/base/ime/linux/linux_input_method_context.h b/ui/base/ime/linux/linux_input_method_context.h
index 4fbaebc..ca80623 100644
--- a/ui/base/ime/linux/linux_input_method_context.h
+++ b/ui/base/ime/linux/linux_input_method_context.h
@@ -11,7 +11,8 @@
 
 namespace gfx {
 class Rect;
-}
+class Range;
+}  // namespace gfx
 
 namespace ui {
 
@@ -33,6 +34,10 @@
   // client window rect.
   virtual void SetCursorLocation(const gfx::Rect& rect) = 0;
 
+  // Tells the system IME the surrounding text around the cursor location.
+  virtual void SetSurroundingText(const base::string16& text,
+                                  const gfx::Range& selection_range) = 0;
+
   // Resets the context.  A client needs to call OnTextInputTypeChanged() again
   // before calling DispatchKeyEvent().
   virtual void Reset() = 0;
@@ -52,6 +57,9 @@
   // Commits the |text| to the text input client.
   virtual void OnCommit(const base::string16& text) = 0;
 
+  // Deletes the surrounding text at |index| for given |length|.
+  virtual void OnDeleteSurroundingText(int32_t index, uint32_t length) = 0;
+
   // Sets the composition text to the text input client.
   virtual void OnPreeditChanged(const CompositionText& composition_text) = 0;
 
diff --git a/ui/chromeos/events/event_rewriter_chromeos.cc b/ui/chromeos/events/event_rewriter_chromeos.cc
index 5607e96..11552015 100644
--- a/ui/chromeos/events/event_rewriter_chromeos.cc
+++ b/ui/chromeos/events/event_rewriter_chromeos.cc
@@ -302,7 +302,8 @@
       return EventRewriterChromeOS::kDeviceAppleKeyboard;
   }
 
-  if (!found_apple && keyboard_device.type == INPUT_DEVICE_EXTERNAL) {
+  if (!found_apple && (keyboard_device.type == INPUT_DEVICE_USB ||
+                       keyboard_device.type == INPUT_DEVICE_BLUETOOTH)) {
     // ui::InputDevice is a generic input device, and we're not sure if it's
     // actually a keyboard.
     return found_keyboard
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index bcbdfc13a..92ed2ff0 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -407,6 +407,7 @@
   void DidPresentCompositorFrame(
       uint32_t frame_token,
       const gfx::PresentationFeedback& feedback) override {}
+  void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override {}
 
   // cc::LayerTreeHostSingleThreadClient implementation.
   void DidSubmitCompositorFrame() override;
diff --git a/ui/display/manager/touch_device_manager.cc b/ui/display/manager/touch_device_manager.cc
index b71cfa5..41606b4e 100644
--- a/ui/display/manager/touch_device_manager.cc
+++ b/ui/display/manager/touch_device_manager.cc
@@ -715,8 +715,10 @@
 bool HasExternalTouchscreenDevice() {
   for (const auto& device :
        ui::InputDeviceManager::GetInstance()->GetTouchscreenDevices()) {
-    if (device.type == ui::InputDeviceType::INPUT_DEVICE_EXTERNAL)
+    if (device.type == ui::InputDeviceType::INPUT_DEVICE_USB ||
+        device.type == ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH) {
       return true;
+    }
   }
   return false;
 }
diff --git a/ui/display/manager/touch_device_manager_unittest.cc b/ui/display/manager/touch_device_manager_unittest.cc
index acc60f5..54c57f5 100644
--- a/ui/display/manager/touch_device_manager_unittest.cc
+++ b/ui/display/manager/touch_device_manager_unittest.cc
@@ -142,7 +142,7 @@
   std::vector<ui::TouchscreenDevice> devices;
   for (int i = 0; i < 5; ++i) {
     devices.push_back(CreateTouchscreenDevice(
-        i, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(256, 256)));
+        i, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(256, 256)));
   }
 
   DisplayInfoList displays;
@@ -159,9 +159,9 @@
 TEST_F(TouchAssociationTest, OneToOneMapping) {
   std::vector<ui::TouchscreenDevice> devices;
   devices.push_back(CreateTouchscreenDevice(
-      1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(800, 600)));
+      1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(800, 600)));
   devices.push_back(CreateTouchscreenDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1024, 768)));
+      2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1024, 768)));
 
   test::ScopedSetInternalDisplayId set_internal(display_manager(),
                                                 displays_[0].id());
@@ -178,7 +178,7 @@
 TEST_F(TouchAssociationTest, MapToCorrectDisplaySize) {
   std::vector<ui::TouchscreenDevice> devices;
   devices.push_back(CreateTouchscreenDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1024, 768)));
+      2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1024, 768)));
 
   test::ScopedSetInternalDisplayId set_internal(display_manager(),
                                                 displays_[0].id());
@@ -194,9 +194,9 @@
 TEST_F(TouchAssociationTest, MapWhenSizeDiffersByOne) {
   std::vector<ui::TouchscreenDevice> devices;
   devices.push_back(CreateTouchscreenDevice(
-      1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(801, 600)));
+      1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(801, 600)));
   devices.push_back(CreateTouchscreenDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1023, 768)));
+      2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1023, 768)));
 
   test::ScopedSetInternalDisplayId set_internal(display_manager(),
                                                 displays_[0].id());
@@ -213,9 +213,9 @@
 TEST_F(TouchAssociationTest, MapWhenSizesDoNotMatch) {
   std::vector<ui::TouchscreenDevice> devices;
   devices.push_back(CreateTouchscreenDevice(
-      1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1022, 768)));
+      1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1022, 768)));
   devices.push_back(CreateTouchscreenDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(802, 600)));
+      2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(802, 600)));
 
   DisplayInfoList displays;
   displays.push_back(displays_[0]);
@@ -236,7 +236,7 @@
 TEST_F(TouchAssociationTest, MapInternalTouchscreen) {
   std::vector<ui::TouchscreenDevice> devices;
   devices.push_back(CreateTouchscreenDevice(
-      1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080)));
+      1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080)));
   devices.push_back(CreateTouchscreenDevice(
       2, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(9999, 888)));
 
@@ -279,7 +279,7 @@
   devices.push_back(CreateTouchscreenDevice(
       2, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(1920, 1080)));
   devices.push_back(CreateTouchscreenDevice(
-      3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1024, 768)));
+      3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1024, 768)));
 
   test::ScopedSetInternalDisplayId set_internal(display_manager(),
                                                 displays_[0].id());
@@ -298,7 +298,7 @@
 TEST_F(TouchAssociationTest, TestWithNoInternalDisplay) {
   std::vector<ui::TouchscreenDevice> devices;
   devices.push_back(CreateTouchscreenDevice(
-      1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080)));
+      1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080)));
   devices.push_back(CreateTouchscreenDevice(
       2, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(9999, 888)));
 
@@ -315,11 +315,11 @@
 TEST_F(TouchAssociationTest, MatchRemainingDevicesToInternalDisplay) {
   std::vector<ui::TouchscreenDevice> devices;
   devices.push_back(CreateTouchscreenDevice(
-      1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(123, 456)));
+      1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(123, 456)));
   devices.push_back(CreateTouchscreenDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(234, 567)));
+      2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(234, 567)));
   devices.push_back(CreateTouchscreenDevice(
-      3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(345, 678)));
+      3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(345, 678)));
 
   test::ScopedSetInternalDisplayId set_internal(display_manager(),
                                                 displays_[0].id());
@@ -338,11 +338,11 @@
        MatchRemainingDevicesWithNoInternalDisplayPresent) {
   std::vector<ui::TouchscreenDevice> devices;
   devices.push_back(CreateTouchscreenDevice(
-      1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(123, 456)));
+      1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(123, 456)));
   devices.push_back(CreateTouchscreenDevice(
-      2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(234, 567)));
+      2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(234, 567)));
   devices.push_back(CreateTouchscreenDevice(
-      3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(345, 678)));
+      3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(345, 678)));
 
   touch_device_manager()->AssociateTouchscreens(&displays_, devices);
 
@@ -364,11 +364,11 @@
     TouchDeviceManager::TouchAssociationMap touch_associations;
 
     devices_.push_back(CreateTouchscreenDevice(
-        1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080)));
+        1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080)));
     devices_.push_back(CreateTouchscreenDevice(
-        2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1024, 768)));
+        2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1024, 768)));
     devices_.push_back(CreateTouchscreenDevice(
-        3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(640, 480)));
+        3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(640, 480)));
     devices_.push_back(CreateTouchscreenDevice(
         4, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(800, 600)));
 
@@ -600,7 +600,7 @@
 
     // Create a device with name |device_name_1| connected to |ports[0]|.
     devices_.push_back(CreateTouchscreenDevice(
-        1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080)));
+        1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080)));
     devices_.back().name = device_name_1;
     devices_.back().phys = ports[0];
 
@@ -608,7 +608,7 @@
     int product_id = devices_.back().product_id;
 
     devices_.push_back(CreateTouchscreenDevice(
-        2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080)));
+        2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080)));
 
     // Create another device with the same name but different port. Ensure that
     // the touch device idnetifier is the same by setting the same vendor id,
@@ -619,7 +619,7 @@
     devices_.back().product_id = product_id;
 
     devices_.push_back(CreateTouchscreenDevice(
-        3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080)));
+        3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080)));
     devices_.back().name = device_name_1;
     devices_.back().phys = ports[2];
     devices_.back().vendor_id = vendor_id;
@@ -629,7 +629,7 @@
         4, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(800, 600)));
 
     devices_.push_back(CreateTouchscreenDevice(
-        5, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(4096, 4096)));
+        5, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(4096, 4096)));
     devices_.back().name = device_name_2;
     devices_.back().phys = ports[3];
 
@@ -637,7 +637,7 @@
     product_id = devices_.back().product_id;
 
     devices_.push_back(CreateTouchscreenDevice(
-        6, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(4096, 4096)));
+        6, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(4096, 4096)));
     devices_.back().name = device_name_2;
     devices_.back().phys = ports[4];
     devices_.back().vendor_id = vendor_id;
diff --git a/ui/display/manager/touch_transform_controller_unittest.cc b/ui/display/manager/touch_transform_controller_unittest.cc
index 131bb54..ba7cdd1 100644
--- a/ui/display/manager/touch_transform_controller_unittest.cc
+++ b/ui/display/manager/touch_transform_controller_unittest.cc
@@ -41,7 +41,7 @@
 
 ui::TouchscreenDevice CreateTouchscreenDevice(unsigned int id,
                                               const gfx::Size& size) {
-  return ui::TouchscreenDevice(id, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL,
+  return ui::TouchscreenDevice(id, ui::InputDeviceType::INPUT_DEVICE_USB,
                                std::string(), size, 0);
 }
 
diff --git a/ui/events/devices/device_util_linux.cc b/ui/events/devices/device_util_linux.cc
index 2d703f5..d81d3a8 100644
--- a/ui/events/devices/device_util_linux.cc
+++ b/ui/events/devices/device_util_linux.cc
@@ -37,8 +37,9 @@
        path = path.DirName()) {
     // Bluetooth LE devices are virtual "uhid" devices.
     if (path ==
-        base::FilePath(FILE_PATH_LITERAL("/sys/devices/virtual/misc/uhid")))
-      return InputDeviceType::INPUT_DEVICE_EXTERNAL;
+        base::FilePath(FILE_PATH_LITERAL("/sys/devices/virtual/misc/uhid"))) {
+      return InputDeviceType::INPUT_DEVICE_BLUETOOTH;
+    }
 
     std::string subsystem_path =
         base::MakeAbsoluteFilePath(path.Append(FILE_PATH_LITERAL("subsystem")))
@@ -60,9 +61,9 @@
 
     // External bus attachments.
     if (subsystem_path == "/sys/bus/usb")
-      return InputDeviceType::INPUT_DEVICE_EXTERNAL;
+      return InputDeviceType::INPUT_DEVICE_USB;
     if (subsystem_path == "/sys/class/bluetooth")
-      return InputDeviceType::INPUT_DEVICE_EXTERNAL;
+      return InputDeviceType::INPUT_DEVICE_BLUETOOTH;
   }
 
   return InputDeviceType::INPUT_DEVICE_UNKNOWN;
diff --git a/ui/events/devices/input_device.h b/ui/events/devices/input_device.h
index f97154d9..2e0da79 100644
--- a/ui/events/devices/input_device.h
+++ b/ui/events/devices/input_device.h
@@ -14,9 +14,10 @@
 namespace ui {
 
 enum InputDeviceType {
-  INPUT_DEVICE_INTERNAL,  // Internally connected input device.
-  INPUT_DEVICE_EXTERNAL,  // Known externally connected input device.
-  INPUT_DEVICE_UNKNOWN,   // Device that may or may not be an external device.
+  INPUT_DEVICE_INTERNAL,   // Internally connected input device.
+  INPUT_DEVICE_USB,        // Known externally connected usb input device.
+  INPUT_DEVICE_BLUETOOTH,  // Known externally connected bluetooth input device.
+  INPUT_DEVICE_UNKNOWN,    // Device that may or may not be an external device.
 };
 
 // Represents an input device state.
diff --git a/ui/events/devices/mojo/input_device_struct_traits.cc b/ui/events/devices/mojo/input_device_struct_traits.cc
index b7e005c..edae74a 100644
--- a/ui/events/devices/mojo/input_device_struct_traits.cc
+++ b/ui/events/devices/mojo/input_device_struct_traits.cc
@@ -15,8 +15,10 @@
   switch (type) {
     case ui::INPUT_DEVICE_INTERNAL:
       return ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL;
-    case ui::INPUT_DEVICE_EXTERNAL:
-      return ui::mojom::InputDeviceType::INPUT_DEVICE_EXTERNAL;
+    case ui::INPUT_DEVICE_USB:
+      return ui::mojom::InputDeviceType::INPUT_DEVICE_USB;
+    case ui::INPUT_DEVICE_BLUETOOTH:
+      return ui::mojom::InputDeviceType::INPUT_DEVICE_BLUETOOTH;
     case ui::INPUT_DEVICE_UNKNOWN:
       return ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN;
   }
@@ -31,8 +33,11 @@
     case ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL:
       *output = ui::INPUT_DEVICE_INTERNAL;
       break;
-    case ui::mojom::InputDeviceType::INPUT_DEVICE_EXTERNAL:
-      *output = ui::INPUT_DEVICE_EXTERNAL;
+    case ui::mojom::InputDeviceType::INPUT_DEVICE_USB:
+      *output = ui::INPUT_DEVICE_USB;
+      break;
+    case ui::mojom::InputDeviceType::INPUT_DEVICE_BLUETOOTH:
+      *output = ui::INPUT_DEVICE_BLUETOOTH;
       break;
     case ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN:
       *output = ui::INPUT_DEVICE_UNKNOWN;
diff --git a/ui/events/devices/mojo/input_devices.mojom b/ui/events/devices/mojo/input_devices.mojom
index c9f60f6..2671cec 100644
--- a/ui/events/devices/mojo/input_devices.mojom
+++ b/ui/events/devices/mojo/input_devices.mojom
@@ -9,7 +9,8 @@
 // Corresponds to ui::InputDeviceType
 enum InputDeviceType {
   INPUT_DEVICE_INTERNAL,
-  INPUT_DEVICE_EXTERNAL,
+  INPUT_DEVICE_USB,
+  INPUT_DEVICE_BLUETOOTH,
   INPUT_DEVICE_UNKNOWN,
 };
 
diff --git a/ui/events/ozone/evdev/event_device_test_util.cc b/ui/events/ozone/evdev/event_device_test_util.cc
index 86feff7..e72c4e7b 100644
--- a/ui/events/ozone/evdev/event_device_test_util.cc
+++ b/ui/events/ozone/evdev/event_device_test_util.cc
@@ -634,7 +634,7 @@
       return ui::InputDeviceType::INPUT_DEVICE_INTERNAL;
     case BUS_USB:
     case 0x1D:  // Used in kLogitechTouchKeyboardK400 but not listed in input.h.
-      return ui::InputDeviceType::INPUT_DEVICE_EXTERNAL;
+      return ui::InputDeviceType::INPUT_DEVICE_USB;
     default:
       NOTREACHED() << "Unexpected bus type";
       return ui::InputDeviceType::INPUT_DEVICE_UNKNOWN;
diff --git a/ui/latency/frame_metrics.cc b/ui/latency/frame_metrics.cc
index 99bdf25..27f26b9 100644
--- a/ui/latency/frame_metrics.cc
+++ b/ui/latency/frame_metrics.cc
@@ -8,6 +8,7 @@
 #include <limits>
 #include <vector>
 
+#include "base/bit_cast.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 
@@ -389,6 +390,27 @@
   latency_acceleration_analyzer_.StartNewReportPeriod();
 }
 
+double FrameMetrics::FastApproximateSqrt(double x) {
+  if (x <= 0)
+    return 0;
+  // Basically performs x*fastinvSqrt(x) - using high precision (3 steps)
+  double y = x;
+  double xhalf = 0.5f * x;
+  float xf = static_cast<float>(x);
+  int32_t i = bit_cast<int32_t>(xf);
+  // Magic Number for initial guess. Reference:
+  // http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf.
+  i = 0x5f3759df - (i >> 1);
+  x = static_cast<double>(bit_cast<float>(i));
+  // Newton step.
+  x = x * (1.5 - xhalf * x * x);
+  // Newton step.
+  x = x * (1.5 - xhalf * x * x);
+  // Newton step.
+  x = x * (1.5 - xhalf * x * x);
+  return y * x;
+}
+
 namespace {
 
 // FrameMetricsTraceData delegates tracing logic to TracedValue in a deferred
diff --git a/ui/latency/frame_metrics.h b/ui/latency/frame_metrics.h
index 221c11f..d0f6f35 100644
--- a/ui/latency/frame_metrics.h
+++ b/ui/latency/frame_metrics.h
@@ -146,6 +146,14 @@
   void AddFrameDisplayed(base::TimeTicks source_timestamp,
                          base::TimeTicks display_timestamp);
 
+  // Compute the square root by using method described in paper:
+  // http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf.
+  // It finds a result within 0.0001 and 0.1 of the true square root for |x| <
+  // 100 and |x| < 2^15 respectively. It's more than 2 times faster for Nexus 4
+  // and other lower end android devices and ~3-5% faster on desktop. Crash when
+  // x is less than 0.
+  static double FastApproximateSqrt(double x);
+
  protected:
   void TraceStats() const;
 
diff --git a/ui/latency/frame_metrics_test_common.h b/ui/latency/frame_metrics_test_common.h
index 30ed36d9..5ee17c4 100644
--- a/ui/latency/frame_metrics_test_common.h
+++ b/ui/latency/frame_metrics_test_common.h
@@ -15,10 +15,8 @@
 // Some convenience macros for checking expected error.
 #define EXPECT_ABS_LT(a, b) EXPECT_LT(std::abs(a), std::abs(b))
 #define EXPECT_ABS_LE(a, b) EXPECT_LE(std::abs(a), std::abs(b))
-#define EXPECT_NEAR_SMR(expected, actual, weight) \
-  EXPECT_NEAR(expected, actual, MaxErrorSMR(expected, weight))
-#define EXPECT_NEAR_VARIANCE_OF_ROOT(expected, actual, mean, weight) \
-  EXPECT_NEAR(expected, actual, MaxErrorSMR(mean, weight));
+#define EXPECT_NEAR_SQRT_APPROX(expected, actual) \
+  EXPECT_NEAR(expected, actual, MaxErrorSQRTApprox(expected, actual))
 
 namespace ui {
 namespace frame_metrics {
@@ -84,8 +82,8 @@
 // between ~5 and ~13 decimal places.
 // The precision should be even better when the sample's |weight| > 1 since
 // the implementation should only do any rounding after scaling by weight.
-inline double MaxErrorSMR(double expected_value, uint64_t weight) {
-  return std::max(.5, 1e-8 * expected_value / weight);
+inline double MaxErrorSQRTApprox(double expected_value, double value) {
+  return std::max(0.5, std::max(expected_value, value) * 1e-3);
 }
 
 // This class initializes the ratio boundaries on construction in a way that
diff --git a/ui/latency/frame_metrics_unittest.cc b/ui/latency/frame_metrics_unittest.cc
index 8306e93..55f43a7a 100644
--- a/ui/latency/frame_metrics_unittest.cc
+++ b/ui/latency/frame_metrics_unittest.cc
@@ -5,6 +5,7 @@
 #include "ui/latency/frame_metrics.h"
 
 #include "base/bind.h"
+#include "base/rand_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #include "ui/latency/frame_metrics_test_common.h"
@@ -240,15 +241,13 @@
 
   TestStreamAnalysis r = LatencyAnalysis();
   EXPECT_DOUBLE_EQ(latency.InSecondsF(), r.mean);
-  EXPECT_DOUBLE_EQ(latency.InSecondsF(), r.rms);
-  EXPECT_NEAR_SMR(r.smr, latency.InSecondsF(), produced.InMicroseconds());
+  EXPECT_NEAR_SQRT_APPROX(latency.InSecondsF(), r.rms);
+  EXPECT_NEAR_SQRT_APPROX(r.smr, latency.InSecondsF());
   EXPECT_EQ(0, r.std_dev);
-  EXPECT_NEAR_VARIANCE_OF_ROOT(0, r.variance_of_roots, 0,
-                               produced.InMicroseconds());
+  EXPECT_NEAR_SQRT_APPROX(0, r.variance_of_roots);
   EXPECT_DOUBLE_EQ(latency.InSecondsF(), r.worst_mean.value);
-  EXPECT_DOUBLE_EQ(latency.InSecondsF(), r.worst_rms.value);
-  EXPECT_NEAR_SMR(r.worst_smr.value, latency.InSecondsF(),
-                  produced.InMicroseconds());
+  EXPECT_NEAR_SQRT_APPROX(latency.InSecondsF(), r.worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(r.worst_smr.value, latency.InSecondsF());
 }
 
 // Apply a saw tooth pattern to the frame skips with values that are easy to
@@ -276,8 +275,8 @@
   const double expected_skip_to_produce_rms =
       std::sqrt(expected_skip_to_produce_mean_square);
   const double expected_skip_rms = SkipTransform(expected_skip_to_produce_rms);
-  EXPECT_EQ(expected_skip_rms, r.rms);
-  EXPECT_EQ(expected_skip_rms, r.worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_skip_rms, r.rms);
+  EXPECT_NEAR_SQRT_APPROX(expected_skip_rms, r.worst_rms.value);
 
   const double expected_expected_skip_to_produce_mean_root = (0 + 1.0) / 2;
   const double expected_expected_skip_to_produce_smr =
@@ -285,13 +284,13 @@
       expected_expected_skip_to_produce_mean_root;
   const double expected_skip_smr =
       SkipTransform(expected_expected_skip_to_produce_smr);
-  EXPECT_EQ(expected_skip_smr, r.smr);
-  EXPECT_EQ(expected_skip_smr, r.worst_smr.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_skip_smr, r.smr);
+  EXPECT_NEAR_SQRT_APPROX(expected_skip_smr, r.worst_smr.value);
 
   const double expected_skip_to_produce_std_dev = (0.5 + 0.5) / 2;
   const double expected_skip_std_dev =
       SkipTransform(expected_skip_to_produce_std_dev);
-  EXPECT_EQ(expected_skip_std_dev, r.std_dev);
+  EXPECT_NEAR_SQRT_APPROX(expected_skip_std_dev, r.std_dev);
 
   const double expected_skip_to_produce_std_dev_of_roots = (0.5 + 0.5) / 2;
   const double expected_skip_to_produce_variance_of_roots =
@@ -299,7 +298,7 @@
       expected_skip_to_produce_std_dev_of_roots;
   const double expected_skip_variance_of_roots =
       SkipTransform(expected_skip_to_produce_variance_of_roots);
-  EXPECT_EQ(expected_skip_variance_of_roots, r.variance_of_roots);
+  EXPECT_NEAR_SQRT_APPROX(expected_skip_variance_of_roots, r.variance_of_roots);
 }
 
 // Apply a saw tooth pattern to the latency with values that are easy to
@@ -322,34 +321,35 @@
 
   const double expected_latency_mean_square = (100.0 * 100 + 36 * 36) / 2;
   const double expected_latency_rms = std::sqrt(expected_latency_mean_square);
-  EXPECT_DOUBLE_EQ(expected_latency_rms, r.rms);
-  EXPECT_DOUBLE_EQ(expected_latency_rms, r.worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_latency_rms, r.rms);
+  EXPECT_NEAR_SQRT_APPROX(expected_latency_rms, r.worst_rms.value);
 
   const double expected_latency_mean_root = (10.0 + 6) / 2;
   const double expected_latency_smr =
       expected_latency_mean_root * expected_latency_mean_root;
-  EXPECT_DOUBLE_EQ(expected_latency_smr, r.smr);
-  EXPECT_DOUBLE_EQ(expected_latency_smr, r.worst_smr.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_latency_smr, r.smr);
+  EXPECT_NEAR_SQRT_APPROX(expected_latency_smr, r.worst_smr.value);
 
   const double expected_latency_std_dev = (100.0 - 36) / 2;
-  EXPECT_DOUBLE_EQ(expected_latency_std_dev, r.std_dev);
+  EXPECT_NEAR_SQRT_APPROX(expected_latency_std_dev, r.std_dev);
 
   const double expected_latency_std_dev_of_roots = (10.0 - 6) / 2;
   const double expected_latency_variance_of_roots =
       expected_latency_std_dev_of_roots * expected_latency_std_dev_of_roots;
-  EXPECT_DOUBLE_EQ(expected_latency_variance_of_roots, r.variance_of_roots);
+  EXPECT_NEAR_SQRT_APPROX(expected_latency_variance_of_roots,
+                          r.variance_of_roots);
 
   // Verify latency speed, where mean, RMS, SMR, etc. should be equal.
   r = SpeedAnalysis();
   const double expected_speed = 64;
   EXPECT_DOUBLE_EQ(expected_speed, r.mean);
-  EXPECT_DOUBLE_EQ(expected_speed, r.rms);
-  EXPECT_DOUBLE_EQ(expected_speed, r.smr);
+  EXPECT_NEAR_SQRT_APPROX(expected_speed, r.rms);
+  EXPECT_NEAR_SQRT_APPROX(expected_speed, r.smr);
   EXPECT_DOUBLE_EQ(0, r.std_dev);
-  EXPECT_DOUBLE_EQ(0, r.variance_of_roots);
+  EXPECT_NEAR_SQRT_APPROX(0, r.variance_of_roots);
   EXPECT_DOUBLE_EQ(expected_speed, r.worst_mean.value);
-  EXPECT_DOUBLE_EQ(expected_speed, r.worst_rms.value);
-  EXPECT_DOUBLE_EQ(expected_speed, r.worst_smr.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_speed, r.worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_speed, r.worst_smr.value);
 
   // Verify latency accelleration, where mean, RMS, SMR, etc. should be equal.
   // The slack is relatively large since the frame durations are so long, which
@@ -889,6 +889,30 @@
       &FrameMetricsTest::AccelerationAnalysis);
 }
 
+// Test the accuracy of the Newton's approximate square root calculation.
+// Since suqare_rooot is always used on small numbers in cc, this test only test
+// accuracy of small |x| value. A random number |x| between (0 - 100) is
+// generated, Test if the difference of square roots obtained from
+// FastApproximateSqrt and std::sqrt is less than |error_rage| (0.0001);
+TEST_F(FrameMetricsTest, SquareRootApproximation) {
+  const double slack = 0.001;
+  for (int i = 0; i < 3; i++) {
+    int x = base::RandInt(0, 100);
+    double sol1 = std::sqrt(x);
+    double sol2 = FrameMetrics::FastApproximateSqrt(x);
+    EXPECT_NEAR(sol1, sol2, slack)
+        << "failed to give a good approximate square root of " << x;
+  }
+
+  for (int i = 0; i < 3; i++) {
+    double x = double{base::RandUint64()} / base::RandomBitGenerator::max();
+    double sol1 = std::sqrt(x);
+    double sol2 = FrameMetrics::FastApproximateSqrt(x);
+    EXPECT_NEAR(sol1, sol2, slack)
+        << "failed to give a good approximate square root of " << x;
+  }
+}
+
 }  // namespace
 }  // namespace frame_metrics
 }  // namespace ui
diff --git a/ui/latency/stream_analyzer.cc b/ui/latency/stream_analyzer.cc
index 0453e27..2623e46 100644
--- a/ui/latency/stream_analyzer.cc
+++ b/ui/latency/stream_analyzer.cc
@@ -4,6 +4,8 @@
 
 #include "ui/latency/stream_analyzer.h"
 
+#include "ui/latency/frame_metrics.h"
+
 namespace ui {
 
 StreamAnalysis::StreamAnalysis() = default;
@@ -89,8 +91,9 @@
   DCHECK_GT(weight, 0u);
 
   const uint64_t weighted_value = static_cast<uint64_t>(weight) * value;
-  const uint64_t weighted_root = weight * std::sqrt(static_cast<double>(value) *
-                                                    kFixedPointRootMultiplier);
+  const uint64_t weighted_root =
+      weight * FrameMetrics::FastApproximateSqrt(static_cast<double>(value) *
+                                                 kFixedPointRootMultiplier);
   const Accumulator96b weighted_square(value, weight);
 
   // Verify overflow isn't an issue.
@@ -128,7 +131,7 @@
 
 double StreamAnalyzer::ComputeRMS() const {
   double mean_square = square_accumulator_.ToDouble() / total_weight_;
-  double result = std::sqrt(mean_square);
+  double result = FrameMetrics::FastApproximateSqrt(mean_square);
   return client_->TransformResult(result);
 }
 
@@ -152,7 +155,7 @@
 double StreamAnalyzer::ComputeStdDev() const {
   double variance =
       VarianceHelper(accumulator_, square_accumulator_.ToDouble());
-  double std_dev = std::sqrt(variance);
+  double std_dev = FrameMetrics::FrameMetrics::FastApproximateSqrt(variance);
   return client_->TransformResult(std_dev);
 }
 
diff --git a/ui/latency/stream_analyzer_unittest.cc b/ui/latency/stream_analyzer_unittest.cc
index 0841096..5aca77c 100644
--- a/ui/latency/stream_analyzer_unittest.cc
+++ b/ui/latency/stream_analyzer_unittest.cc
@@ -44,6 +44,7 @@
 };
 
 TEST_F(StreamAnalyzerTest, AllResultsTheSame) {
+  const double approx_sqrt_error = 0.0001;
   // Try adding a single sample vs. multiple samples.
   for (size_t samples : {1u, 100u}) {
     // A power of 2 sweep for both the value and weight dimensions.
@@ -57,17 +58,18 @@
         uint64_t expected_value =
             value * TestStreamAnalyzerClient::result_scale;
         EXPECT_EQ(expected_value, analyzer_->ComputeMean());
-        EXPECT_EQ(expected_value, analyzer_->ComputeRMS());
-        EXPECT_NEAR_SMR(analyzer_->ComputeSMR(), expected_value, weight);
-        EXPECT_DOUBLE_EQ(0, analyzer_->ComputeStdDev());
-        EXPECT_NEAR_VARIANCE_OF_ROOT(0, analyzer_->ComputeVarianceOfRoots(),
-                                     expected_value, weight);
+        EXPECT_NEAR_SQRT_APPROX(expected_value, analyzer_->ComputeRMS());
+        EXPECT_NEAR_SQRT_APPROX(analyzer_->ComputeSMR(), expected_value);
+        EXPECT_NEAR_SQRT_APPROX(0, analyzer_->ComputeStdDev());
+        EXPECT_NEAR(0, analyzer_->ComputeVarianceOfRoots(),
+                    approx_sqrt_error * value);
 
         // Verify values are forwarded to the WindowedAnalyzer.
         EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstMean().value);
-        EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstRMS().value);
-        EXPECT_NEAR_SMR(expected_value,
-                        analyzer_->window().ComputeWorstSMR().value, weight);
+        EXPECT_NEAR_SQRT_APPROX(expected_value,
+                                analyzer_->window().ComputeWorstRMS().value);
+        EXPECT_NEAR_SQRT_APPROX(expected_value,
+                                analyzer_->window().ComputeWorstSMR().value);
       }
     }
   }
@@ -83,17 +85,18 @@
       uint64_t expected_value = value * TestStreamAnalyzerClient::result_scale;
       // Makes sure our precision is good enough.
       EXPECT_EQ(expected_value, analyzer_->ComputeMean());
-      EXPECT_EQ(expected_value, analyzer_->ComputeRMS());
-      EXPECT_NEAR_SMR(expected_value, analyzer_->ComputeSMR(), weight);
-      EXPECT_DOUBLE_EQ(0, analyzer_->ComputeStdDev());
-      EXPECT_NEAR_VARIANCE_OF_ROOT(0, analyzer_->ComputeVarianceOfRoots(),
-                                   expected_value, weight);
+      EXPECT_NEAR_SQRT_APPROX(expected_value, analyzer_->ComputeRMS());
+      EXPECT_NEAR_SQRT_APPROX(expected_value, analyzer_->ComputeSMR());
+      EXPECT_NEAR_SQRT_APPROX(0, analyzer_->ComputeStdDev());
+      EXPECT_NEAR(0, analyzer_->ComputeVarianceOfRoots(),
+                  approx_sqrt_error * value);
 
       // Verify values are forwarded to the WindowedAnalyzer.
       EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstMean().value);
-      EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstRMS().value);
-      EXPECT_NEAR_SMR(expected_value,
-                      analyzer_->window().ComputeWorstSMR().value, weight);
+      EXPECT_NEAR_SQRT_APPROX(expected_value,
+                              analyzer_->window().ComputeWorstRMS().value);
+      EXPECT_NEAR_SQRT_APPROX(expected_value,
+                              analyzer_->window().ComputeWorstSMR().value);
     }
   }
 }
@@ -133,11 +136,12 @@
   for (size_t i = 0; i < 1000; i++) {
     AddPatternHelper(&shared_client_, analyzer(), pattern49, kSampleWeight);
     EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean());
-    EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), kSampleWeight);
-    EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS());
-    EXPECT_DOUBLE_EQ(expected_std_dev, analyzer_->ComputeStdDev());
-    EXPECT_DOUBLE_EQ(expected_variance_of_roots,
-                     analyzer_->ComputeVarianceOfRoots());
+    // since each value creates a difference of 0.001, the result should
+    EXPECT_NEAR_SQRT_APPROX(expected_smr, analyzer_->ComputeSMR());
+    EXPECT_NEAR_SQRT_APPROX(expected_rms, analyzer_->ComputeRMS());
+    EXPECT_NEAR_SQRT_APPROX(expected_std_dev, analyzer_->ComputeStdDev());
+    EXPECT_NEAR_SQRT_APPROX(expected_variance_of_roots,
+                            analyzer_->ComputeVarianceOfRoots());
   }
   thresholds = analyzer_->ComputeThresholds();
   ASSERT_EQ(3u, thresholds.size());
@@ -158,11 +162,11 @@
   }
   thresholds = analyzer_->ComputeThresholds();
   EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean());
-  EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), kSampleWeight);
-  EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS());
-  EXPECT_DOUBLE_EQ(expected_std_dev, analyzer_->ComputeStdDev());
-  EXPECT_DOUBLE_EQ(expected_variance_of_roots,
-                   analyzer_->ComputeVarianceOfRoots());
+  EXPECT_NEAR_SQRT_APPROX(expected_smr, analyzer_->ComputeSMR());
+  EXPECT_NEAR_SQRT_APPROX(expected_rms, analyzer_->ComputeRMS());
+  EXPECT_NEAR_SQRT_APPROX(expected_std_dev, analyzer_->ComputeStdDev());
+  EXPECT_NEAR_SQRT_APPROX(expected_variance_of_roots,
+                          analyzer_->ComputeVarianceOfRoots());
   EXPECT_EQ(client_.TransformResult(thresholds_[0]), thresholds[0].threshold);
   EXPECT_EQ(client_.TransformResult(thresholds_[1]), thresholds[1].threshold);
   EXPECT_EQ(client_.TransformResult(thresholds_[2]), thresholds[2].threshold);
@@ -180,11 +184,11 @@
   }
   thresholds = analyzer_->ComputeThresholds();
   EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean());
-  EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), kSampleWeight);
-  EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS());
-  EXPECT_DOUBLE_EQ(expected_std_dev, analyzer_->ComputeStdDev());
-  EXPECT_DOUBLE_EQ(expected_variance_of_roots,
-                   analyzer_->ComputeVarianceOfRoots());
+  EXPECT_NEAR_SQRT_APPROX(expected_smr, analyzer_->ComputeSMR());
+  EXPECT_NEAR_SQRT_APPROX(expected_rms, analyzer_->ComputeRMS());
+  EXPECT_NEAR_SQRT_APPROX(expected_std_dev, analyzer_->ComputeStdDev());
+  EXPECT_NEAR_SQRT_APPROX(expected_variance_of_roots,
+                          analyzer_->ComputeVarianceOfRoots());
   EXPECT_EQ(client_.TransformResult(thresholds_[0]), thresholds[0].threshold);
   EXPECT_EQ(client_.TransformResult(thresholds_[1]), thresholds[1].threshold);
   EXPECT_EQ(client_.TransformResult(thresholds_[2]), thresholds[2].threshold);
@@ -295,7 +299,7 @@
   double expected_rms = client_.TransformResult(std::sqrt(mean_square));
   EXPECT_ABS_LT(expected_rms * .001,
                 expected_rms - naive_analyzer.ComputeRMS());
-  EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS());
+  EXPECT_NEAR_SQRT_APPROX(expected_rms, analyzer_->ComputeRMS());
 
   double large_value_root = std::sqrt(large_value_f) * large_weight;
   double small_value_root = std::sqrt(small_value_f) * small_weight;
@@ -304,7 +308,7 @@
   double expected_smr = client_.TransformResult(mean_root * mean_root);
   EXPECT_ABS_LT(expected_smr * .001,
                 expected_smr - naive_analyzer.ComputeSMR());
-  EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), 1);
+  EXPECT_NEAR_SQRT_APPROX(expected_smr, analyzer_->ComputeSMR());
 }
 
 }  // namespace
diff --git a/ui/latency/windowed_analyzer.cc b/ui/latency/windowed_analyzer.cc
index a78d003..cd718d87 100644
--- a/ui/latency/windowed_analyzer.cc
+++ b/ui/latency/windowed_analyzer.cc
@@ -4,6 +4,8 @@
 
 #include "ui/latency/windowed_analyzer.h"
 
+#include "ui/latency/frame_metrics.h"
+
 namespace ui {
 
 void FrameRegionResult::AsValueInto(
@@ -57,9 +59,10 @@
     accumulator_ -= static_cast<uint64_t>(old_weight) * old_value;
     // Casting the whole rhs is important to ensure rounding happens at a place
     // equivalent to when it was added.
-    root_accumulator_ -= static_cast<uint64_t>(
-        old_weight *
-        std::sqrt(static_cast<uint64_t>(old_value) << kFixedPointRootShift));
+    root_accumulator_ -=
+        static_cast<uint64_t>(old_weight * FrameMetrics::FastApproximateSqrt(
+                                               static_cast<uint64_t>(old_value)
+                                               << kFixedPointRootShift));
     square_accumulator_.Subtract(Accumulator96b(old_value, old_weight));
   }
 
@@ -107,7 +110,8 @@
   } else {
     UpdateWorst(square_accumulator_, &result, true);
   }
-  result.value = client_->TransformResult(std::sqrt(result.value));
+  result.value =
+      client_->TransformResult(FrameMetrics::FastApproximateSqrt(result.value));
   return result;
 }
 
diff --git a/ui/latency/windowed_analyzer_unittest.cc b/ui/latency/windowed_analyzer_unittest.cc
index f60eb82..5aa05034 100644
--- a/ui/latency/windowed_analyzer_unittest.cc
+++ b/ui/latency/windowed_analyzer_unittest.cc
@@ -36,10 +36,11 @@
             value * TestWindowedAnalyzerClient::result_scale;
         EXPECT_EQ(analyzer.ComputeWorstMean().value, expected_value)
             << value << " x " << weight;
-        EXPECT_EQ(analyzer.ComputeWorstRMS().value, expected_value)
+        EXPECT_NEAR_SQRT_APPROX(analyzer.ComputeWorstRMS().value,
+                                expected_value)
             << value << " x " << weight;
-        EXPECT_NEAR_SMR(analyzer.ComputeWorstSMR().value, expected_value,
-                        weight)
+        EXPECT_NEAR_SQRT_APPROX(analyzer.ComputeWorstSMR().value,
+                                expected_value)
             << value << " x " << weight;
       }
     }
@@ -58,9 +59,9 @@
       // Makes sure our precision is good enough.
       EXPECT_EQ(analyzer.ComputeWorstMean().value, expected_value)
           << value << " x " << weight;
-      EXPECT_EQ(analyzer.ComputeWorstRMS().value, expected_value)
+      EXPECT_NEAR_SQRT_APPROX(analyzer.ComputeWorstRMS().value, expected_value)
           << value << " x " << weight;
-      EXPECT_NEAR_SMR(analyzer.ComputeWorstSMR().value, expected_value, weight)
+      EXPECT_NEAR_SQRT_APPROX(analyzer.ComputeWorstSMR().value, expected_value)
           << value << " x " << weight;
     }
   }
@@ -126,12 +127,12 @@
   EXPECT_EQ(worst_mean_client.window_end, worst_mean.window_end);
 
   FrameRegionResult worst_smr = analyzer.ComputeWorstSMR();
-  EXPECT_NEAR_SMR(expected_worst_smr, worst_smr.value, kSampleWeight);
+  EXPECT_NEAR_SQRT_APPROX(expected_worst_smr, worst_smr.value);
   EXPECT_EQ(worst_smr_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(worst_smr_client.window_end, worst_smr.window_end);
 
   FrameRegionResult worst_rms = analyzer.ComputeWorstRMS();
-  EXPECT_DOUBLE_EQ(expected_worst_rms, worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_worst_rms, worst_rms.value);
   EXPECT_EQ(worst_rms_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(worst_rms_client.window_end, worst_rms.window_end);
 }
@@ -160,12 +161,12 @@
   EXPECT_EQ(short_client.window_end, worst_mean.window_end);
 
   FrameRegionResult worst_smr = analyzer.ComputeWorstSMR();
-  EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
+  EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_smr.value);
   EXPECT_EQ(short_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(short_client.window_end, worst_smr.window_end);
 
   FrameRegionResult worst_rms = analyzer.ComputeWorstRMS();
-  EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_rms.value);
   EXPECT_EQ(short_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(short_client.window_end, worst_rms.window_end);
 }
@@ -197,12 +198,12 @@
   EXPECT_EQ(short_client.window_end, worst_mean.window_end);
 
   worst_smr = analyzer.ComputeWorstSMR();
-  EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
+  EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_smr.value);
   EXPECT_EQ(short_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(short_client.window_end, worst_smr.window_end);
 
   worst_rms = analyzer.ComputeWorstRMS();
-  EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_rms.value);
   EXPECT_EQ(short_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(short_client.window_end, worst_rms.window_end);
 
@@ -223,12 +224,12 @@
   EXPECT_EQ(long_client.window_end, worst_mean.window_end);
 
   worst_smr = analyzer.ComputeWorstSMR();
-  EXPECT_NEAR_SMR(expected_final_value, worst_smr.value, kSampleWeight);
+  EXPECT_NEAR_SQRT_APPROX(expected_final_value, worst_smr.value);
   EXPECT_EQ(long_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(long_client.window_end, worst_smr.window_end);
 
   worst_rms = analyzer.ComputeWorstRMS();
-  EXPECT_DOUBLE_EQ(expected_final_value, worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_final_value, worst_rms.value);
   EXPECT_EQ(long_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(long_client.window_end, worst_rms.window_end);
 }
@@ -258,12 +259,12 @@
   EXPECT_EQ(initial_client.window_end, worst_mean.window_end);
 
   worst_smr = analyzer.ComputeWorstSMR();
-  EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
+  EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_smr.value);
   EXPECT_EQ(initial_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_smr.window_end);
 
   worst_rms = analyzer.ComputeWorstRMS();
-  EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_rms.value);
   EXPECT_EQ(initial_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_rms.window_end);
 
@@ -278,12 +279,12 @@
   EXPECT_EQ(initial_client.window_end, worst_mean.window_end);
 
   worst_smr = analyzer.ComputeWorstSMR();
-  EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
+  EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_smr.value);
   EXPECT_EQ(initial_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_smr.window_end);
 
   worst_rms = analyzer.ComputeWorstRMS();
-  EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_rms.value);
   EXPECT_EQ(initial_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_rms.window_end);
 
@@ -309,12 +310,12 @@
   EXPECT_EQ(final_client.window_end, worst_mean.window_end);
 
   worst_smr = analyzer.ComputeWorstSMR();
-  EXPECT_NEAR_SMR(expected_final_value, worst_smr.value, kSampleWeight);
+  EXPECT_NEAR_SQRT_APPROX(expected_final_value, worst_smr.value);
   EXPECT_EQ(final_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(final_client.window_end, worst_smr.window_end);
 
   worst_rms = analyzer.ComputeWorstRMS();
-  EXPECT_DOUBLE_EQ(expected_final_value, worst_rms.value);
+  EXPECT_NEAR_SQRT_APPROX(expected_final_value, worst_rms.value);
   EXPECT_EQ(final_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(final_client.window_end, worst_rms.window_end);
 }
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 76dcdb5..7d3c40afd 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -37,6 +37,10 @@
     "wayland_data_offer.h",
     "wayland_data_source.cc",
     "wayland_data_source.h",
+    "wayland_input_method_context.cc",
+    "wayland_input_method_context.h",
+    "wayland_input_method_context_factory.cc",
+    "wayland_input_method_context_factory.h",
     "wayland_keyboard.cc",
     "wayland_keyboard.h",
     "wayland_native_display_delegate.cc",
@@ -66,6 +70,9 @@
     "xdg_surface_wrapper_v5.h",
     "xdg_surface_wrapper_v6.cc",
     "xdg_surface_wrapper_v6.h",
+    "zwp_text_input_wrapper.h",
+    "zwp_text_input_wrapper_v1.cc",
+    "zwp_text_input_wrapper_v1.h",
   ]
 
   import("//ui/base/ui_features.gni")
@@ -86,12 +93,15 @@
     "//third_party/wayland:wayland_client",
     "//third_party/wayland-protocols:linux_dmabuf_protocol",
     "//third_party/wayland-protocols:presentation_time_protocol",
+    "//third_party/wayland-protocols:text_input_protocol",
     "//third_party/wayland-protocols:xdg_shell_protocol",
     "//ui/base",
     "//ui/base:ui_features",
+    "//ui/base/ime/linux",
     "//ui/display/manager",
     "//ui/events",
     "//ui/events:dom_keycode_converter",
+    "//ui/events/keycodes:xkb",
     "//ui/events/ozone:events_ozone",
     "//ui/events/ozone:events_ozone_evdev",
     "//ui/events/ozone:events_ozone_layout",
@@ -143,6 +153,7 @@
     "fake_server.h",
     "wayland_connection_unittest.cc",
     "wayland_data_device_unittest.cc",
+    "wayland_input_method_context_unittest.cc",
     "wayland_keyboard_unittest.cc",
     "wayland_pointer_unittest.cc",
     "wayland_surface_factory_unittest.cc",
@@ -160,6 +171,7 @@
     "//third_party/wayland-protocols:xdg_shell_protocol",
     "//ui/base",
     "//ui/base:ui_features",
+    "//ui/base/ime/linux",
     "//ui/events/ozone:events_ozone_layout",
     "//ui/ozone:platform",
     "//ui/ozone:test_support",
diff --git a/ui/ozone/platform/wayland/DEPS b/ui/ozone/platform/wayland/DEPS
index 42e7c86b..73360bcf 100644
--- a/ui/ozone/platform/wayland/DEPS
+++ b/ui/ozone/platform/wayland/DEPS
@@ -1,5 +1,8 @@
 include_rules = [
   "+ui/base/ui_features.h",  # UI features doesn't bring in all of ui/base.
+  "+ui/base/ime/composition_text.h",
+  "+ui/base/ime/linux/linux_input_method_context.h",
+  "+ui/base/ime/linux/linux_input_method_context_factory.h",
   "+mojo/public",
   "+ui/base/dragdrop/drag_drop_types.h",
   "+ui/base/dragdrop/os_exchange_data.h",
diff --git a/ui/ozone/platform/wayland/fake_server.cc b/ui/ozone/platform/wayland/fake_server.cc
index 2bd0f9c..d9edf99f 100644
--- a/ui/ozone/platform/wayland/fake_server.cc
+++ b/ui/ozone/platform/wayland/fake_server.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include "ui/ozone/platform/wayland/fake_server.h"
+
 #include <sys/socket.h>
+#include <text-input-unstable-v1-server-protocol.h>
 #include <wayland-server.h>
 #include <xdg-shell-unstable-v5-server-protocol.h>
 #include <xdg-shell-unstable-v6-server-protocol.h>
@@ -21,11 +23,12 @@
 namespace wl {
 namespace {
 
-const uint32_t kCompositorVersion = 4;
-const uint32_t kOutputVersion = 2;
-const uint32_t kDataDeviceManagerVersion = 3;
-const uint32_t kSeatVersion = 4;
-const uint32_t kXdgShellVersion = 1;
+constexpr uint32_t kCompositorVersion = 4;
+constexpr uint32_t kOutputVersion = 2;
+constexpr uint32_t kDataDeviceManagerVersion = 3;
+constexpr uint32_t kSeatVersion = 4;
+constexpr uint32_t kTextInputManagerVersion = 1;
+constexpr uint32_t kXdgShellVersion = 1;
 
 bool ResourceHasImplementation(wl_resource* resource,
                                const wl_interface* interface,
@@ -471,6 +474,84 @@
     &DestroyResource,  // release
 };
 
+// zwp_text_input_v1
+
+void TextInputV1Activate(wl_client* client,
+                         wl_resource* resource,
+                         wl_resource* seat,
+                         wl_resource* surface) {
+  static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource))
+      ->Activate(surface);
+}
+
+void TextInputV1Deactivate(wl_client* client,
+                           wl_resource* resource,
+                           wl_resource* seat) {
+  static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource))
+      ->Deactivate();
+}
+
+void TextInputV1ShowInputPanel(wl_client* client, wl_resource* resource) {
+  static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource))
+      ->ShowInputPanel();
+}
+
+void TextInputV1HideInputPanel(wl_client* client, wl_resource* resource) {
+  static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource))
+      ->HideInputPanel();
+}
+
+void TextInputV1Reset(wl_client* client, wl_resource* resource) {
+  static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource))->Reset();
+}
+
+void TextInputV1SetCursorRectangle(wl_client* client,
+                                   wl_resource* resource,
+                                   int32_t x,
+                                   int32_t y,
+                                   int32_t width,
+                                   int32_t height) {
+  static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource))
+      ->SetCursorRect(x, y, width, height);
+}
+
+const struct zwp_text_input_v1_interface zwp_text_input_v1_impl = {
+    &TextInputV1Activate,            // activate
+    &TextInputV1Deactivate,          // deactivate
+    &TextInputV1ShowInputPanel,      // show_input_panel
+    &TextInputV1HideInputPanel,      // hide_input_panel
+    &TextInputV1Reset,               // reset
+    nullptr,                         // set_surrounding_text
+    nullptr,                         // set_content_type
+    &TextInputV1SetCursorRectangle,  // set_cursor_rectangle
+    nullptr,                         // set_preferred_language
+    nullptr,                         // commit_state
+    nullptr,                         // invoke_action
+};
+
+// zwp_text_input_manager_v1
+
+void CreateTextInput(struct wl_client* client,
+                     struct wl_resource* resource,
+                     uint32_t id) {
+  auto* im =
+      static_cast<MockTextInputManagerV1*>(wl_resource_get_user_data(resource));
+  wl_resource* text_resource =
+      wl_resource_create(client, &zwp_text_input_v1_interface,
+                         wl_resource_get_version(resource), id);
+  if (!text_resource) {
+    wl_client_post_no_memory(client);
+    return;
+  }
+  im->text_input.reset(
+      new MockZwpTextInput(text_resource, &zwp_text_input_v1_impl));
+}
+
+const struct zwp_text_input_manager_v1_interface
+    zwp_text_input_manager_v1_impl = {
+        &CreateTextInput,  // create_text_input
+};
+
 // xdg_surface, zxdg_surface_v6 and zxdg_toplevel shared methods.
 
 void SetTitle(wl_client* client, wl_resource* resource, const char* title) {
@@ -800,6 +881,15 @@
 
 MockTouch::~MockTouch() {}
 
+MockZwpTextInput::MockZwpTextInput(wl_resource* resource,
+                                   const void* implementation)
+    : ServerObject(resource) {
+  wl_resource_set_implementation(resource, implementation, this,
+                                 &ServerObject::OnResourceDestroyed);
+}
+
+MockZwpTextInput::~MockZwpTextInput() {}
+
 MockDataOffer::MockDataOffer(wl_resource* resource)
     : ServerObject(resource),
       io_thread_("Worker thread"),
@@ -1006,6 +1096,13 @@
 
 MockXdgShellV6::~MockXdgShellV6() {}
 
+MockTextInputManagerV1::MockTextInputManagerV1()
+    : Global(&zwp_text_input_manager_v1_interface,
+             &zwp_text_input_manager_v1_impl,
+             kTextInputManagerVersion) {}
+
+MockTextInputManagerV1::~MockTextInputManagerV1() {}
+
 void DisplayDeleter::operator()(wl_display* display) {
   wl_display_destroy(display);
 }
@@ -1052,6 +1149,8 @@
     if (!zxdg_shell_v6_.Initialize(display_.get()))
       return false;
   }
+  if (!zwp_text_input_manager_v1_.Initialize(display_.get()))
+    return false;
 
   client_ = wl_client_create(display_.get(), server_fd.get());
   if (!client_)
diff --git a/ui/ozone/platform/wayland/fake_server.h b/ui/ozone/platform/wayland/fake_server.h
index 4ee8348..27b8f07 100644
--- a/ui/ozone/platform/wayland/fake_server.h
+++ b/ui/ozone/platform/wayland/fake_server.h
@@ -182,6 +182,24 @@
   DISALLOW_COPY_AND_ASSIGN(MockTouch);
 };
 
+// Manage zwp_text_input_v1.
+class MockZwpTextInput : public ServerObject {
+ public:
+  MockZwpTextInput(wl_resource* resource, const void* implementation);
+  ~MockZwpTextInput() override;
+
+  MOCK_METHOD0(Reset, void());
+  MOCK_METHOD1(Activate, void(wl_resource* window));
+  MOCK_METHOD0(Deactivate, void());
+  MOCK_METHOD0(ShowInputPanel, void());
+  MOCK_METHOD0(HideInputPanel, void());
+  MOCK_METHOD4(SetCursorRect,
+               void(int32_t x, int32_t y, int32_t width, int32_t height));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockZwpTextInput);
+};
+
 class MockDataOffer : public ServerObject {
  public:
   explicit MockDataOffer(wl_resource* resource);
@@ -392,6 +410,18 @@
   DISALLOW_COPY_AND_ASSIGN(MockXdgShellV6);
 };
 
+// Manage zwp_text_input_manager_v1 object.
+class MockTextInputManagerV1 : public Global {
+ public:
+  MockTextInputManagerV1();
+  ~MockTextInputManagerV1() override;
+
+  std::unique_ptr<MockZwpTextInput> text_input;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockTextInputManagerV1);
+};
+
 struct DisplayDeleter {
   void operator()(wl_display* display);
 };
@@ -425,6 +455,9 @@
   MockSeat* seat() { return &seat_; }
   MockXdgShell* xdg_shell() { return &xdg_shell_; }
   MockOutput* output() { return &output_; }
+  MockTextInputManagerV1* text_input_manager_v1() {
+    return &zwp_text_input_manager_v1_;
+  }
 
  private:
   void DoPause();
@@ -449,6 +482,7 @@
   MockSeat seat_;
   MockXdgShell xdg_shell_;
   MockXdgShellV6 zxdg_shell_v6_;
+  MockTextInputManagerV1 zwp_text_input_manager_v1_;
 
   base::MessagePumpLibevent::FdWatchController controller_;
 
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 4476357..c19c251 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -14,6 +14,7 @@
 #include "ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h"
 #include "ui/ozone/platform/wayland/wayland_connection.h"
 #include "ui/ozone/platform/wayland/wayland_connection_connector.h"
+#include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h"
 #include "ui/ozone/platform/wayland/wayland_native_display_delegate.h"
 #include "ui/ozone/platform/wayland/wayland_surface_factory.h"
 #include "ui/ozone/platform/wayland/wayland_window.h"
@@ -80,6 +81,15 @@
   std::unique_ptr<PlatformWindow> CreatePlatformWindow(
       PlatformWindowDelegate* delegate,
       PlatformWindowInitProperties properties) override {
+    // Some unit tests may try to set custom input method context factory
+    // after InitializeUI. Thus instead of creating factory in InitializeUI
+    // it is set at this point if none exists
+    if (!LinuxInputMethodContextFactory::instance() &&
+        !wayland_input_method_context_factory_) {
+      wayland_input_method_context_factory_.reset(
+          new WaylandInputMethodContextFactory(connection_.get()));
+    }
+
     auto window = std::make_unique<WaylandWindow>(delegate, connection_.get());
     if (!window->Initialize(std::move(properties)))
       return nullptr;
@@ -168,6 +178,8 @@
   std::unique_ptr<StubOverlayManager> overlay_manager_;
   std::unique_ptr<InputController> input_controller_;
   std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
+  std::unique_ptr<WaylandInputMethodContextFactory>
+      wayland_input_method_context_factory_;
 
 #if BUILDFLAG(USE_XKBCOMMON)
   XkbEvdevCodes xkb_evdev_code_converter_;
diff --git a/ui/ozone/platform/wayland/wayland_connection.cc b/ui/ozone/platform/wayland/wayland_connection.cc
index b0cd50e3..0ddacd8 100644
--- a/ui/ozone/platform/wayland/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/wayland_connection.cc
@@ -16,6 +16,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "ui/gfx/swap_result.h"
 #include "ui/ozone/platform/wayland/wayland_buffer_manager.h"
+#include "ui/ozone/platform/wayland/wayland_input_method_context.h"
 #include "ui/ozone/platform/wayland/wayland_object.h"
 #include "ui/ozone/platform/wayland/wayland_window.h"
 
@@ -31,6 +32,7 @@
 constexpr uint32_t kMaxXdgShellVersion = 1;
 constexpr uint32_t kMaxDeviceManagerVersion = 3;
 constexpr uint32_t kMaxWpPresentationVersion = 1;
+constexpr uint32_t kMaxTextInputManagerVersion = 1;
 
 std::unique_ptr<WaylandDataSource> CreateWaylandDataSource(
     WaylandDataDeviceManager* data_device_manager,
@@ -128,6 +130,15 @@
   return nullptr;
 }
 
+WaylandWindow* WaylandConnection::GetCurrentKeyboardFocusedWindow() {
+  for (auto entry : window_map_) {
+    WaylandWindow* window = entry.second;
+    if (window->has_keyboard_focus())
+      return window;
+  }
+  return nullptr;
+}
+
 void WaylandConnection::AddWindow(gfx::AcceleratedWidget widget,
                                   WaylandWindow* window) {
   window_map_[widget] = window;
@@ -445,6 +456,14 @@
              (strcmp(interface, "wp_presentation") == 0)) {
     connection->presentation_ =
         wl::Bind<wp_presentation>(registry, name, kMaxWpPresentationVersion);
+  } else if (!connection->text_input_manager_v1_ &&
+             strcmp(interface, "zwp_text_input_manager_v1") == 0) {
+    connection->text_input_manager_v1_ = wl::Bind<zwp_text_input_manager_v1>(
+        registry, name, std::min(version, kMaxTextInputManagerVersion));
+    if (!connection->text_input_manager_v1_) {
+      LOG(ERROR) << "Failed to bind to zwp_text_input_manager_v1 global";
+      return;
+    }
   }
 
   connection->ScheduleFlush();
diff --git a/ui/ozone/platform/wayland/wayland_connection.h b/ui/ozone/platform/wayland/wayland_connection.h
index 961bf6f..15eecf7 100644
--- a/ui/ozone/platform/wayland/wayland_connection.h
+++ b/ui/ozone/platform/wayland/wayland_connection.h
@@ -76,9 +76,13 @@
   wl_seat* seat() { return seat_.get(); }
   wl_data_device* data_device() { return data_device_->data_device(); }
   wp_presentation* presentation() const { return presentation_.get(); }
+  zwp_text_input_manager_v1* text_input_manager_v1() {
+    return text_input_manager_v1_.get();
+  }
 
   WaylandWindow* GetWindow(gfx::AcceleratedWidget widget);
   WaylandWindow* GetCurrentFocusedWindow();
+  WaylandWindow* GetCurrentKeyboardFocusedWindow();
   void AddWindow(gfx::AcceleratedWidget widget, WaylandWindow* window);
   void RemoveWindow(gfx::AcceleratedWidget widget);
 
@@ -143,6 +147,9 @@
                        base::OnceCallback<void(const std::string&)> callback);
 
  private:
+  // WaylandInputMethodContextFactory needs access to DispatchUiEvent
+  friend class WaylandInputMethodContextFactory;
+
   void Flush();
   void DispatchUiEvent(Event* event);
 
@@ -185,6 +192,7 @@
   wl::Object<xdg_shell> shell_;
   wl::Object<zxdg_shell_v6> shell_v6_;
   wl::Object<wp_presentation> presentation_;
+  wl::Object<zwp_text_input_manager_v1> text_input_manager_v1_;
 
   std::unique_ptr<WaylandDataDeviceManager> data_device_manager_;
   std::unique_ptr<WaylandDataDevice> data_device_;
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context.cc b/ui/ozone/platform/wayland/wayland_input_method_context.cc
new file mode 100644
index 0000000..959a8e3
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_input_method_context.cc
@@ -0,0 +1,151 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/wayland_input_method_context.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/ime/composition_text.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/events/keycodes/keyboard_code_conversion.h"
+#include "ui/events/keycodes/keyboard_code_conversion_xkb.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/gfx/range/range.h"
+#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h"
+#include "ui/ozone/public/ozone_switches.h"
+
+namespace ui {
+
+namespace {
+
+constexpr int kXkbKeycodeOffset = 8;
+
+}  // namespace
+
+WaylandInputMethodContext::WaylandInputMethodContext(
+    WaylandConnection* connection,
+    LinuxInputMethodContextDelegate* delegate,
+    bool is_simple,
+    const EventDispatchCallback& callback)
+    : connection_(connection),
+      delegate_(delegate),
+      is_simple_(is_simple),
+      callback_(callback),
+      text_input_(nullptr) {
+  Init();
+}
+
+WaylandInputMethodContext::~WaylandInputMethodContext() {
+  if (text_input_) {
+    text_input_->Deactivate();
+    text_input_->HideInputPanel();
+  }
+}
+
+void WaylandInputMethodContext::Init(bool initialize_for_testing) {
+  bool use_ozone_wayland_vkb =
+      initialize_for_testing ||
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableWaylandIme);
+
+  // If text input instance is not created then all ime context operations
+  // are noop. This option is because in some environments someone might not
+  // want to enable ime/virtual keyboard even if it's available.
+  if (use_ozone_wayland_vkb && !is_simple_ && !text_input_ &&
+      connection_->text_input_manager_v1()) {
+    text_input_ = std::make_unique<ZWPTextInputWrapperV1>(
+        connection_->text_input_manager_v1());
+    text_input_->Initialize(connection_, this);
+  }
+}
+
+bool WaylandInputMethodContext::DispatchKeyEvent(
+    const ui::KeyEvent& key_event) {
+  return false;
+}
+
+void WaylandInputMethodContext::Reset() {
+  if (text_input_)
+    text_input_->Reset();
+}
+
+void WaylandInputMethodContext::Focus() {
+  WaylandWindow* window = connection_->GetCurrentKeyboardFocusedWindow();
+  if (!text_input_ || !window)
+    return;
+
+  text_input_->Activate(window);
+  text_input_->ShowInputPanel();
+}
+
+void WaylandInputMethodContext::Blur() {
+  if (text_input_) {
+    text_input_->Deactivate();
+    text_input_->HideInputPanel();
+  }
+}
+
+void WaylandInputMethodContext::SetCursorLocation(const gfx::Rect& rect) {
+  if (text_input_)
+    text_input_->SetCursorRect(rect);
+}
+
+void WaylandInputMethodContext::SetSurroundingText(
+    const base::string16& text,
+    const gfx::Range& selection_range) {
+  if (text_input_)
+    text_input_->SetSurroundingText(text, selection_range);
+}
+
+void WaylandInputMethodContext::OnPreeditString(const std::string& text,
+                                                int preedit_cursor) {
+  gfx::Range selection_range = gfx::Range::InvalidRange();
+
+  if (!selection_range.IsValid()) {
+    int cursor_pos = (preedit_cursor) ? text.length() : preedit_cursor;
+    selection_range.set_start(cursor_pos);
+    selection_range.set_end(cursor_pos);
+  }
+
+  ui::CompositionText composition_text;
+  composition_text.text = base::UTF8ToUTF16(text);
+  composition_text.selection = selection_range;
+  delegate_->OnPreeditChanged(composition_text);
+}
+
+void WaylandInputMethodContext::OnCommitString(const std::string& text) {
+  delegate_->OnCommit(base::UTF8ToUTF16(text));
+}
+
+void WaylandInputMethodContext::OnDeleteSurroundingText(int32_t index,
+                                                        uint32_t length) {
+  delegate_->OnDeleteSurroundingText(index, length);
+}
+
+void WaylandInputMethodContext::OnKeysym(uint32_t key,
+                                         uint32_t state,
+                                         uint32_t modifiers) {
+  uint8_t flags = 0;  // for now ignore modifiers
+  DomKey dom_key = NonPrintableXKeySymToDomKey(key);
+  KeyboardCode key_code = NonPrintableDomKeyToKeyboardCode(dom_key);
+  DomCode dom_code =
+      KeycodeConverter::NativeKeycodeToDomCode(key_code + kXkbKeycodeOffset);
+  if (dom_code == ui::DomCode::NONE)
+    return;
+
+  bool down = state == WL_KEYBOARD_KEY_STATE_PRESSED;
+  ui::KeyEvent event(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code,
+                     dom_code, flags, dom_key, EventTimeForNow());
+  callback_.Run(&event);
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context.h b/ui/ozone/platform/wayland/wayland_input_method_context.h
new file mode 100644
index 0000000..1023ecc
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_input_method_context.h
@@ -0,0 +1,59 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_H_
+#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_H_
+
+#include "base/macros.h"
+#include "ui/base/ime/linux/linux_input_method_context.h"
+#include "ui/events/ozone/evdev/event_dispatch_callback.h"
+#include "ui/ozone/platform/wayland/zwp_text_input_wrapper.h"
+
+namespace ui {
+
+class WaylandConnection;
+class ZWPTextInputWrapper;
+
+class WaylandInputMethodContext : public LinuxInputMethodContext,
+                                  public ZWPTextInputWrapperClient {
+ public:
+  WaylandInputMethodContext(WaylandConnection* connection,
+                            LinuxInputMethodContextDelegate* delegate,
+                            bool is_simple,
+                            const EventDispatchCallback& callback);
+  ~WaylandInputMethodContext() override;
+
+  void Init(bool initialize_for_testing = false);
+
+  // LinuxInputMethodContext overrides:
+  bool DispatchKeyEvent(const ui::KeyEvent& key_event) override;
+  void SetCursorLocation(const gfx::Rect& rect) override;
+  void SetSurroundingText(const base::string16& text,
+                          const gfx::Range& selection_range) override;
+  void Reset() override;
+  void Focus() override;
+  void Blur() override;
+
+  // ui::ZWPTextInputWrapperClient
+  void OnPreeditString(const std::string& text, int preedit_cursor) override;
+  void OnCommitString(const std::string& text) override;
+  void OnDeleteSurroundingText(int32_t index, uint32_t length) override;
+  void OnKeysym(uint32_t key, uint32_t state, uint32_t modifiers) override;
+
+ private:
+  WaylandConnection* connection_ = nullptr;  // TODO(jani) Handle this better
+
+  // Delegate interface back to IME code in ui.
+  LinuxInputMethodContextDelegate* delegate_;
+  bool is_simple_;
+  EventDispatchCallback callback_;
+
+  std::unique_ptr<ZWPTextInputWrapper> text_input_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandInputMethodContext);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_H_
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc b/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc
new file mode 100644
index 0000000..1eaf6fa
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h"
+
+#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/wayland_input_method_context.h"
+
+namespace ui {
+
+WaylandInputMethodContextFactory::WaylandInputMethodContextFactory(
+    WaylandConnection* connection)
+    : connection_(connection) {
+  LinuxInputMethodContextFactory::SetInstance(this);
+}
+
+WaylandInputMethodContextFactory::~WaylandInputMethodContextFactory() {
+  LinuxInputMethodContextFactory::SetInstance(nullptr);
+}
+
+std::unique_ptr<LinuxInputMethodContext>
+WaylandInputMethodContextFactory::CreateInputMethodContext(
+    LinuxInputMethodContextDelegate* delegate,
+    bool is_simple) const {
+  return CreateWaylandInputMethodContext(delegate, is_simple);
+}
+
+std::unique_ptr<WaylandInputMethodContext>
+WaylandInputMethodContextFactory::CreateWaylandInputMethodContext(
+    ui::LinuxInputMethodContextDelegate* delegate,
+    bool is_simple) const {
+  return std::make_unique<WaylandInputMethodContext>(
+      connection_, delegate, is_simple,
+      base::BindRepeating(&WaylandConnection::DispatchUiEvent,
+                          base::Unretained(connection_)));
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_factory.h b/ui/ozone/platform/wayland/wayland_input_method_context_factory.h
new file mode 100644
index 0000000..413f3a4
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_input_method_context_factory.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
+#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
+
+#include "base/macros.h"
+#include "ui/base/ime/linux/linux_input_method_context_factory.h"
+
+namespace ui {
+
+class WaylandConnection;
+class WaylandInputMethodContext;
+
+class WaylandInputMethodContextFactory : public LinuxInputMethodContextFactory {
+ public:
+  explicit WaylandInputMethodContextFactory(WaylandConnection* connection);
+  ~WaylandInputMethodContextFactory() override;
+
+  std::unique_ptr<LinuxInputMethodContext> CreateInputMethodContext(
+      ui::LinuxInputMethodContextDelegate* delegate,
+      bool is_simple) const override;
+
+  // Exposed for unit tests but also called by CreateInputMethodContext
+  std::unique_ptr<WaylandInputMethodContext> CreateWaylandInputMethodContext(
+      ui::LinuxInputMethodContextDelegate* delegate,
+      bool is_simple) const;
+
+ private:
+  WaylandConnection* connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandInputMethodContextFactory);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc b/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc
new file mode 100644
index 0000000..666910c
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <text-input-unstable-v1-server-protocol.h>
+#include <wayland-server.h>
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/linux/linux_input_method_context.h"
+#include "ui/events/event.h"
+#include "ui/ozone/platform/wayland/fake_server.h"
+#include "ui/ozone/platform/wayland/wayland_input_method_context.h"
+#include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h"
+#include "ui/ozone/platform/wayland/wayland_test.h"
+#include "ui/ozone/platform/wayland/wayland_window.h"
+
+using ::testing::SaveArg;
+using ::testing::_;
+
+namespace ui {
+
+class TestInputMethodContextDelegate : public LinuxInputMethodContextDelegate {
+ public:
+  TestInputMethodContextDelegate() {}
+  ~TestInputMethodContextDelegate() override {}
+
+  void OnCommit(const base::string16& text) override {
+    was_on_commit_called_ = true;
+  }
+  void OnPreeditChanged(const ui::CompositionText& composition_text) override {
+    was_on_preedit_changed_called_ = true;
+  }
+  void OnPreeditEnd() override {}
+  void OnPreeditStart() override {}
+  void OnDeleteSurroundingText(int32_t index, uint32_t length) override{};
+
+  bool was_on_commit_called() { return was_on_commit_called_; }
+
+  bool was_on_preedit_changed_called() {
+    return was_on_preedit_changed_called_;
+  }
+
+ private:
+  bool was_on_commit_called_ = false;
+  bool was_on_preedit_changed_called_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInputMethodContextDelegate);
+};
+
+class WaylandInputMethodContextTest : public WaylandTest {
+ public:
+  WaylandInputMethodContextTest() {}
+
+  void SetUp() override {
+    WaylandTest::SetUp();
+
+    Sync();
+
+    input_method_context_delegate_ =
+        std::make_unique<TestInputMethodContextDelegate>();
+
+    WaylandInputMethodContextFactory factory(connection_.get());
+    input_method_context_ = factory.CreateWaylandInputMethodContext(
+        input_method_context_delegate_.get(), false);
+    input_method_context_->Init(true);
+    connection_->ScheduleFlush();
+
+    Sync();
+
+    zwp_text_input_ = server_.text_input_manager_v1()->text_input.get();
+    window_->set_keyboard_focus(true);
+
+    ASSERT_TRUE(connection_->text_input_manager_v1());
+    ASSERT_TRUE(zwp_text_input_);
+  }
+
+ protected:
+  std::unique_ptr<TestInputMethodContextDelegate>
+      input_method_context_delegate_;
+  std::unique_ptr<WaylandInputMethodContext> input_method_context_;
+  wl::MockZwpTextInput* zwp_text_input_ = nullptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WaylandInputMethodContextTest);
+};
+
+TEST_P(WaylandInputMethodContextTest, Focus) {
+  EXPECT_CALL(*zwp_text_input_, Activate(surface_->resource()));
+  EXPECT_CALL(*zwp_text_input_, ShowInputPanel());
+  input_method_context_->Focus();
+  connection_->ScheduleFlush();
+  Sync();
+}
+
+TEST_P(WaylandInputMethodContextTest, Blur) {
+  EXPECT_CALL(*zwp_text_input_, Deactivate());
+  EXPECT_CALL(*zwp_text_input_, HideInputPanel());
+  input_method_context_->Blur();
+  connection_->ScheduleFlush();
+  Sync();
+}
+
+TEST_P(WaylandInputMethodContextTest, Reset) {
+  EXPECT_CALL(*zwp_text_input_, Reset());
+  input_method_context_->Reset();
+  connection_->ScheduleFlush();
+  Sync();
+}
+
+TEST_P(WaylandInputMethodContextTest, SetCursorLocation) {
+  EXPECT_CALL(*zwp_text_input_, SetCursorRect(50, 0, 1, 1));
+  input_method_context_->SetCursorLocation(gfx::Rect(50, 0, 1, 1));
+  connection_->ScheduleFlush();
+  Sync();
+}
+
+TEST_P(WaylandInputMethodContextTest, OnPreeditChanged) {
+  zwp_text_input_v1_send_preedit_string(zwp_text_input_->resource(), 0,
+                                        "PreeditString", "");
+  Sync();
+  EXPECT_TRUE(input_method_context_delegate_->was_on_preedit_changed_called());
+}
+
+TEST_P(WaylandInputMethodContextTest, OnCommit) {
+  zwp_text_input_v1_send_commit_string(zwp_text_input_->resource(), 0,
+                                       "CommitString");
+  Sync();
+  EXPECT_TRUE(input_method_context_delegate_->was_on_commit_called());
+}
+
+INSTANTIATE_TEST_CASE_P(XdgVersionV5Test,
+                        WaylandInputMethodContextTest,
+                        ::testing::Values(kXdgShellV5));
+INSTANTIATE_TEST_CASE_P(XdgVersionV6Test,
+                        WaylandInputMethodContextTest,
+                        ::testing::Values(kXdgShellV6));
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_object.cc b/ui/ozone/platform/wayland/wayland_object.cc
index c3cbb08..ed4de39 100644
--- a/ui/ozone/platform/wayland/wayland_object.cc
+++ b/ui/ozone/platform/wayland/wayland_object.cc
@@ -6,6 +6,7 @@
 
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include <presentation-time-client-protocol.h>
+#include <text-input-unstable-v1-client-protocol.h>
 #include <wayland-client.h>
 #include <xdg-shell-unstable-v5-client-protocol.h>
 #include <xdg-shell-unstable-v6-client-protocol.h>
@@ -177,4 +178,14 @@
 void (*ObjectTraits<zxdg_positioner_v6>::deleter)(zxdg_positioner_v6*) =
     &zxdg_positioner_v6_destroy;
 
+const wl_interface* ObjectTraits<zwp_text_input_manager_v1>::interface =
+    &zwp_text_input_manager_v1_interface;
+void (*ObjectTraits<zwp_text_input_manager_v1>::deleter)(
+    zwp_text_input_manager_v1*) = &zwp_text_input_manager_v1_destroy;
+
+const wl_interface* ObjectTraits<zwp_text_input_v1>::interface =
+    &zwp_text_input_v1_interface;
+void (*ObjectTraits<zwp_text_input_v1>::deleter)(zwp_text_input_v1*) =
+    &zwp_text_input_v1_destroy;
+
 }  // namespace wl
diff --git a/ui/ozone/platform/wayland/wayland_object.h b/ui/ozone/platform/wayland/wayland_object.h
index 62890452..34984d3 100644
--- a/ui/ozone/platform/wayland/wayland_object.h
+++ b/ui/ozone/platform/wayland/wayland_object.h
@@ -38,6 +38,8 @@
 struct zxdg_toplevel_v6;
 struct zxdg_popup_v6;
 struct zxdg_positioner_v6;
+struct zwp_text_input_manager_v1;
+struct zwp_text_input_v1;
 
 namespace wl {
 
@@ -224,6 +226,18 @@
   static void (*deleter)(zxdg_positioner_v6*);
 };
 
+template <>
+struct ObjectTraits<zwp_text_input_manager_v1> {
+  static const wl_interface* interface;
+  static void (*deleter)(zwp_text_input_manager_v1*);
+};
+
+template <>
+struct ObjectTraits<zwp_text_input_v1> {
+  static const wl_interface* interface;
+  static void (*deleter)(zwp_text_input_v1*);
+};
+
 struct Deleter {
   template <typename T>
   void operator()(T* obj) {
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc
index 9b251587..cb5e40b 100644
--- a/ui/ozone/platform/wayland/wayland_window.cc
+++ b/ui/ozone/platform/wayland/wayland_window.cc
@@ -197,6 +197,9 @@
 }
 
 void WaylandWindow::Show() {
+  if (!is_tooltip_)  // Tooltip windows should not get keyboard focus
+    set_keyboard_focus(true);
+
   if (xdg_surface_)
     return;
   if (is_tooltip_) {
diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/wayland_window.h
index 4cd69ff..4148648 100644
--- a/ui/ozone/platform/wayland/wayland_window.h
+++ b/ui/ozone/platform/wayland/wayland_window.h
@@ -57,6 +57,8 @@
   // Set whether this window has keyboard focus and should dispatch key events.
   void set_keyboard_focus(bool focus) { has_keyboard_focus_ = focus; }
 
+  bool has_keyboard_focus() const { return has_keyboard_focus_; }
+
   // Set whether this window has touch focus and should dispatch touch events.
   void set_touch_focus(bool focus) { has_touch_focus_ = focus; }
 
diff --git a/ui/ozone/platform/wayland/zwp_text_input_wrapper.h b/ui/ozone/platform/wayland/zwp_text_input_wrapper.h
new file mode 100644
index 0000000..8b11a95b7
--- /dev/null
+++ b/ui/ozone/platform/wayland/zwp_text_input_wrapper.h
@@ -0,0 +1,74 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_H_
+
+#include "ui/ozone/platform/wayland/wayland_object.h"
+
+#include "base/strings/string16.h"
+
+namespace gfx {
+class Rect;
+class Range;
+}  // namespace gfx
+
+namespace ui {
+
+class WaylandConnection;
+class WaylandWindow;
+
+// Client interface which handles wayland text input callbacks
+class ZWPTextInputWrapperClient {
+ public:
+  virtual ~ZWPTextInputWrapperClient() {}
+
+  // Called when a new composing text (pre-edit) should be set around the
+  // current cursor position. Any previously set composing text should
+  // be removed.
+  virtual void OnPreeditString(const std::string& text,
+                               int32_t preedit_cursor) = 0;
+
+  // Called when a complete input sequence has been entered.  The text to
+  // commit could be either just a single character after a key press or the
+  // result of some composing (pre-edit).
+  virtual void OnCommitString(const std::string& text) = 0;
+
+  // Called when client needs to delete all or part of the text surrounding
+  // the cursor
+  virtual void OnDeleteSurroundingText(int32_t index, uint32_t length) = 0;
+
+  // Notify when a key event was sent. Key events should not be used
+  // for normal text input operations, which should be done with
+  // commit_string, delete_surrounding_text, etc.
+  virtual void OnKeysym(uint32_t key, uint32_t state, uint32_t modifiers) = 0;
+};
+
+// A wrapper around different versions of wayland text input protocols.
+// Wayland compositors support various different text input protocols which
+// all from Chromium point of view provide the functionality needed by Chromium
+// IME. This interface collects the functionality behind one wrapper API.
+class ZWPTextInputWrapper {
+ public:
+  virtual ~ZWPTextInputWrapper() {}
+
+  virtual void Initialize(WaylandConnection* connection,
+                          ZWPTextInputWrapperClient* client) = 0;
+
+  virtual void Reset() = 0;
+
+  virtual void Activate(WaylandWindow* window) = 0;
+  virtual void Deactivate() = 0;
+
+  virtual void ShowInputPanel() = 0;
+  virtual void HideInputPanel() = 0;
+
+  virtual void SetCursorRect(const gfx::Rect& rect) = 0;
+  virtual void SetSurroundingText(const base::string16& text,
+                                  const gfx::Range& selection_range) = 0;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_H_
diff --git a/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.cc b/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.cc
new file mode 100644
index 0000000..4a12ace
--- /dev/null
+++ b/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.cc
@@ -0,0 +1,197 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/gfx/range/range.h"
+#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/wayland_window.h"
+
+namespace ui {
+
+ZWPTextInputWrapperV1::ZWPTextInputWrapperV1(
+    zwp_text_input_manager_v1* text_input_manager)
+    : client_(nullptr) {
+  static const zwp_text_input_v1_listener text_input_listener = {
+      &ZWPTextInputWrapperV1::OnEnter,         // text_input_enter,
+      &ZWPTextInputWrapperV1::OnLeave,         // text_input_leave,
+      &ZWPTextInputWrapperV1::OnModifiersMap,  // text_input_modifiers_map,
+      &ZWPTextInputWrapperV1::
+          OnInputPanelState,                    // text_input_input_panel_state,
+      &ZWPTextInputWrapperV1::OnPreeditString,  // text_input_preedit_string,
+      &ZWPTextInputWrapperV1::OnPreeditStyling,  // text_input_preedit_styling,
+      &ZWPTextInputWrapperV1::OnPreeditCursor,   // text_input_preedit_cursor,
+      &ZWPTextInputWrapperV1::OnCommitString,    // text_input_commit_string,
+      &ZWPTextInputWrapperV1::OnCursorPosition,  // text_input_cursor_position,
+      &ZWPTextInputWrapperV1::
+          OnDeleteSurroundingText,       // text_input_delete_surrounding_text,
+      &ZWPTextInputWrapperV1::OnKeysym,  // text_input_keysym,
+      &ZWPTextInputWrapperV1::OnLanguage,       // text_input_language,
+      &ZWPTextInputWrapperV1::OnTextDirection,  // text_input_text_direction
+  };
+  ResetInputEventState();
+
+  zwp_text_input_v1* text_input =
+      zwp_text_input_manager_v1_create_text_input(text_input_manager);
+  obj_ = wl::Object<zwp_text_input_v1>(text_input);
+
+  zwp_text_input_v1_add_listener(text_input, &text_input_listener, this);
+}
+
+ZWPTextInputWrapperV1::~ZWPTextInputWrapperV1() {}
+
+void ZWPTextInputWrapperV1::Initialize(WaylandConnection* connection,
+                                       ZWPTextInputWrapperClient* client) {
+  connection_ = connection;
+  client_ = client;
+}
+
+void ZWPTextInputWrapperV1::Reset() {
+  ResetInputEventState();
+  zwp_text_input_v1_reset(obj_.get());
+}
+
+void ZWPTextInputWrapperV1::Activate(WaylandWindow* window) {
+  zwp_text_input_v1_activate(obj_.get(), connection_->seat(),
+                             window->surface());
+}
+
+void ZWPTextInputWrapperV1::Deactivate() {
+  zwp_text_input_v1_deactivate(obj_.get(), connection_->seat());
+}
+
+void ZWPTextInputWrapperV1::ShowInputPanel() {
+  zwp_text_input_v1_show_input_panel(obj_.get());
+}
+
+void ZWPTextInputWrapperV1::HideInputPanel() {
+  zwp_text_input_v1_hide_input_panel(obj_.get());
+}
+
+void ZWPTextInputWrapperV1::SetCursorRect(const gfx::Rect& rect) {
+  zwp_text_input_v1_set_cursor_rectangle(obj_.get(), rect.x(), rect.y(),
+                                         rect.width(), rect.height());
+}
+
+void ZWPTextInputWrapperV1::SetSurroundingText(
+    const base::string16& text,
+    const gfx::Range& selection_range) {
+  const std::string text_utf8 = base::UTF16ToUTF8(text);
+  zwp_text_input_v1_set_surrounding_text(obj_.get(), text_utf8.c_str(),
+                                         selection_range.start(),
+                                         selection_range.end());
+}
+
+void ZWPTextInputWrapperV1::ResetInputEventState() {
+  preedit_cursor_ = -1;
+}
+
+void ZWPTextInputWrapperV1::OnEnter(void* data,
+                                    struct zwp_text_input_v1* text_input,
+                                    struct wl_surface* surface) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void ZWPTextInputWrapperV1::OnLeave(void* data,
+                                    struct zwp_text_input_v1* text_input) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void ZWPTextInputWrapperV1::OnModifiersMap(void* data,
+                                           struct zwp_text_input_v1* text_input,
+                                           struct wl_array* map) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void ZWPTextInputWrapperV1::OnInputPanelState(
+    void* data,
+    struct zwp_text_input_v1* text_input,
+    uint32_t state) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void ZWPTextInputWrapperV1::OnPreeditString(
+    void* data,
+    struct zwp_text_input_v1* text_input,
+    uint32_t serial,
+    const char* text,
+    const char* commit) {
+  ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data);
+  wti->ResetInputEventState();
+  wti->client_->OnPreeditString(std::string(text), wti->preedit_cursor_);
+}
+
+void ZWPTextInputWrapperV1::OnPreeditStyling(
+    void* data,
+    struct zwp_text_input_v1* text_input,
+    uint32_t index,
+    uint32_t length,
+    uint32_t style) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void ZWPTextInputWrapperV1::OnPreeditCursor(
+    void* data,
+    struct zwp_text_input_v1* text_input,
+    int32_t index) {
+  ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data);
+  wti->preedit_cursor_ = index;
+}
+
+void ZWPTextInputWrapperV1::OnCommitString(void* data,
+                                           struct zwp_text_input_v1* text_input,
+                                           uint32_t serial,
+                                           const char* text) {
+  ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data);
+  wti->ResetInputEventState();
+  wti->client_->OnCommitString(std::string(text));
+}
+
+void ZWPTextInputWrapperV1::OnCursorPosition(
+    void* data,
+    struct zwp_text_input_v1* text_input,
+    int32_t index,
+    int32_t anchor) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void ZWPTextInputWrapperV1::OnDeleteSurroundingText(
+    void* data,
+    struct zwp_text_input_v1* text_input,
+    int32_t index,
+    uint32_t length) {
+  ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data);
+  wti->client_->OnDeleteSurroundingText(index, length);
+}
+
+void ZWPTextInputWrapperV1::OnKeysym(void* data,
+                                     struct zwp_text_input_v1* text_input,
+                                     uint32_t serial,
+                                     uint32_t time,
+                                     uint32_t key,
+                                     uint32_t state,
+                                     uint32_t modifiers) {
+  ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data);
+  wti->client_->OnKeysym(key, state, modifiers);
+}
+
+void ZWPTextInputWrapperV1::OnLanguage(void* data,
+                                       struct zwp_text_input_v1* text_input,
+                                       uint32_t serial,
+                                       const char* language) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void ZWPTextInputWrapperV1::OnTextDirection(
+    void* data,
+    struct zwp_text_input_v1* text_input,
+    uint32_t serial,
+    uint32_t direction) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h b/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h
new file mode 100644
index 0000000..62cfaa6
--- /dev/null
+++ b/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h
@@ -0,0 +1,106 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_V1_H_
+#define UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_V1_H_
+
+#include <text-input-unstable-v1-client-protocol.h>
+#include <string>
+
+#include "ui/ozone/platform/wayland/zwp_text_input_wrapper.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class WaylandConnection;
+class WaylandWindow;
+
+class ZWPTextInputWrapperV1 : public ZWPTextInputWrapper {
+ public:
+  explicit ZWPTextInputWrapperV1(zwp_text_input_manager_v1* text_input_manager);
+  ~ZWPTextInputWrapperV1() override;
+
+  void Initialize(WaylandConnection* connection,
+                  ZWPTextInputWrapperClient* client) override;
+
+  void Reset() override;
+
+  void Activate(WaylandWindow* window) override;
+  void Deactivate() override;
+
+  void ShowInputPanel() override;
+  void HideInputPanel() override;
+
+  void SetCursorRect(const gfx::Rect& rect) override;
+  void SetSurroundingText(const base::string16& text,
+                          const gfx::Range& selection_range) override;
+
+ private:
+  void ResetInputEventState();
+
+  // zwp_text_input_v1_listener
+  static void OnEnter(void* data,
+                      struct zwp_text_input_v1* text_input,
+                      struct wl_surface* surface);
+  static void OnLeave(void* data, struct zwp_text_input_v1* text_input);
+  static void OnModifiersMap(void* data,
+                             struct zwp_text_input_v1* text_input,
+                             struct wl_array* map);
+  static void OnInputPanelState(void* data,
+                                struct zwp_text_input_v1* text_input,
+                                uint32_t state);
+  static void OnPreeditString(void* data,
+                              struct zwp_text_input_v1* text_input,
+                              uint32_t serial,
+                              const char* text,
+                              const char* commit);
+  static void OnPreeditStyling(void* data,
+                               struct zwp_text_input_v1* text_input,
+                               uint32_t index,
+                               uint32_t length,
+                               uint32_t style);
+  static void OnPreeditCursor(void* data,
+                              struct zwp_text_input_v1* text_input,
+                              int32_t index);
+  static void OnCommitString(void* data,
+                             struct zwp_text_input_v1* text_input,
+                             uint32_t serial,
+                             const char* text);
+  static void OnCursorPosition(void* data,
+                               struct zwp_text_input_v1* text_input,
+                               int32_t index,
+                               int32_t anchor);
+  static void OnDeleteSurroundingText(void* data,
+                                      struct zwp_text_input_v1* text_input,
+                                      int32_t index,
+                                      uint32_t length);
+  static void OnKeysym(void* data,
+                       struct zwp_text_input_v1* text_input,
+                       uint32_t serial,
+                       uint32_t time,
+                       uint32_t key,
+                       uint32_t state,
+                       uint32_t modifiers);
+  static void OnLanguage(void* data,
+                         struct zwp_text_input_v1* text_input,
+                         uint32_t serial,
+                         const char* language);
+  static void OnTextDirection(void* data,
+                              struct zwp_text_input_v1* text_input,
+                              uint32_t serial,
+                              uint32_t direction);
+
+  WaylandConnection* connection_ = nullptr;
+  wl::Object<zwp_text_input_v1> obj_;
+  ZWPTextInputWrapperClient* client_;
+
+  int32_t preedit_cursor_;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_V1_H_
diff --git a/ui/ozone/public/ozone_switches.cc b/ui/ozone/public/ozone_switches.cc
index 0a9b3ab32..7bec0b7e 100644
--- a/ui/ozone/public/ozone_switches.cc
+++ b/ui/ozone/public/ozone_switches.cc
@@ -12,4 +12,7 @@
 // Specify location for image dumps.
 const char kOzoneDumpFile[] = "ozone-dump-file";
 
+// Try to enable wayland input method editor.
+const char kEnableWaylandIme[] = "enable-wayland-ime";
+
 }  // namespace switches
diff --git a/ui/ozone/public/ozone_switches.h b/ui/ozone/public/ozone_switches.h
index b062e67..d7e7d8a 100644
--- a/ui/ozone/public/ozone_switches.h
+++ b/ui/ozone/public/ozone_switches.h
@@ -14,6 +14,8 @@
 
 OZONE_BASE_EXPORT extern const char kOzoneDumpFile[];
 
+OZONE_BASE_EXPORT extern const char kEnableWaylandIme[];
+
 }  // namespace switches
 
 #endif  // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_
diff --git a/ui/views/accessibility/ax_aura_obj_cache.cc b/ui/views/accessibility/ax_aura_obj_cache.cc
index 9fffbd6..5811bf2 100644
--- a/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -31,6 +31,7 @@
 }
 
 AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(View* view) {
+  // Avoid problems with transient focus events. https://crbug.com/729449
   if (!view->GetWidget())
     return nullptr;
   return CreateInternal<AXViewObjWrapper>(view, view_to_id_map_);
diff --git a/ui/views/accessibility/ax_aura_obj_cache.h b/ui/views/accessibility/ax_aura_obj_cache.h
index 83f3155..3a4a448 100644
--- a/ui/views/accessibility/ax_aura_obj_cache.h
+++ b/ui/views/accessibility/ax_aura_obj_cache.h
@@ -45,8 +45,11 @@
                          ax::mojom::Event event_type) = 0;
   };
 
-  // Get or create an entry in the cache based on an Aura view.
+  // Get or create an entry in the cache. May return null if the View is not
+  // associated with a Widget.
   AXAuraObjWrapper* GetOrCreate(View* view);
+
+  // Get or create an entry in the cache.
   AXAuraObjWrapper* GetOrCreate(Widget* widget);
   AXAuraObjWrapper* GetOrCreate(aura::Window* window);
 
diff --git a/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc b/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
index 84b893f..2e78f27 100644
--- a/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
+++ b/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
@@ -21,6 +21,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gl/test/gl_surface_test_support.h"
+#include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_test_api.h"
 #include "ui/views/test/widget_test.h"
@@ -74,6 +75,132 @@
   DISALLOW_COPY_AND_ASSIGN(AXSystemCaretWinTest);
 };
 
+class WinAccessibilityCaretEventMonitor {
+ public:
+  WinAccessibilityCaretEventMonitor(UINT event_min, UINT event_max);
+  ~WinAccessibilityCaretEventMonitor();
+
+  // Blocks until the next event is received. When it's received, it
+  // queries accessibility information about the object that fired the
+  // event and populates the event, hwnd, role, state, and name in the
+  // passed arguments.
+  void WaitForNextEvent(DWORD* out_event, UINT* out_role, UINT* out_state);
+
+ private:
+  void OnWinEventHook(HWINEVENTHOOK handle,
+                      DWORD event,
+                      HWND hwnd,
+                      LONG obj_id,
+                      LONG child_id,
+                      DWORD event_thread,
+                      DWORD event_time);
+
+  static void CALLBACK WinEventHookThunk(HWINEVENTHOOK handle,
+                                         DWORD event,
+                                         HWND hwnd,
+                                         LONG obj_id,
+                                         LONG child_id,
+                                         DWORD event_thread,
+                                         DWORD event_time);
+
+  struct EventInfo {
+    DWORD event;
+    HWND hwnd;
+    LONG obj_id;
+    LONG child_id;
+  };
+
+  base::circular_deque<EventInfo> event_queue_;
+  base::RunLoop loop_runner_;
+  HWINEVENTHOOK win_event_hook_handle_;
+  static WinAccessibilityCaretEventMonitor* instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(WinAccessibilityCaretEventMonitor);
+};
+
+// static
+WinAccessibilityCaretEventMonitor*
+    WinAccessibilityCaretEventMonitor::instance_ = NULL;
+
+WinAccessibilityCaretEventMonitor::WinAccessibilityCaretEventMonitor(
+    UINT event_min,
+    UINT event_max) {
+  CHECK(!instance_) << "There can be only one instance of"
+                    << " WinAccessibilityCaretEventMonitor at a time.";
+  instance_ = this;
+  win_event_hook_handle_ =
+      SetWinEventHook(event_min, event_max, NULL,
+                      &WinAccessibilityCaretEventMonitor::WinEventHookThunk,
+                      GetCurrentProcessId(),
+                      0,  // Hook all threads
+                      WINEVENT_OUTOFCONTEXT);
+}
+
+WinAccessibilityCaretEventMonitor::~WinAccessibilityCaretEventMonitor() {
+  UnhookWinEvent(win_event_hook_handle_);
+  instance_ = NULL;
+}
+
+void WinAccessibilityCaretEventMonitor::WaitForNextEvent(DWORD* out_event,
+                                                         UINT* out_role,
+                                                         UINT* out_state) {
+  if (event_queue_.empty())
+    loop_runner_.Run();
+
+  EventInfo event_info = event_queue_.front();
+  event_queue_.pop_front();
+
+  *out_event = event_info.event;
+
+  Microsoft::WRL::ComPtr<IAccessible> acc_obj;
+  base::win::ScopedVariant child_variant;
+  CHECK(S_OK == AccessibleObjectFromEvent(
+                    event_info.hwnd, event_info.obj_id, event_info.child_id,
+                    acc_obj.GetAddressOf(), child_variant.Receive()));
+
+  base::win::ScopedVariant role_variant;
+  if (S_OK == acc_obj->get_accRole(child_variant, role_variant.Receive()))
+    *out_role = V_I4(role_variant.ptr());
+  else
+    *out_role = 0;
+
+  base::win::ScopedVariant state_variant;
+  if (S_OK == acc_obj->get_accState(child_variant, state_variant.Receive()))
+    *out_state = V_I4(state_variant.ptr());
+  else
+    *out_state = 0;
+}
+
+void WinAccessibilityCaretEventMonitor::OnWinEventHook(HWINEVENTHOOK handle,
+                                                       DWORD event,
+                                                       HWND hwnd,
+                                                       LONG obj_id,
+                                                       LONG child_id,
+                                                       DWORD event_thread,
+                                                       DWORD event_time) {
+  EventInfo event_info;
+  event_info.event = event;
+  event_info.hwnd = hwnd;
+  event_info.obj_id = obj_id;
+  event_info.child_id = child_id;
+  event_queue_.push_back(event_info);
+  loop_runner_.Quit();
+}
+
+// static
+void CALLBACK
+WinAccessibilityCaretEventMonitor::WinEventHookThunk(HWINEVENTHOOK handle,
+                                                     DWORD event,
+                                                     HWND hwnd,
+                                                     LONG obj_id,
+                                                     LONG child_id,
+                                                     DWORD event_thread,
+                                                     DWORD event_time) {
+  if (instance_ && obj_id == OBJID_CARET) {
+    instance_->OnWinEventHook(handle, event, hwnd, obj_id, child_id,
+                              event_thread, event_time);
+  }
+}
 }  // namespace
 
 TEST_F(AXSystemCaretWinTest, DISABLED_TestOnCaretBoundsChangeInTextField) {
@@ -183,4 +310,81 @@
   EXPECT_EQ(height, height3);
 }
 
+TEST_F(AXSystemCaretWinTest, TestCaretMSAAEvents) {
+  TextfieldTestApi textfield_test_api(textfield_);
+  Microsoft::WRL::ComPtr<IAccessible> caret_accessible;
+  gfx::NativeWindow native_window = widget_->GetNativeWindow();
+  ASSERT_NE(nullptr, native_window);
+  HWND hwnd = native_window->GetHost()->GetAcceleratedWidget();
+  EXPECT_HRESULT_SUCCEEDED(AccessibleObjectFromWindow(
+      hwnd, static_cast<DWORD>(OBJID_CARET), IID_IAccessible,
+      reinterpret_cast<void**>(caret_accessible.GetAddressOf())));
+
+  DWORD event;
+  UINT role;
+  UINT state;
+
+  {
+    // Set caret to start of textfield.
+    WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW,
+                                              EVENT_OBJECT_LOCATIONCHANGE);
+    textfield_test_api.ExecuteTextEditCommand(
+        ui::TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT);
+    monitor.WaitForNextEvent(&event, &role, &state);
+    ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_LOCATIONCHANGE))
+        << "Event should be EVENT_OBJECT_LOCATIONCHANGE";
+    ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET))
+        << "Role should be ROLE_SYSTEM_CARET";
+    ASSERT_EQ(state, static_cast<UINT>(0)) << "State should be 0";
+  }
+
+  {
+    // Set caret to end of textfield.
+    WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW,
+                                              EVENT_OBJECT_LOCATIONCHANGE);
+    textfield_test_api.ExecuteTextEditCommand(
+        ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT);
+    monitor.WaitForNextEvent(&event, &role, &state);
+    ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_LOCATIONCHANGE))
+        << "Event should be EVENT_OBJECT_LOCATIONCHANGE";
+    ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET))
+        << "Role should be ROLE_SYSTEM_CARET";
+    ASSERT_EQ(state, static_cast<UINT>(0)) << "State should be 0";
+  }
+
+  {
+    // Move focus to a button.
+    LabelButton button(nullptr, base::string16());
+    button.SetBounds(500, 0, 200, 20);
+    widget_->GetRootView()->AddChildView(&button);
+    test::WidgetActivationWaiter waiter(widget_, true);
+    WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW,
+                                              EVENT_OBJECT_LOCATIONCHANGE);
+    widget_->Show();
+    waiter.Wait();
+    button.SetFocusBehavior(View::FocusBehavior::ALWAYS);
+    button.RequestFocus();
+    monitor.WaitForNextEvent(&event, &role, &state);
+    ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_HIDE))
+        << "Event should be EVENT_OBJECT_HIDE";
+    ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET))
+        << "Role should be ROLE_SYSTEM_CARET";
+    ASSERT_EQ(state, static_cast<UINT>(STATE_SYSTEM_INVISIBLE))
+        << "State should be STATE_SYSTEM_INVISIBLE";
+  }
+
+  {
+    // Move focus back to the text field.
+    WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW,
+                                              EVENT_OBJECT_LOCATIONCHANGE);
+    textfield_->RequestFocus();
+    monitor.WaitForNextEvent(&event, &role, &state);
+    ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_SHOW))
+        << "Event should be EVENT_OBJECT_SHOW";
+    ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET))
+        << "Role should be ROLE_SYSTEM_CARET";
+    ASSERT_EQ(state, static_cast<UINT>(0)) << "State should be 0";
+  }
+}
+
 }  // namespace views
diff --git a/ui/views/cocoa/bridge_factory_impl.mm b/ui/views/cocoa/bridge_factory_impl.mm
index 5861321..f909e24 100644
--- a/ui/views/cocoa/bridge_factory_impl.mm
+++ b/ui/views/cocoa/bridge_factory_impl.mm
@@ -40,6 +40,10 @@
     *found_word = false;
   }
   double SheetPositionY() override { return 0; }
+  views_bridge_mac::DragDropClient* GetDragDropClient() override {
+    // Drag-drop only doesn't work across mojo yet.
+    return nullptr;
+  }
 
   mojom::BridgedNativeWidgetHostPtr host_ptr_;
   std::unique_ptr<BridgedNativeWidgetImpl> bridge_impl_;
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm
index bf1a9c71..89b149b 100644
--- a/ui/views/cocoa/bridged_content_view.mm
+++ b/ui/views/cocoa/bridged_content_view.mm
@@ -252,7 +252,7 @@
 - (void)insertTextInternal:(id)text;
 
 // Returns the native Widget's drag drop client. Possibly null.
-- (views::DragDropClientMac*)dragDropClient;
+- (views_bridge_mac::DragDropClient*)dragDropClient;
 
 // Menu action handlers.
 - (void)undo:(id)sender;
@@ -621,7 +621,7 @@
   }
 }
 
-- (views::DragDropClientMac*)dragDropClient {
+- (views_bridge_mac::DragDropClient*)dragDropClient {
   return bridge_ ? bridge_->drag_drop_client() : nullptr;
 }
 
@@ -769,18 +769,18 @@
 }
 
 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
-  views::DragDropClientMac* client = [self dragDropClient];
+  views_bridge_mac::DragDropClient* client = [self dragDropClient];
   return client ? client->DragUpdate(sender) : ui::DragDropTypes::DRAG_NONE;
 }
 
 - (void)draggingExited:(id<NSDraggingInfo>)sender {
-  views::DragDropClientMac* client = [self dragDropClient];
+  views_bridge_mac::DragDropClient* client = [self dragDropClient];
   if (client)
     client->DragExit();
 }
 
 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
-  views::DragDropClientMac* client = [self dragDropClient];
+  views_bridge_mac::DragDropClient* client = [self dragDropClient];
   return client && client->Drop(sender) != NSDragOperationNone;
 }
 
@@ -1541,7 +1541,7 @@
 - (void)draggingSession:(NSDraggingSession*)session
            endedAtPoint:(NSPoint)screenPoint
               operation:(NSDragOperation)operation {
-  views::DragDropClientMac* client = [self dragDropClient];
+  views_bridge_mac::DragDropClient* client = [self dragDropClient];
   if (client)
     client->EndDrag();
 }
diff --git a/ui/views/cocoa/bridged_native_widget.h b/ui/views/cocoa/bridged_native_widget.h
index 20c93f6..bcee3c0 100644
--- a/ui/views/cocoa/bridged_native_widget.h
+++ b/ui/views/cocoa/bridged_native_widget.h
@@ -19,7 +19,6 @@
 #include "ui/base/ime/text_input_client.h"
 #include "ui/display/display_observer.h"
 #import "ui/views/cocoa/bridged_native_widget_owner.h"
-#import "ui/views/focus/focus_manager.h"
 #include "ui/views/views_export.h"
 #include "ui/views/widget/widget.h"
 #import "ui/views_bridge_mac/cocoa_mouse_capture_delegate.h"
@@ -36,8 +35,9 @@
 class BridgedNativeWidgetHost;
 }  // namespace mojom
 
-class CocoaMouseCapture;
 class BridgedNativeWidgetHostHelper;
+class CocoaMouseCapture;
+class DragDropClient;
 
 }  // namespace views_bridge_mac
 
@@ -47,8 +47,6 @@
 }
 
 class CocoaWindowMoveLoop;
-class DragDropClientMac;
-class View;
 
 using views_bridge_mac::mojom::BridgedNativeWidgetHost;
 using views_bridge_mac::BridgedNativeWidgetHostHelper;
@@ -94,12 +92,6 @@
   // this way.
   void SetWindow(base::scoped_nsobject<NativeWidgetMacNSWindow> window);
 
-  // Create the drag drop client for this widget.
-  // TODO(ccameron): This function takes a views::View (and is not rolled into
-  // CreateContentView) because drag-drop has not been routed through |host_|
-  // yet.
-  void CreateDragDropClient(views::View* view);
-
   // Set the parent NSView for the widget.
   // TODO(ccameron): Like SetWindow, this will need to pass a handle instead of
   // an NSView across processes.
@@ -170,7 +162,7 @@
   BridgedNativeWidgetHostHelper* host_helper() { return host_helper_; }
   NSWindow* ns_window();
 
-  DragDropClientMac* drag_drop_client() { return drag_drop_client_.get(); }
+  views_bridge_mac::DragDropClient* drag_drop_client();
   bool is_translucent_window() const { return is_translucent_window_; }
 
   // The parent widget specified in Widget::InitParams::parent. If non-null, the
@@ -267,9 +259,6 @@
   // Notify descendants of a visibility change.
   void NotifyVisibilityChangeDown();
 
-  // Installs the NSView for hosting the composited layer.
-  void AddCompositorSuperview();
-
   // Query the display properties of the monitor that |window_| is on, and
   // forward them to |host_|.
   void UpdateWindowDisplay();
@@ -304,7 +293,6 @@
   base::scoped_nsobject<ModalShowAnimationWithLayer> show_animation_;
   std::unique_ptr<CocoaMouseCapture> mouse_capture_;
   std::unique_ptr<CocoaWindowMoveLoop> window_move_loop_;
-  std::unique_ptr<DragDropClientMac> drag_drop_client_;
   ui::ModalType modal_type_ = ui::MODAL_TYPE_NONE;
   bool is_translucent_window_ = false;
   bool widget_is_top_level_ = false;
@@ -321,7 +309,6 @@
   // |content_dip_size_|, which is the frame size most recently *sent to* the
   // compositor.
   gfx::Size compositor_frame_dip_size_;
-  base::scoped_nsobject<NSView> compositor_superview_;
   std::unique_ptr<ui::DisplayCALayerTree> display_ca_layer_tree_;
 
   // Tracks the bounds when the window last started entering fullscreen. Used to
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm
index fafbe54..ffc6669 100644
--- a/ui/views/cocoa/bridged_native_widget.mm
+++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -16,6 +16,7 @@
 #include "base/no_destructor.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/sys_string_conversions.h"
+#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
 #import "ui/base/cocoa/window_size_constants.h"
@@ -78,18 +79,6 @@
 }
 @end
 
-// The NSView that hosts the composited CALayer drawing the UI. It fills the
-// window but is not hittable so that accessibility hit tests always go to the
-// BridgedContentView.
-@interface ViewsCompositorSuperview : NSView
-@end
-
-@implementation ViewsCompositorSuperview
-- (NSView*)hitTest:(NSPoint)aPoint {
-  return nil;
-}
-@end
-
 // This class overrides NSAnimation methods to invalidate the shadow for each
 // frame. It is required because the show animation uses CGSSetWindowWarp()
 // which is touchy about the consistency of the points it is given. The show
@@ -295,7 +284,8 @@
 
 void BridgedNativeWidgetImpl::BindRequest(
     views_bridge_mac::mojom::BridgedNativeWidgetRequest request) {
-  bridge_mojo_binding_.Bind(std::move(request));
+  bridge_mojo_binding_.Bind(std::move(request),
+                            ui::WindowResizeHelperMac::Get()->task_runner());
 }
 
 void BridgedNativeWidgetImpl::SetWindow(
@@ -454,7 +444,6 @@
 void BridgedNativeWidgetImpl::DestroyContentView() {
   if (!bridged_view_)
     return;
-  drag_drop_client_.reset();
   [bridged_view_ clearView];
   bridged_view_.reset();
   [window_ setContentView:nil];
@@ -462,8 +451,6 @@
 
 void BridgedNativeWidgetImpl::CreateContentView(const gfx::Rect& bounds) {
   DCHECK(!bridged_view_);
-  // The compositor needs to point at the new content view created here.
-  DCHECK(!compositor_superview_);
 
   bridged_view_.reset(
       [[BridgedContentView alloc] initWithBridge:this bounds:bounds]);
@@ -472,17 +459,17 @@
   // this should be treated as an error and caught early.
   CHECK(bridged_view_);
 
-  // Layer backing the content view improves resize performance, reduces memory
-  // use (no backing store), and clips sublayers to rounded window corners.
+  // Set the layer first to create a layer-hosting view (not layer-backed), and
+  // set the compositor output to go to that layer.
+  base::scoped_nsobject<CALayer> background_layer([[CALayer alloc] init]);
+  display_ca_layer_tree_ =
+      std::make_unique<ui::DisplayCALayerTree>(background_layer.get());
+  [bridged_view_ setLayer:background_layer];
   [bridged_view_ setWantsLayer:YES];
 
   [window_ setContentView:bridged_view_];
 }
 
-void BridgedNativeWidgetImpl::CreateDragDropClient(View* view) {
-  drag_drop_client_.reset(new DragDropClientMac(this, view));
-}
-
 void BridgedNativeWidgetImpl::CloseWindow() {
   // Keep |window| on the stack so that the ObjectiveC block below can capture
   // it and properly increment the reference count bound to the posted task.
@@ -889,8 +876,6 @@
 }
 
 void BridgedNativeWidgetImpl::InitCompositorView() {
-  AddCompositorSuperview();
-
   // Use the regular window background for window modal sheets. The layer will
   // still paint over most of it, but the native -[NSApp beginSheet:] animation
   // blocks the UI thread, so there's no way to invalidate the shadow to match
@@ -922,12 +907,6 @@
   // orderOut: in Close(), which notifies visibility changes to Views.
   if (!bridged_view_)
     return;
-
-  // Unassociated NSViews should be ordered above associated ones. The exception
-  // is the UI compositor's superview, which should always be on the very
-  // bottom, so give it an explicit negative rank.
-  if (compositor_superview_)
-    rank[compositor_superview_] = -1;
   [bridged_view_ sortSubviewsUsingFunction:&SubviewSorter context:&rank];
 }
 
@@ -1003,6 +982,10 @@
   return window_.get();
 }
 
+views_bridge_mac::DragDropClient* BridgedNativeWidgetImpl::drag_drop_client() {
+  return host_helper_->GetDragDropClient();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // BridgedNativeWidgetImpl, ui::CATransactionObserver
 
@@ -1020,7 +1003,7 @@
     return false;
   if (ca_transaction_sync_suppressed_)
     return false;
-  if (!compositor_superview_)
+  if (!bridged_view_)
     return false;
   return content_dip_size_ != compositor_frame_dip_size_;
 }
@@ -1226,35 +1209,6 @@
             CountBridgedWindows([window_ childWindows]));
 }
 
-void BridgedNativeWidgetImpl::AddCompositorSuperview() {
-  DCHECK(!compositor_superview_);
-  compositor_superview_.reset(
-      [[ViewsCompositorSuperview alloc] initWithFrame:[bridged_view_ bounds]]);
-
-  // Size and resize automatically with |bridged_view_|.
-  [compositor_superview_
-      setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-  // Enable HiDPI backing when supported (only on 10.7+).
-  if ([compositor_superview_ respondsToSelector:
-      @selector(setWantsBestResolutionOpenGLSurface:)]) {
-    [compositor_superview_ setWantsBestResolutionOpenGLSurface:YES];
-  }
-
-  // Set the layer first to create a layer-hosting view (not layer-backed), and
-  // set the compositor output to go to that layer.
-  base::scoped_nsobject<CALayer> background_layer([[CALayer alloc] init]);
-  display_ca_layer_tree_ =
-      std::make_unique<ui::DisplayCALayerTree>(background_layer.get());
-  [compositor_superview_ setLayer:background_layer];
-  [compositor_superview_ setWantsLayer:YES];
-
-  // The UI compositor should always be the first subview, to ensure webviews
-  // are drawn on top of it.
-  DCHECK_EQ(0u, [[bridged_view_ subviews] count]);
-  [bridged_view_ addSubview:compositor_superview_];
-}
-
 void BridgedNativeWidgetImpl::UpdateWindowGeometry() {
   gfx::Rect window_in_screen = gfx::ScreenRectFromNSRect([window_ frame]);
   gfx::Rect content_in_screen = gfx::ScreenRectFromNSRect(
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.h b/ui/views/cocoa/bridged_native_widget_host_impl.h
index 2e08c03..91a2e35a 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.h
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -15,6 +15,7 @@
 #include "ui/base/ime/input_method_delegate.h"
 #include "ui/compositor/layer_owner.h"
 #include "ui/views/cocoa/bridge_factory_host.h"
+#include "ui/views/cocoa/drag_drop_client_mac.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/views_export.h"
 #include "ui/views/widget/widget.h"
@@ -92,6 +93,10 @@
 
   TooltipManager* tooltip_manager() { return tooltip_manager_.get(); }
 
+  DragDropClientMac* drag_drop_client() const {
+    return drag_drop_client_.get();
+  }
+
   // Create and set the bridge object to be in this process.
   void CreateLocalBridge(base::scoped_nsobject<NativeWidgetMacNSWindow> window,
                          NSView* parent);
@@ -190,6 +195,7 @@
                  gfx::DecoratedText* decorated_word,
                  gfx::Point* baseline_point) override;
   double SheetPositionY() override;
+  views_bridge_mac::DragDropClient* GetDragDropClient() override;
 
   // BridgeFactoryHost::Observer:
   void OnBridgeFactoryHostDestroying(BridgeFactoryHost* host) override;
@@ -293,6 +299,7 @@
   Widget::InitParams::Type widget_type_ = Widget::InitParams::TYPE_WINDOW;
 
   views::View* root_view_ = nullptr;  // Weak. Owned by |native_widget_mac_|.
+  std::unique_ptr<DragDropClientMac> drag_drop_client_;
 
   // The mojo pointer to a BridgedNativeWidget, which may exist in another
   // process.
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.mm b/ui/views/cocoa/bridged_native_widget_host_impl.mm
index 72405ed..d3e9d99e1 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.mm
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -5,6 +5,7 @@
 #include "ui/views/cocoa/bridged_native_widget_host_impl.h"
 
 #include "base/mac/foundation_util.h"
+#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/input_method_factory.h"
@@ -145,7 +146,8 @@
 
   // Initialize |bridge_ptr_| to point to a bridge created by |factory|.
   views_bridge_mac::mojom::BridgedNativeWidgetHostPtr host_ptr;
-  host_mojo_binding_.Bind(mojo::MakeRequest(&host_ptr));
+  host_mojo_binding_.Bind(mojo::MakeRequest(&host_ptr),
+                          ui::WindowResizeHelperMac::Get()->task_runner());
   bridge_factory_host_->GetFactory()->CreateBridge(
       id_, mojo::MakeRequest(&bridge_ptr_), std::move(host_ptr));
 
@@ -247,6 +249,15 @@
 
 void BridgedNativeWidgetHostImpl::SetRootView(views::View* root_view) {
   root_view_ = root_view;
+  if (root_view_) {
+    // TODO(ccameron): Drag-drop functionality does not yet run over mojo.
+    if (bridge_impl_) {
+      drag_drop_client_.reset(
+          new DragDropClientMac(bridge_impl_.get(), root_view_));
+    }
+  } else {
+    drag_drop_client_.reset();
+  }
 }
 
 void BridgedNativeWidgetHostImpl::CreateCompositor(
@@ -453,6 +464,11 @@
   return native_widget_mac_->SheetPositionY();
 }
 
+views_bridge_mac::DragDropClient*
+BridgedNativeWidgetHostImpl::GetDragDropClient() {
+  return drag_drop_client_.get();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // BridgedNativeWidgetHostImpl, BridgeFactoryHost::Observer:
 void BridgedNativeWidgetHostImpl::OnBridgeFactoryHostDestroying(
diff --git a/ui/views/cocoa/drag_drop_client_mac.h b/ui/views/cocoa/drag_drop_client_mac.h
index f4044b7..e93d8a0 100644
--- a/ui/views/cocoa/drag_drop_client_mac.h
+++ b/ui/views/cocoa/drag_drop_client_mac.h
@@ -14,6 +14,7 @@
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/views/views_export.h"
 #include "ui/views/widget/drop_helper.h"
+#include "ui/views_bridge_mac/drag_drop_client.h"
 
 // This class acts as a bridge between NSPasteboardItem and OSExchangeData by
 // implementing NSPasteboardItemDataProvider and writing data from
@@ -38,10 +39,10 @@
 // Implements drag and drop on MacViews. This class acts as a bridge between
 // the Views and native system's drag and drop. This class mimics
 // DesktopDragDropClientAuraX11.
-class VIEWS_EXPORT DragDropClientMac {
+class VIEWS_EXPORT DragDropClientMac : public views_bridge_mac::DragDropClient {
  public:
   DragDropClientMac(BridgedNativeWidgetImpl* bridge, View* root_view);
-  ~DragDropClientMac();
+  ~DragDropClientMac() override;
 
   // Initiates a drag and drop session. Returns the drag operation that was
   // applied at the end of the drag drop session.
@@ -50,20 +51,14 @@
                         int operation,
                         ui::DragDropTypes::DragEventSource source);
 
-  // Called when mouse is dragged during a drag and drop.
-  NSDragOperation DragUpdate(id<NSDraggingInfo>);
-
-  // Called when mouse is released during a drag and drop.
-  NSDragOperation Drop(id<NSDraggingInfo> sender);
-
-  // Called when the drag and drop session has ended.
-  void EndDrag();
-
-  // Called when mouse leaves the drop area.
-  void DragExit();
-
   DropHelper* drop_helper() { return &drop_helper_; }
 
+  // views_bridge_mac::DragDropClient:
+  NSDragOperation DragUpdate(id<NSDraggingInfo>) override;
+  NSDragOperation Drop(id<NSDraggingInfo> sender) override;
+  void EndDrag() override;
+  void DragExit() override;
+
  private:
   friend class test::DragDropClientMacTest;
 
diff --git a/ui/views/cocoa/drag_drop_client_mac_unittest.mm b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
index e91bb57..47c8ffe 100644
--- a/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -156,7 +156,9 @@
  public:
   DragDropClientMacTest() : widget_(new Widget) {}
 
-  DragDropClientMac* drag_drop_client() { return bridge_->drag_drop_client(); }
+  DragDropClientMac* drag_drop_client() {
+    return bridge_host_->drag_drop_client();
+  }
 
   NSDragOperation DragUpdate(NSPasteboard* pasteboard) {
     DragDropClientMac* client = drag_drop_client();
diff --git a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
index 2cc6a8c..7acfc99f 100644
--- a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
+++ b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -106,6 +106,8 @@
         gfx::Rect(kWindowOffset, kWindowOffset, kWindowWidth, kWindowHeight));
     parent_->Show();
 
+    native_view_subview_count_ = [[parent_->GetNativeView() subviews] count];
+
     base::Closure on_close = base::Bind(&MenuRunnerCocoaTest::MenuCloseCallback,
                                         base::Unretained(this));
     if (GetParam() == MenuType::NATIVE)
@@ -116,6 +118,9 @@
   }
 
   void TearDown() override {
+    EXPECT_EQ(native_view_subview_count_,
+              [[parent_->GetNativeView() subviews] count]);
+
     if (runner_) {
       runner_->Release();
       runner_ = NULL;
@@ -151,10 +156,6 @@
   void RunMenuAt(const gfx::Rect& anchor) {
     last_anchor_frame_ = NSZeroRect;
 
-    // Should be one child (the compositor layer) before showing, and it should
-    // go up by one (the anchor view) while the menu is shown.
-    EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]);
-
     base::OnceClosure callback =
         base::BindOnce(&MenuRunnerCocoaTest::ComboboxRunMenuAtCallback,
                        base::Unretained(this));
@@ -168,9 +169,6 @@
     runner_->RunMenuAt(parent_, nullptr, anchor, MENU_ANCHOR_TOPLEFT,
                        MenuRunner::COMBOBOX);
     MaybeRunAsync();
-
-    // Ensure the anchor view is removed.
-    EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]);
   }
 
   void MenuCancelCallback() {
@@ -244,6 +242,7 @@
   internal::MenuRunnerImplInterface* runner_ = nullptr;
   views::Widget* parent_ = nullptr;
   NSRect last_anchor_frame_ = NSZeroRect;
+  NSUInteger native_view_subview_count_ = 0;
   int menu_close_count_ = 0;
 
  private:
@@ -256,10 +255,11 @@
     NSArray* subviews = [parent_->GetNativeView() subviews];
     // An anchor view should only be added for Native menus.
     if (GetParam() == MenuType::NATIVE) {
-      ASSERT_EQ(2u, [subviews count]);
-      last_anchor_frame_ = [[subviews objectAtIndex:1] frame];
+      ASSERT_EQ(native_view_subview_count_ + 1, [subviews count]);
+      last_anchor_frame_ =
+          [[subviews objectAtIndex:native_view_subview_count_] frame];
     } else {
-      EXPECT_EQ(1u, [subviews count]);
+      EXPECT_EQ(native_view_subview_count_, [subviews count]);
     }
     runner_->Cancel();
   }
diff --git a/ui/views/mus/ax_remote_host.cc b/ui/views/mus/ax_remote_host.cc
index edb77057..6fa87f1 100644
--- a/ui/views/mus/ax_remote_host.cc
+++ b/ui/views/mus/ax_remote_host.cc
@@ -102,9 +102,15 @@
   if (!enabled_)
     return;
 
-  AXAuraObjWrapper* aura_obj =
-      view ? AXAuraObjCache::GetInstance()->GetOrCreate(view)
-           : tree_source_->GetRoot();
+  if (!view) {
+    SendEvent(tree_source_->GetRoot(), event_type);
+    return;
+  }
+
+  // Can return null for views without a widget.
+  AXAuraObjWrapper* aura_obj = AXAuraObjCache::GetInstance()->GetOrCreate(view);
+  if (!aura_obj)
+    return;
   SendEvent(aura_obj, event_type);
 }
 
diff --git a/ui/views/mus/ax_remote_host_unittest.cc b/ui/views/mus/ax_remote_host_unittest.cc
index f853363..359d057 100644
--- a/ui/views/mus/ax_remote_host_unittest.cc
+++ b/ui/views/mus/ax_remote_host_unittest.cc
@@ -165,6 +165,20 @@
   EXPECT_EQ(ax::mojom::Event::kLoadComplete, service.last_event_.event_type);
 }
 
+// Verifies that a remote app doesn't crash if a View triggers an accessibility
+// event before it is attached to a Widget. https://crbug.com/889121
+TEST_F(AXRemoteHostTest, SendEventOnViewWithNoWidget) {
+  TestAXHostService service(true /*automation_enabled*/);
+  AXRemoteHost* remote = CreateRemote(&service);
+  std::unique_ptr<Widget> widget = CreateTestWidget();
+  remote->FlushForTesting();
+
+  // Create a view that is not yet associated with the widget.
+  views::View view;
+  remote->HandleEvent(&view, ax::mojom::Event::kLocationChanged);
+  // No crash.
+}
+
 // Verifies that the AXRemoteHost stops monitoring widgets that are closed
 // asynchronously, like when ash requests close via DesktopWindowTreeHostMus.
 // https://crbug.com/869608
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 3fa4df8..cba45a1a7 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -145,8 +145,6 @@
   DCHECK(GetWidget()->GetRootView());
   bridge_host_->SetRootView(GetWidget()->GetRootView());
   bridge()->CreateContentView(GetWidget()->GetRootView()->bounds());
-  if (bridge_impl())
-    bridge_impl()->CreateDragDropClient(GetWidget()->GetRootView());
   if (auto* focus_manager = GetWidget()->GetFocusManager()) {
     bridge()->MakeFirstResponder();
     bridge_host_->SetFocusManager(focus_manager);
@@ -220,7 +218,7 @@
 
 void NativeWidgetMac::ViewRemoved(View* view) {
   DragDropClientMac* client =
-      bridge_impl() ? bridge_impl()->drag_drop_client() : nullptr;
+      bridge_host_ ? bridge_host_->drag_drop_client() : nullptr;
   if (client)
     client->drop_helper()->ResetTargetViewIfEquals(view);
 }
@@ -513,8 +511,8 @@
                                    const gfx::Point& location,
                                    int operation,
                                    ui::DragDropTypes::DragEventSource source) {
-  bridge_impl()->drag_drop_client()->StartDragAndDrop(view, data, operation,
-                                                      source);
+  bridge_host_->drag_drop_client()->StartDragAndDrop(view, data, operation,
+                                                     source);
 }
 
 void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index 7436e30..b4ae028 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -2180,8 +2180,10 @@
 
     widget_ = CreateTopLevelPlatformWidget();
 
-    ASSERT_EQ(1u, [[widget_->GetNativeView() subviews] count]);
-    compositor_view_ = [[widget_->GetNativeView() subviews] firstObject];
+    // It's not a bug if the native view has a different number of subviews,
+    // but the rest of this test assumes it. It may or may not be worth
+    // removing that assumption at some point.
+    ASSERT_EQ(0u, [[widget_->GetNativeView() subviews] count]);
 
     native_host_parent_ = new View();
     widget_->GetContentsView()->AddChildView(native_host_parent_);
@@ -2194,10 +2196,8 @@
       hosts_.push_back(std::move(holder));
     }
     EXPECT_EQ(kNativeViewCount, native_host_parent_->child_count());
-    EXPECT_NSEQ([widget_->GetNativeView() subviews], (@[
-                  compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
-                  hosts_[2]->view()
-                ]));
+    EXPECT_NSEQ([widget_->GetNativeView() subviews],
+                (@[ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view() ]));
   }
 
   void TearDown() override {
@@ -2209,7 +2209,6 @@
 
   Widget* widget_ = nullptr;
   View* native_host_parent_ = nullptr;
-  NSView* compositor_view_ = nil;
   std::vector<std::unique_ptr<NativeHostHolder>> hosts_;
 
  private:
@@ -2221,58 +2220,50 @@
 TEST_F(NativeWidgetMacViewsOrderTest, NativeViewAttached) {
   hosts_[1]->Detach();
   EXPECT_NSEQ([GetContentNativeView() subviews],
-              (@[ compositor_view_, hosts_[0]->view(), hosts_[2]->view() ]));
+              (@[ hosts_[0]->view(), hosts_[2]->view() ]));
 
   hosts_[1]->AttachNativeView();
-  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
-                compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
-                hosts_[2]->view()
-              ]));
+  EXPECT_NSEQ([GetContentNativeView() subviews],
+              (@[ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view() ]));
 }
 
 // Tests that NativeViews order changes according to views::View hierarchy.
 TEST_F(NativeWidgetMacViewsOrderTest, ReorderViews) {
   native_host_parent_->ReorderChildView(hosts_[2]->host(), 1);
-  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
-                compositor_view_, hosts_[0]->view(), hosts_[2]->view(),
-                hosts_[1]->view()
-              ]));
+  EXPECT_NSEQ([GetContentNativeView() subviews],
+              (@[ hosts_[0]->view(), hosts_[2]->view(), hosts_[1]->view() ]));
 
   native_host_parent_->RemoveChildView(hosts_[2]->host());
   EXPECT_NSEQ([GetContentNativeView() subviews],
-              (@[ compositor_view_, hosts_[0]->view(), hosts_[1]->view() ]));
+              (@[ hosts_[0]->view(), hosts_[1]->view() ]));
 
   View* new_parent = new View();
   native_host_parent_->RemoveChildView(hosts_[1]->host());
   native_host_parent_->AddChildView(new_parent);
   new_parent->AddChildView(hosts_[1]->host());
   new_parent->AddChildView(hosts_[2]->host());
-  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
-                compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
-                hosts_[2]->view()
-              ]));
+  EXPECT_NSEQ([GetContentNativeView() subviews],
+              (@[ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view() ]));
 
   native_host_parent_->ReorderChildView(new_parent, 0);
-  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
-                compositor_view_, hosts_[1]->view(), hosts_[2]->view(),
-                hosts_[0]->view()
-              ]));
+  EXPECT_NSEQ([GetContentNativeView() subviews],
+              (@[ hosts_[1]->view(), hosts_[2]->view(), hosts_[0]->view() ]));
 }
 
 // Test that unassociated native views stay on top after reordering.
 TEST_F(NativeWidgetMacViewsOrderTest, UnassociatedViewsIsAbove) {
   base::scoped_nsobject<NSView> child_view([[NSView alloc] init]);
   [GetContentNativeView() addSubview:child_view];
-  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
-                compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
-                hosts_[2]->view(), child_view
-              ]));
+  EXPECT_NSEQ(
+      [GetContentNativeView() subviews], (@[
+        hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view(), child_view
+      ]));
 
   native_host_parent_->ReorderChildView(hosts_[2]->host(), 1);
-  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
-                compositor_view_, hosts_[0]->view(), hosts_[2]->view(),
-                hosts_[1]->view(), child_view
-              ]));
+  EXPECT_NSEQ(
+      [GetContentNativeView() subviews], (@[
+        hosts_[0]->view(), hosts_[2]->view(), hosts_[1]->view(), child_view
+      ]));
 }
 
 // Test -[NSWindowDelegate windowShouldClose:].
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 9ca4bdad..2841eb8b 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -1017,7 +1017,10 @@
 }
 
 void HWNDMessageHandler::OnTextInputStateChanged(
-    const ui::TextInputClient* client) {}
+    const ui::TextInputClient* client) {
+  if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+    OnCaretBoundsChanged(client);
+}
 
 void HWNDMessageHandler::OnInputMethodDestroyed(
     const ui::InputMethod* input_method) {
diff --git a/ui/views_bridge_mac/BUILD.gn b/ui/views_bridge_mac/BUILD.gn
index 30af4801..1043a8a 100644
--- a/ui/views_bridge_mac/BUILD.gn
+++ b/ui/views_bridge_mac/BUILD.gn
@@ -12,6 +12,7 @@
     "cocoa_mouse_capture.h",
     "cocoa_mouse_capture.mm",
     "cocoa_mouse_capture_delegate.h",
+    "drag_drop_client.h",
     "views_bridge_mac_export.h",
   ]
   defines = [ "VIEWS_BRIDGE_MAC_IMPLEMENTATION" ]
diff --git a/ui/views_bridge_mac/bridged_native_widget_host_helper.h b/ui/views_bridge_mac/bridged_native_widget_host_helper.h
index 39457d5..4fe8218c 100644
--- a/ui/views_bridge_mac/bridged_native_widget_host_helper.h
+++ b/ui/views_bridge_mac/bridged_native_widget_host_helper.h
@@ -15,6 +15,8 @@
 
 namespace views_bridge_mac {
 
+class DragDropClient;
+
 // This is a helper class for the mojo interface BridgedNativeWidgetHost.
 // This provides an easier-to-use interface than the mojo for selected
 // functions. It also is temporarily exposing functionality that is not yet
@@ -54,6 +56,10 @@
   // TODO(ccameron): This should be either moved to the mojo interface or
   // separated out in such a way as to avoid needing to go through mojo.
   virtual double SheetPositionY() = 0;
+
+  // Return a pointer to host's DragDropClientMac.
+  // TODO(ccameron): Drag-drop behavior needs to be implemented over mojo.
+  virtual DragDropClient* GetDragDropClient() = 0;
 };
 
 }  // namespace views_bridge_mac
diff --git a/ui/views_bridge_mac/drag_drop_client.h b/ui/views_bridge_mac/drag_drop_client.h
new file mode 100644
index 0000000..3efa842
--- /dev/null
+++ b/ui/views_bridge_mac/drag_drop_client.h
@@ -0,0 +1,37 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_BRIDGE_MAC_DRAG_DROP_CLIENT_H_
+#define UI_VIEWS_BRIDGE_MAC_DRAG_DROP_CLIENT_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "ui/views_bridge_mac/views_bridge_mac_export.h"
+
+namespace views_bridge_mac {
+
+// Interface between the content view of a BridgedNativeWidgetImpl and a
+// DragDropClientMac in the browser process. This interface should eventually
+// become mojo-ified, but at the moment only passes raw pointers (consequently,
+// drag-drop behavior does not work in RemoteMacViews).
+class VIEWS_BRIDGE_MAC_EXPORT DragDropClient {
+ public:
+  virtual ~DragDropClient() {}
+
+  // Called when mouse is dragged during a drag and drop.
+  virtual NSDragOperation DragUpdate(id<NSDraggingInfo>) = 0;
+
+  // Called when mouse is released during a drag and drop.
+  virtual NSDragOperation Drop(id<NSDraggingInfo> sender) = 0;
+
+  // Called when the drag and drop session has ended.
+  virtual void EndDrag() = 0;
+
+  // Called when mouse leaves the drop area.
+  virtual void DragExit() = 0;
+};
+
+}  // namespace views_bridge_mac
+
+#endif  // UI_VIEWS_BRIDGE_MAC_DRAG_DROP_CLIENT_H_