diff --git a/DEPS b/DEPS
index 93366c3..37460fe 100644
--- a/DEPS
+++ b/DEPS
@@ -86,7 +86,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': '361df070323f430aa0614c6eb04fb595dec3daa9',
+  'angle_revision': '76746f9bc29d23a00a56eaa5941209976e3301bc',
   # 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.
@@ -98,7 +98,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': '1f0d1fda6db83ee402561902c76ae8a6da124663',
+  'pdfium_revision': '752e9bf892abdf1ee588ba87c857d0783a017b27',
   # 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.
diff --git a/ash/frame/custom_frame_view_ash.cc b/ash/frame/custom_frame_view_ash.cc
index 23e918d..c1539cf5 100644
--- a/ash/frame/custom_frame_view_ash.cc
+++ b/ash/frame/custom_frame_view_ash.cc
@@ -15,6 +15,7 @@
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
 #include "ash/shell.h"
+#include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/resize_handle_window_targeter.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_observer.h"
@@ -322,10 +323,13 @@
                                                   enable_immersive)));
   }
   Shell::Get()->AddShellObserver(this);
+  Shell::Get()->split_view_controller()->AddObserver(this);
 }
 
 CustomFrameViewAsh::~CustomFrameViewAsh() {
   Shell::Get()->RemoveShellObserver(this);
+  if (Shell::Get()->split_view_controller())
+    Shell::Get()->split_view_controller()->RemoveObserver(this);
 }
 
 void CustomFrameViewAsh::InitImmersiveFullscreenControllerForView(
@@ -477,6 +481,26 @@
   return header_view_->avatar_icon();
 }
 
+void CustomFrameViewAsh::MaybePaintHeaderForSplitview(
+    SplitViewController::State state) {
+  if (state == SplitViewController::NO_SNAP) {
+    header_view_->SetShouldPaintHeader(/*paint=*/false);
+    return;
+  }
+
+  SplitViewController* controller = Shell::Get()->split_view_controller();
+  aura::Window* window = nullptr;
+  if (state == SplitViewController::LEFT_SNAPPED)
+    window = controller->left_window();
+  else if (state == SplitViewController::RIGHT_SNAPPED)
+    window = controller->right_window();
+
+  // TODO(sammiequon): This works for now, but we may have to check if
+  // |frame_|'s native window is in the overview list instead.
+  if (window && window == frame_->GetNativeWindow())
+    header_view_->SetShouldPaintHeader(/*paint=*/true);
+}
+
 void CustomFrameViewAsh::SetShouldPaintHeader(bool paint) {
   header_view_->SetShouldPaintHeader(paint);
 }
@@ -489,6 +513,13 @@
   SetShouldPaintHeader(true);
 }
 
+void CustomFrameViewAsh::OnSplitViewStateChanged(
+    SplitViewController::State /* previous_state */,
+    SplitViewController::State state) {
+  if (Shell::Get()->window_selector_controller()->IsSelecting())
+    MaybePaintHeaderForSplitview(state);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // CustomFrameViewAsh, private:
 
diff --git a/ash/frame/custom_frame_view_ash.h b/ash/frame/custom_frame_view_ash.h
index ee408094..9d74736 100644
--- a/ash/frame/custom_frame_view_ash.h
+++ b/ash/frame/custom_frame_view_ash.h
@@ -10,6 +10,7 @@
 #include "ash/ash_export.h"
 #include "ash/public/interfaces/window_style.mojom.h"
 #include "ash/shell_observer.h"
+#include "ash/wm/splitview/split_view_controller.h"
 #include "base/macros.h"
 #include "base/optional.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -39,7 +40,8 @@
 // the top of the screen. See also views::CustomFrameView and
 // BrowserNonClientFrameViewAsh.
 class ASH_EXPORT CustomFrameViewAsh : public views::NonClientFrameView,
-                                      public ash::ShellObserver {
+                                      public ShellObserver,
+                                      public SplitViewController::Observer {
  public:
   // Internal class name.
   static const char kViewClassName[];
@@ -100,15 +102,24 @@
   void SchedulePaintInRect(const gfx::Rect& r) override;
   void SetVisible(bool visible) override;
 
+  // Called when splitview state changes. Depending on |state| and if the window
+  // associated with |widget_| is the snapped window, paint the header in
+  // overview mode.
+  void MaybePaintHeaderForSplitview(SplitViewController::State state);
+
   // If |paint| is false, we should not paint the header. Used for overview mode
   // with OnOverviewModeStarting() and OnOverviewModeEnded() to hide/show the
   // header of v2 and ARC apps.
   virtual void SetShouldPaintHeader(bool paint);
 
-  // ash::ShellObserver:
+  // ShellObserver:
   void OnOverviewModeStarting() override;
   void OnOverviewModeEnded() override;
 
+  // SplitViewController::Observer:
+  void OnSplitViewStateChanged(SplitViewController::State previous_state,
+                               SplitViewController::State state) override;
+
   const views::View* GetAvatarIconViewForTest() const;
 
  private:
diff --git a/ash/frame/custom_frame_view_ash_unittest.cc b/ash/frame/custom_frame_view_ash_unittest.cc
index 4666979..fc4176c 100644
--- a/ash/frame/custom_frame_view_ash_unittest.cc
+++ b/ash/frame/custom_frame_view_ash_unittest.cc
@@ -13,9 +13,11 @@
 #include "ash/frame/header_view.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
+#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/events/test/event_generator.h"
@@ -45,6 +47,8 @@
 
   CustomFrameViewAsh* custom_frame_view() const { return custom_frame_view_; }
 
+  HeaderView* header_view() const { return custom_frame_view_->header_view_; }
+
  private:
   // Not owned.
   CustomFrameViewAsh* custom_frame_view_;
@@ -316,6 +320,63 @@
       delegate->GetCustomFrameViewTopBorderHeight());
 }
 
+TEST_F(CustomFrameViewAshTest, HeaderVisibilityInOverviewMode) {
+  auto* delegate = new CustomFrameTestWidgetDelegate();
+  auto* widget = new views::Widget();
+  views::Widget::InitParams params;
+  params.context = CurrentContext();
+  params.delegate = delegate;
+  widget->Init(params);
+  widget->Show();
+
+  // Verify the header is not painted in overview mode and painted when not in
+  // overview mode.
+  Shell::Get()->window_selector_controller()->ToggleOverview();
+  EXPECT_FALSE(delegate->header_view()->should_paint());
+
+  Shell::Get()->window_selector_controller()->ToggleOverview();
+  EXPECT_TRUE(delegate->header_view()->should_paint());
+}
+
+TEST_F(CustomFrameViewAshTest, HeaderVisibilityInSplitview) {
+  auto set_up_widget = [this](CustomFrameTestWidgetDelegate* delegate,
+                              views::Widget* widget) {
+    views::Widget::InitParams params;
+    params.context = CurrentContext();
+    params.delegate = delegate;
+    widget->Init(params);
+    widget->Show();
+    // Windows need to be resizable and maximizable to be used in splitview.
+    widget->GetNativeWindow()->SetProperty(
+        aura::client::kResizeBehaviorKey,
+        ui::mojom::kResizeBehaviorCanMaximize |
+            ui::mojom::kResizeBehaviorCanResize);
+  };
+
+  auto* delegate1 = new CustomFrameTestWidgetDelegate();
+  auto* widget1 = new views::Widget();
+  auto* delegate2 = new CustomFrameTestWidgetDelegate();
+  auto* widget2 = new views::Widget();
+  set_up_widget(delegate1, widget1);
+  set_up_widget(delegate2, widget2);
+
+  // Verify that when one window is snapped, the header is drawn for the snapped
+  // window, but not drawn for the window still in overview.
+  Shell::Get()->window_selector_controller()->ToggleOverview();
+  Shell::Get()->split_view_controller()->SnapWindow(widget1->GetNativeWindow(),
+                                                    SplitViewController::LEFT);
+  EXPECT_TRUE(delegate1->header_view()->should_paint());
+  EXPECT_FALSE(delegate2->header_view()->should_paint());
+
+  // Verify that when both windows are snapped, the header is drawn for both.
+  Shell::Get()->split_view_controller()->SnapWindow(widget2->GetNativeWindow(),
+                                                    SplitViewController::RIGHT);
+  EXPECT_TRUE(delegate1->header_view()->should_paint());
+  EXPECT_TRUE(delegate2->header_view()->should_paint());
+
+  Shell::Get()->split_view_controller()->EndSplitView();
+}
+
 namespace {
 
 class TestTarget : public ui::AcceleratorTarget {
diff --git a/ash/frame/header_view.h b/ash/frame/header_view.h
index 6a5a750..5055eeb 100644
--- a/ash/frame/header_view.h
+++ b/ash/frame/header_view.h
@@ -51,6 +51,8 @@
 
   FrameCaptionButton* back_button() { return back_button_; }
 
+  bool should_paint() { return should_paint_; }
+
   // Schedules a repaint for the entire title.
   void SchedulePaintForTitle();
 
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index f9f1334..06400921 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -31,7 +31,8 @@
 
 }  // namespace
 
-LoginScreenController::LoginScreenController() : binding_(this) {}
+LoginScreenController::LoginScreenController()
+    : binding_(this), weak_factory_(this) {}
 
 LoginScreenController::~LoginScreenController() = default;
 
@@ -122,13 +123,18 @@
   }
 }
 
-void LoginScreenController::AuthenticateUser(
-    const AccountId& account_id,
-    const std::string& password,
-    bool authenticated_by_pin,
-    mojom::LoginScreenClient::AuthenticateUserCallback callback) {
-  if (!login_screen_client_)
+void LoginScreenController::AuthenticateUser(const AccountId& account_id,
+                                             const std::string& password,
+                                             bool authenticated_by_pin,
+                                             OnAuthenticateCallback callback) {
+  // Ignore concurrent auth attempts. This can happen if the user quickly enters
+  // two separate passwords and hits enter.
+  if (!login_screen_client_ || is_authenticating_) {
+    LOG_IF(ERROR, is_authenticating_) << "Ignoring concurrent auth attempt";
+    std::move(callback).Run(base::nullopt);
     return;
+  }
+  is_authenticating_ = true;
 
   // If auth is disabled by the debug overlay bypass the mojo call entirely, as
   // it will dismiss the lock screen if the password is correct.
@@ -136,25 +142,26 @@
     case ForceFailAuth::kOff:
       break;
     case ForceFailAuth::kImmediate:
-      std::move(callback).Run(false);
+      OnAuthenticateComplete(std::move(callback), false /*success*/);
       return;
     case ForceFailAuth::kDelayed:
       base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-          FROM_HERE, base::BindOnce(std::move(callback), false),
+          FROM_HERE,
+          base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
+                         weak_factory_.GetWeakPtr(), base::Passed(&callback),
+                         false),
           base::TimeDelta::FromSeconds(1));
       return;
   }
 
-  // We cannot execute auth requests directly via GetSystemSalt because it
-  // expects a base::Callback instance, but |callback| is a base::OnceCallback.
-  // Instead, we store |callback| on this object and invoke it locally once we
-  // have the system salt.
-  DCHECK(!pending_user_auth_) << "More than one concurrent auth attempt";
-  pending_user_auth_ = base::BindOnce(
-      &LoginScreenController::DoAuthenticateUser, base::Unretained(this),
+  // |DoAuthenticateUser| requires the system salt, so we fetch it first, and
+  // then run |DoAuthenticateUser| as a continuation.
+  auto do_authenticate = base::BindOnce(
+      &LoginScreenController::DoAuthenticateUser, weak_factory_.GetWeakPtr(),
       account_id, password, authenticated_by_pin, std::move(callback));
-  chromeos::SystemSaltGetter::Get()->GetSystemSalt(base::Bind(
-      &LoginScreenController::OnGetSystemSalt, base::Unretained(this)));
+  chromeos::SystemSaltGetter::Get()->GetSystemSalt(base::BindRepeating(
+      &LoginScreenController::OnGetSystemSalt, weak_factory_.GetWeakPtr(),
+      base::Passed(&do_authenticate)));
 }
 
 void LoginScreenController::HandleFocusLeavingLockScreenApps(bool reverse) {
@@ -240,12 +247,11 @@
   login_screen_client_.FlushForTesting();
 }
 
-void LoginScreenController::DoAuthenticateUser(
-    const AccountId& account_id,
-    const std::string& password,
-    bool authenticated_by_pin,
-    mojom::LoginScreenClient::AuthenticateUserCallback callback,
-    const std::string& system_salt) {
+void LoginScreenController::DoAuthenticateUser(const AccountId& account_id,
+                                               const std::string& password,
+                                               bool authenticated_by_pin,
+                                               OnAuthenticateCallback callback,
+                                               const std::string& system_salt) {
   int dummy_value;
   bool is_pin =
       authenticated_by_pin && base::StringToInt(password, &dummy_value);
@@ -273,12 +279,22 @@
   Shell::Get()->metrics()->login_metrics_recorder()->SetAuthMethod(
       is_pin ? LoginMetricsRecorder::AuthMethod::kPin
              : LoginMetricsRecorder::AuthMethod::kPassword);
-  login_screen_client_->AuthenticateUser(account_id, hashed_password, is_pin,
-                                         std::move(callback));
+  login_screen_client_->AuthenticateUser(
+      account_id, hashed_password, is_pin,
+      base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
+                     weak_factory_.GetWeakPtr(), base::Passed(&callback)));
 }
 
-void LoginScreenController::OnGetSystemSalt(const std::string& system_salt) {
-  std::move(pending_user_auth_).Run(system_salt);
+void LoginScreenController::OnAuthenticateComplete(
+    OnAuthenticateCallback callback,
+    bool success) {
+  is_authenticating_ = false;
+  std::move(callback).Run(success);
+}
+
+void LoginScreenController::OnGetSystemSalt(PendingDoAuthenticateUser then,
+                                            const std::string& system_salt) {
+  std::move(then).Run(system_salt);
 }
 
 LoginDataDispatcher* LoginScreenController::DataDispatcher() const {
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h
index fd85f4f..d74c5a86 100644
--- a/ash/login/login_screen_controller.h
+++ b/ash/login/login_screen_controller.h
@@ -9,6 +9,7 @@
 #include "ash/public/interfaces/login_screen.mojom.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
+#include "base/optional.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
 class PrefRegistrySimple;
@@ -26,6 +27,11 @@
 class ASH_EXPORT LoginScreenController : public mojom::LoginScreen {
  public:
   using OnShownCallback = base::OnceCallback<void(bool did_show)>;
+  // Callback for authentication checks. |success| is nullopt if an
+  // authentication check did not run, otherwise it is true/false if auth
+  // succeeded/failed.
+  using OnAuthenticateCallback =
+      base::OnceCallback<void(base::Optional<bool> success)>;
 
   LoginScreenController();
   ~LoginScreenController() override;
@@ -63,11 +69,10 @@
   // LoginScreenClient(chrome) will do the authentication and request to show
   // error messages in the screen if auth fails, or request to clear errors if
   // auth succeeds.
-  void AuthenticateUser(
-      const AccountId& account_id,
-      const std::string& password,
-      bool authenticated_by_pin,
-      mojom::LoginScreenClient::AuthenticateUserCallback callback);
+  void AuthenticateUser(const AccountId& account_id,
+                        const std::string& password,
+                        bool authenticated_by_pin,
+                        OnAuthenticateCallback callback);
   void AttemptUnlock(const AccountId& account_id);
   void HardlockPod(const AccountId& account_id);
   void RecordClickOnLockIcon(const AccountId& account_id);
@@ -95,29 +100,30 @@
   }
 
  private:
-  using PendingAuthenticateUserCall =
+  using PendingDoAuthenticateUser =
       base::OnceCallback<void(const std::string& system_salt)>;
 
-  void DoAuthenticateUser(
-      const AccountId& account_id,
-      const std::string& password,
-      bool authenticated_by_pin,
-      mojom::LoginScreenClient::AuthenticateUserCallback callback,
-      const std::string& system_salt);
+  void DoAuthenticateUser(const AccountId& account_id,
+                          const std::string& password,
+                          bool authenticated_by_pin,
+                          OnAuthenticateCallback callback,
+                          const std::string& system_salt);
+  void OnAuthenticateComplete(OnAuthenticateCallback callback, bool success);
 
-  void OnGetSystemSalt(const std::string& system_salt);
+  void OnGetSystemSalt(PendingDoAuthenticateUser then,
+                       const std::string& system_salt);
 
-  // Returns the active data dispatcher or nullptr if there is no screen.
+  // Returns the active data dispatcher or nullptr if there is no lock screen.
   LoginDataDispatcher* DataDispatcher() const;
 
   // Client interface in chrome browser. May be null in tests.
   mojom::LoginScreenClientPtr login_screen_client_;
 
-  // Binding for the LoginScreen interface.
+  // Binding for the LockScreen interface.
   mojo::Binding<mojom::LoginScreen> binding_;
 
-  // User authentication call that will run when we have system salt.
-  PendingAuthenticateUserCall pending_user_auth_;
+  // True iff we are currently authentication.
+  bool is_authenticating_ = false;
 
   base::ObserverList<LockScreenAppsFocusObserver>
       lock_screen_apps_focus_observers_;
@@ -125,9 +131,11 @@
   // If set to false, all auth requests will forcibly fail.
   ForceFailAuth force_fail_auth_for_debug_overlay_ = ForceFailAuth::kOff;
 
+  base::WeakPtrFactory<LoginScreenController> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(LoginScreenController);
 };
 
 }  // namespace ash
 
-#endif  // ASH_LOGIN_LOGIN_SCREEN_CONTROLLER_H_
+#endif  // ASH_LOGIN_LOCK_SCREEN_CONTROLLER_H_
diff --git a/ash/login/login_screen_controller_unittest.cc b/ash/login/login_screen_controller_unittest.cc
index 4ddb7a4..b46664b 100644
--- a/ash/login/login_screen_controller_unittest.cc
+++ b/ash/login/login_screen_controller_unittest.cc
@@ -39,7 +39,7 @@
   controller->AuthenticateUser(
       id, password, false,
       base::BindOnce([](base::Optional<bool>* result,
-                        bool did_auth) { *result = did_auth; },
+                        base::Optional<bool> did_auth) { *result = *did_auth; },
                      &callback_result));
 
   base::RunLoop().RunUntilIdle();
@@ -52,6 +52,9 @@
       Shell::Get()->session_controller()->GetLastActiveUserPrefService();
   EXPECT_TRUE(prefs->FindPreference(prefs::kQuickUnlockPinSalt));
 
+  // We hardcode the hashed PIN. This is fine because the PIN hash algorithm
+  // should never accidentally change; if it does we will need to have migration
+  // code and one failing test isn't a problem.
   std::string pin = "123456";
   std::string hashed_pin = "cqgMB9rwrcE35iFxm+4vP2toO6qkzW+giCnCcEou92Y=";
   EXPECT_NE(pin, hashed_pin);
@@ -60,7 +63,7 @@
   controller->AuthenticateUser(
       id, pin, true,
       base::BindOnce([](base::Optional<bool>* result,
-                        bool did_auth) { *result = did_auth; },
+                        base::Optional<bool> did_auth) { *result = *did_auth; },
                      &callback_result));
 
   base::RunLoop().RunUntilIdle();
diff --git a/ash/login/mock_login_screen_client.cc b/ash/login/mock_login_screen_client.cc
index 32d3360..eb36e81 100644
--- a/ash/login/mock_login_screen_client.cc
+++ b/ash/login/mock_login_screen_client.cc
@@ -27,7 +27,10 @@
     bool authenticated_by_pin,
     AuthenticateUserCallback callback) {
   AuthenticateUser_(account_id, password, authenticated_by_pin, callback);
-  std::move(callback).Run(authenticate_user_callback_result_);
+  if (authenticate_user_callback_storage_)
+    *authenticate_user_callback_storage_ = std::move(callback);
+  else
+    std::move(callback).Run(authenticate_user_callback_result_);
 }
 
 std::unique_ptr<MockLoginScreenClient> BindMockLoginScreenClient() {
diff --git a/ash/login/mock_login_screen_client.h b/ash/login/mock_login_screen_client.h
index 34a4fb2..d6de8130 100644
--- a/ash/login/mock_login_screen_client.h
+++ b/ash/login/mock_login_screen_client.h
@@ -29,6 +29,13 @@
     authenticate_user_callback_result_ = value;
   }
 
+  // If set to non-null, when |AuthenticateUser| is called the callback will be
+  // stored in |storage| instead of being executed.
+  void set_authenticate_user_callback_storage(
+      AuthenticateUserCallback* storage) {
+    authenticate_user_callback_storage_ = storage;
+  }
+
   // mojom::LoginScreenClient:
   void AuthenticateUser(const AccountId& account_id,
                         const std::string& password,
@@ -48,6 +55,7 @@
 
  private:
   bool authenticate_user_callback_result_ = true;
+  AuthenticateUserCallback* authenticate_user_callback_storage_ = nullptr;
 
   mojo::Binding<mojom::LoginScreenClient> binding_;
 
diff --git a/ash/login/ui/lock_screen_sanity_unittest.cc b/ash/login/ui/lock_screen_sanity_unittest.cc
index 264407b..746d31bb 100644
--- a/ash/login/ui/lock_screen_sanity_unittest.cc
+++ b/ash/login/ui/lock_screen_sanity_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/widget/widget.h"
 
@@ -137,6 +138,41 @@
   base::RunLoop().RunUntilIdle();
 }
 
+// Verifies that password text is cleared only after the browser-process
+// authentication request is complete.
+TEST_F(LockScreenSanityTest, PasswordSubmitClearsPasswordAfterAuthentication) {
+  std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient();
+
+  auto* contents = new LockContentsView(mojom::TrayActionState::kAvailable,
+                                        data_dispatcher());
+  SetUserCount(1);
+  std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents);
+
+  // Capture the authentication callback.
+  MockLoginScreenClient::AuthenticateUserCallback callback;
+  client->set_authenticate_user_callback_storage(&callback);
+  EXPECT_CALL(*client, AuthenticateUser_(testing::_, testing::_, testing::_,
+                                         testing::_));
+
+  // Submit password with content 'a'. This creates a browser-process
+  // authentication request stored in |callback|.
+  DCHECK(callback.is_null());
+  ui::test::EventGenerator& generator = GetEventGenerator();
+  generator.PressKey(ui::KeyboardCode::VKEY_A, 0);
+  generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
+  base::RunLoop().RunUntilIdle();
+  DCHECK(!callback.is_null());
+
+  // Run the browser-process authentication request. Verify that after the ash
+  // callback handler has completed the password is cleared.
+  LoginPasswordView::TestApi password_test_api =
+      MakeLoginPasswordTestApi(contents);
+  EXPECT_FALSE(password_test_api.textfield()->text().empty());
+  std::move(callback).Run(true);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(password_test_api.textfield()->text().empty());
+}
+
 // Verifies that tabbing from the lock screen will eventually focus the shelf.
 // Then, a shift+tab will bring focus back to the lock screen.
 TEST_F(LockScreenSanityTest, TabGoesFromLockToShelfAndBackToLock) {
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 99f0208..13be1c8 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -102,7 +102,8 @@
     const OnEasyUnlockIconTapped& on_easy_unlock_icon_tapped)
     : NonAccessibleView(kLoginAuthUserViewClassName),
       on_auth_(on_auth),
-      on_tap_(on_tap) {
+      on_tap_(on_tap),
+      weak_factory_(this) {
   // Build child views.
   user_view_ = new LoginUserView(
       LoginDisplayStyle::kLarge, true /*show_dropdown*/,
@@ -173,7 +174,6 @@
 LoginAuthUserView::~LoginAuthUserView() = default;
 
 void LoginAuthUserView::SetAuthMethods(uint32_t auth_methods) {
-  // TODO(jdufault): Implement additional auth methods.
   auth_methods_ = static_cast<AuthMethods>(auth_methods);
   bool has_password = HasAuthMethod(AUTH_PASSWORD);
   bool has_pin = HasAuthMethod(AUTH_PIN);
@@ -183,13 +183,8 @@
   password_view_->SetFocusEnabledForChildViews(has_password);
   password_view_->layer()->SetOpacity(has_password ? 1 : 0);
 
-  // Make sure to clear any existing password on showing the view. We do this on
-  // show instead of on hide so that the password does not clear when animating
-  // out.
-  if (has_password) {
-    password_view_->Clear();
+  if (has_password)
     password_view_->RequestFocus();
-  }
 
   pin_view_->SetVisible(has_pin);
 
@@ -320,6 +315,7 @@
 void LoginAuthUserView::UpdateForUser(const mojom::LoginUserInfoPtr& user) {
   user_view_->UpdateForUser(user, true /*animate*/);
   password_view_->UpdateForUser(user);
+  password_view_->Clear();
 }
 
 const mojom::LoginUserInfoPtr& LoginAuthUserView::current_user() const {
@@ -340,9 +336,20 @@
 
 void LoginAuthUserView::OnAuthSubmit(const base::string16& password) {
   bool authenticated_by_pin = (auth_methods_ & AUTH_PIN) != 0;
+
+  password_view_->SetReadOnly(true);
   Shell::Get()->login_screen_controller()->AuthenticateUser(
       current_user()->basic_user_info->account_id, base::UTF16ToUTF8(password),
-      authenticated_by_pin, on_auth_);
+      authenticated_by_pin,
+      base::BindOnce(&LoginAuthUserView::OnAuthComplete,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void LoginAuthUserView::OnAuthComplete(base::Optional<bool> auth_success) {
+  password_view_->SetReadOnly(false);
+  password_view_->Clear();
+  if (auth_success.has_value())
+    on_auth_.Run(*auth_success);
 }
 
 void LoginAuthUserView::OnUserViewTap() {
diff --git a/ash/login/ui/login_auth_user_view.h b/ash/login/ui/login_auth_user_view.h
index 025a9e60..f6e0125 100644
--- a/ash/login/ui/login_auth_user_view.h
+++ b/ash/login/ui/login_auth_user_view.h
@@ -13,6 +13,7 @@
 #include "ash/login/ui/login_user_view.h"
 #include "ash/login/ui/non_accessible_view.h"
 #include "ash/public/interfaces/user_info.mojom.h"
+#include "base/memory/weak_ptr.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/view.h"
 
@@ -101,6 +102,8 @@
 
   // Called when the user submits an auth method. Runs mojo call.
   void OnAuthSubmit(const base::string16& password);
+  // Called with the result of the request started in |OnAuthSubmit|.
+  void OnAuthComplete(base::Optional<bool> auth_success);
 
   // Called when the user view has been tapped. This will run |on_auth_| if tap
   // to unlock is enabled, otherwise it will run |on_tap_|.
@@ -122,6 +125,8 @@
   // |ApplyAnimationPostLayout|.
   std::unique_ptr<AnimationState> cached_animation_state_;
 
+  base::WeakPtrFactory<LoginAuthUserView> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(LoginAuthUserView);
 };
 
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc
index f186157..88bd591 100644
--- a/ash/login/ui/login_password_view.cc
+++ b/ash/login/ui/login_password_view.cc
@@ -327,7 +327,7 @@
 
 LoginPasswordView::TestApi::~TestApi() = default;
 
-views::View* LoginPasswordView::TestApi::textfield() const {
+views::Textfield* LoginPasswordView::TestApi::textfield() const {
   return view_->textfield_;
 }
 
@@ -501,13 +501,17 @@
                                   ui::DomCode::BACKSPACE, ui::EF_NONE));
 }
 
-void LoginPasswordView::Submit() {}
-
 void LoginPasswordView::SetPlaceholderText(
     const base::string16& placeholder_text) {
   textfield_->set_placeholder_text(placeholder_text);
 }
 
+void LoginPasswordView::SetReadOnly(bool read_only) {
+  textfield_->SetReadOnly(read_only);
+  textfield_->SetCursorEnabled(!read_only);
+  UpdateUiState();
+}
+
 const char* LoginPasswordView::GetClassName() const {
   return kLoginPasswordViewName;
 }
@@ -540,9 +544,13 @@
 void LoginPasswordView::ContentsChanged(views::Textfield* sender,
                                         const base::string16& new_contents) {
   DCHECK_EQ(sender, textfield_);
-  bool is_enabled = !new_contents.empty();
+  UpdateUiState();
+  on_password_text_changed_.Run(new_contents.empty() /*is_empty*/);
+}
+
+void LoginPasswordView::UpdateUiState() {
+  bool is_enabled = !textfield_->text().empty() && !textfield_->read_only();
   submit_button_->SetEnabled(is_enabled);
-  on_password_text_changed_.Run(!is_enabled);
   SkColor color = is_enabled
                       ? login_constants::kButtonEnabledColor
                       : SkColorSetA(login_constants::kButtonEnabledColor,
@@ -558,8 +566,9 @@
 }
 
 void LoginPasswordView::SubmitPassword() {
+  if (textfield_->read_only())
+    return;
   on_submit_.Run(textfield_->text());
-  Clear();
 }
 
 }  // namespace ash
diff --git a/ash/login/ui/login_password_view.h b/ash/login/ui/login_password_view.h
index a605ede..315d3aa 100644
--- a/ash/login/ui/login_password_view.h
+++ b/ash/login/ui/login_password_view.h
@@ -48,7 +48,7 @@
     explicit TestApi(LoginPasswordView* view);
     ~TestApi();
 
-    views::View* textfield() const;
+    views::Textfield* textfield() const;
     views::View* submit_button() const;
     views::View* easy_unlock_icon() const;
     void set_immediately_hover_easy_unlock_icon();
@@ -59,7 +59,7 @@
 
   using OnPasswordSubmit =
       base::RepeatingCallback<void(const base::string16& password)>;
-  using OnPasswordTextChanged = base::RepeatingCallback<void(bool)>;
+  using OnPasswordTextChanged = base::RepeatingCallback<void(bool is_empty)>;
   using OnEasyUnlockIconHovered = base::RepeatingClosure;
   using OnEasyUnlockIconTapped = base::RepeatingClosure;
 
@@ -95,13 +95,13 @@
   // Erase the last entered value.
   void Backspace();
 
-  // Dispatch a submit event.
-  void Submit();
-
   // Set password field placeholder. The password view cannot set the text by
   // itself because it doesn't know which auth methods are enabled.
   void SetPlaceholderText(const base::string16& placeholder_text);
 
+  // Makes the textfield read-only and enables/disables submitting.
+  void SetReadOnly(bool read_only);
+
   // views::View:
   const char* GetClassName() const override;
   gfx::Size CalculatePreferredSize() const override;
@@ -123,6 +123,10 @@
   class EasyUnlockIcon;
   friend class TestApi;
 
+  // Enables/disables the submit button and changes the color of the separator
+  // based on if the view is enabled.
+  void UpdateUiState();
+
   // Submits the current password field text to mojo call and resets the text
   // field.
   void SubmitPassword();
diff --git a/ash/login/ui/login_password_view_test.cc b/ash/login/ui/login_password_view_test.cc
index eadd254..9b4da41 100644
--- a/ash/login/ui/login_password_view_test.cc
+++ b/ash/login/ui/login_password_view_test.cc
@@ -90,7 +90,7 @@
   EXPECT_EQ(base::ASCIIToUTF16("abc1"), *password_);
 }
 
-// Verifies that text is cleared after submitting a password.
+// Verifies that text is not cleared after submitting a password.
 TEST_F(LoginPasswordViewTest, PasswordSubmitClearsPassword) {
   LoginPasswordView::TestApi test_api(view_);
   ui::test::EventGenerator& generator = GetEventGenerator();
@@ -100,17 +100,20 @@
   generator.PressKey(ui::KeyboardCode::VKEY_A, 0);
   EXPECT_FALSE(is_password_field_empty_);
   generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
-  EXPECT_TRUE(is_password_field_empty_);
+  EXPECT_FALSE(is_password_field_empty_);
   EXPECT_TRUE(password_.has_value());
   EXPECT_EQ(base::ASCIIToUTF16("a"), *password_);
 
+  // Clear password.
   password_.reset();
+  view_->Clear();
+  EXPECT_TRUE(is_password_field_empty_);
 
   // Submit 'b' password.
   generator.PressKey(ui::KeyboardCode::VKEY_B, 0);
   EXPECT_FALSE(is_password_field_empty_);
   generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
-  EXPECT_TRUE(is_password_field_empty_);
+  EXPECT_FALSE(is_password_field_empty_);
   EXPECT_TRUE(password_.has_value());
   // The submitted password is 'b' instead of "ab".
   EXPECT_EQ(base::ASCIIToUTF16("b"), *password_);
diff --git a/ash/manifest.json b/ash/manifest.json
index 11824769..458fb5d1 100644
--- a/ash/manifest.json
+++ b/ash/manifest.json
@@ -45,6 +45,7 @@
       "requires": {
         "*": [ "accessibility", "app" ],
         "ash_pref_connector": [ "pref_connector" ],
+        "catalog": [ "directory" ],
         "local_state": [ "pref_client" ],
         "ui": [ "display_dev", "window_manager", "video_detector" ],
         "touch_hud": [ "mash:launchable" ]
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 1f798d4..f59c90e 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -631,8 +631,6 @@
     "media/media_engagement_session.h",
     "media/media_storage_id_salt.cc",
     "media/media_storage_id_salt.h",
-    "media/media_url_constants.cc",
-    "media/media_url_constants.h",
     "media/midi_permission_context.cc",
     "media/midi_permission_context.h",
     "media/midi_sysex_permission_context.cc",
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
index bd1657f..06044b8b 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
@@ -393,6 +393,9 @@
       main_frame_it->second.data_use_recorder;
   old_frame_entry->set_page_transition(page_transition);
 
+  if (old_frame_entry == entry)
+    return;
+
   if (is_same_document_navigation) {
     std::vector<net::URLRequest*> pending_url_requests;
     entry->GetPendingURLRequests(&pending_url_requests);
@@ -402,6 +405,7 @@
           DataUseRecorderEntryAsUserData::kDataUseAscriberUserDataKey);
       AscribeRecorderWithRequest(request, old_frame_entry);
     }
+    entry->RemoveAllPendingURLRequests();
     DCHECK(entry->IsDataUseComplete());
     data_use_recorders_.erase(entry);
 
diff --git a/chrome/browser/media/media_url_constants.cc b/chrome/browser/media/media_url_constants.cc
deleted file mode 100644
index b2ac4d1..0000000
--- a/chrome/browser/media/media_url_constants.cc
+++ /dev/null
@@ -1,7 +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.
-
-#include "chrome/browser/media/media_url_constants.h"
-
-const char kUploadURL[] = "https://clients2.google.com/cr/report";
diff --git a/chrome/browser/media/media_url_constants.h b/chrome/browser/media/media_url_constants.h
deleted file mode 100644
index adc3891ca..0000000
--- a/chrome/browser/media/media_url_constants.h
+++ /dev/null
@@ -1,10 +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_MEDIA_MEDIA_URL_CONSTANTS_H_
-#define CHROME_BROWSER_MEDIA_MEDIA_URL_CONSTANTS_H_
-
-extern const char kUploadURL[];
-
-#endif  // CHROME_BROWSER_MEDIA_MEDIA_URL_CONSTANTS_H_
diff --git a/chrome/browser/media/webrtc/webrtc_log_uploader.cc b/chrome/browser/media/webrtc/webrtc_log_uploader.cc
index 34fd5e9..ab8617a 100644
--- a/chrome/browser/media/webrtc/webrtc_log_uploader.cc
+++ b/chrome/browser/media/webrtc/webrtc_log_uploader.cc
@@ -18,7 +18,6 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/media/media_url_constants.h"
 #include "chrome/browser/media/webrtc/webrtc_log_list.h"
 #include "chrome/browser/media/webrtc/webrtc_log_util.h"
 #include "chrome/common/partial_circular_buffer.h"
@@ -472,6 +471,7 @@
             "Not implemented, it would be good to do so."
         })");
 
+  constexpr char kUploadURL[] = "https://clients2.google.com/cr/report";
   std::unique_ptr<net::URLFetcher> url_fetcher(net::URLFetcher::Create(
       GURL(kUploadURL), net::URLFetcher::POST, this, traffic_annotation));
   url_fetcher->SetUploadData(content_type, *post_data);
diff --git a/chrome/browser/resources/chromeos/select_to_speak/options.css b/chrome/browser/resources/chromeos/select_to_speak/options.css
index 49c0cc655..eb89feb0 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/options.css
+++ b/chrome/browser/resources/chromeos/select_to_speak/options.css
@@ -45,7 +45,6 @@
     background-color: #fff;
     border: 1px solid #ddd;
     font-size: 13px;
-    line-height: 60px;
     min-height: 60px;
     padding: 0 20px;
     vertical-align: middle;
@@ -100,9 +99,19 @@
     padding: 0 20px;
 }
 
+label {
+    line-height: 60px;
+    vertical-align: middle;
+}
+
 .example {
     display: inline-block;
+    float: right;
+    font-size: 1em;
+    height: 60px;
+    line-height: 60px;
     padding: 0 3px;
+    vertical-align: middle;
 }
 
 .dark {
@@ -110,10 +119,15 @@
     color: white;
 }
 
+.light {
+    background: white;
+}
+
 .highlight {
     opacity: .3;
     z-index: 10;
-    top: -45px;
+    top: -40px;
     position: relative;
-    height: 2em;
+    height: 20px;
+    width: 100%;
 }
diff --git a/chrome/browser/resources/chromeos/select_to_speak/options.html b/chrome/browser/resources/chromeos/select_to_speak/options.html
index 192d112..aa4828f 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/options.html
+++ b/chrome/browser/resources/chromeos/select_to_speak/options.html
@@ -70,12 +70,14 @@
                   msgid="options_highlight_color_pink">
           </option>
         </select>
-        <div style="float:right">
-          <span class="i18n example dark" msgid="options_highlight_dark">
-          </span>
-          <span class="i18n example" msgid="options_highlight_light">
-          </span>
-          <div class="highlight" id="highlightExample">
+        <div class="example dark">
+          <span class="i18n" msgid="options_highlight_dark"></span>
+          <div class="highlight">
+          </div>
+        </div>
+        <div class="example light">
+          <span class="i18n" msgid="options_highlight_light"></span>
+          <div class="highlight">
           </div>
         </div>
       </div>
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_options.js b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_options.js
index 28ccdfc..806cbff7 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_options.js
+++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_options.js
@@ -158,8 +158,10 @@
    */
   setUpHighlightListener_: function() {
     let onChange = function(value) {
-      let example = document.getElementById('highlightExample');
-      example.style.background = value;
+      let examples = document.getElementsByClassName('highlight');
+      for (let i = 0; i < examples.length; i++) {
+        examples[i].style.background = value;
+      }
     };
 
     this.syncSelectControlToPref_('highlightColor', 'highlightColor', onChange);
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 1c02ce0..236029e6 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -314,7 +314,6 @@
     icon_->SetAttention(TabIcon::AttentionType::kBlockedWebContents,
                         data_.blocked);
   }
-  icon_->SchedulePaint();
 
   base::string16 title = data_.title;
   if (title.empty()) {
diff --git a/chrome/common/extensions/api/devtools/experimental_audits.json b/chrome/common/extensions/api/devtools/experimental_audits.json
deleted file mode 100644
index d6cd544c..0000000
--- a/chrome/common/extensions/api/devtools/experimental_audits.json
+++ /dev/null
@@ -1,191 +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.
-
-[
-  {
-    "namespace": "experimental.devtools.audits",
-    "description": "Use the <code>chrome.experimental.devtools.audits</code> API to add new audit categories to the Developer Tools' Audit panel.",
-    "nocompile": true,
-    "functions": [
-      {
-        "name": "addCategory",
-        "type": "function",
-        "description": "Adds an audit category.",
-        "parameters": [
-          { "name": "displayName", "type": "string", "description": "A display name for the category." },
-          { "name": "resultCount", "type": "number", "description": "The expected number of audit results in the category." }
-        ],
-        "returns": {
-          "$ref": "AuditCategory"
-        }
-      }
-    ],
-    "types": [
-      {
-        "id": "AuditCategory",
-        "type": "object",
-        "description": "A group of logically related audit checks.",
-        "events": [
-          {
-            "name": "onAuditStarted",
-            "type": "function",
-            "description": "If the category is enabled, this event is fired when the audit is started. The event handler is expected to initiate execution of the audit logic that will populate the <code>results</code> collection.",
-            "parameters": [
-              { "name": "results", "$ref": "AuditResults" }
-            ]
-          }
-        ]
-      },
-      {
-        "id": "FormattedValue",
-        "type": "object",
-        "additionalProperties": { "type": "any" },
-        "description": "A value returned from one of the formatters (a URL, code snippet etc), to be passed to <code>createResult()</code> or <code>addChild()</code>. See $(ref:AuditResults.createSnippet) and $(ref:AuditResults.createURL)."
-      },
-      {
-        "id": "AuditResults",
-        "type": "object",
-        "description": "A collection of audit results for the current run of the audit category.",
-        "functions": [
-          {
-            "name": "addResult",
-            "type": "function",
-            "description": "Adds an audit result. The results are rendered as bulleted items under the audit category associated with the <code>AuditResults</code> object.",
-            "parameters": [
-              {
-                "name": "displayName",
-                "type": "string",
-                "description": "A concise, high-level description of the result."
-              },
-              {
-                "name": "description",
-                "type": "string",
-                "description": "A detailed description of what the displayName means."
-              },
-              {
-                "name": "severity",
-                "$ref": "AuditResultSeverity"
-              },
-              {
-                "name": "details",
-                "$ref": "AuditResultNode",
-                "optional": true,
-                "description": "A subtree that appears under the added result that may provide additional details on the violations found."
-              }
-            ]
-          },
-          {
-            "name": "createResult",
-            "type": "function",
-            "description": "Creates a result node that may be used as the <code>details</code> parameters to the <code>addResult()</code> method.",
-            "parameters": [
-              {
-                "name": "content",
-                "choices": [
-                  { "type": "string" },
-                  { "$ref": "FormattedValue" }
-                ],
-                "description": "Either string or formatted values returned by one of the AuditResult formatters (a URL, a snippet etc). If multiple arguments are passed, these will be concatenated into a single node."
-              }
-            ],
-            "returns": {
-              "$ref": "AuditResultNode"
-            }
-          },
-          {
-            "name": "done",
-            "type": "function",
-            "description": "Signals the DevTools Audits panel that the run of this category is over. The audit run also completes automatically when the number of added top-level results is equal to that declared when AuditCategory was created."
-          },
-          {
-            "name": "createURL",
-            "type": "function",
-            "description": "Render passed value as a URL in the Audits panel.",
-            "parameters": [
-              { "name": "href", "type": "string", "description": "A URL that appears as the href value on the resulting link." },
-              { "name": "displayText", "type": "string", "description": "Text that appears to the user.", "optional": true }
-            ],
-            "returns": { "$ref": "FormattedValue" }
-          },
-          {
-            "name": "createSnippet",
-            "type": "function",
-            "description": "Render passed text as a code snippet in the Audits panel.",
-            "parameters": [
-              { "name": "text", "type": "string", "description": "Snippet text." }
-            ],
-            "returns": { "$ref": "FormattedValue" }
-          }
-        ],
-        "properties": {
-          "Severity": {
-            "$ref": "AuditResultSeverity",
-            "description": "A class that contains possible values for the audit result severities."
-          },
-          "text": {
-            "type": "string",
-            "description": "The contents of the node."
-          },
-          "children": {
-            "optional": true,
-            "type": "array",
-            "items": { "$ref": "AuditResultNode" },
-            "description": "Children of this node."
-          },
-          "expanded": {
-            "optional": true,
-            "type": "boolean",
-            "description": "Whether the node is expanded by default."
-          }
-        }
-      },
-      {
-        "id": "AuditResultNode",
-        "type": "object",
-        "description": "A node in the audit result tree. Displays content and may optionally have children nodes.",
-        "functions": [
-          {
-            "name": "addChild",
-            "description": "Adds a child node to this node.",
-            "parameters": [
-              {
-                "name": "content",
-                "choices": [
-                  { "type": "string" },
-                  { "$ref": "FormattedValue" }
-                ],
-                "description": "Either string or formatted values returned by one of the AuditResult formatters (URL, snippet etc). If multiple arguments are passed, these will be concatenated into a single node."
-              }
-            ],
-            "returns": {
-              "$ref": "AuditResultNode"
-            }
-          }
-        ],
-        "properties": {
-          "expanded": {
-            "type": "boolean",
-            "description": "If set, the subtree will always be expanded."
-          }
-        }
-      },
-      {
-        "id": "AuditResultSeverity",
-        "type": "object",
-        "description": "This type contains possible values for a result severity. The results of different severities are distinguished by colored bullets near the result's display name.",
-        "properties": {
-          "Info": {
-            "type": "string"
-          },
-          "Warning": {
-            "type": "string"
-          },
-          "Severe": {
-            "type": "string"
-          }
-        }
-      }
-    ]
-  }
-]
diff --git a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/background.js b/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/background.js
deleted file mode 100644
index 6751a247..0000000
--- a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/background.js
+++ /dev/null
@@ -1,49 +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.
-
-function validateLinks(links, callback) {
-  var results = [];
-  var pendingRequests = 0;
-
-  function fetchLink(link) {
-    if (!/^http(s?):\/\//.test(link.href))
-      return;
-    var xhr = new XMLHttpRequest();
-    xhr.open("HEAD", link.href, true);
-    xhr.onreadystatechange = function() {
-      if (xhr.readyState < xhr.HEADERS_RECEIVED || xhr.processed)
-        return;
-      if (!xhr.status || xhr.status >= 400) {
-        results.push({
-            href: link.href,
-            text: link.text,
-            status: xhr.statusText
-        });
-      }
-      xhr.processed = true;
-      xhr.abort();
-      if (!--pendingRequests) {
-        callback({ total: links.length, badlinks: results });
-      }
-    }
-    try {
-      xhr.send(null);
-      pendingRequests++;
-    } catch (e) {
-      console.error("XHR failed for " + link.href + ", " + e);
-    }
-  }
-
-  for (var i = 0; i < links.length; ++i)
-    fetchLink(links[i]);
-}
-
-chrome.extension.onRequest.addListener(function(request, sender, callback) {
-  var tabId = request.tabId;
-  chrome.tabs.executeScript(tabId, { file: "content.js" }, function() {
-    chrome.tabs.sendRequest(tabId, {}, function(results) {
-      validateLinks(results, callback);
-    });
-  });
-});
diff --git a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/content.js b/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/content.js
deleted file mode 100644
index 1cf0456..0000000
--- a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/content.js
+++ /dev/null
@@ -1,20 +0,0 @@
-function getLinks() {
-  var links = document.querySelectorAll("a");
-  var results = [];
-  var seenLinks = {};
-  for (var i  = 0; i < links.length; ++i) {
-    var text = links[i].textContent;
-    if (text.length > 100)
-      text = text.substring(0, 100) + "...";
-    var link = links[i].href.replace(/(.*)#?/, "$1");
-    if (seenLinks[link])
-      continue;
-    seenLinks[link] = 1;
-    results.push({ href: link, text: text });
-  }
-  return results;
-};
-
-chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
-  sendResponse(getLinks());
-});
diff --git a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/devtools.html b/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/devtools.html
deleted file mode 100644
index dc6e791f..0000000
--- a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/devtools.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-<head>
-<script src="devtools.js"></script>
-</head>
-</html>
diff --git a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/devtools.js b/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/devtools.js
deleted file mode 100644
index 5696dcd6..0000000
--- a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/devtools.js
+++ /dev/null
@@ -1,30 +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.
-
-var category = chrome.experimental.devtools.audits.addCategory(
-    "Broken links", 1);
-category.onAuditStarted.addListener(function callback(auditResults) {
-  chrome.extension.sendRequest({ tabId: webInspector.inspectedWindow.tabId },
-      function(results) {
-    if (!results.badlinks.length) {
-      auditResults.addResult("No broken links",
-                             "There are no broken links on the page!",
-                             auditResults.Severity.Info);
-    }
-    else {
-      var details = auditResults.createResult(results.badlinks.length +
-          " links out of " + results.total + " are broken");
-      for (var i = 0; i < results.badlinks.length; ++i) {
-        details.addChild(auditResults.createURL(results.badlinks[i].href,
-                                                results.badlinks[i].text));
-      }
-      auditResults.addResult("Broken links found (" +
-                                 results.badlinks.length +
-                                 ")", "",
-                             auditResults.Severity.Severe,
-                             details);
-    }
-    auditResults.done();
-  });
-});
diff --git a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/manifest.json b/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/manifest.json
deleted file mode 100644
index ee3b5b7..0000000
--- a/chrome/common/extensions/docs/examples/api/devtools/audits/broken-links/manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "name": "Broken Links",
-  "version": "1.1",
-  "description": "Extends the Developer Tools, adding an audit category that finds broken links on the inspected page.",
-  "background": {
-    "scripts": ["background.js"]
-  },
-  "devtools_page": "devtools.html",
-  "permissions":  [
-    "experimental",
-    "tabs",
-    "http://*/*",
-    "https://*/*"
-  ],
-  "manifest_version": 2
-}
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index 4cc9f65..619b6b2 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@
 application: chrome-apps-doc
-version: 3-53-0
+version: 3-54-0
 runtime: python27
 api_version: 1
 threadsafe: false
diff --git a/chrome/common/extensions/docs/server2/known_broken_links.json b/chrome/common/extensions/docs/server2/known_broken_links.json
index f42c4ff..64f436e 100644
--- a/chrome/common/extensions/docs/server2/known_broken_links.json
+++ b/chrome/common/extensions/docs/server2/known_broken_links.json
@@ -102,12 +102,6 @@
     "redirects to /extensions/experimental_devtools.html"
   ],
   [
-    200,
-    "extensions/experimental_devtools_audits.html",
-    "extensions/samples.html#devtools.audits",
-    "target anchor not found"
-  ],
-  [
     302,
     "apps/experimental_devtools_network.html",
     "apps/devtools_network.html",
@@ -624,12 +618,6 @@
   ],
   [
     302,
-    "apps/experimental_webInspector_audits.html",
-    "apps/experimental_devtools_audits.html",
-    "redirects to /extensions/experimental_devtools_audits.html"
-  ],
-  [
-    302,
     "apps/samples.html",
     "apps/extension.html#property-lastError",
     "redirects to /extensions/extension.html"
@@ -858,12 +846,6 @@
   [
     302,
     "apps/private_apis.html",
-    "apps/experimental_devtools_audits.html",
-    "redirects to /extensions/experimental_devtools_audits.html"
-  ],
-  [
-    302,
-    "apps/private_apis.html",
     "apps/experimental_devtools_console.html",
     "redirects to /extensions/experimental_devtools_console.html"
   ],
diff --git a/chrome/common/extensions/docs/static/images/devtools-audits-category.png b/chrome/common/extensions/docs/static/images/devtools-audits-category.png
deleted file mode 100644
index ef51671..0000000
--- a/chrome/common/extensions/docs/static/images/devtools-audits-category.png
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/static/images/devtools-audits-results.png b/chrome/common/extensions/docs/static/images/devtools-audits-results.png
deleted file mode 100644
index 58a2802a..0000000
--- a/chrome/common/extensions/docs/static/images/devtools-audits-results.png
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/templates/articles/manifest/requirements.html b/chrome/common/extensions/docs/templates/articles/manifest/requirements.html
index 1c68cee2..89c3596d 100644
--- a/chrome/common/extensions/docs/templates/articles/manifest/requirements.html
+++ b/chrome/common/extensions/docs/templates/articles/manifest/requirements.html
@@ -28,6 +28,10 @@
 }
 </pre>
 
+<p class="warning">
+NPAPI Plugin support for extension has been <a href="http://blog.chromium.org/2013/09/saying-goodbye-to-our-old-friend-npapi.html">discontinued</a>. As part of this, the <b>"plugins"</b> requirement described below has been deprecated.
+</p>
+
 <p>
 The "plugins" requirement indicates
 if an app or extension requires NPAPI to run.
diff --git a/chrome/common/extensions/docs/templates/intros/experimental_devtools_audits.html b/chrome/common/extensions/docs/templates/intros/experimental_devtools_audits.html
deleted file mode 100644
index 29fde0c..0000000
--- a/chrome/common/extensions/docs/templates/intros/experimental_devtools_audits.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<p>
-See <a href="experimental.devtools">DevTools APIs summary</a> for
-general introduction to using Developer Tools APIs.
-</p>
-
-<h2 id="overview">Overview</h2>
-
-<p>
-Each audit category is represented by a line on <em>Select audits to run</em>
-screen in the Audits panel. The following example adds a category named
-<em>Readability</em>:</p>
-<pre>
-var category = chrome.experimental.devtools.audits.addCategory("Readability", 2);
-</pre>
-<img src="{{static}}/images/devtools-audits-category.png"
-     style="margin-left: 20px"
-     width="489" height="342"
-     alt="Extension audit category on the launch screen of Audits panel" />
-<p>
-If the category's checkbox is checked, the <code>onAuditStarted</code> event of
-that category will be fired when user clicks the <em>Run</em> button.
-</p>
-<p>The event handler in your extension receives <code>AuditResults</code>
-as an argument and should add one or more results using <code>addResult()</code>
-method. This may be done asynchronously, i.e. after the handler returns. The
-run of the category is considered to be complete once the extension adds the
-number of results declared when adding the  category with
-<code>addCategory()</code> or
-calls AuditResult's <code>done()</code> method.
-</p>
-<p>The results may include additional details visualized as an expandable
-tree by the Audits panel. You may build the details tree using the
-<code>createResult()</code> and <code>addChild()</code> methods. The child node
-may include specially formatted fragments created by the
-<code>auditResults.createSnippet()</code>
-and <code>auditResults.createURL()</code> methods.
-</p>
-
-<h2 id="examples">Examples</h2>
-<p>The following example adds a handler for onAuditStarted event that creates
-two audit results and populates one of them with the additional details:
-</p>
-
-<pre>
-category.onAuditStarted.addListener(function(results) {
-  var details = results.createResult("Details...");
-  var styles = details.addChild("2 styles with small font");
-  var elements = details.addChild("3 elements with small font");
-
-  results.addResult("Font Size (5)",
-      "5 elements use font size below 10pt",
-      results.Severity.Severe,
-      details);
-  results.addResult("Contrast",
-                    "Text should stand out from background",
-                    results.Severity.Info);
-});
-</pre>
-<p>The audit result tree produced by the snippet above will look like this:
-</p>
-<img src="{{static}}/images/devtools-audits-results.png"
-     style="margin-left: 20px"
-     width="330" height="169"
-     alt="Audit results example" />
-
-<p>
-You can find more examples that use this API in
-<a href="samples#search:devtools.audits">Samples</a>.
-</p>
diff --git a/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_audits.html b/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_audits.html
deleted file mode 100644
index 259c715..0000000
--- a/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_audits.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_extensions_api api:apis.extensions.devtools/experimental_audits intro:intros.experimental_devtools_audits/}}
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc
index 34791354..7b56ef53e 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc
@@ -33,15 +33,6 @@
     Testcase("requirements_invalid_3d_no_features.json",
              ErrorUtils::FormatErrorMessage(
                  errors::kInvalidRequirement, "3D")),
-    Testcase("requirements_invalid_plugins.json",
-             ErrorUtils::FormatErrorMessage(
-                 errors::kInvalidRequirement, "plugins")),
-    Testcase("requirements_invalid_plugins_key.json",
-             ErrorUtils::FormatErrorMessage(
-                 errors::kInvalidRequirement, "plugins")),
-    Testcase("requirements_invalid_plugins_value.json",
-             ErrorUtils::FormatErrorMessage(
-                 errors::kInvalidRequirement, "plugins"))
   };
 
   RunTestcases(testcases, arraysize(testcases), EXPECT_TYPE_ERROR);
@@ -53,39 +44,27 @@
       "requirements_valid_empty.json"));
   ASSERT_TRUE(extension.get());
   EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).webgl, false);
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).npapi, false);
 
   // Test loading all the requirements.
   extension = LoadAndExpectSuccess("requirements_valid_full.json");
   ASSERT_TRUE(extension.get());
   EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).webgl, true);
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).npapi, true);
 }
 
-// When an npapi plugin is present, the default of the "npapi" requirement
-// changes.
-TEST_F(RequirementsManifestTest, RequirementsNpapiDefault) {
-  scoped_refptr<Extension> extension(LoadAndExpectSuccess(
-      "requirements_npapi_empty.json"));
-  ASSERT_TRUE(extension.get());
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).webgl, false);
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).npapi, true);
+// Tests the deprecated plugin requirement.
+TEST_F(RequirementsManifestTest, RequirementsPlugin) {
+  // Using the plugins requirement should cause an install warning.
+  RunTestcase({"requirements_invalid_plugins_value.json",
+               errors::kPluginsRequirementDeprecated},
+              EXPECT_TYPE_WARNING);
+  RunTestcase(
+      {"requirements_npapi_false.json", errors::kPluginsRequirementDeprecated},
+      EXPECT_TYPE_WARNING);
 
-  extension = LoadAndExpectSuccess(
-      "requirements_npapi_empty_plugins_empty.json");
-  ASSERT_TRUE(extension.get());
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).webgl, false);
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).npapi, false);
-
-  extension = LoadAndExpectSuccess("requirements_npapi.json");
-  ASSERT_TRUE(extension.get());
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).webgl, false);
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).npapi, false);
-
-  extension = LoadAndExpectSuccess("requirements_npapi_plugins_empty.json");
-  ASSERT_TRUE(extension.get());
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).webgl, false);
-  EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).npapi, true);
+  // Explicitly requesting the npapi requirement should cause an error.
+  RunTestcase(
+      {"requirements_npapi_true.json", errors::kNPAPIPluginsNotSupported},
+      EXPECT_TYPE_ERROR);
 }
 
 }  // namespace extensions
diff --git a/chrome/test/data/extensions/api_test/cross_origin_xhr/all_urls/manifest.json b/chrome/test/data/extensions/api_test/cross_origin_xhr/all_urls/manifest.json
index cd1abce..84abd4e 100644
--- a/chrome/test/data/extensions/api_test/cross_origin_xhr/all_urls/manifest.json
+++ b/chrome/test/data/extensions/api_test/cross_origin_xhr/all_urls/manifest.json
@@ -11,13 +11,5 @@
     "js": ["content_script.js"],
     "run_at": "document_start"
   }],
-  "permissions": [ "<all_urls>" ],
-  "plugins": [
-    {"path": "plugin.dll", "public": true}
-  ],
-  "requirements": {
-    "plugins": {
-      "npapi": false
-    }
-  }
+  "permissions": [ "<all_urls>" ]
 }
diff --git a/chrome/test/data/extensions/api_test/cross_origin_xhr/all_urls/plugin.dll b/chrome/test/data/extensions/api_test/cross_origin_xhr/all_urls/plugin.dll
deleted file mode 100755
index 8b13789..0000000
--- a/chrome/test/data/extensions/api_test/cross_origin_xhr/all_urls/plugin.dll
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/chrome/test/data/extensions/manifest_tests/requirements_invalid_plugins.json b/chrome/test/data/extensions/manifest_tests/requirements_invalid_plugins.json
deleted file mode 100644
index a2b08ae..0000000
--- a/chrome/test/data/extensions/manifest_tests/requirements_invalid_plugins.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "name": "Requirements Manifest Test",
-  "version": "1.0",
-  "manifest_version": 2,
-  "requirements": {
-    "plugins": false
-  }
-}
diff --git a/chrome/test/data/extensions/manifest_tests/requirements_invalid_plugins_key.json b/chrome/test/data/extensions/manifest_tests/requirements_invalid_plugins_key.json
deleted file mode 100644
index 0d75b85d..0000000
--- a/chrome/test/data/extensions/manifest_tests/requirements_invalid_plugins_key.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "name": "Requirements Manifest Test",
-  "version": "1.0",
-  "manifest_version": 2,
-  "requirements": {
-    "plugins": {
-      "foo": false
-    }
-  }
-}
diff --git a/chrome/test/data/extensions/manifest_tests/requirements_npapi_empty.json b/chrome/test/data/extensions/manifest_tests/requirements_npapi_empty.json
deleted file mode 100644
index 4edb888..0000000
--- a/chrome/test/data/extensions/manifest_tests/requirements_npapi_empty.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "name": "Requirements Manifest Test",
-  "version": "1.0",
-  "manifest_version": 2,
-  "plugins": [
-    {"path": "foo.dll", "public": true}
-  ]
-}
diff --git a/chrome/test/data/extensions/manifest_tests/requirements_npapi_empty_plugins_empty.json b/chrome/test/data/extensions/manifest_tests/requirements_npapi_empty_plugins_empty.json
deleted file mode 100644
index 0591973..0000000
--- a/chrome/test/data/extensions/manifest_tests/requirements_npapi_empty_plugins_empty.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "name": "Requirements Manifest Test",
-  "version": "1.0",
-  "manifest_version": 2,
-  "plugins": [
-  ]
-}
diff --git a/chrome/test/data/extensions/manifest_tests/requirements_npapi.json b/chrome/test/data/extensions/manifest_tests/requirements_npapi_false.json
similarity index 100%
rename from chrome/test/data/extensions/manifest_tests/requirements_npapi.json
rename to chrome/test/data/extensions/manifest_tests/requirements_npapi_false.json
diff --git a/chrome/test/data/extensions/manifest_tests/requirements_npapi_plugins_empty.json b/chrome/test/data/extensions/manifest_tests/requirements_npapi_true.json
similarity index 100%
rename from chrome/test/data/extensions/manifest_tests/requirements_npapi_plugins_empty.json
rename to chrome/test/data/extensions/manifest_tests/requirements_npapi_true.json
diff --git a/chrome/test/data/extensions/manifest_tests/requirements_valid_full.json b/chrome/test/data/extensions/manifest_tests/requirements_valid_full.json
index 7eefc47..8bcefa2 100644
--- a/chrome/test/data/extensions/manifest_tests/requirements_valid_full.json
+++ b/chrome/test/data/extensions/manifest_tests/requirements_valid_full.json
@@ -5,9 +5,6 @@
   "requirements": {
     "3D": {
       "features": ["css3d", "webgl"]
-    },
-    "plugins": {
-      "npapi": true
     }
   }
 }
diff --git a/chromecast/browser/url_request_context_factory.cc b/chromecast/browser/url_request_context_factory.cc
index 670bf90..9430a53 100644
--- a/chromecast/browser/url_request_context_factory.cc
+++ b/chromecast/browser/url_request_context_factory.cc
@@ -41,6 +41,7 @@
 #include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/file_protocol_handler.h"
 #include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_intercepting_job_factory.h"
 #include "net/url_request/url_request_job_factory_impl.h"
@@ -251,13 +252,11 @@
 }
 
 void URLRequestContextFactory::InitializeMainContextDependencies(
-    net::HttpTransactionFactory* transaction_factory,
     content::ProtocolHandlerMap* protocol_handlers,
     content::URLRequestInterceptorScopedVector request_interceptors) {
   if (main_dependencies_initialized_)
     return;
 
-  main_transaction_factory_.reset(transaction_factory);
   std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory(
       new net::URLRequestJobFactoryImpl());
   // Keep ProtocolHandlers added in sync with
@@ -311,20 +310,8 @@
 
 void URLRequestContextFactory::PopulateNetworkSessionParams(
     bool ignore_certificate_errors,
-    net::HttpNetworkSession::Params* session_params,
-    net::HttpNetworkSession::Context* session_context) {
+    net::HttpNetworkSession::Params* session_params) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  session_context->host_resolver = host_resolver_.get();
-  session_context->cert_verifier = cert_verifier_.get();
-  session_context->channel_id_service = channel_id_service_.get();
-  session_context->ssl_config_service = ssl_config_service_.get();
-  session_context->transport_security_state = transport_security_state_.get();
-  session_context->cert_transparency_verifier =
-      cert_transparency_verifier_.get();
-  session_context->ct_policy_enforcer = ct_policy_enforcer_.get();
-  session_context->http_auth_handler_factory = http_auth_handler_factory_.get();
-  session_context->http_server_properties = http_server_properties_.get();
-  session_context->proxy_service = proxy_service_.get();
 
   session_params->ignore_certificate_errors = ignore_certificate_errors;
 
@@ -339,11 +326,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   InitializeSystemContextDependencies();
   net::HttpNetworkSession::Params session_params;
-  net::HttpNetworkSession::Context session_context;
-  PopulateNetworkSessionParams(IgnoreCertificateErrors(), &session_params,
-                               &session_context);
-  system_transaction_factory_.reset(new net::HttpNetworkLayer(
-      new net::HttpNetworkSession(session_params, session_context)));
+  PopulateNetworkSessionParams(IgnoreCertificateErrors(), &session_params);
   system_job_factory_.reset(new net::URLRequestJobFactoryImpl());
   system_cookie_store_ =
       content::CreateCookieStore(content::CookieStoreConfig());
@@ -362,14 +345,21 @@
   system_context->set_http_auth_handler_factory(
       http_auth_handler_factory_.get());
   system_context->set_http_server_properties(http_server_properties_.get());
-  system_context->set_http_transaction_factory(
-      system_transaction_factory_.get());
   system_context->set_http_user_agent_settings(
       http_user_agent_settings_.get());
   system_context->set_job_factory(system_job_factory_.get());
   system_context->set_cookie_store(system_cookie_store_.get());
   system_context->set_network_delegate(system_network_delegate_.get());
   system_context->set_net_log(net_log_);
+
+  net::HttpNetworkSession::Context session_context;
+  net::URLRequestContextBuilder::SetHttpNetworkSessionComponents(
+      system_context, &session_context);
+  system_transaction_factory_.reset(new net::HttpNetworkLayer(
+      new net::HttpNetworkSession(session_params, session_context)));
+  system_context->set_http_transaction_factory(
+      system_transaction_factory_.get());
+
   return system_context;
 }
 
@@ -401,12 +391,8 @@
   InitializeSystemContextDependencies();
 
   net::HttpNetworkSession::Params session_params;
-  net::HttpNetworkSession::Context session_context;
-  PopulateNetworkSessionParams(IgnoreCertificateErrors(), &session_params,
-                               &session_context);
+  PopulateNetworkSessionParams(IgnoreCertificateErrors(), &session_params);
   InitializeMainContextDependencies(
-      new net::HttpNetworkLayer(
-          new net::HttpNetworkSession(session_params, session_context)),
       protocol_handlers, std::move(request_interceptors));
 
   content::CookieStoreConfig cookie_config(
@@ -436,6 +422,14 @@
   main_context->set_job_factory(main_job_factory_.get());
   main_context->set_network_delegate(app_network_delegate_.get());
   main_context->set_net_log(net_log_);
+
+  net::HttpNetworkSession::Context session_context;
+  net::URLRequestContextBuilder::SetHttpNetworkSessionComponents(
+      main_context, &session_context);
+  main_transaction_factory_.reset(new net::HttpNetworkLayer(
+      new net::HttpNetworkSession(session_params, session_context)));
+  main_context->set_http_transaction_factory(main_transaction_factory_.get());
+
   return main_context;
 }
 
diff --git a/chromecast/browser/url_request_context_factory.h b/chromecast/browser/url_request_context_factory.h
index 85814a4..86ad3cc 100644
--- a/chromecast/browser/url_request_context_factory.h
+++ b/chromecast/browser/url_request_context_factory.h
@@ -75,15 +75,13 @@
 
   void InitializeSystemContextDependencies();
   void InitializeMainContextDependencies(
-      net::HttpTransactionFactory* factory,
       content::ProtocolHandlerMap* protocol_handlers,
       content::URLRequestInterceptorScopedVector request_interceptors);
   void InitializeMediaContextDependencies(net::HttpTransactionFactory* factory);
 
   void PopulateNetworkSessionParams(
       bool ignore_certificate_errors,
-      net::HttpNetworkSession::Params* session_params,
-      net::HttpNetworkSession::Context* session_context);
+      net::HttpNetworkSession::Params* session_params);
 
   // These are called by the RequestContextGetters to create each
   // RequestContext.
diff --git a/components/arc/net/arc_net_host_impl.cc b/components/arc/net/arc_net_host_impl.cc
index 50f464a4..3848665a 100644
--- a/components/arc/net/arc_net_host_impl.cc
+++ b/components/arc/net/arc_net_host_impl.cc
@@ -399,6 +399,10 @@
 }
 
 void ArcNetHostImpl::OnConnectionClosed() {
+  // Make sure shill doesn't leave an ARC VPN connected after Android
+  // goes down.
+  AndroidVpnStateChanged(arc::mojom::ConnectionStateType::NOT_CONNECTED);
+
   if (!observing_network_state_)
     return;
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 5029537c..1f08638c 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1320,6 +1320,8 @@
     "renderer_host/media/audio_output_authorization_handler.h",
     "renderer_host/media/audio_output_delegate_impl.cc",
     "renderer_host/media/audio_output_delegate_impl.h",
+    "renderer_host/media/audio_output_stream_observer_impl.cc",
+    "renderer_host/media/audio_output_stream_observer_impl.h",
     "renderer_host/media/audio_renderer_host.cc",
     "renderer_host/media/audio_renderer_host.h",
     "renderer_host/media/audio_sync_reader.cc",
diff --git a/content/browser/media/audio_stream_monitor.cc b/content/browser/media/audio_stream_monitor.cc
index 6d4bbdc2..01736cc 100644
--- a/content/browser/media/audio_stream_monitor.cc
+++ b/content/browser/media/audio_stream_monitor.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/stl_util.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_thread.h"
@@ -15,20 +16,9 @@
 
 namespace {
 
-enum class ActionType { STARTING, STOPPING };
-AudioStreamMonitor* StartStopMonitoringHelper(ActionType action_type,
-                                              int render_process_id,
-                                              int render_frame_id) {
+AudioStreamMonitor* GetMonitorForRenderFrame(int render_process_id,
+                                             int render_frame_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  // It's important that this code uses only the process id for lookup as there
-  // may not be a RenderFrameHost or WebContents attached to the RenderProcess
-  // at time of call; e.g., in the event of a crash.
-  RenderProcessHost* const render_process_host =
-      RenderProcessHost::FromID(render_process_id);
-  if (!render_process_host)
-    return nullptr;
-
   WebContentsImpl* const web_contents =
       static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(
           RenderFrameHost::FromID(render_process_id, render_frame_id)));
@@ -52,7 +42,7 @@
 AudioStreamMonitor::AudioStreamMonitor(WebContents* contents)
     : web_contents_(contents),
       clock_(base::DefaultTickClock::GetInstance()),
-      was_recently_audible_(false),
+      indicator_is_on_(false),
       is_audible_(false) {
   DCHECK(web_contents_);
 }
@@ -61,7 +51,7 @@
 
 bool AudioStreamMonitor::WasRecentlyAudible() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return was_recently_audible_;
+  return indicator_is_on_;
 }
 
 bool AudioStreamMonitor::IsCurrentlyAudible() const {
@@ -74,32 +64,33 @@
 
   // Note: It's possible for the RenderProcessHost and WebContents (and thus
   // this class) to survive the death of the render process and subsequently be
-  // reused. During this period StartStopMonitoringHelper() will be unable to
+  // reused. During this period GetMonitorForRenderFrame() will be unable to
   // lookup the WebContents using the now-dead |render_frame_id|. We must thus
-  // have this secondary mechanism for clearing stale callbacks.
-  for (auto it = poll_callbacks_.begin(); it != poll_callbacks_.end();) {
-    if (it->first.render_process_id == render_process_id) {
-      it = poll_callbacks_.erase(it);
-      OnStreamRemoved();
-    } else {
-      ++it;
-    }
-  }
-
-  if (poll_callbacks_.empty())
-    poll_timer_.Stop();
+  // have this secondary mechanism for clearing stale streams.
+  // Streams must be removed locally before calling UpdateStreams() in order to
+  // avoid removing streams from the process twice, since RenderProcessHost
+  // removes the streams on its own when the renderer process is gone.
+  base::EraseIf(streams_,
+                [render_process_id](const std::pair<StreamID, bool>& entry) {
+                  return entry.first.render_process_id == render_process_id;
+                });
+  UpdateStreams();
 }
 
 // static
-void AudioStreamMonitor::StartMonitoringStream(
-    int render_process_id,
-    int render_frame_id,
-    int stream_id,
-    const ReadPowerAndClipCallback& read_power_callback) {
+void AudioStreamMonitor::StartMonitoringStream(int render_process_id,
+                                               int render_frame_id,
+                                               int stream_id) {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&StartMonitoringHelper, render_process_id, render_frame_id,
-                     stream_id, read_power_callback));
+      base::BindOnce(
+          [](const StreamID& sid) {
+            if (AudioStreamMonitor* monitor = GetMonitorForRenderFrame(
+                    sid.render_process_id, sid.render_frame_id)) {
+              monitor->StartMonitoringStreamOnUIThread(sid);
+            }
+          },
+          StreamID{render_process_id, render_frame_id, stream_id}));
 }
 
 // static
@@ -108,106 +99,71 @@
                                               int stream_id) {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&StopMonitoringHelper, render_process_id, render_frame_id,
-                     stream_id));
+      base::BindOnce(
+          [](const StreamID& sid) {
+            if (AudioStreamMonitor* monitor = GetMonitorForRenderFrame(
+                    sid.render_process_id, sid.render_frame_id)) {
+              monitor->StopMonitoringStreamOnUIThread(sid);
+            }
+          },
+          StreamID{render_process_id, render_frame_id, stream_id}));
 }
 
 // static
-void AudioStreamMonitor::StartMonitoringHelper(
-    int render_process_id,
-    int render_frame_id,
-    int stream_id,
-    const ReadPowerAndClipCallback& read_power_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (AudioStreamMonitor* monitor = StartStopMonitoringHelper(
-          ActionType::STARTING, render_process_id, render_frame_id)) {
-    monitor->StartMonitoringStreamOnUIThread(render_process_id, render_frame_id,
-                                             stream_id, read_power_callback);
-  }
+void AudioStreamMonitor::UpdateStreamAudibleState(int render_process_id,
+                                                  int render_frame_id,
+                                                  int stream_id,
+                                                  bool is_audible) {
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::BindOnce(
+          [](const StreamID& sid, bool is_audible) {
+            if (AudioStreamMonitor* monitor = GetMonitorForRenderFrame(
+                    sid.render_process_id, sid.render_frame_id)) {
+              monitor->UpdateStreamAudibleStateOnUIThread(sid, is_audible);
+            }
+          },
+          StreamID{render_process_id, render_frame_id, stream_id}, is_audible));
 }
 
-// static
-void AudioStreamMonitor::StopMonitoringHelper(int render_process_id,
-                                              int render_frame_id,
-                                              int stream_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (AudioStreamMonitor* monitor = StartStopMonitoringHelper(
-          ActionType::STOPPING, render_process_id, render_frame_id)) {
-    monitor->StopMonitoringStreamOnUIThread(render_process_id, render_frame_id,
-                                            stream_id);
-  }
-}
-
-void AudioStreamMonitor::StartMonitoringStreamOnUIThread(
-    int render_process_id,
-    int render_frame_id,
-    int stream_id,
-    const ReadPowerAndClipCallback& read_power_callback) {
+void AudioStreamMonitor::StartMonitoringStreamOnUIThread(const StreamID& sid) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!read_power_callback.is_null());
-
-  const StreamID qualified_id = {render_process_id, render_frame_id, stream_id};
-  DCHECK(poll_callbacks_.find(qualified_id) == poll_callbacks_.end());
-
-  poll_callbacks_[qualified_id] = read_power_callback;
-
-  // Sends audible signal to RenderFrameHost when there is no power level
-  // monitoring, otherwise sends the signal when the stream becomes audible.
-  if (!power_level_monitoring_available()) {
-    if (auto* render_frame_host = static_cast<RenderFrameHostImpl*>(
-            RenderFrameHost::FromID(render_process_id, render_frame_id))) {
-      render_frame_host->OnAudibleStateChanged(true);
-    }
-  }
-
-  OnStreamAdded();
+  DCHECK(streams_.find(sid) == streams_.end());
+  streams_[sid] = false;
 }
 
-void AudioStreamMonitor::StopMonitoringStreamOnUIThread(int render_process_id,
-                                                        int render_frame_id,
-                                                        int stream_id) {
+void AudioStreamMonitor::StopMonitoringStreamOnUIThread(const StreamID& sid) {
   DCHECK(thread_checker_.CalledOnValidThread());
-
-  // In the event of render process death, these may have already been cleared.
-  auto it = poll_callbacks_.find(
-      StreamID{render_process_id, render_frame_id, stream_id});
-  if (it == poll_callbacks_.end())
+  auto it = streams_.find(sid);
+  if (it == streams_.end())
     return;
 
-  poll_callbacks_.erase(it);
-
-  // Sends non-audible signal to RenderFrameHost when there is no power level
-  // monitoring, otherwise sends the signal when the stream becomes non-audible.
-  if (!power_level_monitoring_available()) {
-    if (auto* render_frame_host = static_cast<RenderFrameHostImpl*>(
-            RenderFrameHost::FromID(render_process_id, render_frame_id))) {
-      render_frame_host->OnAudibleStateChanged(false);
-    }
-  }
-
-  OnStreamRemoved();
+  // First set the state of stream to silent in order to correctly update the
+  // frame state.
+  streams_[sid] = false;
+  UpdateStreams();
+  streams_.erase(it);
 }
 
-void AudioStreamMonitor::Poll() {
+void AudioStreamMonitor::UpdateStreamAudibleStateOnUIThread(const StreamID& sid,
+                                                            bool is_audible) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  auto it = streams_.find(sid);
+  DCHECK(it != streams_.end());
+  it->second = is_audible;
+  UpdateStreams();
+}
+
+void AudioStreamMonitor::UpdateStreams() {
   bool was_audible = is_audible_;
   is_audible_ = false;
 
   // Record whether or not a RenderFrameHost is audible.
   base::flat_map<RenderFrameHostImpl*, bool> audible_frame_map;
-  audible_frame_map.reserve(poll_callbacks_.size());
-  for (auto& kv : poll_callbacks_) {
-    // TODO(miu): A new UI for delivering specific power level and clipping
-    // information is still in the works.  For now, we throw away all
-    // information except for "is it audible?"
-    const float power_dbfs = kv.second.Run().first;
-    const float kSilenceThresholdDBFS = -72.24719896f;
-
-    const bool is_stream_audible = power_dbfs >= kSilenceThresholdDBFS;
-    if (!is_audible_ && is_stream_audible) {
-      last_blurt_time_ = clock_->NowTicks();
-      is_audible_ = true;
-      MaybeToggle();
-    }
+  audible_frame_map.reserve(streams_.size());
+  for (auto& kv : streams_) {
+    const bool is_stream_audible = kv.second;
+    is_audible_ |= is_stream_audible;
 
     // Record whether or not the RenderFrame is audible. A RenderFrame is
     // audible when it has at least one audio stream that is audible.
@@ -220,6 +176,9 @@
     audible_frame_map[render_frame_host_impl] |= is_stream_audible;
   }
 
+  if (was_audible && !is_audible_)
+    last_became_silent_time_ = clock_->NowTicks();
+
   // Update RenderFrameHost audible state only when state changed.
   for (auto& kv : audible_frame_map) {
     auto* render_frame_host_impl = kv.first;
@@ -228,23 +187,26 @@
       render_frame_host_impl->OnAudibleStateChanged(is_frame_audible);
   }
 
-  if (is_audible_ != was_audible)
+  if (is_audible_ != was_audible) {
+    MaybeToggle();
     web_contents_->OnAudioStateChanged(is_audible_);
+  }
 }
 
 void AudioStreamMonitor::MaybeToggle() {
-  const bool indicator_was_on = was_recently_audible_;
   const base::TimeTicks off_time =
-      last_blurt_time_ + base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds);
+      last_became_silent_time_ +
+      base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds);
   const base::TimeTicks now = clock_->NowTicks();
-  const bool should_indicator_be_on = now < off_time;
+  const bool should_stop_timer = is_audible_ || now >= off_time;
+  const bool should_indicator_be_on = is_audible_ || !should_stop_timer;
 
-  if (should_indicator_be_on != indicator_was_on) {
-    was_recently_audible_ = should_indicator_be_on;
+  if (should_indicator_be_on != indicator_is_on_) {
+    indicator_is_on_ = should_indicator_be_on;
     web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
   }
 
-  if (!should_indicator_be_on) {
+  if (should_stop_timer) {
     off_timer_.Stop();
   } else if (!off_timer_.IsRunning()) {
     off_timer_.Start(
@@ -254,35 +216,4 @@
   }
 }
 
-void AudioStreamMonitor::OnStreamAdded() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (poll_callbacks_.size() != 1u)
-    return;
-
-  if (!power_level_monitoring_available()) {
-    is_audible_ = true;
-    web_contents_->OnAudioStateChanged(true);
-    MaybeToggle();
-  } else if (!poll_timer_.IsRunning()) {
-    poll_timer_.Start(
-        FROM_HERE, base::TimeDelta::FromSeconds(1) /
-                       static_cast<int>(kPowerMeasurementsPerSecond),
-        base::Bind(&AudioStreamMonitor::Poll, base::Unretained(this)));
-  }
-}
-
-void AudioStreamMonitor::OnStreamRemoved() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!poll_callbacks_.empty())
-    return;
-
-  if (!power_level_monitoring_available()) {
-    is_audible_ = false;
-    web_contents_->OnAudioStateChanged(false);
-    MaybeToggle();
-  } else {
-    poll_timer_.Stop();
-  }
-}
-
 }  // namespace content
diff --git a/content/browser/media/audio_stream_monitor.h b/content/browser/media/audio_stream_monitor.h
index 0e8da39..4674b37 100644
--- a/content/browser/media/audio_stream_monitor.h
+++ b/content/browser/media/audio_stream_monitor.h
@@ -27,16 +27,16 @@
 
 class WebContents;
 
-// Repeatedly polls audio streams for their power levels, and "debounces" the
-// information into a simple, binary "was recently audible" result for the audio
-// indicators in the tab UI.  The debouncing logic is to: 1) Turn on immediately
-// when sound is audible; and 2) Hold on for X amount of time after sound has
-// gone silent, then turn off.  Said another way, we don't want tab indicators
-// to turn on/off repeatedly and annoy the user.  AudioStreamMonitor sends UI
+// Keeps track of the audible state of audio output streams and uses it to
+// maintain a "was recently audible" binary state for the audio indicators in
+// the tab UI.  The logic is to: 1) Turn on immediately when sound is audible;
+// and 2) Hold on for X amount of time after sound has gone silent, then turn
+// off if no longer audible.  Said another way, we don't want tab indicators to
+// turn on/off repeatedly and annoy the user.  AudioStreamMonitor sends UI
 // update notifications only when needed, but may be queried at any time.
 //
-// When power level monitoring is not available, audibility is approximated
-// with having active audio streams.
+// When monitoring is not available, audibility is approximated with having
+// active audio streams.
 //
 // Each WebContentsImpl owns an AudioStreamMonitor.
 class CONTENT_EXPORT AudioStreamMonitor {
@@ -59,24 +59,23 @@
   // any outstanding poll callbacks.
   void RenderProcessGone(int render_process_id);
 
-  // Starts or stops audio level monitoring respectively for the stream owned by
-  // the specified renderer.  Safe to call from any thread.
-  //
-  // The callback returns the current power level (in dBFS units) and the clip
-  // status (true if any part of the audio signal has clipped since the last
-  // callback run).  |stream_id| must be unique within a |render_process_id|.
-  typedef base::Callback<std::pair<float, bool>()> ReadPowerAndClipCallback;
-  static void StartMonitoringStream(
-      int render_process_id,
-      int render_frame_id,
-      int stream_id,
-      const ReadPowerAndClipCallback& read_power_callback);
+  // Starts or stops monitoring respectively for the stream owned by the
+  // specified renderer.  Safe to call from any thread.
+  static void StartMonitoringStream(int render_process_id,
+                                    int render_frame_id,
+                                    int stream_id);
   static void StopMonitoringStream(int render_process_id,
                                    int render_frame_id,
                                    int stream_id);
+  // Updates the audible state for the given stream. Safe to call from any
+  // thread.
+  static void UpdateStreamAudibleState(int render_process_id,
+                                       int render_frame_id,
+                                       int stream_id,
+                                       bool is_audible);
 
   void set_was_recently_audible_for_testing(bool value) {
-    was_recently_audible_ = value;
+    indicator_is_on_ = value;
   }
 
   void set_is_currently_audible_for_testing(bool value) { is_audible_ = value; }
@@ -85,58 +84,35 @@
   friend class AudioStreamMonitorTest;
 
   enum {
-    // Desired polling frequency.  Note: If this is set too low, short-duration
-    // "blip" sounds won't be detected.  http://crbug.com/339133#c4
-    kPowerMeasurementsPerSecond = 15,
-
-    // Amount of time to hold a tab indicator on after its last blurt.
+    // Minimum amount of time to hold a tab indicator on after it becomes
+    // silent.
     kHoldOnMilliseconds = 2000
   };
 
-  // Indicates if monitoring of audio stream power level is available.
-  // It's only available if AudioOutputController can and will monitor
-  // output power levels.
-  static bool power_level_monitoring_available() {
-    return media::AudioOutputController::will_monitor_audio_levels();
-  }
+  struct CONTENT_EXPORT StreamID {
+    int render_process_id;
+    int render_frame_id;
+    int stream_id;
+    bool operator<(const StreamID& other) const;
+    bool operator==(const StreamID& other) const;
+  };
 
-  // Helper methods for starting and stopping monitoring which lookup the
-  // identified renderer and forward calls to the correct AudioStreamMonitor.
-  static void StartMonitoringHelper(
-      int render_process_id,
-      int render_frame_id,
-      int stream_id,
-      const ReadPowerAndClipCallback& read_power_callback);
-  static void StopMonitoringHelper(int render_process_id,
-                                   int render_frame_id,
-                                   int stream_id);
+  // Starts monitoring the audible state for the given stream.
+  void StartMonitoringStreamOnUIThread(const StreamID& sid);
 
-  // Starts polling the stream for audio stream power levels using |callback|.
-  void StartMonitoringStreamOnUIThread(
-      int render_process_id,
-      int render_frame_id,
-      int stream_id,
-      const ReadPowerAndClipCallback& callback);
+  // Stops monitoring the audible state for the given stream.
+  void StopMonitoringStreamOnUIThread(const StreamID& sid);
 
-  // Stops polling the stream, discarding the internal copy of the |callback|
-  // provided in the call to StartMonitoringStream().
-  void StopMonitoringStreamOnUIThread(int render_process_id,
-                                      int render_frame_id,
-                                      int stream_id);
-
-  // Called by |poll_timer_| to sample the power levels from each of the streams
-  // playing in the tab.
-  void Poll();
+  // Updates the audible state for the given stream.
+  void UpdateStreamAudibleStateOnUIThread(const StreamID& sid, bool is_audible);
 
   // Compares last known indicator state with what it should be, and triggers UI
   // updates through |web_contents_| if needed.  When the indicator is turned
   // on, |off_timer_| is started to re-invoke this method in the future.
   void MaybeToggle();
+  void UpdateStreams();
 
-  // Helper functions to track number of active streams when power level
-  // monitoring is not available.
-  void OnStreamAdded();
-  void OnStreamRemoved();
+  // void OnStreamRemoved();
 
   // The WebContents instance to receive indicator toggle notifications.  This
   // pointer should be valid for the lifetime of AudioStreamMonitor.
@@ -149,32 +125,20 @@
   // Confirms single-threaded access in debug builds.
   base::ThreadChecker thread_checker_;
 
-  // The callbacks to read power levels for each stream.  Only playing (i.e.,
-  // not paused) streams will have an entry in this map.
-  struct CONTENT_EXPORT StreamID {
-    int render_process_id;
-    int render_frame_id;
-    int stream_id;
-    bool operator<(const StreamID& other) const;
-    bool operator==(const StreamID& other) const;
-  };
-  using StreamPollCallbackMap =
-      base::flat_map<StreamID, ReadPowerAndClipCallback>;
-  StreamPollCallbackMap poll_callbacks_;
+  // The audible state for each stream.  Only playing (i.e., not paused)
+  // streams will have an entry in this map.
+  base::flat_map<StreamID, bool> streams_;
 
-  // Records the last time at which sound was audible from any stream.
-  base::TimeTicks last_blurt_time_;
+  // Records the last time at which all streams became silent.
+  base::TimeTicks last_became_silent_time_;
 
   // Set to true if the last call to MaybeToggle() determined the indicator
   // should be turned on.
-  bool was_recently_audible_;
+  bool indicator_is_on_;
 
   // Whether the WebContents is currently audible.
   bool is_audible_;
 
-  // Calls Poll() at regular intervals while |poll_callbacks_| is non-empty.
-  base::RepeatingTimer poll_timer_;
-
   // Started only when an indicator is toggled on, to turn it off again in the
   // future.
   base::OneShotTimer off_timer_;
diff --git a/content/browser/media/audio_stream_monitor_unittest.cc b/content/browser/media/audio_stream_monitor_unittest.cc
index cb6931d576..1f02f7c 100644
--- a/content/browser/media/audio_stream_monitor_unittest.cc
+++ b/content/browser/media/audio_stream_monitor_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/debug/stack_trace.h"
 #include "base/macros.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -64,40 +65,27 @@
 
   void AdvanceClock(const base::TimeDelta& delta) { clock_.Advance(delta); }
 
-  AudioStreamMonitor::ReadPowerAndClipCallback CreatePollCallback(
-      int stream_id) {
-    return base::Bind(
-        &AudioStreamMonitorTest::ReadPower, base::Unretained(this), stream_id);
-  }
-
-  void SetStreamPower(int stream_id, float power) {
-    current_power_[stream_id] = power;
-  }
-
-  void SimulatePollTimerFired() { monitor_->Poll(); }
-
   void SimulateOffTimerFired() { monitor_->MaybeToggle(); }
 
-  void ExpectIsPolling(int render_process_id,
-                       int render_frame_id,
-                       int stream_id,
-                       bool is_polling) {
+  void ExpectIsMonitoring(int render_process_id,
+                          int render_frame_id,
+                          int stream_id,
+                          bool is_polling) {
     const AudioStreamMonitor::StreamID key = {render_process_id,
                                               render_frame_id, stream_id};
-    EXPECT_EQ(is_polling, monitor_->poll_callbacks_.find(key) !=
-                              monitor_->poll_callbacks_.end());
-    EXPECT_EQ(!monitor_->poll_callbacks_.empty(),
-              power_level_monitoring_available()
-                  ? monitor_->poll_timer_.IsRunning()
-                  : monitor_->IsCurrentlyAudible());
+    EXPECT_EQ(is_polling,
+              monitor_->streams_.find(key) != monitor_->streams_.end());
   }
 
-  void ExpectTabWasRecentlyAudible(bool was_audible,
-                                   const base::TimeTicks& last_blurt_time) {
-    EXPECT_EQ(was_audible, monitor_->was_recently_audible_);
-    EXPECT_EQ(last_blurt_time, monitor_->last_blurt_time_);
-    EXPECT_EQ(monitor_->was_recently_audible_,
-              monitor_->off_timer_.IsRunning());
+  void ExpectTabWasRecentlyAudible(
+      bool was_audible,
+      const base::TimeTicks& last_became_silent_time) {
+    EXPECT_EQ(was_audible, monitor_->indicator_is_on_);
+    EXPECT_EQ(last_became_silent_time, monitor_->last_became_silent_time_);
+    EXPECT_EQ(monitor_->off_timer_.IsRunning(),
+              monitor_->indicator_is_on_ && !monitor_->IsCurrentlyAudible() &&
+                  clock_.NowTicks() <
+                      monitor_->last_became_silent_time_ + holding_period());
   }
 
   void ExpectIsCurrentlyAudible() const {
@@ -134,9 +122,9 @@
         .RetiresOnSaturation();
   }
 
-  static base::TimeDelta one_polling_interval() {
-    return base::TimeDelta::FromSeconds(1) /
-           static_cast<int>(AudioStreamMonitor::kPowerMeasurementsPerSecond);
+  // A small time step useful for testing the passage of time.
+  static base::TimeDelta one_time_step() {
+    return base::TimeDelta::FromSeconds(1) / 15;
   }
 
   static base::TimeDelta holding_period() {
@@ -144,42 +132,34 @@
         AudioStreamMonitor::kHoldOnMilliseconds);
   }
 
-  void StartMonitoring(
-      int render_process_id,
-      int render_frame_id,
-      int stream_id,
-      const AudioStreamMonitor::ReadPowerAndClipCallback& callback) {
-    if (!power_level_monitoring_available() &&
-        monitor_->poll_callbacks_.empty()) {
-      ExpectCurrentlyAudibleChangeNotification(true);
-    }
-    monitor_->StartMonitoringStreamOnUIThread(
-        render_process_id, render_frame_id, stream_id, callback);
+  void StartMonitoring(int render_process_id,
+                       int render_frame_id,
+                       int stream_id) {
+    monitor_->StartMonitoringStreamOnUIThread(AudioStreamMonitor::StreamID{
+        render_process_id, render_frame_id, stream_id});
   }
 
   void StopMonitoring(int render_process_id,
                       int render_frame_id,
                       int stream_id) {
-    if (!power_level_monitoring_available() &&
-        monitor_->poll_callbacks_.size() == 1u) {
-      ExpectCurrentlyAudibleChangeNotification(false);
-    }
-    monitor_->StopMonitoringStreamOnUIThread(render_process_id, render_frame_id,
-                                             stream_id);
+    monitor_->StopMonitoringStreamOnUIThread(AudioStreamMonitor::StreamID{
+        render_process_id, render_frame_id, stream_id});
   }
 
-  bool power_level_monitoring_available() {
-    return AudioStreamMonitor::power_level_monitoring_available();
+  void UpdateAudibleState(int render_process_id,
+                          int render_frame_id,
+                          int stream_id,
+                          bool is_audible) {
+    monitor_->UpdateStreamAudibleStateOnUIThread(
+        AudioStreamMonitor::StreamID{render_process_id, render_frame_id,
+                                     stream_id},
+        is_audible);
   }
 
  protected:
   AudioStreamMonitor* monitor_;
 
  private:
-  std::pair<float, bool> ReadPower(int stream_id) {
-    return std::make_pair(current_power_[stream_id], false);
-  }
-
   void ExpectWasRecentlyAudible() const {
     EXPECT_TRUE(monitor_->WasRecentlyAudible());
   }
@@ -190,79 +170,64 @@
 
   MockWebContentsDelegate mock_web_contents_delegate_;
   base::SimpleTestTickClock clock_;
-  std::map<int, float> current_power_;
 
   DISALLOW_COPY_AND_ASSIGN(AudioStreamMonitorTest);
 };
 
-// Tests that AudioStreamMonitor is polling while it has a
-// ReadPowerAndClipCallback, and is not polling at other times.
-TEST_F(AudioStreamMonitorTest, PollsWhenProvidedACallback) {
-  if (!power_level_monitoring_available())
-    return;
-
+TEST_F(AudioStreamMonitorTest, MonitorsWhenProvidedAStream) {
   EXPECT_FALSE(monitor_->WasRecentlyAudible());
   ExpectNotCurrentlyAudible();
-  ExpectIsPolling(kRenderProcessId, kRenderFrameId, kStreamId, false);
+  ExpectIsMonitoring(kRenderProcessId, kRenderFrameId, kStreamId, false);
 
-  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId,
-                  CreatePollCallback(kStreamId));
+  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId);
   EXPECT_FALSE(monitor_->WasRecentlyAudible());
   ExpectNotCurrentlyAudible();
-  ExpectIsPolling(kRenderProcessId, kRenderFrameId, kStreamId, true);
+  ExpectIsMonitoring(kRenderProcessId, kRenderFrameId, kStreamId, true);
 
   StopMonitoring(kRenderProcessId, kRenderFrameId, kStreamId);
   EXPECT_FALSE(monitor_->WasRecentlyAudible());
   ExpectNotCurrentlyAudible();
-  ExpectIsPolling(kRenderProcessId, kRenderFrameId, kStreamId, false);
+  ExpectIsMonitoring(kRenderProcessId, kRenderFrameId, kStreamId, false);
 }
 
-// Tests that AudioStreamMonitor debounces the power level readings it's taking,
-// which could be fluctuating rapidly between the audible versus silence
-// threshold.  See comments in audio_stream_monitor.h for expected behavior.
-TEST_F(AudioStreamMonitorTest,
-       ImpulsesKeepIndicatorOnUntilHoldingPeriodHasPassed) {
-  if (!power_level_monitoring_available())
-    return;
-
-  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId,
-                  CreatePollCallback(kStreamId));
+// Tests that AudioStreamMonitor keeps the indicator on for the holding period
+// even if there is silence during the holding period.
+// See comments in audio_stream_monitor.h for expected behavior.
+TEST_F(AudioStreamMonitorTest, IndicatorIsOnUntilHoldingPeriodHasPassed) {
+  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId);
 
   // Expect WebContents will get one call form AudioStreamMonitor to toggle the
-  // indicator on upon the very first poll.
+  // indicator upon the very first notification that the stream has become
+  // audible.
   ExpectRecentlyAudibleChangeNotification(true);
 
-  // Loop, each time testing a slightly longer period of polled silence.  The
-  // recently audible state should not change while the currently audible one
-  // should.
-  int num_silence_polls = 1;
-  base::TimeTicks last_blurt_time;
+  // Loop, each time testing a slightly longer period of silence.  The recently
+  // audible state should not change while the currently audible one should.
+  int num_silence_steps = 1;
+  base::TimeTicks last_became_silent_time;
   do {
     ExpectCurrentlyAudibleChangeNotification(true);
 
-    // Poll an audible signal, and expect tab indicator state is on.
-    SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
-    last_blurt_time = GetTestClockTime();
-    SimulatePollTimerFired();
-    ExpectTabWasRecentlyAudible(true, last_blurt_time);
-    AdvanceClock(one_polling_interval());
+    UpdateAudibleState(kRenderProcessId, kRenderFrameId, kStreamId, true);
+    ExpectTabWasRecentlyAudible(true, last_became_silent_time);
+    AdvanceClock(one_time_step());
 
     ExpectCurrentlyAudibleChangeNotification(false);
 
-    // Poll a silent signal repeatedly, ensuring that the indicator is being
-    // held on during the holding period.
-    SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
-    for (int i = 0; i < num_silence_polls; ++i) {
-      SimulatePollTimerFired();
-      ExpectTabWasRecentlyAudible(true, last_blurt_time);
+    // Notify that the stream has become silent and advance time repeatedly,
+    // ensuring that the indicator is being held on during the holding period.
+    UpdateAudibleState(kRenderProcessId, kRenderFrameId, kStreamId, false);
+    last_became_silent_time = GetTestClockTime();
+    ExpectTabWasRecentlyAudible(true, last_became_silent_time);
+    for (int i = 0; i < num_silence_steps; ++i) {
       // Note: Redundant off timer firings should not have any effect.
       SimulateOffTimerFired();
-      ExpectTabWasRecentlyAudible(true, last_blurt_time);
-      AdvanceClock(one_polling_interval());
+      ExpectTabWasRecentlyAudible(true, last_became_silent_time);
+      AdvanceClock(one_time_step());
     }
 
-    ++num_silence_polls;
-  } while (GetTestClockTime() < last_blurt_time + holding_period());
+    ++num_silence_steps;
+  } while (GetTestClockTime() < last_became_silent_time + holding_period());
 
   // At this point, the clock has just advanced to beyond the holding period, so
   // the next firing of the off timer should turn off the tab indicator.  Also,
@@ -270,149 +235,143 @@
   ExpectRecentlyAudibleChangeNotification(false);
   for (int i = 0; i < 10; ++i) {
     SimulateOffTimerFired();
-    ExpectTabWasRecentlyAudible(false, last_blurt_time);
-    AdvanceClock(one_polling_interval());
+    ExpectTabWasRecentlyAudible(false, last_became_silent_time);
+    AdvanceClock(one_time_step());
   }
 }
 
-// Tests that the AudioStreamMonitor correctly processes the blurts from two
+// Tests that the AudioStreamMonitor correctly processes updates from two
 // different streams in the same tab.
-TEST_F(AudioStreamMonitorTest, HandlesMultipleStreamsBlurting) {
-  if (!power_level_monitoring_available())
-    return;
+TEST_F(AudioStreamMonitorTest, HandlesMultipleStreamUpdate) {
+  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId);
+  StartMonitoring(kRenderProcessId, kAnotherRenderFrameId, kAnotherStreamId);
 
-  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId,
-                  CreatePollCallback(kStreamId));
-  StartMonitoring(kRenderProcessId, kAnotherRenderFrameId, kAnotherStreamId,
-                  CreatePollCallback(kAnotherStreamId));
-
-  base::TimeTicks last_blurt_time;
-  ExpectTabWasRecentlyAudible(false, last_blurt_time);
+  base::TimeTicks last_became_silent_time;
+  ExpectTabWasRecentlyAudible(false, last_became_silent_time);
   ExpectNotCurrentlyAudible();
 
-  // Measure audible sound from the first stream and silence from the second.
-  // The tab becomes audible.
+  // The first stream becomes audible and the second stream is silent. The tab
+  // becomes audible.
   ExpectRecentlyAudibleChangeNotification(true);
   ExpectCurrentlyAudibleChangeNotification(true);
 
-  SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
-  SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
-  last_blurt_time = GetTestClockTime();
-  SimulatePollTimerFired();
-  ExpectTabWasRecentlyAudible(true, last_blurt_time);
+  UpdateAudibleState(kRenderProcessId, kRenderFrameId, kStreamId, true);
+  UpdateAudibleState(kRenderProcessId, kAnotherRenderFrameId, kAnotherStreamId,
+                     false);
+  ExpectTabWasRecentlyAudible(true, last_became_silent_time);
   ExpectIsCurrentlyAudible();
 
   // Halfway through the holding period, the second stream joins in.  The
   // indicator stays on.
   AdvanceClock(holding_period() / 2);
   SimulateOffTimerFired();
-  SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
-  last_blurt_time = GetTestClockTime();
-  SimulatePollTimerFired();  // Restarts holding period.
-  ExpectTabWasRecentlyAudible(true, last_blurt_time);
+  UpdateAudibleState(kRenderProcessId, kAnotherRenderFrameId, kAnotherStreamId,
+                     true);
+  ExpectTabWasRecentlyAudible(true, last_became_silent_time);
   ExpectIsCurrentlyAudible();
 
-  // Now, measure silence from both streams.  After an entire holding period
-  // has passed (since the second stream joined in), the tab will no longer
-  // become audible nor recently audible.
+  // Now, both streams become silent. The tab becoms silent but the indicator
+  // stays on.
   ExpectCurrentlyAudibleChangeNotification(false);
-  ExpectRecentlyAudibleChangeNotification(false);
+  UpdateAudibleState(kRenderProcessId, kRenderFrameId, kStreamId, false);
+  UpdateAudibleState(kRenderProcessId, kAnotherRenderFrameId, kAnotherStreamId,
+                     false);
+  last_became_silent_time = GetTestClockTime();
+  ExpectNotCurrentlyAudible();
+  ExpectTabWasRecentlyAudible(true, last_became_silent_time);
 
-  AdvanceClock(holding_period());
+  // Advance half a holding period and the indicator should still be on.
+  AdvanceClock(holding_period() / 2);
   SimulateOffTimerFired();
-  SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
-  SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
-  SimulatePollTimerFired();
-  ExpectTabWasRecentlyAudible(false, last_blurt_time);
+  ExpectTabWasRecentlyAudible(true, last_became_silent_time);
   ExpectNotCurrentlyAudible();
 
-  // Now, measure silence from the first stream and audible sound from the
-  // second.  The tab becomes audible again.
+  // The first stream becomes audible again during the holding period.
+  // The tab becomes audible and the indicator stays on.
+  ExpectCurrentlyAudibleChangeNotification(true);
+  UpdateAudibleState(kRenderProcessId, kRenderFrameId, kStreamId, true);
+  ExpectTabWasRecentlyAudible(true, last_became_silent_time);
+  ExpectIsCurrentlyAudible();
+
+  // Advance a holding period. The original holding period has expired but the
+  // indicator should stay on because a stream became audible in the meantime.
+  AdvanceClock(holding_period() / 2);
+  SimulateOffTimerFired();
+  ExpectTabWasRecentlyAudible(true, last_became_silent_time);
+  ExpectIsCurrentlyAudible();
+
+  // The first stream becomes silent again. The tab becomes silent and the
+  // indicator is still on.
+  ExpectCurrentlyAudibleChangeNotification(false);
+  UpdateAudibleState(kRenderProcessId, kRenderFrameId, kStreamId, false);
+  last_became_silent_time = GetTestClockTime();
+  ExpectTabWasRecentlyAudible(true, last_became_silent_time);
+  ExpectNotCurrentlyAudible();
+
+  // After a holding period passes, the indicator turns off.
+  ExpectRecentlyAudibleChangeNotification(false);
+  AdvanceClock(holding_period());
+  SimulateOffTimerFired();
+  ExpectTabWasRecentlyAudible(false, last_became_silent_time);
+  ExpectNotCurrentlyAudible();
+
+  // Now, the second stream becomes audible and the first one remains silent.
+  // The tab becomes audible again.
   ExpectRecentlyAudibleChangeNotification(true);
   ExpectCurrentlyAudibleChangeNotification(true);
-
-  SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
-  last_blurt_time = GetTestClockTime();
-  SimulatePollTimerFired();
-  ExpectTabWasRecentlyAudible(true, last_blurt_time);
+  UpdateAudibleState(kRenderProcessId, kAnotherRenderFrameId, kAnotherStreamId,
+                     true);
+  ExpectTabWasRecentlyAudible(true, last_became_silent_time);
   ExpectIsCurrentlyAudible();
 
   // From here onwards, both streams are silent.  Halfway through the holding
   // period, the tab is no longer audible but stays as recently audible.
   ExpectCurrentlyAudibleChangeNotification(false);
-
-  SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
+  UpdateAudibleState(kRenderProcessId, kAnotherRenderFrameId, kAnotherStreamId,
+                     false);
+  last_became_silent_time = GetTestClockTime();
   AdvanceClock(holding_period() / 2);
-  SimulatePollTimerFired();
   SimulateOffTimerFired();
-  ExpectTabWasRecentlyAudible(true, last_blurt_time);
+  ExpectTabWasRecentlyAudible(true, last_became_silent_time);
   ExpectNotCurrentlyAudible();
 
   // Just past the holding period, the tab is no longer marked as recently
   // audible.
   ExpectRecentlyAudibleChangeNotification(false);
-
-  AdvanceClock(holding_period() - (GetTestClockTime() - last_blurt_time));
+  AdvanceClock(holding_period() -
+               (GetTestClockTime() - last_became_silent_time));
   SimulateOffTimerFired();
-  ExpectTabWasRecentlyAudible(false, last_blurt_time);
+  ExpectTabWasRecentlyAudible(false, last_became_silent_time);
   ExpectNotCurrentlyAudible();
 
-  // Polling should not turn the indicator back while both streams are remaining
-  // silent.
+  // The passage of time should not turn the indicator back while both streams
+  // are remaining silent.
   for (int i = 0; i < 100; ++i) {
-    AdvanceClock(one_polling_interval());
-    SimulatePollTimerFired();
-    ExpectTabWasRecentlyAudible(false, last_blurt_time);
+    AdvanceClock(one_time_step());
+    ExpectTabWasRecentlyAudible(false, last_became_silent_time);
     ExpectNotCurrentlyAudible();
   }
 }
 
 TEST_F(AudioStreamMonitorTest, MultipleRendererProcesses) {
-  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId,
-                  CreatePollCallback(kStreamId));
-  StartMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId,
-                  CreatePollCallback(kStreamId));
-  ExpectIsPolling(kRenderProcessId, kRenderFrameId, kStreamId, true);
-  ExpectIsPolling(kAnotherRenderProcessId, kRenderFrameId, kStreamId, true);
+  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId);
+  StartMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId);
+  ExpectIsMonitoring(kRenderProcessId, kRenderFrameId, kStreamId, true);
+  ExpectIsMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId, true);
   StopMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId);
-  ExpectIsPolling(kRenderProcessId, kRenderFrameId, kStreamId, true);
-  ExpectIsPolling(kAnotherRenderProcessId, kRenderFrameId, kStreamId, false);
+  ExpectIsMonitoring(kRenderProcessId, kRenderFrameId, kStreamId, true);
+  ExpectIsMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId, false);
 }
 
 TEST_F(AudioStreamMonitorTest, RenderProcessGone) {
-  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId,
-                  CreatePollCallback(kStreamId));
-  StartMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId,
-                  CreatePollCallback(kStreamId));
-  ExpectIsPolling(kRenderProcessId, kRenderFrameId, kStreamId, true);
-  ExpectIsPolling(kAnotherRenderProcessId, kRenderFrameId, kStreamId, true);
+  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId);
+  StartMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId);
+  ExpectIsMonitoring(kRenderProcessId, kRenderFrameId, kStreamId, true);
+  ExpectIsMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId, true);
   monitor_->RenderProcessGone(kRenderProcessId);
-  ExpectIsPolling(kRenderProcessId, kRenderFrameId, kStreamId, false);
-  if (!power_level_monitoring_available())
-    ExpectCurrentlyAudibleChangeNotification(false);
+  ExpectIsMonitoring(kRenderProcessId, kRenderFrameId, kStreamId, false);
   monitor_->RenderProcessGone(kAnotherRenderProcessId);
-  ExpectIsPolling(kAnotherRenderProcessId, kRenderFrameId, kStreamId, false);
-}
-
-TEST_F(AudioStreamMonitorTest, NoPowerLevelMonitoring) {
-  if (power_level_monitoring_available())
-    return;
-
-  ExpectNotCurrentlyAudible();
-  StartMonitoring(kRenderProcessId, kRenderFrameId, kStreamId,
-                  CreatePollCallback(kStreamId));
-  ExpectIsCurrentlyAudible();
-  ExpectIsPolling(kRenderProcessId, kRenderFrameId, kStreamId, true);
-
-  StartMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId,
-                  CreatePollCallback(kStreamId));
-  ExpectIsCurrentlyAudible();
-  ExpectIsPolling(kAnotherRenderProcessId, kRenderFrameId, kStreamId, true);
-
-  StopMonitoring(kRenderProcessId, kRenderFrameId, kStreamId);
-  ExpectIsCurrentlyAudible();
-  StopMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId);
-  ExpectNotCurrentlyAudible();
+  ExpectIsMonitoring(kAnotherRenderProcessId, kRenderFrameId, kStreamId, false);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/audio_output_delegate_impl.cc b/content/browser/renderer_host/media/audio_output_delegate_impl.cc
index 43d7083..edaa789 100644
--- a/content/browser/renderer_host/media/audio_output_delegate_impl.cc
+++ b/content/browser/renderer_host/media/audio_output_delegate_impl.cc
@@ -21,6 +21,11 @@
 
 namespace content {
 
+const float kSilenceThresholdDBFS = -72.24719896f;
+// Desired polling frequency.  Note: If this is set too low, short-duration
+// "blip" sounds won't be detected.  http://crbug.com/339133#c4
+const int kPowerMeasurementsPerSecond = 15;
+
 // This class trampolines callbacks from the controller to the delegate. Since
 // callbacks from the controller are stopped asynchronously, this class holds
 // a weak pointer to the delegate, allowing the delegate to stop callbacks
@@ -93,6 +98,7 @@
     int render_frame_id,
     int render_process_id,
     const media::AudioParameters& params,
+    media::mojom::AudioOutputStreamObserverPtr observer,
     const std::string& output_device_id) {
   auto socket = std::make_unique<base::CancelableSyncSocket>();
   auto reader = AudioSyncReader::Create(params, socket.get());
@@ -102,7 +108,8 @@
   return std::make_unique<AudioOutputDelegateImpl>(
       std::move(reader), std::move(socket), handler, audio_manager,
       std::move(audio_log), mirroring_manager, media_observer, stream_id,
-      render_frame_id, render_process_id, params, output_device_id);
+      render_frame_id, render_process_id, params, std::move(observer),
+      output_device_id);
 }
 
 AudioOutputDelegateImpl::AudioOutputDelegateImpl(
@@ -117,6 +124,7 @@
     int render_frame_id,
     int render_process_id,
     const media::AudioParameters& params,
+    media::mojom::AudioOutputStreamObserverPtr observer,
     const std::string& output_device_id)
     : subscriber_(handler),
       audio_log_(std::move(audio_log)),
@@ -126,6 +134,7 @@
       stream_id_(stream_id),
       render_frame_id_(render_frame_id),
       render_process_id_(render_process_id),
+      observer_(std::move(observer)),
       weak_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(subscriber_);
@@ -133,6 +142,7 @@
   DCHECK(audio_log_);
   DCHECK(mirroring_manager_);
   DCHECK(reader_);
+  DCHECK(observer_);
   // Since the event handler never directly calls functions on |this| but rather
   // posts them to the IO thread, passing a pointer from the constructor is
   // safe.
@@ -217,17 +227,27 @@
 
   playing_ = playing;
   if (playing) {
-    // Note that this takes a reference to |controller_|, and
-    // (Start|Stop)MonitoringStream calls are async, so we don't have a
-    // guarantee for when the controller is destroyed.
-    AudioStreamMonitor::StartMonitoringStream(
-        render_process_id_, render_frame_id_, stream_id_,
-        base::BindRepeating(
-            &media::AudioOutputController::ReadCurrentPowerAndClip,
-            controller_));
+    if (observer_)
+      observer_->DidStartPlaying();
+    if (media::AudioOutputController::will_monitor_audio_levels()) {
+      DCHECK(!poll_timer_.IsRunning());
+      // base::Unretained is safe in this case because |this| owns
+      // |poll_timer_|.
+      poll_timer_.Start(
+          FROM_HERE,
+          base::TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond,
+          base::Bind(&AudioOutputDelegateImpl::PollAudioLevel,
+                     base::Unretained(this)));
+    } else if (observer_) {
+      observer_->DidChangeAudibleState(true);
+    }
   } else {
-    AudioStreamMonitor::StopMonitoringStream(render_process_id_,
-                                             render_frame_id_, stream_id_);
+    if (media::AudioOutputController::will_monitor_audio_levels()) {
+      DCHECK(poll_timer_.IsRunning());
+      poll_timer_.Stop();
+    }
+    if (observer_)
+      observer_->DidStopPlaying();
   }
 }
 
@@ -243,4 +263,19 @@
   return controller_.get();
 }
 
+void AudioOutputDelegateImpl::PollAudioLevel() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  bool was_audible = is_audible_;
+  is_audible_ = IsAudible();
+
+  if (observer_ && is_audible_ != was_audible)
+    observer_->DidChangeAudibleState(is_audible_);
+}
+
+bool AudioOutputDelegateImpl::IsAudible() const {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  float power_dbfs = controller_->ReadCurrentPowerAndClip().first;
+  return power_dbfs >= kSilenceThresholdDBFS;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/media/audio_output_delegate_impl.h b/content/browser/renderer_host/media/audio_output_delegate_impl.h
index cb56e2b..c7bad03 100644
--- a/content/browser/renderer_host/media/audio_output_delegate_impl.h
+++ b/content/browser/renderer_host/media/audio_output_delegate_impl.h
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
 #include "media/audio/audio_output_delegate.h"
+#include "media/mojo/interfaces/audio_output_stream.mojom.h"
 
 namespace content {
 class AudioMirroringManager;
@@ -43,6 +44,7 @@
       int render_frame_id,
       int render_process_id,
       const media::AudioParameters& params,
+      media::mojom::AudioOutputStreamObserverPtr observer,
       const std::string& output_device_id);
 
   AudioOutputDelegateImpl(
@@ -57,6 +59,7 @@
       int render_frame_id,
       int render_process_id,
       const media::AudioParameters& params,
+      media::mojom::AudioOutputStreamObserverPtr observer,
       const std::string& output_device_id);
 
   ~AudioOutputDelegateImpl() override;
@@ -75,6 +78,8 @@
   void OnError();
   void UpdatePlayingState(bool playing);
   media::AudioOutputController* GetControllerForTesting() const;
+  void PollAudioLevel();
+  bool IsAudible() const;
 
   // This is the event handler which |this| send notifications to.
   EventHandler* subscriber_;
@@ -94,6 +99,13 @@
   // This flag ensures that we only send OnStreamStateChanged notifications
   // and (de)register with the stream monitor when the state actually changes.
   bool playing_ = false;
+
+  // Calls PollAudioLevel() at regular intervals while |playing_| is true.
+  base::RepeatingTimer poll_timer_;
+  bool is_audible_ = false;
+  // |observer_| is notified about changes in the audible state of the stream.
+  media::mojom::AudioOutputStreamObserverPtr observer_;
+
   base::WeakPtrFactory<AudioOutputDelegateImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AudioOutputDelegateImpl);
diff --git a/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc b/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc
index f7ebc95..cfa46544 100644
--- a/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc
+++ b/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc
@@ -27,6 +27,8 @@
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/gmock_callback_support.h"
 #include "media/base/media_switches.h"
+#include "media/mojo/interfaces/audio_output_stream.mojom.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -103,6 +105,17 @@
   void Close() override {}
 };
 
+class MockAudioOutputStreamObserver
+    : public media::mojom::AudioOutputStreamObserver {
+ public:
+  ~MockAudioOutputStreamObserver() override = default;
+
+  // media::mojom::AudioOutputStreamObserver implementation
+  MOCK_METHOD0(DidStartPlaying, void());
+  MOCK_METHOD0(DidStopPlaying, void());
+  MOCK_METHOD1(DidChangeAudibleState, void(bool));
+};
+
 }  // namespace
 
 class AudioOutputDelegateTest : public testing::Test {
@@ -123,6 +136,21 @@
   }
   ~AudioOutputDelegateTest() { audio_manager_->Shutdown(); }
 
+  mojo::StrongBindingPtr<media::mojom::AudioOutputStreamObserver>
+  CreateObserverBinding(
+      media::mojom::AudioOutputStreamObserverPtr* observer_ptr) {
+    return mojo::MakeStrongBinding(
+        std::make_unique<MockAudioOutputStreamObserver>(),
+        mojo::MakeRequest(observer_ptr));
+  }
+
+  MockAudioOutputStreamObserver& GetMockObserver(
+      mojo::StrongBindingPtr<media::mojom::AudioOutputStreamObserver>*
+          observer_binding) {
+    return *static_cast<MockAudioOutputStreamObserver*>(
+        (*observer_binding)->impl());
+  }
+
   // Test bodies are here, so that we can run them on the IO thread.
   void CreateTest(base::Closure done) {
     EXPECT_CALL(media_observer_,
@@ -130,6 +158,10 @@
     EXPECT_CALL(event_handler_, GotOnStreamCreated());
     EXPECT_CALL(mirroring_manager_,
                 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()));
+    media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+    auto observer_binding = CreateObserverBinding(&observer_ptr);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying()).Times(0);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying()).Times(0);
 
     {
       auto socket = std::make_unique<base::CancelableSyncSocket>();
@@ -140,7 +172,8 @@
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
 
       SyncWithAllThreads();
 
@@ -150,23 +183,43 @@
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done);
   }
 
-  void PlayTest(base::Closure done) {
+  void PlayTest(base::Closure done, bool use_bound_observer) {
     EXPECT_CALL(media_observer_,
                 OnCreatingAudioStream(kRenderProcessId, kRenderFrameId));
     EXPECT_CALL(event_handler_, GotOnStreamCreated());
     EXPECT_CALL(mirroring_manager_,
                 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()));
+    media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+    auto observer_binding = CreateObserverBinding(&observer_ptr);
+    if (use_bound_observer) {
+      EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying())
+          .Times(0);
+      EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying())
+          .Times(0);
+    }
 
     {
       auto socket = std::make_unique<base::CancelableSyncSocket>();
       auto reader = AudioSyncReader::Create(Params(), socket.get());
+      media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+      auto observer_binding = CreateObserverBinding(&observer_ptr);
+      if (use_bound_observer) {
+        InSequence s;
+        EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying());
+        EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying());
+      }
+
       AudioOutputDelegateImpl delegate(
           std::move(reader), std::move(socket), &event_handler_,
           audio_manager_.get(),
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
+
+      if (!use_bound_observer)
+        observer_binding->Close();
 
       delegate.OnPlayStream();
 
@@ -184,6 +237,10 @@
     EXPECT_CALL(event_handler_, GotOnStreamCreated());
     EXPECT_CALL(mirroring_manager_,
                 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()));
+    media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+    auto observer_binding = CreateObserverBinding(&observer_ptr);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying()).Times(0);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying()).Times(0);
 
     {
       auto socket = std::make_unique<base::CancelableSyncSocket>();
@@ -194,7 +251,8 @@
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
 
       delegate.OnPauseStream();
 
@@ -216,13 +274,22 @@
     {
       auto socket = std::make_unique<base::CancelableSyncSocket>();
       auto reader = AudioSyncReader::Create(Params(), socket.get());
+      media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+      auto observer_binding = CreateObserverBinding(&observer_ptr);
+      InSequence s;
+      EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying());
+      EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying());
+      EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying());
+      EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying());
+
       AudioOutputDelegateImpl delegate(
           std::move(reader), std::move(socket), &event_handler_,
           audio_manager_.get(),
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
 
       delegate.OnPlayStream();
       delegate.OnPauseStream();
@@ -246,13 +313,20 @@
     {
       auto socket = std::make_unique<base::CancelableSyncSocket>();
       auto reader = AudioSyncReader::Create(Params(), socket.get());
+      media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+      auto observer_binding = CreateObserverBinding(&observer_ptr);
+      InSequence s;
+      EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying());
+      EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying());
+
       AudioOutputDelegateImpl delegate(
           std::move(reader), std::move(socket), &event_handler_,
           audio_manager_.get(),
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
 
       delegate.OnPlayStream();
       delegate.OnPlayStream();
@@ -271,6 +345,10 @@
     EXPECT_CALL(event_handler_, GotOnStreamCreated());
     EXPECT_CALL(mirroring_manager_,
                 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()));
+    media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+    auto observer_binding = CreateObserverBinding(&observer_ptr);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying()).Times(0);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying()).Times(0);
 
     DummyAudioOutputStream stream;
     {
@@ -282,7 +360,8 @@
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
 
       delegate.GetControllerForTesting()->StartDiverting(&stream);
 
@@ -311,7 +390,7 @@
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), nullptr, kDefaultDeviceId);
 
       delegate.GetControllerForTesting()->StartDiverting(&stream);
 
@@ -332,6 +411,11 @@
     EXPECT_CALL(event_handler_, GotOnStreamCreated());
     EXPECT_CALL(mirroring_manager_,
                 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()));
+    media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+    auto observer_binding = CreateObserverBinding(&observer_ptr);
+    InSequence s;
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying());
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying());
 
     DummyAudioOutputStream stream;
     {
@@ -343,7 +427,8 @@
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
 
       delegate.OnPlayStream();
       delegate.GetControllerForTesting()->StartDiverting(&stream);
@@ -371,6 +456,10 @@
     EXPECT_CALL(mirroring_manager_,
                 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()));
     EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull()));
+    media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+    auto observer_binding = CreateObserverBinding(&observer_ptr);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying());
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying());
 
     auto socket = std::make_unique<base::CancelableSyncSocket>();
     auto reader = AudioSyncReader::Create(Params(), socket.get());
@@ -380,7 +469,7 @@
         log_factory_.CreateAudioLog(
             media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
         &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-        kRenderProcessId, Params(), kDefaultDeviceId);
+        kRenderProcessId, Params(), std::move(observer_ptr), kDefaultDeviceId);
 
     delegate->OnPlayStream();
     delegate->GetControllerForTesting()->OnError();
@@ -400,6 +489,10 @@
     EXPECT_CALL(mirroring_manager_,
                 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()));
     EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull()));
+    media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+    auto observer_binding = CreateObserverBinding(&observer_ptr);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying()).Times(0);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying()).Times(0);
 
     {
       auto socket = std::make_unique<base::CancelableSyncSocket>();
@@ -410,7 +503,8 @@
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
     }
     SyncWithAllThreads();
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done);
@@ -423,6 +517,10 @@
     EXPECT_CALL(mirroring_manager_,
                 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()));
     EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull()));
+    media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+    auto observer_binding = CreateObserverBinding(&observer_ptr);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying()).Times(0);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying()).Times(0);
 
     {
       auto socket = std::make_unique<base::CancelableSyncSocket>();
@@ -433,7 +531,8 @@
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
 
       SyncWithAllThreads();
 
@@ -450,6 +549,10 @@
     EXPECT_CALL(mirroring_manager_,
                 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()));
     EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull()));
+    media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+    auto observer_binding = CreateObserverBinding(&observer_ptr);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStartPlaying()).Times(0);
+    EXPECT_CALL(GetMockObserver(&observer_binding), DidStopPlaying()).Times(0);
 
     {
       auto socket = std::make_unique<base::CancelableSyncSocket>();
@@ -460,7 +563,8 @@
           log_factory_.CreateAudioLog(
               media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER),
           &mirroring_manager_, &media_observer_, kStreamId, kRenderFrameId,
-          kRenderProcessId, Params(), kDefaultDeviceId);
+          kRenderProcessId, Params(), std::move(observer_ptr),
+          kDefaultDeviceId);
       SyncWithAllThreads();
 
       delegate.GetControllerForTesting()->OnError();
@@ -521,7 +625,16 @@
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::BindOnce(&AudioOutputDelegateTest::PlayTest, base::Unretained(this),
-                     l.QuitClosure()));
+                     l.QuitClosure(), true /* use_bound_observer */));
+  l.Run();
+}
+
+TEST_F(AudioOutputDelegateTest, PlayWithUnboundObserver) {
+  base::RunLoop l;
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&AudioOutputDelegateTest::PlayTest, base::Unretained(this),
+                     l.QuitClosure(), false /* use_bound_observer */));
   l.Run();
 }
 
diff --git a/content/browser/renderer_host/media/audio_output_stream_observer_impl.cc b/content/browser/renderer_host/media/audio_output_stream_observer_impl.cc
new file mode 100644
index 0000000..8cf2dd2
--- /dev/null
+++ b/content/browser/renderer_host/media/audio_output_stream_observer_impl.cc
@@ -0,0 +1,45 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/media/audio_output_stream_observer_impl.h"
+
+#include "content/browser/media/audio_stream_monitor.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+AudioOutputStreamObserverImpl::AudioOutputStreamObserverImpl(
+    int render_process_id,
+    int render_frame_id,
+    int stream_id)
+    : render_process_id_(render_process_id),
+      render_frame_id_(render_frame_id),
+      stream_id_(stream_id) {}
+
+AudioOutputStreamObserverImpl::~AudioOutputStreamObserverImpl() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (did_start_playing_)
+    DidStopPlaying();
+}
+
+void AudioOutputStreamObserverImpl::DidStartPlaying() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  did_start_playing_ = true;
+  AudioStreamMonitor::StartMonitoringStream(render_process_id_,
+                                            render_frame_id_, stream_id_);
+}
+void AudioOutputStreamObserverImpl::DidStopPlaying() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  AudioStreamMonitor::StopMonitoringStream(render_process_id_, render_frame_id_,
+                                           stream_id_);
+  did_start_playing_ = false;
+}
+
+void AudioOutputStreamObserverImpl::DidChangeAudibleState(bool is_audible) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  AudioStreamMonitor::UpdateStreamAudibleState(
+      render_process_id_, render_frame_id_, stream_id_, is_audible);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/media/audio_output_stream_observer_impl.h b/content/browser/renderer_host/media/audio_output_stream_observer_impl.h
new file mode 100644
index 0000000..edbb892
--- /dev/null
+++ b/content/browser/renderer_host/media/audio_output_stream_observer_impl.h
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_OUTPUT_STREAM_OBSERVER_IMPL_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_OUTPUT_STREAM_OBSERVER_IMPL_H_
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+#include "media/mojo/interfaces/audio_output_stream.mojom.h"
+
+namespace content {
+
+class CONTENT_EXPORT AudioOutputStreamObserverImpl
+    : public media::mojom::AudioOutputStreamObserver {
+ public:
+  AudioOutputStreamObserverImpl(int render_process_id,
+                                int render_frame_id,
+                                int stream_id);
+  ~AudioOutputStreamObserverImpl() override;
+
+  // media::mojom::AudioOutputStreamObserver implementation
+  void DidStartPlaying() override;
+  void DidStopPlaying() override;
+  void DidChangeAudibleState(bool is_audible) override;
+
+ private:
+  const int render_process_id_;
+  const int render_frame_id_;
+  const int stream_id_;
+  bool did_start_playing_ = false;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(AudioOutputStreamObserverImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_OUTPUT_STREAM_OBSERVER_IMPL_H_
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc
index 43f72f2..e70b72d 100644
--- a/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -18,6 +18,7 @@
 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
 #include "content/browser/renderer_host/media/audio_output_authorization_handler.h"
 #include "content/browser/renderer_host/media/audio_output_delegate_impl.h"
+#include "content/browser/renderer_host/media/audio_output_stream_observer_impl.h"
 #include "content/browser/renderer_host/media/audio_sync_reader.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/common/media/audio_messages.h"
@@ -28,6 +29,8 @@
 #include "media/audio/audio_device_description.h"
 #include "media/base/audio_bus.h"
 #include "media/base/limits.h"
+#include "media/mojo/interfaces/audio_output_stream.mojom.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 
 using media::AudioBus;
 using media::AudioManager;
@@ -275,10 +278,15 @@
   audio_log->OnCreated(stream_id, params, device_unique_id);
   media_internals->SetWebContentsTitleForAudioLogEntry(
       stream_id, render_process_id_, render_frame_id, audio_log.get());
+
+  media::mojom::AudioOutputStreamObserverPtr observer_ptr;
+  mojo::MakeStrongBinding(std::make_unique<AudioOutputStreamObserverImpl>(
+                              render_process_id_, render_frame_id, stream_id),
+                          mojo::MakeRequest(&observer_ptr));
   auto delegate = AudioOutputDelegateImpl::Create(
       this, audio_manager_, std::move(audio_log), mirroring_manager_,
       media_observer, stream_id, render_frame_id, render_process_id_, params,
-      device_unique_id);
+      std::move(observer_ptr), device_unique_id);
   if (delegate)
     delegates_.push_back(std::move(delegate));
   else
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
index f9754ab..7da6506 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
@@ -8,6 +8,7 @@
 
 #include "base/task_runner_util.h"
 #include "content/browser/renderer_host/media/audio_output_authorization_handler.h"
+#include "content/browser/renderer_host/media/audio_output_stream_observer_impl.h"
 #include "content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h"
 #include "content/public/browser/render_frame_host.h"
 #include "media/base/audio_parameters.h"
@@ -116,6 +117,10 @@
     return;
   }
 
+  int stream_id = next_stream_id_++;
+  std::unique_ptr<media::mojom::AudioOutputStreamObserver> observer =
+      base::MakeUnique<AudioOutputStreamObserverImpl>(
+          context_->GetRenderProcessId(), render_frame_id_, stream_id);
   // Since |context_| outlives |this| and |this| outlives |stream_providers_|,
   // unretained is safe.
   stream_providers_.insert(
@@ -123,9 +128,11 @@
           std::move(request),
           base::BindOnce(
               &RendererAudioOutputStreamFactoryContext::CreateDelegate,
-              base::Unretained(context_), raw_device_id, render_frame_id_),
+              base::Unretained(context_), raw_device_id, render_frame_id_,
+              stream_id),
           base::BindOnce(&RenderFrameAudioOutputStreamFactory::RemoveStream,
-                         base::Unretained(this))));
+                         base::Unretained(this)),
+          std::move(observer)));
 
   std::move(callback).Run(media::OutputDeviceStatus(status), params,
                           device_id_for_renderer);
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
index 8ae2999..0f75bdc7 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
@@ -64,6 +64,9 @@
   // The stream providers will contain the corresponding streams.
   OutputStreamProviderSet stream_providers_;
 
+  // All streams require IDs. Use a counter to generate them.
+  int next_stream_id_ = 0;
+
   base::WeakPtrFactory<RenderFrameAudioOutputStreamFactory> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderFrameAudioOutputStreamFactory);
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
index 8d9cafb..6603b1c 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
@@ -132,7 +132,9 @@
   std::unique_ptr<media::AudioOutputDelegate> CreateDelegate(
       const std::string& unique_device_id,
       int render_frame_id,
+      int stream_id,
       const media::AudioParameters& params,
+      media::mojom::AudioOutputStreamObserverPtr stream_observer,
       media::AudioOutputDelegate::EventHandler* handler) override {
     EXPECT_NE(nullptr, delegate_);
     EXPECT_NE(nullptr, delegate_event_handler_location_);
diff --git a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h
index 980f43a..5545740 100644
--- a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h
+++ b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h
@@ -11,6 +11,7 @@
 #include "content/browser/renderer_host/media/audio_output_authorization_handler.h"
 #include "content/common/content_export.h"
 #include "media/audio/audio_output_delegate.h"
+#include "media/mojo/interfaces/audio_output_stream.mojom.h"
 
 namespace media {
 class AudioParameters;
@@ -39,7 +40,9 @@
   virtual std::unique_ptr<media::AudioOutputDelegate> CreateDelegate(
       const std::string& unique_device_id,
       int render_frame_id,
+      int stream_id,
       const media::AudioParameters& params,
+      media::mojom::AudioOutputStreamObserverPtr stream_observer,
       media::AudioOutputDelegate::EventHandler* handler) = 0;
 };
 
diff --git a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.cc b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.cc
index 6f1960f..3cc07352 100644
--- a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.cc
+++ b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.cc
@@ -56,10 +56,11 @@
 RendererAudioOutputStreamFactoryContextImpl::CreateDelegate(
     const std::string& unique_device_id,
     int render_frame_id,
+    int stream_id,
     const media::AudioParameters& params,
+    media::mojom::AudioOutputStreamObserverPtr stream_observer,
     media::AudioOutputDelegate::EventHandler* handler) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  int stream_id = next_stream_id_++;
   MediaObserver* const media_observer =
       GetContentClient()->browser()->GetMediaObserver();
 
@@ -73,7 +74,8 @@
   return AudioOutputDelegateImpl::Create(
       handler, audio_manager_, std::move(audio_log),
       AudioMirroringManager::GetInstance(), media_observer, stream_id,
-      render_frame_id, render_process_id_, params, unique_device_id);
+      render_frame_id, render_process_id_, params, std::move(stream_observer),
+      unique_device_id);
 }
 
 // static
diff --git a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.h b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.h
index 12bf8a38..95e5ec5a 100644
--- a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.h
+++ b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.h
@@ -64,7 +64,9 @@
   std::unique_ptr<media::AudioOutputDelegate> CreateDelegate(
       const std::string& unique_device_id,
       int render_frame_id,
+      int stream_id,
       const media::AudioParameters& params,
+      media::mojom::AudioOutputStreamObserverPtr stream_observer,
       media::AudioOutputDelegate::EventHandler* handler) override;
 
   static bool UseMojoFactories();
@@ -77,9 +79,6 @@
   const AudioOutputAuthorizationHandler authorization_handler_;
   const int render_process_id_;
 
-  // All streams requires ids for logging, so we keep a count for that.
-  int next_stream_id_ = 0;
-
   DISALLOW_COPY_AND_ASSIGN(RendererAudioOutputStreamFactoryContextImpl);
 };
 
diff --git a/extensions/browser/preload_check.h b/extensions/browser/preload_check.h
index 7ddf4a1..8c92a23 100644
--- a/extensions/browser/preload_check.h
+++ b/extensions/browser/preload_check.h
@@ -27,7 +27,6 @@
     BLACKLISTED_ID,
     BLACKLISTED_UNKNOWN,
     DISALLOWED_BY_POLICY,
-    NPAPI_NOT_SUPPORTED,
     WEBGL_NOT_SUPPORTED,
     WINDOW_SHAPE_NOT_SUPPORTED,
   };
diff --git a/extensions/browser/requirements_checker.cc b/extensions/browser/requirements_checker.cc
index a70b043..68b9da9 100644
--- a/extensions/browser/requirements_checker.cc
+++ b/extensions/browser/requirements_checker.cc
@@ -30,11 +30,6 @@
   const RequirementsInfo& requirements =
       RequirementsInfo::GetRequirements(extension());
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-  if (requirements.npapi)
-    errors_.insert(NPAPI_NOT_SUPPORTED);
-#endif
-
 #if !defined(USE_AURA)
   if (requirements.window_shape)
     errors_.insert(WINDOW_SHAPE_NOT_SUPPORTED);
@@ -55,12 +50,6 @@
 base::string16 RequirementsChecker::GetErrorMessage() const {
   // Join the error messages into one string.
   std::vector<std::string> messages;
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-  if (errors_.count(NPAPI_NOT_SUPPORTED)) {
-    messages.push_back(
-        l10n_util::GetStringUTF8(IDS_EXTENSION_NPAPI_NOT_SUPPORTED));
-  }
-#endif
   if (errors_.count(WEBGL_NOT_SUPPORTED)) {
     messages.push_back(
         l10n_util::GetStringUTF8(IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
diff --git a/extensions/browser/requirements_checker_unittest.cc b/extensions/browser/requirements_checker_unittest.cc
index c2754322..3bd077f 100644
--- a/extensions/browser/requirements_checker_unittest.cc
+++ b/extensions/browser/requirements_checker_unittest.cc
@@ -36,14 +36,6 @@
     false;
 #endif
 
-// Whether this build supports the plugins.npapi requirement.
-const bool kSupportsNPAPI =
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-    false;
-#else
-    true;
-#endif
-
 // Returns true if a WebGL check might not fail immediately.
 bool MightSupportWebGL() {
   return content::GpuDataManager::GetInstance()->GpuAccessAllowed(nullptr);
@@ -87,10 +79,6 @@
     manifest_dict_->SetBoolean("requirements.window.shape", true);
   }
 
-  void RequireNPAPI() {
-    manifest_dict_->SetBoolean("requirements.plugins.npapi", true);
-  }
-
   void RequireFeature(const char feature[]) {
     if (!manifest_dict_->HasKey(kFeaturesKey))
       manifest_dict_->Set(kFeaturesKey, std::make_unique<base::ListValue>());
@@ -120,8 +108,7 @@
 TEST_F(RequirementsCheckerTest, RequirementsSuccess) {
   if (kSupportsWindowShape)
     RequireWindowShape();
-  if (kSupportsNPAPI)
-    RequireNPAPI();
+
   RequireFeature(kFeatureCSS3d);
 
   CreateExtension();
@@ -138,10 +125,6 @@
     RequireWindowShape();
     expected_errors++;
   }
-  if (!kSupportsNPAPI) {
-    RequireNPAPI();
-    expected_errors++;
-  }
   if (!MightSupportWebGL()) {
     RequireFeature(kFeatureWebGL);
     expected_errors++;
diff --git a/extensions/common/common_manifest_handlers.cc b/extensions/common/common_manifest_handlers.cc
index 7abe61f..8c48684 100644
--- a/extensions/common/common_manifest_handlers.cc
+++ b/extensions/common/common_manifest_handlers.cc
@@ -64,7 +64,7 @@
   (new OAuth2ManifestHandler)->Register();
   (new OfflineEnabledHandler)->Register();
   (new PluginsHandler)->Register();
-  (new RequirementsHandler)->Register();  // Depends on plugins.
+  (new RequirementsHandler)->Register();
   (new SandboxedPageHandler)->Register();
   (new SharedModuleHandler)->Register();
   (new SocketsManifestHandler)->Register();
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index 5219c7b6..add3746 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -739,6 +739,7 @@
     "An extension cannot override more than one page.";
 const char kNoWildCardsInPaths[] =
   "Wildcards are not allowed in extent URL pattern paths.";
+const char kNPAPIPluginsNotSupported[] = "NPAPI plugins are not supported.";
 const char kOneUISurfaceOnly[] =
     "Only one of 'browser_action', 'page_action', and 'app' can be specified.";
 const char kPermissionMustBeOptional[] =
@@ -749,6 +750,8 @@
     "Permission '*' cannot be specified in the manifest.";
 const char kPermissionUnknownOrMalformed[] =
     "Permission '*' is unknown or URL pattern is malformed.";
+const char kPluginsRequirementDeprecated[] =
+    "The \"plugins\" requirement is deprecated.";
 const char kReservedMessageFound[] =
     "Reserved key * found in message catalog.";
 const char kRulesFileIsInvalid[] =
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index bc43887a..cc6c6eb 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -495,11 +495,13 @@
 extern const char kMissingFile[];
 extern const char kMultipleOverrides[];
 extern const char kNoWildCardsInPaths[];
+extern const char kNPAPIPluginsNotSupported[];
 extern const char kOneUISurfaceOnly[];
 extern const char kPermissionMustBeOptional[];
 extern const char kPermissionNotAllowed[];
 extern const char kPermissionNotAllowedInManifest[];
 extern const char kPermissionUnknownOrMalformed[];
+extern const char kPluginsRequirementDeprecated[];
 extern const char kReservedMessageFound[];
 extern const char kRulesFileIsInvalid[];
 extern const char kUnrecognizedManifestKey[];
diff --git a/extensions/common/manifest_handlers/requirements_info.cc b/extensions/common/manifest_handlers/requirements_info.cc
index 0acbf7b..4b97d17 100644
--- a/extensions/common/manifest_handlers/requirements_info.cc
+++ b/extensions/common/manifest_handlers/requirements_info.cc
@@ -18,15 +18,7 @@
 namespace errors = manifest_errors;
 
 RequirementsInfo::RequirementsInfo(const Manifest* manifest)
-    : webgl(false),
-      npapi(false),
-      window_shape(false) {
-  // Before parsing requirements from the manifest, automatically default the
-  // NPAPI plugin requirement based on whether it includes NPAPI plugins.
-  const base::ListValue* list_value = NULL;
-  npapi = manifest->GetList(keys::kPlugins, &list_value) &&
-          !list_value->empty();
-}
+    : webgl(false), window_shape(false) {}
 
 RequirementsInfo::~RequirementsInfo() {
 }
@@ -49,10 +41,6 @@
 RequirementsHandler::~RequirementsHandler() {
 }
 
-const std::vector<std::string> RequirementsHandler::PrerequisiteKeys() const {
-  return SingleKey(keys::kPlugins);
-}
-
 const std::vector<std::string> RequirementsHandler::Keys() const {
   return SingleKey(keys::kRequirements);
 }
@@ -87,22 +75,17 @@
       return false;
     }
 
+    // The plugins requirement is deprecated. Raise an install warning. If the
+    // extension explicitly requires npapi plugins, raise an error.
     if (iter.key() == "plugins") {
-      for (base::DictionaryValue::Iterator plugin_iter(*requirement_value);
-           !plugin_iter.IsAtEnd(); plugin_iter.Advance()) {
-        bool plugin_required = false;
-        if (!plugin_iter.value().GetAsBoolean(&plugin_required)) {
-          *error = ErrorUtils::FormatErrorMessageUTF16(
-              errors::kInvalidRequirement, iter.key());
-          return false;
-        }
-        if (plugin_iter.key() == "npapi") {
-          requirements->npapi = plugin_required;
-        } else {
-          *error = ErrorUtils::FormatErrorMessageUTF16(
-              errors::kInvalidRequirement, iter.key());
-          return false;
-        }
+      extension->AddInstallWarning(
+          InstallWarning(errors::kPluginsRequirementDeprecated));
+      bool requires_npapi = false;
+      if (requirement_value->GetBooleanWithoutPathExpansion("npapi",
+                                                            &requires_npapi) &&
+          requires_npapi) {
+        *error = base::ASCIIToUTF16(errors::kNPAPIPluginsNotSupported);
+        return false;
       }
     } else if (iter.key() == "3D") {
       const base::ListValue* features = NULL;
diff --git a/extensions/common/manifest_handlers/requirements_info.h b/extensions/common/manifest_handlers/requirements_info.h
index 64d107cd..2e4173e 100644
--- a/extensions/common/manifest_handlers/requirements_info.h
+++ b/extensions/common/manifest_handlers/requirements_info.h
@@ -21,7 +21,6 @@
   ~RequirementsInfo() override;
 
   bool webgl;
-  bool npapi;
   bool window_shape;
 
   static const RequirementsInfo& GetRequirements(const Extension* extension);
@@ -37,8 +36,6 @@
 
   bool AlwaysParseForType(Manifest::Type type) const override;
 
-  const std::vector<std::string> PrerequisiteKeys() const override;
-
  private:
   const std::vector<std::string> Keys() const override;
 
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index f3c9078c..4e12af83 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -201,19 +201,8 @@
   const base::CommandLine& command_line =
       *(base::CommandLine::ForCurrentProcess());
 
-  std::unique_ptr<IPCMessageSender> ipc_message_sender =
-      IPCMessageSender::CreateMainThreadIPCMessageSender();
-  if (base::FeatureList::IsEnabled(features::kNativeCrxBindings)) {
-    // This Unretained is safe because the IPCMessageSender is guaranteed to
-    // outlive the bindings system.
-    auto system = std::make_unique<NativeExtensionBindingsSystem>(
-        std::move(ipc_message_sender));
-    delegate_->InitializeBindingsSystem(this, system->api_system());
-    bindings_system_ = std::move(system);
-  } else {
-    bindings_system_ = std::make_unique<JsExtensionBindingsSystem>(
-        &source_map_, std::move(ipc_message_sender));
-  }
+  bindings_system_ = CreateBindingsSystem(
+      IPCMessageSender::CreateMainThreadIPCMessageSender());
 
   set_idle_notifications_ =
       command_line.HasSwitch(switches::kExtensionProcess) ||
@@ -417,8 +406,13 @@
   context->set_service_worker_scope(service_worker_scope);
 
   if (ExtensionsClient::Get()->ExtensionAPIEnabledInExtensionServiceWorkers()) {
-    WorkerThreadDispatcher::Get()->AddWorkerData(service_worker_version_id,
-                                                 context, &source_map_);
+    WorkerThreadDispatcher* worker_dispatcher = WorkerThreadDispatcher::Get();
+    std::unique_ptr<IPCMessageSender> ipc_sender =
+        IPCMessageSender::CreateWorkerThreadIPCMessageSender(
+            worker_dispatcher, service_worker_version_id);
+    worker_dispatcher->AddWorkerData(
+        service_worker_version_id, context,
+        CreateBindingsSystem(std::move(ipc_sender)));
 
     // TODO(lazyboy): Make sure accessing |source_map_| in worker thread is
     // safe.
@@ -1449,4 +1443,19 @@
   }
 }
 
+std::unique_ptr<ExtensionBindingsSystem> Dispatcher::CreateBindingsSystem(
+    std::unique_ptr<IPCMessageSender> ipc_sender) {
+  std::unique_ptr<ExtensionBindingsSystem> bindings_system;
+  if (base::FeatureList::IsEnabled(features::kNativeCrxBindings)) {
+    auto system =
+        std::make_unique<NativeExtensionBindingsSystem>(std::move(ipc_sender));
+    delegate_->InitializeBindingsSystem(this, system->api_system());
+    bindings_system = std::move(system);
+  } else {
+    bindings_system = std::make_unique<JsExtensionBindingsSystem>(
+        &source_map_, std::move(ipc_sender));
+  }
+  return bindings_system;
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h
index d91b814..e0a75d6 100644
--- a/extensions/renderer/dispatcher.h
+++ b/extensions/renderer/dispatcher.h
@@ -55,6 +55,7 @@
 class ContentWatcher;
 class DispatcherDelegate;
 class ExtensionBindingsSystem;
+class IPCMessageSender;
 class ScriptContext;
 class ScriptInjectionManager;
 struct EventFilteringInfo;
@@ -246,6 +247,12 @@
   // |context|.
   void RequireGuestViewModules(ScriptContext* context);
 
+  // Creates the ExtensionBindingsSystem. Note: this may be called on any
+  // thread, and thus cannot mutate any state or rely on state which can be
+  // mutated in Dispatcher.
+  std::unique_ptr<ExtensionBindingsSystem> CreateBindingsSystem(
+      std::unique_ptr<IPCMessageSender> ipc_sender);
+
   // The delegate for this dispatcher to handle embedder-specific logic.
   std::unique_ptr<DispatcherDelegate> delegate_;
 
diff --git a/extensions/renderer/worker_thread_dispatcher.cc b/extensions/renderer/worker_thread_dispatcher.cc
index 563251a..6159370 100644
--- a/extensions/renderer/worker_thread_dispatcher.cc
+++ b/extensions/renderer/worker_thread_dispatcher.cc
@@ -17,7 +17,7 @@
 #include "extensions/common/extension_messages.h"
 #include "extensions/renderer/dispatcher.h"
 #include "extensions/renderer/extension_bindings_system.h"
-#include "extensions/renderer/ipc_message_sender.h"
+#include "extensions/renderer/extensions_renderer_client.h"
 #include "extensions/renderer/js_extension_bindings_system.h"
 #include "extensions/renderer/native_extension_bindings_system.h"
 #include "extensions/renderer/service_worker_data.h"
@@ -148,26 +148,9 @@
 void WorkerThreadDispatcher::AddWorkerData(
     int64_t service_worker_version_id,
     ScriptContext* context,
-    ResourceBundleSourceMap* source_map) {
+    std::unique_ptr<ExtensionBindingsSystem> bindings_system) {
   ServiceWorkerData* data = g_data_tls.Pointer()->Get();
   if (!data) {
-    std::unique_ptr<ExtensionBindingsSystem> bindings_system;
-    // QUESTION(lazyboy): Why is passing the WorkerThreadDispatcher to the
-    // IPCMessageSender (previously the ServiceWorkerRequestSender) safe? The
-    // WorkerThreadDispatcher is a process-wide singleton, but the
-    // IPCMessageSender is per-context (thus potentially many per process).
-    std::unique_ptr<IPCMessageSender> ipc_message_sender =
-        IPCMessageSender::CreateWorkerThreadIPCMessageSender(
-            this, service_worker_version_id);
-    if (base::FeatureList::IsEnabled(features::kNativeCrxBindings)) {
-      // The Unretained below is safe since the IPC message sender outlives the
-      // bindings system.
-      bindings_system = std::make_unique<NativeExtensionBindingsSystem>(
-          std::move(ipc_message_sender));
-    } else {
-      bindings_system = std::make_unique<JsExtensionBindingsSystem>(
-          source_map, std::move(ipc_message_sender));
-    }
     ServiceWorkerData* new_data = new ServiceWorkerData(
         service_worker_version_id, context, std::move(bindings_system));
     g_data_tls.Pointer()->Set(new_data);
diff --git a/extensions/renderer/worker_thread_dispatcher.h b/extensions/renderer/worker_thread_dispatcher.h
index 5372dbe3..efd5573 100644
--- a/extensions/renderer/worker_thread_dispatcher.h
+++ b/extensions/renderer/worker_thread_dispatcher.h
@@ -23,7 +23,6 @@
 struct ExtensionMsg_DispatchEvent_Params;
 namespace extensions {
 class ExtensionBindingsSystem;
-class ResourceBundleSourceMap;
 class ScriptContext;
 class V8SchemaRegistry;
 
@@ -52,7 +51,7 @@
 
   void AddWorkerData(int64_t service_worker_version_id,
                      ScriptContext* context,
-                     ResourceBundleSourceMap* source_map);
+                     std::unique_ptr<ExtensionBindingsSystem> bindings_system);
   void RemoveWorkerData(int64_t service_worker_version_id);
 
   EventBookkeeper* event_bookkeeper() { return &event_bookkeeper_; }
diff --git a/extensions/strings/extensions_strings.grd b/extensions/strings/extensions_strings.grd
index 7ec32bab..88c0a3f 100644
--- a/extensions/strings/extensions_strings.grd
+++ b/extensions/strings/extensions_strings.grd
@@ -311,11 +311,6 @@
       <message name="IDS_EXTENSION_INSTALL_PROCESS_CRASHED" desc="Error message in case package fails to install because a utility process crashed.">
         Could not install package because a utility process crashed. Try restarting Chrome and trying again.
       </message>
-      <if expr="is_posix and not is_macosx">
-        <message name="IDS_EXTENSION_NPAPI_NOT_SUPPORTED" desc="Error message when an extension has a requirement for plugins that the system does not support.">
-          NPAPI plugins are not supported.
-        </message>
-      </if>
       <message name="IDS_EXTENSION_PACKAGE_ERROR_CODE" desc="Error message in cases where we fail to install the extension because the crx file is invalid. For example, because the crx header or signature is invalid.">
         Package is invalid: '<ph name="ERROR_CODE">$1<ex>error</ex></ph>'.
       </message>
diff --git a/ios/chrome/browser/ui/commands/BUILD.gn b/ios/chrome/browser/ui/commands/BUILD.gn
index 9a72824..a920fca 100644
--- a/ios/chrome/browser/ui/commands/BUILD.gn
+++ b/ios/chrome/browser/ui/commands/BUILD.gn
@@ -33,6 +33,7 @@
     "snackbar_commands.h",
     "start_voice_search_command.h",
     "start_voice_search_command.mm",
+    "toolbar_commands.h",
     "tools_menu_commands.h",
   ]
   deps = [
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h
index 589b8bb4..6384ab7a 100644
--- a/ios/chrome/browser/ui/commands/browser_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -13,6 +13,7 @@
 #import "ios/chrome/browser/ui/commands/page_info_commands.h"
 #import "ios/chrome/browser/ui/commands/qr_scanner_commands.h"
 #import "ios/chrome/browser/ui/commands/snackbar_commands.h"
+#import "ios/chrome/browser/ui/commands/toolbar_commands.h"
 #import "ios/chrome/browser/ui/commands/tools_menu_commands.h"
 
 @class OpenNewTabCommand;
@@ -27,6 +28,7 @@
                           QRScannerCommands,
                           SnackbarCommands,
                           TabHistoryPopupCommands,
+                          ToolbarCommands,
                           ToolsMenuCommands>
 
 // Closes the current tab.
diff --git a/ios/chrome/browser/ui/commands/toolbar_commands.h b/ios/chrome/browser/ui/commands/toolbar_commands.h
new file mode 100644
index 0000000..647a77f4
--- /dev/null
+++ b/ios/chrome/browser/ui/commands/toolbar_commands.h
@@ -0,0 +1,14 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_COMMANDS_TOOLBAR_COMMANDS_H_
+#define IOS_CHROME_BROWSER_UI_COMMANDS_TOOLBAR_COMMANDS_H_
+
+// Protocol that describes the commands that trigger Toolbar UI changes.
+@protocol ToolbarCommands
+// Contracts the Toolbar to its regular form.
+- (void)contractToolbar;
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_COMMANDS_TOOLBAR_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
index f9003b38..cce8e88 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
@@ -433,6 +433,9 @@
   [buttonConstraints
       addObject:[self.contractButton.widthAnchor
                     constraintEqualToConstant:kToolbarButtonWidth]];
+  [self.contractButton addTarget:self.dispatcher
+                          action:@selector(contractToolbar)
+                forControlEvents:UIControlEventTouchUpInside];
 
   // Add buttons to button updater.
   self.buttonUpdater.backButton = self.backButton;
diff --git a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
index 227ae3a..120c0484 100644
--- a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h"
 
+#import "ios/chrome/browser/ui/commands/toolbar_commands.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_updater.h"
 #import "ios/chrome/browser/ui/toolbar/omnibox_focuser.h"
 #import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
@@ -38,6 +39,9 @@
     _toolsMenuCoordinator.dispatcher = dispatcher;
     _toolsMenuCoordinator.configurationProvider = configurationProvider;
 
+    [dispatcher startDispatchingToTarget:self
+                             forProtocol:@protocol(ToolbarCommands)];
+
     NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
     [defaultCenter addObserver:self
                       selector:@selector(toolsMenuWillShowNotification:)
@@ -274,4 +278,10 @@
   [self.toolbarController setToolsMenuIsVisibleForToolsMenuButton:NO];
 }
 
+#pragma mark - Toolbar Commands
+
+- (void)contractToolbar {
+  [self cancelOmniboxEdit];
+}
+
 @end
diff --git a/ios/web/web_state/navigation_and_load_callbacks_inttest.mm b/ios/web/web_state/navigation_and_load_callbacks_inttest.mm
index a2861a1..ac1dcfc 100644
--- a/ios/web/web_state/navigation_and_load_callbacks_inttest.mm
+++ b/ios/web/web_state/navigation_and_load_callbacks_inttest.mm
@@ -421,6 +421,34 @@
   LoadUrl(url);
 }
 
+// Tests that if web usage is already enabled, enabling it again would not cause
+// any page loads (related to restoring cached session). This is a regression
+// test for crbug.com/781916.
+TEST_F(NavigationAndLoadCallbacksTest, EnableWebUsageTwice) {
+  const GURL url = HttpServer::MakeUrl("http://chromium.test");
+  std::map<GURL, std::string> responses;
+  responses[url] = "Chromium Test";
+  web::test::SetUpSimpleHttpServer(responses);
+
+  // Only expect one set of load events from the first LoadUrl(), not subsequent
+  // SetWebUsageEnabled(true) calls. Web usage is already enabled, so the
+  // subsequent calls should be noops.
+  NavigationContext* context = nullptr;
+  EXPECT_CALL(observer_, DidStartLoading(web_state()));
+  EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true));
+  EXPECT_CALL(observer_, DidStartNavigation(web_state(), _))
+      .WillOnce(VerifyNewPageStartedContext(web_state(), url, &context));
+  EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true))
+      .WillOnce(Return(true));
+  EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _))
+      .WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context));
+  EXPECT_CALL(observer_, DidStopLoading(web_state()));
+
+  LoadUrl(url);
+  web_state()->SetWebUsageEnabled(true);
+  web_state()->SetWebUsageEnabled(true);
+}
+
 // Tests failed navigation to a new page.
 TEST_F(NavigationAndLoadCallbacksTest, FailedNavigation) {
   const GURL url = HttpServer::MakeUrl("unsupported://chromium.test");
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index e617b6e..b5a4ede 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -551,8 +551,10 @@
   // the newly created WKWebView.
   // TODO(crbug.com/557963): don't destroy WKWebView to clear browser data.
   if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
-    if (enabled && cached_session_storage_) {
-      RestoreSessionStorage(cached_session_storage_.get());
+    if (enabled) {
+      if (cached_session_storage_) {
+        RestoreSessionStorage(cached_session_storage_.get());
+      }
       cached_session_storage_.reset();
     } else {
       cached_session_storage_.reset(BuildSessionStorage());
diff --git a/mash/quick_launch/manifest.json b/mash/quick_launch/manifest.json
index 8dfbf4a..ac63cbe 100644
--- a/mash/quick_launch/manifest.json
+++ b/mash/quick_launch/manifest.json
@@ -7,7 +7,10 @@
       "provides": { "mash:launchable": [ "mash::mojom::Launchable" ] },
       "requires": {
         "*": [ "app", "mash:launchable" ],
-        "catalog": [ "catalog:catalog" ]
+        "catalog": [
+          "catalog:catalog",
+          "directory"
+        ]
       }
     }
   }
diff --git a/media/base/android/media_codec_bridge_impl.cc b/media/base/android/media_codec_bridge_impl.cc
index 1a74f5c..a1d0df0 100644
--- a/media/base/android/media_codec_bridge_impl.cc
+++ b/media/base/android/media_codec_bridge_impl.cc
@@ -240,6 +240,8 @@
     const JavaRef<jobject>& media_crypto,
     const std::vector<uint8_t>& csd0,
     const std::vector<uint8_t>& csd1,
+    const VideoColorSpace& color_space,
+    const base::Optional<HDRMetadata>& hdr_metadata,
     bool allow_adaptive_playback) {
   if (!MediaCodecUtil::IsMediaCodecAvailable())
     return nullptr;
diff --git a/media/base/android/media_codec_bridge_impl.h b/media/base/android/media_codec_bridge_impl.h
index f1bf404..88a6fa17 100644
--- a/media/base/android/media_codec_bridge_impl.h
+++ b/media/base/android/media_codec_bridge_impl.h
@@ -22,6 +22,9 @@
 
 namespace media {
 
+class VideoColorSpace;
+struct HDRMetadata;
+
 // A bridge to a Java MediaCodec.
 class MEDIA_EXPORT MediaCodecBridgeImpl : public MediaCodecBridge {
  public:
@@ -38,6 +41,8 @@
       // Codec specific data. See MediaCodec docs.
       const std::vector<uint8_t>& csd0,
       const std::vector<uint8_t>& csd1,
+      const VideoColorSpace& color_space,
+      const base::Optional<HDRMetadata>& hdr_metadata,
       // Should adaptive playback be allowed if supported.
       bool allow_adaptive_playback = true);
 
diff --git a/media/base/android/media_codec_bridge_impl_unittest.cc b/media/base/android/media_codec_bridge_impl_unittest.cc
index 27978cb..afc3397 100644
--- a/media/base/android/media_codec_bridge_impl_unittest.cc
+++ b/media/base/android/media_codec_bridge_impl_unittest.cc
@@ -293,7 +293,8 @@
 
   MediaCodecBridgeImpl::CreateVideoDecoder(
       kCodecH264, CodecType::kAny, gfx::Size(640, 480), nullptr, nullptr,
-      std::vector<uint8_t>(), std::vector<uint8_t>());
+      std::vector<uint8_t>(), std::vector<uint8_t>(), VideoColorSpace(),
+      HDRMetadata());
 }
 
 TEST(MediaCodecBridgeTest, DoNormal) {
@@ -402,7 +403,8 @@
   std::unique_ptr<MediaCodecBridge> media_codec(
       MediaCodecBridgeImpl::CreateVideoDecoder(
           kCodecVP8, CodecType::kAny, gfx::Size(320, 240), nullptr, nullptr,
-          std::vector<uint8_t>(), std::vector<uint8_t>()));
+          std::vector<uint8_t>(), std::vector<uint8_t>(), VideoColorSpace(),
+          HDRMetadata()));
   ASSERT_THAT(media_codec, NotNull());
   scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("vp8-I-frame-320x240");
   DecodeMediaFrame(media_codec.get(), buffer->data(), buffer->data_size(),
@@ -429,11 +431,11 @@
   EXPECT_THAT(MediaCodecBridgeImpl::CreateAudioDecoder(
                   NewAudioConfig(kUnknownAudioCodec), nullptr),
               IsNull());
-  EXPECT_THAT(
-      MediaCodecBridgeImpl::CreateVideoDecoder(
-          kUnknownVideoCodec, CodecType::kAny, gfx::Size(320, 240), nullptr,
-          nullptr, std::vector<uint8_t>(), std::vector<uint8_t>()),
-      IsNull());
+  EXPECT_THAT(MediaCodecBridgeImpl::CreateVideoDecoder(
+                  kUnknownVideoCodec, CodecType::kAny, gfx::Size(320, 240),
+                  nullptr, nullptr, std::vector<uint8_t>(),
+                  std::vector<uint8_t>(), VideoColorSpace(), HDRMetadata()),
+              IsNull());
 }
 
 // Test MediaCodec HW H264 encoding and validate the format of encoded frames.
diff --git a/media/base/android/mock_media_codec_bridge.cc b/media/base/android/mock_media_codec_bridge.cc
index 6ed1b46..e459075 100644
--- a/media/base/android/mock_media_codec_bridge.cc
+++ b/media/base/android/mock_media_codec_bridge.cc
@@ -54,6 +54,8 @@
     const base::android::JavaRef<jobject>& media_crypto,
     const std::vector<uint8_t>& csd0,
     const std::vector<uint8_t>& csd1,
+    const VideoColorSpace& color_space,
+    const base::Optional<HDRMetadata>& hdr_metadata,
     bool allow_adaptive_playback) {
   return base::MakeUnique<MockMediaCodecBridge>();
 }
diff --git a/media/base/android/mock_media_codec_bridge.h b/media/base/android/mock_media_codec_bridge.h
index c7bd5c9c..2fbc8f4 100644
--- a/media/base/android/mock_media_codec_bridge.h
+++ b/media/base/android/mock_media_codec_bridge.h
@@ -8,6 +8,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "media/base/android/media_codec_bridge.h"
 #include "media/base/android/test_destruction_observable.h"
+#include "media/base/hdr_metadata.h"
 #include "media/base/video_codecs.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -85,6 +86,8 @@
       const base::android::JavaRef<jobject>& media_crypto,
       const std::vector<uint8_t>& csd0,
       const std::vector<uint8_t>& csd1,
+      const VideoColorSpace& color_space,
+      const base::Optional<HDRMetadata>& hdr_metadata,
       bool allow_adaptive_playback);
 
  private:
diff --git a/media/base/ipc/media_param_traits_macros.h b/media/base/ipc/media_param_traits_macros.h
index 47c2713..9eeaebc 100644
--- a/media/base/ipc/media_param_traits_macros.h
+++ b/media/base/ipc/media_param_traits_macros.h
@@ -19,6 +19,7 @@
 #include "media/base/demuxer_stream.h"
 #include "media/base/eme_constants.h"
 #include "media/base/encryption_scheme.h"
+#include "media/base/hdr_metadata.h"
 #include "media/base/media_log_event.h"
 #include "media/base/output_device_info.h"
 #include "media/base/overlay_info.h"
@@ -159,6 +160,21 @@
   IPC_STRUCT_TRAITS_MEMBER(range)
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_TRAITS_BEGIN(media::MasteringMetadata)
+  IPC_STRUCT_TRAITS_MEMBER(primary_r)
+  IPC_STRUCT_TRAITS_MEMBER(primary_g)
+  IPC_STRUCT_TRAITS_MEMBER(primary_b)
+  IPC_STRUCT_TRAITS_MEMBER(white_point)
+  IPC_STRUCT_TRAITS_MEMBER(luminance_max)
+  IPC_STRUCT_TRAITS_MEMBER(luminance_min)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::HDRMetadata)
+  IPC_STRUCT_TRAITS_MEMBER(mastering_metadata)
+  IPC_STRUCT_TRAITS_MEMBER(max_content_light_level)
+  IPC_STRUCT_TRAITS_MEMBER(max_frame_average_light_level)
+IPC_STRUCT_TRAITS_END()
+
 IPC_STRUCT_TRAITS_BEGIN(media::OverlayInfo)
   IPC_STRUCT_TRAITS_MEMBER(surface_id)
   IPC_STRUCT_TRAITS_MEMBER(routing_token)
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 53bc1bf8..22331c9b 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -334,6 +334,7 @@
   vda_config.initial_expected_coded_size = config_.coded_size();
   vda_config.container_color_space = config_.color_space_info();
   vda_config.target_color_space = target_color_space_;
+  vda_config.hdr_metadata = config_.hdr_metadata();
 
 #if defined(OS_ANDROID) && BUILDFLAG(USE_PROPRIETARY_CODECS)
   // We pass the SPS and PPS on Android because it lets us initialize
diff --git a/media/gpu/android/android_video_decode_accelerator.cc b/media/gpu/android/android_video_decode_accelerator.cc
index 54875a9..3312b14 100644
--- a/media/gpu/android/android_video_decode_accelerator.cc
+++ b/media/gpu/android/android_video_decode_accelerator.cc
@@ -321,6 +321,9 @@
     codec_config_->csd1 = config.pps;
   }
 
+  codec_config_->container_color_space = config.container_color_space;
+  codec_config_->hdr_metadata = config.hdr_metadata;
+
   // Only use MediaCodec for VP8/9 if it's likely backed by hardware
   // or if the stream is encrypted.
   if (IsMediaCodecSoftwareDecodingForbidden() &&
diff --git a/media/gpu/android/avda_codec_allocator.cc b/media/gpu/android/avda_codec_allocator.cc
index 9942a61..f724da7a 100644
--- a/media/gpu/android/avda_codec_allocator.cc
+++ b/media/gpu/android/avda_codec_allocator.cc
@@ -62,7 +62,8 @@
       codec_config->codec, codec_type,
       codec_config->initial_expected_coded_size,
       codec_config->surface_bundle->GetJavaSurface(), media_crypto,
-      codec_config->csd0, codec_config->csd1, true));
+      codec_config->csd0, codec_config->csd1,
+      codec_config->container_color_space, codec_config->hdr_metadata, true));
 
   return codec;
 }
diff --git a/media/gpu/android/avda_codec_allocator.h b/media/gpu/android/avda_codec_allocator.h
index fc68449..e28efe54 100644
--- a/media/gpu/android/avda_codec_allocator.h
+++ b/media/gpu/android/avda_codec_allocator.h
@@ -73,6 +73,11 @@
   std::vector<uint8_t> csd0;
   std::vector<uint8_t> csd1;
 
+  // VP9 HDR metadata is only embedded in the container
+  // HDR10 meta data is embedded in the video stream
+  VideoColorSpace container_color_space;
+  base::Optional<HDRMetadata> hdr_metadata;
+
  protected:
   friend class base::RefCountedThreadSafe<CodecConfig>;
   virtual ~CodecConfig();
@@ -127,6 +132,8 @@
           const base::android::JavaRef<jobject>& media_crypto,
           const std::vector<uint8_t>& csd0,
           const std::vector<uint8_t>& csd1,
+          const VideoColorSpace& color_space,
+          const base::Optional<HDRMetadata>& hdr_metadata,
           bool allow_adaptive_playback)>;
 
   // Make sure the construction threads are started for |client|.  If the
diff --git a/media/gpu/ipc/common/media_param_traits_macros.h b/media/gpu/ipc/common/media_param_traits_macros.h
index 409e5a2..22d0b7eb 100644
--- a/media/gpu/ipc/common/media_param_traits_macros.h
+++ b/media/gpu/ipc/common/media_param_traits_macros.h
@@ -29,6 +29,7 @@
   IPC_STRUCT_TRAITS_MEMBER(pps)
   IPC_STRUCT_TRAITS_MEMBER(container_color_space)
   IPC_STRUCT_TRAITS_MEMBER(target_color_space)
+  IPC_STRUCT_TRAITS_MEMBER(hdr_metadata)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(media::CreateVideoEncoderParams)
diff --git a/media/mojo/interfaces/audio_output_stream.mojom b/media/mojo/interfaces/audio_output_stream.mojom
index 57d88a2..236ec43c 100644
--- a/media/mojo/interfaces/audio_output_stream.mojom
+++ b/media/mojo/interfaces/audio_output_stream.mojom
@@ -42,3 +42,27 @@
   Acquire(AudioOutputStream& output_stream, AudioOutputStreamClient client, AudioParameters params)
   => (handle<shared_buffer> shared_buffer, handle socket_descriptor);
 };
+
+// An AudioOutputStreamObserver gets notifications about events related to an
+// AudioOutputStream. DidStartPlaying() is invoked when the stream starts
+// playing and it is eventually followed by a DidStopPlaying() call. A stream
+// may start playing again after being stopped.
+//
+// Note: It is possible that DidStopPlaying() is not called in shutdown
+// situations.
+interface AudioOutputStreamObserver {
+  // This notification indicates that the stream started playing. The stream
+  // should be considered non-audible until a DidChangeAudibleState() call says
+  // otherwise.
+  DidStartPlaying();
+
+  // This notification indicates that the stream stopped playing. The stream
+  // should be considered no longer audible at this time; no further
+  // audible-state change notifications will be issued.
+  DidStopPlaying();
+
+  // This notification carries the latest value of the audible state of the
+  // stream. Multiple instances of this notification may occur after
+  // DidStartPlaying() and before DidStopPlaying().
+  DidChangeAudibleState(bool is_audible);
+};
diff --git a/media/mojo/services/mojo_audio_output_stream_provider.cc b/media/mojo/services/mojo_audio_output_stream_provider.cc
index e86be275..58048d1 100644
--- a/media/mojo/services/mojo_audio_output_stream_provider.cc
+++ b/media/mojo/services/mojo_audio_output_stream_provider.cc
@@ -11,10 +11,13 @@
 MojoAudioOutputStreamProvider::MojoAudioOutputStreamProvider(
     mojom::AudioOutputStreamProviderRequest request,
     CreateDelegateCallback create_delegate_callback,
-    DeleterCallback deleter_callback)
+    DeleterCallback deleter_callback,
+    std::unique_ptr<media::mojom::AudioOutputStreamObserver> observer)
     : binding_(this, std::move(request)),
       create_delegate_callback_(std::move(create_delegate_callback)),
-      deleter_callback_(std::move(deleter_callback)) {
+      deleter_callback_(std::move(deleter_callback)),
+      observer_(std::move(observer)),
+      observer_binding_(observer_.get()) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Unretained is safe since |this| owns |binding_|.
   binding_.set_connection_error_handler(base::Bind(
@@ -36,17 +39,20 @@
   if (audio_output_) {
     LOG(ERROR) << "Output acquired twice.";
     binding_.Unbind();
+    observer_binding_.Unbind();
     std::move(deleter_callback_).Run(this);  // deletes |this|.
     return;
   }
 
+  mojom::AudioOutputStreamObserverPtr observer_ptr;
+  observer_binding_.Bind(mojo::MakeRequest(&observer_ptr));
   // Unretained is safe since |this| owns |audio_output_|.
-  audio_output_.emplace(
-      std::move(stream_request), std::move(client),
-      base::BindOnce(std::move(create_delegate_callback_), params),
-      std::move(callback),
-      base::BindOnce(&MojoAudioOutputStreamProvider::OnError,
-                     base::Unretained(this)));
+  audio_output_.emplace(std::move(stream_request), std::move(client),
+                        base::BindOnce(std::move(create_delegate_callback_),
+                                       params, std::move(observer_ptr)),
+                        std::move(callback),
+                        base::BindOnce(&MojoAudioOutputStreamProvider::OnError,
+                                       base::Unretained(this)));
 }
 
 void MojoAudioOutputStreamProvider::OnError() {
diff --git a/media/mojo/services/mojo_audio_output_stream_provider.h b/media/mojo/services/mojo_audio_output_stream_provider.h
index 0be8131a..2c0055c 100644
--- a/media/mojo/services/mojo_audio_output_stream_provider.h
+++ b/media/mojo/services/mojo_audio_output_stream_provider.h
@@ -24,6 +24,7 @@
   using CreateDelegateCallback =
       base::OnceCallback<std::unique_ptr<AudioOutputDelegate>(
           const AudioParameters& params,
+          mojom::AudioOutputStreamObserverPtr observer,
           AudioOutputDelegate::EventHandler*)>;
   using DeleterCallback = base::OnceCallback<void(AudioOutputStreamProvider*)>;
 
@@ -31,9 +32,11 @@
   // AudioOutput when it's initialized and |deleter_callback| is called when
   // this class should be removed (stream ended/error). |deleter_callback| is
   // required to destroy |this| synchronously.
-  MojoAudioOutputStreamProvider(mojom::AudioOutputStreamProviderRequest request,
-                                CreateDelegateCallback create_delegate_callback,
-                                DeleterCallback deleter_callback);
+  MojoAudioOutputStreamProvider(
+      mojom::AudioOutputStreamProviderRequest request,
+      CreateDelegateCallback create_delegate_callback,
+      DeleterCallback deleter_callback,
+      std::unique_ptr<mojom::AudioOutputStreamObserver> observer);
 
   ~MojoAudioOutputStreamProvider() override;
 
@@ -53,6 +56,8 @@
   mojo::Binding<AudioOutputStreamProvider> binding_;
   CreateDelegateCallback create_delegate_callback_;
   DeleterCallback deleter_callback_;
+  std::unique_ptr<mojom::AudioOutputStreamObserver> observer_;
+  mojo::Binding<mojom::AudioOutputStreamObserver> observer_binding_;
 
   DISALLOW_COPY_AND_ASSIGN(MojoAudioOutputStreamProvider);
 };
diff --git a/media/test/data/README b/media/test/data/README
index c404921..dfcafef 100644
--- a/media/test/data/README
+++ b/media/test/data/README
@@ -200,7 +200,7 @@
   configured with the option --enable-vp9-highbitdepth).
 
 test-25fps.vp9_2.md5:
-  MD5 of RGB thumbnail rendered version of test-25fps.vp9_@. Written out by
+  MD5 of RGB thumbnail rendered version of test-25fps.vp9_2. Written out by
   video_decode_accelerator_unittest.
 
 // VDA test files: bear
diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h
index 173fe0d..5941bf5 100644
--- a/media/video/video_decode_accelerator.h
+++ b/media/video/video_decode_accelerator.h
@@ -178,6 +178,9 @@
     // Used as a hint to the decoder. Outputting VideoFrames in this color space
     // may avoid extra conversion steps.
     gfx::ColorSpace target_color_space;
+
+    // HDR metadata specified by the container.
+    base::Optional<HDRMetadata> hdr_metadata;
   };
 
   // Interface for collaborating with picture interface to provide memory for
diff --git a/net/http/http_basic_state.cc b/net/http/http_basic_state.cc
index 0690de6..041d73f 100644
--- a/net/http/http_basic_state.cc
+++ b/net/http/http_basic_state.cc
@@ -24,7 +24,10 @@
       connection_(std::move(connection)),
       using_proxy_(using_proxy),
       http_09_on_non_default_ports_enabled_(
-          http_09_on_non_default_ports_enabled) {}
+          http_09_on_non_default_ports_enabled) {
+  CHECK(connection_) << "ClientSocketHandle passed to HttpBasicState must "
+                        "not be NULL. See crbug.com/790776";
+}
 
 HttpBasicState::~HttpBasicState() = default;
 
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc
index ced3da36..965065e6 100644
--- a/net/http/http_stream_parser.cc
+++ b/net/http/http_stream_parser.cc
@@ -207,6 +207,8 @@
       sent_last_chunk_(false),
       upload_error_(OK),
       weak_ptr_factory_(this) {
+  CHECK(connection_) << "ClientSocketHandle passed to HttpStreamParser must "
+                        "not be NULL. See crbug.com/790776";
   io_callback_ = base::Bind(&HttpStreamParser::OnIOComplete,
                             weak_ptr_factory_.GetWeakPtr());
 }
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index c8234b39..dcc122b 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -19493,7 +19493,6 @@
     { "name": "la-grande-jaugue.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "letsencrypt-for-cpanel.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "liukang.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "leticiagomeztagle.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "levans.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kvetinymilt.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "liquidhost.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -34700,7 +34699,6 @@
     { "name": "ying299.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ythyth.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "xiangqiushi.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "xtremenutrition.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "zhujicaihong.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "zeug.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "youwatchporn.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -39334,7 +39332,6 @@
     { "name": "icys2017.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "idealinflatablehire.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "idraulico.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "idtechnowizard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ienakanote.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ifyou.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ignet.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39532,7 +39529,6 @@
     { "name": "lipartydepot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lisburnhottubnbounce.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "littlejumpers.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "littlelundgrenladies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "littleprincessandmascotparties.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "littlescallywagsplay.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "livebetterwith.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39779,7 +39775,6 @@
     { "name": "prestigebouncycastles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "prestigeeventshire.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "primalinea.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "printsos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pristineevents.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "proautorepairs.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "projectcastle.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -40674,7 +40669,6 @@
     { "name": "mexicanjokes.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "michaelsweater.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "michmexguides.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "micropoint.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mikebelanger.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mikeybailey.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mikhlevich.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
diff --git a/services/catalog/manifest.json b/services/catalog/manifest.json
index 4fd82fd..4b31651 100644
--- a/services/catalog/manifest.json
+++ b/services/catalog/manifest.json
@@ -9,7 +9,7 @@
     // build time or something. Same with service:service_manager.
     "service_manager:connector": {
       "provides": {
-        "app": [ "filesystem::mojom::Directory" ],
+        "directory": [ "filesystem::mojom::Directory" ],
         "control": [ "catalog::mojom::CatalogControl" ]
       },
       "requires": {
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc
index f25a789..2d984f8 100644
--- a/services/service_manager/service_manager.cc
+++ b/services/service_manager/service_manager.cc
@@ -1050,7 +1050,7 @@
   // TODO(beng): It'd be great to build this from the manifest, however there's
   //             a bit of a chicken-and-egg problem.
   InterfaceProviderSpec spec;
-  spec.provides["app"].insert("filesystem::mojom::Directory");
+  spec.provides["directory"].insert("filesystem::mojom::Directory");
   spec.provides["catalog:catalog"].insert("catalog::mojom::Catalog");
   spec.provides["control"].insert("catalog::mojom::CatalogControl");
   InterfaceProviderSpecMap specs;
diff --git a/services/ui/manifest.json b/services/ui/manifest.json
index 3e7df926..dfd2c55 100644
--- a/services/ui/manifest.json
+++ b/services/ui/manifest.json
@@ -79,7 +79,7 @@
       },
       "requires": {
         "*": [ "app" ],
-        "catalog": [ "app" ],
+        "catalog": [ "directory" ],
         "service_manager": [ "service_manager:all_users" ],
         "ui": [ "ozone" ],
         "viz": [ "viz_host" ]
diff --git a/services/viz/manifest.json b/services/viz/manifest.json
index f1db488..a2d462d 100644
--- a/services/viz/manifest.json
+++ b/services/viz/manifest.json
@@ -17,7 +17,7 @@
       },
       "requires": {
         "*": [ "app" ],
-        "catalog": [ "app" ],
+        "catalog": [ "directory" ],
         "service_manager": [ "service_manager:all_users" ],
         "ui": [ "ozone" ]
       }
diff --git a/testing/buildbot/filters/ash_unittests_mash.filter b/testing/buildbot/filters/ash_unittests_mash.filter
index 181542d..ef501303 100644
--- a/testing/buildbot/filters/ash_unittests_mash.filter
+++ b/testing/buildbot/filters/ash_unittests_mash.filter
@@ -61,6 +61,9 @@
 -ImmersiveFullscreenControllerTest.RevealViaGestureChildConsumesEvents
 -ImmersiveFullscreenControllerTest.Transient
 
+# TODO: http://crbug.com/725257
+-LockScreenSanityTest.PasswordSubmitClearsPasswordAfterAuthentication
+
 # TODO: Triage
 -LoginMetricsRecorderTest.UnlockAttempts
 -LoginPasswordViewTest.PasswordSubmitClearsPassword
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index e4b3aa9..c8be4e2 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -6288,8 +6288,6 @@
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-disable-inherited.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-4/styles-history.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles-4/svg-style.xhtml [ Failure ]
-crbug.com/591099 http/tests/devtools/extensions/extensions-audits-content-script.html [ Failure ]
-crbug.com/591099 http/tests/devtools/extensions/extensions-audits.html [ Failure ]
 crbug.com/591099 http/tests/devtools/extensions/extensions-network.html [ Failure ]
 crbug.com/591099 http/tests/devtools/extensions/extensions-sidebar.html [ Failure ]
 crbug.com/591099 http/tests/devtools/extensions/extensions-timeline-api.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 89fdb4a..f7a3490 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2489,7 +2489,6 @@
 # css-multicol tests failing on initial import from web-platform-tests
 crbug.com/788337 external/wpt/css/css-multicol/multicol-block-no-clip-001.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-block-no-clip-002.xht [ Failure ]
-crbug.com/788337 external/wpt/css/css-multicol/multicol-break-001.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-count-computed-001.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-count-computed-002.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-count-computed-003.xht [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/compositing/images/direct-image-clip-path-expected.png b/third_party/WebKit/LayoutTests/compositing/images/direct-image-clip-path-expected.png
index ba84a79..133a1af 100644
--- a/third_party/WebKit/LayoutTests/compositing/images/direct-image-clip-path-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/images/direct-image-clip-path-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/images/direct-image-dynamic-clip-path-expected.png b/third_party/WebKit/LayoutTests/compositing/images/direct-image-dynamic-clip-path-expected.png
index ba84a79..133a1af 100644
--- a/third_party/WebKit/LayoutTests/compositing/images/direct-image-dynamic-clip-path-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/images/direct-image-dynamic-clip-path-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 3ca95b8..d856dac 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -37973,6 +37973,90 @@
      {}
     ]
    ],
+   "css/css-fonts/first-available-font-001.html": [
+    [
+     "/css/css-fonts/first-available-font-001.html",
+     [
+      [
+       "/css/css-fonts/first-available-font-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-fonts/first-available-font-002.html": [
+    [
+     "/css/css-fonts/first-available-font-002.html",
+     [
+      [
+       "/css/css-fonts/first-available-font-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-fonts/first-available-font-003.html": [
+    [
+     "/css/css-fonts/first-available-font-003.html",
+     [
+      [
+       "/css/css-fonts/first-available-font-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-fonts/first-available-font-004.html": [
+    [
+     "/css/css-fonts/first-available-font-004.html",
+     [
+      [
+       "/css/css-fonts/first-available-font-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-fonts/first-available-font-005.html": [
+    [
+     "/css/css-fonts/first-available-font-005.html",
+     [
+      [
+       "/css/css-fonts/first-available-font-005-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-fonts/first-available-font-006.html": [
+    [
+     "/css/css-fonts/first-available-font-006.html",
+     [
+      [
+       "/css/css-fonts/first-available-font-005-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-fonts/first-available-font-007.html": [
+    [
+     "/css/css-fonts/first-available-font-007.html",
+     [
+      [
+       "/css/css-fonts/first-available-font-005-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-fonts/font-display/font-display.html": [
     [
      "/css/css-fonts/font-display/font-display.html",
@@ -100391,6 +100475,26 @@
      {}
     ]
    ],
+   "css/css-fonts/first-available-font-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-fonts/first-available-font-002-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-fonts/first-available-font-003-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-fonts/first-available-font-005-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-fonts/font-display/font-display-ref.html": [
     [
      {}
@@ -100931,11 +101035,21 @@
      {}
     ]
    ],
+   "css/css-fonts/support/AD.woff": [
+    [
+     {}
+    ]
+   ],
    "css/css-fonts/support/README": [
     [
      {}
     ]
    ],
+   "css/css-fonts/support/Revalia.woff": [
+    [
+     {}
+    ]
+   ],
    "css/css-fonts/support/bar_with_corner_dot.png": [
     [
      {}
@@ -124781,6 +124895,16 @@
      {}
     ]
    ],
+   "encoding/resources/single-byte-raw.py": [
+    [
+     {}
+    ]
+   ],
+   "encoding/resources/text-plain-charset.py": [
+    [
+     {}
+    ]
+   ],
    "encoding/resources/utf-32-big-endian-bom.html": [
     [
      {}
@@ -127006,6 +127130,11 @@
      {}
     ]
    ],
+   "html/browsers/history/the-history-interface/001-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/browsers/history/the-history-interface/007-expected.txt": [
     [
      {}
@@ -131641,6 +131770,26 @@
      {}
     ]
    ],
+   "html/editing/dnd/platform/plugin/swfsources/dragndrop.hx": [
+    [
+     {}
+    ]
+   ],
+   "html/editing/dnd/platform/plugin/swfsources/dragndrop.hxml": [
+    [
+     {}
+    ]
+   ],
+   "html/editing/dnd/platform/plugin/swfsources/mouseup.hx": [
+    [
+     {}
+    ]
+   ],
+   "html/editing/dnd/platform/plugin/swfsources/mouseup.hxml": [
+    [
+     {}
+    ]
+   ],
    "html/editing/dnd/platform/plugindrop.html": [
     [
      {}
@@ -134841,6 +134990,11 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-candidate-moved-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-in-sync-event-expected.txt": [
     [
      {}
@@ -135326,6 +135480,11 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/iframe-load-event-expected.txt": [
     [
      {}
@@ -146761,6 +146920,11 @@
      {}
     ]
    ],
+   "touch-events/multi-touch-interactions.js": [
+    [
+     {}
+    ]
+   ],
    "touch-events/touch-support.js": [
     [
      {}
@@ -172774,6 +172938,14 @@
      {}
     ]
    ],
+   "encoding/single-byte-decoder.html": [
+    [
+     "/encoding/single-byte-decoder.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
    "encoding/textdecoder-byte-order-marks.html": [
     [
      "/encoding/textdecoder-byte-order-marks.html",
@@ -175854,6 +176026,18 @@
      {}
     ]
    ],
+   "html/browsers/history/the-history-interface/001.html": [
+    [
+     "/html/browsers/history/the-history-interface/001.html",
+     {}
+    ]
+   ],
+   "html/browsers/history/the-history-interface/002.html": [
+    [
+     "/html/browsers/history/the-history-interface/002.html",
+     {}
+    ]
+   ],
    "html/browsers/history/the-history-interface/004.html": [
     [
      "/html/browsers/history/the-history-interface/004.html",
@@ -179368,6 +179552,18 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-candidate-moved.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-candidate-moved.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-candidate-remove-no-listener.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-candidate-remove-no-listener.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-audio-constructor-no-src.html": [
     [
      "/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-audio-constructor-no-src.html",
@@ -180612,6 +180808,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/iframe-append-to-child-document.html": [
     [
      "/html/semantics/embedded-content/the-iframe-element/iframe-append-to-child-document.html",
@@ -180690,6 +180892,42 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/move_iframe_in_dom_01.html": [
     [
      "/html/semantics/embedded-content/the-iframe-element/move_iframe_in_dom_01.html",
@@ -181278,6 +181516,12 @@
      }
     ]
    ],
+   "html/semantics/forms/form-submission-0/url-encoded.html": [
+    [
+     "/html/semantics/forms/form-submission-0/url-encoded.html",
+     {}
+    ]
+   ],
    "html/semantics/forms/historical.html": [
     [
      "/html/semantics/forms/historical.html",
@@ -255239,6 +255483,50 @@
    "b4992b381f6a8f83ee043f379e614b43c7ead393",
    "reftest"
   ],
+  "css/css-fonts/first-available-font-001-ref.html": [
+   "b908d93443cee9e64628e85a29d288d567f19e5a",
+   "support"
+  ],
+  "css/css-fonts/first-available-font-001.html": [
+   "b766a6b03eda1f84317330e4144efda1fe11877e",
+   "reftest"
+  ],
+  "css/css-fonts/first-available-font-002-ref.html": [
+   "1d2b31f4624182d4e1451a7af73e11a049faba75",
+   "support"
+  ],
+  "css/css-fonts/first-available-font-002.html": [
+   "85d82a4b714deac3ab2dc15cf1c90d340039ea0e",
+   "reftest"
+  ],
+  "css/css-fonts/first-available-font-003-ref.html": [
+   "561cd0ffcb017ae0a5cd8489cc335afaa43fd95d",
+   "support"
+  ],
+  "css/css-fonts/first-available-font-003.html": [
+   "60fa4838cce77f2516689b368cf9058adcab22e9",
+   "reftest"
+  ],
+  "css/css-fonts/first-available-font-004.html": [
+   "449a20a6fecb03821cdb5253fa09a70340b8321c",
+   "reftest"
+  ],
+  "css/css-fonts/first-available-font-005-ref.html": [
+   "460dc6967318b4c75c9776ef4d4e76e39f51534e",
+   "support"
+  ],
+  "css/css-fonts/first-available-font-005.html": [
+   "6c4d33aa1d766da74c5d0ad6cbcda3793c3df926",
+   "reftest"
+  ],
+  "css/css-fonts/first-available-font-006.html": [
+   "9cf39bd6493745a35b586046ffb3ad98334ba1b7",
+   "reftest"
+  ],
+  "css/css-fonts/first-available-font-007.html": [
+   "955b6034a43ed937c87df87b35e37d6cdb4f1e0d",
+   "reftest"
+  ],
   "css/css-fonts/font-display/font-display-failure-fallback.html": [
    "9fbf0c808f338c5d668554ab62f10cfe0ca93c91",
    "testharness"
@@ -256239,10 +256527,18 @@
    "415b835abaaab822aab11880354296e7356bbb0a",
    "support"
   ],
+  "css/css-fonts/support/AD.woff": [
+   "2bff1f1a01ce7c959341300952b2467e87e60dd5",
+   "support"
+  ],
   "css/css-fonts/support/README": [
    "c46bfcee920aef0b9167764ec78c699ed217c8f2",
    "support"
   ],
+  "css/css-fonts/support/Revalia.woff": [
+   "f2b20022818e53e9c9c5f22bcc52703c6858eb1c",
+   "support"
+  ],
   "css/css-fonts/support/bar_with_corner_dot.png": [
    "76cb66964d085f70c0c91635c9369ea8fb41f2a3",
    "support"
@@ -295855,6 +296151,14 @@
    "66626403db30a2778878a187df339b0bfd767495",
    "support"
   ],
+  "encoding/resources/single-byte-raw.py": [
+   "a5e5464b00944713d7e90d3e5f9313ef2924b375",
+   "support"
+  ],
+  "encoding/resources/text-plain-charset.py": [
+   "f94642c1168f0c3d51a97c61c32ccec7627a0cf0",
+   "support"
+  ],
   "encoding/resources/utf-32-big-endian-bom.html": [
    "e428533955536e3cf6bbf419aeb2555f96b5ecfa",
    "support"
@@ -295887,6 +296191,10 @@
    "79133d037352faca749753860fc9146e111ca083",
    "support"
   ],
+  "encoding/single-byte-decoder.html": [
+   "2f64550e5e845fa2de949577f0756a021bede269",
+   "testharness"
+  ],
   "encoding/textdecoder-byte-order-marks.html": [
    "d53e5217cd1cfe73c01b1136449a6dd2a0ef0c21",
    "testharness"
@@ -299827,6 +300135,18 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
+  "html/browsers/history/the-history-interface/001-expected.txt": [
+   "e0bdc817e3754e6abf154b355c3123f925858204",
+   "support"
+  ],
+  "html/browsers/history/the-history-interface/001.html": [
+   "5eb4991d51ef483a8ab629ad014977296da4ea68",
+   "testharness"
+  ],
+  "html/browsers/history/the-history-interface/002.html": [
+   "4568f49e7c762e299cbc0ef6f286e3bcf0ac8c02",
+   "testharness"
+  ],
   "html/browsers/history/the-history-interface/004.html": [
    "dcfddde7f1f05b04748fcaa67eb200df306496b3",
    "testharness"
@@ -305547,6 +305867,22 @@
    "e5d33d9a6a6f26bee085c37f356f9126fb471bba",
    "support"
   ],
+  "html/editing/dnd/platform/plugin/swfsources/dragndrop.hx": [
+   "cc53296297cb0619595762e9e47d0da6392f8d21",
+   "support"
+  ],
+  "html/editing/dnd/platform/plugin/swfsources/dragndrop.hxml": [
+   "cedf011ae5c47d503547b922f1787b8efe3ab229",
+   "support"
+  ],
+  "html/editing/dnd/platform/plugin/swfsources/mouseup.hx": [
+   "e25a2eb738256296edc2645f7396a113450add22",
+   "support"
+  ],
+  "html/editing/dnd/platform/plugin/swfsources/mouseup.hxml": [
+   "729b02246a7d074467f5b7b09c75db74a5fa7aed",
+   "support"
+  ],
   "html/editing/dnd/platform/plugindrop.html": [
    "6e37e2f982802d2f622bdcb5a3bc5f5a582fc4f5",
    "support"
@@ -309479,6 +309815,18 @@
    "85074dd09d194ded62141e0e724a444f6e5f1c5c",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-candidate-moved-expected.txt": [
+   "cce21f607dbb0e6845ef545f5e89e45c5bfcdbc5",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-candidate-moved.html": [
+   "7b381d3d661c2e26ad2d694a9b839e3144c45d49",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-candidate-remove-no-listener.html": [
+   "5dc206e147d772f076e2e4a6340d912bc85123b0",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-audio-constructor-no-src.html": [
    "bb04c2e07224b24cdb1a64c171cd76bd97383995",
    "testharness"
@@ -310747,6 +311095,14 @@
    "cf6e961b764d5c6e7e1289f3db988fe94efaf030",
    "testharness"
   ],
+  "html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen-expected.txt": [
+   "5bc2f2e4103c64f7df3521c30ef3fcd58e3a3b64",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html": [
+   "70a1607f74e1550681a4b7b589f7a41db9174e7a",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-iframe-element/iframe-append-to-child-document.html": [
    "a732337b181e924195a53b586a1cae849dc504ef",
    "testharness"
@@ -310819,6 +311175,18 @@
    "2f6d9ad5237db0f3973b0910bd45f184fb4831f9",
    "testharness"
   ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html": [
+   "5dcb098cdef98557922b9dd71d7b39d3de7a595b",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html": [
+   "76e10a874b9a604b39e66246a46f8435e7a980a1",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html": [
+   "b785d99493fd74ca901fe640b6db83999b54e60c",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_helper-1.html": [
    "414c2815f1fb26963df6e231e36087a7f3789164",
    "support"
@@ -310831,6 +311199,18 @@
    "93ba0e0a74f2e2213a1aae306578170935367c89",
    "support"
   ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html": [
+   "22e2f2b8986981e95ed5d0f79bfc9c4ef177b53b",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html": [
+   "adb85ad6da836f44b75cb11bcb9a34fbc3fc9211",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html": [
+   "aea637881bfc46b3bc9a277a11a41cbd4b0582ba",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-iframe-element/move_iframe_in_dom_01.html": [
    "6dcbd6cb4509403f03ce4b9df63d064305618e51",
    "testharness"
@@ -311671,6 +312051,10 @@
    "f73376af978f2fb89dcbd6e9092f113d90c7a3d6",
    "testharness"
   ],
+  "html/semantics/forms/form-submission-0/url-encoded.html": [
+   "04568ab3b18733d4773a5020fdf0c22bdca3b210",
+   "testharness"
+  ],
   "html/semantics/forms/historical.html": [
    "96c0951e2b6d718c1b044f71911508cc673e37de",
    "testharness"
@@ -340539,6 +340923,10 @@
    "668253cfe71fe71583697c8f927791b3c2fb5bdf",
    "testharness"
   ],
+  "touch-events/multi-touch-interactions.js": [
+   "ebd23ef9b71a949ba6f45a08b342ec569626fd82",
+   "support"
+  ],
   "touch-events/touch-globaleventhandler-interface.html": [
    "6ba9f3eef329c218d5a1b47b78dae1fdb4d2877b",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-001-ref.html
new file mode 100644
index 0000000..f5cc3bd65
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-001-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS-fonts: reference file</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<style>
+@font-face {
+  font-family: 'B';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+}
+
+div {
+  width: 1ex;
+  height: 1ex;
+
+  font-size: 200px;
+  background: blue;
+  font-family: 'B';
+}
+</style>
+
+<p>Test passes if there is <strong>a blue square</strong> below.
+
+<div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-001.html
new file mode 100644
index 0000000..065be3a4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-001.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS-fonts: first available font and the ex unit</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#first-available-font">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#first-available-font">
+<link rel="match" href="first-available-font-001-ref.html">
+<meta name="flags" content="">
+<meta name="assert" content="Fonts that do not include the U+0020 character are not considered the first available font (used to determine the ex unit), even when at the start of the font list.">
+<style>
+/* Two arbitrary fonts with different metrics */
+@font-face {
+  font-family: 'A-no-space';
+  font-style: normal;
+  font-weight: 400;
+  src:  url(support/Revalia.woff) format('woff');
+  unicode-range: U+0061; /* Not including U+0020, so it cannot be the first available font*/
+}
+@font-face {
+  font-family: 'B';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+}
+
+div {
+  width: 1ex;
+  height: 0.5ex;
+
+  font-size: 200px;
+  background: blue;
+  position: absolute;
+}
+#t1 { font-family: 'B', sans-serif; margin-top: 0.5ex; } /* half a square, shifted down */
+#t2 { font-family: 'A-no-space', 'B', monospace; } /* Should use B as the first available font, and therefore be the same size as t1 */
+
+/* Both elements are using different generic fallback fonts, so that they end up being sized differently if web-fonts fail to load. */
+
+</style>
+
+<p>Test passes if there is <strong>a blue square</strong> below.
+
+<div id=t1></div>
+<div id=t2></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-002-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-002-ref.html
new file mode 100644
index 0000000..cbfcd31
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-002-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS-fonts: reference file</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<style>
+@font-face {
+  font-family: 'B';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+}
+
+div {
+  width: 1ch;
+  height: 1ch;
+
+  font-size: 200px;
+  background: blue;
+  font-family: 'B';
+}
+</style>
+
+<p>Test passes if there is <strong>a blue square</strong> below.
+
+<div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-002.html
new file mode 100644
index 0000000..cfd5809
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-002.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS-fonts: first available font and the ch unit</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#first-available-font">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#first-available-font">
+<link rel="match" href="first-available-font-002-ref.html">
+<meta name="flags" content="">
+<meta name="assert" content="Fonts that do not include the U+0020 character are not considered the first available font (used to determine the ch unit), even when at the start of the font list.">
+<style>
+/* Two arbitrary fonts with different metrics */
+@font-face {
+  font-family: 'A-no-space';
+  font-style: normal;
+  font-weight: 400;
+  src:  url(support/Revalia.woff) format('woff');
+  unicode-range: U+0061; /* Not including U+0020, so it cannot be the first available font*/
+}
+@font-face {
+  font-family: 'B';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+}
+
+div {
+  width: 1ch;
+  height: 0.5ch;
+
+  font-size: 200px;
+  background: blue;
+  position: absolute;
+}
+#t1 { font-family: 'B', sans-serif; margin-top: 0.5ch; } /* half a square, shifted down */
+#t2 { font-family: 'A-no-space', 'B', monospace; } /* Should use B as the first available font, and therefore be the same size as t1 */
+
+/* Both elements are using different generic fallback fonts, so that they end up being sized differently if web-fonts fail to load. */
+
+</style>
+
+<p>Test passes if there is <strong>a blue square</strong> below.
+
+<div id=t1></div>
+<div id=t2></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-003-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-003-ref.html
new file mode 100644
index 0000000..afcbe3b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-003-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS-fonts: reference file</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<style>
+@font-face {
+  font-family: 'A';
+  font-style: normal;
+  font-weight: 400;
+  src:  url(support/Revalia.woff) format('woff');
+}
+div {
+  position: absolute;
+  line-height: normal;
+  font-size: 100px;
+  color: transparent;
+  border: solid black 1px;
+  width: 100px;
+  font-family: A;
+}
+
+.ba { margin-left: 100px; }
+</style>
+
+<p>There should be <strong>two identically sized rectangles</strong> below.
+
+<div class="ba">a</div>
+<div class="a">a</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-003.html
new file mode 100644
index 0000000..948171d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-003.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS-fonts: first available font and the strut</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#first-available-font">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#first-available-font">
+<link rel="match" href="first-available-font-003-ref.html">
+<meta name="flags" content="">
+<meta name="assert" content="The strut, which impacts the line height, is taken from the primary font, which is the first font to include the U+0020 character.">
+<style>
+/* Two arbitrary fonts with different metrics */
+@font-face {
+  font-family: 'A';
+  font-style: normal;
+  font-weight: 400;
+  src:  url(support/Revalia.woff) format('woff');
+}
+@font-face {
+  font-family: 'B-no-space';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+  unicode-range: U+0062;
+}
+
+div {
+  position: absolute;
+  line-height: normal;
+  font-size: 100px;
+  color: transparent;
+  border: solid black 1px;
+  width: 100px;
+}
+
+.a { font-family: A; }
+.ba { font-family: B-no-space, A; margin-left: 100px; }
+</style>
+
+<p>There should be <strong>two identically sized rectangles</strong> below.
+
+<!-- Both divs show the same content with the same font,
+     but the first div has an unused font earlier in the list,
+     while the second one does not.
+     However, that font does not include the U+0020 character,
+     and can therefore not be the first available font.
+     If it had been, it would affect the height of the strut,
+     making the height different.
+     Since it is not, both boxes are expected to be the same height. -->
+<div class="ba">a</div>
+<div class="a">a</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-004.html
new file mode 100644
index 0000000..d2fb1616
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-004.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS-fonts: first available font and the strut</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#first-available-font">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#first-available-font">
+<link rel="match" href="first-available-font-003-ref.html">
+<meta name="flags" content="">
+<meta name="assert" content="The strut, which impacts the line height, is taken from the primary font, which is the first font to include the U+0020 character.
+The fact that that font is used somewhere else in the page makes no difference.">
+<style>
+/* Two arbitrary fonts with different metrics */
+@font-face {
+  font-family: 'A';
+  font-style: normal;
+  font-weight: 400;
+  src:  url(support/Revalia.woff) format('woff');
+}
+@font-face {
+  font-family: 'B-no-space';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+  unicode-range: U+0062;
+}
+
+div {
+  position: absolute;
+  line-height: normal;
+  font-size: 100px;
+  color: transparent;
+  border: solid black 1px;
+  width: 100px;
+}
+
+.a { font-family: A; }
+.ba { font-family: B-no-space, A; margin-left: 100px; }
+.loader { font-family: B-no-space; border: none; }
+</style>
+
+<p>There should be <strong>two identically sized rectangles</strong> below.
+
+<div class=loader>b</div>
+
+<!-- Both divs show the same content with the same font,
+     but the first div has an unused font earlier in the list,
+     while the second one does not.
+     However, that font does not include the U+0020 character,
+     and can therefore not be the first available font.
+     If it had been, it would affect the height of the strut,
+     making the height different.
+     Since it is not, both boxes are expected to be the same height. -->
+<div class="ba">a</div>
+<div class="a">a</div>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-005-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-005-ref.html
new file mode 100644
index 0000000..9f27c19
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-005-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS fonts test: baseline position with explicit sizing, no space in first font</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<p>Test passes if there is <strong>no red</strong> below.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-005.html
new file mode 100644
index 0000000..bf46a9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-005.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS fonts test: baseline position with explicit sizing, no space in first font</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#first-available-font">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#first-available-font">
+<link rel="match" href="first-available-font-005-ref.html">
+<meta name="flags" content="">
+<meta name="assert" content="The position of the baseline in an inline-level box whose height is determined by a non-normal value of line-height
+                             does depend on the primary font, which is the first that contains U+0020.">
+<style>
+@font-face {
+  font-family: 'A-no-space';
+  font-style: normal;
+  font-weight: 400;
+  src:  url(support/Revalia.woff) format('woff');
+  unicode-range: U+0061;
+}
+@font-face {
+  font-family: 'B-no-space';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+  unicode-range: U+0061;
+}
+@font-face {
+  font-family: 'B';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+}
+
+div {
+  position: absolute;
+  line-height: 100px;
+  font-size: 100px;
+  width: 300px; /* plenty of room for the (invisible) text */
+  text-align: right;
+  color: transparent;
+  outline: solid;
+}
+span { /* visible thing aligned to the baseline, and small enough to not influence its position */
+  display: inline-block;
+  width: 20px;
+  height: 20px;
+}
+
+/* white #a is on top of red #b,
+   The first font in their respective lists do no contain U+0020,
+   and therfore the first available font should be the next one, which is the same.
+   Since the baseline should be based on the primary font,
+   their baselines should line up and red #b should be invisible.*/
+#a { font-family: A-no-space, B; }
+#a span { background: red; }
+
+#b { font-family: B-no-space, B; }
+#b span { background: white; }
+
+</style>
+
+<p>Test passes if there is <strong>no red</strong> below.
+
+<div id=a>bb<span></span></div>
+<div id=b>bb<span></span></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-006.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-006.html
new file mode 100644
index 0000000..6f54384
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-006.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS fonts test: baseline position with explicit sizing, no space in first font</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#first-available-font">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#first-available-font">
+<link rel="match" href="first-available-font-005-ref.html">
+<meta name="flags" content="">
+<meta name="assert" content="The position of the baseline in an inline-level box whose height is determined by a non-normal value of line-height
+                             does depend on the primary font, which is the first that contains U+0020.">
+<style>
+@font-face {
+  font-family: 'A-no-space';
+  font-style: normal;
+  font-weight: 400;
+  src:  url(support/Revalia.woff) format('woff');
+  unicode-range: U+0061;
+}
+@font-face {
+  font-family: 'B-no-space';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+  unicode-range: U+0061;
+}
+@font-face {
+  font-family: 'B';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+}
+
+div {
+  position: absolute;
+  line-height: 100px;
+  font-size: 100px;
+  width: 300px; /* plenty of room for the (invisible) text */
+  text-align: right;
+  color: transparent;
+  outline: solid;
+}
+span { /* visible thing aligned to the baseline, and small enough to not influence its position */
+  display: inline-block;
+  width: 20px;
+  height: 20px;
+}
+
+/* white #a is on top of red #b,
+   The first font in their respective lists do no contain U+0020,
+   and therfore the first available font should be the next one, which is the same.
+   Since the baseline should be based on the primary font,
+   their baselines should line up and red #b should be invisible.
+   The fact that that font is used should make no difference.
+ */
+#a { font-family: A-no-space, B; }
+#a span { background: red; }
+
+#b { font-family: B-no-space, B; }
+#b span { background: white; }
+
+</style>
+
+<p>Test passes if there is <strong>no red</strong> below.
+
+<div id=a>aa<span></span></div>
+<div id=b>aa<span></span></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-007.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-007.html
new file mode 100644
index 0000000..a05b029a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/first-available-font-007.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS-fonts: inline level box content height and first available font, missing U+0020</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#first-available-font">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#first-available-font">
+<link rel="match" href="first-available-font-005-ref.html">
+<meta name="flags" content="">
+<meta name="assert" content="The height of the content area of an inline-level depends only on the first available font, which is the first one to include U+0020.">
+<style>
+/* Two Arbitrary fonts with different metrics. One has a taller ascender, the other a deeper descender. */
+@font-face {
+  font-family: 'A-no-space';
+  font-style: normal;
+  font-weight: 400;
+  src:  url(support/Revalia.woff) format('woff');
+  unicode-range: U+0061;
+}
+@font-face {
+  font-family: 'B';
+  font-style: normal;
+  font-weight: 400;
+  src: url(support/AD.woff) format('woff');
+}
+
+div {
+  font-size: 50px;
+  display: inline-block;
+  width: 40px;
+  overflow: hidden;
+}
+
+span { color: transparent; }
+
+div:nth-of-type(1) {
+  font-family: B;
+}
+div:nth-of-type(1) span { background: red; }
+
+/* The second div should have the same first available font as the first one, since A-no-space does no include U+0020.
+   Both div's span's should thefore overflap exactly, with the white one hiding the red.
+ */
+div:nth-of-type(2) {
+  font-family: A-no-space, B;
+  margin-left: -40px;
+}
+div:nth-of-type(2) span { background: white; }
+</style>
+
+<p>Test passes if there is <strong>no red</strong> below.
+
+<div><span>aaaaa</span></div><div><span>aaaaa</span></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/AD.woff b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/AD.woff
new file mode 100644
index 0000000..3df8ea8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/AD.woff
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/Revalia.woff b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/Revalia.woff
new file mode 100644
index 0000000..631bee6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/Revalia.woff
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-break-001-ref.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-break-001-ref.xht
index b363c2b..f753518 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-break-001-ref.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-break-001-ref.xht
@@ -21,9 +21,9 @@
 
   <p>Test passes if the 2 horizontal bars are <strong>identical</strong>.</p>
 
-  <div>&nbsp; <img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /></div>
+  <div><img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /></div>
 
-  <div>&nbsp; <img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /></div>
+  <div><img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /></div>
 
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-break-001.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-break-001.xht
index 8c3f6a7..a0366741 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-break-001.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-break-001.xht
@@ -47,7 +47,7 @@
       <div>C</div>
   </div>
 
-  <div id="reference">&nbsp; <img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /></div>
+  <div id="reference"><img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /> <img src="support/black20x20.png" alt="Image download support must be enabled" /></div>
 
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-empty-stylesheet-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-empty-stylesheet-expected.txt
deleted file mode 100644
index c6ebda9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-empty-stylesheet-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Tests running audits with a single empty stylesheet.
-
-Page reloaded.
-    Network Utilization
-        [spritesheet-smallicons smallicon-red-ball severity] Leverage browser caching (3)
-         The following resources are missing a cache expiration. Resources that do not specify an expiration may not be cached by browsers:
-           audits-empty-stylesheet.html
-           inspector-test.js
-           audits-test.js
-    Web Page Performance
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-empty-stylesheet.html b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-empty-stylesheet.html
deleted file mode 100644
index 6f7a2332..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-empty-stylesheet.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<style>
-/* Empty stylesheet */
-</style>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/audits-test.js"></script>
-
-<script>
-function test() {
-  TestRunner.reloadPage(step1);
-
-  function step1() {
-    Audits.AuditRuleResult.resourceDomain = function() {
-      return '[domain]';
-    };
-
-    AuditsTestRunner.launchAllAudits(false, step2);
-  }
-
-  function step2() {
-    AuditsTestRunner.collectAuditResults(TestRunner.completeTest);
-  }
-}
-</script>
-</head>
-
-<body onload="runTest()">
-<p>Tests running audits with a single empty stylesheet.</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-functional-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-functional-expected.txt
deleted file mode 100644
index 4d5d517..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-functional-expected.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-Tests audit rules.
-
-   Text Link
-Page reloaded.
-    Network Utilization
-        [spritesheet-smallicons smallicon-red-ball severity] Combine external JavaScript (4)
-         There are multiple resources served from same domain. Consider combining them into as few files as possible.
-          4 JavaScript resources served from [domain].
-        [spritesheet-smallicons smallicon-red-ball severity] Leverage browser caching (6)
-         The following resources are missing a cache expiration. Resources that do not specify an expiration may not be cached by browsers:
-           audits-panel-functional.html
-           inspector-test.js
-           audits-test.js
-           audits-script1.js
-           audits-style1.css
-           audits-script2.js
-        [spritesheet-smallicons smallicon-orange-ball severity] Specify image dimensions (2)
-         A width and height should be specified for all images in order to speed up page display. The following image(s) are missing a width and/or height:
-           foo1.jpg
-           foo2.jpg
-    Web Page Performance
-        [spritesheet-smallicons smallicon-red-ball severity] Optimize the order of styles and scripts (2)
-         The following external CSS files were included after an external JavaScript file in the document head. To ensure CSS files are downloaded in parallel, always include external CSS before external JavaScript.
-           audits-style1.css
-          1 inline script block was found in the head between an external CSS file and another resource. To allow parallel downloading, move the inline script before the external CSS file, or after the next resource.
-        [spritesheet-smallicons smallicon-red-ball severity] Put CSS in the document head (2)
-         CSS in the document body adversely impacts rendering performance.
-         1 style block(s) in the 
-          audits-panel-functional.html
-          body should be moved to the document head.
-         Link node 
-          audits-style1.css
-          should be moved to the document head in 
-          audits-panel-functional.html
-        [spritesheet-smallicons smallicon-orange-ball severity] Remove unused CSS rules (10)
-         10 rules (50%) of CSS not used by the current page.
-          Inline block #1: 41% is not used by the current page.
-           .unused
-           x:before
-           x:nth-child(1):hover:after
-           x:after
-           x:hover
-           x:first-letter
-           x:nth-child(2n + 1)
-          Inline block #2: 100% is not used by the current page.
-           .violation
-           audits-style1.css
-          : 100% is not used by the current page.
-           .some-style
-           audits-style1.css
-          : 100% is not used by the current page.
-           .some-style
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-functional.html b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-functional.html
deleted file mode 100644
index c7d1e31..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-functional.html
+++ /dev/null
@@ -1,96 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<style>
-@media all {
-
-/* This is a comment to use some space before the unused rule */
-
-.unused {
-    color: green;
-    -webkit-opacity: 1;
-    opacity: 1;
-}
-
-x:before { color: black }
-x:nth-child(1):hover:after { color: black }
-x:after { color: black }
-x:hover { color: black }
-x:first-letter { color: black }
-x:nth-child(2n + 1) { color: black }
-
-/* These rules should NOT be reported as unused */
-
-a:visited { text-decoration: none }
-
-img::before { color: red }
-img:after { color: red }
-
-img:hover { border: 1px solid black }
-img:focus { border: 1px solid black }
-img:active { border: 1px solid black }
-
-span:first-letter { color: red }
-
-img:nth-child(2n) { border: 1px solid blue }
-img:nth-child(2n + 1) { border: 1px solid green }
-img:nth-child(1):hover:after { border: 1px solid cyan }
-
-}
-</style>
-<script>
-JSON = {};
-</script>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/audits-test.js"></script>
-
-<!-- These scripts are needed to result in a violation of the max JS resource count from the same domain -->
-<script src="resources/audits-script1.js"></script>
-<link rel="stylesheet" href="resources/audits-style1.css" type="text/css">
-<script src="resources/audits-script2.js"></script>
-<script>
-var test = function() {
-  TestRunner.reloadPage(onPageReloaded);
-  var pendingStyleSheetsCount = 4;
-  TestRunner.addSniffer(SDK.CSSModel.prototype, '_styleSheetAdded', maybeStylesheetsLoaded, true);
-
-  var pageReloaded = false;
-  function onPageReloaded() {
-    pageReloaded = true;
-    maybeStylesheetsLoaded();
-  }
-
-  function maybeStylesheetsLoaded() {
-    if (!pageReloaded)
-      return;
-    if (TestRunner.cssModel.styleSheetHeaders().length !== pendingStyleSheetsCount)
-      return;
-    Audits.AuditRuleResult.resourceDomain = function() {
-      return '[domain]';
-    };
-
-    AuditsTestRunner.launchAllAudits(false, onAuditsFinished);
-  }
-
-  function onAuditsFinished() {
-    AuditsTestRunner.collectAuditResults(TestRunner.completeTest);
-  }
-};
-</script>
-</head>
-
-<body onload="runTest()">
-<p>Tests audit rules.</p>
-<style>
-.violation { color: red; -webkit-border-radius: 3px; }
-</style>
-<link rel="stylesheet" href="resources/audits-style1.css" type="text/css">
-<img src="foo1.jpg">
-<img src="foo2.jpg" width=100>
-<img src="foo3.jpg" style="position: absolute">
-<img src="foo4.jpg" style="width: 16px; height: 16px">
-<span>Text</span>
-<a>Link</a>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-noimages-functional-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-noimages-functional-expected.txt
deleted file mode 100644
index c801c550..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-noimages-functional-expected.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-Tests audit rules on a page without images.
-Page reloaded.
-    Network Utilization
-        [spritesheet-smallicons smallicon-red-ball severity] Combine external JavaScript (4)
-         There are multiple resources served from same domain. Consider combining them into as few files as possible.
-          4 JavaScript resources served from [domain].
-        [spritesheet-smallicons smallicon-red-ball severity] Leverage browser caching (6)
-         The following resources are missing a cache expiration. Resources that do not specify an expiration may not be cached by browsers:
-           audits-panel-noimages-functional.html
-           audits-style1.css
-           inspector-test.js
-           audits-test.js
-           audits-script1.js
-           audits-script2.js
-    Web Page Performance
-        [spritesheet-smallicons smallicon-red-ball severity] Optimize the order of styles and scripts (3)
-          3 inline script blocks were found in the head between an external CSS file and another resource. To allow parallel downloading, move the inline script before the external CSS file, or after the next resource.
-        [spritesheet-smallicons smallicon-red-ball severity] Put CSS in the document head (2)
-         CSS in the document body adversely impacts rendering performance.
-         1 style block(s) in the 
-          audits-panel-noimages-functional.html
-          body should be moved to the document head.
-         Link node 
-          audits-style1.css
-          should be moved to the document head in 
-          audits-panel-noimages-functional.html
-        [spritesheet-smallicons smallicon-orange-ball severity] Remove unused CSS rules (5)
-         5 rules (100%) of CSS not used by the current page.
-          Inline block #1: 100% is not used by the current page.
-           .unused
-          Inline block #2: 100% is not used by the current page.
-           .violation
-           audits-style1.css
-          : 100% is not used by the current page.
-           .some-style
-           audits-style1.css
-          : 100% is not used by the current page.
-           .some-style
-           audits-style1.css
-          : 100% is not used by the current page.
-           .some-style
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-noimages-functional.html b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-noimages-functional.html
deleted file mode 100644
index d038290..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/audits-panel-noimages-functional.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<style>
-.unused {
-    color: green;
-}
-</style>
-<link rel="stylesheet" href="resources/audits-style1.css" type="text/css">
-<script>function foo() { }</script>
-<link rel="stylesheet" href="resources/audits-style1.css" type="text/css">
-<script>
-JSON = {};
-</script>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/audits-test.js"></script>
-
-<!-- These scripts are needed to result in a violation of the max JS resource count from the same domain -->
-<script src="resources/audits-script1.js"></script>
-<script src="resources/audits-script2.js"></script>
-<script>
-var test = function() {
-  TestRunner.reloadPage();
-  TestRunner.addSniffer(SDK.CSSModel.prototype, '_styleSheetAdded', onStyleSheetAdded, true);
-
-  var pendingStyleSheetsCount = 5;
-  function onStyleSheetAdded() {
-    if (--pendingStyleSheetsCount)
-      return;
-    Audits.AuditRuleResult.resourceDomain = function() {
-      return '[domain]';
-    };
-
-    AuditsTestRunner.launchAllAudits(false, onAuditsFinished);
-  }
-
-  function onAuditsFinished() {
-    AuditsTestRunner.collectAuditResults(TestRunner.completeTest);
-  }
-};
-</script>
-</head>
-
-<body onload="runTest()">
-Tests audit rules on a page without images.
-<style>
-.violation { color: red; }
-</style>
-<link rel="stylesheet" href="resources/audits-style1.css" type="text/css">
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/abe.png b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/abe.png
deleted file mode 100644
index c932536..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/abe.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/audits-script1.js b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/audits-script1.js
deleted file mode 100644
index c9920ac4..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/audits-script1.js
+++ /dev/null
@@ -1,3 +0,0 @@
-function foo1()
-{
-}
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/audits-script2.js b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/audits-script2.js
deleted file mode 100644
index 283fe1f..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/audits-script2.js
+++ /dev/null
@@ -1,3 +0,0 @@
-function foo2()
-{
-}
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/audits-style1.css b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/audits-style1.css
deleted file mode 100644
index 77112ad..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/resources/audits-style1.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.some-style {
-    vertical-align: middle;
-}
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/set-cookie-header-audit-no-false-positive-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/set-cookie-header-audit-no-false-positive-expected.txt
deleted file mode 100644
index 09f96f87..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/set-cookie-header-audit-no-false-positive-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Tests there is no false positive Set-Cookie audit error. 
-Page reloaded.
-Success, no Set-Cookie headers found.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/set-cookie-header-audit-no-false-positive.html b/third_party/WebKit/LayoutTests/http/tests/devtools/audits/set-cookie-header-audit-no-false-positive.html
deleted file mode 100644
index 779118e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/audits/set-cookie-header-audit-no-false-positive.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/network-test.js"></script>
-<script>
-var test = function() {
-  TestRunner.reloadPage(step1);
-
-  function step1() {
-    var requests = NetworkTestRunner.networkRequests();
-    for (var i = 0; i < requests.length; ++i)
-      TestRunner.assertTrue(requests[i].responseHeaderValue('Set-Cookie') === undefined);
-    TestRunner.addResult('Success, no Set-Cookie headers found.');
-    TestRunner.completeTest();
-  }
-};
-</script>
-</head>
-<body onload="runTest()">
-Tests there is no false positive Set-Cookie audit error.
-<img src="resources/abe.png">
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-api-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-api-expected.txt
index 20cb68c1..fdec36f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-api-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-api-expected.txt
@@ -4,9 +4,6 @@
 Running tests...
 RUNNING TEST: extension_testAPI
 {
-    audits : {
-        addCategory : <function>
-    }
     inspectedWindow : {
         eval : <function>
         getResources : <function>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-api-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-api-expected.txt
deleted file mode 100644
index 3e31d2b..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-api-expected.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-Tests audits support in WebInspector Extensions API
-
-Started extension.
-Running tests...
-RUNNING TEST: extension_testAuditsAPI
-Added audit category, result dump follows:
-{
-    onAuditStarted : {
-        addListener : <function>
-        removeListener : <function>
-    }
-}
-category.onAuditStarted fired, results dump follows:
-{
-    Severity : {
-        Info : "info"
-        Severe : "severe"
-        Warning : "warning"
-    }
-    addResult : <function>
-    createNode : <function>
-    createObject : <function>
-    createResourceLink : <function>
-    createResult : <function>
-    createSnippet : <function>
-    createText : <function>
-    createURL : <function>
-    done : <function>
-    updateProgress : <function>
-}
-{
-    addChild : <function>
-    children : {
-    }
-    contents : {
-        0 : "Subtree"
-    }
-    expanded : false
-}
-    Extension audits
-All tests done.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-api.html b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-api.html
deleted file mode 100644
index efcf53e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-api.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/extensions-test.js"></script>
-<script src="../../inspector/audits-test.js"></script>
-<script src="../../inspector/extensions/extensions-audits-tests.js"></script>
-
-<script type="text/javascript">
-
-function extension_testAuditsAPI(nextTest)
-{
-    function onStartAuditCategory(results)
-    {
-        output("category.onAuditStarted fired, results dump follows:");
-        dumpObject(results);
-        var node = results.createResult("Subtree");
-        dumpObject(node);
-        // Make sure dumpObject() pushes stuff through before we continue.
-        evaluateOnFrontend("TestRunner.deprecatedRunAfterPendingDispatches(reply)", function() {
-            results.done();
-        });
-    }
-    var category = webInspector.audits.addCategory("Extension audits");
-    category.onAuditStarted.addListener(onStartAuditCategory);
-    output("Added audit category, result dump follows:");
-    dumpObject(category);
-    extension_runAudits(nextTest);
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests audits support in WebInspector Extensions API</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-content-script-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-content-script-expected.txt
deleted file mode 100644
index 76e757e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-content-script-expected.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-Tests audit formatters performing evals on content scripts in WebInspector Extensions API
-
- Started extension.
-Running tests...
-RUNNING TEST: extension_testAudits
-    Extension audits
-        [spritesheet-smallicons smallicon-orange-ball severity] Rule with details subtree (1)
-          Test Formatters
-                 main world object
-                   whereAmI
-                   : 
-                    "
-                   main world
-                    "
-                   __proto__
-                   : 
-                   Object
-                   <
-                    span
-                    
-                     id
-                    ="
-                     test-element
-                    "
-                   >
-                   …
-                   <
-                    /span
-                   >
-                 content script object
-                   whereAmI
-                   : 
-                    "
-                   brave new world
-                    "
-                   __proto__
-                   : 
-                   Object
-                   <
-                    span
-                    
-                     id
-                    ="
-                     test-element
-                    "
-                   >
-                   …
-                   <
-                    /span
-                   >
-category.onAuditStarted fired
-All tests done.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-content-script.html b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-content-script.html
deleted file mode 100644
index 20ede7ee..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-content-script.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/extensions-test.js"></script>
-<script src="../../inspector/audits-test.js"></script>
-<script src="../../inspector/extensions/extensions-audits-tests.js"></script>
-
-<script type="text/javascript">
-
-window.whereAmI = "main world";
-
-testRunner.setIsolatedWorldSecurityOrigin(632, extensionsOrigin);
-testRunner.evaluateScriptInIsolatedWorld(632, "window.whereAmI = 'brave new world'");
-
-function extension_testAudits(nextTest)
-{
-    var pendingOutput = [];
-
-    function onStartAuditCategory(results)
-    {
-        pendingOutput.push("category.onAuditStarted fired");
-        var node = results.createResult("Test Formatters");
-        node.addChild(results.createObject("({whereAmI: window.whereAmI})", "main world object"));
-        node.addChild(results.createNode("document.getElementById('test-element')"));
-
-        node.addChild(results.createObject("({whereAmI: window.whereAmI})", "content script object", { useContentScriptContext: true }));
-        node.addChild(results.createNode("document.getElementById('test-element')", { useContentScriptContext: true }));
-
-        results.addResult("Rule with details subtree (1)", "", results.Severity.Warning, node);
-        results.done();
-    }
-    var category = webInspector.audits.addCategory("Extension audits", 20);
-    category.onAuditStarted.addListener(onStartAuditCategory);
-
-    function auditsDone()
-    {
-        pendingOutput.sort().forEach(output);
-        nextTest();
-    }
-    webInspector.inspectedWindow.eval("undefined", function() {
-        extension_runAudits(auditsDone);
-    });
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests audit formatters performing evals on content scripts in WebInspector Extensions API</p>
-<span id="test-element"><b></b></span>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-expected.txt
deleted file mode 100644
index fd4c4ae..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits-expected.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-Tests audits support in WebInspector Extensions API
-
- Started extension.
-Running tests...
-RUNNING TEST: extension_testAudits
-Progress: 50%
-Progress: 75%
-    Extension audits
-        [spritesheet-smallicons smallicon-red-ball severity] Failed rule (42)
-         this rule always fails
-        [spritesheet-smallicons smallicon-orange-ball severity] Rule with details subtree (1)
-         This rule has a lot of details
-          Subtree
-           Some url: 
-            WebKit
-            more text 
-            http://www.google.com
-           ... and a snippet
-             function rand()
-{
-    return 4;
-}
-             /path/to/error.html:10
-                  object details
-                    a
-                    : 
-                    42
-                    b
-                    : 
-                     "
-                    foo
-                     "
-                    __proto__
-                    : 
-                    Object
-                    <
-                     span
-                     
-                      id
-                     ="
-                      test-element
-                     "
-                    >
-                    …
-                    <
-                     /span
-                    >
-             extensions-audits.html:20
-        [spritesheet-smallicons smallicon-green-ball severity] Passed rule
-         this rule always passes ok
-    Extension audits that fail
-category.onAuditStarted fired
-failedCategory.onAuditStarted fired, throwing exception
-All tests done.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits.html b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits.html
deleted file mode 100644
index c8751c8a..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-audits.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/extensions-test.js"></script>
-<script src="../../inspector/audits-test.js"></script>
-<script src="../../inspector/extensions/extensions-audits-tests.js"></script>
-
-<script type="text/javascript">
-
-function extension_testAudits(nextTest)
-{
-    var pendingOutput = [];
-
-    function onStartAuditCategory(results)
-    {
-        pendingOutput.push("category.onAuditStarted fired");
-        results.addResult("Passed rule", "this rule always passes ok", results.Severity.Info);
-        results.addResult("Failed rule (42)", "this rule always fails", results.Severity.Severe);
-
-        var node = results.createResult("Subtree");
-        node.addChild("Some url: ", results.createURL("http://www.webkit.org", "WebKit"), " more text ", results.createURL("http://www.google.com"));
-        var nestedNode = node.addChild("... and a snippet");
-        nestedNode.expanded = true;
-        nestedNode.addChild(results.createSnippet("function rand()\n{\n    return 4;\n}"));
-        nestedNode.addChild(results.createResourceLink("file:///path/to/error.html", 10));
-        nestedNode.addChild(results.createObject("({a: 42, b: 'foo'})", "object details"));
-        nestedNode.addChild(results.createNode("document.getElementById('test-element')"));
-
-        webInspector.inspectedWindow.eval("location.href", function(inspectedPageURL) {
-            nestedNode.addChild(results.createResourceLink(inspectedPageURL, 20));
-
-            evaluateOnFrontend("ExtensionsTestRunner.dumpAuditProgress(); reply();", function() {
-                results.addResult("Rule with details subtree (1)", "This rule has a lot of details", results.Severity.Warning, node);
-                results.updateProgress(10, 20);
-                evaluateOnFrontend("ExtensionsTestRunner.dumpAuditProgress(); reply();", results.done.bind(results));
-            });
-        });
-    }
-    function onStartAuditFailedCategory()
-    {
-        pendingOutput.push("failedCategory.onAuditStarted fired, throwing exception");
-        throw "oops!";
-    }
-    function onStartAuditDisabledCategory(results)
-    {
-        pendingOutput.push("FAIL: disabledCategory.onAuditStarted fired");
-        results.done();
-    }
-    var category = webInspector.audits.addCategory("Extension audits");
-    category.onAuditStarted.addListener(onStartAuditCategory);
-
-    var failedCategory = webInspector.audits.addCategory("Extension audits that fail", 2);
-    failedCategory.onAuditStarted.addListener(onStartAuditFailedCategory);
-
-    var disabledCategory = webInspector.audits.addCategory("Disabled extension audits", 2);
-    disabledCategory.onAuditStarted.addListener(onStartAuditDisabledCategory);
-
-    function auditsDone()
-    {
-        pendingOutput.sort().forEach(output);
-        nextTest();
-    }
-    extension_runAudits(auditsDone);
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests audits support in WebInspector Extensions API</p>
-<span id="test-element"><b></b></span>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/user-metrics-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/user-metrics-expected.txt
index c63b18d..8e0755c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/user-metrics-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/user-metrics-expected.txt
@@ -59,5 +59,4 @@
 }
 Panel shown: js_profiler
 Panel shown: timeline
-Panel shown: audits
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/user-metrics.js b/third_party/WebKit/LayoutTests/http/tests/devtools/user-metrics.js
index c9c809b..f11fafa 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/user-metrics.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/user-metrics.js
@@ -6,7 +6,6 @@
   TestRunner.addResult(`Tests list of user metrics codes and invocations.\n`);
   await TestRunner.loadModule('performance_test_runner');
   await TestRunner.loadModule('cpu_profiler_test_runner');
-  await TestRunner.loadModule('audits_test_runner');
 
   InspectorFrontendHost.recordEnumeratedHistogram = function(name, code) {
     if (name === 'DevTools.ActionTaken')
@@ -32,7 +31,6 @@
   TestRunner.dump(Host.UserMetrics._PanelCodes);
   UI.viewManager.showView('js_profiler');
   UI.viewManager.showView('timeline');
-  UI.viewManager.showView('audits');
 
   TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/audits-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/audits-test.js
deleted file mode 100644
index f6e07b68..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/audits-test.js
+++ /dev/null
@@ -1,4 +0,0 @@
-function initialize_AuditTests() {
-    InspectorTest.preloadModule('audits_test_runner');
-    InspectorTest.preloadPanel("audits");
-}
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/extensions/extensions-audits-tests.js b/third_party/WebKit/LayoutTests/http/tests/inspector/extensions/extensions-audits-tests.js
deleted file mode 100644
index 82dce79..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/extensions/extensions-audits-tests.js
+++ /dev/null
@@ -1,8 +0,0 @@
-var initialize_ExtensionsAuditsTest = function()
-{
-    InspectorTest.preloadModule('extensions_test_runner');
-
-    // We will render DOM node results, so preload elements.
-    InspectorTest.preloadPanel("elements");
-    InspectorTest.preloadPanel("audits");
-}
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.png
index 931c320..7fabcef4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/js-late-clipPath-creation-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/js-late-clipPath-creation-expected.png
index 931c320..7fabcef4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/js-late-clipPath-creation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/js-late-clipPath-creation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-01-b-expected.png
index 233fbe9d..cfa5f6e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-02-b-expected.png
index e41e2a85..1b87849 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-05-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-05-f-expected.png
index 3d76123..4001b6b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-05-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/masking-path-05-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png
index 9b16560ec..499ef76 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/clip-mask-negative-scale-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/clip-mask-negative-scale-expected.png
index 72ef83c..b85c915 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/clip-mask-negative-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/clip-mask-negative-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/focus-ring-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/focus-ring-expected.png
index b4534f5c..9641a55 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/focus-ring-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/focus-ring-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/masking-clipping-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/masking-clipping-hidpi-expected.png
index 5692896..19d7b9c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/masking-clipping-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/masking-clipping-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/transformed-outlines-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/transformed-outlines-expected.png
index 12516f4..ee2d5e7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/transformed-outlines-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/transformed-outlines-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/transforms/svg-css-transforms-clip-path-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/transforms/svg-css-transforms-clip-path-expected.png
index a5c8ccb..64e35866 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/transforms/svg-css-transforms-clip-path-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/transforms/svg-css-transforms-clip-path-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-01-b-expected.png
index b5372424..80a1a2b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-02-b-expected.png
index 0c2831ea..6ac524a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-05-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-05-f-expected.png
index 6bc544f..9cffbb99 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-05-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/masking-path-05-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png
index ec34f363..222ab34c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/clip-mask-negative-scale-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/clip-mask-negative-scale-expected.png
index f7fa1f06..505c436 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/clip-mask-negative-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/clip-mask-negative-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/focus-ring-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/focus-ring-expected.png
index 0301123..88544088 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/focus-ring-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/focus-ring-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/masking-clipping-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/masking-clipping-hidpi-expected.png
index 2724ab5..449f293 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/masking-clipping-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/masking-clipping-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/transformed-outlines-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/transformed-outlines-expected.png
index ec336cb..22a6ccab 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/transformed-outlines-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/transformed-outlines-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/transforms/svg-css-transforms-clip-path-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/transforms/svg-css-transforms-clip-path-expected.png
index 71b782d..694c11c0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/transforms/svg-css-transforms-clip-path-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/transforms/svg-css-transforms-clip-path-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-01-b-expected.png
index 74099605..8629736 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-02-b-expected.png
index fc146847..26cc2c5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-05-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-05-f-expected.png
index dc885f8..e48474e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-05-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/masking-path-05-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png
index f2a518ff..43630a38 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/painting-marker-02-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/clip-mask-negative-scale-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/clip-mask-negative-scale-expected.png
index d9bc2c5..51381ea0b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/clip-mask-negative-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/clip-mask-negative-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/focus-ring-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/focus-ring-expected.png
index 45c44f9..a6b939e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/focus-ring-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/focus-ring-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/masking-clipping-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/masking-clipping-hidpi-expected.png
index b1896fe7..520040c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/masking-clipping-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/masking-clipping-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/transformed-outlines-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/transformed-outlines-expected.png
index 62d5395..8298369 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/transformed-outlines-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/transformed-outlines-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/transforms/svg-css-transforms-clip-path-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/transforms/svg-css-transforms-clip-path-expected.png
index 3ff5834..b3a4800 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/transforms/svg-css-transforms-clip-path-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/transforms/svg-css-transforms-clip-path-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/clip-path/clip-path-clipped-evenodd-twice-expected.png b/third_party/WebKit/LayoutTests/svg/clip-path/clip-path-clipped-evenodd-twice-expected.png
index ae0ebec..3f7a64da 100644
--- a/third_party/WebKit/LayoutTests/svg/clip-path/clip-path-clipped-evenodd-twice-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/clip-path/clip-path-clipped-evenodd-twice-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/custom/use-on-clip-path-with-transformation-expected.png b/third_party/WebKit/LayoutTests/svg/custom/use-on-clip-path-with-transformation-expected.png
index ebf4eb3..abc1dcf1 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/use-on-clip-path-with-transformation-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/custom/use-on-clip-path-with-transformation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-clip-path-expected.png b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-clip-path-expected.png
index 220414d..27afec0 100644
--- a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-clip-path-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-clip-path-expected.png
Binary files differ
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index 1bceed9..2202a63a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -3682,74 +3682,6 @@
   return CanBeSelectionLeafInternal();
 }
 
-FloatRect LayoutObject::LocalReferenceBoxForClipPath() const {
-  if (IsSVGChild())
-    return ObjectBoundingBox();
-
-  if (IsBox())
-    return FloatRect(ToLayoutBox(*this).BorderBoxRect());
-
-  SECURITY_DCHECK(IsLayoutInline());
-  const LayoutInline& layout_inline = ToLayoutInline(*this);
-  // This somewhat convoluted computation matches what Gecko does.
-  // See crbug.com/641907.
-  LayoutRect inline_b_box = layout_inline.LinesBoundingBox();
-  const InlineFlowBox* flow_box = layout_inline.FirstLineBox();
-  inline_b_box.SetHeight(flow_box ? flow_box->FrameRect().Height()
-                                  : LayoutUnit(0));
-  return FloatRect(inline_b_box);
-}
-
-Optional<FloatRect> LayoutObject::LocalClipPathBoundingBox() const {
-  if (IsText() || !StyleRef().ClipPath())
-    return WTF::nullopt;
-
-  FloatRect reference_box = LocalReferenceBoxForClipPath();
-  ClipPathOperation& clip_path = *StyleRef().ClipPath();
-  if (clip_path.GetType() == ClipPathOperation::SHAPE) {
-    ShapeClipPathOperation& shape = ToShapeClipPathOperation(clip_path);
-    if (!shape.IsValid())
-      return WTF::nullopt;
-    const Path& path = shape.GetPath(reference_box);
-    return path.BoundingRect();
-  }
-
-  DCHECK_EQ(clip_path.GetType(), ClipPathOperation::REFERENCE);
-  LayoutSVGResourceClipper* clipper = nullptr;
-  if (IsSVGChild()) {
-    SVGResources* resources =
-        SVGResourcesCache::CachedResourcesForLayoutObject(this);
-    if (!resources)
-      return WTF::nullopt;
-    clipper = resources->Clipper();
-  } else {
-    // TODO(crbug.com/109212): Doesn't work with external SVG references.
-    Node* node = GetNode();
-    if (!node)
-      return WTF::nullopt;
-    SVGElement* path_element =
-        ToReferenceClipPathOperation(clip_path).FindElement(
-            node->GetTreeScope());
-    if (!IsSVGClipPathElement(path_element))
-      return WTF::nullopt;
-    clipper = ToLayoutSVGResourceClipper(
-        ToLayoutSVGResourceContainer(path_element->GetLayoutObject()));
-  }
-  if (!clipper)
-    return WTF::nullopt;
-
-  FloatRect bounding_box = clipper->ResourceBoundingBox(reference_box);
-  if (!IsSVGChild() &&
-      clipper->ClipPathUnits() == SVGUnitTypes::kSvgUnitTypeUserspaceonuse) {
-    // With kSvgUnitTypeUserspaceonuse, the clip path layout is relative to
-    // the current transform space, and the reference box is unused.
-    // While SVG object has no concept of paint offset, HTML object's
-    // local space is shifted by paint offset.
-    bounding_box.MoveBy(reference_box.Location());
-  }
-  return bounding_box;
-}
-
 }  // namespace blink
 
 #ifndef NDEBUG
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 73f6d62..e492dd8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -741,12 +741,6 @@
     return LocalSVGTransform();
   }
 
-  // Returns the reference box for clip path layout. Note the actual bounding
-  // box of the clip path can be bigger or smaller than the reference.
-  FloatRect LocalReferenceBoxForClipPath() const;
-  // Returns the bounding box of the clip path in local coordinates.
-  Optional<FloatRect> LocalClipPathBoundingBox() const;
-
   // SVG uses FloatPoint precise hit testing, and passes the point in parent
   // coordinates instead of in paint invalidation container coordinates.
   // Eventually the rest of the layout tree will move to a similar model.
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping.cc
index d4581cee..3a43ca6 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping.cc
@@ -39,6 +39,23 @@
   return {*position.AnchorNode(), 1};
 }
 
+// TODO(xiaochengh): Expose it properly as a utility function.
+const LayoutObject* NGInlineFormattingContextOf(const Position& position) {
+  if (!NGOffsetMapping::AcceptsPosition(position))
+    return nullptr;
+  const auto node_offset_pair = ToNodeOffsetPair(position);
+  const LayoutObject* layout_object =
+      AssociatedLayoutObjectOf(node_offset_pair.first, node_offset_pair.second);
+  // For an atomic inline, EnclosingNGBlockFlow() may return itself. Example:
+  // <div><span style='display: inline-block'>foo</span></div>
+  // EnclosingNGBlockFlow() on SPAN returns SPAN itself. However, the inline
+  // formatting context of SPAN@Before/After is DIV, not SPAN.
+  // Therefore, we return its parent's EnclosingNGBlockFlow() instead.
+  if (layout_object->IsAtomicInlineLevel())
+    layout_object = layout_object->Parent();
+  return layout_object->EnclosingNGBlockFlow();
+}
+
 // TODO(xiaochengh): Introduce predicates for comparing Position and
 // NGOffsetMappingUnit, to reduce position-offset conversion and ad-hoc
 // predicates below.
@@ -122,10 +139,7 @@
     return nullptr;
   if (!NGOffsetMapping::AcceptsPosition(position))
     return nullptr;
-  const auto node_offset_pair = ToNodeOffsetPair(position);
-  const LayoutObject* layout_object =
-      AssociatedLayoutObjectOf(node_offset_pair.first, node_offset_pair.second);
-  return GetFor(layout_object);
+  return GetFor(NGInlineFormattingContextOf(position));
 }
 
 // static
@@ -133,12 +147,11 @@
     const LayoutObject* layout_object) {
   if (!RuntimeEnabledFeatures::LayoutNGEnabled())
     return nullptr;
-  if (!layout_object || !layout_object->IsInline())
+  if (!layout_object)
     return nullptr;
   LayoutBlockFlow* block_flow = layout_object->EnclosingNGBlockFlow();
-  if (!block_flow)
+  if (!block_flow || !block_flow->ChildrenInline())
     return nullptr;
-  DCHECK(block_flow->ChildrenInline());
   NGBlockNode block_node = NGBlockNode(block_flow);
   if (!block_node.CanUseNewLayout())
     return nullptr;
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping.h
index 43d9288..eb19cb3 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping.h
@@ -116,9 +116,10 @@
   static const NGOffsetMapping* GetFor(const Position&);
 
   // Returns the mapping object of the inline formatting context containing the
-  // given LayoutObject, if it's laid out with LayoutNG. This makes the
-  // retrieval of the mapping object easier when we already have a LayoutObject
-  // at hand.
+  // given LayoutObject, if it's laid out with LayoutNG. If the LayoutObject is
+  // itself an inline formatting context, returns its own offset mapping object.
+  // This makes the retrieval of the mapping object easier when we already have
+  // a LayoutObject at hand.
   static const NGOffsetMapping* GetFor(const LayoutObject*);
 
   // Returns the NGOffsetMappingUnit whose DOM range contains the position.
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping_test.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping_test.cc
index dc72493..0923b114 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_offset_mapping_test.cc
@@ -740,4 +740,32 @@
   TEST_RANGE(result.GetRanges(), foo_node, 0u, 3u);
 }
 
+TEST_P(ParameterizedNGOffsetMappingTest, GetMappingForInlineBlock) {
+  SetupHtml("t",
+            "<div id=t>foo"
+            "<span style='display: inline-block' id=span> bar </span>"
+            "baz</div>");
+
+  const Element* div = GetElementById("t");
+  const Element* span = GetElementById("span");
+
+  const NGOffsetMapping* div_mapping =
+      NGOffsetMapping::GetFor(Position(div->firstChild(), 0));
+  const NGOffsetMapping* span_mapping =
+      NGOffsetMapping::GetFor(Position(span->firstChild(), 0));
+
+  // NGOffsetMapping::GetFor for Before/AfterAnchor of an inline block should
+  // return the mapping of the containing block, not of the inline block itself.
+
+  const NGOffsetMapping* span_before_mapping =
+      NGOffsetMapping::GetFor(Position::BeforeNode(*span));
+  EXPECT_EQ(div_mapping, span_before_mapping);
+  EXPECT_NE(span_mapping, span_before_mapping);
+
+  const NGOffsetMapping* span_after_mapping =
+      NGOffsetMapping::GetFor(Position::AfterNode(*span));
+  EXPECT_EQ(div_mapping, span_after_mapping);
+  EXPECT_NE(span_mapping, span_after_mapping);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp
index 2ed15e4..7130fdc7 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp
@@ -90,11 +90,14 @@
   return DetermineClipStrategy(element) != ClipStrategy::kNone;
 }
 
-void PathFromElement(const SVGElement& element, Path& clip_path) {
-  if (auto* geometry = ToSVGGeometryElementOrNull(element))
-    geometry->ToClipPath(clip_path);
-  else if (auto* use = ToSVGUseElementOrNull(element))
-    use->ToClipPath(clip_path);
+Path PathFromElement(const SVGElement& element) {
+  if (IsSVGGeometryElement(element))
+    return ToSVGGeometryElement(element).ToClipPath();
+
+  // Guaranteed by DetermineClipStrategy() above, only <use> element and
+  // SVGGraphicsElement that has a LayoutSVGShape can reach here.
+  SECURITY_DCHECK(IsSVGUseElement(element));
+  return ToSVGUseElement(element).ToClipPath();
 }
 
 }  // namespace
@@ -106,6 +109,7 @@
 
 void LayoutSVGResourceClipper::RemoveAllClientsFromCache(
     bool mark_for_invalidation) {
+  clip_content_path_validity_ = kClipContentPathUnknown;
   clip_content_path_.Clear();
   cached_paint_record_.reset();
   local_clip_bounds_ = FloatRect();
@@ -123,86 +127,54 @@
                                         : kParentOnlyInvalidation);
 }
 
-bool LayoutSVGResourceClipper::CalculateClipContentPathIfNeeded() {
-  if (!clip_content_path_.IsEmpty())
-    return true;
+Optional<Path> LayoutSVGResourceClipper::AsPath() {
+  if (clip_content_path_validity_ == kClipContentPathValid)
+    return Optional<Path>(clip_content_path_);
+  if (clip_content_path_validity_ == kClipContentPathInvalid)
+    return WTF::nullopt;
+  DCHECK_EQ(clip_content_path_validity_, kClipContentPathUnknown);
 
+  clip_content_path_validity_ = kClipContentPathInvalid;
   // If the current clip-path gets clipped itself, we have to fallback to
   // masking.
   if (StyleRef().ClipPath())
-    return false;
+    return WTF::nullopt;
 
   unsigned op_count = 0;
-  bool using_builder = false;
-  SkOpBuilder clip_path_builder;
-
+  Optional<SkOpBuilder> clip_path_builder;
+  SkPath resolved_path;
   for (const SVGElement& child_element :
        Traversal<SVGElement>::ChildrenOf(*GetElement())) {
     ClipStrategy strategy = DetermineClipStrategy(child_element);
     if (strategy == ClipStrategy::kNone)
       continue;
-    if (strategy == ClipStrategy::kMask) {
-      clip_content_path_.Clear();
-      return false;
-    }
-
-    // First clip shape.
-    if (clip_content_path_.IsEmpty()) {
-      PathFromElement(child_element, clip_content_path_);
-      continue;
-    }
+    if (strategy == ClipStrategy::kMask)
+      return WTF::nullopt;
 
     // Multiple shapes require PathOps. In some degenerate cases PathOps can
     // exhibit quadratic behavior, so we cap the number of ops to a reasonable
     // count.
     const unsigned kMaxOps = 42;
-    if (++op_count > kMaxOps) {
-      clip_content_path_.Clear();
-      return false;
+    if (++op_count > kMaxOps)
+      return WTF::nullopt;
+    if (clip_path_builder) {
+      clip_path_builder->add(PathFromElement(child_element).GetSkPath(),
+                             kUnion_SkPathOp);
+    } else if (resolved_path.isEmpty()) {
+      resolved_path = PathFromElement(child_element).GetSkPath();
+    } else {
+      clip_path_builder.emplace();
+      clip_path_builder->add(std::move(resolved_path), kUnion_SkPathOp);
+      clip_path_builder->add(PathFromElement(child_element).GetSkPath(),
+                             kUnion_SkPathOp);
     }
-
-    // Second clip shape => start using the builder.
-    if (!using_builder) {
-      clip_path_builder.add(clip_content_path_.GetSkPath(), kUnion_SkPathOp);
-      using_builder = true;
-    }
-
-    Path sub_path;
-    PathFromElement(child_element, sub_path);
-
-    clip_path_builder.add(sub_path.GetSkPath(), kUnion_SkPathOp);
   }
 
-  if (using_builder) {
-    SkPath resolved_path;
-    clip_path_builder.resolve(&resolved_path);
-    clip_content_path_ = resolved_path;
-  }
-
-  return true;
-}
-
-bool LayoutSVGResourceClipper::AsPath(
-    const AffineTransform& animated_local_transform,
-    const FloatRect& reference_box,
-    Path& clip_path) {
-  if (!CalculateClipContentPathIfNeeded())
-    return false;
-
-  clip_path = clip_content_path_;
-
-  // We are able to represent the clip as a path. Continue with direct clipping,
-  // and transform the content to userspace if necessary.
-  if (ClipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
-    AffineTransform transform;
-    transform.Translate(reference_box.X(), reference_box.Y());
-    transform.ScaleNonUniform(reference_box.Width(), reference_box.Height());
-    clip_path.Transform(transform);
-  }
-
-  // Transform path by animatedLocalTransform.
-  clip_path.Transform(animated_local_transform);
-  return true;
+  if (clip_path_builder)
+    clip_path_builder->resolve(&resolved_path);
+  clip_content_path_ = std::move(resolved_path);
+  clip_content_path_validity_ = kClipContentPathValid;
+  return Optional<Path>(clip_content_path_);
 }
 
 sk_sp<const PaintRecord> LayoutSVGResourceClipper::CreatePaintRecord() {
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.h
index 61cd858d..3b49312 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.h
@@ -51,7 +51,7 @@
         ->EnumValue();
   }
 
-  bool AsPath(const AffineTransform&, const FloatRect& reference_box, Path&);
+  Optional<Path> AsPath();
   sk_sp<const PaintRecord> CreatePaintRecord();
 
   bool HasCycle() { return in_clip_expansion_; }
@@ -67,10 +67,12 @@
  private:
   void CalculateLocalClipBounds();
 
-  // Return true if the clip path was calculated or a cached value is available.
-  bool CalculateClipContentPathIfNeeded();
-
   // Cache of the clip path when using path clipping.
+  enum ClipContentPathValidity {
+    kClipContentPathUnknown,
+    kClipContentPathValid,
+    kClipContentPathInvalid
+  } clip_content_path_validity_ = kClipContentPathUnknown;
   Path clip_content_path_;
 
   // Cache of the clip path paint record when falling back to masking for
diff --git a/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp b/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp
index cd30a93f..6257985b 100644
--- a/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp
@@ -5,15 +5,14 @@
 #include "core/paint/ClipPathClipper.h"
 
 #include "core/dom/ElementTraversal.h"
+#include "core/layout/LayoutBox.h"
+#include "core/layout/LayoutInline.h"
 #include "core/layout/svg/LayoutSVGResourceClipper.h"
 #include "core/layout/svg/SVGLayoutSupport.h"
 #include "core/layout/svg/SVGResources.h"
 #include "core/layout/svg/SVGResourcesCache.h"
 #include "core/paint/PaintInfo.h"
-#include "core/paint/TransformRecorder.h"
 #include "core/style/ClipPathOperation.h"
-#include "platform/graphics/paint/ClipPathDisplayItem.h"
-#include "platform/graphics/paint/ClipPathRecorder.h"
 #include "platform/graphics/paint/DrawingDisplayItem.h"
 #include "platform/graphics/paint/DrawingRecorder.h"
 #include "platform/graphics/paint/PaintController.h"
@@ -25,13 +24,18 @@
 
 class SVGClipExpansionCycleHelper {
  public:
-  SVGClipExpansionCycleHelper(LayoutSVGResourceClipper& clip) : clip_(clip) {
-    clip.BeginClipExpansion();
+  void Lock(LayoutSVGResourceClipper& clipper) {
+    DCHECK(!clipper.HasCycle());
+    clipper.BeginClipExpansion();
+    clippers_.push_back(&clipper);
   }
-  ~SVGClipExpansionCycleHelper() { clip_.EndClipExpansion(); }
+  ~SVGClipExpansionCycleHelper() {
+    for (auto* clipper : clippers_)
+      clipper->EndClipExpansion();
+  }
 
  private:
-  LayoutSVGResourceClipper& clip_;
+  Vector<LayoutSVGResourceClipper*, 1> clippers_;
 };
 
 LayoutSVGResourceClipper* ResolveElementReference(
@@ -59,192 +63,229 @@
 
 }  // namespace
 
+FloatRect ClipPathClipper::LocalReferenceBox(const LayoutObject& object) {
+  if (object.IsSVGChild())
+    return object.ObjectBoundingBox();
+
+  if (object.IsBox())
+    return FloatRect(ToLayoutBox(object).BorderBoxRect());
+
+  SECURITY_DCHECK(object.IsLayoutInline());
+  const LayoutInline& layout_inline = ToLayoutInline(object);
+  // This somewhat convoluted computation matches what Gecko does.
+  // See crbug.com/641907.
+  LayoutRect inline_b_box = layout_inline.LinesBoundingBox();
+  const InlineFlowBox* flow_box = layout_inline.FirstLineBox();
+  inline_b_box.SetHeight(flow_box ? flow_box->FrameRect().Height()
+                                  : LayoutUnit(0));
+  return FloatRect(inline_b_box);
+}
+
+Optional<FloatRect> ClipPathClipper::LocalClipPathBoundingBox(
+    const LayoutObject& object) {
+  if (object.IsText() || !object.StyleRef().ClipPath())
+    return WTF::nullopt;
+
+  FloatRect reference_box = LocalReferenceBox(object);
+  ClipPathOperation& clip_path = *object.StyleRef().ClipPath();
+  if (clip_path.GetType() == ClipPathOperation::SHAPE) {
+    ShapeClipPathOperation& shape = ToShapeClipPathOperation(clip_path);
+    if (!shape.IsValid())
+      return WTF::nullopt;
+    return shape.GetPath(reference_box).BoundingRect();
+  }
+
+  DCHECK_EQ(clip_path.GetType(), ClipPathOperation::REFERENCE);
+  LayoutSVGResourceClipper* clipper =
+      ResolveElementReference(object, ToReferenceClipPathOperation(clip_path));
+  if (!clipper)
+    return WTF::nullopt;
+
+  FloatRect bounding_box = clipper->ResourceBoundingBox(reference_box);
+  if (!object.IsSVGChild() &&
+      clipper->ClipPathUnits() == SVGUnitTypes::kSvgUnitTypeUserspaceonuse) {
+    bounding_box.Scale(clipper->StyleRef().EffectiveZoom());
+    // With kSvgUnitTypeUserspaceonuse, the clip path layout is relative to
+    // the current transform space, and the reference box is unused.
+    // While SVG object has no concept of paint offset, HTML object's
+    // local space is shifted by paint offset.
+    bounding_box.MoveBy(reference_box.Location());
+  }
+  return bounding_box;
+}
+
+// Note: Return resolved LayoutSVGResourceClipper for caller's convenience,
+// if the clip path is a reference to SVG.
+static bool IsClipPathOperationValid(
+    const ClipPathOperation& clip_path,
+    const LayoutObject& search_scope,
+    LayoutSVGResourceClipper*& resource_clipper) {
+  if (clip_path.GetType() == ClipPathOperation::SHAPE) {
+    if (!ToShapeClipPathOperation(clip_path).IsValid())
+      return false;
+  } else {
+    DCHECK_EQ(clip_path.GetType(), ClipPathOperation::REFERENCE);
+    resource_clipper = ResolveElementReference(
+        search_scope, ToReferenceClipPathOperation(clip_path));
+    if (!resource_clipper)
+      return false;
+    SECURITY_DCHECK(!resource_clipper->NeedsLayout());
+    resource_clipper->ClearInvalidationMask();
+    if (resource_clipper->HasCycle())
+      return false;
+  }
+  return true;
+}
+
 ClipPathClipper::ClipPathClipper(GraphicsContext& context,
-                                 ClipPathOperation& clip_path_operation,
                                  const LayoutObject& layout_object,
-                                 const FloatRect& reference_box,
-                                 const FloatPoint& origin)
-    : resource_clipper_(nullptr),
-      clipper_state_(ClipperState::kNotApplied),
+                                 const LayoutPoint& paint_offset)
+    : context_(context),
       layout_object_(layout_object),
-      context_(context) {
+      paint_offset_(paint_offset) {
+  DCHECK(layout_object.StyleRef().ClipPath());
+
   if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
-  if (clip_path_operation.GetType() == ClipPathOperation::SHAPE) {
-    ShapeClipPathOperation& shape =
-        ToShapeClipPathOperation(clip_path_operation);
-    if (!shape.IsValid())
-      return;
-    clip_path_recorder_.emplace(context, layout_object,
-                                shape.GetPath(reference_box));
-    clipper_state_ = ClipperState::kAppliedPath;
-  } else {
-    DCHECK_EQ(clip_path_operation.GetType(), ClipPathOperation::REFERENCE);
-    resource_clipper_ = ResolveElementReference(
-        layout_object, ToReferenceClipPathOperation(clip_path_operation));
-    if (!resource_clipper_)
-      return;
-    // Compute the (conservative) bounds of the clip-path.
-    FloatRect clip_path_bounds =
-        resource_clipper_->ResourceBoundingBox(reference_box);
-    // When SVG applies the clip, and the coordinate system is "userspace on
-    // use", we must explicitly pass in the offset to have the clip paint in the
-    // correct location. When the coordinate system is "object bounding box" the
-    // offset should already be accounted for in the reference box.
-    FloatPoint origin_translation;
-    if (resource_clipper_->ClipPathUnits() ==
-        SVGUnitTypes::kSvgUnitTypeUserspaceonuse) {
-      clip_path_bounds.MoveBy(origin);
-      origin_translation = origin;
-    }
-    if (!PrepareEffect(reference_box, clip_path_bounds, origin_translation)) {
-      // Indicate there is no cleanup to do.
-      resource_clipper_ = nullptr;
-      return;
+
+  Optional<FloatRect> bounding_box = LocalClipPathBoundingBox(layout_object);
+  if (!bounding_box)
+    return;
+
+  FloatRect adjusted_bounding_box = *bounding_box;
+  adjusted_bounding_box.MoveBy(FloatPoint(paint_offset));
+  clip_recorder_.emplace(context, layout_object,
+                         DisplayItem::kFloatClipClipPathBounds,
+                         adjusted_bounding_box);
+
+  bool is_valid = false;
+  if (Optional<Path> as_path =
+          PathBasedClip(layout_object, layout_object.IsSVGChild(),
+                        LocalReferenceBox(layout_object), is_valid)) {
+    as_path->Translate(FloatSize(paint_offset.X(), paint_offset.Y()));
+    clip_path_recorder_.emplace(context, layout_object, *as_path);
+  } else if (is_valid) {
+    mask_isolation_recorder_.emplace(context, layout_object,
+                                     SkBlendMode::kSrcOver, 1.f);
+  }
+}
+
+static AffineTransform MaskToContentTransform(
+    const LayoutSVGResourceClipper& resource_clipper,
+    bool is_svg_child,
+    const FloatRect& reference_box) {
+  AffineTransform mask_to_content;
+  if (resource_clipper.ClipPathUnits() ==
+      SVGUnitTypes::kSvgUnitTypeUserspaceonuse) {
+    if (!is_svg_child) {
+      mask_to_content.Translate(reference_box.X(), reference_box.Y());
+      mask_to_content.Scale(resource_clipper.StyleRef().EffectiveZoom());
     }
   }
+
+  mask_to_content.Multiply(
+      ToSVGClipPathElement(resource_clipper.GetElement())
+          ->CalculateTransform(SVGElement::kIncludeMotionTransform));
+
+  if (resource_clipper.ClipPathUnits() ==
+      SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
+    mask_to_content.Translate(reference_box.X(), reference_box.Y());
+    mask_to_content.ScaleNonUniform(reference_box.Width(),
+                                    reference_box.Height());
+  }
+  return mask_to_content;
 }
 
 ClipPathClipper::~ClipPathClipper() {
   if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
-  if (resource_clipper_)
-    FinishEffect();
-}
+  if (!mask_isolation_recorder_)
+    return;
 
-bool ClipPathClipper::PrepareEffect(const FloatRect& target_bounding_box,
-                                    const FloatRect& visual_rect,
-                                    const FloatPoint& layer_position_offset) {
-  DCHECK_EQ(clipper_state_, ClipperState::kNotApplied);
-  SECURITY_DCHECK(!resource_clipper_->NeedsLayout());
+  bool is_svg_child = layout_object_.IsSVGChild();
+  FloatRect reference_box = LocalReferenceBox(layout_object_);
 
-  resource_clipper_->ClearInvalidationMask();
-
-  if (resource_clipper_->HasCycle())
-    return false;
-
-  SVGClipExpansionCycleHelper in_clip_expansion_change(*resource_clipper_);
-
-  AffineTransform animated_local_transform =
-      ToSVGClipPathElement(resource_clipper_->GetElement())
-          ->CalculateTransform(SVGElement::kIncludeMotionTransform);
-  // When drawing a clip for non-SVG elements, the CTM does not include the zoom
-  // factor.  In this case, we need to apply the zoom scale explicitly - but
-  // only for clips with userSpaceOnUse units (the zoom is accounted for
-  // objectBoundingBox-resolved lengths).
-  if (!layout_object_.IsSVG() && resource_clipper_->ClipPathUnits() ==
-                                     SVGUnitTypes::kSvgUnitTypeUserspaceonuse) {
-    DCHECK(resource_clipper_->Style());
-    animated_local_transform.Scale(resource_clipper_->Style()->EffectiveZoom());
-  }
-
-  // First, try to apply the clip as a clipPath.
-  Path clip_path;
-  if (resource_clipper_->AsPath(animated_local_transform, target_bounding_box,
-                                clip_path)) {
-    AffineTransform position_transform;
-    position_transform.Translate(layer_position_offset.X(),
-                                 layer_position_offset.Y());
-    clip_path.Transform(position_transform);
-    clipper_state_ = ClipperState::kAppliedPath;
-    context_.GetPaintController().CreateAndAppend<BeginClipPathDisplayItem>(
-        layout_object_, clip_path);
-    return true;
-  }
-
-  // Fall back to masking.
-  clipper_state_ = ClipperState::kAppliedMask;
-
-  // Begin compositing the clip mask.
-  mask_clip_recorder_.emplace(context_, layout_object_, SkBlendMode::kSrcOver,
-                              1, &visual_rect);
-  {
-    if (!DrawClipAsMask(target_bounding_box, animated_local_transform,
-                        layer_position_offset)) {
-      // End the clip mask's compositor.
-      mask_clip_recorder_.reset();
-      return false;
-    }
-  }
-
-  // Masked content layer start.
-  mask_content_recorder_.emplace(context_, layout_object_, SkBlendMode::kSrcIn,
-                                 1, &visual_rect);
-  // This is a hack to make sure masked content layer's visual rect at least
-  // as big as the clip mask layer, so it won't get culled out inadvertently.
-  if (!DrawingRecorder::UseCachedDrawingIfPossible(
-          context_, layout_object_, DisplayItem::kSVGClipBoundsHack)) {
-    DrawingRecorder recorder(context_, layout_object_,
-                             DisplayItem::kSVGClipBoundsHack);
-    context_.FillRect(FloatRect());
-  }
-  return true;
-}
-
-bool ClipPathClipper::DrawClipAsMask(const FloatRect& target_bounding_box,
-                                     const AffineTransform& local_transform,
-                                     const FloatPoint& layer_position_offset) {
+  CompositingRecorder mask_recorder(context_, layout_object_,
+                                    SkBlendMode::kDstIn, 1.f);
   if (DrawingRecorder::UseCachedDrawingIfPossible(context_, layout_object_,
                                                   DisplayItem::kSVGClip))
-    return true;
-
-  PaintRecordBuilder mask_builder(nullptr, &context_);
-  GraphicsContext& mask_context = mask_builder.Context();
-  {
-    TransformRecorder recorder(mask_context, layout_object_, local_transform);
-
-    // Apply any clip-path clipping this clipPath (nested shape/clipPath.)
-    Optional<ClipPathClipper> nested_clip_path_clipper;
-    if (ClipPathOperation* clip_path_operation =
-            resource_clipper_->StyleRef().ClipPath()) {
-      nested_clip_path_clipper.emplace(mask_context, *clip_path_operation,
-                                       *resource_clipper_, target_bounding_box,
-                                       layer_position_offset);
-    }
-
-    {
-      AffineTransform content_transform;
-      if (resource_clipper_->ClipPathUnits() ==
-          SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
-        content_transform.Translate(target_bounding_box.X(),
-                                    target_bounding_box.Y());
-        content_transform.ScaleNonUniform(target_bounding_box.Width(),
-                                          target_bounding_box.Height());
-      }
-      SubtreeContentTransformScope content_transform_scope(content_transform);
-
-      TransformRecorder content_transform_recorder(mask_context, layout_object_,
-                                                   content_transform);
-      mask_context.GetPaintController().CreateAndAppend<DrawingDisplayItem>(
-          layout_object_, DisplayItem::kSVGClip,
-          resource_clipper_->CreatePaintRecord());
-    }
-  }
-
+    return;
   DrawingRecorder recorder(context_, layout_object_, DisplayItem::kSVGClip);
-  context_.DrawRecord(mask_builder.EndRecording());
-  return true;
+  context_.Save();
+  context_.Translate(paint_offset_.X(), paint_offset_.Y());
+
+  SVGClipExpansionCycleHelper locks;
+  bool is_first = true;
+  bool rest_of_the_chain_already_appled = false;
+  const LayoutObject* current_object = &layout_object_;
+  while (!rest_of_the_chain_already_appled && current_object) {
+    const ClipPathOperation* clip_path = current_object->StyleRef().ClipPath();
+    if (!clip_path)
+      break;
+    LayoutSVGResourceClipper* resource_clipper = nullptr;
+    if (!IsClipPathOperationValid(*clip_path, *current_object,
+                                  resource_clipper))
+      break;
+
+    if (is_first)
+      context_.Save();
+    else
+      context_.BeginLayer(1.f, SkBlendMode::kDstIn);
+
+    // We wouldn't have reached here if the current clip-path is a shape,
+    // because it would have been applied as path-based clip already.
+    DCHECK(resource_clipper);
+    DCHECK_EQ(clip_path->GetType(), ClipPathOperation::REFERENCE);
+    locks.Lock(*resource_clipper);
+    if (resource_clipper->StyleRef().ClipPath()) {
+      // Try to apply nested clip-path as path-based clip.
+      bool unused;
+      if (Optional<Path> path = PathBasedClip(*resource_clipper, is_svg_child,
+                                              reference_box, unused)) {
+        context_.ClipPath(path->GetSkPath(), kAntiAliased);
+        rest_of_the_chain_already_appled = true;
+      }
+    }
+    context_.ConcatCTM(
+        MaskToContentTransform(*resource_clipper, is_svg_child, reference_box));
+    context_.DrawRecord(resource_clipper->CreatePaintRecord());
+
+    if (is_first)
+      context_.Restore();
+    else
+      context_.EndLayer();
+
+    is_first = false;
+    current_object = resource_clipper;
+  }
+  context_.Restore();
 }
 
-void ClipPathClipper::FinishEffect() {
-  switch (clipper_state_) {
-    case ClipperState::kAppliedPath:
-      // Path-only clipping, no layers to restore but we need to emit an end to
-      // the clip path display item.
-      context_.GetPaintController().EndItem<EndClipPathDisplayItem>(
-          layout_object_);
-      break;
-    case ClipperState::kAppliedMask:
-      // Transfer content -> clip mask (SrcIn)
-      mask_content_recorder_.reset();
+Optional<Path> ClipPathClipper::PathBasedClip(
+    const LayoutObject& clip_path_owner,
+    bool is_svg_child,
+    const FloatRect& reference_box,
+    bool& is_valid) {
+  const ClipPathOperation& clip_path = *clip_path_owner.StyleRef().ClipPath();
+  LayoutSVGResourceClipper* resource_clipper = nullptr;
+  is_valid =
+      IsClipPathOperationValid(clip_path, clip_path_owner, resource_clipper);
+  if (!is_valid)
+    return WTF::nullopt;
 
-      // Transfer clip mask -> bg (SrcOver)
-      mask_clip_recorder_.reset();
-      break;
-    case ClipperState::kNotApplied:
-      NOTREACHED();
-      break;
+  if (resource_clipper) {
+    DCHECK_EQ(clip_path.GetType(), ClipPathOperation::REFERENCE);
+    Optional<Path> path = resource_clipper->AsPath();
+    if (!path)
+      return path;
+    path->Transform(
+        MaskToContentTransform(*resource_clipper, is_svg_child, reference_box));
+    return path;
   }
+
+  DCHECK_EQ(clip_path.GetType(), ClipPathOperation::SHAPE);
+  auto& shape = ToShapeClipPathOperation(clip_path);
+  return Optional<Path>(shape.GetPath(reference_box));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/ClipPathClipper.h b/third_party/WebKit/Source/core/paint/ClipPathClipper.h
index e7504f6e..f801059 100644
--- a/third_party/WebKit/Source/core/paint/ClipPathClipper.h
+++ b/third_party/WebKit/Source/core/paint/ClipPathClipper.h
@@ -5,56 +5,59 @@
 #ifndef ClipPathClipper_h
 #define ClipPathClipper_h
 
+#include "core/paint/FloatClipRecorder.h"
+#include "platform/geometry/FloatRect.h"
 #include "platform/graphics/paint/ClipPathRecorder.h"
 #include "platform/graphics/paint/CompositingRecorder.h"
 #include "platform/wtf/Optional.h"
 
 namespace blink {
 
-class ClipPathOperation;
-class FloatPoint;
-class FloatRect;
 class GraphicsContext;
-class LayoutSVGResourceClipper;
 class LayoutObject;
 
-enum class ClipperState { kNotApplied, kAppliedPath, kAppliedMask };
-
 class ClipPathClipper {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
   ClipPathClipper(GraphicsContext&,
-                  ClipPathOperation&,
                   const LayoutObject&,
-                  const FloatRect& reference_box,
-                  const FloatPoint& origin);
+                  const LayoutPoint& paint_offset);
   ~ClipPathClipper();
 
-  bool UsingMask() const {
-    return clipper_state_ == ClipperState::kAppliedMask;
-  }
+  bool IsIsolationInstalled() const { return !!mask_isolation_recorder_; }
+
+  // Returns the reference box used by CSS clip-path. For HTML objects,
+  // this is the border box of the element. For SVG objects this is the
+  // object bounding box.
+  static FloatRect LocalReferenceBox(const LayoutObject&);
+  // Returns the bounding box of the computed clip path, which could be
+  // smaller or bigger than the reference box. Returns nullopt if the
+  // clip path is invalid.
+  static Optional<FloatRect> LocalClipPathBoundingBox(const LayoutObject&);
+  // The argument |clip_path_owner| is the layout object that owns the
+  // ClipPathOperation we are currently processing. Usually it is the
+  // same as the layout object getting clipped, but in the case of nested
+  // clip-path, it could be one of the SVG clip path in the chain.
+  // The output is tri-state:
+  // is_valid == false: The clip path is invalid. Always returns nullopt.
+  // is_valid == true && return == nullopt: The clip path is valid,
+  //   but cannot use path-based clip.
+  // is_valid == true && return != nullopt: The clip path can be applied
+  //   as path-based clip, and the computed path is returned.
+  static Optional<Path> PathBasedClip(const LayoutObject& clip_path_owner,
+                                      bool is_svg_child,
+                                      const FloatRect& reference_box,
+                                      bool& is_valid);
 
  private:
-  // Returns false if there is a problem drawing the mask.
-  bool PrepareEffect(const FloatRect& target_bounding_box,
-                     const FloatRect& visual_rect,
-                     const FloatPoint& layer_position_offset);
-  bool DrawClipAsMask(const FloatRect& target_bounding_box,
-                      const AffineTransform&,
-                      const FloatPoint&);
-  void FinishEffect();
-
-  LayoutSVGResourceClipper* resource_clipper_;
-  ClipperState clipper_state_;
-  const LayoutObject& layout_object_;
   GraphicsContext& context_;
+  const LayoutObject& layout_object_;
+  LayoutPoint paint_offset_;
 
-  // TODO(pdr): This pattern should be cleaned up so that the recorders are just
-  // on the stack.
+  Optional<FloatClipRecorder> clip_recorder_;
   Optional<ClipPathRecorder> clip_path_recorder_;
-  Optional<CompositingRecorder> mask_clip_recorder_;
-  Optional<CompositingRecorder> mask_content_recorder_;
+  Optional<CompositingRecorder> mask_isolation_recorder_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp b/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp
index d2cdd27..7fa6c9b9 100644
--- a/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp
@@ -14,9 +14,16 @@
                                      const DisplayItemClient& client,
                                      PaintPhase paint_phase,
                                      const FloatRect& clip_rect)
-    : context_(context),
-      client_(client),
-      clip_type_(DisplayItem::PaintPhaseToFloatClipType(paint_phase)) {
+    : FloatClipRecorder(context,
+                        client,
+                        DisplayItem::PaintPhaseToFloatClipType(paint_phase),
+                        clip_rect) {}
+
+FloatClipRecorder::FloatClipRecorder(GraphicsContext& context,
+                                     const DisplayItemClient& client,
+                                     DisplayItem::Type clip_type,
+                                     const FloatRect& clip_rect)
+    : context_(context), client_(client), clip_type_(clip_type) {
   if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   context_.GetPaintController().CreateAndAppend<FloatClipDisplayItem>(
diff --git a/third_party/WebKit/Source/core/paint/FloatClipRecorder.h b/third_party/WebKit/Source/core/paint/FloatClipRecorder.h
index 1f930196..7261464 100644
--- a/third_party/WebKit/Source/core/paint/FloatClipRecorder.h
+++ b/third_party/WebKit/Source/core/paint/FloatClipRecorder.h
@@ -22,6 +22,10 @@
                     const DisplayItemClient&,
                     PaintPhase,
                     const FloatRect&);
+  FloatClipRecorder(GraphicsContext&,
+                    const DisplayItemClient&,
+                    DisplayItem::Type,
+                    const FloatRect&);
 
   ~FloatClipRecorder();
 
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
index 965d97d..df487edb 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
@@ -13,6 +13,7 @@
 #include "core/layout/LayoutTableSection.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/svg/SVGLayoutSupport.h"
+#include "core/paint/ClipPathClipper.h"
 #include "core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h"
 #include "core/paint/ObjectPaintProperties.h"
 #include "core/paint/PaintLayer.h"
@@ -90,7 +91,7 @@
     // Note: SVG children don't need this adjustment because their visual
     // overflow rects are already adjusted by clip path.
     if (Optional<FloatRect> clip_path_bounding_box =
-            object.LocalClipPathBoundingBox()) {
+            ClipPathClipper::LocalClipPathBoundingBox(object)) {
       Rect box(EnclosingIntRect(*clip_path_bounding_box));
       rect.Unite(box);
     }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 1ae86d2c..d312a611 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -70,6 +70,7 @@
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/page/scrolling/StickyPositionScrollingConstraints.h"
 #include "core/paint/BoxReflectionUtils.h"
+#include "core/paint/ClipPathClipper.h"
 #include "core/paint/FilterEffectBuilder.h"
 #include "core/paint/ObjectPaintInvalidator.h"
 #include "core/paint/compositing/CompositedLayerMapping.h"
@@ -2481,7 +2482,8 @@
   DCHECK(IsSelfPaintingLayer());
   DCHECK(root_layer);
 
-  LayoutRect reference_box(GetLayoutObject().LocalReferenceBoxForClipPath());
+  LayoutRect reference_box(
+      ClipPathClipper::LocalReferenceBox(GetLayoutObject()));
   if (EnclosingPaginationLayer())
     ConvertFromFlowThreadToVisualBoundingBoxInAncestor(root_layer,
                                                        reference_box);
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index 4ad2d04..cf2a110 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -376,21 +376,13 @@
        (paint_flags & (kPaintLayerPaintingChildClippingMaskPhase |
                        kPaintLayerPaintingAncestorClippingMaskPhase)))) {
     painting_info.ancestor_has_clip_path_clipping = true;
-
-    LayoutRect reference_box(
-        paint_layer_.GetLayoutObject().LocalReferenceBoxForClipPath());
-    // Note that this isn't going to work correctly if crossing a column
-    // boundary. The reference box should be determined per-fragment, and hence
-    // this ought to be performed after fragmentation.
-    if (paint_layer_.EnclosingPaginationLayer())
-      paint_layer_.ConvertFromFlowThreadToVisualBoundingBoxInAncestor(
-          painting_info.root_layer, reference_box);
-    else
-      reference_box.MoveBy(offset_from_root);
-    clip_path_clipper.emplace(
-        context, *paint_layer_.GetLayoutObject().StyleRef().ClipPath(),
-        paint_layer_.GetLayoutObject(), FloatRect(reference_box),
-        FloatPoint(reference_box.Location()));
+    LayoutPoint visual_offset_from_root =
+        paint_layer_.EnclosingPaginationLayer()
+            ? paint_layer_.VisualOffsetFromAncestor(
+                  painting_info.root_layer, LayoutPoint(subpixel_accumulation))
+            : offset_from_root;
+    clip_path_clipper.emplace(context, paint_layer_.GetLayoutObject(),
+                              visual_offset_from_root);
   }
 
   Optional<CompositingRecorder> compositing_recorder;
diff --git a/third_party/WebKit/Source/core/paint/SVGPaintContext.cpp b/third_party/WebKit/Source/core/paint/SVGPaintContext.cpp
index 7e54afc..8a3fab2 100644
--- a/third_party/WebKit/Source/core/paint/SVGPaintContext.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGPaintContext.cpp
@@ -156,14 +156,11 @@
 }
 
 void SVGPaintContext::ApplyClipIfNecessary() {
-  ClipPathOperation* clip_path_operation = object_.StyleRef().ClipPath();
-  if (!clip_path_operation)
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
-  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
-    clip_path_clipper_.emplace(GetPaintInfo().context, *clip_path_operation,
-                               object_, object_.ObjectBoundingBox(),
-                               FloatPoint());
-  }
+
+  if (object_.StyleRef().ClipPath())
+    clip_path_clipper_.emplace(GetPaintInfo().context, object_, LayoutPoint());
 }
 
 bool SVGPaintContext::ApplyMaskIfNecessary(SVGResources* resources) {
@@ -218,7 +215,7 @@
   if (masker_ || filter_)
     return true;
   if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() && clip_path_clipper_ &&
-      clip_path_clipper_->UsingMask())
+      clip_path_clipper_->IsIsolationInstalled())
     return true;
   return false;
 }
diff --git a/third_party/WebKit/Source/core/style/ClipPathOperation.h b/third_party/WebKit/Source/core/style/ClipPathOperation.h
index 24b9c52..e6626f7f 100644
--- a/third_party/WebKit/Source/core/style/ClipPathOperation.h
+++ b/third_party/WebKit/Source/core/style/ClipPathOperation.h
@@ -103,13 +103,12 @@
 
   const BasicShape* GetBasicShape() const { return shape_.get(); }
   bool IsValid() const { return shape_.get(); }
-  const Path& GetPath(const FloatRect& bounding_rect) {
+  Path GetPath(const FloatRect& bounding_rect) const {
     DCHECK(shape_);
-    path_.reset();
-    path_ = WTF::WrapUnique(new Path);
-    shape_->GetPath(*path_, bounding_rect);
-    path_->SetWindRule(shape_->GetWindRule());
-    return *path_;
+    Path path;
+    shape_->GetPath(path, bounding_rect);
+    path.SetWindRule(shape_->GetWindRule());
+    return path;
   }
 
  private:
@@ -120,7 +119,6 @@
       : shape_(std::move(shape)) {}
 
   scoped_refptr<BasicShape> shape_;
-  std::unique_ptr<Path> path_;
 };
 
 DEFINE_TYPE_CASTS(ShapeClipPathOperation,
diff --git a/third_party/WebKit/Source/core/svg/SVGGeometryElement.cpp b/third_party/WebKit/Source/core/svg/SVGGeometryElement.cpp
index 2db5348..aea74fc 100644
--- a/third_party/WebKit/Source/core/svg/SVGGeometryElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGGeometryElement.cpp
@@ -107,13 +107,14 @@
       ->NodeAtFloatPointInternal(request, point->Target()->Value(), hit_rules);
 }
 
-void SVGGeometryElement::ToClipPath(Path& path) const {
-  path = AsPath();
+Path SVGGeometryElement::ToClipPath() const {
+  Path path = AsPath();
   path.Transform(CalculateTransform(SVGElement::kIncludeMotionTransform));
 
   DCHECK(GetLayoutObject());
   DCHECK(GetLayoutObject()->Style());
   path.SetWindRule(GetLayoutObject()->Style()->SvgStyle().ClipRule());
+  return path;
 }
 
 float SVGGeometryElement::getTotalLength() {
diff --git a/third_party/WebKit/Source/core/svg/SVGGeometryElement.h b/third_party/WebKit/Source/core/svg/SVGGeometryElement.h
index 8af980b..fb7a0b09 100644
--- a/third_party/WebKit/Source/core/svg/SVGGeometryElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGGeometryElement.h
@@ -47,7 +47,7 @@
   bool isPointInFill(SVGPointTearOff*) const;
   bool isPointInStroke(SVGPointTearOff*) const;
 
-  void ToClipPath(Path&) const;
+  Path ToClipPath() const;
 
   SVGAnimatedNumber* pathLength() const { return path_length_.Get(); }
   LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
index 9ac03e8..280589f 100644
--- a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
@@ -493,22 +493,18 @@
          IsSVGTextElement(element);
 }
 
-void SVGUseElement::ToClipPath(Path& path) const {
-  DCHECK(path.IsEmpty());
-
+Path SVGUseElement::ToClipPath() const {
   const SVGGraphicsElement* element = VisibleTargetGraphicsElementForClipping();
+  if (!element || !element->IsSVGGeometryElement())
+    return Path();
 
-  if (!element)
-    return;
-
-  if (element->IsSVGGeometryElement()) {
-    ToSVGGeometryElement(*element).ToClipPath(path);
-    // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
-    SVGLengthContext length_context(this);
-    path.Translate(FloatSize(x_->CurrentValue()->Value(length_context),
-                             y_->CurrentValue()->Value(length_context)));
-    path.Transform(CalculateTransform(SVGElement::kIncludeMotionTransform));
-  }
+  Path path = ToSVGGeometryElement(*element).ToClipPath();
+  // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
+  SVGLengthContext length_context(this);
+  path.Translate(FloatSize(x_->CurrentValue()->Value(length_context),
+                           y_->CurrentValue()->Value(length_context)));
+  path.Transform(CalculateTransform(SVGElement::kIncludeMotionTransform));
+  return path;
 }
 
 SVGGraphicsElement* SVGUseElement::VisibleTargetGraphicsElementForClipping()
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.h b/third_party/WebKit/Source/core/svg/SVGUseElement.h
index 3d6b636..526af58 100644
--- a/third_party/WebKit/Source/core/svg/SVGUseElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGUseElement.h
@@ -57,7 +57,7 @@
   String title() const override;
 
   void DispatchPendingEvent();
-  void ToClipPath(Path&) const;
+  Path ToClipPath() const;
 
   virtual void Trace(blink::Visitor*);
 
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index da763efd..f033dfa1 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -36,19 +36,6 @@
   "front_end/application_test_runner/ResourcesTestRunner.js",
   "front_end/application_test_runner/ResourceTreeTestRunner.js",
   "front_end/application_test_runner/ServiceWorkersTestRunner.js",
-  "front_end/audits/AuditCategories.js",
-  "front_end/audits/AuditCategory.js",
-  "front_end/audits/AuditController.js",
-  "front_end/audits/AuditExtensionCategory.js",
-  "front_end/audits/AuditFormatters.js",
-  "front_end/audits/AuditLauncherView.js",
-  "front_end/audits/auditResultTree.css",
-  "front_end/audits/AuditResultView.js",
-  "front_end/audits/AuditRules.js",
-  "front_end/audits/auditsPanel.css",
-  "front_end/audits/AuditsPanel.js",
-  "front_end/audits/auditsSidebarTree.css",
-  "front_end/audits/module.json",
   "front_end/audits2_worker.js",
   "front_end/audits2_worker.json",
   "front_end/audits2_worker/Audits2Service.js",
@@ -65,8 +52,6 @@
   "front_end/audits2/module.json",
   "front_end/audits2_test_runner/Audits2TestRunner.js",
   "front_end/audits2_test_runner/module.json",
-  "front_end/audits_test_runner/AuditsTestRunner.js",
-  "front_end/audits_test_runner/module.json",
   "front_end/bindings/BlackboxManager.js",
   "front_end/bindings/BreakpointManager.js",
   "front_end/bindings/CompilerScriptMapping.js",
@@ -263,13 +248,12 @@
   "front_end/event_listeners/EventListenersView.js",
   "front_end/event_listeners/module.json",
   "front_end/extensions/ExtensionAPI.js",
-  "front_end/extensions/ExtensionAuditCategory.js",
+
   "front_end/extensions/ExtensionPanel.js",
   "front_end/extensions/ExtensionRegistryStub.js",
   "front_end/extensions/ExtensionServer.js",
   "front_end/extensions/ExtensionView.js",
   "front_end/extensions/module.json",
-  "front_end/extensions_test_runner/ExtensionsAuditsTestRunner.js",
   "front_end/extensions_test_runner/ExtensionsNetworkTestRunner.js",
   "front_end/extensions_test_runner/ExtensionsTestRunner.js",
   "front_end/extensions_test_runner/module.json",
diff --git a/third_party/WebKit/Source/devtools/front_end/accessibility/ARIAAttributesView.js b/third_party/WebKit/Source/devtools/front_end/accessibility/ARIAAttributesView.js
index 4820650..902b71f 100644
--- a/third_party/WebKit/Source/devtools/front_end/accessibility/ARIAAttributesView.js
+++ b/third_party/WebKit/Source/devtools/front_end/accessibility/ARIAAttributesView.js
@@ -6,9 +6,9 @@
  */
 Accessibility.ARIAAttributesPane = class extends Accessibility.AccessibilitySubPane {
   constructor() {
-    super(Common.UIString('ARIA Attributes'));
+    super(ls`ARIA Attributes`);
 
-    this._noPropertiesInfo = this.createInfo(Common.UIString('No ARIA attributes'));
+    this._noPropertiesInfo = this.createInfo(ls`No ARIA attributes`);
     this._treeOutline = this.createTreeOutline();
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/accessibility/AXBreadcrumbsPane.js b/third_party/WebKit/Source/devtools/front_end/accessibility/AXBreadcrumbsPane.js
index f9f30e90..2821407 100644
--- a/third_party/WebKit/Source/devtools/front_end/accessibility/AXBreadcrumbsPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/accessibility/AXBreadcrumbsPane.js
@@ -7,7 +7,7 @@
    * @param {!Accessibility.AccessibilitySidebarView} axSidebarView
    */
   constructor(axSidebarView) {
-    super(Common.UIString('Accessibility Tree'));
+    super(ls`Accessibility Tree`);
 
     this.element.classList.add('ax-subpane');
     UI.ARIAUtils.markAsTree(this.element);
@@ -271,7 +271,7 @@
       return;
 
     var contextMenu = new UI.ContextMenu(event);
-    contextMenu.viewSection().appendItem(Common.UIString('Scroll into view'), () => {
+    contextMenu.viewSection().appendItem(ls`Scroll into view`, () => {
       axNode.deferredDOMNode().resolvePromise().then(domNode => {
         if (!domNode)
           return;
@@ -485,7 +485,7 @@
 
   _appendIgnoredNodeElement() {
     var ignoredNodeElement = createElementWithClass('span', 'monospace');
-    ignoredNodeElement.textContent = Common.UIString('Ignored');
+    ignoredNodeElement.textContent = ls`Ignored`;
     ignoredNodeElement.classList.add('ax-breadcrumbs-ignored-node');
     this._nodeWrapper.appendChild(ignoredNodeElement);
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilityNodeView.js b/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilityNodeView.js
index a21cf80..8629cc3 100644
--- a/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilityNodeView.js
+++ b/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilityNodeView.js
@@ -6,12 +6,12 @@
  */
 Accessibility.AXNodeSubPane = class extends Accessibility.AccessibilitySubPane {
   constructor() {
-    super(Common.UIString('Computed Properties'));
+    super(ls`Computed Properties`);
 
     this.contentElement.classList.add('ax-subpane');
 
-    this._noNodeInfo = this.createInfo(Common.UIString('No accessibility node'));
-    this._ignoredInfo = this.createInfo(Common.UIString('Accessibility node not exposed'), 'ax-ignored-info hidden');
+    this._noNodeInfo = this.createInfo(ls`No accessibility node`);
+    this._ignoredInfo = this.createInfo(ls`Accessibility node not exposed`, 'ax-ignored-info hidden');
 
     this._treeOutline = this.createTreeOutline();
     this._ignoredReasonsTree = this.createTreeOutline();
@@ -164,7 +164,7 @@
     var nameElement = createElement('span');
     var AXAttributes = Accessibility.AccessibilityStrings.AXAttributes;
     if (name in AXAttributes) {
-      nameElement.textContent = Common.UIString(AXAttributes[name].name);
+      nameElement.textContent = ls(AXAttributes[name].name);
       nameElement.title = AXAttributes[name].description;
       nameElement.classList.add('ax-readable-name');
     } else {
@@ -392,8 +392,8 @@
         if (source.nativeSource) {
           var AXNativeSourceTypes = Accessibility.AccessibilityStrings.AXNativeSourceTypes;
           var nativeSource = source.nativeSource;
-          nameElement.textContent = Common.UIString(AXNativeSourceTypes[nativeSource].name);
-          nameElement.title = Common.UIString(AXNativeSourceTypes[nativeSource].description);
+          nameElement.textContent = ls(AXNativeSourceTypes[nativeSource].name);
+          nameElement.title = ls(AXNativeSourceTypes[nativeSource].description);
           nameElement.classList.add('ax-readable-name');
           break;
         }
@@ -404,12 +404,12 @@
       default:
         var AXSourceTypes = Accessibility.AccessibilityStrings.AXSourceTypes;
         if (type in AXSourceTypes) {
-          nameElement.textContent = Common.UIString(AXSourceTypes[type].name);
-          nameElement.title = Common.UIString(AXSourceTypes[type].description);
+          nameElement.textContent = ls(AXSourceTypes[type].name);
+          nameElement.title = ls(AXSourceTypes[type].description);
           nameElement.classList.add('ax-readable-name');
         } else {
           console.warn(type, 'not in AXSourceTypes');
-          nameElement.textContent = Common.UIString(type);
+          nameElement.textContent = ls(type);
         }
     }
     this.listItemElement.appendChild(nameElement);
@@ -419,8 +419,7 @@
     this.listItemElement.removeChildren();
 
     if (this._source.invalid) {
-      var exclamationMark =
-          Accessibility.AXNodePropertyTreeElement.createExclamationMark(Common.UIString('Invalid source.'));
+      var exclamationMark = Accessibility.AXNodePropertyTreeElement.createExclamationMark(ls`Invalid source.`);
       this.listItemElement.appendChild(exclamationMark);
       this.listItemElement.classList.add('ax-value-source-invalid');
     } else if (this._source.superseded) {
@@ -443,7 +442,7 @@
       this.appendValueElement(this._source.value);
     } else {
       var valueElement = Accessibility.AXNodePropertyTreeElement.createSimpleValueElement(
-          Protocol.Accessibility.AXValueType.ValueUndefined, Common.UIString('Not specified'));
+          Protocol.Accessibility.AXValueType.ValueUndefined, ls`Not specified`);
       this.listItemElement.appendChild(valueElement);
       this.listItemElement.classList.add('ax-value-source-unused');
     }
@@ -519,8 +518,7 @@
       this._deferredNode.resolve(onNodeResolved.bind(this));
     } else if (this._idref) {
       element.classList.add('invalid');
-      valueElement =
-          Accessibility.AXNodePropertyTreeElement.createExclamationMark(Common.UIString('No node with this ID.'));
+      valueElement = Accessibility.AXNodePropertyTreeElement.createExclamationMark(ls`No node with this ID.`);
       valueElement.createTextChild(this._idref);
       element.appendChild(valueElement);
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditCategories.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditCategories.js
deleted file mode 100644
index a22396c..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditCategories.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-
-/**
- * @unrestricted
- */
-Audits.AuditCategories.PagePerformance = class extends Audits.AuditCategoryImpl {
-  constructor() {
-    super(Audits.AuditCategories.PagePerformance.AuditCategoryName);
-  }
-
-  initialize() {
-    this.addRule(new Audits.AuditRules.UnusedCssRule(), Audits.AuditRule.Severity.Warning);
-    this.addRule(new Audits.AuditRules.CssInHeadRule(), Audits.AuditRule.Severity.Severe);
-    this.addRule(new Audits.AuditRules.StylesScriptsOrderRule(), Audits.AuditRule.Severity.Severe);
-  }
-};
-
-Audits.AuditCategories.PagePerformance.AuditCategoryName = Common.UIString('Web Page Performance');
-
-/**
- * @unrestricted
- */
-Audits.AuditCategories.NetworkUtilization = class extends Audits.AuditCategoryImpl {
-  constructor() {
-    super(Audits.AuditCategories.NetworkUtilization.AuditCategoryName);
-  }
-
-  initialize() {
-    this.addRule(new Audits.AuditRules.GzipRule(), Audits.AuditRule.Severity.Severe);
-    this.addRule(new Audits.AuditRules.ImageDimensionsRule(), Audits.AuditRule.Severity.Warning);
-    this.addRule(new Audits.AuditRules.CookieSizeRule(400), Audits.AuditRule.Severity.Warning);
-    this.addRule(new Audits.AuditRules.StaticCookielessRule(5), Audits.AuditRule.Severity.Warning);
-    this.addRule(new Audits.AuditRules.CombineJsResourcesRule(2), Audits.AuditRule.Severity.Severe);
-    this.addRule(new Audits.AuditRules.CombineCssResourcesRule(2), Audits.AuditRule.Severity.Severe);
-    this.addRule(new Audits.AuditRules.MinimizeDnsLookupsRule(4), Audits.AuditRule.Severity.Warning);
-    this.addRule(new Audits.AuditRules.ParallelizeDownloadRule(4, 10, 0.5), Audits.AuditRule.Severity.Warning);
-    this.addRule(new Audits.AuditRules.BrowserCacheControlRule(), Audits.AuditRule.Severity.Severe);
-  }
-};
-
-Audits.AuditCategories.NetworkUtilization.AuditCategoryName = Common.UIString('Network Utilization');
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditCategory.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditCategory.js
deleted file mode 100644
index 79ecef6..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditCategory.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2014 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided 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 GOOGLE INC. AND ITS CONTRIBUTORS
- * "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 GOOGLE INC.
- * OR ITS CONTRIBUTORS 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.
- */
-/**
- * @interface
- */
-Audits.AuditCategory = function() {};
-
-Audits.AuditCategory.prototype = {
-  /**
-   * @return {string}
-   */
-  get id() {},
-
-  /**
-   * @return {string}
-   */
-  get displayName() {},
-
-  /**
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {function(!Audits.AuditRuleResult)} ruleResultCallback
-   * @param {!Common.Progress} progress
-   */
-  run(target, requests, ruleResultCallback, progress) {}
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditController.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditController.js
deleted file mode 100644
index e669294..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditController.js
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- * Copyright (C) 2013 Samsung Electronics. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-
-/**
- * @unrestricted
- */
-Audits.AuditController = class {
-  /**
-   * @param {!Audits.AuditsPanel} auditsPanel
-   */
-  constructor(auditsPanel) {
-    this._auditsPanel = auditsPanel;
-    SDK.targetManager.addModelListener(
-        SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this._didMainResourceLoad, this);
-    SDK.targetManager.addModelListener(
-        SDK.NetworkManager, SDK.NetworkManager.Events.RequestFinished, this._didLoadResource, this);
-  }
-
-  /**
-   * @param {!SDK.Target} target
-   * @param {!Array.<!Audits.AuditCategory>} categories
-   * @param {function(string, !Array.<!Audits.AuditCategoryResult>)} resultCallback
-   */
-  _executeAudit(target, categories, resultCallback) {
-    this._progress.setTitle(Common.UIString('Running audit'));
-
-    /**
-     * @param {!Audits.AuditCategoryResult} categoryResult
-     * @param {!Audits.AuditRuleResult} ruleResult
-     */
-    function ruleResultReadyCallback(categoryResult, ruleResult) {
-      if (ruleResult && ruleResult.children)
-        categoryResult.addRuleResult(ruleResult);
-    }
-
-    var results = [];
-    var mainResourceURL = target.inspectedURL();
-    var categoriesDone = 0;
-
-    function categoryDoneCallback() {
-      if (++categoriesDone !== categories.length)
-        return;
-      resultCallback(mainResourceURL, results);
-    }
-
-    var networkManager = target.model(SDK.NetworkManager);
-    var requests =
-        NetworkLog.networkLog.requests().filter(request => SDK.NetworkManager.forRequest(request) === networkManager);
-
-    var compositeProgress = new Common.CompositeProgress(this._progress);
-    var subprogresses = [];
-    for (var i = 0; i < categories.length; ++i)
-      subprogresses.push(new Common.ProgressProxy(compositeProgress.createSubProgress(), categoryDoneCallback));
-    for (var i = 0; i < categories.length; ++i) {
-      if (this._progress.isCanceled()) {
-        subprogresses[i].done();
-        continue;
-      }
-      var category = categories[i];
-      var result = new Audits.AuditCategoryResult(category);
-      results.push(result);
-      category.run(target, requests, ruleResultReadyCallback.bind(null, result), subprogresses[i]);
-    }
-  }
-
-  /**
-   * @param {string} mainResourceURL
-   * @param {!Array.<!Audits.AuditCategoryResult>} results
-   */
-  _auditFinishedCallback(mainResourceURL, results) {
-    if (!this._progress.isCanceled())
-      this._auditsPanel.auditFinishedCallback(mainResourceURL, results);
-    this._progress.done();
-  }
-
-  /**
-   * @param {!Array.<string>} categoryIds
-   * @param {!Common.Progress} progress
-   * @param {boolean} runImmediately
-   * @param {function()} startedCallback
-   */
-  initiateAudit(categoryIds, progress, runImmediately, startedCallback) {
-    var target = SDK.targetManager.mainTarget();
-    if (!categoryIds || !categoryIds.length || !target)
-      return;
-
-    this._progress = progress;
-
-    var categories = [];
-    for (var i = 0; i < categoryIds.length; ++i)
-      categories.push(this._auditsPanel.categoriesById[categoryIds[i]]);
-
-    if (runImmediately)
-      this._startAuditWhenResourcesReady(target, categories, startedCallback);
-    else
-      this._reloadResources(this._startAuditWhenResourcesReady.bind(this, target, categories, startedCallback));
-
-    Host.userMetrics.actionTaken(Host.UserMetrics.Action.AuditsStarted);
-  }
-
-  /**
-   * @param {!SDK.Target} target
-   * @param {!Array<!Audits.AuditCategory>} categories
-   * @param {function()} startedCallback
-   */
-  _startAuditWhenResourcesReady(target, categories, startedCallback) {
-    if (this._progress.isCanceled()) {
-      this._progress.done();
-      return;
-    }
-    startedCallback();
-    this._executeAudit(target, categories, this._auditFinishedCallback.bind(this));
-  }
-
-  /**
-   * @param {function()=} callback
-   */
-  _reloadResources(callback) {
-    this._pageReloadCallback = callback;
-    SDK.ResourceTreeModel.reloadAllPages();
-  }
-
-  _didLoadResource() {
-    if (this._pageReloadCallback && this._progress && this._progress.isCanceled())
-      this._pageReloadCallback();
-  }
-
-  /**
-   * @param {!Common.Event} event
-   */
-  _didMainResourceLoad(event) {
-    if (event.data.resourceTreeModel.target() !== SDK.targetManager.mainTarget())
-      return;
-    if (this._pageReloadCallback) {
-      var callback = this._pageReloadCallback;
-      delete this._pageReloadCallback;
-      callback();
-    }
-  }
-
-  clearResults() {
-    this._auditsPanel.clearResults();
-  }
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditExtensionCategory.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditExtensionCategory.js
deleted file mode 100644
index e0d2687..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditExtensionCategory.js
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-/**
- * @implements {Audits.AuditCategory}
- * @unrestricted
- */
-Audits.AuditExtensionCategory = class {
-  /**
-   * @param {string} extensionOrigin
-   * @param {string} id
-   * @param {string} displayName
-   * @param {number=} ruleCount
-   */
-  constructor(extensionOrigin, id, displayName, ruleCount) {
-    this._extensionOrigin = extensionOrigin;
-    this._id = id;
-    this._displayName = displayName;
-    this._ruleCount = ruleCount;
-  }
-
-  /**
-   * @override
-   */
-  get id() {
-    return this._id;
-  }
-
-  /**
-   * @override
-   */
-  get displayName() {
-    return this._displayName;
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {function(!Audits.AuditRuleResult)} ruleResultCallback
-   * @param {!Common.Progress} progress
-   */
-  run(target, requests, ruleResultCallback, progress) {
-    var results = new Audits.AuditExtensionCategoryResults(this, target, ruleResultCallback, progress);
-    Extensions.extensionServer.startAuditRun(this.id, results);
-  }
-};
-
-/**
- * @implements {Extensions.ExtensionAuditCategoryResults}
- * @unrestricted
- */
-Audits.AuditExtensionCategoryResults = class {
-  /**
-   * @param {!Audits.AuditExtensionCategory} category
-   * @param {!SDK.Target} target
-   * @param {function(!Audits.AuditRuleResult)} ruleResultCallback
-   * @param {!Common.Progress} progress
-   */
-  constructor(category, target, ruleResultCallback, progress) {
-    this._target = target;
-    this._category = category;
-    this._ruleResultCallback = ruleResultCallback;
-    this._progress = progress;
-    this._progress.setTotalWork(1);
-    this._expectedResults = category._ruleCount;
-    this._actualResults = 0;
-
-    this._id = category.id + '-' + ++Audits.AuditExtensionCategoryResults._lastId;
-  }
-
-  /**
-   * @override
-   * @return {string}
-   */
-  id() {
-    return this._id;
-  }
-
-  /**
-   * @override
-   */
-  done() {
-    Extensions.extensionServer.stopAuditRun(this);
-    this._progress.done();
-  }
-
-  /**
-   * @override
-   * @param {string} displayName
-   * @param {string} description
-   * @param {string} severity
-   * @param {!Object} details
-   */
-  addResult(displayName, description, severity, details) {
-    var result = new Audits.AuditRuleResult(displayName);
-    if (description)
-      result.addChild(description);
-    result.severity = severity;
-    if (details)
-      this._addNode(result, details);
-    this._addResult(result);
-  }
-
-  _addNode(parent, node) {
-    var contents = Audits.auditFormatters.partiallyApply(Audits.AuditExtensionFormatters, this, node.contents);
-    var addedNode = parent.addChild(contents, node.expanded);
-    if (node.children) {
-      for (var i = 0; i < node.children.length; ++i)
-        this._addNode(addedNode, node.children[i]);
-    }
-  }
-
-  _addResult(result) {
-    this._ruleResultCallback(result);
-    ++this._actualResults;
-    if (typeof this._expectedResults === 'number') {
-      this._progress.setWorked(this._actualResults / this._expectedResults);
-      if (this._actualResults === this._expectedResults)
-        this.done();
-    }
-  }
-
-  /**
-   * @override
-   * @param {number} progress
-   */
-  updateProgress(progress) {
-    this._progress.setWorked(progress);
-  }
-
-  /**
-   * @param {string} expression
-   * @param {?Object} evaluateOptions
-   * @param {function(!SDK.RemoteObject)} callback
-   */
-  evaluate(expression, evaluateOptions, callback) {
-    /**
-     * @param {?string} error
-     * @param {?SDK.RemoteObject} result
-     * @param {boolean=} wasThrown
-     * @this {Audits.AuditExtensionCategoryResults}
-     */
-    function onEvaluate(error, result, wasThrown) {
-      var runtimeModel = this._target.model(SDK.RuntimeModel);
-      if (wasThrown || !runtimeModel || !result)
-        return;
-      callback(result);
-    }
-    Extensions.extensionServer.evaluate(
-        expression, false, false, evaluateOptions, this._category._extensionOrigin, onEvaluate.bind(this));
-  }
-};
-
-Audits.AuditExtensionFormatters = {
-  /**
-   * @this {Audits.AuditExtensionCategoryResults}
-   * @param {string} expression
-   * @param {string} title
-   * @param {?Object} evaluateOptions
-   * @return {!Element}
-   */
-  object: function(expression, title, evaluateOptions) {
-    var parentElement = createElement('div');
-    function onEvaluate(remoteObject) {
-      var section = new ObjectUI.ObjectPropertiesSection(remoteObject, title);
-      section.expand();
-      section.editable = false;
-      parentElement.appendChild(section.element);
-    }
-    this.evaluate(expression, evaluateOptions, onEvaluate);
-    return parentElement;
-  },
-
-  /**
-   * @this {Audits.AuditExtensionCategoryResults}
-   * @param {string} expression
-   * @param {?Object} evaluateOptions
-   * @return {!Element}
-   */
-  node: function(expression, evaluateOptions) {
-    var parentElement = createElement('div');
-    this.evaluate(expression, evaluateOptions, async remoteObject => {
-      await append(remoteObject);
-      remoteObject.release();
-    });
-    return parentElement;
-
-    /**
-     * @param {!SDK.RemoteObject} remoteObject
-     */
-    async function append(remoteObject) {
-      if (!remoteObject.isNode())
-        return;
-      var domModel = remoteObject.runtimeModel().target().model(SDK.DOMModel);
-      if (!domModel)
-        return;
-      var node = await domModel.pushObjectAsNodeToFrontend(remoteObject);
-      if (!node)
-        return;
-      var element = await Common.Renderer.renderPromise(/** @type {!SDK.DOMNode} */ (node));
-      parentElement.appendChild(element);
-    }
-  }
-};
-
-Audits.AuditExtensionCategoryResults._lastId = 0;
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditFormatters.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditFormatters.js
deleted file mode 100644
index a639e9d2..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditFormatters.js
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-
-/**
- * @unrestricted
- */
-Audits.AuditFormatters = class {
-  /**
-   * @param {string|boolean|number|!Object} value
-   * @return {!Node}
-   */
-  apply(value) {
-    var formatter;
-    var type = typeof value;
-    var args;
-
-    switch (type) {
-      case 'string':
-      case 'boolean':
-      case 'number':
-        formatter = Audits.AuditFormatters.Registry.text;
-        args = [value.toString()];
-        break;
-
-      case 'object':
-        if (value instanceof Node)
-          return value;
-        if (Array.isArray(value)) {
-          formatter = Audits.AuditFormatters.Registry.concat;
-          args = value;
-        } else if (value.type && value.arguments) {
-          formatter = Audits.AuditFormatters.Registry[value.type];
-          args = value.arguments;
-        }
-    }
-    if (!formatter)
-      throw 'Invalid value or formatter: ' + type + JSON.stringify(value);
-
-    return formatter.apply(null, args);
-  }
-
-  /**
-   * @param {!Object} formatters
-   * @param {?Object} thisArgument
-   * @param {string|boolean|number|!Object} value
-   * @return {*}
-   */
-  partiallyApply(formatters, thisArgument, value) {
-    if (Array.isArray(value))
-      return value.map(this.partiallyApply.bind(this, formatters, thisArgument));
-    if (typeof value === 'object' && typeof formatters[value.type] === 'function' && value.arguments)
-      return formatters[value.type].apply(thisArgument, value.arguments);
-    return value;
-  }
-};
-
-Audits.AuditFormatters.Registry = {
-
-  /**
-   * @param {string} text
-   * @return {!Text}
-   */
-  text: function(text) {
-    return createTextNode(text);
-  },
-
-  /**
-   * @param {string} snippetText
-   * @return {!Element}
-   */
-  snippet: function(snippetText) {
-    var div = createElement('div');
-    div.textContent = snippetText;
-    div.className = 'source-code';
-    return div;
-  },
-
-  /**
-   * @return {!Element}
-   */
-  concat: function() {
-    var parent = createElement('span');
-    for (var arg = 0; arg < arguments.length; ++arg)
-      parent.appendChild(Audits.auditFormatters.apply(arguments[arg]));
-    return parent;
-  },
-
-  /**
-   * @param {string} url
-   * @param {string=} displayText
-   * @return {!Element}
-   */
-  url: function(url, displayText) {
-    return UI.createExternalLink(url, displayText);
-  },
-
-  /**
-   * @param {string} url
-   * @param {number=} line
-   * @return {!Element}
-   */
-  resourceLink: function(url, line) {
-    return Components.Linkifier.linkifyURL(url, {className: 'resource-url', lineNumber: line});
-  }
-};
-
-Audits.auditFormatters = new Audits.AuditFormatters();
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditLauncherView.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditLauncherView.js
deleted file mode 100644
index 6f1a58c..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditLauncherView.js
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-
-/**
- * @unrestricted
- */
-Audits.AuditLauncherView = class extends UI.VBox {
-  /**
-   * @param {!Audits.AuditController} auditController
-   */
-  constructor(auditController) {
-    super();
-    this.setMinimumSize(100, 25);
-
-    this._auditController = auditController;
-
-    this._categoryIdPrefix = 'audit-category-item-';
-    this._auditRunning = false;
-
-    this.element.classList.add('audit-launcher-view');
-    this.element.classList.add('panel-enabler-view');
-
-    this._contentElement = createElement('div');
-    this._contentElement.className = 'audit-launcher-view-content';
-    this.element.appendChild(this._contentElement);
-    this._boundCategoryClickListener = this._categoryClicked.bind(this);
-
-    this._resetResourceCount();
-
-    this._sortedCategories = [];
-
-    this._headerElement = createElement('h1');
-    this._headerElement.className = 'no-audits';
-    this._headerElement.textContent = Common.UIString('No audits to run');
-    this._contentElement.appendChild(this._headerElement);
-
-    SDK.targetManager.addModelListener(
-        SDK.NetworkManager, SDK.NetworkManager.Events.RequestStarted, this._onRequestStarted, this);
-    SDK.targetManager.addModelListener(
-        SDK.NetworkManager, SDK.NetworkManager.Events.RequestFinished, this._onRequestFinished, this);
-
-    var defaultSelectedAuditCategory = {};
-    defaultSelectedAuditCategory[Audits.AuditLauncherView.AllCategoriesKey] = true;
-    this._selectedCategoriesSetting =
-        Common.settings.createSetting('selectedAuditCategories', defaultSelectedAuditCategory);
-  }
-
-  _resetResourceCount() {
-    this._loadedResources = 0;
-    this._totalResources = 0;
-  }
-
-  _onRequestStarted(event) {
-    var request = /** @type {!SDK.NetworkRequest} */ (event.data);
-    // Ignore long-living WebSockets for the sake of progress indicator, as we won't be waiting them anyway.
-    if (request.resourceType() === Common.resourceTypes.WebSocket)
-      return;
-    ++this._totalResources;
-    this._updateResourceProgress();
-  }
-
-  _onRequestFinished(event) {
-    var request = /** @type {!SDK.NetworkRequest} */ (event.data);
-    // See resorceStarted for details.
-    if (request.resourceType() === Common.resourceTypes.WebSocket)
-      return;
-    ++this._loadedResources;
-    this._updateResourceProgress();
-  }
-
-  /**
-   * @param {!Audits.AuditCategory} category
-   */
-  addCategory(category) {
-    if (!this._sortedCategories.length)
-      this._createLauncherUI();
-
-    var selectedCategories = this._selectedCategoriesSetting.get();
-    var categoryElement = this._createCategoryElement(category.displayName, category.id);
-    category._checkboxElement = categoryElement.checkboxElement;
-    if (this._selectAllCheckboxElement.checked || selectedCategories[category.displayName]) {
-      category._checkboxElement.checked = true;
-      ++this._currentCategoriesCount;
-    }
-
-    /**
-     * @param {!Audits.AuditCategory} a
-     * @param {!Audits.AuditCategory} b
-     * @return {number}
-     */
-    function compareCategories(a, b) {
-      var aTitle = a.displayName || '';
-      var bTitle = b.displayName || '';
-      return aTitle.localeCompare(bTitle);
-    }
-    var insertBefore = this._sortedCategories.lowerBound(category, compareCategories);
-    this._categoriesElement.insertBefore(categoryElement, this._categoriesElement.children[insertBefore]);
-    this._sortedCategories.splice(insertBefore, 0, category);
-    this._selectedCategoriesUpdated();
-  }
-
-  _startAudit() {
-    this._auditRunning = true;
-    this._updateButton();
-    this._toggleUIComponents(this._auditRunning);
-
-    var catIds = [];
-    for (var category = 0; category < this._sortedCategories.length; ++category) {
-      if (this._sortedCategories[category]._checkboxElement.checked)
-        catIds.push(this._sortedCategories[category].id);
-    }
-
-    this._resetResourceCount();
-    this._progressIndicator = new UI.ProgressIndicator();
-    this._buttonContainerElement.appendChild(this._progressIndicator.element);
-    this._displayResourceLoadingProgress = true;
-
-    /**
-     * @this {Audits.AuditLauncherView}
-     */
-    function onAuditStarted() {
-      this._displayResourceLoadingProgress = false;
-    }
-    this._auditController.initiateAudit(
-        catIds, new Common.ProgressProxy(this._progressIndicator, this._auditsDone.bind(this)),
-        this._auditPresentStateElement.checked, onAuditStarted.bind(this));
-  }
-
-  _auditsDone() {
-    this._displayResourceLoadingProgress = false;
-    delete this._progressIndicator;
-    this._launchButton.disabled = false;
-    this._auditRunning = false;
-    this._updateButton();
-    this._toggleUIComponents(this._auditRunning);
-  }
-
-  /**
-   * @param {boolean} disable
-   */
-  _toggleUIComponents(disable) {
-    this._selectAllCheckboxElement.disabled = disable;
-    for (var child = this._categoriesElement.firstChild; child; child = child.nextSibling)
-      child.checkboxElement.disabled = disable;
-    this._auditPresentStateElement.disabled = disable;
-    this._auditReloadedStateElement.disabled = disable;
-  }
-
-  _launchButtonClicked(event) {
-    if (this._auditRunning) {
-      this._launchButton.disabled = true;
-      this._progressIndicator.cancel();
-      return;
-    }
-    this._startAudit();
-  }
-
-  _clearButtonClicked() {
-    this._auditController.clearResults();
-  }
-
-  /**
-   * @param {boolean} checkCategories
-   * @param {boolean=} userGesture
-   */
-  _selectAllClicked(checkCategories, userGesture) {
-    var childNodes = this._categoriesElement.childNodes;
-    for (var i = 0, length = childNodes.length; i < length; ++i)
-      childNodes[i].checkboxElement.checked = checkCategories;
-    this._currentCategoriesCount = checkCategories ? this._sortedCategories.length : 0;
-    this._selectedCategoriesUpdated(userGesture);
-  }
-
-  _categoryClicked(event) {
-    this._currentCategoriesCount += event.target.checked ? 1 : -1;
-    this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._sortedCategories.length;
-    this._selectedCategoriesUpdated(true);
-  }
-
-  /**
-   * @param {string} title
-   * @param {string=} id
-   */
-  _createCategoryElement(title, id) {
-    var labelElement = UI.CheckboxLabel.create(title);
-    if (id) {
-      labelElement.id = this._categoryIdPrefix + id;
-      labelElement.checkboxElement.addEventListener('click', this._boundCategoryClickListener, false);
-    }
-    /** @type {!Object} */ (labelElement).__displayName = title;
-    return labelElement;
-  }
-
-  _createLauncherUI() {
-    this._headerElement = createElement('h1');
-    this._headerElement.textContent = Common.UIString('Select audits to run');
-
-    this._contentElement.removeChildren();
-    this._contentElement.appendChild(this._headerElement);
-
-    /**
-     * @param {!Event} event
-     * @this {Audits.AuditLauncherView}
-     */
-    function handleSelectAllClick(event) {
-      this._selectAllClicked(event.target.checked, true);
-    }
-    var categoryElement = this._createCategoryElement(Common.UIString('Select All'), '');
-    categoryElement.id = 'audit-launcher-selectall';
-    this._selectAllCheckboxElement = categoryElement.checkboxElement;
-    this._selectAllCheckboxElement.checked =
-        this._selectedCategoriesSetting.get()[Audits.AuditLauncherView.AllCategoriesKey];
-    this._selectAllCheckboxElement.addEventListener('click', handleSelectAllClick.bind(this), false);
-    this._contentElement.appendChild(categoryElement);
-
-    this._categoriesElement = this._contentElement.createChild('fieldset', 'audit-categories-container');
-    this._currentCategoriesCount = 0;
-
-    this._contentElement.createChild('div', 'flexible-space');
-
-    this._buttonContainerElement = this._contentElement.createChild('div', 'button-container');
-
-    var radio = UI.createRadioLabel('audit-mode', Common.UIString('Audit Present State'), true);
-    this._buttonContainerElement.appendChild(radio);
-    this._auditPresentStateElement = radio.radioElement;
-
-    radio = UI.createRadioLabel('audit-mode', Common.UIString('Reload Page and Audit on Load'));
-    this._buttonContainerElement.appendChild(radio);
-    this._auditReloadedStateElement = radio.radioElement;
-
-    this._launchButton = UI.createTextButton(Common.UIString('Run'), this._launchButtonClicked.bind(this));
-    this._buttonContainerElement.appendChild(this._launchButton);
-
-    this._clearButton = UI.createTextButton(Common.UIString('Clear'), this._clearButtonClicked.bind(this));
-    this._buttonContainerElement.appendChild(this._clearButton);
-
-    this._selectAllClicked(this._selectAllCheckboxElement.checked);
-  }
-
-  _updateResourceProgress() {
-    if (this._displayResourceLoadingProgress) {
-      this._progressIndicator.setTitle(
-          Common.UIString('Loading (%d of %d)', this._loadedResources, this._totalResources));
-    }
-  }
-
-  /**
-   * @param {boolean=} userGesture
-   */
-  _selectedCategoriesUpdated(userGesture) {
-    // Save present categories only upon user gesture to clean up junk from past versions and removed extensions.
-    // Do not remove old categories if not handling a user gesture, as there's chance categories will be added
-    // later during start-up.
-    var selectedCategories = userGesture ? {} : this._selectedCategoriesSetting.get();
-    var childNodes = this._categoriesElement.childNodes;
-    for (var i = 0, length = childNodes.length; i < length; ++i)
-      selectedCategories[childNodes[i].__displayName] = childNodes[i].checkboxElement.checked;
-    selectedCategories[Audits.AuditLauncherView.AllCategoriesKey] = this._selectAllCheckboxElement.checked;
-    this._selectedCategoriesSetting.set(selectedCategories);
-    this._updateButton();
-  }
-
-  _updateButton() {
-    this._launchButton.textContent = this._auditRunning ? Common.UIString('Stop') : Common.UIString('Run');
-    this._launchButton.disabled = !this._currentCategoriesCount;
-  }
-};
-
-Audits.AuditLauncherView.AllCategoriesKey = '__AllCategories';
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditResultView.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditResultView.js
deleted file mode 100644
index b90146a6..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditResultView.js
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-
-/**
- * @unrestricted
- */
-Audits.AuditCategoryResultPane = class extends UI.SimpleView {
-  /**
-   * @param {!Audits.AuditCategoryResult} categoryResult
-   */
-  constructor(categoryResult) {
-    super(categoryResult.title);
-    this._treeOutline = new UI.TreeOutlineInShadow();
-    this._treeOutline.registerRequiredCSS('audits/auditResultTree.css');
-    this._treeOutline.element.classList.add('audit-result-tree');
-    this.element.appendChild(this._treeOutline.element);
-    this._treeOutline.expandTreeElementsWhenArrowing = true;
-
-    function ruleSorter(a, b) {
-      var result = Audits.AuditRule.SeverityOrder[a.severity || 0] - Audits.AuditRule.SeverityOrder[b.severity || 0];
-      if (!result)
-        result = (a.value || '').localeCompare(b.value || '');
-      return result;
-    }
-
-    categoryResult.ruleResults.sort(ruleSorter);
-
-    for (var i = 0; i < categoryResult.ruleResults.length; ++i) {
-      var ruleResult = categoryResult.ruleResults[i];
-      var treeElement = this._appendResult(this._treeOutline.rootElement(), ruleResult, ruleResult.severity);
-      treeElement.listItemElement.classList.add('audit-result');
-    }
-    this.revealView();
-  }
-
-  /**
-   * @param {!UI.TreeElement} parentTreeNode
-   * @param {!Audits.AuditRuleResult} result
-   * @param {?Audits.AuditRule.Severity=} severity
-   */
-  _appendResult(parentTreeNode, result, severity) {
-    var title = '';
-
-    if (typeof result.value === 'string') {
-      title = result.value;
-      if (result.violationCount)
-        title = String.sprintf('%s (%d)', title, result.violationCount);
-    }
-
-    var titleFragment = createDocumentFragment();
-    if (severity) {
-      var severityElement = UI.Icon.create();
-      if (severity === Audits.AuditRule.Severity.Info)
-        severityElement.setIconType('smallicon-green-ball');
-      else if (severity === Audits.AuditRule.Severity.Warning)
-        severityElement.setIconType('smallicon-orange-ball');
-      else if (severity === Audits.AuditRule.Severity.Severe)
-        severityElement.setIconType('smallicon-red-ball');
-      severityElement.classList.add('severity');
-      titleFragment.appendChild(severityElement);
-    }
-    titleFragment.createTextChild(title);
-
-    var treeElement = new UI.TreeElement(titleFragment, !!result.children);
-    treeElement.selectable = false;
-    parentTreeNode.appendChild(treeElement);
-
-    if (result.className)
-      treeElement.listItemElement.classList.add(result.className);
-    if (typeof result.value !== 'string')
-      treeElement.listItemElement.appendChild(Audits.auditFormatters.apply(result.value));
-
-    if (result.children) {
-      for (var i = 0; i < result.children.length; ++i)
-        this._appendResult(treeElement, result.children[i]);
-    }
-    if (result.expanded) {
-      treeElement.listItemElement.classList.remove('parent');
-      treeElement.listItemElement.classList.add('parent-expanded');
-      treeElement.expand();
-    }
-    return treeElement;
-  }
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js
deleted file mode 100644
index 3c41ff8..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js
+++ /dev/null
@@ -1,1471 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-Audits.AuditRules.IPAddressRegexp = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
-
-Audits.AuditRules.CacheableResponseCodes = {
-  200: true,
-  203: true,
-  206: true,
-  300: true,
-  301: true,
-  410: true,
-
-  304: true  // Underlying request is cacheable
-};
-
-/**
- * @param {!Array.<!SDK.NetworkRequest>} requests
- * @param {?Array.<!Common.ResourceType>} types
- * @param {boolean} needFullResources
- * @return {!Object.<string, !Array.<!SDK.NetworkRequest|string>>}
- */
-Audits.AuditRules.getDomainToResourcesMap = function(requests, types, needFullResources) {
-  /** @type {!Object<string, !Array<!SDK.NetworkRequest|string>>} */
-  var domainToResourcesMap = {};
-  for (var i = 0, size = requests.length; i < size; ++i) {
-    var request = requests[i];
-    if (types && types.indexOf(request.resourceType()) === -1)
-      continue;
-    var parsedURL = request.url().asParsedURL();
-    if (!parsedURL)
-      continue;
-    var domain = parsedURL.host;
-    var domainResources = domainToResourcesMap[domain];
-    if (domainResources === undefined) {
-      domainResources = /** @type {!Array<!SDK.NetworkRequest|string>} */ ([]);
-      domainToResourcesMap[domain] = domainResources;
-    }
-    domainResources.push(needFullResources ? request : request.url());
-  }
-  return domainToResourcesMap;
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.GzipRule = class extends Audits.AuditRule {
-  constructor() {
-    super('network-gzip', Common.UIString('Enable gzip compression'));
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var totalSavings = 0;
-    var summary = result.addChild('', true);
-    for (var i = 0, length = requests.length; i < length; ++i) {
-      var request = requests[i];
-      if (request.cached() || request.statusCode === 304)
-        continue;  // Do not test cached resources.
-      if (this._shouldCompress(request)) {
-        var size = request.resourceSize;
-        if (this._isCompressed(request))
-          continue;
-        var savings = 2 * size / 3;
-        totalSavings += savings;
-        summary.addFormatted('%r could save ~%s', request.url(), Number.bytesToString(savings));
-        result.violationCount++;
-      }
-    }
-    if (!totalSavings) {
-      callback(null);
-      return;
-    }
-    summary.value = Common.UIString(
-        'Compressing the following resources with gzip could reduce their transfer size by about two thirds (~%s):',
-        Number.bytesToString(totalSavings));
-    callback(result);
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   */
-  _isCompressed(request) {
-    var encodingHeader = request.responseHeaderValue('Content-Encoding');
-    if (!encodingHeader)
-      return false;
-
-    return /\b(?:gzip|deflate)\b/.test(encodingHeader);
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   */
-  _shouldCompress(request) {
-    return request.resourceType().isTextType() && request.parsedURL.host && request.resourceSize !== undefined &&
-        request.resourceSize > 150;
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.CombineExternalResourcesRule = class extends Audits.AuditRule {
-  /**
-   * @param {string} id
-   * @param {string} name
-   * @param {!Common.ResourceType} type
-   * @param {string} resourceTypeName
-   * @param {boolean} allowedPerDomain
-   */
-  constructor(id, name, type, resourceTypeName, allowedPerDomain) {
-    super(id, name);
-    this._type = type;
-    this._resourceTypeName = resourceTypeName;
-    this._allowedPerDomain = allowedPerDomain;
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap(requests, [this._type], false);
-    var penalizedResourceCount = 0;
-    // TODO: refactor according to the chosen i18n approach
-    var summary = result.addChild('', true);
-    for (var domain in domainToResourcesMap) {
-      var domainResources = domainToResourcesMap[domain];
-      var extraResourceCount = domainResources.length - this._allowedPerDomain;
-      if (extraResourceCount <= 0)
-        continue;
-      penalizedResourceCount += extraResourceCount - 1;
-      summary.addChild(Common.UIString(
-          '%d %s resources served from %s.', domainResources.length, this._resourceTypeName,
-          Audits.AuditRuleResult.resourceDomain(domain)));
-      result.violationCount += domainResources.length;
-    }
-    if (!penalizedResourceCount) {
-      callback(null);
-      return;
-    }
-
-    summary.value = Common.UIString(
-        'There are multiple resources served from same domain. Consider combining them into as few files as possible.');
-    callback(result);
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.CombineJsResourcesRule = class extends Audits.AuditRules.CombineExternalResourcesRule {
-  constructor(allowedPerDomain) {
-    super(
-        'page-externaljs', Common.UIString('Combine external JavaScript'), Common.resourceTypes.Script, 'JavaScript',
-        allowedPerDomain);
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.CombineCssResourcesRule = class extends Audits.AuditRules.CombineExternalResourcesRule {
-  constructor(allowedPerDomain) {
-    super(
-        'page-externalcss', Common.UIString('Combine external CSS'), Common.resourceTypes.Stylesheet, 'CSS',
-        allowedPerDomain);
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.MinimizeDnsLookupsRule = class extends Audits.AuditRule {
-  constructor(hostCountThreshold) {
-    super('network-minimizelookups', Common.UIString('Minimize DNS lookups'));
-    this._hostCountThreshold = hostCountThreshold;
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var summary = result.addChild('');
-    var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap(requests, null, false);
-    for (var domain in domainToResourcesMap) {
-      if (domainToResourcesMap[domain].length > 1)
-        continue;
-      var parsedURL = domain.asParsedURL();
-      if (!parsedURL)
-        continue;
-      if (!parsedURL.host.search(Audits.AuditRules.IPAddressRegexp))
-        continue;  // an IP address
-      summary.addSnippet(domain);
-      result.violationCount++;
-    }
-    if (!summary.children || summary.children.length <= this._hostCountThreshold) {
-      callback(null);
-      return;
-    }
-
-    summary.value = Common.UIString(
-        'The following domains only serve one resource each. If possible, avoid the extra DNS lookups by serving these resources from existing domains.');
-    callback(result);
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.ParallelizeDownloadRule = class extends Audits.AuditRule {
-  constructor(optimalHostnameCount, minRequestThreshold, minBalanceThreshold) {
-    super('network-parallelizehosts', Common.UIString('Parallelize downloads across hostnames'));
-    this._optimalHostnameCount = optimalHostnameCount;
-    this._minRequestThreshold = minRequestThreshold;
-    this._minBalanceThreshold = minBalanceThreshold;
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    /**
-     * @param {string} a
-     * @param {string} b
-     */
-    function hostSorter(a, b) {
-      var aCount = domainToResourcesMap[a].length;
-      var bCount = domainToResourcesMap[b].length;
-      return (aCount < bCount) ? 1 : (aCount === bCount) ? 0 : -1;
-    }
-
-    var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap(
-        requests, [Common.resourceTypes.Stylesheet, Common.resourceTypes.Image], true);
-
-    var hosts = [];
-    for (var url in domainToResourcesMap)
-      hosts.push(url);
-
-    if (!hosts.length) {
-      callback(null);  // no hosts (local file or something)
-      return;
-    }
-
-    hosts.sort(hostSorter);
-
-    var optimalHostnameCount = this._optimalHostnameCount;
-    if (hosts.length > optimalHostnameCount)
-      hosts.splice(optimalHostnameCount);
-
-    var busiestHostResourceCount = domainToResourcesMap[hosts[0]].length;
-    var requestCountAboveThreshold = busiestHostResourceCount - this._minRequestThreshold;
-    if (requestCountAboveThreshold <= 0) {
-      callback(null);
-      return;
-    }
-
-    var avgResourcesPerHost = 0;
-    for (var i = 0, size = hosts.length; i < size; ++i)
-      avgResourcesPerHost += domainToResourcesMap[hosts[i]].length;
-
-    // Assume optimal parallelization.
-    avgResourcesPerHost /= optimalHostnameCount;
-    avgResourcesPerHost = Math.max(avgResourcesPerHost, 1);
-
-    var pctAboveAvg = (requestCountAboveThreshold / avgResourcesPerHost) - 1.0;
-    var minBalanceThreshold = this._minBalanceThreshold;
-    if (pctAboveAvg < minBalanceThreshold) {
-      callback(null);
-      return;
-    }
-
-    var requestsOnBusiestHost = domainToResourcesMap[hosts[0]];
-    var entry = result.addChild(
-        Common.UIString(
-            'This page makes %d parallelizable requests to %s. Increase download parallelization by distributing the following requests across multiple hostnames.',
-            busiestHostResourceCount, hosts[0]),
-        true);
-    for (var i = 0; i < requestsOnBusiestHost.length; ++i)
-      entry.addURL(requestsOnBusiestHost[i].url());
-
-    result.violationCount = requestsOnBusiestHost.length;
-    callback(result);
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.UnusedCssRule = class extends Audits.AuditRule {
-  /**
-   * The reported CSS rule size is incorrect (parsed != original in WebKit),
-   * so use percentages instead, which gives a better approximation.
-   */
-  constructor() {
-    super('page-unusedcss', Common.UIString('Remove unused CSS rules'));
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var domModel = target.model(SDK.DOMModel);
-    var cssModel = target.model(SDK.CSSModel);
-    if (!domModel || !cssModel) {
-      callback(null);
-      return;
-    }
-
-    /**
-     * @param {!Array.<!Audits.AuditRules.ParsedStyleSheet>} styleSheets
-     */
-    function evalCallback(styleSheets) {
-      if (!styleSheets.length)
-        return callback(null);
-
-      var selectors = [];
-      var testedSelectors = {};
-      for (var i = 0; i < styleSheets.length; ++i) {
-        var styleSheet = styleSheets[i];
-        for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) {
-          var selectorText = styleSheet.rules[curRule].selectorText;
-          if (testedSelectors[selectorText])
-            continue;
-          selectors.push(selectorText);
-          testedSelectors[selectorText] = 1;
-        }
-      }
-
-      var foundSelectors = {};
-
-      /**
-       * @param {!Array.<!Audits.AuditRules.ParsedStyleSheet>} styleSheets
-       */
-      function selectorsCallback(styleSheets) {
-        if (progress.isCanceled()) {
-          callback(null);
-          return;
-        }
-
-        var inlineBlockOrdinal = 0;
-        var totalStylesheetSize = 0;
-        var totalUnusedStylesheetSize = 0;
-        var summary;
-
-        for (var i = 0; i < styleSheets.length; ++i) {
-          var styleSheet = styleSheets[i];
-          var unusedRules = [];
-          for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) {
-            var rule = styleSheet.rules[curRule];
-            if (!testedSelectors[rule.selectorText] || foundSelectors[rule.selectorText])
-              continue;
-            unusedRules.push(rule.selectorText);
-          }
-          totalStylesheetSize += styleSheet.rules.length;
-          totalUnusedStylesheetSize += unusedRules.length;
-
-          if (!unusedRules.length)
-            continue;
-
-          var resource = Bindings.resourceForURL(styleSheet.sourceURL);
-          var isInlineBlock =
-              resource && resource.request && resource.request.resourceType() === Common.resourceTypes.Document;
-          var url = !isInlineBlock ? Audits.AuditRuleResult.linkifyDisplayName(styleSheet.sourceURL) :
-                                     Common.UIString('Inline block #%d', ++inlineBlockOrdinal);
-          var pctUnused = Math.round(100 * unusedRules.length / styleSheet.rules.length);
-          if (!summary)
-            summary = result.addChild('', true);
-          var entry = summary.addFormatted('%s: %d% is not used by the current page.', url, pctUnused);
-
-          for (var j = 0; j < unusedRules.length; ++j)
-            entry.addSnippet(unusedRules[j]);
-
-          result.violationCount += unusedRules.length;
-        }
-
-        if (!totalUnusedStylesheetSize)
-          return callback(null);
-
-        var totalUnusedPercent = Math.round(100 * totalUnusedStylesheetSize / totalStylesheetSize);
-        summary.value = Common.UIString(
-            '%s rules (%d%) of CSS not used by the current page.', totalUnusedStylesheetSize, totalUnusedPercent);
-
-        callback(result);
-      }
-
-      /**
-       * @param {?function()} boundSelectorsCallback
-       * @param {string} selector
-       * @param {?Protocol.DOM.NodeId} nodeId
-       */
-      function queryCallback(boundSelectorsCallback, selector, nodeId) {
-        if (nodeId)
-          foundSelectors[selector] = true;
-        if (boundSelectorsCallback)
-          boundSelectorsCallback();
-      }
-
-      /**
-       * @param {!Array.<string>} selectors
-       * @param {!SDK.DOMDocument} document
-       */
-      function documentLoaded(selectors, document) {
-        var pseudoSelectorRegexp = /::?(?:[\w-]+)(?:\(.*?\))?/g;
-        if (!selectors.length) {
-          selectorsCallback([]);
-          return;
-        }
-        for (var i = 0; i < selectors.length; ++i) {
-          if (progress.isCanceled()) {
-            callback(null);
-            return;
-          }
-          var effectiveSelector = selectors[i].replace(pseudoSelectorRegexp, '');
-          domModel.querySelector(document.id, effectiveSelector)
-              .then(queryCallback.bind(
-                  null, i === selectors.length - 1 ? selectorsCallback.bind(null, styleSheets) : null, selectors[i]));
-        }
-      }
-
-      domModel.requestDocumentPromise().then(documentLoaded.bind(null, selectors));
-    }
-
-    var styleSheetInfos = cssModel.allStyleSheets();
-    if (!styleSheetInfos || !styleSheetInfos.length) {
-      evalCallback([]);
-      return;
-    }
-    var styleSheetProcessor = new Audits.AuditRules.StyleSheetProcessor(styleSheetInfos, progress, evalCallback);
-    styleSheetProcessor.run();
-  }
-};
-
-/**
- * @typedef {!{sourceURL: string, rules: !Array.<!Formatter.FormatterWorkerPool.CSSStyleRule>}}
- */
-Audits.AuditRules.ParsedStyleSheet;
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.StyleSheetProcessor = class {
-  /**
-   * @param {!Array.<!SDK.CSSStyleSheetHeader>} styleSheetHeaders
-   * @param {!Common.Progress} progress
-   * @param {function(!Array.<!Audits.AuditRules.ParsedStyleSheet>)} styleSheetsParsedCallback
-   */
-  constructor(styleSheetHeaders, progress, styleSheetsParsedCallback) {
-    this._styleSheetHeaders = styleSheetHeaders;
-    this._progress = progress;
-    this._styleSheets = [];
-    this._styleSheetsParsedCallback = styleSheetsParsedCallback;
-  }
-
-  run() {
-    this._processNextStyleSheet();
-  }
-
-  _processNextStyleSheet() {
-    if (!this._styleSheetHeaders.length) {
-      this._styleSheetsParsedCallback(this._styleSheets);
-      return;
-    }
-    this._currentStyleSheetHeader = this._styleSheetHeaders.shift();
-
-    var allRules = [];
-    this._currentStyleSheetHeader.requestContent().then(
-        content => Formatter.formatterWorkerPool().parseCSS(content || '', onRulesParsed.bind(this)));
-
-    /**
-     * @param {boolean} isLastChunk
-     * @param {!Array<!Formatter.FormatterWorkerPool.CSSRule>} rules
-     * @this {Audits.AuditRules.StyleSheetProcessor}
-     */
-    function onRulesParsed(isLastChunk, rules) {
-      allRules.push(...rules);
-      if (isLastChunk)
-        this._onStyleSheetParsed(allRules);
-    }
-  }
-
-  /**
-   * @param {!Array.<!Formatter.FormatterWorkerPool.CSSRule>} rules
-   */
-  _onStyleSheetParsed(rules) {
-    if (this._progress.isCanceled()) {
-      this._styleSheetsParsedCallback(this._styleSheets);
-      return;
-    }
-
-    var styleRules = [];
-    for (var i = 0; i < rules.length; ++i) {
-      var rule = rules[i];
-      if (rule.selectorText)
-        styleRules.push(rule);
-    }
-    this._styleSheets.push({sourceURL: this._currentStyleSheetHeader.sourceURL, rules: styleRules});
-    this._processNextStyleSheet();
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.CacheControlRule = class extends Audits.AuditRule {
-  constructor(id, name) {
-    super(id, name);
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(!Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var cacheableAndNonCacheableResources = this._cacheableAndNonCacheableResources(requests);
-    if (cacheableAndNonCacheableResources[0].length)
-      this.runChecks(cacheableAndNonCacheableResources[0], result);
-    this.handleNonCacheableResources(cacheableAndNonCacheableResources[1], result);
-
-    callback(result);
-  }
-
-  handleNonCacheableResources(requests, result) {
-  }
-
-  _cacheableAndNonCacheableResources(requests) {
-    var processedResources = [[], []];
-    for (var i = 0; i < requests.length; ++i) {
-      var request = requests[i];
-      if (!this.isCacheableResource(request))
-        continue;
-      if (this._isExplicitlyNonCacheable(request))
-        processedResources[1].push(request);
-      else
-        processedResources[0].push(request);
-    }
-    return processedResources;
-  }
-
-  execCheck(messageText, requestCheckFunction, requests, result) {
-    var requestCount = requests.length;
-    var urls = [];
-    for (var i = 0; i < requestCount; ++i) {
-      if (requestCheckFunction.call(this, requests[i]))
-        urls.push(requests[i].url());
-    }
-    if (urls.length) {
-      var entry = result.addChild(messageText, true);
-      entry.addURLs(urls);
-      result.violationCount += urls.length;
-    }
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   * @param {number} timeMs
-   * @return {boolean}
-   */
-  freshnessLifetimeGreaterThan(request, timeMs) {
-    var dateHeader = this.responseHeader(request, 'Date');
-    if (!dateHeader)
-      return false;
-
-    var dateHeaderMs = Date.parse(dateHeader);
-    if (isNaN(dateHeaderMs))
-      return false;
-
-    var freshnessLifetimeMs;
-    var maxAgeMatch = this.responseHeaderMatch(request, 'Cache-Control', 'max-age=(\\d+)');
-
-    if (maxAgeMatch) {
-      freshnessLifetimeMs = (maxAgeMatch[1]) ? 1000 * maxAgeMatch[1] : 0;
-    } else {
-      var expiresHeader = this.responseHeader(request, 'Expires');
-      if (expiresHeader) {
-        var expDate = Date.parse(expiresHeader);
-        if (!isNaN(expDate))
-          freshnessLifetimeMs = expDate - dateHeaderMs;
-      }
-    }
-
-    return (isNaN(freshnessLifetimeMs)) ? false : freshnessLifetimeMs > timeMs;
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   * @param {string} header
-   * @return {string|undefined}
-   */
-  responseHeader(request, header) {
-    return request.responseHeaderValue(header);
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   * @param {string} header
-   * @return {boolean}
-   */
-  hasResponseHeader(request, header) {
-    return request.responseHeaderValue(header) !== undefined;
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   * @return {boolean}
-   */
-  isCompressible(request) {
-    return request.resourceType().isTextType();
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   * @return {boolean}
-   */
-  isPubliclyCacheable(request) {
-    if (this._isExplicitlyNonCacheable(request))
-      return false;
-
-    if (this.responseHeaderMatch(request, 'Cache-Control', 'public'))
-      return true;
-
-    return request.url().indexOf('?') === -1 && !this.responseHeaderMatch(request, 'Cache-Control', 'private');
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   * @param {string} header
-   * @param {string} regexp
-   * @return {?Array.<string>}
-   */
-  responseHeaderMatch(request, header, regexp) {
-    return request.responseHeaderValue(header) ? request.responseHeaderValue(header).match(new RegExp(regexp, 'im')) :
-                                                 null;
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   * @return {boolean}
-   */
-  hasExplicitExpiration(request) {
-    return this.hasResponseHeader(request, 'Date') &&
-        (this.hasResponseHeader(request, 'Expires') || !!this.responseHeaderMatch(request, 'Cache-Control', 'max-age'));
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   * @return {boolean}
-   */
-  _isExplicitlyNonCacheable(request) {
-    var hasExplicitExp = this.hasExplicitExpiration(request);
-    return !!(
-        !!this.responseHeaderMatch(request, 'Cache-Control', '(no-cache|no-store)') ||
-        !!this.responseHeaderMatch(request, 'Pragma', 'no-cache') ||
-        (hasExplicitExp && !this.freshnessLifetimeGreaterThan(request, 0)) ||
-        (!hasExplicitExp && request.url() && request.url().indexOf('?') >= 0) ||
-        (!hasExplicitExp && !this.isCacheableResource(request)));
-  }
-
-  /**
-   * @param {!SDK.NetworkRequest} request
-   * @return {boolean}
-   */
-  isCacheableResource(request) {
-    return request.statusCode !== undefined && Audits.AuditRules.CacheableResponseCodes[request.statusCode];
-  }
-};
-
-Audits.AuditRules.CacheControlRule.MillisPerMonth = 1000 * 60 * 60 * 24 * 30;
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.BrowserCacheControlRule = class extends Audits.AuditRules.CacheControlRule {
-  constructor() {
-    super('http-browsercache', Common.UIString('Leverage browser caching'));
-  }
-
-  /**
-   * @override
-   */
-  handleNonCacheableResources(requests, result) {
-    if (requests.length) {
-      var entry = result.addChild(
-          Common.UIString(
-              'The following resources are explicitly non-cacheable. Consider making them cacheable if possible:'),
-          true);
-      result.violationCount += requests.length;
-      for (var i = 0; i < requests.length; ++i)
-        entry.addURL(requests[i].url());
-    }
-  }
-
-  runChecks(requests, result, callback) {
-    this.execCheck(
-        Common.UIString(
-            'The following resources are missing a cache expiration. Resources that do not specify an expiration may not be cached by browsers:'),
-        this._missingExpirationCheck, requests, result);
-    this.execCheck(
-        Common.UIString(
-            'The following resources specify a "Vary" header that disables caching in most versions of Internet Explorer:'),
-        this._varyCheck, requests, result);
-    this.execCheck(
-        Common.UIString('The following cacheable resources have a short freshness lifetime:'),
-        this._oneMonthExpirationCheck, requests, result);
-
-    // Unable to implement the favicon check due to the WebKit limitations.
-    this.execCheck(
-        Common.UIString(
-            'To further improve cache hit rate, specify an expiration one year in the future for the following cacheable resources:'),
-        this._oneYearExpirationCheck, requests, result);
-  }
-
-  _missingExpirationCheck(request) {
-    return this.isCacheableResource(request) && !this.hasResponseHeader(request, 'Set-Cookie') &&
-        !this.hasExplicitExpiration(request);
-  }
-
-  _varyCheck(request) {
-    var varyHeader = this.responseHeader(request, 'Vary');
-    if (varyHeader) {
-      varyHeader = varyHeader.replace(/User-Agent/gi, '');
-      varyHeader = varyHeader.replace(/Accept-Encoding/gi, '');
-      varyHeader = varyHeader.replace(/[, ]*/g, '');
-    }
-    return varyHeader && varyHeader.length && this.isCacheableResource(request) &&
-        this.freshnessLifetimeGreaterThan(request, 0);
-  }
-
-  _oneMonthExpirationCheck(request) {
-    return this.isCacheableResource(request) && !this.hasResponseHeader(request, 'Set-Cookie') &&
-        !this.freshnessLifetimeGreaterThan(request, Audits.AuditRules.CacheControlRule.MillisPerMonth) &&
-        this.freshnessLifetimeGreaterThan(request, 0);
-  }
-
-  _oneYearExpirationCheck(request) {
-    return this.isCacheableResource(request) && !this.hasResponseHeader(request, 'Set-Cookie') &&
-        !this.freshnessLifetimeGreaterThan(request, 11 * Audits.AuditRules.CacheControlRule.MillisPerMonth) &&
-        this.freshnessLifetimeGreaterThan(request, Audits.AuditRules.CacheControlRule.MillisPerMonth);
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.ImageDimensionsRule = class extends Audits.AuditRule {
-  constructor() {
-    super('page-imagedims', Common.UIString('Specify image dimensions'));
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var domModel = target.model(SDK.DOMModel);
-    var cssModel = target.model(SDK.CSSModel);
-    if (!domModel || !cssModel) {
-      callback(null);
-      return;
-    }
-
-    var urlToNoDimensionCount = {};
-
-    function doneCallback() {
-      for (var url in urlToNoDimensionCount) {
-        var entry = entry ||
-            result.addChild(
-                Common.UIString(
-                    'A width and height should be specified for all images in order to speed up page display. The following image(s) are missing a width and/or height:'),
-                true);
-        var format = '%r';
-        if (urlToNoDimensionCount[url] > 1)
-          format += ' (%d uses)';
-        entry.addFormatted(format, url, urlToNoDimensionCount[url]);
-        result.violationCount++;
-      }
-      callback(entry ? result : null);
-    }
-
-    function imageStylesReady(imageId, styles) {
-      if (progress.isCanceled()) {
-        callback(null);
-        return;
-      }
-
-      const node = domModel.nodeForId(imageId);
-      var src = node.getAttribute('src');
-      if (!src.asParsedURL()) {
-        for (var frameOwnerCandidate = node; frameOwnerCandidate;
-             frameOwnerCandidate = frameOwnerCandidate.parentNode) {
-          if (frameOwnerCandidate.baseURL) {
-            var completeSrc = Common.ParsedURL.completeURL(frameOwnerCandidate.baseURL, src);
-            break;
-          }
-        }
-      }
-      if (completeSrc)
-        src = completeSrc;
-
-      if (styles.computedStyle.get('position') === 'absolute')
-        return;
-
-      var widthFound = false;
-      var heightFound = false;
-      for (var i = 0; !(widthFound && heightFound) && i < styles.nodeStyles.length; ++i) {
-        var style = styles.nodeStyles[i];
-        if (style.getPropertyValue('width') !== '')
-          widthFound = true;
-        if (style.getPropertyValue('height') !== '')
-          heightFound = true;
-      }
-
-      if (!widthFound || !heightFound) {
-        if (src in urlToNoDimensionCount)
-          ++urlToNoDimensionCount[src];
-        else
-          urlToNoDimensionCount[src] = 1;
-      }
-    }
-
-    /**
-     * @param {?Array<!Protocol.DOM.NodeId>} nodeIds
-     */
-    function getStyles(nodeIds) {
-      if (progress.isCanceled()) {
-        callback(null);
-        return;
-      }
-      var targetResult = {};
-
-      /**
-       * @param {?SDK.CSSMatchedStyles} matchedStyleResult
-       */
-      function matchedCallback(matchedStyleResult) {
-        if (!matchedStyleResult)
-          return;
-        targetResult.nodeStyles = matchedStyleResult.nodeStyles();
-      }
-
-      /**
-       * @param {?Map.<string, string>} computedStyle
-       */
-      function computedCallback(computedStyle) {
-        targetResult.computedStyle = computedStyle;
-      }
-
-      if (!nodeIds || !nodeIds.length)
-        doneCallback();
-
-      var nodePromises = [];
-      for (var i = 0; nodeIds && i < nodeIds.length; ++i) {
-        var stylePromises = [
-          cssModel.matchedStylesPromise(nodeIds[i]).then(matchedCallback),
-          cssModel.computedStylePromise(nodeIds[i]).then(computedCallback)
-        ];
-        var nodePromise = Promise.all(stylePromises).then(imageStylesReady.bind(null, nodeIds[i], targetResult));
-        nodePromises.push(nodePromise);
-      }
-      Promise.all(nodePromises).catchException(null).then(doneCallback);
-    }
-
-    function onDocumentAvailable(root) {
-      if (progress.isCanceled()) {
-        callback(null);
-        return;
-      }
-      domModel.querySelectorAll(root.id, 'img[src]').then(getStyles);
-    }
-
-    if (progress.isCanceled()) {
-      callback(null);
-      return;
-    }
-    domModel.requestDocumentPromise().then(onDocumentAvailable);
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.CssInHeadRule = class extends Audits.AuditRule {
-  constructor() {
-    super('page-cssinhead', Common.UIString('Put CSS in the document head'));
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var domModel = target.model(SDK.DOMModel);
-    if (!domModel) {
-      callback(null);
-      return;
-    }
-
-    function evalCallback(evalResult) {
-      if (progress.isCanceled()) {
-        callback(null);
-        return;
-      }
-
-      if (!evalResult)
-        return callback(null);
-
-      var summary = result.addChild('');
-
-      for (var url in evalResult) {
-        var urlViolations = evalResult[url];
-        if (urlViolations[0]) {
-          result.addFormatted(
-              '%s style block(s) in the %r body should be moved to the document head.', urlViolations[0], url);
-          result.violationCount += urlViolations[0];
-        }
-        for (var i = 0; i < urlViolations[1].length; ++i)
-          result.addFormatted('Link node %r should be moved to the document head in %r', urlViolations[1][i], url);
-        result.violationCount += urlViolations[1].length;
-      }
-      summary.value = Common.UIString('CSS in the document body adversely impacts rendering performance.');
-      callback(result);
-    }
-
-    /**
-     * @param {!SDK.DOMNode} root
-     * @param {!Array<!Protocol.DOM.NodeId>} inlineStyleNodeIds
-     * @param {?Array<!Protocol.DOM.NodeId>} nodeIds
-     */
-    function externalStylesheetsReceived(root, inlineStyleNodeIds, nodeIds) {
-      if (progress.isCanceled()) {
-        callback(null);
-        return;
-      }
-
-      if (!nodeIds)
-        return;
-      var externalStylesheetNodeIds = nodeIds;
-      var result = null;
-      if (inlineStyleNodeIds.length || externalStylesheetNodeIds.length) {
-        var urlToViolationsArray = {};
-        var externalStylesheetHrefs = [];
-        for (var j = 0; j < externalStylesheetNodeIds.length; ++j) {
-          var linkNode = domModel.nodeForId(externalStylesheetNodeIds[j]);
-          var completeHref =
-              Common.ParsedURL.completeURL(linkNode.ownerDocument.baseURL, linkNode.getAttribute('href'));
-          externalStylesheetHrefs.push(completeHref || '<empty>');
-        }
-        urlToViolationsArray[root.documentURL] = [inlineStyleNodeIds.length, externalStylesheetHrefs];
-        result = urlToViolationsArray;
-      }
-      evalCallback(result);
-    }
-
-    /**
-     * @param {!SDK.DOMNode} root
-     * @param {?Array<!Protocol.DOM.NodeId>} nodeIds
-     */
-    function inlineStylesReceived(root, nodeIds) {
-      if (progress.isCanceled()) {
-        callback(null);
-        return;
-      }
-
-      if (!nodeIds)
-        return;
-      domModel.querySelectorAll(root.id, 'body link[rel~=\'stylesheet\'][href]')
-          .then(externalStylesheetsReceived.bind(null, root, nodeIds));
-    }
-
-    /**
-     * @param {!SDK.DOMNode} root
-     */
-    function onDocumentAvailable(root) {
-      if (progress.isCanceled()) {
-        callback(null);
-        return;
-      }
-
-      domModel.querySelectorAll(root.id, 'body style').then(inlineStylesReceived.bind(null, root));
-    }
-
-    domModel.requestDocumentPromise().then(onDocumentAvailable);
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.StylesScriptsOrderRule = class extends Audits.AuditRule {
-  constructor() {
-    super('page-stylescriptorder', Common.UIString('Optimize the order of styles and scripts'));
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var domModel = target.model(SDK.DOMModel);
-    if (!domModel) {
-      callback(null);
-      return;
-    }
-
-    domModel.requestDocumentPromise().then(onDocumentAvailable).then(callback);
-
-    /**
-     * @param {!SDK.DOMDocument} root
-     * @return {!Promise<?Audits.AuditRuleResult>}
-     */
-    async function onDocumentAvailable(root) {
-      if (progress.isCanceled())
-        return null;
-
-      var lateStyleIds = await domModel.querySelectorAll(root.id, 'head script[src] ~ link[rel~=\'stylesheet\'][href]');
-
-      if (progress.isCanceled())
-        return null;
-      if (!lateStyleIds)
-        return null;
-
-      var nodeIds =
-          await domModel.querySelectorAll(root.id, 'head link[rel~=\'stylesheet\'][href] ~ script:not([src])');
-
-      if (progress.isCanceled())
-        return null;
-      if (!nodeIds)
-        return null;
-
-      var cssBeforeInlineCount = nodeIds.length;
-      var resultValue = null;
-      if (lateStyleIds.length || cssBeforeInlineCount) {
-        var lateStyleUrls = [];
-        for (var i = 0; i < lateStyleIds.length; ++i) {
-          var lateStyleNode = domModel.nodeForId(lateStyleIds[i]);
-          var completeHref =
-              Common.ParsedURL.completeURL(lateStyleNode.ownerDocument.baseURL, lateStyleNode.getAttribute('href'));
-          lateStyleUrls.push(completeHref || '<empty>');
-        }
-        resultValue = [lateStyleUrls, cssBeforeInlineCount];
-      }
-
-      if (progress.isCanceled())
-        return null;
-      if (!resultValue)
-        return null;
-
-      var lateCssUrls = resultValue[0];
-      cssBeforeInlineCount = resultValue[1];
-
-      if (lateCssUrls.length) {
-        var entry = result.addChild(
-            Common.UIString(
-                'The following external CSS files were included after an external JavaScript file in the ' +
-                'document head. To ensure CSS files are downloaded in parallel, always include external CSS ' +
-                'before external JavaScript.'),
-            true);
-        entry.addURLs(lateCssUrls);
-        result.violationCount += lateCssUrls.length;
-      }
-
-      if (cssBeforeInlineCount) {
-        result.addChild(Common.UIString(
-            ' %d inline script %s found in the head between an external CSS file and another resource. ' +
-                'To allow parallel downloading, move the inline script before the external CSS file, ' +
-                'or after the next resource.',
-            cssBeforeInlineCount, cssBeforeInlineCount > 1 ? 'blocks were' : 'block was'));
-        result.violationCount += cssBeforeInlineCount;
-      }
-      return result;
-    }
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.CSSRuleBase = class extends Audits.AuditRule {
-  constructor(id, name) {
-    super(id, name);
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var cssModel = target.model(SDK.CSSModel);
-    if (!cssModel) {
-      callback(null);
-      return;
-    }
-
-    var headers = cssModel.allStyleSheets();
-    if (!headers.length) {
-      callback(null);
-      return;
-    }
-    var activeHeaders = [];
-    for (var i = 0; i < headers.length; ++i) {
-      if (!headers[i].disabled)
-        activeHeaders.push(headers[i]);
-    }
-
-    var styleSheetProcessor = new Audits.AuditRules.StyleSheetProcessor(
-        activeHeaders, progress, this._styleSheetsLoaded.bind(this, result, callback, progress));
-    styleSheetProcessor.run();
-  }
-
-  /**
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(!Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   * @param {!Array.<!Audits.AuditRules.ParsedStyleSheet>} styleSheets
-   */
-  _styleSheetsLoaded(result, callback, progress, styleSheets) {
-    for (var i = 0; i < styleSheets.length; ++i)
-      this._visitStyleSheet(styleSheets[i], result);
-    callback(result);
-  }
-
-  /**
-   * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet
-   * @param {!Audits.AuditRuleResult} result
-   */
-  _visitStyleSheet(styleSheet, result) {
-    this.visitStyleSheet(styleSheet, result);
-
-    for (var i = 0; i < styleSheet.rules.length; ++i)
-      this._visitRule(styleSheet, styleSheet.rules[i], result);
-
-    this.didVisitStyleSheet(styleSheet, result);
-  }
-
-  /**
-   * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet
-   * @param {!Formatter.FormatterWorkerPool.CSSStyleRule} rule
-   * @param {!Audits.AuditRuleResult} result
-   */
-  _visitRule(styleSheet, rule, result) {
-    this.visitRule(styleSheet, rule, result);
-    var allProperties = rule.properties;
-    for (var i = 0; i < allProperties.length; ++i)
-      this.visitProperty(styleSheet, rule, allProperties[i], result);
-    this.didVisitRule(styleSheet, rule, result);
-  }
-
-  /**
-   * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet
-   * @param {!Audits.AuditRuleResult} result
-   */
-  visitStyleSheet(styleSheet, result) {
-    // Subclasses can implement.
-  }
-
-  /**
-   * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet
-   * @param {!Audits.AuditRuleResult} result
-   */
-  didVisitStyleSheet(styleSheet, result) {
-    // Subclasses can implement.
-  }
-
-  /**
-   * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet
-   * @param {!Formatter.FormatterWorkerPool.CSSStyleRule} rule
-   * @param {!Audits.AuditRuleResult} result
-   */
-  visitRule(styleSheet, rule, result) {
-    // Subclasses can implement.
-  }
-
-  /**
-   * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet
-   * @param {!Formatter.FormatterWorkerPool.CSSStyleRule} rule
-   * @param {!Audits.AuditRuleResult} result
-   */
-  didVisitRule(styleSheet, rule, result) {
-    // Subclasses can implement.
-  }
-
-  /**
-   * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet
-   * @param {!Formatter.FormatterWorkerPool.CSSStyleRule} rule
-   * @param {!Formatter.FormatterWorkerPool.CSSProperty} property
-   * @param {!Audits.AuditRuleResult} result
-   */
-  visitProperty(styleSheet, rule, property, result) {
-    // Subclasses can implement.
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.CookieRuleBase = class extends Audits.AuditRule {
-  constructor(id, name) {
-    super(id, name);
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(!Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    var self = this;
-    function resultCallback(receivedCookies) {
-      if (progress.isCanceled()) {
-        callback(result);
-        return;
-      }
-
-      self.processCookies(receivedCookies, requests, result);
-      callback(result);
-    }
-
-    const nonDataUrls = requests.map(r => r.url()).filter(url => url && url.asParsedURL());
-    var cookieModel = target.model(SDK.CookieModel);
-    if (cookieModel)
-      cookieModel.getCookies(nonDataUrls).then(resultCallback);
-    else
-      callback(result);
-  }
-
-  mapResourceCookies(requestsByDomain, allCookies, callback) {
-    for (var i = 0; i < allCookies.length; ++i) {
-      for (var requestDomain in requestsByDomain) {
-        if (SDK.CookieModel.cookieDomainMatchesResourceDomain(allCookies[i].domain(), requestDomain))
-          this._callbackForResourceCookiePairs(requestsByDomain[requestDomain], allCookies[i], callback);
-      }
-    }
-  }
-
-  _callbackForResourceCookiePairs(requests, cookie, callback) {
-    if (!requests)
-      return;
-    for (var i = 0; i < requests.length; ++i) {
-      if (SDK.CookieModel.cookieMatchesResourceURL(cookie, requests[i].url()))
-        callback(requests[i], cookie);
-    }
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.CookieSizeRule = class extends Audits.AuditRules.CookieRuleBase {
-  constructor(avgBytesThreshold) {
-    super('http-cookiesize', Common.UIString('Minimize cookie size'));
-    this._avgBytesThreshold = avgBytesThreshold;
-    this._maxBytesThreshold = 1000;
-  }
-
-  _average(cookieArray) {
-    var total = 0;
-    for (var i = 0; i < cookieArray.length; ++i)
-      total += cookieArray[i].size();
-    return cookieArray.length ? Math.round(total / cookieArray.length) : 0;
-  }
-
-  _max(cookieArray) {
-    var result = 0;
-    for (var i = 0; i < cookieArray.length; ++i)
-      result = Math.max(cookieArray[i].size(), result);
-    return result;
-  }
-
-  processCookies(allCookies, requests, result) {
-    function maxSizeSorter(a, b) {
-      return b.maxCookieSize - a.maxCookieSize;
-    }
-
-    function avgSizeSorter(a, b) {
-      return b.avgCookieSize - a.avgCookieSize;
-    }
-
-    var cookiesPerResourceDomain = {};
-
-    function collectorCallback(request, cookie) {
-      var cookies = cookiesPerResourceDomain[request.parsedURL.host];
-      if (!cookies) {
-        cookies = [];
-        cookiesPerResourceDomain[request.parsedURL.host] = cookies;
-      }
-      cookies.push(cookie);
-    }
-
-    if (!allCookies.length)
-      return;
-
-    var sortedCookieSizes = [];
-
-    var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap(requests, null, true);
-    this.mapResourceCookies(domainToResourcesMap, allCookies, collectorCallback);
-
-    for (var requestDomain in cookiesPerResourceDomain) {
-      var cookies = cookiesPerResourceDomain[requestDomain];
-      sortedCookieSizes.push(
-          {domain: requestDomain, avgCookieSize: this._average(cookies), maxCookieSize: this._max(cookies)});
-    }
-    var avgAllCookiesSize = this._average(allCookies);
-
-    var hugeCookieDomains = [];
-    sortedCookieSizes.sort(maxSizeSorter);
-
-    for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) {
-      var maxCookieSize = sortedCookieSizes[i].maxCookieSize;
-      if (maxCookieSize > this._maxBytesThreshold) {
-        hugeCookieDomains.push(
-            Audits.AuditRuleResult.resourceDomain(sortedCookieSizes[i].domain) + ': ' +
-            Number.bytesToString(maxCookieSize));
-      }
-    }
-
-    var bigAvgCookieDomains = [];
-    sortedCookieSizes.sort(avgSizeSorter);
-    for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) {
-      var domain = sortedCookieSizes[i].domain;
-      var avgCookieSize = sortedCookieSizes[i].avgCookieSize;
-      if (avgCookieSize > this._avgBytesThreshold && avgCookieSize < this._maxBytesThreshold) {
-        bigAvgCookieDomains.push(
-            Audits.AuditRuleResult.resourceDomain(domain) + ': ' + Number.bytesToString(avgCookieSize));
-      }
-    }
-    result.addChild(Common.UIString(
-        'The average cookie size for all requests on this page is %s', Number.bytesToString(avgAllCookiesSize)));
-
-    if (hugeCookieDomains.length) {
-      var entry = result.addChild(
-          Common.UIString(
-              'The following domains have a cookie size in excess of 1KB. This is harmful because requests with cookies larger than 1KB typically cannot fit into a single network packet.'),
-          true);
-      entry.addURLs(hugeCookieDomains);
-      result.violationCount += hugeCookieDomains.length;
-    }
-
-    if (bigAvgCookieDomains.length) {
-      var entry = result.addChild(
-          Common.UIString(
-              'The following domains have an average cookie size in excess of %d bytes. Reducing the size of cookies for these domains can reduce the time it takes to send requests.',
-              this._avgBytesThreshold),
-          true);
-      entry.addURLs(bigAvgCookieDomains);
-      result.violationCount += bigAvgCookieDomains.length;
-    }
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRules.StaticCookielessRule = class extends Audits.AuditRules.CookieRuleBase {
-  constructor(minResources) {
-    super('http-staticcookieless', Common.UIString('Serve static content from a cookieless domain'));
-    this._minResources = minResources;
-  }
-
-  processCookies(allCookies, requests, result) {
-    var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap(
-        requests, [Common.resourceTypes.Stylesheet, Common.resourceTypes.Image], true);
-    var totalStaticResources = 0;
-    for (var domain in domainToResourcesMap)
-      totalStaticResources += domainToResourcesMap[domain].length;
-    if (totalStaticResources < this._minResources)
-      return;
-    /** @type {!Object<string, number>} */
-    var matchingResourceData = {};
-    this.mapResourceCookies(domainToResourcesMap, allCookies, this._collectorCallback.bind(this, matchingResourceData));
-
-    var badUrls = [];
-    var cookieBytes = 0;
-    for (var url in matchingResourceData) {
-      badUrls.push(url);
-      cookieBytes += matchingResourceData[url];
-    }
-    if (badUrls.length < this._minResources)
-      return;
-
-    var entry = result.addChild(
-        Common.UIString(
-            '%s of cookies were sent with the following static resources. Serve these static resources from a domain that does not set cookies:',
-            Number.bytesToString(cookieBytes)),
-        true);
-    entry.addURLs(badUrls);
-    result.violationCount = badUrls.length;
-  }
-
-  /**
-   * @param {!Object<string, number>} matchingResourceData
-   * @param {!SDK.NetworkRequest} request
-   * @param {!SDK.Cookie} cookie
-   */
-  _collectorCallback(matchingResourceData, request, cookie) {
-    matchingResourceData[request.url()] = (matchingResourceData[request.url()] || 0) + cookie.size();
-  }
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js
deleted file mode 100644
index 4a6db12b..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-
-/**
- * @unrestricted
- */
-Audits.AuditsPanel = class extends UI.PanelWithSidebar {
-  constructor() {
-    super('audits');
-    this.registerRequiredCSS('ui/panelEnablerView.css');
-    this.registerRequiredCSS('audits/auditsPanel.css');
-
-    this._sidebarTree = new UI.TreeOutlineInShadow();
-    this._sidebarTree.registerRequiredCSS('audits/auditsSidebarTree.css');
-    this.panelSidebarElement().appendChild(this._sidebarTree.element);
-
-    this._auditsItemTreeElement = new Audits.AuditsSidebarTreeElement(this);
-    this._sidebarTree.appendChild(this._auditsItemTreeElement);
-
-    this._auditResultsTreeElement = new UI.TreeElement(Common.UIString('RESULTS'), true);
-    this._auditResultsTreeElement.selectable = false;
-    this._auditResultsTreeElement.listItemElement.classList.add('audits-sidebar-results');
-    this._auditResultsTreeElement.expand();
-    this._auditResultsTreeElement.setCollapsible(false);
-    this._sidebarTree.appendChild(this._auditResultsTreeElement);
-
-    this._constructCategories();
-
-    this._auditController = new Audits.AuditController(this);
-    this._launcherView = new Audits.AuditLauncherView(this._auditController);
-    for (var id in this.categoriesById)
-      this._launcherView.addCategory(this.categoriesById[id]);
-
-    var extensionCategories = Extensions.extensionServer.auditCategories();
-    for (var i = 0; i < extensionCategories.length; ++i) {
-      var category = extensionCategories[i];
-      this.addCategory(new Audits.AuditExtensionCategory(
-          category.extensionOrigin, category.id, category.displayName, category.ruleCount));
-    }
-    Extensions.extensionServer.addEventListener(
-        Extensions.ExtensionServer.Events.AuditCategoryAdded, this._extensionAuditCategoryAdded, this);
-  }
-
-  /**
-   * @return {!Audits.AuditsPanel}
-   */
-  static instance() {
-    return /** @type {!Audits.AuditsPanel} */ (self.runtime.sharedInstance(Audits.AuditsPanel));
-  }
-
-  /**
-   * @return {!Object.<string, !Audits.AuditCategory>}
-   */
-  get categoriesById() {
-    return this._auditCategoriesById;
-  }
-
-  /**
-   * @param {!Audits.AuditCategory} category
-   */
-  addCategory(category) {
-    this.categoriesById[category.id] = category;
-    this._launcherView.addCategory(category);
-  }
-
-  /**
-   * @param {string} id
-   * @return {!Audits.AuditCategory}
-   */
-  getCategory(id) {
-    return this.categoriesById[id];
-  }
-
-  _constructCategories() {
-    this._auditCategoriesById = {};
-    for (var categoryCtorID in Audits.AuditCategories) {
-      var auditCategory = new Audits.AuditCategories[categoryCtorID]();
-      auditCategory._id = categoryCtorID;
-      this.categoriesById[categoryCtorID] = auditCategory;
-    }
-  }
-
-  /**
-   * @param {string} mainResourceURL
-   * @param {!Array.<!Audits.AuditCategoryResult>} results
-   */
-  auditFinishedCallback(mainResourceURL, results) {
-    var ordinal = 1;
-    for (var child of this._auditResultsTreeElement.children()) {
-      if (child.mainResourceURL === mainResourceURL)
-        ordinal++;
-    }
-
-    var resultTreeElement = new Audits.AuditResultSidebarTreeElement(this, results, mainResourceURL, ordinal);
-    this._auditResultsTreeElement.appendChild(resultTreeElement);
-    resultTreeElement.revealAndSelect();
-  }
-
-  /**
-   * @param {!Array.<!Audits.AuditCategoryResult>} categoryResults
-   */
-  showResults(categoryResults) {
-    if (!categoryResults._resultLocation) {
-      categoryResults.sort((a, b) => (a.title || '').localeCompare(b.title || ''));
-      var resultView = UI.viewManager.createStackLocation();
-      resultView.widget().element.classList.add('audit-result-view');
-      for (var i = 0; i < categoryResults.length; ++i)
-        resultView.showView(new Audits.AuditCategoryResultPane(categoryResults[i]));
-      categoryResults._resultLocation = resultView;
-    }
-    this.visibleView = categoryResults._resultLocation.widget();
-  }
-
-  showLauncherView() {
-    this.visibleView = this._launcherView;
-  }
-
-  get visibleView() {
-    return this._visibleView;
-  }
-
-  set visibleView(x) {
-    if (this._visibleView === x)
-      return;
-
-    if (this._visibleView)
-      this._visibleView.detach();
-
-    this._visibleView = x;
-
-    if (x)
-      this.splitWidget().setMainWidget(x);
-  }
-
-  /**
-   * @override
-   */
-  wasShown() {
-    super.wasShown();
-    if (!this._visibleView)
-      this._auditsItemTreeElement.select(true);
-  }
-
-  /**
-   * @override
-   */
-  focus() {
-    this._sidebarTree.focus();
-  }
-
-  clearResults() {
-    this._auditsItemTreeElement.revealAndSelect();
-    this._auditResultsTreeElement.removeChildren();
-  }
-
-  /**
-   * @param {!Common.Event} event
-   */
-  _extensionAuditCategoryAdded(event) {
-    var category = /** @type {!Extensions.ExtensionAuditCategory} */ (event.data);
-    this.addCategory(new Audits.AuditExtensionCategory(
-        category.extensionOrigin, category.id, category.displayName, category.ruleCount));
-  }
-};
-
-/**
- * @implements {Audits.AuditCategory}
- * @unrestricted
- */
-Audits.AuditCategoryImpl = class {
-  /**
-   * @param {string} displayName
-   */
-  constructor(displayName) {
-    this._displayName = displayName;
-    this._rules = [];
-  }
-
-  /**
-   * @override
-   * @return {string}
-   */
-  get id() {
-    // this._id value is injected at construction time.
-    return this._id;
-  }
-
-  /**
-   * @override
-   * @return {string}
-   */
-  get displayName() {
-    return this._displayName;
-  }
-
-  /**
-   * @param {!Audits.AuditRule} rule
-   * @param {!Audits.AuditRule.Severity} severity
-   */
-  addRule(rule, severity) {
-    rule.severity = severity;
-    this._rules.push(rule);
-  }
-
-  /**
-   * @override
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {function(!Audits.AuditRuleResult)} ruleResultCallback
-   * @param {!Common.Progress} progress
-   */
-  run(target, requests, ruleResultCallback, progress) {
-    this._ensureInitialized();
-    var remainingRulesCount = this._rules.length;
-    progress.setTotalWork(remainingRulesCount);
-    function callbackWrapper(result) {
-      ruleResultCallback(result);
-      progress.worked();
-      if (!--remainingRulesCount)
-        progress.done();
-    }
-    for (var i = 0; i < this._rules.length; ++i) {
-      if (!progress.isCanceled())
-        this._rules[i].run(target, requests, callbackWrapper, progress);
-      else
-        callbackWrapper(null);
-    }
-  }
-
-  _ensureInitialized() {
-    if (!this._initialized) {
-      if ('initialize' in this)
-        this.initialize();
-      this._initialized = true;
-    }
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRule = class {
-  /**
-   * @param {string} id
-   * @param {string} displayName
-   */
-  constructor(id, displayName) {
-    this._id = id;
-    this._displayName = displayName;
-  }
-
-  get id() {
-    return this._id;
-  }
-
-  get displayName() {
-    return this._displayName;
-  }
-
-  /**
-   * @param {!Audits.AuditRule.Severity} severity
-   */
-  set severity(severity) {
-    this._severity = severity;
-  }
-
-  /**
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  run(target, requests, callback, progress) {
-    if (progress.isCanceled())
-      return;
-
-    var result = new Audits.AuditRuleResult(this.displayName);
-    result.severity = this._severity;
-    this.doRun(target, requests, result, callback, progress);
-  }
-
-  /**
-   * @param {!SDK.Target} target
-   * @param {!Array.<!SDK.NetworkRequest>} requests
-   * @param {!Audits.AuditRuleResult} result
-   * @param {function(?Audits.AuditRuleResult)} callback
-   * @param {!Common.Progress} progress
-   */
-  doRun(target, requests, result, callback, progress) {
-    throw new Error('doRun() not implemented');
-  }
-};
-
-/**
- * @enum {string}
- */
-Audits.AuditRule.Severity = {
-  Info: 'info',
-  Warning: 'warning',
-  Severe: 'severe'
-};
-
-Audits.AuditRule.SeverityOrder = {
-  'info': 3,
-  'warning': 2,
-  'severe': 1
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditCategoryResult = class {
-  /**
-   * @param {!Audits.AuditCategory} category
-   */
-  constructor(category) {
-    this.title = category.displayName;
-    this.ruleResults = [];
-  }
-
-  /**
-   * @param {!Audits.AuditRuleResult} ruleResult
-   */
-  addRuleResult(ruleResult) {
-    this.ruleResults.push(ruleResult);
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditRuleResult = class {
-  /**
-   * @param {(string|boolean|number|!Object)} value
-   * @param {boolean=} expanded
-   * @param {string=} className
-   */
-  constructor(value, expanded, className) {
-    this.value = value;
-    this.className = className;
-    this.expanded = expanded;
-    this.violationCount = 0;
-    this._formatters = {r: Audits.AuditRuleResult.linkifyDisplayName};
-    var standardFormatters = Object.keys(String.standardFormatters);
-    for (var i = 0; i < standardFormatters.length; ++i)
-      this._formatters[standardFormatters[i]] = String.standardFormatters[standardFormatters[i]];
-  }
-
-  /**
-   * @param {string} url
-   * @return {!Element}
-   */
-  static linkifyDisplayName(url) {
-    return Components.Linkifier.linkifyURL(url, {text: Bindings.displayNameForURL(url)});
-  }
-
-  /**
-   * @param {string} domain
-   * @return {string}
-   */
-  static resourceDomain(domain) {
-    return domain || Common.UIString('[empty domain]');
-  }
-
-  /**
-   * @param {(string|boolean|number|!Object)} value
-   * @param {boolean=} expanded
-   * @param {string=} className
-   * @return {!Audits.AuditRuleResult}
-   */
-  addChild(value, expanded, className) {
-    if (!this.children)
-      this.children = [];
-    var entry = new Audits.AuditRuleResult(value, expanded, className);
-    this.children.push(entry);
-    return entry;
-  }
-
-  /**
-   * @param {string} url
-   */
-  addURL(url) {
-    this.addChild(Audits.AuditRuleResult.linkifyDisplayName(url));
-  }
-
-  /**
-   * @param {!Array.<string>} urls
-   */
-  addURLs(urls) {
-    for (var i = 0; i < urls.length; ++i)
-      this.addURL(urls[i]);
-  }
-
-  /**
-   * @param {string} snippet
-   */
-  addSnippet(snippet) {
-    this.addChild(snippet, false, 'source-code');
-  }
-
-  /**
-   * @param {string} format
-   * @param {...*} vararg
-   * @return {!Audits.AuditRuleResult}
-   */
-  addFormatted(format, vararg) {
-    var substitutions = Array.prototype.slice.call(arguments, 1);
-    var fragment = createDocumentFragment();
-
-    function append(a, b) {
-      if (!(b instanceof Node))
-        b = createTextNode(b);
-      a.appendChild(b);
-      return a;
-    }
-
-    var formattedResult = String.format(format, substitutions, this._formatters, fragment, append).formattedResult;
-    if (formattedResult instanceof Node)
-      formattedResult.normalize();
-    return this.addChild(formattedResult);
-  }
-};
-
-
-/**
- * @unrestricted
- */
-Audits.AuditsSidebarTreeElement = class extends UI.TreeElement {
-  /**
-   * @param {!Audits.AuditsPanel} panel
-   */
-  constructor(panel) {
-    super(Common.UIString('Audits'), false);
-    this.selectable = true;
-    this._panel = panel;
-    this.listItemElement.classList.add('audits-sidebar-header');
-    this.listItemElement.insertBefore(createElementWithClass('div', 'icon'), this.listItemElement.firstChild);
-  }
-
-  /**
-   * @override
-   * @return {boolean}
-   */
-  onselect() {
-    this._panel.showLauncherView();
-    return true;
-  }
-};
-
-/**
- * @unrestricted
- */
-Audits.AuditResultSidebarTreeElement = class extends UI.TreeElement {
-  /**
-   * @param {!Audits.AuditsPanel} panel
-   * @param {!Array.<!Audits.AuditCategoryResult>} results
-   * @param {string} mainResourceURL
-   * @param {number} ordinal
-   */
-  constructor(panel, results, mainResourceURL, ordinal) {
-    super(String.sprintf('%s (%d)', mainResourceURL, ordinal), false);
-    this.selectable = true;
-    this._panel = panel;
-    this.results = results;
-    this.mainResourceURL = mainResourceURL;
-    this.listItemElement.classList.add('audit-result-sidebar-tree-item');
-    this.listItemElement.insertBefore(createElementWithClass('div', 'icon'), this.listItemElement.firstChild);
-  }
-
-  /**
-   * @override
-   * @return {boolean}
-   */
-  onselect() {
-    this._panel.showResults(this.results);
-    return true;
-  }
-};
-
-
-// Contributed audit rules should go into this namespace.
-Audits.AuditRules = {};
-
-/**
- * Contributed audit categories should go into this namespace.
- * @type {!Object.<string, function(new:Audits.AuditCategory)>}
- */
-Audits.AuditCategories = {};
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/auditResultTree.css b/third_party/WebKit/Source/devtools/front_end/audits/auditResultTree.css
deleted file mode 100644
index e2a35901..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/auditResultTree.css
+++ /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.
- */
-
-.severity {
-    margin-right: 4px;
-}
-
-li {
-    -webkit-user-select: text;
-}
-
-.audit-result {
-    font-weight: bold;
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/auditsPanel.css b/third_party/WebKit/Source/devtools/front_end/audits/auditsPanel.css
deleted file mode 100644
index 75b9adf..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/auditsPanel.css
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc.  All rights reserved.
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-
-.audit-launcher-view .audit-launcher-view-content {
-    padding: 0 0 0 16px;
-    white-space: nowrap;
-    display: -webkit-flex;
-    text-align: left;
-    -webkit-flex-direction: column;
-    flex: auto;
-}
-
-.audit-launcher-view h1 {
-    padding-top: 15px;
-    -webkit-flex: none;
-}
-
-.audit-launcher-view h1.no-audits {
-    text-align: center;
-    font-style: italic;
-    position: relative;
-    left: -8px;
-}
-
-.audit-launcher-view div.button-container {
-    width: 100%;
-    padding: 16px 0;
-    -webkit-flex: none;
-}
-
-.audit-launcher-view div.button-container > button {
-    -webkit-align-self: flex-start;
-    margin-right: 10px;
-    margin-bottom: 5px;
-    margin-top: 5px;
-}
-
-.audit-launcher-view fieldset.audit-categories-container {
-    position: relative;
-    top: 11px;
-    left: 0;
-    width: 100%;
-    overflow-y: auto;
-    border: 0 none;
-    -webkit-flex: none;
-}
-
-.audit-launcher-view button {
-    margin: 0 5px 0 0;
-}
-
-.audit-result-view {
-    overflow: auto;
-}
-
-.panel-enabler-view.audit-launcher-view label {
-    padding: 0 0 5px 0;
-    margin: 0;
-    display: flex;
-    flex-shrink: 0;
-}
-
-.panel-enabler-view.audit-launcher-view label.disabled {
-    color: rgb(130, 130, 130);
-}
-
-.audit-launcher-view input[type="checkbox"] {
-    margin-left: 0;
-    height: 14px;
-    width: 14px;
-}
-
-.audit-result-tree {
-    margin: 0 0 3px;
-}
-
-.audit-launcher-view .progress-indicator {
-    display: inline-block;
-}
-
-.resource-url {
-    float: right;
-    text-align: right;
-    max-width: 100%;
-    margin-left: 4px;
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/auditsSidebarTree.css b/third_party/WebKit/Source/devtools/front_end/audits/auditsSidebarTree.css
deleted file mode 100644
index 5bc0845..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/auditsSidebarTree.css
+++ /dev/null
@@ -1,50 +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.
- */
-
-.tree-outline {
-    padding: 0;
-}
-
-.tree-outline li::before {
-    display: none;
-}
-
-.tree-outline ol {
-    padding-left: 0;
-}
-
-.tree-outline li .tree-element-title {
-    margin-left: 4px;
-}
-
-li.audits-sidebar-header {
-    padding-left: 10px;
-    height: 36px;
-}
-
-.audits-sidebar-header .icon {
-    content: url(Images/resourcesTimeGraphIcon.png);
-}
-
-li.audits-sidebar-results {
-    height: 18px;
-    padding: 1px 10px;
-    margin-top: 1px;
-    color: rgb(92, 110, 129);
-    text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0;
-}
-
-li.audit-result-sidebar-tree-item {
-    padding-left: 10px;
-    height: 36px;
-    margin-top: 1px;
-    line-height: 34px;
-    border-top: 1px solid transparent;
-}
-
-.audit-result-sidebar-tree-item .icon {
-    content: url(Images/resourceDocumentIcon.png);
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/module.json b/third_party/WebKit/Source/devtools/front_end/audits/module.json
deleted file mode 100644
index c2e71d25..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits/module.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
-    "extensions": [
-        {
-            "type": "view",
-            "location": "panel",
-            "id": "audits",
-            "title": "Legacy Audits",
-            "order": 90,
-            "persistence": "closeable",
-            "className": "Audits.AuditsPanel"
-        }
-    ],
-    "dependencies": [
-        "components",
-        "extensions",
-        "network_log",
-        "object_ui",
-        "formatter"
-    ],
-    "scripts": [
-        "AuditsPanel.js",
-        "AuditCategory.js",
-        "AuditCategories.js",
-        "AuditController.js",
-        "AuditFormatters.js",
-        "AuditLauncherView.js",
-        "AuditResultView.js",
-        "AuditRules.js",
-        "AuditExtensionCategory.js"
-    ],
-    "resources": [
-        "auditsPanel.css",
-        "auditsSidebarTree.css",
-        "auditResultTree.css"
-    ]
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/audits_test_runner/AuditsTestRunner.js b/third_party/WebKit/Source/devtools/front_end/audits_test_runner/AuditsTestRunner.js
deleted file mode 100644
index 649f1c40..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits_test_runner/AuditsTestRunner.js
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2017 The Chromium Authors. All
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview using private properties isn't a Closure violation in tests.
- * @suppress {accessControls}
- */
-
-AuditsTestRunner.collectAuditResults = function(callback) {
-  UI.panels.audits.showResults(UI.panels.audits._auditResultsTreeElement.firstChild().results);
-  var trees = UI.panels.audits.visibleView.element.querySelectorAll('.audit-result-tree');
-
-  for (var i = 0; i < trees.length; ++i) {
-    var liElements = trees[i].shadowRoot.querySelectorAll('li');
-
-    for (var j = 0; j < liElements.length; ++j) {
-      if (liElements[j].treeElement)
-        liElements[j].treeElement.expand();
-    }
-  }
-
-  TestRunner.deprecatedRunAfterPendingDispatches(function() {
-    AuditsTestRunner.collectTextContent(UI.panels.audits.visibleView.element, '');
-    callback();
-  });
-};
-
-AuditsTestRunner.launchAllAudits = function(shouldReload, callback) {
-  TestRunner.addSniffer(Audits.AuditController.prototype, '_auditFinishedCallback', callback);
-  var launcherView = UI.panels.audits._launcherView;
-  launcherView._selectAllClicked(true);
-  launcherView._auditPresentStateElement.checked = !shouldReload;
-  launcherView._launchButtonClicked();
-};
-
-AuditsTestRunner.collectTextContent = function(element, indent) {
-  var nodeOutput = '';
-  var child = element.shadowRoot || element.firstChild;
-
-  var nonTextTags = {'STYLE': 1, 'SCRIPT': 1};
-
-  while (child) {
-    if (child.nodeName === 'CONTENT') {
-      AuditsTestRunner.collectTextContent(child.getDistributedNodes()[0], indent);
-    } else if (child.nodeType === Node.TEXT_NODE) {
-      if (!nonTextTags[child.parentElement.nodeName])
-        nodeOutput += child.nodeValue.replace('​', '');
-    } else if (child.nodeType === Node.ELEMENT_NODE || child.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
-      if (nodeOutput !== '') {
-        TestRunner.addResult(indent + nodeOutput);
-        nodeOutput = '';
-      }
-
-      if (!child.firstChild && child.classList.contains('severity'))
-        nodeOutput = '[' + child.className + '] ';
-      else
-        AuditsTestRunner.collectTextContent(child, indent + ' ');
-    }
-
-    child = child.nextSibling;
-  }
-
-  if (nodeOutput !== '')
-    TestRunner.addResult(indent + nodeOutput);
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/audits_test_runner/module.json b/third_party/WebKit/Source/devtools/front_end/audits_test_runner/module.json
deleted file mode 100644
index 3599065..0000000
--- a/third_party/WebKit/Source/devtools/front_end/audits_test_runner/module.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "dependencies": [
-    "test_runner",
-    "audits"
-  ],
-  "scripts": [
-    "AuditsTestRunner.js"
-  ],
-  "skip_compilation": [
-    "AuditsTestRunner.js"
-  ]
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/common/UIString.js b/third_party/WebKit/Source/devtools/front_end/common/UIString.js
index 9333b76..2d1d676b 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/UIString.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/UIString.js
@@ -83,3 +83,23 @@
         .formattedResult;
   }
 };
+
+
+/**
+ * @param {!Array<string>|string} strings
+ * @param {...*} vararg
+ * @return {string}
+ */
+self.ls = function(strings, vararg) {
+  if (typeof strings === 'string')
+    return strings;
+  var values = Array.prototype.slice.call(arguments, 1);
+  if (!values.length)
+    return strings[0];
+  var result = '';
+  for (var i = 0; i < values.length; i++) {
+    result += strings[i];
+    result += '' + values[i];
+  }
+  return result + strings[values.length];
+};
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js
index 0fb0077..945f961 100644
--- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js
+++ b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js
@@ -31,10 +31,6 @@
 /* eslint-disable indent */
 
 function defineCommonExtensionSymbols(apiPrivate) {
-  if (!apiPrivate.audits)
-    apiPrivate.audits = {};
-  apiPrivate.audits.Severity = {Info: 'info', Warning: 'warning', Severe: 'severe'};
-
   if (!apiPrivate.panels)
     apiPrivate.panels = {};
   apiPrivate.panels.SearchAction = {
@@ -46,7 +42,6 @@
 
   /** @enum {string} */
   apiPrivate.Events = {
-    AuditStarted: 'audit-started-',
     ButtonClicked: 'button-clicked-',
     PanelObjectSelected: 'panel-objectSelected-',
     NetworkRequestFinished: 'network-request-finished',
@@ -62,8 +57,6 @@
 
   /** @enum {string} */
   apiPrivate.Commands = {
-    AddAuditCategory: 'addAuditCategory',
-    AddAuditResult: 'addAuditResult',
     AddRequestHeaders: 'addRequestHeaders',
     AddTraceProvider: 'addTraceProvider',
     ApplyStyleSheet: 'applyStyleSheet',
@@ -87,9 +80,7 @@
     SetSidebarHeight: 'setSidebarHeight',
     SetSidebarPage: 'setSidebarPage',
     ShowPanel: 'showPanel',
-    StopAuditCategoryRun: 'stopAuditCategoryRun',
     Unsubscribe: 'unsubscribe',
-    UpdateAuditProgress: 'updateAuditProgress',
     UpdateButton: 'updateButton'
   };
 }
@@ -170,7 +161,6 @@
    * @constructor
    */
   function InspectorExtensionAPI() {
-    this.audits = new Audits();
     this.inspectedWindow = new InspectedWindow();
     this.panels = new Panels();
     this.network = new Network();
@@ -360,8 +350,6 @@
     return typeof lastArgument === 'function' ? lastArgument : undefined;
   }
 
-  var AuditCategory = declareInterfaceClass(AuditCategoryImpl);
-  var AuditResult = declareInterfaceClass(AuditResultImpl);
   var Button = declareInterfaceClass(ButtonImpl);
   var EventSink = declareInterfaceClass(EventSinkImpl);
   var ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl);
@@ -543,135 +531,6 @@
   /**
    * @constructor
    */
-  function Audits() {}
-
-  Audits.prototype = {
-    /**
-     * @return {!AuditCategory}
-     */
-    addCategory: function(displayName, resultCount) {
-      var id = 'extension-audit-category-' + extensionServer.nextObjectId();
-      if (typeof resultCount !== 'undefined') {
-        console.warn(
-            'Passing resultCount to audits.addCategory() is deprecated. Use AuditResult.updateProgress() instead.');
-      }
-      extensionServer.sendRequest(
-          {command: commands.AddAuditCategory, id: id, displayName: displayName, resultCount: resultCount});
-      return new AuditCategory(id);
-    }
-  };
-
-  /**
-   * @constructor
-   */
-  function AuditCategoryImpl(id) {
-    /**
-     * @this {EventSinkImpl}
-     */
-    function dispatchAuditEvent(request) {
-      var auditResult = new AuditResult(request.arguments[0]);
-      try {
-        this._fire(auditResult);
-      } catch (e) {
-        console.error('Uncaught exception in extension audit event handler: ' + e);
-        auditResult.done();
-      }
-    }
-    this._id = id;
-    this.onAuditStarted = new EventSink(events.AuditStarted + id, dispatchAuditEvent);
-  }
-
-  /**
-   * @constructor
-   */
-  function AuditResultImpl(id) {
-    this._id = id;
-
-    this.createURL = this._nodeFactory.bind(this, 'url');
-    this.createSnippet = this._nodeFactory.bind(this, 'snippet');
-    this.createText = this._nodeFactory.bind(this, 'text');
-    this.createObject = this._nodeFactory.bind(this, 'object');
-    this.createNode = this._nodeFactory.bind(this, 'node');
-  }
-
-  AuditResultImpl.prototype = {
-    addResult: function(displayName, description, severity, details) {
-      // shorthand for specifying details directly in addResult().
-      if (details && !(details instanceof AuditResultNode))
-        details = new AuditResultNode(Array.isArray(details) ? details : [details]);
-
-      var request = {
-        command: commands.AddAuditResult,
-        resultId: this._id,
-        displayName: displayName,
-        description: description,
-        severity: severity,
-        details: details
-      };
-      extensionServer.sendRequest(request);
-    },
-
-    /**
-     * @return {!Object}
-     */
-    createResult: function() {
-      return new AuditResultNode(Array.prototype.slice.call(arguments));
-    },
-
-    updateProgress: function(worked, totalWork) {
-      extensionServer.sendRequest(
-          {command: commands.UpdateAuditProgress, resultId: this._id, progress: worked / totalWork});
-    },
-
-    done: function() {
-      extensionServer.sendRequest({command: commands.StopAuditCategoryRun, resultId: this._id});
-    },
-
-    /**
-     * @type {!Object.<string, string>}
-     */
-    get Severity() {
-      return apiPrivate.audits.Severity;
-    },
-
-    /**
-     * @return {!{type: string, arguments: !Array.<string|number>}}
-     */
-    createResourceLink: function(url, lineNumber) {
-      return {type: 'resourceLink', arguments: [url, lineNumber && lineNumber - 1]};
-    },
-
-    /**
-     * @return {!{type: string, arguments: !Array.<string|number>}}
-     */
-    _nodeFactory: function(type) {
-      return {type: type, arguments: Array.prototype.slice.call(arguments, 1)};
-    }
-  };
-
-  /**
-   * @constructor
-   */
-  function AuditResultNode(contents) {
-    this.contents = contents;
-    this.children = [];
-    this.expanded = false;
-  }
-
-  AuditResultNode.prototype = {
-    /**
-     * @return {!Object}
-     */
-    addChild: function() {
-      var node = new AuditResultNode(Array.prototype.slice.call(arguments));
-      this.children.push(node);
-      return node;
-    }
-  };
-
-  /**
-   * @constructor
-   */
   function InspectedWindow() {
     /**
      * @this {EventSinkImpl}
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAuditCategory.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAuditCategory.js
deleted file mode 100644
index 50314605..0000000
--- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAuditCategory.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 COPYRIGHT
- * OWNER OR CONTRIBUTORS 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.
- */
-
-/**
- * @unrestricted
- */
-Extensions.ExtensionAuditCategory = class {
-  /**
-   * @param {string} extensionOrigin
-   * @param {string} id
-   * @param {string} displayName
-   * @param {number=} ruleCount
-   */
-  constructor(extensionOrigin, id, displayName, ruleCount) {
-    this.extensionOrigin = extensionOrigin;
-    this.id = id;
-    this.displayName = displayName;
-    this.ruleCount = ruleCount;
-  }
-};
-
-/**
- * @interface
- */
-Extensions.ExtensionAuditCategoryResults = function() {};
-
-Extensions.ExtensionAuditCategoryResults.prototype = {
-  /**
-   * @return {string}
-   */
-  id() {},
-
-  /**
-   * @param {string} displayName
-   * @param {string} description
-   * @param {string} severity
-   * @param {!Object} details
-   */
-  addResult(displayName, description, severity, details) {},
-
-  /**
-   * @param {number} progress
-   */
-  updateProgress(progress) {},
-
-  done() {}
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js
index f8efc75..d2f52ba66 100644
--- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js
+++ b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js
@@ -49,8 +49,6 @@
     this._status = new Extensions.ExtensionStatus();
     /** @type {!Array<!Extensions.ExtensionSidebarPane>} */
     this._sidebarPanes = [];
-    /** @type {!Array<!Extensions.ExtensionAuditCategory>} */
-    this._auditCategories = [];
     /** @type {!Array<!Extensions.ExtensionTraceProvider>} */
     this._traceProviders = [];
     /** @type {!Map<string, !Extensions.TracingSession>} */
@@ -58,8 +56,6 @@
 
     var commands = Extensions.extensionAPI.Commands;
 
-    this._registerHandler(commands.AddAuditCategory, this._onAddAuditCategory.bind(this));
-    this._registerHandler(commands.AddAuditResult, this._onAddAuditResult.bind(this));
     this._registerHandler(commands.AddRequestHeaders, this._onAddRequestHeaders.bind(this));
     this._registerHandler(commands.AddTraceProvider, this._onAddTraceProvider.bind(this));
     this._registerHandler(commands.ApplyStyleSheet, this._onApplyStyleSheet.bind(this));
@@ -80,12 +76,10 @@
     this._registerHandler(commands.SetSidebarContent, this._onSetSidebarContent.bind(this));
     this._registerHandler(commands.SetSidebarPage, this._onSetSidebarPage.bind(this));
     this._registerHandler(commands.ShowPanel, this._onShowPanel.bind(this));
-    this._registerHandler(commands.StopAuditCategoryRun, this._onStopAuditCategoryRun.bind(this));
     this._registerHandler(commands.Subscribe, this._onSubscribe.bind(this));
     this._registerHandler(commands.OpenResource, this._onOpenResource.bind(this));
     this._registerHandler(commands.Unsubscribe, this._onUnsubscribe.bind(this));
     this._registerHandler(commands.UpdateButton, this._onUpdateButton.bind(this));
-    this._registerHandler(commands.UpdateAuditProgress, this._onUpdateAuditProgress.bind(this));
     window.addEventListener('message', this._onWindowMessage.bind(this), false);  // Only for main window.
 
     InspectorFrontendHost.events.addEventListener(
@@ -151,22 +145,6 @@
   }
 
   /**
-   * @param {string} categoryId
-   * @param {!Extensions.ExtensionAuditCategoryResults} auditResults
-   */
-  startAuditRun(categoryId, auditResults) {
-    this._clientObjects[auditResults.id()] = auditResults;
-    this._postNotification('audit-started-' + categoryId, auditResults.id());
-  }
-
-  /**
-   * @param {!Extensions.ExtensionAuditCategoryResults} auditResults
-   */
-  stopAuditRun(auditResults) {
-    delete this._clientObjects[auditResults.id()];
-  }
-
-  /**
    * @param {string} providerId
    * @param {string} sessionId
    * @param {!Extensions.TracingSession} session
@@ -555,14 +533,6 @@
     return this._requests[id];
   }
 
-  _onAddAuditCategory(message, port) {
-    var category = new Extensions.ExtensionAuditCategory(
-        port._extensionOrigin, message.id, message.displayName, message.resultCount);
-    this._clientObjects[message.id] = category;
-    this._auditCategories.push(category);
-    this.dispatchEventToListeners(Extensions.ExtensionServer.Events.AuditCategoryAdded, category);
-  }
-
   /**
    * @param {!Object} message
    * @param {!MessagePort} port
@@ -582,39 +552,6 @@
     return this._traceProviders;
   }
 
-  /**
-   * @return {!Array.<!Extensions.ExtensionAuditCategory>}
-   */
-  auditCategories() {
-    return this._auditCategories;
-  }
-
-  _onAddAuditResult(message) {
-    var auditResult = /** {!Extensions.ExtensionAuditCategoryResults} */ (this._clientObjects[message.resultId]);
-    if (!auditResult)
-      return this._status.E_NOTFOUND(message.resultId);
-    try {
-      auditResult.addResult(message.displayName, message.description, message.severity, message.details);
-    } catch (e) {
-      return e;
-    }
-    return this._status.OK();
-  }
-
-  _onUpdateAuditProgress(message) {
-    var auditResult = /** {!Extensions.ExtensionAuditCategoryResults} */ (this._clientObjects[message.resultId]);
-    if (!auditResult)
-      return this._status.E_NOTFOUND(message.resultId);
-    auditResult.updateProgress(Math.min(Math.max(0, message.progress), 1));
-  }
-
-  _onStopAuditCategoryRun(message) {
-    var auditRun = /** {!Extensions.ExtensionAuditCategoryResults} */ (this._clientObjects[message.resultId]);
-    if (!auditRun)
-      return this._status.E_NOTFOUND(message.resultId);
-    auditRun.done();
-  }
-
   _onForwardKeyboardEvent(message) {
     message.entries.forEach(handleEventEntry);
 
@@ -993,7 +930,6 @@
 /** @enum {symbol} */
 Extensions.ExtensionServer.Events = {
   SidebarPaneAdded: Symbol('SidebarPaneAdded'),
-  AuditCategoryAdded: Symbol('AuditCategoryAdded'),
   TraceProviderAdded: Symbol('TraceProviderAdded')
 };
 
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/module.json b/third_party/WebKit/Source/devtools/front_end/extensions/module.json
index aea0183..fb1058d2 100644
--- a/third_party/WebKit/Source/devtools/front_end/extensions/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/extensions/module.json
@@ -6,7 +6,6 @@
     ],
     "scripts": [
         "ExtensionAPI.js",
-        "ExtensionAuditCategory.js",
         "ExtensionRegistryStub.js",
         "ExtensionTraceProvider.js",
         "ExtensionServer.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions_test_runner/ExtensionsAuditsTestRunner.js b/third_party/WebKit/Source/devtools/front_end/extensions_test_runner/ExtensionsAuditsTestRunner.js
deleted file mode 100644
index f87b7268..0000000
--- a/third_party/WebKit/Source/devtools/front_end/extensions_test_runner/ExtensionsAuditsTestRunner.js
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2017 The Chromium Authors. All
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview using private properties isn't a Closure violation in tests.
- * @suppress {accessControls}
- */
-
-ExtensionsTestRunner.startExtensionAudits = function(callback) {
-  const launcherView = UI.panels.audits._launcherView;
-  launcherView._selectAllClicked(false);
-  launcherView._auditPresentStateElement.checked = true;
-  var extensionCategories = document.querySelectorAll('.audit-categories-container > label');
-
-  for (var i = 0; i < extensionCategories.length; ++i) {
-    var shouldBeEnabled = extensionCategories[i].textContent.includes('Extension');
-
-    if (!shouldBeEnabled && extensionCategories[i].textElement)
-      shouldBeEnabled = extensionCategories[i].textElement.textContent.includes('Extension');
-
-    if (shouldBeEnabled !== extensionCategories[i].checkboxElement.checked)
-      extensionCategories[i].checkboxElement.click();
-  }
-
-  function onAuditsDone() {
-    AuditsTestRunner.collectAuditResults(callback);
-  }
-
-  TestRunner.addSniffer(UI.panels.audits, 'auditFinishedCallback', onAuditsDone, true);
-  launcherView._launchButtonClicked();
-};
-
-ExtensionsTestRunner.dumpAuditProgress = function() {
-  var progress = document.querySelector('.progress-indicator').shadowRoot.querySelector('progress');
-  TestRunner.addResult('Progress: ' + Math.round(100 * progress.value / progress.max) + '%');
-};
-
-TestRunner.deprecatedInitAsync(`
-  function extension_runAudits(callback) {
-    evaluateOnFrontend('ExtensionsTestRunner.startExtensionAudits(reply);', callback);
-  }
-`);
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions_test_runner/module.json b/third_party/WebKit/Source/devtools/front_end/extensions_test_runner/module.json
index 8e42fc4b..36c6e48 100644
--- a/third_party/WebKit/Source/devtools/front_end/extensions_test_runner/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/extensions_test_runner/module.json
@@ -5,12 +5,10 @@
   ],
   "scripts": [
     "ExtensionsNetworkTestRunner.js",
-    "ExtensionsTestRunner.js",
-    "ExtensionsAuditsTestRunner.js"
+    "ExtensionsTestRunner.js"
   ],
   "skip_compilation": [
     "ExtensionsNetworkTestRunner.js",
-    "ExtensionsTestRunner.js",
-    "ExtensionsAuditsTestRunner.js"
+    "ExtensionsTestRunner.js"
   ]
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/externs.js b/third_party/WebKit/Source/devtools/front_end/externs.js
index ce63c44..118ee60 100644
--- a/third_party/WebKit/Source/devtools/front_end/externs.js
+++ b/third_party/WebKit/Source/devtools/front_end/externs.js
@@ -282,12 +282,6 @@
 /** Extensions API */
 
 /** @constructor */
-function AuditCategory() {
-}
-/** @constructor */
-function AuditResult() {
-}
-/** @constructor */
 function EventSink() {
 }
 /** @constructor */
@@ -795,3 +789,11 @@
  * @return {!Console}
  */
 Console.prototype.context = function(context) {};
+
+
+/**
+ * @param {!Array<string>|string} strings
+ * @param {...*} vararg
+ * @return {string}
+ */
+var ls = function(strings, vararg) {};
diff --git a/third_party/WebKit/Source/devtools/front_end/inspector.json b/third_party/WebKit/Source/devtools/front_end/inspector.json
index 5e916447..34d7a8e9 100644
--- a/third_party/WebKit/Source/devtools/front_end/inspector.json
+++ b/third_party/WebKit/Source/devtools/front_end/inspector.json
@@ -25,7 +25,6 @@
         { "name": "product_registry_impl", "condition": "!v8only", "type": "remote" },
         { "name": "profiler" },
         { "name": "resources", "condition": "!v8only" },
-        { "name": "audits", "condition": "!v8only", "type": "remote" },
         { "name": "audits2", "condition": "!v8only" },
         { "name": "devices" },
         { "name": "security", "condition": "!v8only" },
diff --git a/third_party/WebKit/Source/devtools/front_end/integration_test_runner.json b/third_party/WebKit/Source/devtools/front_end/integration_test_runner.json
index f1188a8..4c8f485 100644
--- a/third_party/WebKit/Source/devtools/front_end/integration_test_runner.json
+++ b/third_party/WebKit/Source/devtools/front_end/integration_test_runner.json
@@ -2,7 +2,6 @@
   "modules" : [
     { "name": "test_runner", "type": "autostart" },
     { "name": "application_test_runner" },
-    { "name": "audits_test_runner" },
     { "name": "audits2_test_runner" },
     { "name": "bindings_test_runner" },
     { "name": "extensions_test_runner" },
@@ -52,7 +51,6 @@
     { "name": "product_registry_impl", "condition": "!v8only", "type": "remote" },
     { "name": "profiler" },
     { "name": "resources", "condition": "!v8only" },
-    { "name": "audits", "condition": "!v8only", "type": "remote" },
     { "name": "audits2", "condition": "!v8only" },
     { "name": "devices" },
     { "name": "security", "condition": "!v8only" },
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index 88a8200..20fdd6d6 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -331,9 +331,8 @@
   if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() &&
       DrawsContent()) {
     auto& tracking = EnsureRasterInvalidator().EnsureTracking();
-    tracking.CheckUnderInvalidations(
-        DebugName(), CapturePaintRecord(), InterestRect(),
-        layer_state_ ? layer_state_->offset : IntPoint());
+    tracking.CheckUnderInvalidations(DebugName(), CapturePaintRecord(),
+                                     InterestRect());
     if (auto record = tracking.UnderInvalidationRecord()) {
       // Add the under-invalidation overlay onto the painted result.
       GetPaintController().AppendDebugDrawingAfterCommit(
@@ -1306,15 +1305,18 @@
   GraphicsContext graphics_context(GetPaintController());
   graphics_context.BeginRecording(bounds);
   if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() && !layer_state_) {
+    LOG(WARNING) << "No layer state for GraphicsLayer: " << DebugName();
     // TODO(wangxianzhu): Remove this condition when all drawable layers have
     // layer_state_ for SPv175.
     for (const auto& display_item :
          GetPaintController().GetPaintArtifact().GetDisplayItemList())
       display_item.Replay(graphics_context);
-  } else {
+  } else if (layer_state_) {
     GetPaintController().GetPaintArtifact().Replay(
-        graphics_context,
-        layer_state_ ? layer_state_->state : PropertyTreeState::Root());
+        graphics_context, layer_state_->state, layer_state_->offset);
+  } else {
+    GetPaintController().GetPaintArtifact().Replay(graphics_context,
+                                                   PropertyTreeState::Root());
   }
   return graphics_context.EndRecording();
 }
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
index 2568d4dd..0c3f63d 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
@@ -412,7 +412,7 @@
     recorder.getRecordingCanvas()->drawPicture(list_clone->ReleaseAsRecord());
     params.tracking.CheckUnderInvalidations(params.debug_name,
                                             recorder.finishRecordingAsPicture(),
-                                            params.interest_rect, IntPoint());
+                                            params.interest_rect);
     if (auto record = params.tracking.UnderInvalidationRecord()) {
       cc_list->StartPaint();
       cc_list->push<cc::DrawRecordOp>(std::move(record));
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
index 0ec9402..a06fcb1 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
@@ -87,7 +87,6 @@
     DEBUG_STRING_CASE(PrintedContentPDFURLRect);
     DEBUG_STRING_CASE(Resizer);
     DEBUG_STRING_CASE(SVGClip);
-    DEBUG_STRING_CASE(SVGClipBoundsHack);
     DEBUG_STRING_CASE(SVGFilter);
     DEBUG_STRING_CASE(SVGMask);
     DEBUG_STRING_CASE(ScrollbarBackButtonEnd);
@@ -185,6 +184,8 @@
     return "End" + ClipTypeAsDebugString(endClipTypeToClipType(type));
 
   PAINT_PHASE_BASED_DEBUG_STRINGS(FloatClip);
+  if (type == kFloatClipClipPathBounds)
+    return "FloatClipClipPathBounds";
   if (IsEndFloatClipType(type))
     return "End" + TypeAsDebugString(endFloatClipTypeToFloatClipType(type));
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
index f124d76..9b6894d 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
@@ -89,7 +89,6 @@
     kPrintedContentPDFURLRect,
     kResizer,
     kSVGClip,
-    kSVGClipBoundsHack,
     kSVGFilter,
     kSVGMask,
     kScrollbarBackButtonEnd,
@@ -148,7 +147,8 @@
     kFloatClipFirst,
     kFloatClipPaintPhaseFirst = kFloatClipFirst,
     kFloatClipPaintPhaseLast = kFloatClipFirst + kPaintPhaseMax,
-    kFloatClipLast = kFloatClipPaintPhaseLast,
+    kFloatClipClipPathBounds,
+    kFloatClipLast = kFloatClipClipPathBounds,
     kEndFloatClipFirst,
     kEndFloatClipLast = kEndFloatClipFirst + kFloatClipLast - kFloatClipFirst,
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
index f3fb0960..2e94a164 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
@@ -79,18 +79,21 @@
 }
 
 void PaintArtifact::Replay(GraphicsContext& graphics_context,
-                           const PropertyTreeState& replay_state) const {
+                           const PropertyTreeState& replay_state,
+                           const IntPoint& offset) const {
   if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+    DCHECK(offset == IntPoint());
     TRACE_EVENT0("blink,benchmark", "PaintArtifact::replay");
     for (const DisplayItem& display_item : display_item_list_)
       display_item.Replay(graphics_context);
   } else {
-    Replay(*graphics_context.Canvas(), replay_state);
+    Replay(*graphics_context.Canvas(), replay_state, offset);
   }
 }
 
 void PaintArtifact::Replay(PaintCanvas& canvas,
-                           const PropertyTreeState& replay_state) const {
+                           const PropertyTreeState& replay_state,
+                           const IntPoint& offset) const {
   TRACE_EVENT0("blink,benchmark", "PaintArtifact::replay");
   DCHECK(RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
   Vector<const PaintChunk*> pointer_paint_chunks;
@@ -102,8 +105,8 @@
     pointer_paint_chunks.push_back(&chunk);
   scoped_refptr<cc::DisplayItemList> display_item_list =
       PaintChunksToCcLayer::Convert(
-          pointer_paint_chunks, replay_state, gfx::Vector2dF(),
-          GetDisplayItemList(),
+          pointer_paint_chunks, replay_state,
+          gfx::Vector2dF(offset.X(), offset.Y()), GetDisplayItemList(),
           cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer);
   canvas.drawPicture(display_item_list->ReleaseAsRecord());
 }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.h b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.h
index de30fc86..5825042 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.h
@@ -66,11 +66,15 @@
 
   // Draws the paint artifact to a GraphicsContext.
   // In SPv175+ mode, replays into the ancestor state given by |replay_state|.
-  void Replay(GraphicsContext&, const PropertyTreeState& replay_state) const;
+  void Replay(GraphicsContext&,
+              const PropertyTreeState& replay_state,
+              const IntPoint& offset = IntPoint()) const;
 
   // Draws the paint artifact to a PaintCanvas, into the ancestor state given
   // by |replay_state|. For SPv175+ only.
-  void Replay(PaintCanvas&, const PropertyTreeState& replay_state) const;
+  void Replay(PaintCanvas&,
+              const PropertyTreeState& replay_state,
+              const IntPoint& offset = IntPoint()) const;
 
   // Writes the paint artifact into a WebDisplayItemList.
   void AppendToWebDisplayItemList(const LayoutSize& visual_rect_offset,
diff --git a/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.cpp b/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.cpp
index a360d74..dede1ec 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.cpp
@@ -123,8 +123,7 @@
 void RasterInvalidationTracking::CheckUnderInvalidations(
     const String& layer_debug_name,
     sk_sp<PaintRecord> new_record,
-    const IntRect& new_interest_rect,
-    const IntPoint& paint_record_offset) {
+    const IntRect& new_interest_rect) {
   auto old_interest_rect = last_interest_rect_;
   Region invalidation_region;
   if (!g_simulate_raster_under_invalidations)
@@ -144,14 +143,13 @@
   if (rect.IsEmpty())
     return;
 
-  IntPoint canvas_offset = rect.Location() + paint_record_offset;
   SkBitmap old_bitmap;
   old_bitmap.allocPixels(
       SkImageInfo::MakeN32Premul(rect.Width(), rect.Height()));
   {
     SkiaPaintCanvas canvas(old_bitmap);
     canvas.clear(SK_ColorTRANSPARENT);
-    canvas.translate(-canvas_offset.X(), -canvas_offset.Y());
+    canvas.translate(-rect.X(), -rect.Y());
     canvas.drawPicture(std::move(old_record));
   }
 
@@ -161,7 +159,7 @@
   {
     SkiaPaintCanvas canvas(new_bitmap);
     canvas.clear(SK_ColorTRANSPARENT);
-    canvas.translate(-canvas_offset.X(), -canvas_offset.Y());
+    canvas.translate(-rect.X(), -rect.Y());
     canvas.drawPicture(std::move(new_record));
   }
 
@@ -203,7 +201,7 @@
   auto* canvas = recorder.getRecordingCanvas();
   if (under_invalidation_record_)
     canvas->drawPicture(std::move(under_invalidation_record_));
-  canvas->drawBitmap(new_bitmap, canvas_offset.X(), canvas_offset.Y());
+  canvas->drawBitmap(new_bitmap, rect.X(), rect.Y());
   under_invalidation_record_ = recorder.finishRecordingAsPicture();
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.h b/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.h
index d745996..65eb146 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/RasterInvalidationTracking.h
@@ -68,12 +68,9 @@
   // the corresponding pixels in UnderInvalidationRecord() will be drawn in
   // dark red. The caller can overlay UnderInvalidationRecord() onto the
   // original drawings to show the under raster invalidations.
-  // |paint_record_offset| is the offset of the space of |new_record| from the
-  // origin of the layer.
   void CheckUnderInvalidations(const String& layer_debug_name,
                                sk_sp<PaintRecord> new_record,
-                               const IntRect& new_interest_rect,
-                               const IntPoint& paint_record_offset);
+                               const IntRect& new_interest_rect);
 
   void AsJSON(JSONObject*);
 
diff --git a/ui/accessibility/platform/ax_system_caret_win.cc b/ui/accessibility/platform/ax_system_caret_win.cc
index 53609ca..82feb44 100644
--- a/ui/accessibility/platform/ax_system_caret_win.cc
+++ b/ui/accessibility/platform/ax_system_caret_win.cc
@@ -18,7 +18,10 @@
 AXSystemCaretWin::AXSystemCaretWin(gfx::AcceleratedWidget event_target)
     : event_target_(event_target) {
   caret_ = static_cast<AXPlatformNodeWin*>(AXPlatformNodeWin::Create(this));
-  data_.id = GetNextAXPlatformNodeUniqueId();
+  // The caret object is not part of the accessibility tree and so doesn't need
+  // a node ID. A globally unique ID is used when firing Win events, retrieved
+  // via |unique_id|.
+  data_.id = -1;
   data_.role = AX_ROLE_CARET;
   // |get_accState| should return 0 which means that the caret is visible.
   data_.state = 0;
@@ -28,7 +31,7 @@
 
   if (event_target_) {
     ::NotifyWinEvent(EVENT_OBJECT_CREATE, event_target_, OBJID_CARET,
-                     -data_.id);
+                     -caret_->unique_id());
   }
 }
 
@@ -38,7 +41,7 @@
   // retrieve the destroyed object in this stack frame.
   if (event_target_) {
     ::NotifyWinEvent(EVENT_OBJECT_DESTROY, event_target_, OBJID_CARET,
-                     -data_.id);
+                     -caret_->unique_id());
   }
 }
 
@@ -57,7 +60,7 @@
   data_.location = gfx::RectF(bounds);
   if (event_target_) {
     ::NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, event_target_, OBJID_CARET,
-                     -data_.id);
+                     -caret_->unique_id());
   }
 }
 
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html b/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
index e9e6ecb4..821cb3c 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
@@ -41,6 +41,14 @@
         min-width: 200px;
       }
 
+      .separator {
+        -webkit-border-start: var(--cr-separator-line);
+        -webkit-margin-end: var(--cr-section-padding);
+        -webkit-margin-start: var(--cr-section-padding);
+        flex-shrink: 0;
+        height: calc(var(--cr-section-min-height) - 9px);
+      }
+
       paper-toggle-button {
         -webkit-margin-start: var(--cr-button-edge-spacing);
       }