diff --git a/DEPS b/DEPS
index 20c46ef..289b0748 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '65115a1b1a5c72b47492dc447d1d282353ae3121',
+  'skia_revision': '60c05f98aa22d89e4ef25acb4799936f5df3cff2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -228,7 +228,7 @@
     Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '2410df43d212f3e71fc37601e2b79d431eb5b9da', # commit position 15596
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'fa849a2eb338b0932a973f35e14c56a5544a3072', # commit position 15611
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
index 5c29c5fd..ecf9fbaf 100644
--- a/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
@@ -4436,13 +4436,6 @@
     method register
     setter oncontrollerchange
     setter onmessage
-interface ServiceWorkerMessageEvent : Event
-    getter data
-    getter lastEventId
-    getter origin
-    getter ports
-    getter source
-    method constructor
 interface ServiceWorkerRegistration : EventTarget
     getter onupdatefound
     getter scope
diff --git a/ash/common/system/tray/fixed_sized_scroll_view.cc b/ash/common/system/tray/fixed_sized_scroll_view.cc
index e14a610..33fcef69 100644
--- a/ash/common/system/tray/fixed_sized_scroll_view.cc
+++ b/ash/common/system/tray/fixed_sized_scroll_view.cc
@@ -19,8 +19,10 @@
 
 FixedSizedScrollView::FixedSizedScrollView() {
   set_notify_enter_exit_on_child(true);
-  if (UseMd())
+  if (UseMd()) {
     SetVerticalScrollBar(new views::OverlayScrollBar(false));
+    SetHorizontalScrollBar(new views::OverlayScrollBar(true));
+  }
 }
 
 FixedSizedScrollView::~FixedSizedScrollView() {}
@@ -60,7 +62,7 @@
     return views::ScrollView::Layout();
 
   gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize());
-  bounds.set_width(std::max(0, width() - GetScrollBarWidth()));
+  bounds.set_width(std::max(0, width() - GetScrollBarLayoutWidth()));
   // Keep the origin of the contents unchanged so that the list will not scroll
   // away from the current visible region user is viewing. ScrollView::Layout()
   // will make sure the contents line up with its viewport properly if
@@ -71,7 +73,7 @@
   views::ScrollView::Layout();
   if (!vertical_scroll_bar()->visible()) {
     gfx::Rect bounds = contents()->bounds();
-    bounds.set_width(bounds.width() + GetScrollBarWidth());
+    bounds.set_width(bounds.width() + GetScrollBarLayoutWidth());
     contents()->SetBoundsRect(bounds);
   }
 }
@@ -81,7 +83,7 @@
     return;
 
   gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize());
-  bounds.set_width(std::max(0, width() - GetScrollBarWidth()));
+  bounds.set_width(std::max(0, width() - GetScrollBarLayoutWidth()));
   contents()->SetBoundsRect(bounds);
 }
 
diff --git a/ash/common/system/tray/tray_details_view.cc b/ash/common/system/tray/tray_details_view.cc
index 7086c0c3..2adf398 100644
--- a/ash/common/system/tray/tray_details_view.cc
+++ b/ash/common/system/tray/tray_details_view.cc
@@ -536,7 +536,7 @@
     // row.
     gfx::Size scroller_size = scroll_content_->GetPreferredSize();
     scroller_->set_fixed_size(
-        gfx::Size(width() + scroller_->GetScrollBarWidth(),
+        gfx::Size(width() + scroller_->GetScrollBarLayoutWidth(),
                   scroller_size.height() - (size.height() - height())));
   }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
index 36eff359..e0f7ad1c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
@@ -166,6 +166,9 @@
             // Notification.Builder.setPublicVersion was added in Android L.
             builder.setPublicVersion(createPublicNotification(mContext));
         }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            builder.setExtras(mExtras);
+        }
 
         Notification notification = builder.build();
         notification.bigContentView = bigView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java
index 6635ecca..94ee796 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java
@@ -18,6 +18,7 @@
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Icon;
 import android.os.Build;
+import android.os.Bundle;
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
@@ -121,6 +122,7 @@
     protected long[] mVibratePattern;
     protected long mTimestamp;
     protected boolean mRenotify;
+    protected Bundle mExtras;
 
     private Bitmap mLargeIcon;
 
@@ -309,6 +311,18 @@
     }
 
     /**
+     * Sets the extras bundle on supported platforms.
+     */
+    @TargetApi(Build.VERSION_CODES.M)
+    public NotificationBuilderBase setExtras(Bundle extras) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+            return this;
+        }
+        mExtras = extras;
+        return this;
+    }
+
+    /**
      * Gets the large icon for the notification.
      *
      * If a large icon was supplied to the builder, returns this icon, scaled to an appropriate size
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java
index fd9ae67..f601d75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java
@@ -4,7 +4,10 @@
 
 package org.chromium.chrome.browser.notifications;
 
+import android.annotation.TargetApi;
 import android.app.Notification;
+import android.os.Build;
+import android.service.notification.StatusBarNotification;
 
 /**
  * A proxy for the Android Notification Manager. This allows tests to be written without having to
@@ -18,4 +21,7 @@
     void cancelAll();
     void notify(int id, Notification notification);
     void notify(String tag, int id, Notification notification);
+
+    @TargetApi(Build.VERSION_CODES.M)
+    StatusBarNotification[] getActiveNotifications();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java
index b05fd0047..ece1f75c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java
@@ -6,6 +6,7 @@
 
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.service.notification.StatusBarNotification;
 
 /**
  * Default implementation of the NotificationManagerProxy, which passes through all calls to the
@@ -42,4 +43,9 @@
     public void notify(String tag, int id, Notification notification) {
         mNotificationManager.notify(tag, id, notification);
     }
+
+    @Override
+    public StatusBarNotification[] getActiveNotifications() {
+        return mNotificationManager.getActiveNotifications();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
index 26a96f9..d1c4d1b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -15,6 +15,7 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
+import android.service.notification.StatusBarNotification;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
@@ -43,6 +44,8 @@
 
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.annotation.Nullable;
 
@@ -572,6 +575,15 @@
                 makeDefaults(vibrationPattern.length, silent, vibrateEnabled));
         notificationBuilder.setVibrate(makeVibrationPattern(vibrationPattern));
 
+        // The extras bundle is available from API 20 but it's currenlty only used to retrieve
+        // notifications which is only available from 23 (Marshmallow) onwards.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            Bundle extras = new Bundle();
+            extras.putString(NotificationConstants.EXTRA_NOTIFICATION_ID, notificationId);
+            extras.putString(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_ID, profileId);
+            notificationBuilder.setExtras(extras);
+        }
+
         String platformTag = makePlatformTag(notificationId, origin, tag);
         if (webApkPackage.isEmpty()) {
             mNotificationManager.notify(platformTag, PLATFORM_ID, notificationBuilder.build());
@@ -676,6 +688,35 @@
     }
 
     /**
+     * Returns the notification ids on disply for a given |profileId|.
+     *
+     * @param profileId of the profile to retrieve notifications for.
+     */
+    @CalledByNative
+    private String[] getNotificationsForProfile(String profileId) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+            return null;
+        }
+
+        StatusBarNotification[] displayedNotifications =
+                mNotificationManager.getActiveNotifications();
+        List<String> notifications = new ArrayList<String>();
+        for (StatusBarNotification notification : displayedNotifications) {
+            Bundle extras = notification.getNotification().extras;
+            String notificationId = extras.getString(NotificationConstants.EXTRA_NOTIFICATION_ID);
+            String notificationProfileId =
+                    extras.getString(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_ID);
+            if (notificationId != null && profileId.equals(notificationProfileId)) {
+                notifications.add(notificationId);
+            }
+        }
+        if (notifications.size() == 0) return null;
+
+        String[] result = new String[notifications.size()];
+        return notifications.toArray(result);
+    }
+
+    /**
      * Calls NotificationPlatformBridgeAndroid::OnNotificationClicked in native code to indicate
      * that the notification with the given parameters has been clicked on.
      *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java
index 337b6f4..705d7c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java
@@ -60,6 +60,9 @@
             // Notification.Builder.setPublicVersion was added in Android L.
             builder.setPublicVersion(createPublicNotification(mContext));
         }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            builder.setExtras(mExtras);
+        }
         return builder.build();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAddress.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAddress.java
index c4af2085..9e8102f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAddress.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAddress.java
@@ -163,6 +163,7 @@
 
         switch (checkAddressCompletionStatus(mProfile)) {
             case COMPLETE:
+                editTitleResId = R.string.autofill_edit_profile;
                 break;
             case INVALID_ADDRESS:
                 editMessageResId = R.string.payments_invalid_address;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
index cb71c8a..2069212 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
@@ -256,7 +256,7 @@
      */
     private void checkAndUpateCardCompleteness() {
         int editMessageResId = 0; // Zero is the invalid resource Id.
-        int editTitleResId = 0;
+        int editTitleResId = R.string.payments_edit_card;
         int invalidFieldsCount = 0;
 
         if (mBillingAddress == null) {
@@ -287,7 +287,7 @@
         }
 
         mEditMessage = editMessageResId == 0 ? null : mContext.getString(editMessageResId);
-        mEditTitle = editTitleResId == 0 ? null : mContext.getString(editTitleResId);
+        mEditTitle = mContext.getString(editTitleResId);
         mIsComplete = mEditMessage == null;
     }
 
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 7547369..b71af7e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -597,25 +597,6 @@
     {IDS_FLAGS_SSL_VERSION_MAX_TLS13, switches::kSSLVersionMax, "tls1.3"},
 };
 
-const FeatureEntry::Choice kSecurityChipChoices[] = {
-    {IDS_FLAGS_SECURITY_CHIP_DEFAULT, "", ""},
-    {IDS_FLAGS_SECURITY_CHIP_SHOW_NONSECURE_ONLY, switches::kSecurityChip,
-     switches::kSecurityChipShowNonSecureOnly},
-    {IDS_FLAGS_SECURITY_CHIP_SHOW_ALL, switches::kSecurityChip,
-     switches::kSecurityChipShowAll},
-};
-
-const FeatureEntry::Choice kSecurityChipAnimationChoices[] = {
-    {IDS_FLAGS_SECURITY_CHIP_ANIMATION_DEFAULT, "", ""},
-    {IDS_FLAGS_SECURITY_CHIP_ANIMATION_NONE, switches::kSecurityChipAnimation,
-     switches::kSecurityChipAnimationNone},
-    {IDS_FLAGS_SECURITY_CHIP_ANIMATION_NONSECURE_ONLY,
-     switches::kSecurityChipAnimation,
-     switches::kSecurityChipAnimationNonSecureOnly},
-    {IDS_FLAGS_SECURITY_CHIP_ANIMATION_ALL, switches::kSecurityChipAnimation,
-     switches::kSecurityChipAnimationAll},
-};
-
 #if !defined(OS_ANDROID)
 const FeatureEntry::Choice kEnableDefaultMediaSessionChoices[] = {
     {IDS_FLAGS_ENABLE_DEFAULT_MEDIA_SESSION_DISABLED, "", ""},
@@ -2052,12 +2033,6 @@
      IDS_FLAGS_EXPENSIVE_BACKGROUND_TIMER_THROTTLING_NAME,
      IDS_FLAGS_EXPENSIVE_BACKGROUND_TIMER_THROTTLING_DESCRIPTION, kOsAll,
      FEATURE_VALUE_TYPE(features::kExpensiveBackgroundTimerThrottling)},
-    {"security-chip", IDS_FLAGS_SECURITY_CHIP_NAME,
-     IDS_FLAGS_SECURITY_CHIP_DESCRIPTION, kOsDesktop,
-     MULTI_VALUE_TYPE(kSecurityChipChoices)},
-    {"security-chip-animation", IDS_FLAGS_SECURITY_CHIP_ANIMATION_NAME,
-     IDS_FLAGS_SECURITY_CHIP_ANIMATION_DESCRIPTION, kOsDesktop,
-     MULTI_VALUE_TYPE(kSecurityChipAnimationChoices)},
 #if defined(OS_CHROMEOS)
     {"enumerate-audio-devices", IDS_FLAGS_ENABLE_ENUMERATING_AUDIO_DEVICES_NAME,
      IDS_FLAGS_ENABLE_ENUMERATING_AUDIO_DEVICES_DESCRIPTION, kOsCrOS,
diff --git a/chrome/browser/android/offline_pages/recent_tab_helper_unittest.cc b/chrome/browser/android/offline_pages/recent_tab_helper_unittest.cc
index 0fbca927..8a5fbfe 100644
--- a/chrome/browser/android/offline_pages/recent_tab_helper_unittest.cc
+++ b/chrome/browser/android/offline_pages/recent_tab_helper_unittest.cc
@@ -246,7 +246,7 @@
   RunUntilIdle();
   EXPECT_TRUE(model()->is_loaded());
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
 }
 
@@ -263,7 +263,7 @@
   EXPECT_TRUE(model()->is_loaded());
   GetAllPages();
   // No page should be captured.
-  EXPECT_EQ(0U, all_pages().size());
+  ASSERT_EQ(0U, all_pages().size());
 }
 
 // Triggers two snapshot captures during a single page load. Should end up with
@@ -281,7 +281,7 @@
   EXPECT_EQ(1U, page_added_count());
   EXPECT_EQ(0U, model_removed_count());
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
   int64_t first_offline_id = all_pages()[0].offline_id;
 
@@ -294,7 +294,7 @@
   EXPECT_EQ(1U, model_removed_count());
   // the same page should be simply overridden.
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
   EXPECT_NE(first_offline_id, all_pages()[0].offline_id);
 }
@@ -316,7 +316,7 @@
   EXPECT_EQ(1U, page_added_count());
   EXPECT_EQ(0U, model_removed_count());
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
   int64_t first_offline_id = all_pages()[0].offline_id;
 
@@ -339,7 +339,7 @@
   EXPECT_EQ(0U, model_removed_count());
   // The exact same page should still be available.
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
   EXPECT_EQ(first_offline_id, all_pages()[0].offline_id);
 }
@@ -359,7 +359,7 @@
   EXPECT_EQ(1U, page_added_count());
   EXPECT_EQ(0U, model_removed_count());
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
   int64_t first_offline_id = all_pages()[0].offline_id;
 
@@ -373,7 +373,7 @@
   EXPECT_EQ(1U, model_removed_count());
   // the same page should be simply overridden.
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
   EXPECT_NE(first_offline_id, all_pages()[0].offline_id);
 }
@@ -394,7 +394,7 @@
   EXPECT_EQ(1U, page_added_count());
   EXPECT_EQ(0U, model_removed_count());
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
 
   // Sets a new delegate that will make the second snapshot fail.
@@ -417,7 +417,7 @@
   EXPECT_EQ(1U, model_removed_count());
   // the same page should be simply overridden.
   GetAllPages();
-  EXPECT_EQ(0U, all_pages().size());
+  ASSERT_EQ(0U, all_pages().size());
 }
 
 // Triggers two snapshot captures for two different page loads and URLs. Should
@@ -435,7 +435,7 @@
   EXPECT_EQ(1U, page_added_count());
   EXPECT_EQ(0U, model_removed_count());
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
 
   NavigateAndCommit(kTestPageUrlOther);
@@ -448,7 +448,7 @@
   EXPECT_EQ(1U, model_removed_count());
   // the same page should be simply overridden.
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrlOther, all_pages()[0].url);
 }
 
@@ -469,7 +469,7 @@
   EXPECT_EQ(2U, page_added_count());
   EXPECT_EQ(1U, model_removed_count());
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   EXPECT_EQ(kTestPageUrl, all_pages()[0].url);
   int64_t first_offline_id = all_pages()[0].offline_id;
 
@@ -515,7 +515,7 @@
   RunUntilIdle();
   EXPECT_TRUE(model()->is_loaded());
   GetAllPages();
-  EXPECT_EQ(0U, all_pages().size());
+  ASSERT_EQ(0U, all_pages().size());
 }
 
 // Checks that no snapshots are created if the Offline Page Cache feature is
@@ -530,20 +530,21 @@
   EXPECT_TRUE(model()->is_loaded());
   GetAllPages();
   // No page should be captured.
-  EXPECT_EQ(0U, all_pages().size());
+  ASSERT_EQ(0U, all_pages().size());
 }
 
 // Simulates a download request to offline the current page. Should end up with
 // one offline pages.
-TEST_F(RecentTabHelperTest, DISABLED_DownloadRequest) {
+TEST_F(RecentTabHelperTest, DownloadRequest) {
   NavigateAndCommit(kTestPageUrl);
   recent_tab_helper()->ObserveAndDownloadCurrentPage(
       ClientId("download", "id1"), 153L);
   recent_tab_helper()->DocumentOnLoadCompletedInMainFrame();
+  FastForwardSnapshotController();
   RunUntilIdle();
   EXPECT_TRUE(model()->is_loaded());
   GetAllPages();
-  EXPECT_EQ(1U, all_pages().size());
+  ASSERT_EQ(1U, all_pages().size());
   const OfflinePageItem& page = all_pages()[0];
   EXPECT_EQ(kTestPageUrl, page.url);
   EXPECT_EQ("download", page.client_id.name_space);
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc
index 04985568..f12b8667 100644
--- a/chrome/browser/android/vr_shell/vr_shell.cc
+++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -106,9 +106,11 @@
                  gvr_context* gvr_api)
     : WebContentsObserver(ui_contents),
       main_contents_(main_contents),
+      content_compositor_(new VrCompositor(content_window, false)),
       ui_contents_(ui_contents),
+      ui_compositor_(new VrCompositor(ui_window, true)),
       delegate_(delegate),
-      metrics_helper_(new VrMetricsHelper(main_contents)),
+      metrics_helper_(new VrMetricsHelper(main_contents_)),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       weak_ptr_factory_(this) {
   DCHECK(g_instance == nullptr);
@@ -118,6 +120,9 @@
   content_input_manager_.reset(new VrInputManager(main_contents_));
   ui_input_manager_.reset(new VrInputManager(ui_contents_));
 
+  content_compositor_->SetLayer(main_contents_);
+  ui_compositor_->SetLayer(ui_contents_);
+
   gl_thread_.reset(new GLThread(this, weak_ptr_factory_.GetWeakPtr(),
                                 content_input_manager_->GetWeakPtr(),
                                 ui_input_manager_->GetWeakPtr(),
@@ -133,10 +138,6 @@
   html_interface_.reset(new UiInterface(
       for_web_vr ? UiInterface::Mode::WEB_VR : UiInterface::Mode::STANDARD,
       main_contents_->IsFullscreen()));
-  content_compositor_.reset(new VrCompositor(content_window, false));
-  content_compositor_->SetLayer(main_contents_);
-  ui_compositor_.reset(new VrCompositor(ui_window, true));
-  ui_compositor_->SetLayer(ui_contents_);
   vr_web_contents_observer_.reset(new VrWebContentsObserver(
       main_contents, html_interface_.get(), this));
 
diff --git a/chrome/browser/android/vr_shell/vr_shell.h b/chrome/browser/android/vr_shell/vr_shell.h
index 5de0c394..bd41379 100644
--- a/chrome/browser/android/vr_shell/vr_shell.h
+++ b/chrome/browser/android/vr_shell/vr_shell.h
@@ -145,10 +145,11 @@
 
   std::unique_ptr<UiInterface> html_interface_;
 
-  std::unique_ptr<VrCompositor> content_compositor_;
   content::WebContents* main_contents_;
-  std::unique_ptr<VrCompositor> ui_compositor_;
+  std::unique_ptr<VrCompositor> content_compositor_;
   content::WebContents* ui_contents_;
+  std::unique_ptr<VrCompositor> ui_compositor_;
+
   std::unique_ptr<VrWebContentsObserver> vr_web_contents_observer_;
 
   VrShellDelegate* delegate_ = nullptr;
@@ -156,8 +157,7 @@
 
   std::unique_ptr<VrInputManager> content_input_manager_;
   std::unique_ptr<VrInputManager> ui_input_manager_;
-
-  scoped_refptr<VrMetricsHelper> metrics_helper_;
+  std::unique_ptr<VrMetricsHelper> metrics_helper_;
 
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
   std::unique_ptr<base::Thread> gl_thread_;
diff --git a/chrome/browser/android/vr_shell/vr_usage_monitor.cc b/chrome/browser/android/vr_shell/vr_usage_monitor.cc
index 8bfae60..8381fbf 100644
--- a/chrome/browser/android/vr_shell/vr_usage_monitor.cc
+++ b/chrome/browser/android/vr_shell/vr_usage_monitor.cc
@@ -175,32 +175,16 @@
     SetVrMode(mode);
 }
 
-void VrMetricsHelper::SetWebVREnabledOnMainThread(bool is_webvr_presenting) {
-  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
+void VrMetricsHelper::SetWebVREnabled(bool is_webvr_presenting) {
   is_webvr_ = is_webvr_presenting;
   UpdateMode();
 }
 
-void VrMetricsHelper::SetVRActiveOnMainThread(bool is_vr_enabled) {
-  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
+void VrMetricsHelper::SetVRActive(bool is_vr_enabled) {
   is_vr_enabled_ = is_vr_enabled;
   UpdateMode();
 }
 
-void VrMetricsHelper::SetWebVREnabled(bool is_webvr) {
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&VrMetricsHelper::SetWebVREnabledOnMainThread, this,
-                 is_webvr));
-}
-
-void VrMetricsHelper::SetVRActive(bool is_vr_enabled) {
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&VrMetricsHelper::SetVRActiveOnMainThread, this,
-                 is_vr_enabled));
-}
-
 void VrMetricsHelper::SetVrMode(VRMode mode) {
   DCHECK(mode != mode_);
 
@@ -278,8 +262,7 @@
   mode_ = mode;
 }
 
-VrMetricsHelper::VrMetricsHelper(content::WebContents* contents)
-    : thread_id_(base::PlatformThread::CurrentId()) {
+VrMetricsHelper::VrMetricsHelper(content::WebContents* contents) {
   num_videos_playing_ = contents->GetCurrentlyPlayingVideoCount();
   is_fullscreen_ = contents->IsFullscreen();
   origin_ = contents->GetLastCommittedURL();
@@ -291,13 +274,10 @@
       maximumVideoSessionGap, minimumVideoSessionDuration));
 }
 
-VrMetricsHelper::~VrMetricsHelper() {
-  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
-}
+VrMetricsHelper::~VrMetricsHelper() = default;
 
 void VrMetricsHelper::MediaStartedPlaying(const MediaPlayerInfo& media_info,
                                           const MediaPlayerId&) {
-  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
   if (!media_info.has_video)
     return;
 
@@ -318,7 +298,6 @@
 
 void VrMetricsHelper::MediaStoppedPlaying(const MediaPlayerInfo& media_info,
                                           const MediaPlayerId&) {
-  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
   if (!media_info.has_video)
     return;
 
@@ -336,7 +315,6 @@
 }
 
 void VrMetricsHelper::DidFinishNavigation(content::NavigationHandle* handle) {
-  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
   if (handle != nullptr && handle->HasCommitted() && handle->IsInMainFrame()) {
     origin_ = handle->GetURL();
     // Counting the number of pages viewed is difficult - some websites load
@@ -352,7 +330,6 @@
 
 void VrMetricsHelper::DidToggleFullscreenModeForTab(bool entered_fullscreen,
                                                     bool will_cause_resize) {
-  DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
   is_fullscreen_ = entered_fullscreen;
   UpdateMode();
 }
diff --git a/chrome/browser/android/vr_shell/vr_usage_monitor.h b/chrome/browser/android/vr_shell/vr_usage_monitor.h
index 7e1c6e29..594f348 100644
--- a/chrome/browser/android/vr_shell/vr_usage_monitor.h
+++ b/chrome/browser/android/vr_shell/vr_usage_monitor.h
@@ -5,7 +5,9 @@
 #ifndef CHROME_BROWSER_ANDROID_VR_SHELL_VR_USAGE_MONITOR_H_
 #define CHROME_BROWSER_ANDROID_VR_SHELL_VR_USAGE_MONITOR_H_
 
-#include "base/threading/platform_thread.h"
+#include <memory>
+
+#include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
@@ -51,21 +53,15 @@
   DISALLOW_COPY_AND_ASSIGN(SessionTimer);
 };
 
-// Most methods of this class are not threadsafe - they must be called
-// on the Browser's main thread.  This happens by default except for
-// SetWebVREnabled and SetVRActive, where we'll post a message to get to the
-// correct thread.
-// Destruction must happen on the main thread, or there could be corruption when
-// WebContentsObserver unregisters itself from the web_contents_.
-// There are DCHECKS to ensure these threading rules are satisfied.
-class VrMetricsHelper : public content::WebContentsObserver,
-                        public base::RefCountedThreadSafe<VrMetricsHelper> {
+// This class is not threadsafe and must only be used from the main thread.
+class VrMetricsHelper : public content::WebContentsObserver {
  public:
   explicit VrMetricsHelper(content::WebContents*);
-
+  ~VrMetricsHelper() override;
   void SetWebVREnabled(bool is_webvr_presenting);
   void SetVRActive(bool is_vr_enabled);
 
+ private:
   // WebContentObserver
   void MediaStartedPlaying(const MediaPlayerInfo& media_info,
                            const MediaPlayerId&) override;
@@ -75,13 +71,6 @@
   void DidToggleFullscreenModeForTab(bool entered_fullscreen,
                                      bool will_cause_resize) override;
 
- protected:
-  friend class base::RefCountedThreadSafe<VrMetricsHelper>;
-  ~VrMetricsHelper() override;
-
-  void SetWebVREnabledOnMainThread(bool is_webvr_presenting);
-  void SetVRActiveOnMainThread(bool is_vr_enabled);
-
   void SetVrMode(VRMode mode);
   void UpdateMode();
 
@@ -102,9 +91,6 @@
   int num_session_video_playback_ = 0;
 
   GURL origin_;
-
-  // not thread safe, so ensure we are on the same thread at all times:
-  base::PlatformThreadId thread_id_;
 };
 
 }  // namespace vr_shell
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc
index 6c0b9a9b..b498453 100644
--- a/chrome/browser/extensions/api/automation/automation_apitest.cc
+++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -83,7 +83,7 @@
   content::WebContents* const tab =
       browser()->tab_strip_model()->GetWebContentsAt(0);
   ASSERT_FALSE(tab->IsFullAccessibilityModeForTesting());
-  ASSERT_FALSE(tab->IsTreeOnlyAccessibilityModeForTesting());
+  ASSERT_FALSE(tab->IsWebContentsOnlyAccessibilityModeForTesting());
 
   base::FilePath extension_path =
       test_data_dir_.AppendASCII("automation/tests/basic");
@@ -92,7 +92,7 @@
   ASSERT_TRUE(got_tree.WaitUntilSatisfied());
 
   ASSERT_FALSE(tab->IsFullAccessibilityModeForTesting());
-  ASSERT_TRUE(tab->IsTreeOnlyAccessibilityModeForTesting());
+  ASSERT_TRUE(tab->IsWebContentsOnlyAccessibilityModeForTesting());
 }
 
 IN_PROC_BROWSER_TEST_F(AutomationApiTest, SanityCheck) {
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
index f564ab7..f2238ac 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
+++ b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
@@ -28,6 +28,7 @@
 #include "content/public/browser/browser_accessibility_state.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_plugin_guest_manager.h"
+#include "content/public/browser/media_session.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
@@ -222,6 +223,26 @@
         browser_context_);
   }
 
+  void MediaStartedPlaying(const MediaPlayerInfo& video_type,
+                           const MediaPlayerId& id) override {
+    std::vector<content::AXEventNotificationDetails> details;
+    content::AXEventNotificationDetails detail;
+    detail.ax_tree_id = id.first->GetAXTreeID();
+    detail.event_type = ui::AX_EVENT_MEDIA_STARTED_PLAYING;
+    details.push_back(detail);
+    AccessibilityEventReceived(details);
+  }
+
+  void MediaStoppedPlaying(const MediaPlayerInfo& video_type,
+                           const MediaPlayerId& id) override {
+    std::vector<content::AXEventNotificationDetails> details;
+    content::AXEventNotificationDetails detail;
+    detail.ax_tree_id = id.first->GetAXTreeID();
+    detail.event_type = ui::AX_EVENT_MEDIA_STOPPED_PLAYING;
+    details.push_back(detail);
+    AccessibilityEventReceived(details);
+  }
+
  private:
   friend class content::WebContentsUserData<AutomationWebContentsObserver>;
 
@@ -271,7 +292,7 @@
   }
 
   AutomationWebContentsObserver::CreateForWebContents(contents);
-  contents->EnableTreeOnlyAccessibilityMode();
+  contents->EnableWebContentsOnlyAccessibilityMode();
 
   int ax_tree_id = rfh->GetAXTreeID();
 
@@ -305,7 +326,7 @@
   // Only call this if this is the root of a frame tree, to avoid resetting
   // the accessibility state multiple times.
   if (!rfh->GetParent())
-    contents->EnableTreeOnlyAccessibilityMode();
+    contents->EnableWebContentsOnlyAccessibilityMode();
 
   return RespondNow(NoArguments());
 }
@@ -334,13 +355,36 @@
   if (!rfh)
     return RespondNow(Error("Ignoring action on destroyed node"));
 
-  const content::WebContents* contents =
+  content::WebContents* contents =
       content::WebContents::FromRenderFrameHost(rfh);
   if (!CanRequestAutomation(extension(), automation_info, contents)) {
     return RespondNow(
         Error(kCannotRequestAutomationOnPage, contents->GetURL().spec()));
   }
 
+  // These actions are handled directly for the WebContents.
+  if (params->args.action_type ==
+      api::automation_internal::ACTION_TYPE_STARTDUCKINGMEDIA) {
+    content::MediaSession* session = content::MediaSession::Get(contents);
+    session->StartDucking();
+    return RespondNow(NoArguments());
+  } else if (params->args.action_type ==
+             api::automation_internal::ACTION_TYPE_STOPDUCKINGMEDIA) {
+    content::MediaSession* session = content::MediaSession::Get(contents);
+    session->StopDucking();
+    return RespondNow(NoArguments());
+  } else if (params->args.action_type ==
+             api::automation_internal::ACTION_TYPE_RESUMEMEDIA) {
+    content::MediaSession* session = content::MediaSession::Get(contents);
+    session->Resume(content::MediaSession::SuspendType::SYSTEM);
+    return RespondNow(NoArguments());
+  } else if (params->args.action_type ==
+             api::automation_internal::ACTION_TYPE_SUSPENDMEDIA) {
+    content::MediaSession* session = content::MediaSession::Get(contents);
+    session->Suspend(content::MediaSession::SuspendType::SYSTEM);
+    return RespondNow(NoArguments());
+  }
+
   RenderFrameHostActionAdapter adapter(rfh);
   return RouteActionToAdapter(params.get(), &adapter);
 }
diff --git a/chrome/browser/notifications/notification_platform_bridge_android.cc b/chrome/browser/notifications/notification_platform_bridge_android.cc
index 0c8c82f..3f64247 100644
--- a/chrome/browser/notifications/notification_platform_bridge_android.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_android.cc
@@ -7,6 +7,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/android/build_info.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/command_line.h"
@@ -315,8 +316,30 @@
     const std::string& profile_id,
     bool incognito,
     std::set<std::string>* notifications) const {
-  // TODO(miguelg): This can actually be implemented for M+
-  return false;
+  DCHECK(notifications);
+  JNIEnv* env = AttachCurrentThread();
+
+  // Android only supports retrieving existing notifications from M+
+  if (base::android::BuildInfo::GetInstance()->sdk_int() <
+      base::android::SDK_VERSION_MARSHMALLOW) {
+    return false;
+  }
+
+  const ScopedJavaLocalRef<jstring> j_profile_id =
+      ConvertUTF8ToJavaString(env, profile_id);
+
+  ScopedJavaLocalRef<jobjectArray> j_notification_ids =
+      Java_NotificationPlatformBridge_getNotificationsForProfile(
+          env, java_object_, j_profile_id);
+  if (j_notification_ids.obj()) {
+    std::vector<std::string> notification_ids;
+    base::android::AppendJavaStringArrayToStringVector(
+        env, j_notification_ids.obj(), &notification_ids);
+    for (const auto& id : notification_ids) {
+      notifications->insert(id);
+    }
+  }
+  return true;
 }
 
 // static
diff --git a/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc b/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc
index 0970f35..22c0004 100644
--- a/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc
+++ b/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc
@@ -19,7 +19,7 @@
 ChromePopularSitesFactory::NewForProfile(Profile* profile) {
   base::FilePath directory;  // remains empty if PathService::Get() fails.
   PathService::Get(chrome::DIR_USER_DATA, &directory);
-  return base::MakeUnique<ntp_tiles::PopularSites>(
+  return base::MakeUnique<ntp_tiles::PopularSitesImpl>(
       content::BrowserThread::GetBlockingPool(), profile->GetPrefs(),
       TemplateURLServiceFactory::GetForProfile(profile),
       g_browser_process->variations_service(), profile->GetRequestContext(),
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index bfc962a..acfa037 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -564,7 +564,7 @@
 
 #if BUILDFLAG(ANDROID_JAVA_UI)
   variations::VariationsService::RegisterProfilePrefs(registry);
-  ntp_tiles::PopularSites::RegisterProfilePrefs(registry);
+  ntp_tiles::PopularSitesImpl::RegisterProfilePrefs(registry);
   NewTabPagePrefs::RegisterProfilePrefs(registry);
   PartnerBookmarksShim::RegisterProfilePrefs(registry);
 #else
diff --git a/chrome/browser/resources/chromeos/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
index 3b2e28d..c0b4895 100644
--- a/chrome/browser/resources/chromeos/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
@@ -137,6 +137,7 @@
   "cvox2/background/i_search.js",
   "cvox2/background/keyboard_handler.js",
   "cvox2/background/live_regions.js",
+  "cvox2/background/media_automation_handler.js",
   "cvox2/background/next_earcons.js",
   "cvox2/background/notifications.js",
   "cvox2/background/output.js",
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/media_automation_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/media_automation_handler.js
new file mode 100644
index 0000000..8a57c06
--- /dev/null
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/media_automation_handler.js
@@ -0,0 +1,48 @@
+// 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.
+
+/**
+ * @fileoverview Handles media events automation.
+ */
+
+goog.provide('MediaAutomationHandler');
+
+goog.require('BaseAutomationHandler');
+
+goog.scope(function() {
+var AutomationEvent = chrome.automation.AutomationEvent;
+var AutomationNode = chrome.automation.AutomationNode;
+var EventType = chrome.automation.EventType;
+var RoleType = chrome.automation.RoleType;
+
+/**
+ * @param {!AutomationNode} node The root to observe media changes.
+ * @constructor
+ * @extends {BaseAutomationHandler}
+ */
+MediaAutomationHandler = function(node) {
+  BaseAutomationHandler.call(this, node);
+
+  var e = EventType;
+  this.addListener_(e.mediaStartedPlaying, this.onMediaStartedPlaying);
+  this.addListener_(e.mediaStoppedPlaying, this.onMediaStoppedPlaying);
+};
+
+MediaAutomationHandler.prototype = {
+  __proto__: BaseAutomationHandler.prototype,
+
+  /**
+   * @param {!AutomationEvent} evt
+   */
+  onMediaStartedPlaying: function(evt) {
+  },
+
+  /**
+   * @param {!AutomationEvent} evt
+   */
+  onMediaStoppedPlaying: function(evt) {
+  }
+};
+
+});  // goog.scope
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
index 5fe826d..5f158f2 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
@@ -9,6 +9,7 @@
 #import "base/mac/sdk_forward_declarations.h"
 #include "chrome/browser/themes/theme_service.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/l10n_util.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
@@ -46,6 +47,9 @@
   resizeAnimation_.reset([[NSViewAnimation alloc] init]);
   [resizeAnimation_ setDuration:kAnimationDuration];
   [resizeAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
+  [self setAlignment:cocoa_l10n_util::ShouldDoExperimentalRTLLayout()
+                         ? NSRightTextAlignment
+                         : NSLeftTextAlignment];
 
   // Disable Force Touch in the Omnibox. Note that this API is defined in
   // 10.10.3 and higher so have to check more than just isYosmiteOrLater().
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
index 02a40a8..1d3a1030 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
@@ -318,22 +318,6 @@
   // Indicates whether or not the location bar is currently visible.
   bool location_bar_visible_;
 
-  // True if the HTTPS state should be displayed on the security state
-  // decoration. This does not apply to the EV cert.
-  bool should_show_secure_verbose_;
-
-  // True if the non-secure state should be displayed on the security state
-  // decoration.
-  bool should_show_nonsecure_verbose_;
-
-  // True if the security state decoration should be animated for a secure
-  // security level.
-  bool should_animate_secure_verbose_;
-
-  // True if the security state decoration should be animated for a non-secure
-  // security level.
-  bool should_animate_nonsecure_verbose_;
-
   // True if there's enough room for the omnibox to show the security verbose.
   // If the verbose is displaying the EV cert, then this should always be true.
   bool is_width_available_for_security_verbose_;
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
index 5816108..7e0308f 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -5,7 +5,6 @@
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #import "base/mac/mac_util.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
@@ -50,8 +49,6 @@
 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_features.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
@@ -123,10 +120,6 @@
           new ManagePasswordsDecoration(command_updater, this)),
       browser_(browser),
       location_bar_visible_(true),
-      should_show_secure_verbose_(false),
-      should_show_nonsecure_verbose_(false),
-      should_animate_secure_verbose_(false),
-      should_animate_nonsecure_verbose_(false),
       is_width_available_for_security_verbose_(false),
       security_level_(security_state::NONE),
       weak_ptr_factory_(this) {
@@ -150,39 +143,6 @@
   [[field_ cell] setIsPopupMode:
       !browser->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)];
 
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  std::string security_chip;
-  if (command_line->HasSwitch(switches::kSecurityChip)) {
-    security_chip = command_line->GetSwitchValueASCII(switches::kSecurityChip);
-  } else if (base::FeatureList::IsEnabled(features::kSecurityChip)) {
-    security_chip = variations::GetVariationParamValueByFeature(
-        features::kSecurityChip, kSecurityChipFeatureVisibilityParam);
-  }
-
-  if (security_chip == switches::kSecurityChipShowNonSecureOnly) {
-    should_show_nonsecure_verbose_ = true;
-  } else if (security_chip == switches::kSecurityChipShowAll) {
-    should_show_secure_verbose_ = true;
-    should_show_nonsecure_verbose_ = true;
-  }
-
-  std::string security_chip_animation;
-  if (command_line->HasSwitch(switches::kSecurityChipAnimation)) {
-    security_chip_animation =
-        command_line->GetSwitchValueASCII(switches::kSecurityChipAnimation);
-  } else if (base::FeatureList::IsEnabled(features::kSecurityChip)) {
-    security_chip_animation = variations::GetVariationParamValueByFeature(
-        features::kSecurityChip, kSecurityChipFeatureAnimationParam);
-  }
-
-  if (security_chip_animation ==
-      switches::kSecurityChipAnimationNonSecureOnly) {
-    should_animate_nonsecure_verbose_ = true;
-  } else if (security_chip_animation == switches::kSecurityChipAnimationAll) {
-    should_animate_secure_verbose_ = true;
-    should_animate_nonsecure_verbose_ = true;
-  }
-
   // Sets images for the decorations, and performs a layout. This call ensures
   // that this class is in a consistent state after initialization.
   OnChanged();
@@ -701,14 +661,10 @@
   security_state::SecurityLevel security =
       GetToolbarModel()->GetSecurityLevel(false);
 
-  if (security == security_state::EV_SECURE)
-    return true;
-  else if (security == security_state::SECURE)
-    return should_show_secure_verbose_;
-
-  return should_show_nonsecure_verbose_ &&
-         (security == security_state::DANGEROUS ||
-          security == security_state::HTTP_SHOW_WARNING);
+  return security == security_state::EV_SECURE ||
+         security == security_state::SECURE ||
+         security == security_state::DANGEROUS ||
+         security == security_state::HTTP_SHOW_WARNING;
 }
 
 bool LocationBarViewMac::IsLocationBarDark() const {
@@ -925,15 +881,8 @@
 
 bool LocationBarViewMac::CanAnimateSecurityLevel(
     security_state::SecurityLevel level) const {
-  using SecurityLevel = security_state::SecurityLevel;
-  if (IsSecureConnection(level)) {
-    return should_animate_secure_verbose_;
-  } else if (security_level_ == SecurityLevel::DANGEROUS ||
-             security_level_ == SecurityLevel::HTTP_SHOW_WARNING) {
-    return should_animate_nonsecure_verbose_;
-  } else {
-    return false;
-  }
+  return security_level_ == security_state::SecurityLevel::DANGEROUS ||
+         security_level_ == security_state::SecurityLevel::HTTP_SHOW_WARNING;
 }
 
 bool LocationBarViewMac::IsSecureConnection(
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
index d90e5d8..18c18df0 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
@@ -10,6 +10,7 @@
 
 #include <memory>
 
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
@@ -133,6 +134,8 @@
   AutocompleteTextField* field() const { return field_; }
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(OmniboxViewMacTest, WritingDirectionLTR);
+  FRIEND_TEST_ALL_PREFIXES(OmniboxViewMacTest, WritingDirectionRTL);
   // Called when the user hits backspace in |field_|.  Checks whether
   // keyword search is being terminated.  Returns true if the
   // backspace should be intercepted (not forwarded on to the standard
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
index 715d115..cd2b95f 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
@@ -17,7 +17,8 @@
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/themes/theme_service.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/l10n_util.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
 #include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h"
@@ -530,6 +531,10 @@
   [paragraph_style setMaximumLineHeight:line_height];
   [paragraph_style setMinimumLineHeight:line_height];
   [paragraph_style setLineBreakMode:NSLineBreakByTruncatingTail];
+  // Set an explicit alignment so it isn't implied from writing direction.
+  [paragraph_style setAlignment:cocoa_l10n_util::ShouldDoExperimentalRTLLayout()
+                                    ? NSRightTextAlignment
+                                    : NSLeftTextAlignment];
   // If this is a URL, set the top-level paragraph direction to LTR (avoids RTL
   // characters from making the URL render from right to left, as per RFC 3987
   // Section 4.1).
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
index f3d58416..1038d795 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/scoped_force_rtl_mac.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h"
 #include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
@@ -176,3 +177,65 @@
   view.OnDoCommandBySelector(@selector(moveUp:));
   EXPECT_EQ(-1, model->up_or_down_count());
 }
+
+TEST_F(OmniboxViewMacTest, WritingDirectionLTR) {
+  TestingToolbarModelDelegate delegate;
+  ToolbarModelImpl toolbar_model(&delegate, 32 * 1024);
+  TestingOmniboxEditController edit_controller(&toolbar_model);
+  OmniboxViewMac view(&edit_controller, profile(), NULL, NULL);
+
+  // This is deleted by the omnibox view.
+  MockOmniboxEditModel* model =
+      new MockOmniboxEditModel(&view, &edit_controller, profile());
+  MockOmniboxPopupView popup_view;
+  OmniboxPopupModel popup_model(&popup_view, model);
+
+  model->OnSetFocus(true);
+  SetModel(&view, model);
+  view.SetUserText(base::ASCIIToUTF16("foo.com"));
+  model->OnChanged();
+
+  base::scoped_nsobject<NSMutableAttributedString> string(
+      [[NSMutableAttributedString alloc] initWithString:@"foo.com"]);
+  view.ApplyTextStyle(string);
+
+  NSParagraphStyle* paragraphStyle =
+      [string attribute:NSParagraphStyleAttributeName
+                 atIndex:0
+          effectiveRange:NULL];
+  DCHECK(paragraphStyle);
+  EXPECT_EQ(paragraphStyle.alignment, NSLeftTextAlignment);
+  EXPECT_EQ(paragraphStyle.baseWritingDirection, NSWritingDirectionLeftToRight);
+}
+
+TEST_F(OmniboxViewMacTest, WritingDirectionRTL) {
+  cocoa_l10n_util::ScopedForceRTLMac rtl;
+
+  TestingToolbarModelDelegate delegate;
+  ToolbarModelImpl toolbar_model(&delegate, 32 * 1024);
+  TestingOmniboxEditController edit_controller(&toolbar_model);
+  OmniboxViewMac view(&edit_controller, profile(), NULL, NULL);
+
+  // This is deleted by the omnibox view.
+  MockOmniboxEditModel* model =
+      new MockOmniboxEditModel(&view, &edit_controller, profile());
+  MockOmniboxPopupView popup_view;
+  OmniboxPopupModel popup_model(&popup_view, model);
+
+  model->OnSetFocus(true);
+  SetModel(&view, model);
+  view.SetUserText(base::ASCIIToUTF16("foo.com"));
+  model->OnChanged();
+
+  base::scoped_nsobject<NSMutableAttributedString> string(
+      [[NSMutableAttributedString alloc] initWithString:@"foo.com"]);
+  view.ApplyTextStyle(string);
+
+  NSParagraphStyle* paragraphStyle =
+      [string attribute:NSParagraphStyleAttributeName
+                 atIndex:0
+          effectiveRange:NULL];
+  DCHECK(paragraphStyle);
+  EXPECT_EQ(paragraphStyle.alignment, NSRightTextAlignment);
+  EXPECT_EQ(paragraphStyle.baseWritingDirection, NSWritingDirectionLeftToRight);
+}
diff --git a/chrome/browser/ui/location_bar/location_bar.cc b/chrome/browser/ui/location_bar/location_bar.cc
index efa6c16..81b37242 100644
--- a/chrome/browser/ui/location_bar/location_bar.cc
+++ b/chrome/browser/ui/location_bar/location_bar.cc
@@ -11,9 +11,6 @@
 #include "extensions/common/feature_switch.h"
 #include "extensions/common/permissions/permissions_data.h"
 
-const char LocationBar::kSecurityChipFeatureVisibilityParam[] = "visibility";
-const char LocationBar::kSecurityChipFeatureAnimationParam[] = "animation";
-
 LocationBar::LocationBar(Profile* profile) : profile_(profile) {
 }
 
diff --git a/chrome/browser/ui/location_bar/location_bar.h b/chrome/browser/ui/location_bar/location_bar.h
index e3e316f..2cdd713 100644
--- a/chrome/browser/ui/location_bar/location_bar.h
+++ b/chrome/browser/ui/location_bar/location_bar.h
@@ -32,10 +32,6 @@
 // location bar to be mocked for testing.
 class LocationBar {
  public:
-  // The parameters for the Security Chip Feature.
-  static const char kSecurityChipFeatureVisibilityParam[];
-  static const char kSecurityChipFeatureAnimationParam[];
-
   explicit LocationBar(Profile* profile);
 
   // Shows the first run bubble anchored to the location bar.
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index fcd840cb..fea3325 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <map>
 
-#include "base/command_line.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -52,8 +51,6 @@
 #include "chrome/browser/ui/views/passwords/manage_passwords_icon_views.h"
 #include "chrome/browser/ui/views/translate/translate_bubble_view.h"
 #include "chrome/browser/ui/views/translate/translate_icon_view.h"
-#include "chrome/common/chrome_features.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
@@ -140,11 +137,7 @@
       is_popup_mode_(is_popup_mode),
       show_focus_rect_(false),
       template_url_service_(NULL),
-      web_contents_null_at_last_refresh_(true),
-      should_show_secure_state_(false),
-      should_show_nonsecure_state_(false),
-      should_animate_secure_state_(false),
-      should_animate_nonsecure_state_(false) {
+      web_contents_null_at_last_refresh_(true) {
   edit_bookmarks_enabled_.Init(
       bookmarks::prefs::kEditBookmarksEnabled, profile->GetPrefs(),
       base::Bind(&LocationBarView::UpdateWithoutTabRestore,
@@ -152,38 +145,6 @@
 
   zoom::ZoomEventManager::GetForBrowserContext(profile)
       ->AddZoomEventManagerObserver(this);
-
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  std::string security_chip_visibility;
-  if (command_line->HasSwitch(switches::kSecurityChip)) {
-    security_chip_visibility =
-      command_line->GetSwitchValueASCII(switches::kSecurityChip);
-  } else if (base::FeatureList::IsEnabled(features::kSecurityChip)) {
-    security_chip_visibility =
-        variations::GetVariationParamValueByFeature(
-            features::kSecurityChip, kSecurityChipFeatureVisibilityParam);
-  }
-
-  should_show_secure_state_ =
-      security_chip_visibility == switches::kSecurityChipShowAll;
-  should_show_nonsecure_state_ =
-    should_show_secure_state_ ||
-    security_chip_visibility == switches::kSecurityChipShowNonSecureOnly;
-
-  std::string security_chip_animation;
-  if (command_line->HasSwitch(switches::kSecurityChipAnimation)) {
-    security_chip_animation =
-        command_line->GetSwitchValueASCII(switches::kSecurityChipAnimation);
-  } else if (base::FeatureList::IsEnabled(features::kSecurityChip)) {
-    security_chip_animation = variations::GetVariationParamValueByFeature(
-        features::kSecurityChip, kSecurityChipFeatureAnimationParam);
-  }
-
-  should_animate_secure_state_ =
-      security_chip_animation == switches::kSecurityChipAnimationAll;
-  should_animate_nonsecure_state_ =
-      should_animate_secure_state_ ||
-      security_chip_animation == switches::kSecurityChipAnimationNonSecureOnly;
 }
 
 LocationBarView::~LocationBarView() {
@@ -933,27 +894,16 @@
 bool LocationBarView::ShouldShowSecurityChip() const {
   using SecurityLevel = security_state::SecurityLevel;
   const SecurityLevel level = GetToolbarModel()->GetSecurityLevel(false);
-  if (level == SecurityLevel::EV_SECURE) {
-    return true;
-  } else if (level == SecurityLevel::SECURE) {
-    return should_show_secure_state_;
-  } else {
-    return should_show_nonsecure_state_ &&
-           (level == SecurityLevel::DANGEROUS ||
-            level == SecurityLevel::HTTP_SHOW_WARNING);
-  }
+  return level == SecurityLevel::EV_SECURE || level == SecurityLevel::SECURE ||
+         level == SecurityLevel::DANGEROUS ||
+         level == SecurityLevel::HTTP_SHOW_WARNING;
 }
 
 bool LocationBarView::ShouldAnimateSecurityChip() const {
   using SecurityLevel = security_state::SecurityLevel;
   SecurityLevel level = GetToolbarModel()->GetSecurityLevel(false);
-  if (!ShouldShowSecurityChip())
-    return false;
-  if (level == SecurityLevel::SECURE || level == SecurityLevel::EV_SECURE)
-    return should_animate_secure_state_;
-  return should_animate_nonsecure_state_ &&
-         (level == SecurityLevel::DANGEROUS ||
-          level == SecurityLevel::HTTP_SHOW_WARNING);
+  return level == SecurityLevel::DANGEROUS ||
+         level == SecurityLevel::HTTP_SHOW_WARNING;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 82fb098..44248e05 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -469,12 +469,6 @@
   // during the last RefreshPageAction.
   bool web_contents_null_at_last_refresh_;
 
-  // These allow toggling the verbose security state behavior via flags.
-  bool should_show_secure_state_;
-  bool should_show_nonsecure_state_;
-  bool should_animate_secure_state_;
-  bool should_animate_nonsecure_state_;
-
   DISALLOW_COPY_AND_ASSIGN(LocationBarView);
 };
 
diff --git a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
index 7c86a6d..7651e06 100644
--- a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
+++ b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
@@ -61,7 +61,7 @@
   // views::ScrollView::GetPreferredSize() includes the contents' size, but
   // not the scrollbar width. Add it in if necessary.
   if (container_->GetPreferredSize().height() > max_height_)
-    s.Enlarge(GetScrollBarWidth(), 0);
+    s.Enlarge(GetScrollBarLayoutWidth(), 0);
   return s;
 }
 
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index f651fe9..3c6c446 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -194,12 +194,6 @@
 const base::Feature kSafeSearchUrlReporting{"SafeSearchUrlReporting",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
-// Sets the visibility and animation of the security chip.
-const base::Feature kSecurityChip{"SecurityChip",
-                                  base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
-
 // A new user experience for transitioning into fullscreen and mouse pointer
 // lock states.
 const base::Feature kSimplifiedFullscreenUI{"ViewsSimplifiedFullscreenUI",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 70be0fe..1a983d3 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -117,10 +117,6 @@
 
 extern const base::Feature kSimplifiedFullscreenUI;
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
-extern const base::Feature kSecurityChip;
-#endif
-
 #if defined(SYZYASAN)
 extern const base::Feature kSyzyasanDeferredFree;
 #endif
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index ad2727b5..f68f672a 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -580,16 +580,6 @@
 // Makes Chrome default browser
 const char kMakeDefaultBrowser[]            = "make-default-browser";
 
-extern const char kSecurityChip[] = "security-chip";
-extern const char kSecurityChipShowNonSecureOnly[] = "show-nonsecure-only";
-extern const char kSecurityChipShowAll[] = "show-all";
-
-extern const char kSecurityChipAnimation[] = "security-chip-animation";
-extern const char kSecurityChipAnimationNone[] = "none";
-extern const char kSecurityChipAnimationNonSecureOnly[] =
-    "animate-nonsecure-only";
-extern const char kSecurityChipAnimationAll[] = "animate-all";
-
 // Forces the maximum disk space to be used by the media cache, in bytes.
 const char kMediaCacheSize[]                = "media-cache-size";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 92df33b..95daaf2 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -172,13 +172,6 @@
 extern const char kLoadExtension[];
 extern const char kLoadMediaRouterComponentExtension[];
 extern const char kMakeDefaultBrowser[];
-extern const char kSecurityChip[];
-extern const char kSecurityChipShowNonSecureOnly[];
-extern const char kSecurityChipShowAll[];
-extern const char kSecurityChipAnimation[];
-extern const char kSecurityChipAnimationNone[];
-extern const char kSecurityChipAnimationNonSecureOnly[];
-extern const char kSecurityChipAnimationAll[];
 extern const char kMediaCacheSize[];
 extern const char kMetricsRecordingOnly[];
 extern const char kMonitoringDestinationID[];
diff --git a/chrome/common/extensions/api/automation.idl b/chrome/common/extensions/api/automation.idl
index 0cbb64a6e..f9dc153 100644
--- a/chrome/common/extensions/api/automation.idl
+++ b/chrome/common/extensions/api/automation.idl
@@ -33,6 +33,8 @@
     liveRegionChanged,
     loadComplete,
     locationChanged,
+    mediaStartedPlaying,
+    mediaStoppedPlaying,
     menuEnd,
     menuListItemSelected,
     menuListValueChanged,
diff --git a/chrome/common/extensions/api/automation_internal.idl b/chrome/common/extensions/api/automation_internal.idl
index 6182ebd..e6b1e8b 100644
--- a/chrome/common/extensions/api/automation_internal.idl
+++ b/chrome/common/extensions/api/automation_internal.idl
@@ -33,9 +33,13 @@
     doDefault,
     getImageData,
     makeVisible,
+    resumeMedia,
     setAccessibilityFocus,
     setSequentialFocusNavigationStartingPoint,
     setSelection,
+    startDuckingMedia,
+    stopDuckingMedia,
+    suspendMedia,
     showContextMenu
   };
 
diff --git a/chrome/renderer/resources/extensions/automation/automation_node.js b/chrome/renderer/resources/extensions/automation/automation_node.js
index 54c308a3..225c0d2 100644
--- a/chrome/renderer/resources/extensions/automation/automation_node.js
+++ b/chrome/renderer/resources/extensions/automation/automation_node.js
@@ -377,6 +377,10 @@
     this.performAction_('makeVisible');
   },
 
+    resumeMedia: function() {
+    this.performAction_('resumeMedia');
+  },
+
   setSelection: function(startIndex, endIndex) {
     if (this.role == 'textField' || this.role == 'textBox') {
       this.performAction_('setSelection',
@@ -394,6 +398,18 @@
     this.performAction_('showContextMenu');
   },
 
+  startDuckingMedia: function() {
+    this.performAction_('startDuckingMedia');
+  },
+
+  stopDuckingMedia: function() {
+    this.performAction_('stopDuckingMedia');
+  },
+
+  suspendMedia: function() {
+    this.performAction_('suspendMedia');
+  },
+
   domQuerySelector: function(selector, callback) {
     if (!this.rootImpl)
       callback();
@@ -1072,9 +1088,13 @@
     'getImageData',
     'makeVisible',
     'matches',
+    'resumeMedia',
     'setSelection',
     'setSequentialFocusNavigationStartingPoint',
     'showContextMenu',
+    'startDuckingMedia',
+    'stopDuckingMedia',
+    'suspendMedia',
     'addEventListener',
     'removeEventListener',
     'domQuerySelector',
diff --git a/chrome/renderer/resources/extensions/automation_custom_bindings.js b/chrome/renderer/resources/extensions/automation_custom_bindings.js
index 53222ab..15415a9 100644
--- a/chrome/renderer/resources/extensions/automation_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/automation_custom_bindings.js
@@ -278,16 +278,20 @@
   var id = eventParams.treeID;
   var targetTree = AutomationRootNode.getOrCreate(id);
 
-  // Work around an issue where Chrome sends us 'blur' events on the
-  // root node when nothing has focus, we need to treat those as focus
-  // events but otherwise not handle blur events specially.
   var isFocusEvent = false;
   if (eventParams.eventType == schema.EventType.focus) {
     isFocusEvent = true;
   } else if (eventParams.eventType == schema.EventType.blur) {
+    // Work around an issue where Chrome sends us 'blur' events on the
+    // root node when nothing has focus, we need to treat those as focus
+    // events but otherwise not handle blur events specially.
     var node = privates(targetTree).impl.get(eventParams.targetID);
     if (node == node.root)
       isFocusEvent = true;
+  } else if (eventParams.eventType == schema.EventType.mediaStartedPlaying ||
+      eventParams.eventType == schema.EventType.mediaStoppedPlaying) {
+    // These events are global to the tree.
+    eventParams.targetID = privates(targetTree).impl.id;
   }
 
   // When we get a focus event, ignore the actual event target, and instead
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java
index bd9b9b7..0d774e2 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.test.util.browser.notifications;
 
 import android.app.Notification;
+import android.service.notification.StatusBarNotification;
 
 import org.chromium.chrome.browser.notifications.NotificationManagerProxy;
 
@@ -101,6 +102,11 @@
         mMutationCount++;
     }
 
+    @Override
+    public StatusBarNotification[] getActiveNotifications() {
+        return null;
+    }
+
     private static String makeKey(int id, @Nullable String tag) {
         String key = Integer.toString(id);
         if (tag != null) key += KEY_SEPARATOR + tag;
diff --git a/chromecast/browser/cast_media_blocker_unittest.cc b/chromecast/browser/cast_media_blocker_unittest.cc
index 25d8a322..dddb008 100644
--- a/chromecast/browser/cast_media_blocker_unittest.cc
+++ b/chromecast/browser/cast_media_blocker_unittest.cc
@@ -38,6 +38,8 @@
   MOCK_METHOD1(Resume, void(content::MediaSession::SuspendType));
   MOCK_METHOD1(Suspend, void(content::MediaSession::SuspendType));
   MOCK_METHOD1(Stop, void(content::MediaSession::SuspendType));
+  MOCK_METHOD0(StartDucking, void());
+  MOCK_METHOD0(StopDucking, void());
   MOCK_METHOD1(DidReceiveAction, void(blink::mojom::MediaSessionAction));
 
  private:
diff --git a/cloud_print/BUILD.gn b/cloud_print/BUILD.gn
index 75ed5e0..0ec5a6b 100644
--- a/cloud_print/BUILD.gn
+++ b/cloud_print/BUILD.gn
@@ -14,7 +14,12 @@
     # When compiling 32-bit, also reference the 64-bit driver for installing on
     # 64-bit systems.
     if (target_cpu == "x86" && current_cpu == "x86") {
-      public_deps += [ "//cloud_print/virtual_driver/win/port_monitor(//build/toolchain/win:x64)" ]
+      if (is_clang) {
+        win64 = "//build/toolchain/win:clang_x64"
+      } else {
+        win64 = "//build/toolchain/win:x64"
+      }
+      public_deps += [ "//cloud_print/virtual_driver/win/port_monitor($win64)" ]
     }
   }
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
index afe7a3c3..56a8444 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
@@ -1679,10 +1679,16 @@
         assertEquals(expectResponseInfo, callback.mResponseInfo != null);
         assertEquals(expectError, callback.mError != null);
         assertEquals(expectError, callback.mOnErrorCalled);
-        assertEquals(failureType == FailureType.CANCEL_SYNC
-                        || failureType == FailureType.CANCEL_ASYNC
-                        || failureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE,
-                callback.mOnCanceledCalled);
+        // When failureType is FailureType.CANCEL_ASYNC_WITHOUT_PAUSE and failureStep is
+        // ResponseStep.ON_READ_COMPLETED, there might be an onSucceeded() task already posted. If
+        // that's the case, onCanceled() will not be invoked. See crbug.com/657415.
+        if (!(failureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE
+                    && failureStep == ResponseStep.ON_READ_COMPLETED)) {
+            assertEquals(failureType == FailureType.CANCEL_SYNC
+                            || failureType == FailureType.CANCEL_ASYNC
+                            || failureType == FailureType.CANCEL_ASYNC_WITHOUT_PAUSE,
+                    callback.mOnCanceledCalled);
+        }
     }
 
     @SmallTest
diff --git a/components/ntp_tiles/most_visited_sites.h b/components/ntp_tiles/most_visited_sites.h
index 1b1f9f5..27a98c1 100644
--- a/components/ntp_tiles/most_visited_sites.h
+++ b/components/ntp_tiles/most_visited_sites.h
@@ -75,8 +75,6 @@
 class MostVisitedSites : public history::TopSitesObserver,
                          public MostVisitedSitesSupervisor::Observer {
  public:
-  using PopularSitesVector = std::vector<PopularSites::Site>;
-
   // The observer to be notified when the list of most visited sites changes.
   class Observer {
    public:
diff --git a/components/ntp_tiles/popular_sites.cc b/components/ntp_tiles/popular_sites.cc
index 1631df98..0917a14a 100644
--- a/components/ntp_tiles/popular_sites.cc
+++ b/components/ntp_tiles/popular_sites.cc
@@ -127,7 +127,7 @@
 
 PopularSites::Site::~Site() {}
 
-PopularSites::PopularSites(
+PopularSitesImpl::PopularSitesImpl(
     const scoped_refptr<base::SequencedWorkerPool>& blocking_pool,
     PrefService* prefs,
     const TemplateURLService* template_url_service,
@@ -148,10 +148,10 @@
       is_fallback_(false),
       weak_ptr_factory_(this) {}
 
-PopularSites::~PopularSites() {}
+PopularSitesImpl::~PopularSitesImpl() {}
 
-void PopularSites::StartFetch(bool force_download,
-                              const FinishedCallback& callback) {
+void PopularSitesImpl::StartFetch(bool force_download,
+                                  const FinishedCallback& callback) {
   DCHECK(!callback_);
   callback_ = callback;
 
@@ -163,7 +163,7 @@
       base::TimeDelta::FromHours(kPopularSitesRedownloadIntervalHours);
   const bool download_time_is_future = base::Time::Now() < last_download_time;
 
-  pending_url_ = GetURLToUse();
+  pending_url_ = GetURLToFetch();
   const bool url_changed =
       pending_url_.spec() != prefs_->GetString(kPopularSitesURLPref);
 
@@ -186,17 +186,26 @@
   base::PostTaskAndReplyWithResult(
       blocking_runner_.get(), FROM_HERE,
       base::Bind(&base::ReadFileToString, local_path_, file_data_ptr),
-      base::Bind(&PopularSites::OnReadFileDone, weak_ptr_factory_.GetWeakPtr(),
+      base::Bind(&PopularSitesImpl::OnReadFileDone,
+                 weak_ptr_factory_.GetWeakPtr(),
                  base::Passed(std::move(file_data))));
 }
 
-GURL PopularSites::LastURL() const {
+const PopularSites::SitesVector& PopularSitesImpl::sites() const {
+  return sites_;
+}
+
+GURL PopularSitesImpl::GetLastURLFetched() const {
   return GURL(prefs_->GetString(kPopularSitesURLPref));
 }
 
-GURL PopularSites::GetURLToUse() {
-  const std::string country = GetCountryToUse();
-  const std::string version = GetVersionToUse();
+const base::FilePath& PopularSitesImpl::local_path() const {
+  return local_path_;
+}
+
+GURL PopularSitesImpl::GetURLToFetch() {
+  const std::string country = GetCountryToFetch();
+  const std::string version = GetVersionToFetch();
 
   const GURL override_url =
       GURL(prefs_->GetString(ntp_tiles::prefs::kPopularSitesOverrideURL));
@@ -211,7 +220,7 @@
 //   "--enable-ntp-search-engine-country-detection" switch is present).
 // - The country provided by the VariationsService.
 // - A default fallback.
-std::string PopularSites::GetCountryToUse() {
+std::string PopularSitesImpl::GetCountryToFetch() {
   std::string country_code =
       prefs_->GetString(ntp_tiles::prefs::kPopularSitesOverrideCountry);
 
@@ -239,7 +248,7 @@
 // - The explicit "override version" pref set by the user.
 // - The version from the field trial config (variation parameter).
 // - A default fallback.
-std::string PopularSites::GetVersionToUse() {
+std::string PopularSitesImpl::GetVersionToFetch() {
   std::string version =
       prefs_->GetString(ntp_tiles::prefs::kPopularSitesOverrideVersion);
 
@@ -253,7 +262,7 @@
 }
 
 // static
-void PopularSites::RegisterProfilePrefs(
+void PopularSitesImpl::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* user_prefs) {
   user_prefs->RegisterStringPref(ntp_tiles::prefs::kPopularSitesOverrideURL,
                                  std::string());
@@ -266,8 +275,8 @@
   user_prefs->RegisterStringPref(kPopularSitesURLPref, std::string());
 }
 
-void PopularSites::OnReadFileDone(std::unique_ptr<std::string> data,
-                                  bool success) {
+void PopularSitesImpl::OnReadFileDone(std::unique_ptr<std::string> data,
+                                      bool success) {
   if (success) {
     auto json = base::JSONReader::Read(*data, base::JSON_ALLOW_TRAILING_COMMAS);
     if (json) {
@@ -281,7 +290,7 @@
   }
 }
 
-void PopularSites::FetchPopularSites() {
+void PopularSitesImpl::FetchPopularSites() {
   fetcher_ = URLFetcher::Create(pending_url_, URLFetcher::GET, this);
   data_use_measurement::DataUseUserData::AttachToFetcher(
       fetcher_.get(), data_use_measurement::DataUseUserData::NTP_TILES);
@@ -292,7 +301,7 @@
   fetcher_->Start();
 }
 
-void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) {
+void PopularSitesImpl::OnURLFetchComplete(const net::URLFetcher* source) {
   DCHECK_EQ(fetcher_.get(), source);
   std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_);
 
@@ -304,29 +313,29 @@
     return;
   }
 
-  parse_json_.Run(
-      json_string,
-      base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr()),
-      base::Bind(&PopularSites::OnJsonParseFailed,
-                 weak_ptr_factory_.GetWeakPtr()));
+  parse_json_.Run(json_string, base::Bind(&PopularSitesImpl::OnJsonParsed,
+                                          weak_ptr_factory_.GetWeakPtr()),
+                  base::Bind(&PopularSitesImpl::OnJsonParseFailed,
+                             weak_ptr_factory_.GetWeakPtr()));
 }
 
-void PopularSites::OnJsonParsed(std::unique_ptr<base::Value> json) {
+void PopularSitesImpl::OnJsonParsed(std::unique_ptr<base::Value> json) {
   const base::Value* json_ptr = json.get();
   base::PostTaskAndReplyWithResult(
       blocking_runner_.get(), FROM_HERE,
       base::Bind(&WriteJsonToFile, local_path_, json_ptr),
-      base::Bind(&PopularSites::OnFileWriteDone, weak_ptr_factory_.GetWeakPtr(),
+      base::Bind(&PopularSitesImpl::OnFileWriteDone,
+                 weak_ptr_factory_.GetWeakPtr(),
                  base::Passed(std::move(json))));
 }
 
-void PopularSites::OnJsonParseFailed(const std::string& error_message) {
+void PopularSitesImpl::OnJsonParseFailed(const std::string& error_message) {
   DLOG(WARNING) << "JSON parsing failed: " << error_message;
   OnDownloadFailed();
 }
 
-void PopularSites::OnFileWriteDone(std::unique_ptr<base::Value> json,
-                                   bool success) {
+void PopularSitesImpl::OnFileWriteDone(std::unique_ptr<base::Value> json,
+                                       bool success) {
   if (success) {
     prefs_->SetInt64(kPopularSitesLastDownloadPref,
                      base::Time::Now().ToInternalValue());
@@ -339,7 +348,7 @@
   }
 }
 
-void PopularSites::ParseSiteList(std::unique_ptr<base::Value> json) {
+void PopularSitesImpl::ParseSiteList(std::unique_ptr<base::Value> json) {
   base::ListValue* list = nullptr;
   if (!json || !json->GetAsList(&list)) {
     DLOG(WARNING) << "JSON is not a list";
@@ -348,7 +357,7 @@
     return;
   }
 
-  std::vector<PopularSites::Site> sites;
+  SitesVector sites;
   for (size_t i = 0; i < list->GetSize(); i++) {
     base::DictionaryValue* item;
     if (!list->GetDictionary(i, &item))
@@ -364,16 +373,16 @@
     std::string large_icon_url;
     item->GetString("large_icon_url", &large_icon_url);
 
-    sites.push_back(PopularSites::Site(title, GURL(url), GURL(favicon_url),
-                                       GURL(large_icon_url),
-                                       GURL(thumbnail_url)));
+    sites.push_back(PopularSitesImpl::Site(title, GURL(url), GURL(favicon_url),
+                                           GURL(large_icon_url),
+                                           GURL(thumbnail_url)));
   }
 
   sites_.swap(sites);
   callback_.Run(true);
 }
 
-void PopularSites::OnDownloadFailed() {
+void PopularSitesImpl::OnDownloadFailed() {
   if (!is_fallback_) {
     DLOG(WARNING) << "Download country site list failed";
     is_fallback_ = true;
diff --git a/components/ntp_tiles/popular_sites.h b/components/ntp_tiles/popular_sites.h
index d7679fda..104ae63 100644
--- a/components/ntp_tiles/popular_sites.h
+++ b/components/ntp_tiles/popular_sites.h
@@ -43,10 +43,9 @@
     const base::Callback<void(std::unique_ptr<base::Value>)>& success_callback,
     const base::Callback<void(const std::string&)>& error_callback)>;
 
-// Downloads and provides a list of suggested popular sites, for display on
-// the NTP when there are not enough personalized tiles. Caches the downloaded
-// file on disk to avoid re-downloading on every startup.
-class PopularSites : public net::URLFetcherDelegate {
+// Interface to provide a list of suggested popular sites, for display on the
+// NTP when there are not enough personalized tiles.
+class PopularSites {
  public:
   struct Site {
     Site(const base::string16& title,
@@ -64,15 +63,10 @@
     GURL thumbnail_url;
   };
 
+  using SitesVector = std::vector<Site>;
   using FinishedCallback = base::Callback<void(bool /* success */)>;
 
-  PopularSites(const scoped_refptr<base::SequencedWorkerPool>& blocking_pool,
-               PrefService* prefs,
-               const TemplateURLService* template_url_service,
-               variations::VariationsService* variations_service,
-               net::URLRequestContextGetter* download_context,
-               const base::FilePath& directory,
-               ParseJSONCallback parse_json);
+  virtual ~PopularSites() = default;
 
   // Starts the process of retrieving popular sites. When they are available,
   // invokes |callback| with the result, on the same thread as the caller. Never
@@ -83,21 +77,45 @@
   // if it already exists on disk.
   //
   // Must be called at most once on a given PopularSites object.
-  void StartFetch(bool force_download, const FinishedCallback& callback);
+  // TODO(mastiz): Remove this restriction?
+  virtual void StartFetch(bool force_download,
+                          const FinishedCallback& callback) = 0;
 
-  ~PopularSites() override;
+  // Returns the list of available sites.
+  virtual const SitesVector& sites() const = 0;
 
-  const std::vector<Site>& sites() const { return sites_; }
+  // Various internals exposed publicly for diagnostic pages only.
+  virtual GURL GetLastURLFetched() const = 0;
+  virtual const base::FilePath& local_path() const = 0;
+  virtual GURL GetURLToFetch() = 0;
+  virtual std::string GetCountryToFetch() = 0;
+  virtual std::string GetVersionToFetch() = 0;
+};
 
-  // The URL of the file that was last downloaded.
-  GURL LastURL() const;
+// Actual (non-test) implementation of the PopularSites interface. Caches the
+// downloaded file on disk to avoid re-downloading on every startup.
+class PopularSitesImpl : public PopularSites, public net::URLFetcherDelegate {
+ public:
+  PopularSitesImpl(
+      const scoped_refptr<base::SequencedWorkerPool>& blocking_pool,
+      PrefService* prefs,
+      const TemplateURLService* template_url_service,
+      variations::VariationsService* variations_service,
+      net::URLRequestContextGetter* download_context,
+      const base::FilePath& directory,
+      ParseJSONCallback parse_json);
 
-  const base::FilePath& local_path() const { return local_path_; }
+  ~PopularSitesImpl() override;
 
-  // Public for diagnostic pages only.
-  GURL GetURLToUse();
-  std::string GetCountryToUse();
-  std::string GetVersionToUse();
+  // PopularSites implementation.
+  void StartFetch(bool force_download,
+                  const FinishedCallback& callback) override;
+  const SitesVector& sites() const override;
+  GURL GetLastURLFetched() const override;
+  const base::FilePath& local_path() const override;
+  GURL GetURLToFetch() override;
+  std::string GetCountryToFetch() override;
+  std::string GetVersionToFetch() override;
 
   // Register preferences used by this class.
   static void RegisterProfilePrefs(
@@ -133,12 +151,12 @@
 
   std::unique_ptr<net::URLFetcher> fetcher_;
   bool is_fallback_;
-  std::vector<Site> sites_;
+  SitesVector sites_;
   GURL pending_url_;
 
-  base::WeakPtrFactory<PopularSites> weak_ptr_factory_;
+  base::WeakPtrFactory<PopularSitesImpl> weak_ptr_factory_;
 
-  DISALLOW_COPY_AND_ASSIGN(PopularSites);
+  DISALLOW_COPY_AND_ASSIGN(PopularSitesImpl);
 };
 
 }  // namespace ntp_tiles
diff --git a/components/ntp_tiles/popular_sites_unittest.cc b/components/ntp_tiles/popular_sites_unittest.cc
index 929e68a6..cf2b0d0 100644
--- a/components/ntp_tiles/popular_sites_unittest.cc
+++ b/components/ntp_tiles/popular_sites_unittest.cc
@@ -68,7 +68,7 @@
         },
         worker_pool_owner_(2, "PopularSitesTest."),
         url_fetcher_factory_(nullptr) {
-    PopularSites::RegisterProfilePrefs(prefs_.registry());
+    PopularSitesImpl::RegisterProfilePrefs(prefs_.registry());
     CHECK(scoped_cache_dir_.CreateUniqueTempDir());
     cache_dir_ = scoped_cache_dir_.GetPath();
   }
@@ -106,15 +106,15 @@
   }
 
   bool FetchPopularSites(bool force_download,
-                         std::vector<PopularSites::Site>* sites) {
+                         PopularSites::SitesVector* sites) {
     scoped_refptr<net::TestURLRequestContextGetter> url_request_context(
         new net::TestURLRequestContextGetter(
             base::ThreadTaskRunnerHandle::Get()));
-    PopularSites popular_sites(worker_pool_owner_.pool().get(), &prefs_,
-                               /*template_url_service=*/nullptr,
-                               /*variations_service=*/nullptr,
-                               url_request_context.get(), cache_dir_,
-                               base::Bind(JsonUnsafeParser::Parse));
+    PopularSitesImpl popular_sites(worker_pool_owner_.pool().get(), &prefs_,
+                                   /*template_url_service=*/nullptr,
+                                   /*variations_service=*/nullptr,
+                                   url_request_context.get(), cache_dir_,
+                                   base::Bind(JsonUnsafeParser::Parse));
 
     base::RunLoop loop;
     bool save_success = false;
@@ -149,7 +149,7 @@
       "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
       {kWikipedia});
 
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
   EXPECT_TRUE(FetchPopularSites(/*force_download=*/false, &sites));
 
   ASSERT_THAT(sites.size(), Eq(1u));
@@ -168,7 +168,7 @@
       "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
       {kYouTube, kChromium});
 
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
   EXPECT_TRUE(FetchPopularSites(/*force_download=*/false, &sites));
 
   ASSERT_THAT(sites.size(), Eq(2u));
@@ -191,14 +191,14 @@
   RespondWith404(
       "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
 
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
   EXPECT_FALSE(FetchPopularSites(/*force_download=*/false, &sites));
   ASSERT_THAT(sites, IsEmpty());
 }
 
 TEST_F(PopularSitesTest, FailsWithoutFetchIfNoCacheDir) {
   SetCountryAndVersion("ZZ", "9");
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
   cache_dir_ = base::FilePath();  // Override with invalid file path.
   EXPECT_FALSE(FetchPopularSites(/*force_download=*/false, &sites));
 }
@@ -210,7 +210,7 @@
       {kWikipedia});
 
   // First request succeeds and gets cached.
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
   EXPECT_TRUE(FetchPopularSites(/*force_download=*/false, &sites));
 
   // File disappears from server, but we don't need it because it's cached.
@@ -229,7 +229,7 @@
       {kWikipedia});
 
   // First request succeeds and caches empty suggestions list (no fallback).
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
   EXPECT_TRUE(FetchPopularSites(/*force_download=*/false, &sites));
   EXPECT_THAT(sites, IsEmpty());
 
@@ -248,7 +248,7 @@
       {kWikipedia});
 
   // First request succeeds and gets cached.
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
   EXPECT_TRUE(FetchPopularSites(/*force_download=*/true, &sites));
   EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
 
@@ -268,7 +268,7 @@
       "https://www.gstatic.com/chrome/ntp/suggested_sites_ZX_9.json",
       {kChromium});
 
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
 
   // First request (in ZZ) saves Wikipedia.
   SetCountryAndVersion("ZZ", "9");
@@ -290,7 +290,7 @@
       "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
 
   // First request falls back and gets nothing there either.
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
   EXPECT_FALSE(FetchPopularSites(/*force_download=*/false, &sites));
 
   // Second request refetches ZZ_9, which now has data.
@@ -311,7 +311,7 @@
       {kWikipedia});
 
   // First request falls back.
-  std::vector<PopularSites::Site> sites;
+  PopularSites::SitesVector sites;
   EXPECT_TRUE(FetchPopularSites(/*force_download=*/false, &sites));
   ASSERT_THAT(sites.size(), Eq(1u));
   EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
index d10a6c05..4dce944 100644
--- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
+++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -110,9 +110,9 @@
 
   if (client_->DoesSourceExist(NTPTileSource::POPULAR)) {
     auto popular_sites = client_->MakePopularSites();
-    value.SetString("popular.url", popular_sites->GetURLToUse().spec());
-    value.SetString("popular.country", popular_sites->GetCountryToUse());
-    value.SetString("popular.version", popular_sites->GetVersionToUse());
+    value.SetString("popular.url", popular_sites->GetURLToFetch().spec());
+    value.SetString("popular.country", popular_sites->GetCountryToFetch());
+    value.SetString("popular.version", popular_sites->GetVersionToFetch());
 
     value.SetString(
         "popular.overrideURL",
diff --git a/components/ntp_tiles/webui/popular_sites_internals_message_handler.cc b/components/ntp_tiles/webui/popular_sites_internals_message_handler.cc
index 50f2252..ce02145 100644
--- a/components/ntp_tiles/webui/popular_sites_internals_message_handler.cc
+++ b/components/ntp_tiles/webui/popular_sites_internals_message_handler.cc
@@ -152,7 +152,7 @@
 
   base::DictionaryValue result;
   result.Set("sites", std::move(sites_list));
-  result.SetString("url", popular_sites_->LastURL().spec());
+  result.SetString("url", popular_sites_->GetLastURLFetched().spec());
   web_ui_->CallJavascriptFunction("chrome.popular_sites_internals.receiveSites",
                                   result);
 }
diff --git a/components/previews/core/previews_black_list.h b/components/previews/core/previews_black_list.h
index e9151da..6abac75 100644
--- a/components/previews/core/previews_black_list.h
+++ b/components/previews/core/previews_black_list.h
@@ -49,7 +49,9 @@
   NETWORK_QUALITY_UNAVAILABLE = 6,
   // The network was fast enough to not warrant previews.
   NETWORK_NOT_SLOW = 7,
-  LAST = 8,
+  // If the page was reloaded, the user should not be shown an offline preview.
+  RELOAD_DISALLOWED_FOR_OFFLINE = 8,
+  LAST = 9,
 };
 
 // Manages the state of black listed domains for the previews experiment. Loads
diff --git a/components/previews/core/previews_io_data.cc b/components/previews/core/previews_io_data.cc
index ed9f784d..82d17b2 100644
--- a/components/previews/core/previews_io_data.cc
+++ b/components/previews/core/previews_io_data.cc
@@ -15,6 +15,7 @@
 #include "components/previews/core/previews_black_list.h"
 #include "components/previews/core/previews_opt_out_store.h"
 #include "components/previews/core/previews_ui_service.h"
+#include "net/base/load_flags.h"
 #include "net/nqe/network_quality_estimator.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
@@ -117,6 +118,15 @@
                                  type);
     return false;
   }
+  // LOAD_VALIDATE_CACHE or LOAD_BYPASS_CACHE mean the user reloaded the page.
+  // If this is a query for offline previews, reloads should be disallowed.
+  if (type == PreviewsType::OFFLINE &&
+      request.load_flags() &
+          (net::LOAD_VALIDATE_CACHE | net::LOAD_BYPASS_CACHE)) {
+    LogPreviewsEligibilityReason(
+        PreviewsEligibilityReason::RELOAD_DISALLOWED_FOR_OFFLINE, type);
+    return false;
+  }
   LogPreviewsEligibilityReason(PreviewsEligibilityReason::ALLOWED, type);
   return true;
 }
diff --git a/components/previews/core/previews_io_data_unittest.cc b/components/previews/core/previews_io_data_unittest.cc
index cb8d3aa..39a8925e 100644
--- a/components/previews/core/previews_io_data_unittest.cc
+++ b/components/previews/core/previews_io_data_unittest.cc
@@ -25,6 +25,7 @@
 #include "components/previews/core/previews_opt_out_store.h"
 #include "components/previews/core/previews_ui_service.h"
 #include "components/variations/variations_associated_data.h"
+#include "net/base/load_flags.h"
 #include "net/nqe/effective_connection_type.h"
 #include "net/nqe/network_quality_estimator_test_util.h"
 #include "net/url_request/url_request.h"
@@ -212,12 +213,21 @@
   network_quality_estimator.set_effective_connection_type(
       net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
 
+  request->SetLoadFlags(net::LOAD_BYPASS_CACHE);
+  EXPECT_FALSE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
+  histogram_tester.ExpectBucketCount(
+      "Previews.EligibilityReason.Offline",
+      static_cast<int>(
+          PreviewsEligibilityReason::RELOAD_DISALLOWED_FOR_OFFLINE),
+      1);
+
+  request->SetLoadFlags(0);
   EXPECT_TRUE(io_data()->ShouldAllowPreview(*request, PreviewsType::OFFLINE));
   histogram_tester.ExpectBucketCount(
       "Previews.EligibilityReason.Offline",
       static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
 
-  histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 6);
+  histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 7);
 
   variations::testing::ClearAllVariationParams();
 }
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
index e7b47a5..b04c52a 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -5,6 +5,7 @@
 #include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
 #include "components/subresource_filter/content/browser/content_subresource_filter_driver.h"
 #include "components/subresource_filter/content/common/subresource_filter_messages.h"
 #include "components/subresource_filter/core/browser/subresource_filter_client.h"
@@ -24,6 +25,10 @@
   return url.host() + url.path();
 }
 
+bool ShouldMeasurePerformance(double rate) {
+  return base::RandDouble() < rate;
+}
+
 }  // namespace
 
 // static
@@ -54,7 +59,8 @@
     std::unique_ptr<SubresourceFilterClient> client)
     : content::WebContentsObserver(web_contents),
       client_(std::move(client)),
-      activation_state_(ActivationState::DISABLED) {
+      activation_state_(ActivationState::DISABLED),
+      measure_performance_(false) {
   content::RenderFrameHost* main_frame_host = web_contents->GetMainFrame();
   if (main_frame_host && main_frame_host->IsRenderFrameLive())
     CreateDriverForFrameHostIfNeeded(main_frame_host);
@@ -122,14 +128,10 @@
     content::RenderFrameHost* render_frame_host,
     const GURL& url) {
   if (activation_state_ != ActivationState::DISABLED) {
-    // TODO(pkalinnikov): Introduce a variation parameter controlling how often
-    // the |measure_performance| bit is set. crbug/672519
-    constexpr bool measure_performance = true;
-
     auto* driver = DriverFromFrameHost(render_frame_host);
     DCHECK(driver);
     driver->ActivateForProvisionalLoad(GetMaximumActivationState(), url,
-                                       measure_performance);
+                                       measure_performance_);
   }
 }
 
@@ -164,6 +166,7 @@
 
     client_->ToggleNotificationVisibility(false);
     activation_state_ = ActivationState::DISABLED;
+    measure_performance_ = false;
   }
 }
 
@@ -209,9 +212,12 @@
     RecordRedirectChainMatchPattern();
     if (ShouldActivateForMainFrameURL(url)) {
       activation_state_ = GetMaximumActivationState();
+      measure_performance_ =
+          ShouldMeasurePerformance(GetPerformanceMeasurementRate());
       ActivateForFrameHostIfNeeded(render_frame_host, url);
     } else {
       activation_state_ = ActivationState::DISABLED;
+      measure_performance_ = false;
     }
   } else {
     ActivateForFrameHostIfNeeded(render_frame_host, url);
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
index 6bfd8941..3611723 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -145,6 +145,7 @@
   HostPathSet whitelisted_hosts_;
 
   ActivationState activation_state_;
+  bool measure_performance_;
 
   // The URLs in the navigation chain.
   std::vector<GURL> navigation_chain_;
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
index c2b2410..a746256 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -234,7 +234,8 @@
       rfh_tester->SimulateRedirect(url);
     }
     EXPECT_CALL(*driver(),
-                ActivateForProvisionalLoad(::testing::_, ::testing::_, true))
+                ActivateForProvisionalLoad(::testing::_, ::testing::_,
+                                           expected_measure_performance()))
         .Times(expected_activation);
     if (!content::IsBrowserSideNavigationEnabled()) {
       factory()->ReadyToCommitNavigationInternal(main_rfh(),
@@ -261,7 +262,8 @@
 
   void NavigateAndCommitSubframe(const GURL& url, bool expected_activation) {
     EXPECT_CALL(*subframe_driver(),
-                ActivateForProvisionalLoad(::testing::_, ::testing::_, true))
+                ActivateForProvisionalLoad(::testing::_, ::testing::_,
+                                           expected_measure_performance()))
         .Times(expected_activation);
     EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0);
 
@@ -298,7 +300,7 @@
   void EmulateInPageNavigation(const std::vector<bool>& blacklisted_urls,
                                RedirectChainMatchPattern extected_pattern,
                                bool expected_activation) {
-    // This test-case examinse the nevigation woth following sequence of event:
+    // This test examines the navigation with the following sequence of events:
     //   DidStartProvisional(main, "example.com")
     //   ReadyToCommitNavigation(“example.com”)
     //   DidCommitProvisional(main, "example.com")
@@ -319,6 +321,13 @@
   }
 
  private:
+  static bool expected_measure_performance() {
+    const double rate = GetPerformanceMeasurementRate();
+    // Note: The case when 0 < rate < 1 is not deterministic, don't test it.
+    EXPECT_TRUE(rate == 0 || rate == 1);
+    return rate == 1;
+  }
+
   // Owned by the factory.
   MockSubresourceFilterClient* client_;
   MockSubresourceFilterDriver* driver_;
@@ -413,6 +422,18 @@
                           true /* expected_activation */);
 }
 
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+       SpecialCaseNavigationActivationListEnabledWithPerformanceMeasurement) {
+  base::FieldTrialList field_trial_list(nullptr);
+  testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+      base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+      kActivationScopeActivationList,
+      kActivationListSocialEngineeringAdsInterstitial,
+      "1" /* performance_measurement_rate */);
+  EmulateInPageNavigation({true}, NO_REDIRECTS_HIT,
+                          true /* expected_activation */);
+}
+
 TEST_F(ContentSubresourceFilterDriverFactoryTest, RedirectPatternTest) {
   base::FieldTrialList field_trial_list(nullptr);
   testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.cc b/components/subresource_filter/core/browser/subresource_filter_features.cc
index e85213c3..9ac0acf 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features.cc
+++ b/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "components/variations/variations_associated_data.h"
@@ -30,6 +31,9 @@
     "social_engineering_ads_interstitial";
 const char kActivationListPhishingInterstitial[] = "phishing_interstitial";
 
+const char kPerformanceMeasurementRateParameterName[] =
+    "performance_measurement_rate";
+
 ActivationState GetMaximumActivationState() {
   std::string activation_state = variations::GetVariationParamValueByFeature(
       kSafeBrowsingSubresourceFilter, kActivationStateParameterName);
@@ -70,4 +74,13 @@
   return activation_list_type;
 }
 
+double GetPerformanceMeasurementRate() {
+  const std::string rate = variations::GetVariationParamValueByFeature(
+      kSafeBrowsingSubresourceFilter, kPerformanceMeasurementRateParameterName);
+  double value = 0;
+  if (!base::StringToDouble(rate, &value) || value < 0)
+    return 0;
+  return value < 1 ? value : 1;
+}
+
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.h b/components/subresource_filter/core/browser/subresource_filter_features.h
index b19b2dc1..11f54ff 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features.h
+++ b/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -30,6 +30,8 @@
 extern const char kActivationListSocialEngineeringAdsInterstitial[];
 extern const char kActivationListPhishingInterstitial[];
 
+extern const char kPerformanceMeasurementRateParameterName[];
+
 // Returns the maximum degree to which subresource filtering should be activated
 // on any RenderFrame. This will be ActivationState::DISABLED unless the feature
 // is enabled and variation parameters prescribe a higher activation state.
@@ -46,6 +48,11 @@
 // variation param is empty, returns most conservative ActivationList::NONE.
 ActivationList GetCurrentActivationList();
 
+// Returns a number in the range [0, 1], indicating the fraction of page loads
+// that should have extended performance measurements enabled. The rate will be
+// 0 unless a greater frequency is specified by variation parameters.
+double GetPerformanceMeasurementRate();
+
 }  // namespace subresource_filter
 
 #endif  // COMPONENTS_SUBRESOURCE_FILTER_SUBRESOURCE_FILTER_FEATURES_H_
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc b/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
index 5396c01..78d2c48 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
+++ b/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
@@ -23,23 +23,22 @@
 ScopedSubresourceFilterFeatureToggle::ScopedSubresourceFilterFeatureToggle(
     base::FeatureList::OverrideState feature_state,
     const std::string& maximum_activation_state,
-    const std::string& activation_scope)
-    : ScopedSubresourceFilterFeatureToggle(feature_state,
-                                           maximum_activation_state,
-                                           activation_scope,
-                                           std::string()) {}
+    const std::string& activation_scope,
+    const std::string& activation_lists,
+    const std::string& performance_measurement_rate)
+    : ScopedSubresourceFilterFeatureToggle(
+          feature_state,
+          {{kActivationStateParameterName, maximum_activation_state},
+           {kActivationScopeParameterName, activation_scope},
+           {kActivationListsParameterName, activation_lists},
+           {kPerformanceMeasurementRateParameterName,
+            performance_measurement_rate}}) {}
 
 ScopedSubresourceFilterFeatureToggle::ScopedSubresourceFilterFeatureToggle(
     base::FeatureList::OverrideState feature_state,
-    const std::string& maximum_activation_state,
-    const std::string& activation_scope,
-    const std::string& activation_lists) {
+    std::map<std::string, std::string> variation_params) {
   variations::testing::ClearAllVariationParams();
 
-  std::map<std::string, std::string> variation_params;
-  variation_params[kActivationStateParameterName] = maximum_activation_state;
-  variation_params[kActivationScopeParameterName] = activation_scope;
-  variation_params[kActivationListsParameterName] = activation_lists;
   EXPECT_TRUE(variations::AssociateVariationParams(
       kTestFieldTrialName, kTestExperimentGroupName, variation_params));
 
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_test_support.h b/components/subresource_filter/core/browser/subresource_filter_features_test_support.h
index f2065e9..6fe38513 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features_test_support.h
+++ b/components/subresource_filter/core/browser/subresource_filter_features_test_support.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_TEST_SUPPORT_H_
 #define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_TEST_SUPPORT_H_
 
+#include <map>
 #include <string>
 
 #include "base/feature_list.h"
@@ -14,21 +15,21 @@
 namespace subresource_filter {
 namespace testing {
 
-// Helper to override the state of the |kSafeBrowsingSubresourceFilter| feature
-// and the maximum activation state during tests. Expects a pre-existing global
-// base::FieldTrialList singleton.
+// Helper to override the state of the |kSafeBrowsingSubresourceFilter| feature,
+// and its variation parameters, e.g., maximum activation state and activation
+// scope. Expects a pre-existing global base::FieldTrialList singleton.
 class ScopedSubresourceFilterFeatureToggle {
  public:
   ScopedSubresourceFilterFeatureToggle(
       base::FeatureList::OverrideState feature_state,
       const std::string& maximum_activation_state,
-      const std::string& activation_scope);
+      const std::string& activation_scope,
+      const std::string& activation_lists = std::string(),
+      const std::string& performance_measurement_rate = std::string());
 
   ScopedSubresourceFilterFeatureToggle(
       base::FeatureList::OverrideState feature_state,
-      const std::string& maximum_activation_state,
-      const std::string& activation_scope,
-      const std::string& activation_lists);
+      std::map<std::string, std::string> variation_params);
 
   ~ScopedSubresourceFilterFeatureToggle();
 
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc b/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
index 51a3d58..d2ab51d 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
+++ b/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
@@ -183,4 +183,40 @@
   }
 }
 
+TEST(SubresourceFilterFeaturesTest, PerfMeasurementRate) {
+  const struct {
+    bool feature_enabled;
+    const char* perf_measurement_param;
+    double expected_perf_measurement_rate;
+  } kTestCases[] = {{false, "not_a_number", 0},
+                    {false, "0", 0},
+                    {false, "1", 0},
+                    {true, "not_a_number", 0},
+                    {true, "0.5not_a_number", 0},
+                    {true, "0", 0},
+                    {true, "0.000", 0},
+                    {true, "0.05", 0.05},
+                    {true, "0.5", 0.5},
+                    {true, "1", 1},
+                    {true, "1.0", 1},
+                    {true, "0.333", 0.333},
+                    {true, "1e0", 1}};
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(::testing::Message("Enabled = ") << test_case.feature_enabled);
+    SCOPED_TRACE(::testing::Message("PerfMeasurementParam = \"")
+                 << test_case.perf_measurement_param << "\"");
+
+    base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
+    testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+        test_case.feature_enabled ? base::FeatureList::OVERRIDE_ENABLE_FEATURE
+                                  : base::FeatureList::OVERRIDE_USE_DEFAULT,
+        {{kPerformanceMeasurementRateParameterName,
+          test_case.perf_measurement_param}});
+
+    EXPECT_EQ(test_case.expected_perf_measurement_rate,
+              GetPerformanceMeasurementRate());
+  }
+}
+
 }  // namespace subresource_filter
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index d3294588a..827e7ad 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -184,8 +184,6 @@
     "$target_gen_dir/devtools/protocol/schema.h",
     "$target_gen_dir/devtools/protocol/security.cc",
     "$target_gen_dir/devtools/protocol/security.h",
-    "$target_gen_dir/devtools/protocol/storage.cc",
-    "$target_gen_dir/devtools/protocol/storage.h",
     "$target_gen_dir/devtools/protocol/system_info.cc",
     "$target_gen_dir/devtools/protocol/system_info.h",
     "$target_gen_dir/devtools/protocol/tethering.cc",
@@ -197,8 +195,6 @@
     "../zygote/zygote_linux.cc",
     "../zygote/zygote_linux.h",
     "../zygote/zygote_main_linux.cc",
-    "accessibility/accessibility_mode_helper.cc",
-    "accessibility/accessibility_mode_helper.h",
     "accessibility/accessibility_tree_formatter.cc",
     "accessibility/accessibility_tree_formatter.h",
     "accessibility/accessibility_tree_formatter_blink.cc",
diff --git a/content/browser/accessibility/accessibility_action_browsertest.cc b/content/browser/accessibility/accessibility_action_browsertest.cc
index 3dc80e8..70a7f4f 100644
--- a/content/browser/accessibility/accessibility_action_browsertest.cc
+++ b/content/browser/accessibility/accessibility_action_browsertest.cc
@@ -79,7 +79,7 @@
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         AccessibilityModeComplete,
+                                         ACCESSIBILITY_MODE_COMPLETE,
                                          ui::AX_EVENT_LOAD_COMPLETE);
   GURL url("data:text/html,"
            "<button>One</button>"
@@ -92,7 +92,7 @@
   ASSERT_NE(nullptr, target);
 
   AccessibilityNotificationWaiter waiter2(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_FOCUS);
   GetManager()->SetFocus(*target);
   waiter2.WaitForNotification();
@@ -106,7 +106,7 @@
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         AccessibilityModeComplete,
+                                         ACCESSIBILITY_MODE_COMPLETE,
                                          ui::AX_EVENT_LOAD_COMPLETE);
   GURL url("data:text/html,"
            "<input type=range min=2 value=8 max=10 step=2>");
@@ -120,7 +120,7 @@
   // Increment, should result in value changing from 8 to 10.
   {
     AccessibilityNotificationWaiter waiter2(shell()->web_contents(),
-                                            AccessibilityModeComplete,
+                                            ACCESSIBILITY_MODE_COMPLETE,
                                             ui::AX_EVENT_VALUE_CHANGED);
     GetManager()->Increment(*target);
     waiter2.WaitForNotification();
@@ -130,7 +130,7 @@
   // Increment, should result in value staying the same (max).
   {
     AccessibilityNotificationWaiter waiter2(shell()->web_contents(),
-                                            AccessibilityModeComplete,
+                                            ACCESSIBILITY_MODE_COMPLETE,
                                             ui::AX_EVENT_VALUE_CHANGED);
     GetManager()->Increment(*target);
     waiter2.WaitForNotification();
@@ -140,7 +140,7 @@
   // Decrement, should result in value changing from 10 to 8.
   {
     AccessibilityNotificationWaiter waiter2(shell()->web_contents(),
-                                            AccessibilityModeComplete,
+                                            ACCESSIBILITY_MODE_COMPLETE,
                                             ui::AX_EVENT_VALUE_CHANGED);
     GetManager()->Decrement(*target);
     waiter2.WaitForNotification();
@@ -152,7 +152,7 @@
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         AccessibilityModeComplete,
+                                         ACCESSIBILITY_MODE_COMPLETE,
                                          ui::AX_EVENT_LOAD_COMPLETE);
   GURL url("data:text/html,"
            "<body>"
@@ -179,7 +179,7 @@
   ASSERT_NE(nullptr, target);
 
   AccessibilityNotificationWaiter waiter2(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_IMAGE_FRAME_UPDATED);
   GetManager()->GetImageData(*target, gfx::Size());
   waiter2.WaitForNotification();
@@ -202,7 +202,7 @@
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         AccessibilityModeComplete,
+                                         ACCESSIBILITY_MODE_COMPLETE,
                                          ui::AX_EVENT_LOAD_COMPLETE);
   GURL url("data:text/html,"
            "<body>"
@@ -223,7 +223,7 @@
   ASSERT_NE(nullptr, target);
 
   AccessibilityNotificationWaiter waiter2(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_IMAGE_FRAME_UPDATED);
   GetManager()->GetImageData(*target, gfx::Size(4, 4));
   waiter2.WaitForNotification();
@@ -246,7 +246,7 @@
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         AccessibilityModeComplete,
+                                         ACCESSIBILITY_MODE_COMPLETE,
                                          ui::AX_EVENT_LOAD_COMPLETE);
   GURL url("data:text/html,"
            "<body>"
@@ -261,7 +261,7 @@
   ASSERT_NE(nullptr, target);
 
   AccessibilityNotificationWaiter waiter2(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_IMAGE_FRAME_UPDATED);
   GetManager()->GetImageData(*target, gfx::Size());
   waiter2.WaitForNotification();
diff --git a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
index 7d9f004..cb4d55b 100644
--- a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
+++ b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
@@ -60,12 +60,12 @@
   ASSERT_EQ(nullptr, frame->GetOrCreateBrowserAccessibilityManager());
 
   {
-    // Enable accessibility (passing AccessibilityModeComplete to
+    // Enable accessibility (passing ACCESSIBILITY_MODE_COMPLETE to
     // AccessibilityNotificationWaiter does this automatically) and wait for
     // the first event.
     AccessibilityNotificationWaiter waiter(
         shell()->web_contents(),
-        AccessibilityModeComplete,
+        ACCESSIBILITY_MODE_COMPLETE,
         ui::AX_EVENT_LAYOUT_COMPLETE);
     waiter.WaitForNotification();
   }
@@ -87,7 +87,7 @@
     // notification triggered by the hide.
     AccessibilityNotificationWaiter waiter(
         shell()->web_contents(),
-        AccessibilityModeComplete,
+        ACCESSIBILITY_MODE_COMPLETE,
         ui::AX_EVENT_LIVE_REGION_CHANGED);
     ASSERT_TRUE(ExecuteScript(
         shell(), "document.getElementById('p1').style.display = 'none';"));
@@ -104,7 +104,8 @@
   const ui::AXTree* tree = nullptr;
   {
     AccessibilityNotificationWaiter waiter(
-        shell()->web_contents(), AccessibilityModeComplete, ui::AX_EVENT_FOCUS);
+        shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
+        ui::AX_EVENT_FOCUS);
     ASSERT_TRUE(
         ExecuteScript(shell(), "document.getElementById('button').focus();"));
     waiter.WaitForNotification();
@@ -150,12 +151,12 @@
       shell()->web_contents()->GetMainFrame());
 
   {
-    // Enable accessibility (passing AccessibilityModeComplete to
+    // Enable accessibility (passing ACCESSIBILITY_MODE_COMPLETE to
     // AccessibilityNotificationWaiter does this automatically) and wait for
     // the first event.
     AccessibilityNotificationWaiter waiter(
         shell()->web_contents(),
-        AccessibilityModeComplete,
+        ACCESSIBILITY_MODE_COMPLETE,
         ui::AX_EVENT_LAYOUT_COMPLETE);
     waiter.WaitForNotification();
   }
@@ -185,7 +186,7 @@
 
     AccessibilityNotificationWaiter waiter(
         shell()->web_contents(),
-        AccessibilityModeComplete,
+        ACCESSIBILITY_MODE_COMPLETE,
         ui::AX_EVENT_LOAD_COMPLETE);
     waiter.WaitForNotification();
   }
diff --git a/content/browser/accessibility/accessibility_mode_browsertest.cc b/content/browser/accessibility/accessibility_mode_browsertest.cc
index 11e2ad31b..195362e 100644
--- a/content/browser/accessibility/accessibility_mode_browsertest.cc
+++ b/content/browser/accessibility/accessibility_mode_browsertest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/accessibility/accessibility_mode_helper.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
@@ -42,17 +41,12 @@
     }
   }
 
-  AccessibilityMode CorrectedAccessibility(AccessibilityMode mode) {
-    return AddAccessibilityModeTo(GetBaseAccessibilityMode(), mode);
-  }
-
   bool ShouldBeBrowserAccessibilityManager(AccessibilityMode mode) {
-    mode = CorrectedAccessibility(mode);
     switch (mode) {
       case AccessibilityModeOff:
-      case AccessibilityModeTreeOnly:
+      case ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY:
         return false;
-      case AccessibilityModeComplete:
+      case ACCESSIBILITY_MODE_COMPLETE:
         return true;
       default:
         NOTREACHED();
@@ -64,61 +58,62 @@
 IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, AccessibilityModeOff) {
   NavigateToURL(shell(), GURL(kMinimalPageDataURL));
 
-  EXPECT_EQ(CorrectedAccessibility(AccessibilityModeOff),
-            web_contents()->GetAccessibilityMode());
+  EXPECT_EQ(AccessibilityModeOff, web_contents()->GetAccessibilityMode());
   ExpectBrowserAccessibilityManager(
       ShouldBeBrowserAccessibilityManager(AccessibilityModeOff));
 }
 
-IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, AccessibilityModeComplete) {
+IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, ACCESSIBILITY_MODE_COMPLETE) {
   NavigateToURL(shell(), GURL(kMinimalPageDataURL));
-  ASSERT_EQ(CorrectedAccessibility(AccessibilityModeOff),
-            web_contents()->GetAccessibilityMode());
+  ASSERT_EQ(AccessibilityModeOff, web_contents()->GetAccessibilityMode());
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents());
-  web_contents()->AddAccessibilityMode(AccessibilityModeComplete);
-  EXPECT_EQ(AccessibilityModeComplete, web_contents()->GetAccessibilityMode());
+  web_contents()->AddAccessibilityMode(ACCESSIBILITY_MODE_COMPLETE);
+  EXPECT_EQ(ACCESSIBILITY_MODE_COMPLETE,
+            web_contents()->GetAccessibilityMode());
   waiter.WaitForNotification();
   ExpectBrowserAccessibilityManager(
-      ShouldBeBrowserAccessibilityManager(AccessibilityModeComplete));
+      ShouldBeBrowserAccessibilityManager(ACCESSIBILITY_MODE_COMPLETE));
 }
 
-IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, AccessibilityModeTreeOnly) {
+IN_PROC_BROWSER_TEST_F(AccessibilityModeTest,
+                       ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY) {
   NavigateToURL(shell(), GURL(kMinimalPageDataURL));
-  ASSERT_EQ(CorrectedAccessibility(AccessibilityModeOff),
-            web_contents()->GetAccessibilityMode());
+  ASSERT_EQ(AccessibilityModeOff, web_contents()->GetAccessibilityMode());
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents());
-  web_contents()->AddAccessibilityMode(AccessibilityModeTreeOnly);
-  EXPECT_EQ(CorrectedAccessibility(AccessibilityModeTreeOnly),
+  web_contents()->AddAccessibilityMode(ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY);
+  EXPECT_EQ(ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY,
             web_contents()->GetAccessibilityMode());
   waiter.WaitForNotification();
-  // No BrowserAccessibilityManager expected for AccessibilityModeTreeOnly
-  ExpectBrowserAccessibilityManager(
-      ShouldBeBrowserAccessibilityManager(AccessibilityModeTreeOnly));
+  // No BrowserAccessibilityManager expected for
+  // ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY
+  ExpectBrowserAccessibilityManager(ShouldBeBrowserAccessibilityManager(
+      ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY));
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, AddingModes) {
   NavigateToURL(shell(), GURL(kMinimalPageDataURL));
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents());
-  web_contents()->AddAccessibilityMode(AccessibilityModeTreeOnly);
-  EXPECT_EQ(CorrectedAccessibility(AccessibilityModeTreeOnly),
+  web_contents()->AddAccessibilityMode(ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY);
+  EXPECT_EQ(ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY,
             web_contents()->GetAccessibilityMode());
   waiter.WaitForNotification();
-  ExpectBrowserAccessibilityManager(ShouldBeBrowserAccessibilityManager(
-                                        AccessibilityModeTreeOnly),
-                                    "Should be no BrowserAccessibilityManager "
-                                    "for AccessibilityModeTreeOnly");
+  ExpectBrowserAccessibilityManager(
+      ShouldBeBrowserAccessibilityManager(ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY),
+      "Should be no BrowserAccessibilityManager "
+      "for ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY");
 
   AccessibilityNotificationWaiter waiter2(shell()->web_contents());
-  web_contents()->AddAccessibilityMode(AccessibilityModeComplete);
-  EXPECT_EQ(AccessibilityModeComplete, web_contents()->GetAccessibilityMode());
+  web_contents()->AddAccessibilityMode(ACCESSIBILITY_MODE_COMPLETE);
+  EXPECT_EQ(ACCESSIBILITY_MODE_COMPLETE,
+            web_contents()->GetAccessibilityMode());
   waiter2.WaitForNotification();
-  ExpectBrowserAccessibilityManager(ShouldBeBrowserAccessibilityManager(
-                                          AccessibilityModeComplete),
-                                    "Should be a BrowserAccessibilityManager "
-                                    "for AccessibilityModeComplete");
+  ExpectBrowserAccessibilityManager(
+      ShouldBeBrowserAccessibilityManager(ACCESSIBILITY_MODE_COMPLETE),
+      "Should be a BrowserAccessibilityManager "
+      "for ACCESSIBILITY_MODE_COMPLETE");
 }
 
 }  // namespace content
diff --git a/content/browser/accessibility/accessibility_mode_helper.cc b/content/browser/accessibility/accessibility_mode_helper.cc
deleted file mode 100644
index 9745e63..0000000
--- a/content/browser/accessibility/accessibility_mode_helper.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/logging.h"
-#include "content/browser/accessibility/accessibility_mode_helper.h"
-
-namespace content {
-
-namespace {
-
-AccessibilityMode CastToAccessibilityMode(unsigned int int_mode) {
-  AccessibilityMode mode = static_cast<AccessibilityMode>(int_mode);
-  switch (mode) {
-  case AccessibilityModeOff:
-  case AccessibilityModeComplete:
-  case AccessibilityModeTreeOnly:
-    return mode;
-  }
-  DCHECK(false) << "Could not convert to AccessibilityMode: " << int_mode;
-  return AccessibilityModeOff;
-}
-
-}  // namespace
-
-AccessibilityMode GetBaseAccessibilityMode() {
-  AccessibilityMode accessibility_mode = AccessibilityModeOff;
-  return accessibility_mode;
-}
-
-AccessibilityMode AddAccessibilityModeTo(AccessibilityMode to,
-                                         AccessibilityMode mode_to_add) {
-  return CastToAccessibilityMode(to | mode_to_add);
-}
-
-AccessibilityMode RemoveAccessibilityModeFrom(
-    AccessibilityMode from,
-    AccessibilityMode mode_to_remove) {
-  unsigned int new_mode = from ^ (mode_to_remove & from);
-  return CastToAccessibilityMode(new_mode);
-}
-
-}  // namespace content
diff --git a/content/browser/accessibility/accessibility_mode_helper.h b/content/browser/accessibility/accessibility_mode_helper.h
deleted file mode 100644
index c741173..0000000
--- a/content/browser/accessibility/accessibility_mode_helper.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_MODE_HELPER_H_
-#define CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_MODE_HELPER_H_
-
-#include "content/common/accessibility_mode_enums.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-// Returns base accessibility mode constant, depends on OS version.
-CONTENT_EXPORT AccessibilityMode GetBaseAccessibilityMode();
-
-// Adds the given accessibility mode constant to the given accessibility mode
-// bitmap.
-CONTENT_EXPORT AccessibilityMode
-    AddAccessibilityModeTo(AccessibilityMode to, AccessibilityMode mode_to_add);
-
-// Removes the given accessibility mode constant from the given accessibility
-// mode bitmap, managing the bits that are shared with other modes such that a
-// bit will only be turned off when all modes that depend on it have been
-// removed.
-CONTENT_EXPORT AccessibilityMode
-    RemoveAccessibilityModeFrom(AccessibilityMode to,
-                                AccessibilityMode mode_to_remove);
-
-} //  namespace content
-
-#endif  // CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_MODE_HELPER_H_
diff --git a/content/browser/accessibility/accessibility_mode_helper_unittest.cc b/content/browser/accessibility/accessibility_mode_helper_unittest.cc
deleted file mode 100644
index 6bef704..0000000
--- a/content/browser/accessibility/accessibility_mode_helper_unittest.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/accessibility/accessibility_mode_helper.h"
-#include "content/common/view_message_enums.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-TEST(AccessibilityModeHelperTest, TestNoOpRemove) {
-  EXPECT_EQ(AccessibilityModeComplete,
-            RemoveAccessibilityModeFrom(AccessibilityModeComplete,
-                                        AccessibilityModeOff));
-}
-
-TEST(AccessibilityModeHelperTest, TestRemoveSelf) {
-  AccessibilityMode kBaseMode = GetBaseAccessibilityMode();
-
-  EXPECT_EQ(kBaseMode,
-            RemoveAccessibilityModeFrom(AccessibilityModeComplete,
-                                        AccessibilityModeComplete));
-}
-
-TEST(AccessibilityModeHelperTest, TestAddMode) {
-  EXPECT_EQ(AccessibilityModeComplete,
-            AddAccessibilityModeTo(AccessibilityModeTreeOnly,
-                                   AccessibilityModeComplete));
-}
-
-}  // namespace content
diff --git a/content/browser/accessibility/accessibility_ui.cc b/content/browser/accessibility/accessibility_ui.cc
index 60e7689..e9e7f851 100644
--- a/content/browser/accessibility/accessibility_ui.cc
+++ b/content/browser/accessibility/accessibility_ui.cc
@@ -202,8 +202,8 @@
   auto* web_contents =
       static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(rvh));
   AccessibilityMode mode = web_contents->GetAccessibilityMode();
-  if ((mode & AccessibilityModeComplete) != AccessibilityModeComplete) {
-    web_contents->AddAccessibilityMode(AccessibilityModeComplete);
+  if ((mode & ACCESSIBILITY_MODE_COMPLETE) != ACCESSIBILITY_MODE_COMPLETE) {
+    web_contents->AddAccessibilityMode(ACCESSIBILITY_MODE_COMPLETE);
   } else {
     web_contents->SetAccessibilityMode(
         BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode());
@@ -214,7 +214,7 @@
   BrowserAccessibilityStateImpl* state =
       BrowserAccessibilityStateImpl::GetInstance();
   AccessibilityMode mode = state->accessibility_mode();
-  if ((mode & AccessibilityModeComplete) != AccessibilityModeComplete)
+  if ((mode & ACCESSIBILITY_MODE_COMPLETE) != ACCESSIBILITY_MODE_COMPLETE)
     state->EnableAccessibility();
   else
     state->DisableAccessibility();
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index 546286e..81f7cd04 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -14,7 +14,6 @@
 #include "base/win/scoped_bstr.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_variant.h"
-#include "content/browser/accessibility/accessibility_mode_helper.h"
 #include "content/browser/accessibility/accessibility_tree_formatter.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
@@ -105,7 +104,7 @@
 void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml(
     const std::string& html) {
   AccessibilityNotificationWaiter waiter(
-      shell()->web_contents(), AccessibilityModeComplete,
+      shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
       ui::AX_EVENT_LOAD_COMPLETE);
   GURL html_data_url("data:text/html," + html);
   NavigateToURL(shell(), html_data_url);
@@ -163,7 +162,7 @@
 
   // Set the caret on the last character.
   AccessibilityNotificationWaiter waiter(
-      shell()->web_contents(), AccessibilityModeComplete,
+      shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
       ui::AX_EVENT_TEXT_SELECTION_CHANGED);
   std::wstring caret_offset = base::UTF16ToWide(base::IntToString16(
       static_cast<int>(CONTENTS_LENGTH - 1)));
@@ -215,7 +214,7 @@
 
   // Set the caret on the last character.
   AccessibilityNotificationWaiter waiter(
-      shell()->web_contents(), AccessibilityModeComplete,
+      shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
       ui::AX_EVENT_TEXT_SELECTION_CHANGED);
   std::wstring caret_offset = base::UTF16ToWide(base::IntToString16(
       static_cast<int>(CONTENTS_LENGTH - 1)));
@@ -630,9 +629,6 @@
 
 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
                        TestBusyAccessibilityTree) {
- if (GetBaseAccessibilityMode() != AccessibilityModeOff)
-    return;
-
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
   // The initial accessible returned should have state STATE_SYSTEM_BUSY while
@@ -674,7 +670,7 @@
   // Set focus to the radio group.
   std::unique_ptr<AccessibilityNotificationWaiter> waiter(
       new AccessibilityNotificationWaiter(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_FOCUS));
   ExecuteScript(L"document.body.children[0].focus()");
   waiter->WaitForNotification();
@@ -686,7 +682,7 @@
 
   // Set the active descendant of the radio group
   waiter.reset(new AccessibilityNotificationWaiter(
-      shell()->web_contents(), AccessibilityModeComplete,
+      shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
       ui::AX_EVENT_FOCUS));
   ExecuteScript(
       L"document.body.children[0].setAttribute('aria-activedescendant', 'li')");
@@ -719,7 +715,7 @@
   // Check the checkbox.
   std::unique_ptr<AccessibilityNotificationWaiter> waiter(
       new AccessibilityNotificationWaiter(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_CHECKED_STATE_CHANGED));
   ExecuteScript(L"document.body.children[0].checked=true");
   waiter->WaitForNotification();
@@ -746,7 +742,7 @@
   // Change the children of the document body.
   std::unique_ptr<AccessibilityNotificationWaiter> waiter(
       new AccessibilityNotificationWaiter(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_CHILDREN_CHANGED));
   ExecuteScript(L"document.body.innerHTML='<b>new text</b>'");
   waiter->WaitForNotification();
@@ -772,7 +768,7 @@
   // Change the children of the document body.
   std::unique_ptr<AccessibilityNotificationWaiter> waiter(
       new AccessibilityNotificationWaiter(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_CHILDREN_CHANGED));
   ExecuteScript(L"document.body.children[0].style.visibility='visible'");
   waiter->WaitForNotification();
@@ -805,7 +801,7 @@
   // Focus the div in the document
   std::unique_ptr<AccessibilityNotificationWaiter> waiter(
       new AccessibilityNotificationWaiter(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_FOCUS));
   ExecuteScript(L"document.body.children[0].focus()");
   waiter->WaitForNotification();
@@ -819,7 +815,7 @@
   // Focus the document accessible. This will un-focus the current node.
   waiter.reset(
       new AccessibilityNotificationWaiter(
-          shell()->web_contents(), AccessibilityModeComplete,
+          shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
           ui::AX_EVENT_BLUR));
   base::win::ScopedComPtr<IAccessible> document_accessible(
       GetRendererAccessible());
@@ -855,7 +851,7 @@
   // Set the value of the text control
   std::unique_ptr<AccessibilityNotificationWaiter> waiter(
       new AccessibilityNotificationWaiter(shell()->web_contents(),
-                                          AccessibilityModeComplete,
+                                          ACCESSIBILITY_MODE_COMPLETE,
                                           ui::AX_EVENT_VALUE_CHANGED));
   ExecuteScript(L"document.body.children[0].value='new value'");
   waiter->WaitForNotification();
@@ -1097,7 +1093,7 @@
 
   AccessibilityNotificationWaiter waiter(
       shell()->web_contents(),
-      AccessibilityModeComplete,
+      ACCESSIBILITY_MODE_COMPLETE,
       ui::AX_EVENT_TEXT_SELECTION_CHANGED);
   caret_offset = 0;
   hr = input_text->setCaretOffset(caret_offset);
@@ -1121,7 +1117,7 @@
 
   AccessibilityNotificationWaiter waiter(
       shell()->web_contents(),
-      AccessibilityModeComplete,
+      ACCESSIBILITY_MODE_COMPLETE,
       ui::AX_EVENT_TEXT_SELECTION_CHANGED);
   caret_offset = 0;
   hr = textarea_text->setCaretOffset(caret_offset);
@@ -1716,7 +1712,7 @@
   // Cllicking the image will change its name.
   EXPECT_HRESULT_SUCCEEDED(image_action->doAction(0));
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         AccessibilityModeComplete,
+                                         ACCESSIBILITY_MODE_COMPLETE,
                                          ui::AX_EVENT_TEXT_CHANGED);
   waiter.WaitForNotification();
   EXPECT_HRESULT_SUCCEEDED(
@@ -1745,7 +1741,7 @@
   // Navigate to a new page and wait for the accessibility tree to load.
   AccessibilityNotificationWaiter waiter(
       shell()->web_contents(),
-      AccessibilityModeComplete,
+      ACCESSIBILITY_MODE_COMPLETE,
       ui::AX_EVENT_LOAD_COMPLETE);
   NavigateToURL(shell(), embedded_test_server()->GetURL(
       "/accessibility/html/article.html"));
diff --git a/content/browser/accessibility/android_granularity_movement_browsertest.cc b/content/browser/accessibility/android_granularity_movement_browsertest.cc
index 9ece9acc..d6152ef 100644
--- a/content/browser/accessibility/android_granularity_movement_browsertest.cc
+++ b/content/browser/accessibility/android_granularity_movement_browsertest.cc
@@ -40,7 +40,7 @@
 
     // Load the page.
     AccessibilityNotificationWaiter waiter(
-        shell()->web_contents(), AccessibilityModeComplete,
+        shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
         ui::AX_EVENT_LOAD_COMPLETE);
     NavigateToURL(shell(), url);
     waiter.WaitForNotification();
@@ -70,7 +70,7 @@
       BrowserAccessibility* node,
       int granularity) {
     AccessibilityNotificationWaiter waiter(
-        shell()->web_contents(), AccessibilityModeComplete,
+        shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
         ui::AX_EVENT_TREE_CHANGED);
     node->manager()->SetAccessibilityFocus(*node);
     waiter.WaitForNotification();
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.cc b/content/browser/accessibility/browser_accessibility_state_impl.cc
index a19b103..4c50bb3 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -9,7 +9,6 @@
 #include "base/command_line.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
-#include "content/browser/accessibility/accessibility_mode_helper.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_thread.h"
@@ -70,7 +69,7 @@
 }
 
 void BrowserAccessibilityStateImpl::EnableAccessibility() {
-  AddAccessibilityMode(AccessibilityModeComplete);
+  AddAccessibilityModeFlags(ACCESSIBILITY_MODE_COMPLETE);
 }
 
 void BrowserAccessibilityStateImpl::DisableAccessibility() {
@@ -81,7 +80,7 @@
   accessibility_mode_ = AccessibilityModeOff;
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kForceRendererAccessibility)) {
-    accessibility_mode_ = AccessibilityModeComplete;
+    accessibility_mode_ = ACCESSIBILITY_MODE_COMPLETE;
   }
 }
 
@@ -95,8 +94,8 @@
 }
 
 bool BrowserAccessibilityStateImpl::IsAccessibleBrowser() {
-  return ((accessibility_mode_ & AccessibilityModeComplete) ==
-          AccessibilityModeComplete);
+  return ((accessibility_mode_ & ACCESSIBILITY_MODE_COMPLETE) ==
+          ACCESSIBILITY_MODE_COMPLETE);
 }
 
 void BrowserAccessibilityStateImpl::AddHistogramCallback(
@@ -127,44 +126,33 @@
 }
 #endif
 
-void BrowserAccessibilityStateImpl::AddAccessibilityMode(
+void BrowserAccessibilityStateImpl::AddAccessibilityModeFlags(
     AccessibilityMode mode) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableRendererAccessibility)) {
     return;
   }
 
-  accessibility_mode_ =
-      content::AddAccessibilityModeTo(accessibility_mode_, mode);
-
-  AddOrRemoveFromAllWebContents(mode, true);
+  accessibility_mode_ |= mode;
+  std::vector<WebContentsImpl*> web_contents_vector =
+      WebContentsImpl::GetAllWebContents();
+  for (size_t i = 0; i < web_contents_vector.size(); ++i)
+    web_contents_vector[i]->AddAccessibilityMode(accessibility_mode_);
 }
 
-void BrowserAccessibilityStateImpl::RemoveAccessibilityMode(
+void BrowserAccessibilityStateImpl::RemoveAccessibilityModeFlags(
     AccessibilityMode mode) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kForceRendererAccessibility) &&
-      mode == AccessibilityModeComplete) {
+      mode == ACCESSIBILITY_MODE_COMPLETE) {
     return;
   }
 
-  accessibility_mode_ =
-      content::RemoveAccessibilityModeFrom(accessibility_mode_, mode);
-
-  AddOrRemoveFromAllWebContents(mode, false);
-}
-
-void BrowserAccessibilityStateImpl::AddOrRemoveFromAllWebContents(
-    AccessibilityMode mode,
-    bool add) {
+  accessibility_mode_ = accessibility_mode_ ^ (mode & accessibility_mode_);
   std::vector<WebContentsImpl*> web_contents_vector =
       WebContentsImpl::GetAllWebContents();
-  for (size_t i = 0; i < web_contents_vector.size(); ++i) {
-    if (add)
-      web_contents_vector[i]->AddAccessibilityMode(mode);
-    else
-      web_contents_vector[i]->RemoveAccessibilityMode(mode);
-  }
+  for (size_t i = 0; i < web_contents_vector.size(); ++i)
+    web_contents_vector[i]->SetAccessibilityMode(accessibility_mode());
 }
 
 }  // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.h b/content/browser/accessibility/browser_accessibility_state_impl.h
index 5beb762..043fecce 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl.h
+++ b/content/browser/accessibility/browser_accessibility_state_impl.h
@@ -51,14 +51,13 @@
 
   AccessibilityMode accessibility_mode() const { return accessibility_mode_; };
 
-  // Adds the given accessibility mode to the current accessibility mode bitmap.
-  void AddAccessibilityMode(AccessibilityMode mode);
+  // Adds the given accessibility mode flags to the current accessibility
+  // mode bitmap.
+  void AddAccessibilityModeFlags(AccessibilityMode mode);
 
-  // Removes the given accessibility mode from the current accessibility mode
-  // bitmap, managing the bits that are shared with other modes such that a
-  // bit will only be turned off when all modes that depend on it have been
-  // removed.
-  void RemoveAccessibilityMode(AccessibilityMode mode);
+  // Remove the given accessibility mode flags from the current accessibility
+  // mode bitmap.
+  void RemoveAccessibilityModeFlags(AccessibilityMode mode);
 
   // Accessibility objects can have the "hot tracked" state set when
   // the mouse is hovering over them, but this makes tests flaky because
@@ -88,10 +87,6 @@
 
   void UpdatePlatformSpecificHistograms();
 
-  // Updates the accessibility mode of all web contents, including swapped out
-  // ones. |add| specifies whether the mode should be added or removed.
-  void AddOrRemoveFromAllWebContents(AccessibilityMode mode, bool add);
-
   AccessibilityMode accessibility_mode_;
 
   std::vector<base::Closure> histogram_callbacks_;
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index dc3e99e..bb955ea2 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -45,7 +45,7 @@
   // Tell the renderer to send an accessibility tree, then wait for the
   // notification that it's been received.
   const ui::AXTree& GetAXTree(
-      AccessibilityMode accessibility_mode = AccessibilityModeComplete) {
+      AccessibilityMode accessibility_mode = ACCESSIBILITY_MODE_COMPLETE) {
     AccessibilityNotificationWaiter waiter(
         shell()->web_contents(),
         accessibility_mode,
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index b694772..1866525 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -257,7 +257,7 @@
     NavigateToURL(shell(), url);
     AccessibilityNotificationWaiter accessibility_waiter(
         web_contents,
-        AccessibilityModeComplete,
+        ACCESSIBILITY_MODE_COMPLETE,
         ui::AX_EVENT_NONE);
     accessibility_waiter.WaitForNotification();
   } else {
@@ -265,7 +265,7 @@
     // "load complete" AX event.
     AccessibilityNotificationWaiter accessibility_waiter(
         web_contents,
-        AccessibilityModeComplete,
+        ACCESSIBILITY_MODE_COMPLETE,
         ui::AX_EVENT_LOAD_COMPLETE);
     NavigateToURL(shell(), url);
     accessibility_waiter.WaitForNotification();
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 28daec1..e2326c4 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -91,7 +91,7 @@
   // a result of this function.
   std::unique_ptr<AccessibilityNotificationWaiter> waiter;
   waiter.reset(new AccessibilityNotificationWaiter(
-      shell()->web_contents(), AccessibilityModeComplete, ui::AX_EVENT_NONE));
+      shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE, ui::AX_EVENT_NONE));
 
   web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
       base::ASCIIToUTF16("go()"));
@@ -104,8 +104,9 @@
   // To make sure we've received all accessibility events, add a
   // sentinel by calling AccessibilityHitTest and waiting for a HOVER
   // event in response.
-  waiter.reset(new AccessibilityNotificationWaiter(
-      shell()->web_contents(), AccessibilityModeComplete, ui::AX_EVENT_HOVER));
+  waiter.reset(new AccessibilityNotificationWaiter(shell()->web_contents(),
+                                                   ACCESSIBILITY_MODE_COMPLETE,
+                                                   ui::AX_EVENT_HOVER));
   BrowserAccessibilityManager* manager =
       web_contents->GetRootBrowserAccessibilityManager();
   manager->HitTest(gfx::Point(0, 0));
diff --git a/content/browser/accessibility/hit_testing_browsertest.cc b/content/browser/accessibility/hit_testing_browsertest.cc
index fb9c6707..afcb4f6eb 100644
--- a/content/browser/accessibility/hit_testing_browsertest.cc
+++ b/content/browser/accessibility/hit_testing_browsertest.cc
@@ -31,7 +31,8 @@
         web_contents->GetRootBrowserAccessibilityManager();
 
     AccessibilityNotificationWaiter hover_waiter(
-        shell()->web_contents(), AccessibilityModeComplete, ui::AX_EVENT_HOVER);
+        shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
+        ui::AX_EVENT_HOVER);
     for (FrameTreeNode* node : frame_tree->Nodes())
       hover_waiter.ListenToAdditionalFrame(node->current_frame_host());
     manager->HitTest(point);
@@ -58,7 +59,8 @@
     // Each call to CachingAsyncHitTest results in at least one HOVER
     // event received. Block until we receive it.
     AccessibilityNotificationWaiter hover_waiter(
-        shell()->web_contents(), AccessibilityModeComplete, ui::AX_EVENT_HOVER);
+        shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE,
+        ui::AX_EVENT_HOVER);
     for (FrameTreeNode* node : frame_tree->Nodes())
       hover_waiter.ListenToAdditionalFrame(node->current_frame_host());
     BrowserAccessibility* result = manager->CachingAsyncHitTest(screen_point);
@@ -73,7 +75,7 @@
 
   // Load the page.
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         AccessibilityModeComplete,
+                                         ACCESSIBILITY_MODE_COMPLETE,
                                          ui::AX_EVENT_LOAD_COMPLETE);
   const char url_str[] =
       "data:text/html,"
@@ -102,7 +104,7 @@
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         AccessibilityModeComplete,
+                                         ACCESSIBILITY_MODE_COMPLETE,
                                          ui::AX_EVENT_LOAD_COMPLETE);
   GURL url(embedded_test_server()->GetURL(
       "/accessibility/html/iframe-coordinates.html"));
@@ -158,7 +160,7 @@
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         AccessibilityModeComplete,
+                                         ACCESSIBILITY_MODE_COMPLETE,
                                          ui::AX_EVENT_LOAD_COMPLETE);
   GURL url(embedded_test_server()->GetURL(
       "/accessibility/hit_testing/hit_testing.html"));
diff --git a/content/browser/accessibility/touch_accessibility_aura_browsertest.cc b/content/browser/accessibility/touch_accessibility_aura_browsertest.cc
index c7e1e8c..70845e4 100644
--- a/content/browser/accessibility/touch_accessibility_aura_browsertest.cc
+++ b/content/browser/accessibility/touch_accessibility_aura_browsertest.cc
@@ -36,7 +36,7 @@
   void NavigateToUrlAndWaitForAccessibilityTree(const GURL& url) {
     AccessibilityNotificationWaiter waiter(
         shell()->web_contents(),
-        AccessibilityModeComplete,
+        ACCESSIBILITY_MODE_COMPLETE,
         ui::AX_EVENT_LOAD_COMPLETE);
     NavigateToURL(shell(), url);
     waiter.WaitForNotification();
@@ -93,7 +93,7 @@
   // touch exploration event in the center of that cell, and assert that we
   // get an accessibility hover event fired in the correct cell.
   AccessibilityNotificationWaiter waiter(
-      shell()->web_contents(), AccessibilityModeComplete, ui::AX_EVENT_HOVER);
+      shell()->web_contents(), ACCESSIBILITY_MODE_COMPLETE, ui::AX_EVENT_HOVER);
   for (int row = 0; row < 5; ++row) {
     for (int col = 0; col < 7; ++col) {
       std::string expected_cell_text = base::IntToString(row * 7 + col);
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 458e67f..28e8c88 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -1384,7 +1384,7 @@
     // this WebContents if that succeeded.
     accessibility_state->OnScreenReaderDetected();
     if (accessibility_state->IsAccessibleBrowser() && web_contents_)
-      web_contents_->AddAccessibilityMode(AccessibilityModeComplete);
+      web_contents_->AddAccessibilityMode(ACCESSIBILITY_MODE_COMPLETE);
   } else {
     accessibility_state->ResetAccessibilityMode();
     if (web_contents_) {
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index c4c661d..87e47f6 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -181,6 +181,7 @@
   AOAH_NONSENSE_DEVICE_ID = 157,
   BDH_INVALID_OPTIONS = 158,
   RFH_DID_ADD_CONSOLE_MESSAGE_BAD_SEVERITY = 159,
+  AIRH_VOLUME_OUT_OF_RANGE = 160,
 
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/devtools/BUILD.gn b/content/browser/devtools/BUILD.gn
index 5ef4994..5c0d063 100644
--- a/content/browser/devtools/BUILD.gn
+++ b/content/browser/devtools/BUILD.gn
@@ -76,8 +76,6 @@
     "protocol/schema.h",
     "protocol/security.cc",
     "protocol/security.h",
-    "protocol/storage.cc",
-    "protocol/storage.h",
     "protocol/system_info.cc",
     "protocol/system_info.h",
     "protocol/tethering.cc",
diff --git a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
index 823d2185c..00f9c00b6 100755
--- a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
+++ b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -643,7 +643,7 @@
 includes = []
 fields_init = []
 
-browser_domains_list = ["Target", "ServiceWorker", "Input"]
+browser_domains_list = ["Target", "ServiceWorker", "Input", "Storage"]
 browser_commands_list = []
 async_commands_list = [
     "Input.synthesizePinchGesture",
diff --git a/content/browser/devtools/protocol/storage_handler.cc b/content/browser/devtools/protocol/storage_handler.cc
index 9c3a06ce..94415de7 100644
--- a/content/browser/devtools/protocol/storage_handler.cc
+++ b/content/browser/devtools/protocol/storage_handler.cc
@@ -9,12 +9,14 @@
 #include <vector>
 
 #include "base/strings/string_split.h"
-#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 
 namespace content {
-namespace protocol {
+namespace devtools {
+namespace storage {
 
 namespace {
 static const char kAppCache[] = "appcache";
@@ -29,29 +31,23 @@
 static const char kAll[] = "all";
 }
 
+typedef DevToolsProtocolClient::Response Response;
+
 StorageHandler::StorageHandler()
     : host_(nullptr) {
 }
 
 StorageHandler::~StorageHandler() = default;
 
-void StorageHandler::Wire(UberDispatcher* dispatcher) {
-  Storage::Dispatcher::wire(dispatcher, this);
-}
-
-void StorageHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
+void StorageHandler::SetRenderFrameHost(RenderFrameHost* host) {
   host_ = host;
 }
 
-Response StorageHandler::Disable() {
-  return Response::OK();
-}
-
 Response StorageHandler::ClearDataForOrigin(
     const std::string& origin,
     const std::string& storage_types) {
   if (!host_)
-    return Response::InternalError();
+    return Response::InternalError("Not connected to host");
 
   StoragePartition* partition = host_->GetProcess()->GetStoragePartition();
   std::vector<std::string> types = base::SplitString(
@@ -91,5 +87,6 @@
   return Response::OK();
 }
 
-}  // namespace protocol
+}  // namespace storage
+}  // namespace devtools
 }  // namespace content
diff --git a/content/browser/devtools/protocol/storage_handler.h b/content/browser/devtools/protocol/storage_handler.h
index f203a12..d6f7c65 100644
--- a/content/browser/devtools/protocol/storage_handler.h
+++ b/content/browser/devtools/protocol/storage_handler.h
@@ -6,34 +6,37 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_STORAGE_HANDLER_H_
 
 #include "base/macros.h"
-#include "content/browser/devtools/protocol/storage.h"
+#include "content/browser/devtools/devtools_protocol_handler.h"
+#include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h"
 
 namespace content {
 
-class RenderFrameHostImpl;
+class RenderFrameHost;
 
-namespace protocol {
+namespace devtools {
+namespace storage {
 
-class StorageHandler : public Storage::Backend {
+class StorageHandler {
  public:
-  StorageHandler();
-  ~StorageHandler() override;
+  typedef DevToolsProtocolClient::Response Response;
 
-  void Wire(UberDispatcher*);
-  void SetRenderFrameHost(RenderFrameHostImpl* host);
-  Response Disable() override;
+  StorageHandler();
+  ~StorageHandler();
+
+  void SetRenderFrameHost(RenderFrameHost* host);
 
   Response ClearDataForOrigin(
       const std::string& origin,
-      const std::string& storage_types) override;
+      const std::string& storage_types);
 
  private:
-  RenderFrameHostImpl* host_;
+  RenderFrameHost* host_;
 
   DISALLOW_COPY_AND_ASSIGN(StorageHandler);
 };
 
-}  // namespace protocol
+}  // namespace storage
+}  // namespace devtools
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_STORAGE_HANDLER_H_
diff --git a/content/browser/devtools/protocol_config.json b/content/browser/devtools/protocol_config.json
index c64ec06c..cb1899f7 100644
--- a/content/browser/devtools/protocol_config.json
+++ b/content/browser/devtools/protocol_config.json
@@ -52,9 +52,6 @@
                 "domain": "Security"
             },
             {
-                "domain": "Storage"
-            },
-            {
                 "domain": "SystemInfo",
                 "async": ["getInfo"]
             },
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index b217d8e..c7693a5 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -397,6 +397,7 @@
       input_handler_(new devtools::input::InputHandler()),
       service_worker_handler_(
           new devtools::service_worker::ServiceWorkerHandler()),
+      storage_handler_(new devtools::storage::StorageHandler()),
       target_handler_(new devtools::target::TargetHandler()),
       frame_trace_recorder_(nullptr),
       protocol_handler_(new DevToolsProtocolHandler(this)),
@@ -407,6 +408,7 @@
   DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
   dispatcher->SetInputHandler(input_handler_.get());
   dispatcher->SetServiceWorkerHandler(service_worker_handler_.get());
+  dispatcher->SetStorageHandler(storage_handler_.get());
   dispatcher->SetTargetHandler(target_handler_.get());
 
   SetPending(host);
@@ -509,9 +511,6 @@
     security_handler_->SetRenderFrameHost(handlers_frame_host_);
   }
 
-  storage_handler_.reset(new protocol::StorageHandler());
-  storage_handler_->Wire(session()->dispatcher());
-
   tracing_handler_.reset(new protocol::TracingHandler(
       protocol::TracingHandler::Renderer,
       frame_tree_node_->frame_tree_node_id(),
@@ -548,8 +547,6 @@
     security_handler_->Disable();
     security_handler_.reset();
   }
-  storage_handler_->Disable();
-  storage_handler_.reset();
   tracing_handler_->Disable();
   tracing_handler_.reset();
 
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index 2b464da..b17972cd 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -42,6 +42,7 @@
 namespace devtools {
 namespace input { class InputHandler; }
 namespace service_worker { class ServiceWorkerHandler; }
+namespace storage { class StorageHandler; }
 namespace target { class TargetHandler; }
 }
 
@@ -54,7 +55,6 @@
 class PageHandler;
 class SchemaHandler;
 class SecurityHandler;
-class StorageHandler;
 class TracingHandler;
 }  // namespace protocol
 
@@ -193,7 +193,8 @@
   std::unique_ptr<protocol::SecurityHandler> security_handler_;
   std::unique_ptr<devtools::service_worker::ServiceWorkerHandler>
       service_worker_handler_;
-  std::unique_ptr<protocol::StorageHandler> storage_handler_;
+  std::unique_ptr<devtools::storage::StorageHandler>
+      storage_handler_;
   std::unique_ptr<devtools::target::TargetHandler> target_handler_;
   std::unique_ptr<protocol::TracingHandler> tracing_handler_;
   std::unique_ptr<protocol::EmulationHandler> emulation_handler_;
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h
index a22a5bf..6f3497c 100644
--- a/content/browser/frame_host/render_frame_host_delegate.h
+++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -150,8 +150,9 @@
   // Get the accessibility mode for the WebContents that owns this frame.
   virtual AccessibilityMode GetAccessibilityMode() const;
 
-  // Forward accessibility messages to other potential listeners like
-  // the automation extension API.
+  // Called when accessibility events or location changes are received
+  // from a render frame, when the accessibility mode has the
+  // ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS flag set.
   virtual void AccessibilityEventReceived(
       const std::vector<AXEventNotificationDetails>& details) {}
   virtual void AccessibilityLocationChangesReceived(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 25d7098..c845479 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -16,7 +16,6 @@
 #include "base/process/kill.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "content/browser/accessibility/accessibility_mode_helper.h"
 #include "content/browser/accessibility/ax_tree_id_registry.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
@@ -1899,7 +1898,7 @@
 
   AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
   if ((accessibility_mode != AccessibilityModeOff) && view && is_active()) {
-    if (accessibility_mode & AccessibilityModeFlagPlatform)
+    if (accessibility_mode & ACCESSIBILITY_MODE_FLAG_NATIVE_APIS)
       GetOrCreateBrowserAccessibilityManager();
 
     std::vector<AXEventNotificationDetails> details;
@@ -1926,12 +1925,11 @@
       details.push_back(detail);
     }
 
-    if (accessibility_mode & AccessibilityModeFlagPlatform) {
+    if (accessibility_mode & ACCESSIBILITY_MODE_FLAG_NATIVE_APIS) {
       if (browser_accessibility_manager_)
         browser_accessibility_manager_->OnAccessibilityEvents(details);
     }
 
-    // Send the updates to the automation extension API.
     delegate_->AccessibilityEventReceived(details);
 
     // For testing only.
@@ -1972,7 +1970,7 @@
       render_view_host_->GetWidget()->GetView());
   if (view && is_active()) {
     AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
-    if (accessibility_mode & AccessibilityModeFlagPlatform) {
+    if (accessibility_mode & ACCESSIBILITY_MODE_FLAG_NATIVE_APIS) {
       BrowserAccessibilityManager* manager =
           GetOrCreateBrowserAccessibilityManager();
       if (manager)
@@ -1997,7 +1995,7 @@
 void RenderFrameHostImpl::OnAccessibilityFindInPageResult(
     const AccessibilityHostMsg_FindInPageResultParams& params) {
   AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
-  if (accessibility_mode & AccessibilityModeFlagPlatform) {
+  if (accessibility_mode & ACCESSIBILITY_MODE_FLAG_NATIVE_APIS) {
     BrowserAccessibilityManager* manager =
         GetOrCreateBrowserAccessibilityManager();
     if (manager) {
@@ -2871,7 +2869,7 @@
 void RenderFrameHostImpl::ActivateFindInPageResultForAccessibility(
     int request_id) {
   AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
-  if (accessibility_mode & AccessibilityModeFlagPlatform) {
+  if (accessibility_mode & ACCESSIBILITY_MODE_FLAG_NATIVE_APIS) {
     BrowserAccessibilityManager* manager =
         GetOrCreateBrowserAccessibilityManager();
     if (manager)
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h
index a7dc62df..148e3b2 100644
--- a/content/browser/media/session/media_session_impl.h
+++ b/content/browser/media/session/media_session_impl.h
@@ -132,11 +132,11 @@
 
   // Let the media session start ducking such that the volume multiplier is
   // reduced.
-  CONTENT_EXPORT void StartDucking();
+  CONTENT_EXPORT void StartDucking() override;
 
   // Let the media session stop ducking such that the volume multiplier is
   // recovered.
-  CONTENT_EXPORT void StopDucking();
+  CONTENT_EXPORT void StopDucking() override;
 
   // Returns if the session can be controlled by Resume() and Suspend calls
   // above.
diff --git a/content/browser/renderer_host/input/gesture_event_queue.cc b/content/browser/renderer_host/input/gesture_event_queue.cc
index 6952862..ac20e606 100644
--- a/content/browser/renderer_host/input/gesture_event_queue.cc
+++ b/content/browser/renderer_host/input/gesture_event_queue.cc
@@ -13,47 +13,6 @@
 using blink::WebInputEvent;
 
 namespace content {
-namespace {
-
-// Whether |event_in_queue| is GesturePinchUpdate or GestureScrollUpdate and
-// has the same modifiers/source as the new scroll/pinch event. Compatible
-// scroll and pinch event pairs can be logically coalesced.
-bool IsCompatibleScrollorPinch(
-    const GestureEventWithLatencyInfo& new_event,
-    const GestureEventWithLatencyInfo& event_in_queue) {
-  DCHECK(new_event.event.type == WebInputEvent::GestureScrollUpdate ||
-         new_event.event.type == WebInputEvent::GesturePinchUpdate)
-      << "Invalid event type for pinch/scroll coalescing: "
-      << WebInputEvent::GetName(new_event.event.type);
-  DLOG_IF(WARNING, new_event.event.timeStampSeconds <
-                       event_in_queue.event.timeStampSeconds)
-      << "Event time not monotonic?\n";
-  return (event_in_queue.event.type == WebInputEvent::GestureScrollUpdate ||
-          event_in_queue.event.type == WebInputEvent::GesturePinchUpdate) &&
-         event_in_queue.event.modifiers == new_event.event.modifiers &&
-         event_in_queue.event.sourceDevice == new_event.event.sourceDevice;
-}
-
-// Returns the transform matrix corresponding to the gesture event.
-gfx::Transform GetTransformForEvent(
-    const GestureEventWithLatencyInfo& gesture_event) {
-  gfx::Transform gesture_transform;
-  if (gesture_event.event.type == WebInputEvent::GestureScrollUpdate) {
-    gesture_transform.Translate(gesture_event.event.data.scrollUpdate.deltaX,
-                                gesture_event.event.data.scrollUpdate.deltaY);
-  } else if (gesture_event.event.type == WebInputEvent::GesturePinchUpdate) {
-    float scale = gesture_event.event.data.pinchUpdate.scale;
-    gesture_transform.Translate(-gesture_event.event.x, -gesture_event.event.y);
-    gesture_transform.Scale(scale, scale);
-    gesture_transform.Translate(gesture_event.event.x, gesture_event.event.y);
-  } else {
-    NOTREACHED() << "Invalid event type for transform retrieval: "
-                 << WebInputEvent::GetName(gesture_event.event.type);
-  }
-  return gesture_transform;
-}
-
-}  // namespace
 
 GestureEventQueue::Config::Config() {
 }
@@ -335,7 +294,8 @@
       const GestureEventWithLatencyInfo& first_event =
           coalesced_gesture_events_.front();
       if (gesture_event.event.type != first_event.event.type &&
-          IsCompatibleScrollorPinch(gesture_event, first_event)) {
+          ui::IsCompatibleScrollorPinch(gesture_event.event,
+                                        first_event.event)) {
         ignore_next_ack_ = true;
         client_->SendGestureEventImmediately(gesture_event);
       }
@@ -349,63 +309,50 @@
     return;
   }
 
-  if (!IsCompatibleScrollorPinch(gesture_event, *last_event)) {
+  if (!ui::IsCompatibleScrollorPinch(gesture_event.event, last_event->event)) {
     coalesced_gesture_events_.push_back(gesture_event);
     return;
   }
 
-  GestureEventWithLatencyInfo scroll_event;
-  GestureEventWithLatencyInfo pinch_event;
-  scroll_event.event.modifiers |= gesture_event.event.modifiers;
-  scroll_event.event.sourceDevice = gesture_event.event.sourceDevice;
-  scroll_event.event.timeStampSeconds = gesture_event.event.timeStampSeconds;
-  // Keep the oldest LatencyInfo.
-  DCHECK_LE(last_event->latency.trace_id(), gesture_event.latency.trace_id());
-  scroll_event.latency = last_event->latency;
-  pinch_event = scroll_event;
-  scroll_event.event.type = WebInputEvent::GestureScrollUpdate;
-  pinch_event.event.type = WebInputEvent::GesturePinchUpdate;
-  pinch_event.event.x = gesture_event.event.type ==
-      WebInputEvent::GesturePinchUpdate ?
-          gesture_event.event.x : last_event->event.x;
-  pinch_event.event.y = gesture_event.event.type ==
-      WebInputEvent::GesturePinchUpdate ?
-          gesture_event.event.y : last_event->event.y;
-
-  gfx::Transform combined_scroll_pinch = GetTransformForEvent(*last_event);
-  // Only include the second-to-last event in the coalesced pair if it exists
-  // and can be combined with the new event.
-  if (unsent_events_count > 1) {
-    const GestureEventWithLatencyInfo& second_last_event =
-        coalesced_gesture_events_[coalesced_gesture_events_.size() - 2];
-    if (IsCompatibleScrollorPinch(gesture_event, second_last_event)) {
-      // Keep the oldest LatencyInfo.
-      DCHECK_LE(second_last_event.latency.trace_id(),
-                scroll_event.latency.trace_id());
-      scroll_event.latency = second_last_event.latency;
-      pinch_event.latency = second_last_event.latency;
-      combined_scroll_pinch.PreconcatTransform(
-          GetTransformForEvent(second_last_event));
-      coalesced_gesture_events_.pop_back();
-    }
-  }
-  combined_scroll_pinch.ConcatTransform(GetTransformForEvent(gesture_event));
+  // Extract the last event in queue.
+  blink::WebGestureEvent last_gesture_event =
+      coalesced_gesture_events_.back().event;
+  DCHECK_LE(coalesced_gesture_events_.back().latency.trace_id(),
+            gesture_event.latency.trace_id());
+  ui::LatencyInfo oldest_latency = coalesced_gesture_events_.back().latency;
+  oldest_latency.set_coalesced();
   coalesced_gesture_events_.pop_back();
 
-  float combined_scale =
-      SkMScalarToFloat(combined_scroll_pinch.matrix().get(0, 0));
-  float combined_scroll_pinch_x =
-      SkMScalarToFloat(combined_scroll_pinch.matrix().get(0, 3));
-  float combined_scroll_pinch_y =
-      SkMScalarToFloat(combined_scroll_pinch.matrix().get(1, 3));
-  scroll_event.event.data.scrollUpdate.deltaX =
-      (combined_scroll_pinch_x + pinch_event.event.x) / combined_scale -
-      pinch_event.event.x;
-  scroll_event.event.data.scrollUpdate.deltaY =
-      (combined_scroll_pinch_y + pinch_event.event.y) / combined_scale -
-      pinch_event.event.y;
+  // Extract the second last event in queue.
+  ui::ScopedWebInputEvent second_last_gesture_event = nullptr;
+  if (unsent_events_count > 1 &&
+      ui::IsCompatibleScrollorPinch(gesture_event.event,
+                                    coalesced_gesture_events_.back().event)) {
+    second_last_gesture_event =
+        ui::WebInputEventTraits::Clone(coalesced_gesture_events_.back().event);
+    DCHECK_LE(coalesced_gesture_events_.back().latency.trace_id(),
+              oldest_latency.trace_id());
+    oldest_latency = coalesced_gesture_events_.back().latency;
+    oldest_latency.set_coalesced();
+    coalesced_gesture_events_.pop_back();
+  }
+
+  std::pair<blink::WebGestureEvent, blink::WebGestureEvent> coalesced_events =
+      ui::CoalesceScrollAndPinch(
+          second_last_gesture_event
+              ? &ui::ToWebGestureEvent(*second_last_gesture_event)
+              : nullptr,
+          last_gesture_event, gesture_event.event);
+
+  GestureEventWithLatencyInfo scroll_event;
+  scroll_event.event = coalesced_events.first;
+  scroll_event.latency = oldest_latency;
+
+  GestureEventWithLatencyInfo pinch_event;
+  pinch_event.event = coalesced_events.second;
+  pinch_event.latency = oldest_latency;
+
   coalesced_gesture_events_.push_back(scroll_event);
-  pinch_event.event.data.pinchUpdate.scale = combined_scale;
   coalesced_gesture_events_.push_back(pinch_event);
 }
 
diff --git a/content/browser/renderer_host/input/gesture_event_queue.h b/content/browser/renderer_host/input/gesture_event_queue.h
index 3f1e240..4649cca 100644
--- a/content/browser/renderer_host/input/gesture_event_queue.h
+++ b/content/browser/renderer_host/input/gesture_event_queue.h
@@ -19,7 +19,6 @@
 #include "content/common/content_export.h"
 #include "content/common/input/input_event_ack_state.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
-#include "ui/gfx/transform.h"
 
 namespace content {
 class GestureEventQueueTest;
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc
index aefb424..661924a 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc
@@ -16,7 +16,9 @@
 #include "base/process/process.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/sync_socket.h"
 #include "build/build_config.h"
+#include "content/browser/bad_message.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
 #include "content/browser/media/capture/web_contents_audio_input_stream.h"
 #include "content/browser/media/media_internals.h"
@@ -48,8 +50,9 @@
   if (add_prefix)
     oss << "AIRH::";
   oss << msg;
-  content::MediaStreamManager::SendMessageToNativeLog(oss.str());
-  DVLOG(1) << oss.str();
+  const std::string message = oss.str();
+  content::MediaStreamManager::SendMessageToNativeLog(message);
+  DVLOG(1) << message;
 }
 
 }  // namespace
@@ -105,8 +108,7 @@
       audio_mirroring_manager_(audio_mirroring_manager),
       user_input_monitor_(user_input_monitor),
       audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
-          media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)),
-      weak_factory_(this) {}
+          media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)) {}
 
 AudioInputRendererHost::~AudioInputRendererHost() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -184,22 +186,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   AudioEntry* entry = LookupByController(controller);
-  if (!entry) {
-    NOTREACHED() << "AudioInputController is invalid.";
-    return;
-  }
-
-  if (!PeerHandle()) {
-    NOTREACHED() << "Renderer process handle is invalid.";
-    DeleteEntryOnError(entry, INVALID_PEER_HANDLE);
-    return;
-  }
-
-  if (!entry->controller->SharedMemoryAndSyncSocketMode()) {
-    NOTREACHED() << "Only shared-memory/sync-socket mode is supported.";
-    DeleteEntryOnError(entry, INVALID_LATENCY_MODE);
-    return;
-  }
+  DCHECK(entry);
+  DCHECK(PeerHandle());
+  DCHECK(entry->controller->SharedMemoryAndSyncSocketMode());
 
   // Once the audio stream is created then complete the creation process by
   // mapping shared memory and sharing with the renderer process.
@@ -239,10 +228,7 @@
   // TODO(henrika): See crbug.com/115262 for details on why this method
   // should be implemented.
   AudioEntry* entry = LookupByController(controller);
-  if (!entry) {
-    NOTREACHED() << "AudioInputController is invalid.";
-    return;
-  }
+  DCHECK(entry) << "AudioInputController is invalid.";
   LogMessage(
       entry->stream_id, "DoSendRecordingMessage: stream is now started", true);
 }
@@ -252,10 +238,7 @@
     media::AudioInputController::ErrorCode error_code) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   AudioEntry* entry = LookupByController(controller);
-  if (!entry) {
-    NOTREACHED() << "AudioInputController is invalid.";
-    return;
-  }
+  DCHECK(entry);
 
   std::ostringstream oss;
   oss << "AIC reports error_code=" << error_code;
@@ -269,10 +252,7 @@
                                    const std::string& message) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   AudioEntry* entry = LookupByController(controller);
-  if (!entry) {
-    NOTREACHED() << "AudioInputController is invalid.";
-    return;
-  }
+  DCHECK(entry);
 
   // Add stream ID and current audio level reported by AIC to native log.
   LogMessage(entry->stream_id, message, false);
@@ -320,44 +300,41 @@
     const AudioInputHostMsg_CreateStream_Config& config) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  std::ostringstream oss;
-  oss << "[stream_id=" << stream_id << "] "
-      << "AIRH::OnCreateStream(render_frame_id=" << render_frame_id
-      << ", session_id=" << session_id << ")";
   DCHECK_GT(render_frame_id, 0);
 
   // media::AudioParameters is validated in the deserializer.
-  if (LookupById(stream_id) != NULL) {
+  if (LookupById(stream_id)) {
     SendErrorMessage(stream_id, STREAM_ALREADY_EXISTS);
     MaybeUnregisterKeyboardMicStream(config);
     return;
   }
 
+  // Check if we have the permission to open the device and which device to use.
+  const StreamDeviceInfo* info =
+      media_stream_manager_->audio_input_device_manager()
+          ->GetOpenedDeviceInfoById(session_id);
+  if (!info) {
+    SendErrorMessage(stream_id, PERMISSION_DENIED);
+    DLOG(WARNING) << "No permission has been granted to input stream with "
+                  << "session_id=" << session_id;
+    MaybeUnregisterKeyboardMicStream(config);
+    return;
+  }
+
+  const MediaStreamType& type = info->device.type;
+  const std::string& device_id = info->device.id;
+  const std::string& device_name = info->device.name;
   media::AudioParameters audio_params(config.params);
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kUseFakeDeviceForMediaStream)) {
     audio_params.set_format(media::AudioParameters::AUDIO_FAKE);
   }
 
-  // Check if we have the permission to open the device and which device to use.
-  MediaStreamType type = MEDIA_NO_SERVICE;
-  std::string device_name;
-  std::string device_id = media::AudioDeviceDescription::kDefaultDeviceId;
-  if (audio_params.format() != media::AudioParameters::AUDIO_FAKE) {
-    const StreamDeviceInfo* info = media_stream_manager_->
-        audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
-    if (!info) {
-      SendErrorMessage(stream_id, PERMISSION_DENIED);
-      DLOG(WARNING) << "No permission has been granted to input stream with "
-                    << "session_id=" << session_id;
-      MaybeUnregisterKeyboardMicStream(config);
-      return;
-    }
-    type = info->device.type;
-    device_id = info->device.id;
-    device_name = info->device.name;
-    oss << ": device_name=" << device_name;
-  }
+  std::ostringstream oss;
+  oss << "[stream_id=" << stream_id << "] "
+      << "AIRH::OnCreateStream(render_frame_id=" << render_frame_id
+      << ", session_id=" << session_id << ")"
+      << ": device_name=" << device_name;
 
   // Create a new AudioEntry structure.
   std::unique_ptr<AudioEntry> entry(new AudioEntry());
@@ -450,8 +427,9 @@
   }
 #endif
 
-  MediaStreamManager::SendMessageToNativeLog(oss.str());
-  DVLOG(1) << oss.str();
+  const std::string log_message = oss.str();
+  MediaStreamManager::SendMessageToNativeLog(log_message);
+  DVLOG(1) << log_message;
 
   // Since the controller was created successfully, create an entry and add it
   // to the map.
@@ -499,6 +477,12 @@
 void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
+  if (volume < 0 || volume > 1) {
+    bad_message::ReceivedBadMessage(this,
+                                    bad_message::AIRH_VOLUME_OUT_OF_RANGE);
+    return;
+  }
+
   AudioEntry* entry = LookupById(stream_id);
   if (!entry) {
     SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
@@ -575,7 +559,7 @@
   AudioEntryMap::iterator i = audio_entries_.find(stream_id);
   if (i != audio_entries_.end())
     return i->second;
-  return NULL;
+  return nullptr;
 }
 
 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
@@ -589,7 +573,7 @@
     if (controller == i->second->controller.get())
       return i->second;
   }
-  return NULL;
+  return nullptr;
 }
 
 void AudioInputRendererHost::MaybeUnregisterKeyboardMicStream(
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.h b/content/browser/renderer_host/media/audio_input_renderer_host.h
index 284ef56..a6fa5ae 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.h
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.h
@@ -30,20 +30,10 @@
 #include <memory>
 #include <string>
 
-#include "base/compiler_specific.h"
-#include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/process/process.h"
-#include "base/sequenced_task_runner_helpers.h"
 #include "content/common/media/audio_messages.h"
 #include "content/public/browser/browser_message_filter.h"
-#include "content/public/browser/browser_thread.h"
 #include "media/audio/audio_input_controller.h"
-#include "media/audio/audio_io.h"
-#include "media/audio/audio_logging.h"
-#include "media/audio/simple_sources.h"
-#include "media/media_features.h"
 
 namespace media {
 class AudioManager;
@@ -53,13 +43,12 @@
 namespace content {
 class AudioMirroringManager;
 class MediaStreamManager;
-class RenderProcessHost;
 
 class CONTENT_EXPORT AudioInputRendererHost
     : public BrowserMessageFilter,
       public media::AudioInputController::EventHandler {
  public:
-  // Error codes to make native loggin more clear. These error codes are added
+  // Error codes to make native logging more clear. These error codes are added
   // to generic error strings to provide a higher degree of details.
   // Changing these values can lead to problems when matching native debug
   // logs with the actual cause of error.
@@ -85,20 +74,14 @@
     // Failed to create native audio input stream.
     STREAM_CREATE_ERROR,  // = 6
 
-    // Renderer process handle is invalid.
-    INVALID_PEER_HANDLE,  // = 7
-
-    // Only low-latency mode is supported.
-    INVALID_LATENCY_MODE,  // = 8
-
     // Failed to map and share the shared memory.
-    MEMORY_SHARING_FAILED,  // = 9
+    MEMORY_SHARING_FAILED,  // = 7,
 
     // Unable to prepare the foreign socket handle.
-    SYNC_SOCKET_ERROR,  // = 10
+    SYNC_SOCKET_ERROR,  // = 8,
 
     // This error message comes from the AudioInputController instance.
-    AUDIO_INPUT_CONTROLLER_ERROR,  // = 11
+    AUDIO_INPUT_CONTROLLER_ERROR,  // = 9,
   };
 
   // Called from UI thread from the owner of this object.
@@ -135,17 +118,16 @@
   // filename.
   void set_renderer_pid(int32_t renderer_pid);
 
+ protected:
+  ~AudioInputRendererHost() override;
+
  private:
-  // TODO(henrika): extend test suite (compare AudioRenderHost)
   friend class BrowserThread;
-  friend class TestAudioInputRendererHost;
   friend class base::DeleteHelper<AudioInputRendererHost>;
 
   struct AudioEntry;
   typedef std::map<int, AudioEntry*> AudioEntryMap;
 
-  ~AudioInputRendererHost() override;
-
   // Methods called on IO thread ----------------------------------------------
 
   // Audio related IPC message handlers.
@@ -160,8 +142,8 @@
 
   // Creates an audio input stream with the specified format whose data is
   // consumed by an entity in the RenderFrame referenced by |render_frame_id|.
-  // |session_id| is used to find out which device to be used for the stream.
-  // Upon success/failure, the peer is notified via the
+  // |session_id| is used to identify the device that should be used for the
+  // stream. Upon success/failure, the peer is notified via the
   // NotifyStreamCreated message.
   void DoCreateStream(int stream_id,
                       int render_frame_id,
@@ -196,7 +178,7 @@
   // Send an error message to the renderer.
   void SendErrorMessage(int stream_id, ErrorCode error_code);
 
-  // Delete all audio entry and all audio streams
+  // Delete all audio entries and all audio streams.
   void DeleteEntries();
 
   // Closes the stream. The stream is then deleted in DeleteEntry() after it
@@ -261,8 +243,6 @@
 
   std::unique_ptr<media::AudioLog> audio_log_;
 
-  base::WeakPtrFactory<AudioInputRendererHost> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(AudioInputRendererHost);
 };
 
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc
new file mode 100644
index 0000000..74997b2
--- /dev/null
+++ b/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc
@@ -0,0 +1,571 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/media/audio_input_renderer_host.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/media/capture/audio_mirroring_manager.h"
+#include "content/browser/renderer_host/media/audio_input_device_manager.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "media/audio/audio_device_description.h"
+#include "media/audio/audio_input_writer.h"
+#include "media/audio/fake_audio_log_factory.h"
+#include "media/audio/fake_audio_manager.h"
+#include "media/base/media_switches.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+using ::media::AudioInputController;
+using ::testing::_;
+using ::testing::Assign;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::NotNull;
+using ::testing::SaveArg;
+using ::testing::StrictMock;
+
+namespace content {
+
+namespace {
+
+const int kStreamId = 100;
+const int kRenderProcessId = 42;
+const int kRendererPid = 21718;
+const int kRenderFrameId = 31415;
+const int kSharedMemoryCount = 11;
+const char kSecurityOrigin[] = "http://localhost";
+#if defined(OS_WIN)
+const wchar_t kBaseFileName[] = L"some_file_name";
+#else
+const char kBaseFileName[] = "some_file_name";
+#endif
+
+url::Origin SecurityOrigin() {
+  return url::Origin(GURL(kSecurityOrigin));
+}
+
+AudioInputHostMsg_CreateStream_Config DefaultConfig() {
+  AudioInputHostMsg_CreateStream_Config config;
+  config.params = media::AudioParameters::UnavailableDeviceParams();
+  config.automatic_gain_control = false;
+  config.shared_memory_count = kSharedMemoryCount;
+  return config;
+}
+
+class MockRenderer {
+ public:
+  MOCK_METHOD5(NotifyStreamCreated,
+               void(int /*stream_id*/,
+                    base::SharedMemoryHandle /*handle*/,
+                    base::SyncSocket::TransitDescriptor /*socket_desriptor*/,
+                    uint32_t /*length*/,
+                    uint32_t /*total_segments*/));
+  MOCK_METHOD2(NotifyStreamVolume, void(int /*stream_id*/, double /*volume*/));
+  MOCK_METHOD2(NotifyStreamStateChanged,
+               void(int /*stream_id*/,
+                    media::AudioInputIPCDelegateState /*state*/));
+  MOCK_METHOD0(WasShutDown, void());
+};
+
+// This class overrides Send to intercept the messages that the
+// AudioInputRendererHost sends to the renderer. They are sent to
+// the provided MockRenderer instead.
+class AudioInputRendererHostWithInterception : public AudioInputRendererHost {
+ public:
+  AudioInputRendererHostWithInterception(
+      int render_process_id,
+      int32_t renderer_pid,
+      media::AudioManager* audio_manager,
+      MediaStreamManager* media_stream_manager,
+      AudioMirroringManager* audio_mirroring_manager,
+      media::UserInputMonitor* user_input_monitor,
+      MockRenderer* renderer)
+      : AudioInputRendererHost(render_process_id,
+                               renderer_pid,
+                               audio_manager,
+                               media_stream_manager,
+                               audio_mirroring_manager,
+                               user_input_monitor),
+        renderer_(renderer) {
+    set_peer_process_for_testing(base::Process::Current());
+  }
+
+ protected:
+  ~AudioInputRendererHostWithInterception() override = default;
+
+ private:
+  bool Send(IPC::Message* message) override {
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    bool handled = true;
+
+    IPC_BEGIN_MESSAGE_MAP(AudioInputRendererHostWithInterception, *message)
+      IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamCreated,
+                          NotifyRendererStreamCreated)
+      IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamVolume,
+                          NotifyRendererStreamVolume)
+      IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamStateChanged,
+                          NotifyRendererStreamStateChanged)
+      IPC_MESSAGE_UNHANDLED(handled = false)
+    IPC_END_MESSAGE_MAP()
+
+    EXPECT_TRUE(handled);
+    delete message;
+    return true;
+  }
+
+  void ShutdownForBadMessage() override { renderer_->WasShutDown(); }
+
+  void NotifyRendererStreamCreated(
+      int stream_id,
+      base::SharedMemoryHandle handle,
+      base::SyncSocket::TransitDescriptor socket_descriptor,
+      uint32_t length,
+      uint32_t total_segments) {
+    // It's difficult to check that the sync socket and shared memory is
+    // valid in the gmock macros, so we check them here.
+    EXPECT_NE(base::SyncSocket::UnwrapHandle(socket_descriptor),
+              base::SyncSocket::kInvalidHandle);
+    base::SharedMemory memory(handle, /*read_only*/ true);
+    EXPECT_TRUE(memory.Map(length));
+    renderer_->NotifyStreamCreated(stream_id, handle, socket_descriptor, length,
+                                   total_segments);
+    EXPECT_TRUE(memory.Unmap());
+    memory.Close();
+  }
+
+  void NotifyRendererStreamVolume(int stream_id, double volume) {
+    renderer_->NotifyStreamVolume(stream_id, volume);
+  }
+
+  void NotifyRendererStreamStateChanged(
+      int stream_id,
+      media::AudioInputIPCDelegateState state) {
+    renderer_->NotifyStreamStateChanged(stream_id, state);
+  }
+
+  MockRenderer* renderer_;
+};
+
+class MockAudioInputController : public AudioInputController {
+ public:
+  MockAudioInputController(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      AudioInputController::SyncWriter* writer,
+      media::AudioManager* audio_manager,
+      AudioInputController::EventHandler* event_handler,
+      media::UserInputMonitor* user_input_monitor)
+      : AudioInputController(event_handler,
+                             writer,
+                             /*debug_writer*/ nullptr,
+                             user_input_monitor,
+                             /*agc*/ false) {
+    task_runner_ = std::move(task_runner);
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&AudioInputController::EventHandler::OnCreated,
+                   base::Unretained(event_handler), base::Unretained(this)));
+    ON_CALL(*this, Close(_))
+        .WillByDefault(Invoke(this, &MockAudioInputController::ExecuteClose));
+    ON_CALL(*this, EnableDebugRecording(_))
+        .WillByDefault(SaveArg<0>(&file_name));
+  }
+
+  EventHandler* handler() { return handler_; }
+
+  // File name that we pretend to do a debug recording to, if any.
+  base::FilePath debug_file_name() { return file_name; }
+
+  MOCK_METHOD0(Record, void());
+  MOCK_METHOD1(Close, void(const base::Closure&));
+  MOCK_METHOD1(SetVolume, void(double));
+  MOCK_METHOD1(EnableDebugRecording, void(const base::FilePath&));
+  MOCK_METHOD0(DisableDebugRecording, void());
+
+  // AudioInputCallback impl, irrelevant to us.
+  MOCK_METHOD4(
+      OnData,
+      void(media::AudioInputStream*, const media::AudioBus*, uint32_t, double));
+  MOCK_METHOD1(OnError, void(media::AudioInputStream*));
+
+ protected:
+  ~MockAudioInputController() override = default;
+
+ private:
+  void ExecuteClose(const base::Closure& task) {
+    // Hop to audio manager thread before calling task, since this is the real
+    // behavior.
+    task_runner_->PostTaskAndReply(FROM_HERE, base::Bind([]() {}), task);
+  }
+
+  base::FilePath file_name;
+};
+
+class MockControllerFactory : public AudioInputController::Factory {
+ public:
+  using MockController = StrictMock<MockAudioInputController>;
+
+  MockControllerFactory() {
+    AudioInputController::set_factory_for_testing(this);
+  }
+
+  ~MockControllerFactory() override {
+    AudioInputController::set_factory_for_testing(nullptr);
+  }
+
+  // AudioInputController::Factory implementaion:
+  AudioInputController* Create(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      AudioInputController::SyncWriter* sync_writer,
+      media::AudioManager* audio_manager,
+      AudioInputController::EventHandler* event_handler,
+      media::AudioParameters params,
+      media::UserInputMonitor* user_input_monitor) override {
+    ControllerCreated();
+    scoped_refptr<MockController> controller =
+        new MockController(std::move(task_runner), sync_writer, audio_manager,
+                           event_handler, user_input_monitor);
+    controller_list_.push_back(controller);
+    return controller.get();
+  }
+
+  MockController* controller(size_t i) {
+    EXPECT_GT(controller_list_.size(), i);
+    return controller_list_[i].get();
+  }
+
+  MOCK_METHOD0(ControllerCreated, void());
+
+ private:
+  std::vector<scoped_refptr<MockController>> controller_list_;
+};
+
+}  // namespace
+
+class AudioInputRendererHostTest : public testing::Test {
+ public:
+  AudioInputRendererHostTest() {
+    base::CommandLine* flags = base::CommandLine::ForCurrentProcess();
+    flags->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
+    flags->AppendSwitch(switches::kUseFakeUIForMediaStream);
+
+    audio_manager_.reset(new media::FakeAudioManager(
+        base::ThreadTaskRunnerHandle::Get(),
+        base::ThreadTaskRunnerHandle::Get(), &log_factory_));
+    media_stream_manager_ =
+        base::MakeUnique<MediaStreamManager>(audio_manager_.get());
+    airh_ = new AudioInputRendererHostWithInterception(
+        kRenderProcessId, kRendererPid, media::AudioManager::Get(),
+        media_stream_manager_.get(), AudioMirroringManager::GetInstance(),
+        nullptr, &renderer_);
+  }
+
+  ~AudioInputRendererHostTest() override {
+    airh_->OnChannelClosing();
+    base::RunLoop().RunUntilIdle();
+  }
+
+ protected:
+  // Makes device |device_id| with name |name| available to open with the
+  // session id returned.
+  int Open(const std::string& device_id, const std::string& name) {
+    int session_id = media_stream_manager_->audio_input_device_manager()->Open(
+        StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, name, device_id));
+    base::RunLoop().RunUntilIdle();
+    return session_id;
+  }
+
+  std::string GetRawNondefaultId() {
+    std::string id;
+    MediaDevicesManager::BoolDeviceTypes devices_to_enumerate;
+    devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_INPUT] = true;
+
+    media_stream_manager_->media_devices_manager()->EnumerateDevices(
+        devices_to_enumerate,
+        base::Bind(
+            [](std::string* id, const MediaDeviceEnumeration& result) {
+              // Index 0 is default, so use 1.
+              CHECK(result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_INPUT]
+                        .size() > 1)
+                  << "Expected to have a nondefault device.";
+              *id = result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_INPUT][1]
+                        .device_id;
+            },
+            base::Unretained(&id)));
+    base::RunLoop().RunUntilIdle();
+    return id;
+  }
+
+  media::FakeAudioLogFactory log_factory_;
+  StrictMock<MockControllerFactory> controller_factory_;
+  std::unique_ptr<MediaStreamManager> media_stream_manager_;
+  TestBrowserThreadBundle thread_bundle_;
+  media::ScopedAudioManagerPtr audio_manager_;
+  StrictMock<MockRenderer> renderer_;
+  scoped_refptr<AudioInputRendererHost> airh_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AudioInputRendererHostTest);
+};
+
+// Checks that a controller is created and a reply is sent when creating a
+// stream.
+TEST_F(AudioInputRendererHostTest, CreateWithDefaultDevice) {
+  int session_id =
+      Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(controller_factory_, ControllerCreated());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+}
+
+// If authorization hasn't been granted, only reply with and error and do
+// nothing else.
+TEST_F(AudioInputRendererHostTest, CreateWithoutAuthorization_Error) {
+  EXPECT_CALL(renderer_,
+              NotifyStreamStateChanged(
+                  kStreamId, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR));
+
+  int session_id = 0;
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+  base::RunLoop().RunUntilIdle();
+}
+
+// Like CreateWithDefaultDevice but with a nondefault device.
+TEST_F(AudioInputRendererHostTest, CreateWithNonDefaultDevice) {
+  int session_id = Open("Nondefault device", GetRawNondefaultId());
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(controller_factory_, ControllerCreated());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+}
+
+// Checks that stream is started when calling record.
+TEST_F(AudioInputRendererHostTest, CreateRecordClose) {
+  int session_id =
+      Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(controller_factory_, ControllerCreated());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_CALL(*controller_factory_.controller(0), Record());
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+
+  airh_->OnMessageReceived(AudioInputHostMsg_RecordStream(kStreamId));
+  base::RunLoop().RunUntilIdle();
+  airh_->OnMessageReceived(AudioInputHostMsg_CloseStream(kStreamId));
+  base::RunLoop().RunUntilIdle();
+}
+
+// In addition to the above, also check that a SetVolume message is propagated
+// to the controller.
+TEST_F(AudioInputRendererHostTest, CreateSetVolumeRecordClose) {
+  int session_id =
+      Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(controller_factory_, ControllerCreated());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_CALL(*controller_factory_.controller(0), SetVolume(0.5));
+  EXPECT_CALL(*controller_factory_.controller(0), Record());
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+
+  airh_->OnMessageReceived(AudioInputHostMsg_SetVolume(kStreamId, 0.5));
+  airh_->OnMessageReceived(AudioInputHostMsg_RecordStream(kStreamId));
+  airh_->OnMessageReceived(AudioInputHostMsg_CloseStream(kStreamId));
+
+  base::RunLoop().RunUntilIdle();
+}
+
+// Check that a too large volume is treated like a bad message and doesn't
+// reach the controller.
+TEST_F(AudioInputRendererHostTest, SetVolumeTooLarge_BadMessage) {
+  int session_id =
+      Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(controller_factory_, ControllerCreated());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+  EXPECT_CALL(renderer_, WasShutDown());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_SetVolume(kStreamId, 5));
+
+  base::RunLoop().RunUntilIdle();
+}
+
+// Like above.
+TEST_F(AudioInputRendererHostTest, SetVolumeNegative_BadMessage) {
+  int session_id =
+      Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(controller_factory_, ControllerCreated());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+  EXPECT_CALL(renderer_, WasShutDown());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_SetVolume(kStreamId, -0.5));
+
+  base::RunLoop().RunUntilIdle();
+}
+
+// Checks that a stream_id cannot be reused.
+TEST_F(AudioInputRendererHostTest, CreateTwice_Error) {
+  int session_id =
+      Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(renderer_,
+              NotifyStreamStateChanged(
+                  kStreamId, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR));
+  EXPECT_CALL(controller_factory_, ControllerCreated());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+}
+
+// Checks that when two streams are created, messages are routed to the correct
+// stream. Also checks that when enabling debug recording, the streams get
+// different file names.
+TEST_F(AudioInputRendererHostTest, TwoStreams) {
+  int session_id =
+      Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId + 1, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(controller_factory_, ControllerCreated()).Times(2);
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId + 1, kRenderFrameId, session_id, DefaultConfig()));
+  base::RunLoop().RunUntilIdle();
+
+#if BUILDFLAG(ENABLE_WEBRTC)
+  EXPECT_CALL(*controller_factory_.controller(0), EnableDebugRecording(_));
+  EXPECT_CALL(*controller_factory_.controller(1), EnableDebugRecording(_));
+
+  airh_->EnableDebugRecording(base::FilePath(kBaseFileName));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_NE(controller_factory_.controller(0)->debug_file_name(),
+            controller_factory_.controller(1)->debug_file_name());
+  EXPECT_CALL(*controller_factory_.controller(0), DisableDebugRecording());
+  EXPECT_CALL(*controller_factory_.controller(1), DisableDebugRecording());
+
+  airh_->DisableDebugRecording();
+#endif  // ENABLE_WEBRTC
+
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+  EXPECT_CALL(*controller_factory_.controller(1), Close(_));
+}
+
+// Checks that the stream is properly cleaned up and a notification is sent to
+// the renderer when the stream encounters an error.
+TEST_F(AudioInputRendererHostTest, Error_ClosesController) {
+  int session_id =
+      Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId);
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(controller_factory_, ControllerCreated());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+  EXPECT_CALL(renderer_,
+              NotifyStreamStateChanged(
+                  kStreamId, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR));
+
+  controller_factory_.controller(0)->handler()->OnError(
+      controller_factory_.controller(0), AudioInputController::UNKNOWN_ERROR);
+
+  // Check Close expectation before the destructor.
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClear(controller_factory_.controller(0));
+}
+
+// Checks that tab capture streams can be created.
+TEST_F(AudioInputRendererHostTest, TabCaptureStream) {
+  StreamControls controls(/* request_audio */ true, /* request_video */ false);
+  controls.audio.device_id = base::StringPrintf(
+      "web-contents-media-stream://%d:%d", kRenderProcessId, kRenderFrameId);
+  controls.audio.stream_source = kMediaStreamSourceTab;
+  std::string request_label = media_stream_manager_->MakeMediaAccessRequest(
+      kRenderProcessId, kRenderFrameId, 0, controls, SecurityOrigin(),
+      base::Bind([](const MediaStreamDevices& devices,
+                    std::unique_ptr<MediaStreamUIProxy>) {}));
+  base::RunLoop().RunUntilIdle();
+  int session_id = Open("Tab capture", controls.audio.device_id);
+
+  EXPECT_CALL(renderer_,
+              NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount));
+  EXPECT_CALL(controller_factory_, ControllerCreated());
+
+  airh_->OnMessageReceived(AudioInputHostMsg_CreateStream(
+      kStreamId, kRenderFrameId, session_id, DefaultConfig()));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_CALL(*controller_factory_.controller(0), Close(_));
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index a33e65d7..adf4451 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -29,7 +29,6 @@
 #include "build/build_config.h"
 #include "cc/base/switches.h"
 #include "cc/output/compositor_frame.h"
-#include "content/browser/accessibility/accessibility_mode_helper.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/browser_plugin/browser_plugin_guest.h"
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index dc72ecc..71b1dcb 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -1346,10 +1346,6 @@
 // https://crbug.com/491334
 #define MAYBE_SurfaceHitTestPointerEventsNone \
   DISABLED_SurfaceHitTestPointerEventsNone
-#elif defined(THREAD_SANITIZER)
-// Flaky on TSAN. https://crbug.com/582277
-#define MAYBE_SurfaceHitTestPointerEventsNone \
-  DISABLED_SurfaceHitTestPointerEventsNone
 #else
 #define MAYBE_SurfaceHitTestPointerEventsNone SurfaceHitTestPointerEventsNone
 #endif
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index bd1a646..35f0efe1 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -32,7 +32,6 @@
 #include "components/mime_util/mime_util.h"
 #include "components/rappor/public/rappor_utils.h"
 #include "components/url_formatter/url_formatter.h"
-#include "content/browser/accessibility/accessibility_mode_helper.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
@@ -963,11 +962,7 @@
 }
 
 void WebContentsImpl::AddAccessibilityMode(AccessibilityMode mode) {
-  SetAccessibilityMode(AddAccessibilityModeTo(accessibility_mode_, mode));
-}
-
-void WebContentsImpl::RemoveAccessibilityMode(AccessibilityMode mode) {
-  SetAccessibilityMode(RemoveAccessibilityModeFrom(accessibility_mode_, mode));
+  SetAccessibilityMode(accessibility_mode_ | mode);
 }
 
 void WebContentsImpl::RequestAXTreeSnapshot(AXTreeSnapshotCallback callback) {
@@ -1078,21 +1073,21 @@
   return renderer_preferences_.user_agent_override;
 }
 
-void WebContentsImpl::EnableTreeOnlyAccessibilityMode() {
+void WebContentsImpl::EnableWebContentsOnlyAccessibilityMode() {
   if (GetAccessibilityMode() != AccessibilityModeOff) {
     for (RenderFrameHost* rfh : GetAllFrames())
       ResetAccessibility(rfh);
   } else {
-    AddAccessibilityMode(AccessibilityModeTreeOnly);
+    AddAccessibilityMode(ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY);
   }
 }
 
-bool WebContentsImpl::IsTreeOnlyAccessibilityModeForTesting() const {
-  return accessibility_mode_ == AccessibilityModeTreeOnly;
+bool WebContentsImpl::IsWebContentsOnlyAccessibilityModeForTesting() const {
+  return accessibility_mode_ == ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY;
 }
 
 bool WebContentsImpl::IsFullAccessibilityModeForTesting() const {
-  return accessibility_mode_ == AccessibilityModeComplete;
+  return accessibility_mode_ == ACCESSIBILITY_MODE_COMPLETE;
 }
 
 const PageImportanceSignals& WebContentsImpl::GetPageImportanceSignals() const {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 5644671e..589ad951 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -226,12 +226,6 @@
   // bitmap.
   void AddAccessibilityMode(AccessibilityMode mode);
 
-  // Removes the given accessibility mode from the current accessibility
-  // mode bitmap, managing the bits that are shared with other modes such
-  // that a bit will only be turned off when all modes that depend on it
-  // have been removed.
-  void RemoveAccessibilityMode(AccessibilityMode mode);
-
   // Request a one-time snapshot of the accessibility tree without changing
   // the accessibility mode.
   using AXTreeSnapshotCallback =
@@ -294,8 +288,8 @@
   WebUI* GetCommittedWebUI() const override;
   void SetUserAgentOverride(const std::string& override) override;
   const std::string& GetUserAgentOverride() const override;
-  void EnableTreeOnlyAccessibilityMode() override;
-  bool IsTreeOnlyAccessibilityModeForTesting() const override;
+  void EnableWebContentsOnlyAccessibilityMode() override;
+  bool IsWebContentsOnlyAccessibilityModeForTesting() const override;
   bool IsFullAccessibilityModeForTesting() const override;
   const PageImportanceSignals& GetPageImportanceSignals() const override;
   const base::string16& GetTitle() const override;
diff --git a/content/common/accessibility_mode_enums.h b/content/common/accessibility_mode_enums.h
index ae059f2..46f8b4b 100644
--- a/content/common/accessibility_mode_enums.h
+++ b/content/common/accessibility_mode_enums.h
@@ -8,27 +8,61 @@
 // Note: keep enums in content/browser/resources/accessibility/accessibility.js
 // in sync with these two enums.
 enum AccessibilityModeFlag {
-  // Accessibility updates are processed to create platform trees and events are
-  // passed to platform APIs in the browser.
-  AccessibilityModeFlagPlatform = 1 << 0,
+  // Native accessibility APIs, specific to each platform, are enabled.
+  // When this flag is set that indicates the presence of a third-party
+  // client accessing Chrome via accessibility APIs. However, unless one
+  // of the flags below is set, the contents of web pages will not be
+  // accessible.
+  ACCESSIBILITY_MODE_FLAG_NATIVE_APIS = 1 << 0,
 
-  // Accessibility is on, and the full tree is computed. If this flag is off,
-  // only limited information about editable text nodes is sent to the browser
-  // process. Useful for implementing limited UIA on tablets.
-  AccessibilityModeFlagFullTree = 1 << 1,
+  // The renderer process will generate an accessibility tree containing
+  // basic information about all nodes, including role, name, value,
+  // state, and location. This is the minimum flag required in order for
+  // web contents to be accessible, and the remaining flags are meaningless
+  // unless this one is set.
+  //
+  // Note that sometimes this flag will be set when
+  // ACCESSIBILITY_MODE_FLAG_NATIVE_APIS is not, when the content layer embedder
+  // is providing accessibility support via some other mechanism other than
+  // what's implemented in content/browser.
+  ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS = 1 << 1,
+
+  // The accessibility tree will contain inline text boxes, which are
+  // necessary to expose information about line breaks and word boundaries.
+  // Without this flag, you can retrieve the plaintext value of a text field
+  // but not the information about how it's broken down into lines.
+  //
+  // Note that when this flag is off it's still possible to request inline
+  // text boxes for a specific node on-demand, asynchronously.
+  ACCESSIBILITY_MODE_FLAG_INLINE_TEXT_BOXES = 1 << 2,
+
+  // The accessibility tree will contain extra accessibility
+  // attributes typically only needed by screen readers and other
+  // assistive technology for blind users. Examples include text style
+  // attributes, table cell information, live region properties, range
+  // values, and relationship attributes.
+  ACCESSIBILITY_MODE_FLAG_SCREEN_READER = 1 << 3,
+
+  // The accessibility tree will contain the HTML tag name and HTML attributes
+  // for all accessibility nodes that come from web content.
+  ACCESSIBILITY_MODE_FLAG_HTML = 1 << 4,
 };
 
-enum AccessibilityMode {
-  // All accessibility is off.
-  AccessibilityModeOff = 0,
+typedef int AccessibilityMode;
 
-  // Renderer accessibility is on, and platform APIs are called.
-  AccessibilityModeComplete =
-      AccessibilityModeFlagPlatform | AccessibilityModeFlagFullTree,
+const AccessibilityMode AccessibilityModeOff = 0;
 
-  // Renderer accessibility is on, and events are passed to any extensions
-  // requesting automation, but not to platform accessibility.
-  AccessibilityModeTreeOnly = AccessibilityModeFlagFullTree,
-};
+const AccessibilityMode ACCESSIBILITY_MODE_COMPLETE =
+    ACCESSIBILITY_MODE_FLAG_NATIVE_APIS |
+    ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS |
+    ACCESSIBILITY_MODE_FLAG_INLINE_TEXT_BOXES |
+    ACCESSIBILITY_MODE_FLAG_SCREEN_READER |
+    ACCESSIBILITY_MODE_FLAG_HTML;
+
+const AccessibilityMode ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY =
+    ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS |
+    ACCESSIBILITY_MODE_FLAG_INLINE_TEXT_BOXES |
+    ACCESSIBILITY_MODE_FLAG_SCREEN_READER |
+    ACCESSIBILITY_MODE_FLAG_HTML;
 
 #endif  // CONTENT_COMMON_ACCESSIBILITY_MODE_ENUMS_H_
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 478fb11..39326bd 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -80,9 +80,6 @@
 
 #define IPC_MESSAGE_START FrameMsgStart
 
-IPC_ENUM_TRAITS_MIN_MAX_VALUE(AccessibilityMode,
-                              AccessibilityModeOff,
-                              AccessibilityModeComplete)
 IPC_ENUM_TRAITS_MIN_MAX_VALUE(content::JavaScriptMessageType,
                               content::JAVASCRIPT_MESSAGE_TYPE_ALERT,
                               content::JAVASCRIPT_MESSAGE_TYPE_PROMPT)
diff --git a/content/public/browser/media_session.h b/content/public/browser/media_session.h
index 78a1889..509629f 100644
--- a/content/public/browser/media_session.h
+++ b/content/public/browser/media_session.h
@@ -55,6 +55,14 @@
   // Tell the media session a user action has performed.
   virtual void DidReceiveAction(blink::mojom::MediaSessionAction action) = 0;
 
+  // Let the media session start ducking such that the volume multiplier is
+  // reduced.
+  virtual void StartDucking() = 0;
+
+  // Let the media session stop ducking such that the volume multiplier is
+  // recovered.
+  virtual void StopDucking() = 0;
+
  protected:
   MediaSession() = default;
 };
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index dab1686..a5e2535 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -302,13 +302,13 @@
   virtual void SetUserAgentOverride(const std::string& override) = 0;
   virtual const std::string& GetUserAgentOverride() const = 0;
 
-  // Enable the accessibility tree for this WebContents in the renderer,
-  // but don't enable creating a native accessibility tree on the browser
-  // side.
-  virtual void EnableTreeOnlyAccessibilityMode() = 0;
+  // Set the accessibility mode so that accessibility events are forwarded
+  // to each WebContentsObserver.
+  virtual void EnableWebContentsOnlyAccessibilityMode() = 0;
 
-  // Returns true only if "tree only" accessibility mode is on.
-  virtual bool IsTreeOnlyAccessibilityModeForTesting() const = 0;
+  // Returns true only if the WebContentsObserver accessibility mode is
+  // enabled.
+  virtual bool IsWebContentsOnlyAccessibilityModeForTesting() const = 0;
 
   // Returns true only if complete accessibility mode is on, meaning there's
   // both renderer accessibility, and a native browser accessibility tree.
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index 6d945a2..74218f22 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -445,12 +445,11 @@
   // Invoked when a user cancels a before unload dialog.
   virtual void BeforeUnloadDialogCancelled() {}
 
-  // Invoked when an accessibility event is received from the renderer process.
+  // Called when accessibility events or location changes are received
+  // from a render frame, but only when the accessibility mode has the
+  // ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS flag set.
   virtual void AccessibilityEventReceived(
       const std::vector<AXEventNotificationDetails>& details) {}
-
-  // Invoked when an accessibility location change is received from the
-  // renderer process.
   virtual void AccessibilityLocationChangesReceived(
       const std::vector<AXLocationChangeNotificationDetails>& details) {}
 
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 0bac669..fac5648 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -27,7 +27,6 @@
 #include "build/build_config.h"
 #include "cc/surfaces/surface.h"
 #include "cc/surfaces/surface_manager.h"
-#include "content/browser/accessibility/accessibility_mode_helper.h"
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/browser_plugin/browser_plugin_guest.h"
@@ -1027,7 +1026,7 @@
 void EnableAccessibilityForWebContents(WebContents* web_contents) {
   WebContentsImpl* web_contents_impl =
       static_cast<WebContentsImpl*>(web_contents);
-  web_contents_impl->SetAccessibilityMode(AccessibilityModeComplete);
+  web_contents_impl->SetAccessibilityMode(ACCESSIBILITY_MODE_COMPLETE);
 }
 
 void WaitForAccessibilityFocusChange() {
diff --git a/content/renderer/media/audio_input_message_filter.cc b/content/renderer/media/audio_input_message_filter.cc
index ff24d70..1659af3c8 100644
--- a/content/renderer/media/audio_input_message_filter.cc
+++ b/content/renderer/media/audio_input_message_filter.cc
@@ -215,6 +215,8 @@
 
 void AudioInputMessageFilter::AudioInputIPCImpl::SetVolume(double volume) {
   DCHECK_NE(stream_id_, kStreamIDNotSet);
+  DCHECK_GE(volume, 0);
+  DCHECK_LE(volume, 1);
   filter_->Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
 }
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index df68a66..0179a9c 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -2117,7 +2117,7 @@
     render_accessibility_ = NULL;
   }
 
-  if (accessibility_mode_ & AccessibilityModeFlagFullTree)
+  if (accessibility_mode_ & ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS)
     render_accessibility_ = new RenderAccessibilityImpl(this);
 
   for (auto& observer : observers_)
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 88d711e..c0bc0a4 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -1969,16 +1969,17 @@
   ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
   ASSERT_FALSE(frame()->render_accessibility());
 
-  frame()->SetAccessibilityMode(AccessibilityModeTreeOnly);
-  ASSERT_EQ(AccessibilityModeTreeOnly, frame()->accessibility_mode());
+  frame()->SetAccessibilityMode(ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY);
+  ASSERT_EQ(ACCESSIBILITY_MODE_WEB_CONTENTS_ONLY,
+            frame()->accessibility_mode());
   ASSERT_TRUE(frame()->render_accessibility());
 
   frame()->SetAccessibilityMode(AccessibilityModeOff);
   ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
   ASSERT_FALSE(frame()->render_accessibility());
 
-  frame()->SetAccessibilityMode(AccessibilityModeComplete);
-  ASSERT_EQ(AccessibilityModeComplete, frame()->accessibility_mode());
+  frame()->SetAccessibilityMode(ACCESSIBILITY_MODE_COMPLETE);
+  ASSERT_EQ(ACCESSIBILITY_MODE_COMPLETE, frame()->accessibility_mode());
   ASSERT_TRUE(frame()->render_accessibility());
 }
 
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 6115d96..16dc1388 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -2627,8 +2627,8 @@
   AccessibilityMode accessibility_mode =
       GetMainRenderFrame()->accessibility_mode();
   bool matches_accessibility_mode_complete =
-      (accessibility_mode & AccessibilityModeComplete) ==
-          AccessibilityModeComplete;
+      (accessibility_mode & ACCESSIBILITY_MODE_COMPLETE) ==
+          ACCESSIBILITY_MODE_COMPLETE;
   if (matches_accessibility_mode_complete)
     return false;
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 66fe09d..749c1cfd5 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -941,7 +941,6 @@
 
   defines = []
   sources = [
-    "../browser/accessibility/accessibility_mode_helper_unittest.cc",
     "../browser/accessibility/browser_accessibility_mac_unittest.mm",
     "../browser/accessibility/browser_accessibility_manager_unittest.cc",
     "../browser/accessibility/browser_accessibility_win_unittest.cc",
@@ -1180,6 +1179,7 @@
     "../browser/renderer_host/input/web_input_event_util_unittest.cc",
     "../browser/renderer_host/media/audio_input_debug_writer_unittest.cc",
     "../browser/renderer_host/media/audio_input_device_manager_unittest.cc",
+    "../browser/renderer_host/media/audio_input_renderer_host_unittest.cc",
     "../browser/renderer_host/media/audio_input_sync_writer_unittest.cc",
     "../browser/renderer_host/media/audio_output_authorization_handler_unittest.cc",
     "../browser/renderer_host/media/audio_output_delegate_unittest.cc",
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 7cd41523..bf6ae6b 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -48,6 +48,8 @@
         bug=660844) # WebGL 2.0.1
     self.Fail('conformance2/rendering/rendering-sampling-feedback-loop.html',
         bug=660844) # WebGL 2.0.1
+    self.Fail('conformance2/rendering/read-draw-when-missing-image.html',
+        bug=672719) # WebGL 2.0.1
     self.Fail('conformance2/glsl3/float-parsing.html',
         bug=672722) # WebGL 2.0.1
     self.Fail('conformance2/textures/misc/' +
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 06457f1..cd5e0ae 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -7912,10 +7912,6 @@
     return;
   }
 
-  // Detect that designated read/depth/stencil buffer in read framebuffer miss
-  // image, and the corresponding buffers in draw framebuffer have image.
-  bool read_framebuffer_miss_image = false;
-
   // Check whether read framebuffer and draw framebuffer have identical image
   // TODO(yunchao): consider doing something like CheckFramebufferStatus().
   // We cache the validation results, and if read_framebuffer doesn't change,
@@ -7939,18 +7935,6 @@
     is_feedback_loop = FeedbackLoopTrue;
   } else if (!read_framebuffer || !draw_framebuffer) {
     is_feedback_loop = FeedbackLoopFalse;
-    if (read_framebuffer) {
-      if (((mask & GL_COLOR_BUFFER_BIT) != 0 &&
-          !GetBoundReadFramebufferInternalFormat()) ||
-          ((mask & GL_DEPTH_BUFFER_BIT) != 0 &&
-          !read_framebuffer->GetAttachment(GL_DEPTH_ATTACHMENT) &&
-          BoundFramebufferHasDepthAttachment()) ||
-          ((mask & GL_STENCIL_BUFFER_BIT) != 0 &&
-          !read_framebuffer->GetAttachment(GL_STENCIL_ATTACHMENT) &&
-          BoundFramebufferHasStencilAttachment())) {
-        read_framebuffer_miss_image = true;
-      }
-    }
   } else {
     DCHECK(read_framebuffer && draw_framebuffer);
     if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
@@ -7960,9 +7944,6 @@
           draw_framebuffer->GetAttachment(GL_DEPTH_ATTACHMENT);
       if (!depth_buffer_draw || !depth_buffer_read) {
         mask &= ~GL_DEPTH_BUFFER_BIT;
-        if (depth_buffer_draw) {
-          read_framebuffer_miss_image = true;
-        }
       } else if (depth_buffer_draw->IsSameAttachment(depth_buffer_read)) {
         is_feedback_loop = FeedbackLoopTrue;
       }
@@ -7974,14 +7955,11 @@
           draw_framebuffer->GetAttachment(GL_STENCIL_ATTACHMENT);
       if (!stencil_buffer_draw || !stencil_buffer_read) {
         mask &= ~GL_STENCIL_BUFFER_BIT;
-        if (stencil_buffer_draw) {
-          read_framebuffer_miss_image = true;
-        }
       } else if (stencil_buffer_draw->IsSameAttachment(stencil_buffer_read)) {
         is_feedback_loop = FeedbackLoopTrue;
       }
     }
-    if (!mask && !read_framebuffer_miss_image)
+    if (!mask)
       return;
   }
 
@@ -8016,9 +7994,6 @@
       GLenum dst_type = GetBoundColorDrawBufferType(static_cast<GLint>(ii));
       if (dst_format == 0)
         continue;
-      if (!src_internal_format) {
-        read_framebuffer_miss_image = true;
-      }
       if (GetColorEncodingFromInternalFormat(dst_format) == GL_SRGB)
         draw_buffers_has_srgb = true;
       if (read_buffer_samples > 0 &&
@@ -8058,11 +8033,6 @@
         "source buffer and destination buffers are identical");
     return;
   }
-  if (read_framebuffer_miss_image == true) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name,
-       "The designated attachment point(s) in read framebuffer miss image");
-    return;
-  }
 
   if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
     if (filter != GL_NEAREST) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
index 3a0e0be..65c8c28b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -3961,18 +3961,21 @@
                                             1.0f,                 // depth
                                             false,  // scissor test
                                             0, 0, 128, 64);
+    EXPECT_CALL(*gl_, BlitFramebufferEXT(0, 0, _, _, 0, 0, _, _,
+                                      GL_COLOR_BUFFER_BIT, GL_LINEAR))
+        .Times(1)
+        .RetiresOnSaturation();
     BlitFramebufferCHROMIUM cmd;
     cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_LINEAR);
     EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-    // Generate INVALID_OPERATION because of missing read buffer image.
-    EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+    EXPECT_EQ(GL_NO_ERROR, GetGLError());
   }
 }
 
 TEST_P(GLES3DecoderTest, BlitFramebufferMissingDepthOrStencil) {
   // Run BlitFramebufferCHROMIUM with depth or stencil bits, from/to a read/draw
-  // framebuffer that doesn't have depth/stencil. It should generate
-  // INVALID_OPERATION.
+  // framebuffer that doesn't have depth/stencil. The bits should be silently
+  // ignored.
   DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
                      kServiceRenderbufferId);
   DoRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
@@ -4020,13 +4023,16 @@
     EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
         .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
         .RetiresOnSaturation();
+    EXPECT_CALL(*gl_, BlitFramebufferEXT(0, 0, 1, 1, 0, 0, 1, 1,
+                                         _, _))
+        .Times(0);
     BlitFramebufferCHROMIUM cmd;
     cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
     EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-    EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+    EXPECT_EQ(GL_NO_ERROR, GetGLError());
     cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_STENCIL_BUFFER_BIT, GL_NEAREST);
     EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-    EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+    EXPECT_EQ(GL_NO_ERROR, GetGLError());
   }
 
   // Switch FBOs and try the same.
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 5d6c5c2d..bcea0d6f 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -175,6 +175,7 @@
     "//ios/chrome/browser/open_from_clipboard",
     "//ios/chrome/browser/physical_web",
     "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/prefs:browser_prefs",
     "//ios/chrome/browser/services/gcm",
     "//ios/chrome/browser/translate",
     "//ios/chrome/browser/update_client",
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn
index 50c1e4f..ff04e6ea 100644
--- a/ios/chrome/browser/browser_state/BUILD.gn
+++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -89,6 +89,7 @@
     "//ios/chrome/browser/ntp_snippets",
     "//ios/chrome/browser/passwords",
     "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/prefs:browser_prefs",
     "//ios/chrome/browser/reading_list",
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/services/gcm",
@@ -109,7 +110,7 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state_metrics",
     "//ios/chrome/browser/net",
-    "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/prefs:browser_prefs",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/sync/glue",
@@ -146,6 +147,7 @@
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/net",
     "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/prefs:browser_prefs",
     "//ios/chrome/browser/sync/glue",
     "//ios/chrome/test:test_support",
     "//ios/public/provider/chrome/browser",
diff --git a/ios/chrome/browser/device_sharing/BUILD.gn b/ios/chrome/browser/device_sharing/BUILD.gn
index 2c22242..ef719c3f 100644
--- a/ios/chrome/browser/device_sharing/BUILD.gn
+++ b/ios/chrome/browser/device_sharing/BUILD.gn
@@ -12,7 +12,6 @@
     "//base",
     "//components/handoff",
     "//components/prefs",
-    "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/prefs",
     "//net",
@@ -30,7 +29,6 @@
     "//base",
     "//components/handoff",
     "//components/sync_preferences:test_support",
-    "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state:test_support",
     "//ios/web:test_support",
     "//testing/gtest",
diff --git a/ios/chrome/browser/device_sharing/device_sharing_manager.mm b/ios/chrome/browser/device_sharing/device_sharing_manager.mm
index 1039eb5..5449d181 100644
--- a/ios/chrome/browser/device_sharing/device_sharing_manager.mm
+++ b/ios/chrome/browser/device_sharing/device_sharing_manager.mm
@@ -8,10 +8,10 @@
 
 #include "base/mac/scoped_nsobject.h"
 #import "components/handoff/handoff_manager.h"
+#include "components/handoff/pref_names_ios.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/prefs/pref_observer_bridge.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/device_sharing/device_sharing_manager_unittest.mm b/ios/chrome/browser/device_sharing/device_sharing_manager_unittest.mm
index afa58dc5..33d5024 100644
--- a/ios/chrome/browser/device_sharing/device_sharing_manager_unittest.mm
+++ b/ios/chrome/browser/device_sharing/device_sharing_manager_unittest.mm
@@ -9,9 +9,9 @@
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsobject.h"
 #import "components/handoff/handoff_manager.h"
+#include "components/handoff/pref_names_ios.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/pref_names.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #include "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
diff --git a/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
index 577f30cd..e1282205 100644
--- a/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
+++ b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
@@ -21,7 +21,7 @@
     ios::ChromeBrowserState* browser_state) {
   base::FilePath popular_sites_path;
   base::PathService::Get(ios::DIR_USER_DATA, &popular_sites_path);
-  return base::MakeUnique<ntp_tiles::PopularSites>(
+  return base::MakeUnique<ntp_tiles::PopularSitesImpl>(
       web::WebThread::GetBlockingPool(), browser_state->GetPrefs(),
       ios::TemplateURLServiceFactory::GetForBrowserState(browser_state),
       GetApplicationContext()->GetVariationsService(),
diff --git a/ios/chrome/browser/pref_names.h b/ios/chrome/browser/pref_names.h
index feff827..1d0d9ad 100644
--- a/ios/chrome/browser/pref_names.h
+++ b/ios/chrome/browser/pref_names.h
@@ -5,11 +5,6 @@
 #ifndef IOS_CHROME_BROWSER_PREF_NAMES_H_
 #define IOS_CHROME_BROWSER_PREF_NAMES_H_
 
-// TODO(crbug.com/663469): Remove these includes once embedders are migrated to
-// use the new pref header.
-#include "components/handoff/pref_names_ios.h"
-#include "ios/public/provider/chrome/browser/voice/voice_search_prefs.h"
-
 namespace prefs {
 
 extern const char kAcceptLanguages[];
diff --git a/ios/chrome/browser/prefs/BUILD.gn b/ios/chrome/browser/prefs/BUILD.gn
index 459855a6..84c6e4a 100644
--- a/ios/chrome/browser/prefs/BUILD.gn
+++ b/ios/chrome/browser/prefs/BUILD.gn
@@ -4,8 +4,6 @@
 
 source_set("prefs") {
   sources = [
-    "browser_prefs.h",
-    "browser_prefs.mm",
     "ios_chrome_pref_model_associator_client.cc",
     "ios_chrome_pref_model_associator_client.h",
     "ios_chrome_pref_service_factory.cc",
@@ -15,6 +13,26 @@
   ]
   deps = [
     "//base",
+    "//components/content_settings/core/browser",
+    "//components/prefs",
+    "//components/proxy_config",
+    "//components/search_engines",
+    "//components/sync_preferences",
+    "//ios/chrome/browser",
+  ]
+
+  # TODO(sdefresne): remove once downstream dependencies have been fixed.
+  public_deps = [
+    ":browser_prefs",
+  ]
+}
+
+source_set("browser_prefs") {
+  sources = [
+    "browser_prefs.h",
+    "browser_prefs.mm",
+  ]
+  deps = [
     "//components/autofill/core/browser",
     "//components/browsing_data/core",
     "//components/content_settings/core/browser",
@@ -36,7 +54,6 @@
     "//components/ssl_config",
     "//components/strings",
     "//components/sync",
-    "//components/sync_preferences",
     "//components/translate/core/browser",
     "//components/translate/core/common",
     "//components/update_client",
@@ -50,7 +67,6 @@
     "//ios/chrome/browser/metrics",
     "//ios/chrome/browser/net",
     "//ios/chrome/browser/physical_web",
-    "//ios/chrome/browser/reading_list",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/voice:prefs",
     "//ios/public/provider/chrome/browser",
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 7f0c97d..5affdc0 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -93,7 +93,7 @@
   ntp_snippets::RemoteSuggestionsProvider::RegisterProfilePrefs(registry);
   ntp_snippets::ContentSuggestionsService::RegisterProfilePrefs(registry);
   ntp_tiles::MostVisitedSites::RegisterProfilePrefs(registry);
-  ntp_tiles::PopularSites::RegisterProfilePrefs(registry);
+  ntp_tiles::PopularSitesImpl::RegisterProfilePrefs(registry);
   ios::NotificationPromo::RegisterProfilePrefs(registry);
   password_manager::PasswordManager::RegisterProfilePrefs(registry);
   PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry);
diff --git a/ios/chrome/browser/signin/BUILD.gn b/ios/chrome/browser/signin/BUILD.gn
index 4a13d58..c31264b 100644
--- a/ios/chrome/browser/signin/BUILD.gn
+++ b/ios/chrome/browser/signin/BUILD.gn
@@ -120,7 +120,7 @@
     "//google_apis",
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state:test_support",
-    "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/prefs:browser_prefs",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/sync:test_support",
     "//ios/chrome/test:test_support",
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 7d140100..3281242 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -25,7 +25,7 @@
     "//components/prefs:test_support",
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state:browser_state_impl",
-    "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/prefs:browser_prefs",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser:test_support",
     "//ios/web",
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc
index 6391c9e1..6bef687 100644
--- a/media/audio/audio_input_controller.cc
+++ b/media/audio/audio_input_controller.cc
@@ -128,9 +128,11 @@
     return nullptr;
 
   if (factory_) {
-    return factory_->Create(
-        audio_manager, event_handler, params, user_input_monitor);
+    return factory_->Create(audio_manager->GetTaskRunner(),
+                            /*sync_writer*/ nullptr, audio_manager,
+                            event_handler, params, user_input_monitor);
   }
+
   scoped_refptr<AudioInputController> controller(new AudioInputController(
       event_handler, nullptr, nullptr, user_input_monitor, false));
 
@@ -167,6 +169,12 @@
   if (!params.IsValid() || (params.channels() > kMaxInputChannels))
     return nullptr;
 
+  if (factory_) {
+    return factory_->Create(audio_manager->GetTaskRunner(), sync_writer,
+                            audio_manager, event_handler, params,
+                            user_input_monitor);
+  }
+
   // Create the AudioInputController object and ensure that it runs on
   // the audio-manager thread.
   scoped_refptr<AudioInputController> controller(new AudioInputController(
@@ -200,6 +208,12 @@
   DCHECK(sync_writer);
   DCHECK(stream);
 
+  if (factory_) {
+    return factory_->Create(
+        task_runner, sync_writer, AudioManager::Get(), event_handler,
+        media::AudioParameters::UnavailableDeviceParams(), user_input_monitor);
+  }
+
   // Create the AudioInputController object and ensure that it runs on
   // the audio-manager thread.
   scoped_refptr<AudioInputController> controller(new AudioInputController(
diff --git a/media/audio/audio_input_controller.h b/media/audio/audio_input_controller.h
index 86f7cb3..e778838 100644
--- a/media/audio/audio_input_controller.h
+++ b/media/audio/audio_input_controller.h
@@ -147,6 +147,8 @@
   class Factory {
    public:
     virtual AudioInputController* Create(
+        scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+        SyncWriter* sync_writer,
         AudioManager* audio_manager,
         EventHandler* event_handler,
         AudioParameters params,
@@ -232,10 +234,10 @@
   bool SharedMemoryAndSyncSocketMode() const { return sync_writer_ != NULL; }
 
   // Enable debug recording of audio input.
-  void EnableDebugRecording(const base::FilePath& file_name);
+  virtual void EnableDebugRecording(const base::FilePath& file_name);
 
   // Disable debug recording of audio input.
-  void DisableDebugRecording();
+  virtual void DisableDebugRecording();
 
  protected:
   friend class base::RefCountedThreadSafe<AudioInputController>;
diff --git a/media/audio/test_audio_input_controller_factory.cc b/media/audio/test_audio_input_controller_factory.cc
index 9685f4b..024e7ad 100644
--- a/media/audio/test_audio_input_controller_factory.cc
+++ b/media/audio/test_audio_input_controller_factory.cc
@@ -52,6 +52,8 @@
 }
 
 AudioInputController* TestAudioInputControllerFactory::Create(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    AudioInputController::SyncWriter* sync_writer,
     AudioManager* audio_manager,
     AudioInputController::EventHandler* event_handler,
     AudioParameters params,
diff --git a/media/audio/test_audio_input_controller_factory.h b/media/audio/test_audio_input_controller_factory.h
index 66e2cc5..4a04d36e 100644
--- a/media/audio/test_audio_input_controller_factory.h
+++ b/media/audio/test_audio_input_controller_factory.h
@@ -100,6 +100,8 @@
 
   // AudioInputController::Factory methods.
   AudioInputController* Create(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      AudioInputController::SyncWriter* sync_writer,
       AudioManager* audio_manager,
       AudioInputController::EventHandler* event_handler,
       AudioParameters params,
diff --git a/net/ssl/ssl_private_key_test_util.cc b/net/ssl/ssl_private_key_test_util.cc
index 0e60cbc..ddeaca7 100644
--- a/net/ssl/ssl_private_key_test_util.cc
+++ b/net/ssl/ssl_private_key_test_util.cc
@@ -117,12 +117,12 @@
                      const base::StringPiece& digest,
                      EVP_PKEY* key,
                      std::string* result) {
-  size_t sig_len;
+  size_t sig_len = EVP_PKEY_size(key);
   bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key, nullptr));
   if (!ctx || !EVP_PKEY_sign_init(ctx.get()) ||
       !EVP_PKEY_CTX_set_signature_md(ctx.get(), md) ||
-      !EVP_PKEY_sign(ctx.get(), OpenSSLWriteInto(result, EVP_PKEY_size(key)),
-                     &sig_len, reinterpret_cast<const uint8_t*>(digest.data()),
+      !EVP_PKEY_sign(ctx.get(), OpenSSLWriteInto(result, sig_len), &sig_len,
+                     reinterpret_cast<const uint8_t*>(digest.data()),
                      digest.size())) {
     return false;
   }
diff --git a/testing/libfuzzer/efficient_fuzzer.md b/testing/libfuzzer/efficient_fuzzer.md
index fa7efa9..7c3be85 100644
--- a/testing/libfuzzer/efficient_fuzzer.md
+++ b/testing/libfuzzer/efficient_fuzzer.md
@@ -199,7 +199,7 @@
 ./third_party/llvm-build/Release+Asserts/bin/sancov \
   -symbolize my_fuzzer my_fuzzer.123.sancov > my_fuzzer.symcov
 # Launch coverage report server
-curl http://llvm.org/svn/llvm-project/llvm/trunk/tools/sancov/coverage-report-server.py | python3 \
+curl https://llvm.org/svn/llvm-project/llvm/trunk/tools/sancov/coverage-report-server.py | python3 \
   --symcov my_fuzzer.symcov --srcpath path_to_chromium_sources
 # Navigate to http://localhost:8001/ to view coverage report
 ```
diff --git a/third_party/WebKit/LayoutTests/fast/events/constructors/serviceworker-message-event-constructor-expected.txt b/third_party/WebKit/LayoutTests/fast/events/constructors/serviceworker-message-event-constructor-expected.txt
deleted file mode 100644
index 1ed07792..0000000
--- a/third_party/WebKit/LayoutTests/fast/events/constructors/serviceworker-message-event-constructor-expected.txt
+++ /dev/null
@@ -1,112 +0,0 @@
-This tests the constructor for the ServiceWorkerMessageEvent DOM class.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS new ServiceWorkerMessageEvent('eventType').bubbles is false
-PASS new ServiceWorkerMessageEvent('eventType').cancelable is false
-PASS new ServiceWorkerMessageEvent('eventType').data is null
-PASS new ServiceWorkerMessageEvent('eventType').origin is ""
-PASS new ServiceWorkerMessageEvent('eventType').lastEventId is ""
-PASS new ServiceWorkerMessageEvent('eventType').source is null
-PASS new ServiceWorkerMessageEvent('eventType').ports is null
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: false }).bubbles is false
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true }).bubbles is true
-PASS new ServiceWorkerMessageEvent('eventType', { cancelable: false }).cancelable is false
-PASS new ServiceWorkerMessageEvent('eventType', { cancelable: true }).cancelable is true
-PASS new ServiceWorkerMessageEvent('eventType', { data: test_object }).data is test_object
-PASS new ServiceWorkerMessageEvent('eventType', { data: document }).data is document
-PASS new ServiceWorkerMessageEvent('eventType', { data: undefined }).data is null
-PASS new ServiceWorkerMessageEvent('eventType', { data: null }).data is null
-PASS new ServiceWorkerMessageEvent('eventType', { data: false }).data is false
-PASS new ServiceWorkerMessageEvent('eventType', { data: true }).data is true
-PASS new ServiceWorkerMessageEvent('eventType', { data: '' }).data is ""
-PASS new ServiceWorkerMessageEvent('eventType', { data: 'chocolate' }).data is "chocolate"
-PASS new ServiceWorkerMessageEvent('eventType', { data: 12345 }).data is 12345
-PASS new ServiceWorkerMessageEvent('eventType', { data: 18446744073709551615 }).data is 18446744073709552000
-PASS new ServiceWorkerMessageEvent('eventType', { data: NaN }).data is NaN
-PASS new ServiceWorkerMessageEvent('eventType', { data: {valueOf: function () { return test_object; } } }).data == test_object is false
-PASS new ServiceWorkerMessageEvent('eventType', { get data() { return 123; } }).data is 123
-PASS new ServiceWorkerMessageEvent('eventType', { get data() { throw 'ServiceWorkerMessageEvent Error'; } }) threw exception ServiceWorkerMessageEvent Error.
-PASS new ServiceWorkerMessageEvent('eventType', { origin: 'melancholy' }).origin is "melancholy"
-PASS new ServiceWorkerMessageEvent('eventType', { origin: '' }).origin is ""
-PASS new ServiceWorkerMessageEvent('eventType', { origin: undefined }).origin is ""
-PASS new ServiceWorkerMessageEvent('eventType', { origin: null }).origin is "null"
-PASS new ServiceWorkerMessageEvent('eventType', { origin: false }).origin is "false"
-PASS new ServiceWorkerMessageEvent('eventType', { origin: true }).origin is "true"
-PASS new ServiceWorkerMessageEvent('eventType', { origin: 12345 }).origin is "12345"
-PASS new ServiceWorkerMessageEvent('eventType', { origin: 18446744073709551615 }).origin is "18446744073709552000"
-PASS new ServiceWorkerMessageEvent('eventType', { origin: NaN }).origin is "NaN"
-PASS new ServiceWorkerMessageEvent('eventType', { origin: [] }).origin is ""
-PASS new ServiceWorkerMessageEvent('eventType', { origin: [1, 2, 3] }).origin is "1,2,3"
-PASS new ServiceWorkerMessageEvent('eventType', { origin: {melancholy: 12345} }).origin is "[object Object]"
-PASS new ServiceWorkerMessageEvent('eventType', { origin: {valueOf: function () { return 'melancholy'; } } }).origin is "[object Object]"
-PASS new ServiceWorkerMessageEvent('eventType', { get origin() { return 123; } }).origin is "123"
-PASS new ServiceWorkerMessageEvent('eventType', { get origin() { throw 'ServiceWorkerMessageEvent Error'; } }) threw exception ServiceWorkerMessageEvent Error.
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: 'melancholy' }).lastEventId is "melancholy"
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: '' }).lastEventId is ""
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: undefined }).lastEventId is ""
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: null }).lastEventId is "null"
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: false }).lastEventId is "false"
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: true }).lastEventId is "true"
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: 12345 }).lastEventId is "12345"
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: 18446744073709551615 }).lastEventId is "18446744073709552000"
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: NaN }).lastEventId is "NaN"
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: [] }).lastEventId is ""
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: [1, 2, 3] }).lastEventId is "1,2,3"
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: {melancholy: 12345} }).lastEventId is "[object Object]"
-PASS new ServiceWorkerMessageEvent('eventType', { lastEventId: {valueOf: function () { return 'melancholy'; } } }).lastEventId is "[object Object]"
-PASS new ServiceWorkerMessageEvent('eventType', { get lastEventId() { return 123; } }).lastEventId is "123"
-PASS new ServiceWorkerMessageEvent('eventType', { get lastEventId() { throw 'ServiceWorkerMessageEvent Error'; } }) threw exception ServiceWorkerMessageEvent Error.
-PASS new ServiceWorkerMessageEvent('eventType', { ports: [channel.port1], source: channel.port1 }).source is channel.port1
-PASS new ServiceWorkerMessageEvent('eventType', { source: window }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: this }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: test_object }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: document }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: document.body }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: undefined }).source is null
-PASS new ServiceWorkerMessageEvent('eventType', { source: null }).source is null
-PASS new ServiceWorkerMessageEvent('eventType', { source: false }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: true }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: '' }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: 'chocolate' }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: 12345 }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: 18446744073709551615 }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: NaN }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { source: {valueOf: function () { return window; } } }).source == window threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { get source() { return channel.port1; } }).source is channel.port1
-PASS new ServiceWorkerMessageEvent('eventType', { get source() { return 123; } }).source threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The provided value is not of type '(ServiceWorker or MessagePort)'.
-PASS new ServiceWorkerMessageEvent('eventType', { get source() { throw 'ServiceWorkerMessageEvent Error'; } }) threw exception ServiceWorkerMessageEvent Error.
-PASS new ServiceWorkerMessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[0] is channel.port1
-PASS new ServiceWorkerMessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[1] is channel.port2
-PASS new ServiceWorkerMessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[2] is channel2.port1
-PASS new ServiceWorkerMessageEvent('eventType', { ports: [] }).ports is []
-PASS new ServiceWorkerMessageEvent('eventType', { ports: undefined }).ports is null
-PASS new ServiceWorkerMessageEvent('eventType', { ports: null }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { ports: [1, 2, 3] }).ports[2] threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': Invalid Array element type.
-PASS new ServiceWorkerMessageEvent('eventType', { ports: test_object }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { ports: document }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { ports: false }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { ports: true }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { ports: '' }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { ports: 'chocolate' }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { ports: 12345 }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { ports: 18446744073709551615 }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { ports: NaN }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { get ports() { return 123; } }).ports threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { get ports() { throw 'ServiceWorkerMessageEvent Error'; } }) threw exception ServiceWorkerMessageEvent Error.
-PASS new ServiceWorkerMessageEvent('eventType', { ports: {valueOf: function () { return [channel.port1, channel.port2, channel.port2]; } } }).ports[0] threw exception TypeError: Failed to construct 'ServiceWorkerMessageEvent': The value provided is neither an array, nor does it have indexed properties..
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).bubbles is true
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).cancelable is true
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).data is test_object
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).origin is "wonderful"
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).lastEventId is "excellent"
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).source is port
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).ports[0] is channel.port1
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).ports[1] is channel.port2
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).ports[2] is channel2.port1
-PASS new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: {length: 3, 0: channel.port1, 1: channel.port2, 2: channel2.port1} }).ports[2] is channel2.port1
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/events/constructors/serviceworker-message-event-constructor.html b/third_party/WebKit/LayoutTests/fast/events/constructors/serviceworker-message-event-constructor.html
deleted file mode 100644
index d1a207c..0000000
--- a/third_party/WebKit/LayoutTests/fast/events/constructors/serviceworker-message-event-constructor.html
+++ /dev/null
@@ -1,136 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../../resources/js-test.js"></script>
-</head>
-<body>
-<script>
-
-description("This tests the constructor for the ServiceWorkerMessageEvent DOM class.");
-
-var test_object = {nyannyan: 123};
-
-// No initializer is passed.
-shouldBe("new ServiceWorkerMessageEvent('eventType').bubbles", "false");
-shouldBe("new ServiceWorkerMessageEvent('eventType').cancelable", "false");
-shouldBe("new ServiceWorkerMessageEvent('eventType').data", "null");
-shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType').origin", "");
-shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType').lastEventId", "");
-shouldBe("new ServiceWorkerMessageEvent('eventType').source", "null");
-shouldBe("new ServiceWorkerMessageEvent('eventType').ports", "null");
-
-// bubbles is passed.
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: false }).bubbles", "false");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: true }).bubbles", "true");
-
-// cancelable is passed.
-shouldBe("new ServiceWorkerMessageEvent('eventType', { cancelable: false }).cancelable", "false");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { cancelable: true }).cancelable", "true");
-
-// data is passed.
-shouldBe("new ServiceWorkerMessageEvent('eventType', { data: test_object }).data", "test_object");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { data: document }).data", "document");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { data: undefined }).data", "null");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { data: null }).data", "null");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { data: false }).data", "false");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { data: true }).data", "true");
-shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { data: '' }).data", "");
-shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { data: 'chocolate' }).data", "chocolate");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { data: 12345 }).data", "12345");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { data: 18446744073709551615 }).data", "18446744073709552000");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { data: NaN }).data", "NaN");
-// Note that valueOf() is not called, when the left hand side is evaluated.
-shouldBeFalse("new ServiceWorkerMessageEvent('eventType', { data: {valueOf: function () { return test_object; } } }).data == test_object");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { get data() { return 123; } }).data", "123");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { get data() { throw 'ServiceWorkerMessageEvent Error'; } })");
-
-// origin or lastEventId is passed.
-["origin", "lastEventId"].forEach(function (attr) {
-    // Strings.
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": 'melancholy' })." + attr, "melancholy");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": '' })." + attr, "");
-
-    // Non-strings.
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": undefined })." + attr, "");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": null })." + attr, "null");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": false })." + attr, "false");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": true })." + attr, "true");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": 12345 })." + attr, "12345");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": 18446744073709551615 })." + attr, "18446744073709552000");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": NaN })." + attr, "NaN");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": [] })." + attr, "");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": [1, 2, 3] })." + attr, "1,2,3");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": {melancholy: 12345} })." + attr, "[object Object]");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { " + attr + ": {valueOf: function () { return 'melancholy'; } } })." + attr, "[object Object]");
-    shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { get " + attr + "() { return 123; } })." + attr, "123");
-    shouldThrow("new ServiceWorkerMessageEvent('eventType', { get " + attr + "() { throw 'ServiceWorkerMessageEvent Error'; } })");
-});
-
-// MessagePort objects.
-var channel = new MessageChannel();
-shouldBe("new ServiceWorkerMessageEvent('eventType', { ports: [channel.port1], source: channel.port1 }).source", "channel.port1");
-
-// Unacceptable source objects (not a ServiceWorker or a MessagePort).
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: window }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: this }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: test_object }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: document }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: document.body }).source");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { source: undefined }).source", "null");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { source: null }).source", "null");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: false }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: true }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: '' }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: 'chocolate' }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: 12345 }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: 18446744073709551615 }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: NaN }).source");
-// Note that valueOf() is not called, when the left hand side is evaluated.
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { source: {valueOf: function () { return window; } } }).source == window");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { get source() { return channel.port1; } }).source", "channel.port1");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { get source() { return 123; } }).source");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { get source() { throw 'ServiceWorkerMessageEvent Error'; } })");
-
-// ports is passed.
-// Valid message ports.
-var channel2 = new MessageChannel();
-shouldBe("new ServiceWorkerMessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[0]", "channel.port1");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[1]", "channel.port2");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[2]", "channel2.port1");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { ports: [] }).ports", "[]");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { ports: undefined }).ports", "null");
-
-// Invalid message ports.
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: null }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: [1, 2, 3] }).ports[2]");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: test_object }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: document }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: false }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: true }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: '' }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: 'chocolate' }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: 12345 }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: 18446744073709551615 }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: NaN }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { get ports() { return 123; } }).ports");
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { get ports() { throw 'ServiceWorkerMessageEvent Error'; } })");
-// Note that valueOf() is not called, when the left hand side is evaluated.
-shouldThrow("new ServiceWorkerMessageEvent('eventType', { ports: {valueOf: function () { return [channel.port1, channel.port2, channel.port2]; } } }).ports[0]");
-
-// All initializers are passed.
-
-var port = new MessageChannel().port1;
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).bubbles", "true");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).cancelable", "true");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).data", "test_object");
-shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).origin", "wonderful");
-shouldBeEqualToString("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).lastEventId", "excellent");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).source", "port");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).ports[0]", "channel.port1");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).ports[1]", "channel.port2");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: [channel.port1, channel.port2, channel2.port1] }).ports[2]", "channel2.port1");
-shouldBe("new ServiceWorkerMessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: port, ports: {length: 3, 0: channel.port1, 1: channel.port2, 2: channel2.port1} }).ports[2]", "channel2.port1");
-
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/postmessage-to-client.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/postmessage-to-client.html
index fadc7d2a..4862f47 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/postmessage-to-client.html
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/postmessage-to-client.html
@@ -25,16 +25,26 @@
         })
       .then(e => {
           var message = e.data;
-          assert_equals(e.origin, location.origin,
-            'origin of message should be origin of Service Worker');
+          assert_equals(e.constructor, w.MessageEvent,
+                        'message events should use MessageEvent interface.');
+          assert_equals(e.type, 'message', 'type should be "message".');
+          assert_equals(
+              e.origin, location.origin,
+              'origin of message should be origin of Service Worker.');
           assert_equals(e.lastEventId, '',
-            'lastEventId should be an empty string');
+                        'lastEventId should be an empty string.');
+          assert_equals(e.source.constructor, w.ServiceWorker,
+                        'source should use ServiceWorker interface.');
+          assert_equals(
+              e.source, w.navigator.serviceWorker.controller,
+              'source should be the service worker that sent the message.');
+          assert_equals(e.ports.length, 0, 'ports should be an empty array.');
           assert_equals(message, 'Sending message via clients');
           return new Promise(resolve => {
               w.navigator.serviceWorker.onmessage = resolve;
             });
         })
       .then(e => { assert_equals(e.data, 'quit'); });
-  }, 'postMessage from ServiceWorker to Client');
+  }, 'postMessage from ServiceWorker to Client.');
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/serviceworker-message-event.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/serviceworker-message-event.html
deleted file mode 100644
index 66e29612..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/serviceworker-message-event.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<title>Service Worker: ServiceWorkerMessageEvent</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="resources/test-helpers.js"></script>
-<script>
-
-promise_test(function(t) {
-    var scope = 'resources/blank.html';
-    var url = 'resources/postmessage-to-client-worker.js';
-    return service_worker_unregister_and_register(t, url, scope)
-      .then(function(r) {
-          return wait_for_state(t, r.installing, 'activated');
-        })
-      .then(function() {
-          return with_iframe(scope);
-        })
-      .then(function(frame) {
-          var w = frame.contentWindow;
-          var worker = w.navigator.serviceWorker.controller;
-          // Test constructor with ServiceWorker object as source.
-          var e = new ServiceWorkerMessageEvent('eventType', {source: worker});
-          assert_equals(e.source, worker,
-                        'Source should equal to the passing service worker');
-          return new Promise(function(resolve) {
-              w.navigator.serviceWorker.onmessage = t.step_func(function(e) {
-                  assert_true(e instanceof w.ServiceWorkerMessageEvent);
-                  assert_true(e.source instanceof w.ServiceWorker);
-                  assert_equals(e.type, 'message');
-                  assert_equals(e.source, worker,
-                                'Source worker should equal to the controller');
-                  assert_equals(e.ports.length, 0);
-                  resolve();
-              });
-              worker.postMessage('PING');
-          });
-        })
-      .then(function() {
-          return service_worker_unregister_and_done(t, scope);
-        });
-  }, 'Test ServiceWorkerMessageEvent type.');
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions-expected.txt
index 71a6b78..38a3512 100644
--- a/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions-expected.txt
@@ -10,7 +10,7 @@
 FAIL [[Delete]] Should throw on cross-origin objects assert_throws: Can't delete cross-origin indexed property function "function () { delete C[0]; }" did not throw
 FAIL [[DefineOwnProperty]] Should throw for cross-origin objects assert_throws: Can't define cross-origin value property length function "function () { Object.defineProperty(obj, prop, valueDesc); }" did not throw
 FAIL [[Enumerate]] should return an empty iterator assert_unreached: Shouldn't have been able to enumerate stop on cross-origin Window Reached unreachable code
-FAIL [[OwnPropertyKeys]] should return all properties from cross-origin objects assert_array_equals: Object.getOwnPropertyNames() gives the right answer for cross-origin Window lengths differ, expected 862 got 13
+FAIL [[OwnPropertyKeys]] should return all properties from cross-origin objects assert_array_equals: Object.getOwnPropertyNames() gives the right answer for cross-origin Window lengths differ, expected 861 got 13
 PASS A and B jointly observe the same identity for cross-origin Window and Location 
 PASS Cross-origin functions get local Function.prototype 
 FAIL Cross-origin Window accessors get local Function.prototype Cannot read property 'name' of undefined
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
index e562d96..eb181eee 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -5307,14 +5307,6 @@
     method register
     setter oncontrollerchange
     setter onmessage
-interface ServiceWorkerMessageEvent : Event
-    attribute @@toStringTag
-    getter data
-    getter lastEventId
-    getter origin
-    getter ports
-    getter source
-    method constructor
 interface ServiceWorkerRegistration : EventTarget
     attribute @@toStringTag
     getter active
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index ca9ee76..6d96be00 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -5365,14 +5365,6 @@
     method register
     setter oncontrollerchange
     setter onmessage
-interface ServiceWorkerMessageEvent : Event
-    attribute @@toStringTag
-    getter data
-    getter lastEventId
-    getter origin
-    getter ports
-    getter source
-    method constructor
 interface ServiceWorkerRegistration : EventTarget
     attribute @@toStringTag
     getter active
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 1a8febfa..3b31cdd 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -6258,14 +6258,6 @@
     method register
     setter oncontrollerchange
     setter onmessage
-interface ServiceWorkerMessageEvent : Event
-    attribute @@toStringTag
-    getter data
-    getter lastEventId
-    getter origin
-    getter ports
-    getter source
-    method constructor
 interface ServiceWorkerRegistration : EventTarget
     attribute @@toStringTag
     getter active
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8MessageEventCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8MessageEventCustom.cpp
index d7b32a1b..93d36fd 100644
--- a/third_party/WebKit/Source/bindings/core/v8/custom/V8MessageEventCustom.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8MessageEventCustom.cpp
@@ -110,7 +110,7 @@
   v8::Local<v8::Value> dataArg = info[3];
   TOSTRING_VOID(V8StringResource<>, originArg, info[4]);
   TOSTRING_VOID(V8StringResource<>, lastEventIdArg, info[5]);
-  DOMWindow* sourceArg = toDOMWindow(info.GetIsolate(), info[6]);
+  EventTarget* sourceArg = toEventTarget(info.GetIsolate(), info[6]);
   MessagePortArray* portArray = nullptr;
   const int portArrayIndex = 7;
   if (!isUndefinedOrNull(info[portArrayIndex])) {
diff --git a/third_party/WebKit/Source/bindings/modules/BUILD.gn b/third_party/WebKit/Source/bindings/modules/BUILD.gn
index 3b763d0..37c9fb3d 100644
--- a/third_party/WebKit/Source/bindings/modules/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/modules/BUILD.gn
@@ -45,7 +45,6 @@
     "//third_party/WebKit/Source/modules/serviceworkers/FetchEvent.idl",
     "//third_party/WebKit/Source/modules/serviceworkers/ForeignFetchEvent.idl",
     "//third_party/WebKit/Source/modules/serviceworkers/InstallEvent.idl",
-    "//third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerMessageEvent.idl",
     "//third_party/WebKit/Source/modules/speech/SpeechRecognitionError.idl",
     "//third_party/WebKit/Source/modules/speech/SpeechRecognitionEvent.idl",
     "//third_party/WebKit/Source/modules/speech/SpeechSynthesisEvent.idl",
diff --git a/third_party/WebKit/Source/bindings/modules/v8/custom/V8ServiceWorkerMessageEventCustom.cpp b/third_party/WebKit/Source/bindings/modules/v8/custom/V8ServiceWorkerMessageEventCustom.cpp
deleted file mode 100644
index 9b290966..0000000
--- a/third_party/WebKit/Source/bindings/modules/v8/custom/V8ServiceWorkerMessageEventCustom.cpp
+++ /dev/null
@@ -1,24 +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 "bindings/modules/v8/V8ServiceWorkerMessageEvent.h"
-
-#include "bindings/modules/v8/V8ServiceWorkerMessageEventInit.h"
-#include "bindings/modules/v8/V8ServiceWorkerMessageEventInternal.h"
-
-namespace blink {
-
-void V8ServiceWorkerMessageEvent::constructorCustom(
-    const v8::FunctionCallbackInfo<v8::Value>& info) {
-  V8ServiceWorkerMessageEventInternal::constructorCustom<
-      ServiceWorkerMessageEvent, ServiceWorkerMessageEventInit>(info);
-}
-
-void V8ServiceWorkerMessageEvent::dataAttributeGetterCustom(
-    const v8::FunctionCallbackInfo<v8::Value>& info) {
-  V8ServiceWorkerMessageEventInternal::dataAttributeGetterCustom<
-      ServiceWorkerMessageEvent>(info);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/modules/v8/custom/custom.gni b/third_party/WebKit/Source/bindings/modules/v8/custom/custom.gni
index 249329a8..d07743b 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/custom/custom.gni
+++ b/third_party/WebKit/Source/bindings/modules/v8/custom/custom.gni
@@ -10,7 +10,6 @@
                     "V8ExtendableMessageEventCustom.cpp",
                     "V8IDBObserverCustom.cpp",
                     "V8RemotePlaybackCustom.cpp",
-                    "V8ServiceWorkerMessageEventCustom.cpp",
                     "V8WebGLRenderingContextCustom.cpp",
                     "V8WebGL2RenderingContextCustom.cpp",
                   ],
diff --git a/third_party/WebKit/Source/bindings/modules/v8/generated.gni b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
index 0d8f27d..564be191 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/generated.gni
+++ b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
@@ -46,8 +46,6 @@
   "$bindings_modules_v8_output_dir/RenderingContext.h",
   "$bindings_modules_v8_output_dir/RequestOrUSVString.cpp",
   "$bindings_modules_v8_output_dir/RequestOrUSVString.h",
-  "$bindings_modules_v8_output_dir/ServiceWorkerOrMessagePort.cpp",
-  "$bindings_modules_v8_output_dir/ServiceWorkerOrMessagePort.h",
   "$bindings_modules_v8_output_dir/StringOrArrayBufferOrNFCMessage.cpp",
   "$bindings_modules_v8_output_dir/StringOrArrayBufferOrNFCMessage.h",
   "$bindings_modules_v8_output_dir/StringOrCanvasGradientOrCanvasPattern.cpp",
diff --git a/third_party/WebKit/Source/core/events/EventTarget.cpp b/third_party/WebKit/Source/core/events/EventTarget.cpp
index 3bfa7163..0814cb3 100644
--- a/third_party/WebKit/Source/core/events/EventTarget.cpp
+++ b/third_party/WebKit/Source/core/events/EventTarget.cpp
@@ -173,6 +173,10 @@
   return nullptr;
 }
 
+ServiceWorker* EventTarget::toServiceWorker() {
+  return nullptr;
+}
+
 inline LocalDOMWindow* EventTarget::executingWindow() {
   if (ExecutionContext* context = getExecutionContext())
     return context->executingWindow();
diff --git a/third_party/WebKit/Source/core/events/EventTarget.h b/third_party/WebKit/Source/core/events/EventTarget.h
index 75088002..6b77c11e 100644
--- a/third_party/WebKit/Source/core/events/EventTarget.h
+++ b/third_party/WebKit/Source/core/events/EventTarget.h
@@ -56,6 +56,7 @@
 class ExceptionState;
 class MessagePort;
 class Node;
+class ServiceWorker;
 
 struct FiringEventIterator {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
@@ -119,6 +120,7 @@
   virtual const LocalDOMWindow* toLocalDOMWindow() const;
   virtual LocalDOMWindow* toLocalDOMWindow();
   virtual MessagePort* toMessagePort();
+  virtual ServiceWorker* toServiceWorker();
 
   bool addEventListener(const AtomicString& eventType,
                         EventListener*,
diff --git a/third_party/WebKit/Source/core/events/MessageEvent.cpp b/third_party/WebKit/Source/core/events/MessageEvent.cpp
index 2be9e882..ed0b628 100644
--- a/third_party/WebKit/Source/core/events/MessageEvent.cpp
+++ b/third_party/WebKit/Source/core/events/MessageEvent.cpp
@@ -36,7 +36,8 @@
 namespace blink {
 
 static inline bool isValidSource(EventTarget* source) {
-  return !source || source->toLocalDOMWindow() || source->toMessagePort();
+  return !source || source->toLocalDOMWindow() || source->toMessagePort() ||
+         source->toServiceWorker();
 }
 
 MessageEvent::MessageEvent() : m_dataType(DataTypeScriptValue) {}
@@ -155,7 +156,7 @@
                                     ScriptValue data,
                                     const String& origin,
                                     const String& lastEventId,
-                                    DOMWindow* source,
+                                    EventTarget* source,
                                     MessagePortArray* ports) {
   if (isBeingDispatched())
     return;
@@ -177,7 +178,7 @@
                                     PassRefPtr<SerializedScriptValue> data,
                                     const String& origin,
                                     const String& lastEventId,
-                                    DOMWindow* source,
+                                    EventTarget* source,
                                     MessagePortArray* ports) {
   if (isBeingDispatched())
     return;
diff --git a/third_party/WebKit/Source/core/events/MessageEvent.h b/third_party/WebKit/Source/core/events/MessageEvent.h
index b7fb883..de9700cad 100644
--- a/third_party/WebKit/Source/core/events/MessageEvent.h
+++ b/third_party/WebKit/Source/core/events/MessageEvent.h
@@ -37,7 +37,6 @@
 #include "core/events/EventTarget.h"
 #include "core/events/MessageEventInit.h"
 #include "core/fileapi/Blob.h"
-#include "core/frame/DOMWindow.h"
 #include "wtf/Compiler.h"
 #include <memory>
 
@@ -99,7 +98,7 @@
                         ScriptValue data,
                         const String& origin,
                         const String& lastEventId,
-                        DOMWindow* source,
+                        EventTarget* source,
                         MessagePortArray*);
   void initMessageEvent(const AtomicString& type,
                         bool canBubble,
@@ -107,7 +106,7 @@
                         PassRefPtr<SerializedScriptValue> data,
                         const String& origin,
                         const String& lastEventId,
-                        DOMWindow* source,
+                        EventTarget* source,
                         MessagePortArray*);
 
   const String& origin() const { return m_origin; }
diff --git a/third_party/WebKit/Source/core/events/MessageEvent.idl b/third_party/WebKit/Source/core/events/MessageEvent.idl
index 5c3a7e34..61dc799 100644
--- a/third_party/WebKit/Source/core/events/MessageEvent.idl
+++ b/third_party/WebKit/Source/core/events/MessageEvent.idl
@@ -49,6 +49,6 @@
                                    [Default=Undefined] optional any dataArg,
                                    [Default=Undefined] optional DOMString originArg,
                                    [Default=Undefined] optional DOMString lastEventIdArg,
-                                   [Default=Undefined] optional Window sourceArg,
+                                   [Default=Undefined] optional EventTarget sourceArg,
                                    [Default=Undefined] optional sequence<MessagePort> portsArg);
 };
diff --git a/third_party/WebKit/Source/core/frame/History.idl b/third_party/WebKit/Source/core/frame/History.idl
index fef8e1f..6add189 100644
--- a/third_party/WebKit/Source/core/frame/History.idl
+++ b/third_party/WebKit/Source/core/frame/History.idl
@@ -35,8 +35,6 @@
     [CallWith=ExecutionContext] void go(optional long delta = 0);
     [CallWith=ExecutionContext] void back();
     [CallWith=ExecutionContext] void forward();
-    // TODO(foolip): The SerializedScriptValue types should be any.
-    // TODO(foolip): The title arguments should not be nullable.
-    [RaisesException] void pushState(SerializedScriptValue data, DOMString? title, optional DOMString? url = null);
-    [RaisesException] void replaceState(SerializedScriptValue data, DOMString? title, optional DOMString? url = null);
+    [RaisesException] void pushState(SerializedScriptValue data, DOMString title, optional DOMString? url = null);
+    [RaisesException] void replaceState(SerializedScriptValue data, DOMString title, optional DOMString? url = null);
 };
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapOptions.idl b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapOptions.idl
index d34204e7..4073e6a 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapOptions.idl
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapOptions.idl
@@ -12,7 +12,7 @@
     ImageOrientation imageOrientation = "none";
     PremultiplyAlpha premultiplyAlpha = "default";
     CanvasColorSpace colorSpaceConversion = "default";
-    [RuntimeEnabled=ExperimentalCanvasFeatures, EnforceRange] unsigned long? resizeWidth;
-    [RuntimeEnabled=ExperimentalCanvasFeatures, EnforceRange] unsigned long? resizeHeight;
+    [RuntimeEnabled=ExperimentalCanvasFeatures, EnforceRange] unsigned long resizeWidth;
+    [RuntimeEnabled=ExperimentalCanvasFeatures, EnforceRange] unsigned long resizeHeight;
     [RuntimeEnabled=ExperimentalCanvasFeatures] ResizeQuality resizeQuality = "low";
 };
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.cpp
index fb1904068..3b5b2fe 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.cpp
@@ -23,23 +23,17 @@
 #include "core/layout/svg/LayoutSVGViewportContainer.h"
 
 #include "core/layout/svg/SVGLayoutSupport.h"
-#include "core/paint/SVGContainerPainter.h"
 #include "core/svg/SVGSVGElement.h"
-#include "core/svg/SVGUseElement.h"
-#include "platform/graphics/GraphicsContext.h"
 
 namespace blink {
 
-LayoutSVGViewportContainer::LayoutSVGViewportContainer(SVGElement* node)
+LayoutSVGViewportContainer::LayoutSVGViewportContainer(SVGSVGElement* node)
     : LayoutSVGContainer(node),
       m_isLayoutSizeChanged(false),
       m_needsTransformUpdate(true) {}
 
 void LayoutSVGViewportContainer::determineIfLayoutSizeChanged() {
-  ASSERT(element());
-  if (!isSVGSVGElement(*element()))
-    return;
-
+  DCHECK(isSVGSVGElement(element()));
   m_isLayoutSizeChanged =
       toSVGSVGElement(element())->hasRelativeLengths() && selfNeedsLayout();
 }
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h
index 389b9b37..713cffd 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h
@@ -27,11 +27,13 @@
 
 namespace blink {
 
+class SVGSVGElement;
+
 // This is used for non-root <svg> elements which are SVGTransformable thus we
 // inherit from LayoutSVGContainer instead of LayoutSVGTransformableContainer.
 class LayoutSVGViewportContainer final : public LayoutSVGContainer {
  public:
-  explicit LayoutSVGViewportContainer(SVGElement*);
+  explicit LayoutSVGViewportContainer(SVGSVGElement*);
   FloatRect viewport() const { return m_viewport; }
 
   bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; }
diff --git a/third_party/WebKit/Source/modules/compositorworker/WindowAnimationWorklet.cpp b/third_party/WebKit/Source/modules/compositorworker/WindowAnimationWorklet.cpp
index 3512051b..15a48034 100644
--- a/third_party/WebKit/Source/modules/compositorworker/WindowAnimationWorklet.cpp
+++ b/third_party/WebKit/Source/modules/compositorworker/WindowAnimationWorklet.cpp
@@ -4,6 +4,7 @@
 
 #include "modules/compositorworker/WindowAnimationWorklet.h"
 
+#include "core/dom/Document.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
 #include "modules/compositorworker/AnimationWorklet.h"
@@ -11,7 +12,7 @@
 namespace blink {
 
 WindowAnimationWorklet::WindowAnimationWorklet(LocalDOMWindow& window)
-    : DOMWindowProperty(window.frame()) {}
+    : ContextLifecycleObserver(window.frame()->document()) {}
 
 const char* WindowAnimationWorklet::supplementName() {
   return "WindowAnimationWorklet";
@@ -30,24 +31,36 @@
 
 // static
 Worklet* WindowAnimationWorklet::animationWorklet(DOMWindow& window) {
-  return from(toLocalDOMWindow(window)).animationWorklet();
+  return from(toLocalDOMWindow(window))
+      .animationWorklet(toLocalDOMWindow(window));
 }
 
-AnimationWorklet* WindowAnimationWorklet::animationWorklet() {
-  if (!m_animationWorklet && frame())
-    m_animationWorklet = AnimationWorklet::create(frame());
+AnimationWorklet* WindowAnimationWorklet::animationWorklet(
+    LocalDOMWindow& window) {
+  if (!m_animationWorklet && getExecutionContext()) {
+    DCHECK(window.frame());
+    m_animationWorklet = AnimationWorklet::create(window.frame());
+  }
   return m_animationWorklet.get();
 }
 
-void WindowAnimationWorklet::frameDestroyed() {
-  m_animationWorklet.clear();
-  DOMWindowProperty::frameDestroyed();
+// Break the following cycle when the context gets detached.
+// Otherwise, the worklet object will leak.
+//
+// window => window.animationWorklet
+// => WindowAnimationWorklet
+// => AnimationWorklet  <--- break this reference
+// => ThreadedWorkletMessagingProxy
+// => Document
+// => ... => window
+void WindowAnimationWorklet::contextDestroyed() {
+  m_animationWorklet = nullptr;
 }
 
 DEFINE_TRACE(WindowAnimationWorklet) {
   visitor->trace(m_animationWorklet);
   Supplement<LocalDOMWindow>::trace(visitor);
-  DOMWindowProperty::trace(visitor);
+  ContextLifecycleObserver::trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/compositorworker/WindowAnimationWorklet.h b/third_party/WebKit/Source/modules/compositorworker/WindowAnimationWorklet.h
index 9e3349f..3635ec3 100644
--- a/third_party/WebKit/Source/modules/compositorworker/WindowAnimationWorklet.h
+++ b/third_party/WebKit/Source/modules/compositorworker/WindowAnimationWorklet.h
@@ -5,7 +5,7 @@
 #ifndef WindowAnimationWorklet_h
 #define WindowAnimationWorklet_h
 
-#include "core/frame/DOMWindowProperty.h"
+#include "core/dom/ContextLifecycleObserver.h"
 #include "modules/ModulesExport.h"
 #include "platform/Supplementable.h"
 #include "platform/heap/Handle.h"
@@ -20,15 +20,15 @@
 class MODULES_EXPORT WindowAnimationWorklet final
     : public GarbageCollected<WindowAnimationWorklet>,
       public Supplement<LocalDOMWindow>,
-      public DOMWindowProperty {
+      public ContextLifecycleObserver {
   USING_GARBAGE_COLLECTED_MIXIN(WindowAnimationWorklet);
 
  public:
   static WindowAnimationWorklet& from(LocalDOMWindow&);
   static Worklet* animationWorklet(DOMWindow&);
-  AnimationWorklet* animationWorklet();
+  AnimationWorklet* animationWorklet(LocalDOMWindow&);
 
-  void frameDestroyed() override;
+  void contextDestroyed() override;
 
   DECLARE_TRACE();
 
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index bae6525..cbc4dc9 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -242,7 +242,6 @@
                     "serviceworkers/ServiceWorker.idl",
                     "serviceworkers/ServiceWorkerContainer.idl",
                     "serviceworkers/ServiceWorkerGlobalScope.idl",
-                    "serviceworkers/ServiceWorkerMessageEvent.idl",
                     "serviceworkers/ServiceWorkerRegistration.idl",
                     "serviceworkers/WindowClient.idl",
                     "shapedetection/BarcodeDetector.idl",
@@ -493,7 +492,6 @@
                     "serviceworkers/ForeignFetchResponse.idl",
                     "serviceworkers/NavigationPreloadState.idl",
                     "serviceworkers/RegistrationOptions.idl",
-                    "serviceworkers/ServiceWorkerMessageEventInit.idl",
                     "shapedetection/FaceDetectorOptions.idl",
                     "speech/SpeechRecognitionErrorInit.idl",
                     "speech/SpeechRecognitionEventInit.idl",
@@ -870,8 +868,6 @@
   "$blink_modules_output_dir/serviceworkers/NavigationPreloadState.h",
   "$blink_modules_output_dir/serviceworkers/RegistrationOptions.cpp",
   "$blink_modules_output_dir/serviceworkers/RegistrationOptions.h",
-  "$blink_modules_output_dir/serviceworkers/ServiceWorkerMessageEventInit.cpp",
-  "$blink_modules_output_dir/serviceworkers/ServiceWorkerMessageEventInit.h",
   "$blink_modules_output_dir/shapedetection/FaceDetectorOptions.cpp",
   "$blink_modules_output_dir/shapedetection/FaceDetectorOptions.h",
   "$blink_modules_output_dir/speech/SpeechRecognitionErrorInit.cpp",
diff --git a/third_party/WebKit/Source/modules/serviceworkers/BUILD.gn b/third_party/WebKit/Source/modules/serviceworkers/BUILD.gn
index 550563d..b08ba25 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/BUILD.gn
+++ b/third_party/WebKit/Source/modules/serviceworkers/BUILD.gn
@@ -44,8 +44,6 @@
     "ServiceWorkerGlobalScopeClient.h",
     "ServiceWorkerLinkResource.cpp",
     "ServiceWorkerLinkResource.h",
-    "ServiceWorkerMessageEvent.cpp",
-    "ServiceWorkerMessageEvent.h",
     "ServiceWorkerRegistration.cpp",
     "ServiceWorkerRegistration.h",
     "ServiceWorkerScriptCachedMetadataHandler.cpp",
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorker.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorker.h
index 5f06610b..12d4e69 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorker.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorker.h
@@ -69,6 +69,8 @@
   String state() const;
   DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange);
 
+  ServiceWorker* toServiceWorker() override { return this; }
+
   // ScriptWrappable overrides.
   bool hasPendingActivity() const final;
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
index 711d7d7..1132fd5 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
@@ -41,6 +41,7 @@
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/MessagePort.h"
+#include "core/events/MessageEvent.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/UseCounter.h"
 #include "core/frame/csp/ContentSecurityPolicy.h"
@@ -49,7 +50,6 @@
 #include "modules/serviceworkers/ServiceWorker.h"
 #include "modules/serviceworkers/ServiceWorkerContainerClient.h"
 #include "modules/serviceworkers/ServiceWorkerError.h"
-#include "modules/serviceworkers/ServiceWorkerMessageEvent.h"
 #include "modules/serviceworkers/ServiceWorkerRegistration.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/weborigin/SchemeRegistry.h"
@@ -454,9 +454,9 @@
   RefPtr<SerializedScriptValue> value = SerializedScriptValue::create(message);
   ServiceWorker* source = ServiceWorker::from(
       getExecutionContext(), WTF::wrapUnique(handle.release()));
-  dispatchEvent(ServiceWorkerMessageEvent::create(
-      ports, value, source,
-      getExecutionContext()->getSecurityOrigin()->toString()));
+  dispatchEvent(MessageEvent::create(
+      ports, value, getExecutionContext()->getSecurityOrigin()->toString(),
+      String() /* lastEventId */, source, String() /* suborigin */));
 }
 
 const AtomicString& ServiceWorkerContainer::interfaceName() const {
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerMessageEvent.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerMessageEvent.cpp
deleted file mode 100644
index 11972c6..0000000
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerMessageEvent.cpp
+++ /dev/null
@@ -1,83 +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 "modules/serviceworkers/ServiceWorkerMessageEvent.h"
-
-namespace blink {
-
-ServiceWorkerMessageEvent::ServiceWorkerMessageEvent(
-    const AtomicString& type,
-    const ServiceWorkerMessageEventInit& initializer)
-    : Event(type, initializer) {
-  if (initializer.hasOrigin())
-    m_origin = initializer.origin();
-  if (initializer.hasLastEventId())
-    m_lastEventId = initializer.lastEventId();
-  if (initializer.hasSource()) {
-    if (initializer.source().isServiceWorker())
-      m_sourceAsServiceWorker = initializer.source().getAsServiceWorker();
-    else if (initializer.source().isMessagePort())
-      m_sourceAsMessagePort = initializer.source().getAsMessagePort();
-  }
-  if (initializer.hasPorts())
-    m_ports = new MessagePortArray(initializer.ports());
-}
-
-ServiceWorkerMessageEvent::ServiceWorkerMessageEvent(
-    PassRefPtr<SerializedScriptValue> data,
-    const String& origin,
-    const String& lastEventId,
-    ServiceWorker* source,
-    MessagePortArray* ports)
-    : Event(EventTypeNames::message, false, false),
-      m_serializedData(data),
-      m_origin(origin),
-      m_lastEventId(lastEventId),
-      m_sourceAsServiceWorker(source),
-      m_ports(ports) {
-  if (m_serializedData)
-    m_serializedData->registerMemoryAllocatedWithCurrentScriptContext();
-}
-
-ServiceWorkerMessageEvent::~ServiceWorkerMessageEvent() {}
-
-MessagePortArray ServiceWorkerMessageEvent::ports(bool& isNull) const {
-  // TODO(bashi): Currently we return a copied array because the binding
-  // layer could modify the content of the array while executing JS callbacks.
-  // Avoid copying once we can make sure that the binding layer won't
-  // modify the content.
-  if (m_ports) {
-    isNull = false;
-    return *m_ports;
-  }
-  isNull = true;
-  return MessagePortArray();
-}
-
-MessagePortArray ServiceWorkerMessageEvent::ports() const {
-  bool unused;
-  return ports(unused);
-}
-
-void ServiceWorkerMessageEvent::source(
-    ServiceWorkerOrMessagePort& result) const {
-  if (m_sourceAsServiceWorker)
-    result =
-        ServiceWorkerOrMessagePort::fromServiceWorker(m_sourceAsServiceWorker);
-  else if (m_sourceAsMessagePort)
-    result = ServiceWorkerOrMessagePort::fromMessagePort(m_sourceAsMessagePort);
-}
-
-const AtomicString& ServiceWorkerMessageEvent::interfaceName() const {
-  return EventNames::ServiceWorkerMessageEvent;
-}
-
-DEFINE_TRACE(ServiceWorkerMessageEvent) {
-  visitor->trace(m_sourceAsServiceWorker);
-  visitor->trace(m_sourceAsMessagePort);
-  visitor->trace(m_ports);
-  Event::trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerMessageEvent.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerMessageEvent.h
deleted file mode 100644
index 4829e13..0000000
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerMessageEvent.h
+++ /dev/null
@@ -1,72 +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 ServiceWorkerMessageEvent_h
-#define ServiceWorkerMessageEvent_h
-
-#include "core/dom/DOMArrayBuffer.h"
-#include "core/dom/MessagePort.h"
-#include "modules/EventModules.h"
-#include "modules/ModulesExport.h"
-#include "modules/serviceworkers/ServiceWorkerMessageEventInit.h"
-
-namespace blink {
-
-class MODULES_EXPORT ServiceWorkerMessageEvent final : public Event {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static ServiceWorkerMessageEvent* create(
-      const AtomicString& type,
-      const ServiceWorkerMessageEventInit& initializer) {
-    return new ServiceWorkerMessageEvent(type, initializer);
-  }
-
-  static ServiceWorkerMessageEvent* create(
-      MessagePortArray* ports,
-      PassRefPtr<SerializedScriptValue> data,
-      ServiceWorker* source,
-      const String& origin) {
-    return new ServiceWorkerMessageEvent(std::move(data), origin, String(),
-                                         source, ports);
-  }
-
-  ~ServiceWorkerMessageEvent() override;
-
-  SerializedScriptValue* serializedData() const {
-    return m_serializedData.get();
-  }
-  void setSerializedData(PassRefPtr<SerializedScriptValue> serializedData) {
-    m_serializedData = serializedData;
-  }
-  const String& origin() const { return m_origin; }
-  const String& lastEventId() const { return m_lastEventId; }
-  MessagePortArray ports(bool& isNull) const;
-  MessagePortArray ports() const;
-  void source(ServiceWorkerOrMessagePort& result) const;
-
-  const AtomicString& interfaceName() const override;
-
-  DECLARE_VIRTUAL_TRACE();
-
- private:
-  ServiceWorkerMessageEvent(const AtomicString& type,
-                            const ServiceWorkerMessageEventInit& initializer);
-  ServiceWorkerMessageEvent(PassRefPtr<SerializedScriptValue> data,
-                            const String& origin,
-                            const String& lastEventId,
-                            ServiceWorker* source,
-                            MessagePortArray* ports);
-
-  RefPtr<SerializedScriptValue> m_serializedData;
-  String m_origin;
-  String m_lastEventId;
-  Member<ServiceWorker> m_sourceAsServiceWorker;
-  Member<MessagePort> m_sourceAsMessagePort;
-  Member<MessagePortArray> m_ports;
-};
-
-}  // namespace blink
-
-#endif  // ServiceWorkerMessageEvent_h
diff --git a/tools/boilerplate.py b/tools/boilerplate.py
index 74a2a4d..b26493e 100755
--- a/tools/boilerplate.py
+++ b/tools/boilerplate.py
@@ -51,15 +51,22 @@
   ])
 
 
-def _CppImplementation(filename):
+def _RemoveTestSuffix(filename):
   base, _ = os.path.splitext(filename)
-  include = '#include "' + base + '.h"'
+  suffixes = [ '_test', '_unittest', '_browsertest' ]
+  for suffix in suffixes:
+    l = len(suffix)
+    if base[-l:] == suffix:
+      return base[:-l]
+  return base
+
+def _CppImplementation(filename):
+  include = '#include "' + _RemoveTestSuffix(filename) + '.h"'
   return '\n'.join(['', include])
 
 
 def _ObjCppImplementation(filename):
-  base, _ = os.path.splitext(filename)
-  include = '#import "' + base + '.h"'
+  include = '#import "' + _RemoveTestSuffix(filename) + '.h"'
   return '\n'.join(['', include])
 
 
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 543fa7e..4fa4726 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -77003,6 +77003,7 @@
   <int value="157" label="AOAH_NONSENSE_DEVICE_ID"/>
   <int value="158" label="BDH_INVALID_OPTIONS"/>
   <int value="159" label="RFH_DID_ADD_CONSOLE_MESSAGE_BAD_SEVERITY"/>
+  <int value="160" label="AIRH_VOLUME_OUT_OF_RANGE"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions" type="int">
@@ -99311,6 +99312,9 @@
   <int value="5" label="User is blacklisted for the specific host."/>
   <int value="6" label="The network quality estimate is not available."/>
   <int value="7" label="The network is not slow enough to show previews."/>
+  <int value="8"
+      label="The page was being reloaded and the preview type can not be
+             shown on a reload."/>
 </enum>
 
 <enum name="PreviewsInfoBarAction" type="int">
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 2209a27..ac8b0eb 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -45,6 +45,8 @@
     live_region_changed,       // Web
     load_complete,             // Web
     location_changed,          // Web
+    media_started_playing,     // Automation
+    media_stopped_playing,     // Automation
     menu_end,                  // Native / Win
     menu_list_item_selected,   // Web
     menu_list_value_changed,   // Web
diff --git a/ui/events/blink/BUILD.gn b/ui/events/blink/BUILD.gn
index 588f1f4..dcae5dc5 100644
--- a/ui/events/blink/BUILD.gn
+++ b/ui/events/blink/BUILD.gn
@@ -37,6 +37,7 @@
     "//ui/events:dom_keycode_converter",
     "//ui/events:events_base",
     "//ui/events:gesture_detection",
+    "//ui/gfx",
     "//ui/gfx/geometry",
   ]
 
diff --git a/ui/events/blink/DEPS b/ui/events/blink/DEPS
index 198f59ef..a04f3df8 100644
--- a/ui/events/blink/DEPS
+++ b/ui/events/blink/DEPS
@@ -14,6 +14,7 @@
   "+third_party/WebKit/public/web/WebActiveWheelFlingParameters.h",
 
   "+ui/display/win",
+  "+ui/gfx",
   "+ui/gfx/geometry",
   "+ui/events"
 ]
diff --git a/ui/events/blink/blink_event_util.cc b/ui/events/blink/blink_event_util.cc
index 5148bf1..939a1c4 100644
--- a/ui/events/blink/blink_event_util.cc
+++ b/ui/events/blink/blink_event_util.cc
@@ -16,7 +16,6 @@
 
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "third_party/WebKit/public/platform/WebGestureEvent.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/event_constants.h"
@@ -26,6 +25,7 @@
 #include "ui/events/keycodes/dom/keycode_converter.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/transform.h"
 
 using blink::WebGestureEvent;
 using blink::WebInputEvent;
@@ -381,6 +381,24 @@
   }
 }
 
+// Returns the transform matrix corresponding to the gesture event.
+gfx::Transform GetTransformForEvent(const WebGestureEvent& gesture_event) {
+  gfx::Transform gesture_transform;
+  if (gesture_event.type == WebInputEvent::GestureScrollUpdate) {
+    gesture_transform.Translate(gesture_event.data.scrollUpdate.deltaX,
+                                gesture_event.data.scrollUpdate.deltaY);
+  } else if (gesture_event.type == WebInputEvent::GesturePinchUpdate) {
+    float scale = gesture_event.data.pinchUpdate.scale;
+    gesture_transform.Translate(-gesture_event.x, -gesture_event.y);
+    gesture_transform.Scale(scale, scale);
+    gesture_transform.Translate(gesture_event.x, gesture_event.y);
+  } else {
+    NOTREACHED() << "Invalid event type for transform retrieval: "
+                 << WebInputEvent::GetName(gesture_event.type);
+  }
+  return gesture_transform;
+}
+
 }  // namespace
 
 bool CanCoalesce(const blink::WebInputEvent& event_to_coalesce,
@@ -439,6 +457,73 @@
   }
 }
 
+// Whether |event_in_queue| is GesturePinchUpdate or GestureScrollUpdate and
+// has the same modifiers/source as the new scroll/pinch event. Compatible
+// scroll and pinch event pairs can be logically coalesced.
+bool IsCompatibleScrollorPinch(const WebGestureEvent& new_event,
+                               const WebGestureEvent& event_in_queue) {
+  DCHECK(new_event.type == WebInputEvent::GestureScrollUpdate ||
+         new_event.type == WebInputEvent::GesturePinchUpdate)
+      << "Invalid event type for pinch/scroll coalescing: "
+      << WebInputEvent::GetName(new_event.type);
+  DLOG_IF(WARNING, new_event.timeStampSeconds < event_in_queue.timeStampSeconds)
+      << "Event time not monotonic?\n";
+  return (event_in_queue.type == WebInputEvent::GestureScrollUpdate ||
+          event_in_queue.type == WebInputEvent::GesturePinchUpdate) &&
+         event_in_queue.modifiers == new_event.modifiers &&
+         event_in_queue.sourceDevice == new_event.sourceDevice;
+}
+
+std::pair<WebGestureEvent, WebGestureEvent> CoalesceScrollAndPinch(
+    const WebGestureEvent* second_last_event,
+    const WebGestureEvent& last_event,
+    const WebGestureEvent& new_event) {
+  DCHECK(!CanCoalesce(new_event, last_event))
+      << "New event can be coalesced with the last event in queue directly.";
+  DCHECK(IsContinuousGestureEvent(new_event.type));
+  DCHECK(IsCompatibleScrollorPinch(new_event, last_event));
+  DCHECK(!second_last_event ||
+         IsCompatibleScrollorPinch(new_event, *second_last_event));
+
+  WebGestureEvent scroll_event;
+  WebGestureEvent pinch_event;
+  scroll_event.modifiers |= new_event.modifiers;
+  scroll_event.sourceDevice = new_event.sourceDevice;
+  scroll_event.timeStampSeconds = new_event.timeStampSeconds;
+  pinch_event = scroll_event;
+  scroll_event.type = WebInputEvent::GestureScrollUpdate;
+  pinch_event.type = WebInputEvent::GesturePinchUpdate;
+  pinch_event.x = new_event.type == WebInputEvent::GesturePinchUpdate
+                      ? new_event.x
+                      : last_event.x;
+  pinch_event.y = new_event.type == WebInputEvent::GesturePinchUpdate
+                      ? new_event.y
+                      : last_event.y;
+
+  gfx::Transform combined_scroll_pinch = GetTransformForEvent(last_event);
+  if (second_last_event) {
+    combined_scroll_pinch.PreconcatTransform(
+        GetTransformForEvent(*second_last_event));
+  }
+  combined_scroll_pinch.ConcatTransform(GetTransformForEvent(new_event));
+
+  float combined_scale =
+      SkMScalarToFloat(combined_scroll_pinch.matrix().get(0, 0));
+  float combined_scroll_pinch_x =
+      SkMScalarToFloat(combined_scroll_pinch.matrix().get(0, 3));
+  float combined_scroll_pinch_y =
+      SkMScalarToFloat(combined_scroll_pinch.matrix().get(1, 3));
+  scroll_event.data.scrollUpdate.deltaX =
+      (combined_scroll_pinch_x + pinch_event.x) / combined_scale -
+      pinch_event.x;
+  scroll_event.data.scrollUpdate.deltaY =
+      (combined_scroll_pinch_y + pinch_event.y) / combined_scale -
+      pinch_event.y;
+  pinch_event.data.pinchUpdate.scale = combined_scale;
+
+  return std::make_pair(scroll_event, pinch_event);
+}
+
 blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
     const MotionEvent& event,
     bool moved_beyond_slop_region) {
diff --git a/ui/events/blink/blink_event_util.h b/ui/events/blink/blink_event_util.h
index 5636d58..8eae9b03e 100644
--- a/ui/events/blink/blink_event_util.h
+++ b/ui/events/blink/blink_event_util.h
@@ -7,12 +7,11 @@
 
 #include <memory>
 
+#include "third_party/WebKit/public/platform/WebGestureEvent.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "ui/events/gesture_detection/motion_event.h"
 
 namespace blink {
-class WebGestureEvent;
-class WebInputEvent;
 class WebTouchEvent;
 }
 
@@ -33,6 +32,16 @@
 void Coalesce(const blink::WebInputEvent& event_to_coalesce,
               blink::WebInputEvent* event);
 
+bool IsCompatibleScrollorPinch(const blink::WebGestureEvent& new_event,
+                               const blink::WebGestureEvent& event_in_queue);
+
+// Coalesces 3 GestureScroll/PinchUpdate into 2 events.
+// Returns <GestureScrollUpdate, GesturePinchUpdate>.
+std::pair<blink::WebGestureEvent, blink::WebGestureEvent>
+CoalesceScrollAndPinch(const blink::WebGestureEvent* second_last_event,
+                       const blink::WebGestureEvent& last_event,
+                       const blink::WebGestureEvent& new_event);
+
 blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
     const MotionEvent& event,
     bool may_cause_scrolling);
@@ -84,6 +93,12 @@
 
 bool IsContinuousGestureEvent(blink::WebInputEvent::Type);
 
+inline const blink::WebGestureEvent& ToWebGestureEvent(
+    const blink::WebInputEvent& event) {
+  DCHECK(IsGestureScollOrPinch(event.type));
+  return static_cast<const blink::WebGestureEvent&>(event);
+}
+
 }  // namespace ui
 
 #endif  // UI_EVENTS_BLINK_BLINK_EVENT_UTIL_H_
diff --git a/ui/events/blink/compositor_thread_event_queue.cc b/ui/events/blink/compositor_thread_event_queue.cc
index 9eec24e..47e906f 100644
--- a/ui/events/blink/compositor_thread_event_queue.cc
+++ b/ui/events/blink/compositor_thread_event_queue.cc
@@ -4,22 +4,82 @@
 
 #include "ui/events/blink/compositor_thread_event_queue.h"
 
+#include "base/memory/ptr_util.h"
+#include "ui/events/blink/blink_event_util.h"
+#include "ui/events/blink/web_input_event_traits.h"
+
 namespace ui {
 
 CompositorThreadEventQueue::CompositorThreadEventQueue() {}
 
 CompositorThreadEventQueue::~CompositorThreadEventQueue() {}
 
-// TODO(chongz): Support coalescing events across interleaved boundaries.
-// https://crbug.com/661601
-void CompositorThreadEventQueue::Queue(std::unique_ptr<EventWithCallback> event,
-                                       base::TimeTicks timestamp_now) {
-  if (!queue_.empty() && queue_.back()->CanCoalesceWith(*event)) {
-    queue_.back()->CoalesceWith(event.get(), timestamp_now);
+void CompositorThreadEventQueue::Queue(
+    std::unique_ptr<EventWithCallback> new_event,
+    base::TimeTicks timestamp_now) {
+  if (queue_.empty() || !IsContinuousGestureEvent(new_event->event().type) ||
+      !IsCompatibleScrollorPinch(ToWebGestureEvent(new_event->event()),
+                                 ToWebGestureEvent(queue_.back()->event()))) {
+    queue_.emplace_back(std::move(new_event));
     return;
   }
 
-  queue_.emplace_back(std::move(event));
+  if (queue_.back()->CanCoalesceWith(*new_event)) {
+    queue_.back()->CoalesceWith(new_event.get(), timestamp_now);
+    return;
+  }
+
+  // Extract the last event in queue.
+  std::unique_ptr<EventWithCallback> last_event = std::move(queue_.back());
+  queue_.pop_back();
+  DCHECK_LE(last_event->latency_info().trace_id(),
+            new_event->latency_info().trace_id());
+  LatencyInfo oldest_latency = last_event->latency_info();
+  oldest_latency.set_coalesced();
+  base::TimeTicks oldest_creation_timestamp = last_event->creation_timestamp();
+  auto combined_original_events =
+      base::MakeUnique<EventWithCallback::OriginalEventList>();
+  combined_original_events->splice(combined_original_events->end(),
+                                   last_event->original_events());
+  combined_original_events->splice(combined_original_events->end(),
+                                   new_event->original_events());
+
+  // Extract the second last event in queue.
+  std::unique_ptr<EventWithCallback> second_last_event = nullptr;
+  if (!queue_.empty() &&
+      IsCompatibleScrollorPinch(ToWebGestureEvent(new_event->event()),
+                                ToWebGestureEvent(queue_.back()->event()))) {
+    second_last_event = std::move(queue_.back());
+    queue_.pop_back();
+    DCHECK_LE(second_last_event->latency_info().trace_id(),
+              oldest_latency.trace_id());
+    oldest_latency = second_last_event->latency_info();
+    oldest_latency.set_coalesced();
+    oldest_creation_timestamp = second_last_event->creation_timestamp();
+    combined_original_events->splice(combined_original_events->begin(),
+                                     second_last_event->original_events());
+  }
+
+  std::pair<blink::WebGestureEvent, blink::WebGestureEvent> coalesced_events =
+      CoalesceScrollAndPinch(
+          second_last_event ? &ToWebGestureEvent(second_last_event->event())
+                            : nullptr,
+          ToWebGestureEvent(last_event->event()),
+          ToWebGestureEvent(new_event->event()));
+
+  std::unique_ptr<EventWithCallback> scroll_event =
+      base::MakeUnique<EventWithCallback>(
+          WebInputEventTraits::Clone(coalesced_events.first), oldest_latency,
+          oldest_creation_timestamp, timestamp_now, nullptr);
+
+  std::unique_ptr<EventWithCallback> pinch_event =
+      base::MakeUnique<EventWithCallback>(
+          WebInputEventTraits::Clone(coalesced_events.second), oldest_latency,
+          oldest_creation_timestamp, timestamp_now,
+          std::move(combined_original_events));
+
+  queue_.emplace_back(std::move(scroll_event));
+  queue_.emplace_back(std::move(pinch_event));
 }
 
 std::unique_ptr<EventWithCallback> CompositorThreadEventQueue::Pop() {
diff --git a/ui/events/blink/event_with_callback.cc b/ui/events/blink/event_with_callback.cc
index bcbd862e..e2c90a2 100644
--- a/ui/events/blink/event_with_callback.cc
+++ b/ui/events/blink/event_with_callback.cc
@@ -26,6 +26,20 @@
   original_events_.emplace_back(std::move(event), callback);
 }
 
+EventWithCallback::EventWithCallback(
+    ScopedWebInputEvent event,
+    const LatencyInfo& latency,
+    base::TimeTicks creation_timestamp,
+    base::TimeTicks last_coalesced_timestamp,
+    std::unique_ptr<OriginalEventList> original_events)
+    : event_(std::move(event)),
+      latency_(latency),
+      creation_timestamp_(creation_timestamp),
+      last_coalesced_timestamp_(last_coalesced_timestamp) {
+  if (original_events)
+    original_events_.splice(original_events_.end(), *original_events);
+}
+
 EventWithCallback::~EventWithCallback() {}
 
 bool EventWithCallback::CanCoalesceWith(const EventWithCallback& other) const {
diff --git a/ui/events/blink/event_with_callback.h b/ui/events/blink/event_with_callback.h
index c6fd612..14f6eee 100644
--- a/ui/events/blink/event_with_callback.h
+++ b/ui/events/blink/event_with_callback.h
@@ -18,11 +18,26 @@
 
 class EventWithCallback {
  public:
+  struct OriginalEventWithCallback {
+    OriginalEventWithCallback(
+        ScopedWebInputEvent event,
+        const InputHandlerProxy::EventDispositionCallback& callback);
+    ~OriginalEventWithCallback();
+    ScopedWebInputEvent event_;
+    InputHandlerProxy::EventDispositionCallback callback_;
+  };
+  using OriginalEventList = std::list<OriginalEventWithCallback>;
+
   EventWithCallback(
       ScopedWebInputEvent event,
       const LatencyInfo& latency,
       base::TimeTicks timestamp_now,
       const InputHandlerProxy::EventDispositionCallback& callback);
+  EventWithCallback(ScopedWebInputEvent event,
+                    const LatencyInfo& latency,
+                    base::TimeTicks creation_timestamp,
+                    base::TimeTicks last_coalesced_timestamp,
+                    std::unique_ptr<OriginalEventList> original_events);
   ~EventWithCallback();
 
   bool CanCoalesceWith(const EventWithCallback& other) const WARN_UNUSED_RESULT;
@@ -39,23 +54,16 @@
     return last_coalesced_timestamp_;
   }
   size_t coalesced_count() const { return original_events_.size(); }
+  OriginalEventList& original_events() { return original_events_; }
 
  private:
   friend class test::InputHandlerProxyEventQueueTest;
-  struct OriginalEventWithCallback {
-    OriginalEventWithCallback(
-        ScopedWebInputEvent event,
-        const InputHandlerProxy::EventDispositionCallback& callback);
-    ~OriginalEventWithCallback();
-    ScopedWebInputEvent event_;
-    InputHandlerProxy::EventDispositionCallback callback_;
-  };
 
   void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
 
   ScopedWebInputEvent event_;
   LatencyInfo latency_;
-  std::list<OriginalEventWithCallback> original_events_;
+  OriginalEventList original_events_;
 
   base::TimeTicks creation_timestamp_;
   base::TimeTicks last_coalesced_timestamp_;
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 8a0f7e1c..deac383 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -21,6 +21,7 @@
 #include "third_party/WebKit/public/platform/WebGestureCurve.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "third_party/WebKit/public/platform/WebPoint.h"
+#include "ui/events/blink/blink_event_util.h"
 #include "ui/events/blink/compositor_thread_event_queue.h"
 #include "ui/events/blink/did_overscroll_params.h"
 #include "ui/events/blink/event_with_callback.h"
@@ -3087,6 +3088,54 @@
                                      1);
 }
 
+TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceScrollAndPinch) {
+  // Start scroll in the first frame.
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kImplThreadScrollState));
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
+
+  // GSUs and GPUs in one sequence should be coalesced into 1 GSU and 1 GPU.
+  HandleGestureEvent(WebInputEvent::GestureScrollBegin);
+  HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -20);
+  HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -7);
+  HandleGestureEvent(WebInputEvent::GesturePinchUpdate, 2.0f, 13, 10);
+  HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -10);
+  HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -6);
+  HandleGestureEvent(WebInputEvent::GestureScrollEnd);
+  HandleGestureEvent(WebInputEvent::GesturePinchBegin);
+  HandleGestureEvent(WebInputEvent::GesturePinchUpdate, 0.2f, 2, 20);
+  HandleGestureEvent(WebInputEvent::GesturePinchUpdate, 10.0f, 1, 10);
+  HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -30);
+  HandleGestureEvent(WebInputEvent::GesturePinchUpdate, 0.25f, 3, 30);
+  HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -10);
+  HandleGestureEvent(WebInputEvent::GesturePinchEnd);
+
+  // Only the first GSB was dispatched.
+  EXPECT_EQ(7ul, event_queue().size());
+  EXPECT_EQ(1ul, event_disposition_recorder_.size());
+
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, event_queue()[0]->event().type);
+  EXPECT_EQ(
+      -35,
+      ToWebGestureEvent(event_queue()[0]->event()).data.scrollUpdate.deltaY);
+  EXPECT_EQ(WebInputEvent::GesturePinchUpdate, event_queue()[1]->event().type);
+  EXPECT_EQ(
+      2.0f,
+      ToWebGestureEvent(event_queue()[1]->event()).data.pinchUpdate.scale);
+  EXPECT_EQ(WebInputEvent::GestureScrollEnd, event_queue()[2]->event().type);
+  EXPECT_EQ(WebInputEvent::GesturePinchBegin, event_queue()[3]->event().type);
+  EXPECT_EQ(WebInputEvent::GestureScrollUpdate, event_queue()[4]->event().type);
+  EXPECT_EQ(
+      -85,
+      ToWebGestureEvent(event_queue()[4]->event()).data.scrollUpdate.deltaY);
+  EXPECT_EQ(WebInputEvent::GesturePinchUpdate, event_queue()[5]->event().type);
+  EXPECT_EQ(
+      0.5f,
+      ToWebGestureEvent(event_queue()[5]->event()).data.pinchUpdate.scale);
+  EXPECT_EQ(WebInputEvent::GesturePinchEnd, event_queue()[6]->event().type);
+  testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
+}
+
 INSTANTIATE_TEST_CASE_P(AnimateInput,
                         InputHandlerProxyTest,
                         testing::ValuesIn(test_types));
diff --git a/ui/message_center/views/message_center_view.cc b/ui/message_center/views/message_center_view.cc
index 2cae22a..90d9768 100644
--- a/ui/message_center/views/message_center_view.cc
+++ b/ui/message_center/views/message_center_view.cc
@@ -95,6 +95,7 @@
   scroller_ = new views::ScrollView();
   scroller_->ClipHeightTo(kMinScrollViewHeight, max_height - button_height);
   scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false));
+  scroller_->SetHorizontalScrollBar(new views::OverlayScrollBar(true));
   scroller_->set_background(
       views::Background::CreateSolidBackground(kMessageCenterBackgroundColor));
 
diff --git a/ui/message_center/views/notifier_settings_view.cc b/ui/message_center/views/notifier_settings_view.cc
index e4ecb98..d27e03a5 100644
--- a/ui/message_center/views/notifier_settings_view.cc
+++ b/ui/message_center/views/notifier_settings_view.cc
@@ -442,6 +442,7 @@
 
   scroller_ = new views::ScrollView();
   scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false));
+  scroller_->SetHorizontalScrollBar(new views::OverlayScrollBar(true));
   AddChildView(scroller_);
 
   std::vector<Notifier*> notifiers;
@@ -570,7 +571,7 @@
   int content_width = width();
   int content_height = contents_view->GetHeightForWidth(content_width);
   if (title_height + content_height > height()) {
-    content_width -= scroller_->GetScrollBarWidth();
+    content_width -= scroller_->GetScrollBarLayoutWidth();
     content_height = contents_view->GetHeightForWidth(content_width);
   }
   contents_view->SetBounds(0, 0, content_width, content_height);
@@ -582,7 +583,7 @@
   int total_height = title_label_->GetPreferredSize().height() +
                      scroller_->contents()->GetPreferredSize().height();
   if (total_height > kMinimumHeight)
-    size.Enlarge(scroller_->GetScrollBarWidth(), 0);
+    size.Enlarge(scroller_->GetScrollBarLayoutWidth(), 0);
   return size;
 }
 
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc
index cf212b7c..35f7f1b 100644
--- a/ui/views/controls/scroll_view.cc
+++ b/ui/views/controls/scroll_view.cc
@@ -243,12 +243,14 @@
   max_height_ = max_height;
 }
 
-int ScrollView::GetScrollBarWidth() const {
-  return vert_sb_ ? vert_sb_->GetLayoutSize() : 0;
+int ScrollView::GetScrollBarLayoutWidth() const {
+  return vert_sb_ && !vert_sb_->OverlapsContent() ? vert_sb_->GetThickness()
+                                                  : 0;
 }
 
-int ScrollView::GetScrollBarHeight() const {
-  return horiz_sb_ ? horiz_sb_->GetLayoutSize() : 0;
+int ScrollView::GetScrollBarLayoutHeight() const {
+  return horiz_sb_ && !horiz_sb_->OverlapsContent() ? horiz_sb_->GetThickness()
+                                                    : 0;
 }
 
 void ScrollView::SetHorizontalScrollBar(ScrollBar* horiz_sb) {
@@ -302,6 +304,14 @@
 }
 
 void ScrollView::Layout() {
+#if defined(OS_MACOSX)
+  // On Mac, scrollbars may update their style one at a time, so they may
+  // temporarily be of different types. Refuse to lay out at this point.
+  if (horiz_sb_->OverlapsContent() != vert_sb_->OverlapsContent())
+    return;
+#endif
+  DCHECK_EQ(horiz_sb_->OverlapsContent(), vert_sb_->OverlapsContent());
+
   if (focus_ring_)
     focus_ring_->Layout();
 
@@ -310,7 +320,7 @@
     int content_width = available_rect.width();
     int content_height = contents_->GetHeightForWidth(content_width);
     if (content_height > height()) {
-      content_width = std::max(content_width - GetScrollBarWidth(), 0);
+      content_width = std::max(content_width - GetScrollBarLayoutWidth(), 0);
       content_height = contents_->GetHeightForWidth(content_width);
     }
     contents_->SetSize(gfx::Size(content_width, content_height));
@@ -342,9 +352,9 @@
   gfx::Size viewport_size = viewport_bounds.size();
   // Assumes a vertical scrollbar since most of the current views are designed
   // for this.
-  int horiz_sb_height = GetScrollBarHeight();
-  int vert_sb_width = GetScrollBarWidth();
-  viewport_bounds.set_width(viewport_bounds.width() - vert_sb_width);
+  const int horiz_sb_layout_height = GetScrollBarLayoutHeight();
+  const int vert_sb_layout_width = GetScrollBarLayoutWidth();
+  viewport_bounds.set_width(viewport_bounds.width() - vert_sb_layout_width);
   // Update the bounds right now so the inner views can fit in it.
   contents_viewport_->SetBoundsRect(viewport_bounds);
 
@@ -363,7 +373,9 @@
                                 &horiz_sb_required,
                                 &vert_sb_required);
   }
-  bool corner_view_required = horiz_sb_required && vert_sb_required;
+  // Overlay scrollbars don't need a corner view.
+  bool corner_view_required =
+      horiz_sb_required && vert_sb_required && !vert_sb_->OverlapsContent();
   // Take action.
   SetControlVisibility(horiz_sb_, horiz_sb_required);
   SetControlVisibility(vert_sb_, vert_sb_required);
@@ -372,37 +384,45 @@
   // Non-default.
   if (horiz_sb_required) {
     viewport_bounds.set_height(
-        std::max(0, viewport_bounds.height() - horiz_sb_height));
+        std::max(0, viewport_bounds.height() - horiz_sb_layout_height));
     should_layout_contents = true;
   }
   // Default.
   if (!vert_sb_required) {
-    viewport_bounds.set_width(viewport_bounds.width() + vert_sb_width);
+    viewport_bounds.set_width(viewport_bounds.width() + vert_sb_layout_width);
     should_layout_contents = true;
   }
 
-  int height_offset = horiz_sb_required ?
-      horiz_sb_->GetContentOverlapSize() : 0;
-  int width_offset = vert_sb_required ?
-      vert_sb_->GetContentOverlapSize() : 0;
-
   if (horiz_sb_required) {
-    horiz_sb_->SetBounds(contents_x,
-                         viewport_bounds.bottom() - height_offset,
-                         viewport_bounds.right() - contents_x - width_offset,
-                         horiz_sb_height + height_offset);
+    gfx::Rect horiz_sb_bounds(contents_x, viewport_bounds.bottom(),
+                              viewport_bounds.right() - contents_x,
+                              horiz_sb_layout_height);
+    if (horiz_sb_->OverlapsContent()) {
+      horiz_sb_bounds.Inset(
+          gfx::Insets(-horiz_sb_->GetThickness(), 0, 0,
+                      vert_sb_required ? vert_sb_->GetThickness() : 0));
+    }
+
+    horiz_sb_->SetBoundsRect(horiz_sb_bounds);
   }
   if (vert_sb_required) {
-    int width_offset = vert_sb_->GetContentOverlapSize();
-    vert_sb_->SetBounds(viewport_bounds.right() - width_offset,
-                        contents_y,
-                        vert_sb_width + width_offset,
-                        viewport_bounds.bottom() - contents_y - height_offset);
+    gfx::Rect vert_sb_bounds(viewport_bounds.right(), contents_y,
+                             vert_sb_layout_width,
+                             viewport_bounds.bottom() - contents_y);
+    if (vert_sb_->OverlapsContent()) {
+      // In the overlay scrollbar case, the scrollbar only covers the viewport
+      // (and not the header).
+      vert_sb_bounds.Inset(
+          gfx::Insets(header_height, -vert_sb_->GetThickness(),
+                      horiz_sb_required ? horiz_sb_->GetThickness() : 0, 0));
+    }
+
+    vert_sb_->SetBoundsRect(vert_sb_bounds);
   }
   if (corner_view_required) {
     // Show the resize corner.
     corner_view_->SetBounds(vert_sb_->bounds().x(), horiz_sb_->bounds().y(),
-                            vert_sb_width, horiz_sb_height);
+                            vert_sb_layout_width, horiz_sb_layout_height);
   }
 
   // Update to the real client size with the visible scrollbars.
@@ -619,10 +639,12 @@
       content_size.height() <= vp_size.height()) {
     *horiz_is_shown = false;
     *vert_is_shown = false;
-  } else if (content_size.width() <= vp_size.width() - GetScrollBarWidth()) {
+  } else if (content_size.width() <=
+             vp_size.width() - GetScrollBarLayoutWidth()) {
     *horiz_is_shown = false;
     *vert_is_shown = true;
-  } else if (content_size.height() <= vp_size.height() - GetScrollBarHeight()) {
+  } else if (content_size.height() <=
+             vp_size.height() - GetScrollBarLayoutHeight()) {
     *horiz_is_shown = true;
     *vert_is_shown = false;
   } else {
diff --git a/ui/views/controls/scroll_view.h b/ui/views/controls/scroll_view.h
index 288be67..6dc4393 100644
--- a/ui/views/controls/scroll_view.h
+++ b/ui/views/controls/scroll_view.h
@@ -74,10 +74,10 @@
   // Returns whether or not the ScrollView is bounded (as set by ClipHeightTo).
   bool is_bounded() const { return max_height_ >= 0 && min_height_ >= 0; }
 
-  // Retrieves the width/height of scrollbars. These return 0 if the scrollbar
-  // has not yet been created.
-  int GetScrollBarWidth() const;
-  int GetScrollBarHeight() const;
+  // Retrieves the width/height reserved for scrollbars. These return 0 if the
+  // scrollbar has not yet been created or in the case of overlay scrollbars.
+  int GetScrollBarLayoutWidth() const;
+  int GetScrollBarLayoutHeight() const;
 
   // Returns the horizontal/vertical scrollbar. This may return NULL.
   const ScrollBar* horizontal_scroll_bar() const { return horiz_sb_; }
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc
index c4a5ca7..1aa29e15 100644
--- a/ui/views/controls/scroll_view_unittest.cc
+++ b/ui/views/controls/scroll_view_unittest.cc
@@ -167,6 +167,14 @@
 
  protected:
 #endif
+  int VerticalScrollBarWidth() {
+    return scroll_view_.vertical_scroll_bar()->GetThickness();
+  }
+
+  int HorizontalScrollBarHeight() {
+    return scroll_view_.horizontal_scroll_bar()->GetThickness();
+  }
+
   ScrollView scroll_view_;
 
  private:
@@ -309,7 +317,7 @@
   // Size the contents such that vertical scrollbar is needed.
   contents->SetBounds(0, 0, 50, 400);
   scroll_view_.Layout();
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarWidth(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             contents->parent()->width());
   EXPECT_EQ(100, contents->parent()->height());
   CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
@@ -323,7 +331,7 @@
   contents->SetBounds(0, 0, 400, 50);
   scroll_view_.Layout();
   EXPECT_EQ(100, contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarHeight(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(),
             contents->parent()->height());
   CheckScrollbarVisibility(scroll_view_, VERTICAL, false);
   CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
@@ -331,9 +339,9 @@
   // Both horizontal and vertical.
   contents->SetBounds(0, 0, 300, 400);
   scroll_view_.Layout();
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarWidth(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarHeight(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(),
             contents->parent()->height());
   CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
   CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
@@ -347,16 +355,16 @@
                                            kBottomPadding, kRightPadding));
   contents->SetBounds(0, 0, 50, 400);
   scroll_view_.Layout();
-  EXPECT_EQ(
-      100 - scroll_view_.GetScrollBarWidth() - kLeftPadding - kRightPadding,
-      contents->parent()->width());
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth() - kLeftPadding -
+                kRightPadding,
+            contents->parent()->width());
   EXPECT_EQ(100 - kTopPadding - kBottomPadding, contents->parent()->height());
   EXPECT_TRUE(!scroll_view_.horizontal_scroll_bar() ||
               !scroll_view_.horizontal_scroll_bar()->visible());
   ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
   EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
   gfx::Rect bounds = scroll_view_.vertical_scroll_bar()->bounds();
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarWidth() - kRightPadding, bounds.x());
+  EXPECT_EQ(100 - VerticalScrollBarWidth() - kRightPadding, bounds.x());
   EXPECT_EQ(100 - kRightPadding, bounds.right());
   EXPECT_EQ(kTopPadding, bounds.y());
   EXPECT_EQ(100 - kBottomPadding, bounds.bottom());
@@ -365,9 +373,9 @@
   contents->SetBounds(0, 0, 400, 50);
   scroll_view_.Layout();
   EXPECT_EQ(100 - kLeftPadding - kRightPadding, contents->parent()->width());
-  EXPECT_EQ(
-      100 - scroll_view_.GetScrollBarHeight() - kTopPadding - kBottomPadding,
-      contents->parent()->height());
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - kTopPadding -
+                kBottomPadding,
+            contents->parent()->height());
   ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
   EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
   EXPECT_TRUE(!scroll_view_.vertical_scroll_bar() ||
@@ -375,38 +383,35 @@
   bounds = scroll_view_.horizontal_scroll_bar()->bounds();
   EXPECT_EQ(kLeftPadding, bounds.x());
   EXPECT_EQ(100 - kRightPadding, bounds.right());
-  EXPECT_EQ(100 - kBottomPadding - scroll_view_.GetScrollBarHeight(),
-            bounds.y());
+  EXPECT_EQ(100 - kBottomPadding - HorizontalScrollBarHeight(), bounds.y());
   EXPECT_EQ(100 - kBottomPadding, bounds.bottom());
 
   // Both horizontal and vertical with border.
   contents->SetBounds(0, 0, 300, 400);
   scroll_view_.Layout();
-  EXPECT_EQ(
-      100 - scroll_view_.GetScrollBarWidth() - kLeftPadding - kRightPadding,
-      contents->parent()->width());
-  EXPECT_EQ(
-      100 - scroll_view_.GetScrollBarHeight() - kTopPadding - kBottomPadding,
-      contents->parent()->height());
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth() - kLeftPadding -
+                kRightPadding,
+            contents->parent()->width());
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - kTopPadding -
+                kBottomPadding,
+            contents->parent()->height());
   bounds = scroll_view_.horizontal_scroll_bar()->bounds();
   // Check horiz.
   ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
   EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
   bounds = scroll_view_.horizontal_scroll_bar()->bounds();
   EXPECT_EQ(kLeftPadding, bounds.x());
-  EXPECT_EQ(100 - kRightPadding - scroll_view_.GetScrollBarWidth(),
-            bounds.right());
-  EXPECT_EQ(100 - kBottomPadding - scroll_view_.GetScrollBarHeight(),
-            bounds.y());
+  EXPECT_EQ(100 - kRightPadding - VerticalScrollBarWidth(), bounds.right());
+  EXPECT_EQ(100 - kBottomPadding - HorizontalScrollBarHeight(), bounds.y());
   EXPECT_EQ(100 - kBottomPadding, bounds.bottom());
   // Check vert.
   ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
   EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
   bounds = scroll_view_.vertical_scroll_bar()->bounds();
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarWidth() - kRightPadding, bounds.x());
+  EXPECT_EQ(100 - VerticalScrollBarWidth() - kRightPadding, bounds.x());
   EXPECT_EQ(100 - kRightPadding, bounds.right());
   EXPECT_EQ(kTopPadding, bounds.y());
-  EXPECT_EQ(100 - kBottomPadding - scroll_view_.GetScrollBarHeight(),
+  EXPECT_EQ(100 - kBottomPadding - HorizontalScrollBarHeight(),
             bounds.bottom());
 }
 
@@ -464,19 +469,25 @@
   scroll_view_.Layout();
   EXPECT_EQ(0, contents->parent()->x());
   EXPECT_EQ(20, contents->parent()->y());
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarWidth(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             contents->parent()->width());
   EXPECT_EQ(80, contents->parent()->height());
   EXPECT_EQ(0, header->parent()->x());
   EXPECT_EQ(0, header->parent()->y());
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarWidth(), header->parent()->width());
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
+            header->parent()->width());
   EXPECT_EQ(20, header->parent()->height());
   EXPECT_TRUE(!scroll_view_.horizontal_scroll_bar() ||
               !scroll_view_.horizontal_scroll_bar()->visible());
   ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
   EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
-  // Make sure the vertical scrollbar overlaps the header.
-  EXPECT_EQ(header->y(), scroll_view_.vertical_scroll_bar()->y());
+  // Make sure the vertical scrollbar overlaps the header for traditional
+  // scrollbars and doesn't overlap the header for overlay scrollbars.
+  const int expected_scrollbar_y =
+      scroll_view_.vertical_scroll_bar()->OverlapsContent()
+          ? header->bounds().bottom()
+          : header->y();
+  EXPECT_EQ(expected_scrollbar_y, scroll_view_.vertical_scroll_bar()->y());
   EXPECT_EQ(header->y(), contents->y());
 
   // Size the contents such that horizontal scrollbar is needed.
@@ -485,7 +496,7 @@
   EXPECT_EQ(0, contents->parent()->x());
   EXPECT_EQ(20, contents->parent()->y());
   EXPECT_EQ(100, contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarHeight() - 20,
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - 20,
             contents->parent()->height());
   EXPECT_EQ(0, header->parent()->x());
   EXPECT_EQ(0, header->parent()->y());
@@ -501,13 +512,14 @@
   scroll_view_.Layout();
   EXPECT_EQ(0, contents->parent()->x());
   EXPECT_EQ(20, contents->parent()->y());
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarWidth(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarHeight() - 20,
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - 20,
             contents->parent()->height());
   EXPECT_EQ(0, header->parent()->x());
   EXPECT_EQ(0, header->parent()->y());
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarWidth(), header->parent()->width());
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
+            header->parent()->width());
   EXPECT_EQ(20, header->parent()->height());
   ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
   EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
@@ -560,7 +572,7 @@
   const int viewport_height = test_api.contents_viewport()->height();
 
   // Expect there to be a horizontal scrollbar, making the viewport shorter.
-  EXPECT_LT(viewport_height, 100);
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(), viewport_height);
 
   gfx::ScrollOffset offset = test_api.CurrentOffset();
   EXPECT_EQ(415 - viewport_height, offset.y());
@@ -618,10 +630,6 @@
 // Verifies ClipHeightTo() uses the maximum height when the content is longer
 // thamn the maximum height value.
 TEST_F(ScrollViewTest, ClipHeightToTallContentHeight) {
-  // Use a scrollbar that is disabled by default, so the width of the content is
-  // not affected.
-  scroll_view_.SetVerticalScrollBar(new views::OverlayScrollBar(false));
-
   scroll_view_.ClipHeightTo(kMinHeight, kMaxHeight);
 
   const int kTallContentHeight = 1000;
@@ -633,8 +641,9 @@
   scroll_view_.SizeToPreferredSize();
   scroll_view_.Layout();
 
-  EXPECT_EQ(gfx::Size(kWidth, kTallContentHeight),
-            scroll_view_.contents()->size());
+  // The width may be less than kWidth if the scroll bar takes up some width.
+  EXPECT_GE(kWidth, scroll_view_.contents()->width());
+  EXPECT_EQ(kTallContentHeight, scroll_view_.contents()->height());
   EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_.size());
 }
 
@@ -654,8 +663,7 @@
   scroll_view_.SetSize(new_size);
   scroll_view_.Layout();
 
-  int scroll_bar_width = scroll_view_.GetScrollBarWidth();
-  int expected_width = kWidth - scroll_bar_width;
+  int expected_width = kWidth - scroll_view_.GetScrollBarLayoutWidth();
   EXPECT_EQ(scroll_view_.contents()->size().width(), expected_width);
   EXPECT_EQ(scroll_view_.contents()->size().height(), 1000 * expected_width);
   EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_.size());
@@ -665,17 +673,24 @@
   View* contents = InstallContents();
   View* corner_view = ScrollViewTestApi(&scroll_view_).corner_view();
 
-  // Corner view should be visible when both scrollbars are visible.
   contents->SetBounds(0, 0, 200, 200);
   scroll_view_.Layout();
+
+  // Corner view should not exist if using overlay scrollbars.
+  if (scroll_view_.vertical_scroll_bar()->OverlapsContent()) {
+    EXPECT_FALSE(corner_view->parent());
+    return;
+  }
+
+  // Corner view should be visible when both scrollbars are visible.
   EXPECT_EQ(&scroll_view_, corner_view->parent());
   EXPECT_TRUE(corner_view->visible());
 
   // Corner view should be aligned to the scrollbars.
   EXPECT_EQ(scroll_view_.vertical_scroll_bar()->x(), corner_view->x());
   EXPECT_EQ(scroll_view_.horizontal_scroll_bar()->y(), corner_view->y());
-  EXPECT_EQ(scroll_view_.GetScrollBarWidth(), corner_view->width());
-  EXPECT_EQ(scroll_view_.GetScrollBarHeight(), corner_view->height());
+  EXPECT_EQ(scroll_view_.GetScrollBarLayoutWidth(), corner_view->width());
+  EXPECT_EQ(scroll_view_.GetScrollBarLayoutHeight(), corner_view->height());
 
   // Corner view should be removed when only the vertical scrollbar is visible.
   contents->SetBounds(0, 0, 50, 200);
@@ -712,7 +727,7 @@
   scroll_view_.Layout();
   EXPECT_EQ(100, contents->parent()->width());
   EXPECT_EQ(100, contents->parent()->height());
-  EXPECT_EQ(0, scroll_view_.GetScrollBarWidth());
+  EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutWidth());
   CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
   CheckScrollbarVisibility(scroll_view_, HORIZONTAL, false);
 
@@ -721,7 +736,7 @@
   scroll_view_.Layout();
   EXPECT_EQ(100, contents->parent()->width());
   EXPECT_EQ(100, contents->parent()->height());
-  EXPECT_EQ(0, scroll_view_.GetScrollBarHeight());
+  EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutHeight());
   CheckScrollbarVisibility(scroll_view_, VERTICAL, false);
   CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
 
@@ -730,8 +745,8 @@
   scroll_view_.Layout();
   EXPECT_EQ(100, contents->parent()->width());
   EXPECT_EQ(100, contents->parent()->height());
-  EXPECT_EQ(0, scroll_view_.GetScrollBarWidth());
-  EXPECT_EQ(0, scroll_view_.GetScrollBarHeight());
+  EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutWidth());
+  EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutHeight());
   CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
   CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
 
@@ -744,12 +759,10 @@
   // Switch to the non-overlay style and check that the ViewPort is now sized
   // to be smaller, and ScrollbarWidth and ScrollbarHeight are non-zero.
   SetOverlayScrollersEnabled(false);
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarWidth(),
-            contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_.GetScrollBarHeight(),
-            contents->parent()->height());
-  EXPECT_NE(0, scroll_view_.GetScrollBarWidth());
-  EXPECT_NE(0, scroll_view_.GetScrollBarHeight());
+  EXPECT_EQ(100 - VerticalScrollBarWidth(), contents->parent()->width());
+  EXPECT_EQ(100 - HorizontalScrollBarHeight(), contents->parent()->height());
+  EXPECT_NE(0, VerticalScrollBarWidth());
+  EXPECT_NE(0, HorizontalScrollBarHeight());
 }
 
 // Test overlay scrollbar behavior when just resting fingers on the trackpad.
diff --git a/ui/views/controls/scrollbar/base_scroll_bar.cc b/ui/views/controls/scrollbar/base_scroll_bar.cc
index 123e59c..f343948 100644
--- a/ui/views/controls/scrollbar/base_scroll_bar.cc
+++ b/ui/views/controls/scrollbar/base_scroll_bar.cc
@@ -400,6 +400,10 @@
   return thumb_->GetPosition();
 }
 
+bool BaseScrollBar::OverlapsContent() const {
+  return false;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // BaseScrollBar, protected:
 
diff --git a/ui/views/controls/scrollbar/base_scroll_bar.h b/ui/views/controls/scrollbar/base_scroll_bar.h
index 9355e7c..5d077737 100644
--- a/ui/views/controls/scrollbar/base_scroll_bar.h
+++ b/ui/views/controls/scrollbar/base_scroll_bar.h
@@ -78,8 +78,9 @@
   void Update(int viewport_size,
               int content_size,
               int contents_scroll_offset) override;
-  int GetLayoutSize() const override = 0;
   int GetPosition() const override;
+  int GetThickness() const override = 0;
+  bool OverlapsContent() const override;
 
   // ScrollDelegate overrides:
   bool OnScroll(float dx, float dy) override;
diff --git a/ui/views/controls/scrollbar/cocoa_scroll_bar.h b/ui/views/controls/scrollbar/cocoa_scroll_bar.h
index 8b91f6c3..3f1ba279 100644
--- a/ui/views/controls/scrollbar/cocoa_scroll_bar.h
+++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.h
@@ -59,8 +59,8 @@
   gfx::Rect GetTrackBounds() const override;
 
   // ScrollBar:
-  int GetLayoutSize() const override;
-  int GetContentOverlapSize() const override;
+  int GetThickness() const override;
+  bool OverlapsContent() const override;
 
   // View:
   void Layout() override;
diff --git a/ui/views/controls/scrollbar/cocoa_scroll_bar.mm b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
index 40390cd..9d54b67 100644
--- a/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
+++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
@@ -208,12 +208,12 @@
 //////////////////////////////////////////////////////////////////
 // CocoaScrollBar, ScrollBar:
 
-int CocoaScrollBar::GetLayoutSize() const {
-  return scroller_style_ == NSScrollerStyleOverlay ? 0 : ScrollbarThickness();
+int CocoaScrollBar::GetThickness() const {
+  return ScrollbarThickness();
 }
 
-int CocoaScrollBar::GetContentOverlapSize() const {
-  return scroller_style_ == NSScrollerStyleLegacy ? 0 : ScrollbarThickness();
+bool CocoaScrollBar::OverlapsContent() const {
+  return scroller_style_ == NSScrollerStyleOverlay;
 }
 
 //////////////////////////////////////////////////////////////////
diff --git a/ui/views/controls/scrollbar/overlay_scroll_bar.cc b/ui/views/controls/scrollbar/overlay_scroll_bar.cc
index 358a097..5ea32a4 100644
--- a/ui/views/controls/scrollbar/overlay_scroll_bar.cc
+++ b/ui/views/controls/scrollbar/overlay_scroll_bar.cc
@@ -128,12 +128,12 @@
   return local;
 }
 
-int OverlayScrollBar::GetLayoutSize() const {
-  return 0;
+int OverlayScrollBar::GetThickness() const {
+  return kThumbThickness;
 }
 
-int OverlayScrollBar::GetContentOverlapSize() const {
-  return kThumbThickness;
+bool OverlayScrollBar::OverlapsContent() const {
+  return true;
 }
 
 void OverlayScrollBar::Layout() {
diff --git a/ui/views/controls/scrollbar/overlay_scroll_bar.h b/ui/views/controls/scrollbar/overlay_scroll_bar.h
index 4771abb..5a21d424 100644
--- a/ui/views/controls/scrollbar/overlay_scroll_bar.h
+++ b/ui/views/controls/scrollbar/overlay_scroll_bar.h
@@ -22,8 +22,8 @@
   gfx::Rect GetTrackBounds() const override;
 
   // ScrollBar overrides:
-  int GetLayoutSize() const override;
-  int GetContentOverlapSize() const override;
+  int GetThickness() const override;
+  bool OverlapsContent() const override;
 
   // View overrides:
   void Layout() override;
diff --git a/ui/views/controls/scrollbar/scroll_bar.cc b/ui/views/controls/scrollbar/scroll_bar.cc
index ea5d94b..6714693 100644
--- a/ui/views/controls/scrollbar/scroll_bar.cc
+++ b/ui/views/controls/scrollbar/scroll_bar.cc
@@ -31,10 +31,6 @@
   return 0;
 }
 
-int ScrollBar::GetContentOverlapSize() const {
-  return 0;
-}
-
 void ScrollBar::ObserveScrollEvent(const ui::ScrollEvent& event) {}
 
 ScrollBar::ScrollBar(bool is_horiz)
diff --git a/ui/views/controls/scrollbar/scroll_bar.h b/ui/views/controls/scrollbar/scroll_bar.h
index acda1430..ac162b7 100644
--- a/ui/views/controls/scrollbar/scroll_bar.h
+++ b/ui/views/controls/scrollbar/scroll_bar.h
@@ -81,14 +81,14 @@
   // Returns the position of the scrollbar.
   virtual int GetPosition() const = 0;
 
-  // Get the width or height of this scrollbar, for use in layout calculations.
-  // For a vertical scrollbar, this is the width of the scrollbar, likewise it
-  // is the height for a horizontal scrollbar.
-  virtual int GetLayoutSize() const = 0;
+  // Get the width or height of this scrollbar. For a vertical scrollbar, this
+  // is the width of the scrollbar, likewise it is the height for a horizontal
+  // scrollbar.
+  virtual int GetThickness() const = 0;
 
-  // Get the width or height for this scrollbar which overlaps with the content.
-  // Default is 0.
-  virtual int GetContentOverlapSize() const;
+  // Returns true if the scrollbar should sit on top of the content area (e.g.
+  // for overlay scrollbars).
+  virtual bool OverlapsContent() const = 0;
 
   // Called when a ScrollEvent (in any, or no, direction) is seen by the parent
   // ScrollView. E.g., this may reveal an overlay scrollbar to indicate
diff --git a/ui/views/controls/scrollbar/scroll_bar_views.cc b/ui/views/controls/scrollbar/scroll_bar_views.cc
index 066a56c..882e381 100644
--- a/ui/views/controls/scrollbar/scroll_bar_views.cc
+++ b/ui/views/controls/scrollbar/scroll_bar_views.cc
@@ -278,15 +278,15 @@
 }
 
 gfx::Size ScrollBarViews::GetPreferredSize() const {
-  return gfx::Size(IsHorizontal() ? 0 : GetLayoutSize(),
-                   IsHorizontal() ? GetLayoutSize() : 0);
+  return gfx::Size(IsHorizontal() ? 0 : GetThickness(),
+                   IsHorizontal() ? GetThickness() : 0);
 }
 
 const char* ScrollBarViews::GetClassName() const {
   return kViewClassName;
 }
 
-int ScrollBarViews::GetLayoutSize() const {
+int ScrollBarViews::GetThickness() const {
   const ui::NativeTheme* theme = GetNativeTheme();
   return IsHorizontal() ? GetHorizontalScrollBarHeight(theme)
                         : GetVerticalScrollBarWidth(theme);
diff --git a/ui/views/controls/scrollbar/scroll_bar_views.h b/ui/views/controls/scrollbar/scroll_bar_views.h
index 7c480166..8fff6fd 100644
--- a/ui/views/controls/scrollbar/scroll_bar_views.h
+++ b/ui/views/controls/scrollbar/scroll_bar_views.h
@@ -39,7 +39,7 @@
   const char* GetClassName() const override;
 
   // ScrollBar overrides:
-  int GetLayoutSize() const override;
+  int GetThickness() const override;
 
   // BaseButton::ButtonListener overrides:
   void ButtonPressed(Button* sender, const ui::Event& event) override;