diff --git a/DEPS b/DEPS
index adaabf6..5023cef 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '114a3c0b2b26c84b9d0907a99fd8ab7938631246',
+  'skia_revision': 'b5e4842543318e1eac827433855c9a37cdb7f26a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '20ee3efa8a86d2e9ceb835861d2251939443c7c7',
+  'v8_revision': '02777351e7ebb36db9477e225ca6e7689cf99a9e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '32a3f0b8f49bb6a3e5c7f158ff7aea5584843294',
+  'catapult_revision': 'deb4a2aa8f11cb520e9b8bc7413296d899a3af47',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -265,7 +265,7 @@
     Var('chromium_git') + '/chromium/deps/mesa.git' + '@' + 'ef811c6bd4de74e13e7035ca882cc77f85793fef',
 
   'src/third_party/ced/src':
-    Var('chromium_git') + '/external/github.com/google/compact_enc_det.git' + '@' + 'e21eb6aed10b9f6e2727f136c52420033214d458',
+    Var('chromium_git') + '/external/github.com/google/compact_enc_det.git' + '@' + '910cca22d881b02cbc8950fa02ccbcdcfb782456',
 
   'src/third_party/swiftshader':
     Var('swiftshader_git') + '/SwiftShader.git' + '@' +  Var('swiftshader_revision'),
diff --git a/WATCHLISTS b/WATCHLISTS
index 72076941..f036247 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1867,7 +1867,8 @@
     'blink_vibration': ['mlamouri+watch-blink@chromium.org'],
     'blink_viewport_interaction': ['kenneth.christiansen@gmail.com'],
     'blink_w3ctests': ['blink-reviews-w3ctests@chromium.org'],
-    'blink_web': ['kinuko+watch@chromium.org'],
+    'blink_web': ['kinuko+watch@chromium.org',
+                  'platform-architecture-syd+reviews-web@chromium.org'],
     'blink_webcomponents': ['dglazkov+blink@chromium.org',
                             'webcomponents-bugzilla@chromium.org'],
     'blink_webp': ['jzern@chromium.org',
diff --git a/base/task_scheduler/environment_config.h b/base/task_scheduler/environment_config.h
index 3a86453..54f2ff3 100644
--- a/base/task_scheduler/environment_config.h
+++ b/base/task_scheduler/environment_config.h
@@ -7,6 +7,7 @@
 
 #include <stddef.h>
 
+#include "base/base_export.h"
 #include "base/task_scheduler/task_traits.h"
 #include "base/threading/thread.h"
 
diff --git a/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc b/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc
index 3f45500..a445a165 100644
--- a/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc
+++ b/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc
@@ -330,19 +330,9 @@
 SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunnerManager(
     TaskTracker* task_tracker,
     DelayedTaskManager* delayed_task_manager)
-    : task_tracker_(task_tracker),
-      delayed_task_manager_(delayed_task_manager),
-      shared_scheduler_workers_ {}
-#if defined(OS_WIN)
-      ,
-      shared_com_scheduler_workers_ {}
-#endif  // defined(OS_WIN)
-{
+    : task_tracker_(task_tracker), delayed_task_manager_(delayed_task_manager) {
   DCHECK(task_tracker_);
   DCHECK(delayed_task_manager_);
-  static_assert(
-      arraysize(shared_scheduler_workers_) == ENVIRONMENT_COUNT,
-      "The size of |shared_scheduler_workers_| must match ENVIRONMENT_COUNT");
 #if defined(OS_WIN)
   static_assert(arraysize(shared_com_scheduler_workers_) ==
                     arraysize(shared_scheduler_workers_),
@@ -427,7 +417,8 @@
   DCHECK(thread_mode != SingleThreadTaskRunnerThreadMode::SHARED ||
          !traits.with_base_sync_primitives())
       << "Using WithBaseSyncPrimitives() on a shared SingleThreadTaskRunner "
-         "may cause deadlocks. Either reevaluate your usage pattern or use "
+         "may cause deadlocks. Either reevaluate your usage (e.g. use "
+         "SequencedTaskRunner) or use "
          "SingleThreadTaskRunnerThreadMode::DEDICATED.";
   // To simplify the code, |dedicated_worker| is a local only variable that
   // allows the code to treat both the DEDICATED and SHARED cases similarly for
@@ -460,7 +451,8 @@
   if (new_worker && started)
     worker->Start();
 
-  return new SchedulerSingleThreadTaskRunner(this, traits, worker, thread_mode);
+  return MakeRefCounted<SchedulerSingleThreadTaskRunner>(this, traits, worker,
+                                                         thread_mode);
 }
 
 void SchedulerSingleThreadTaskRunnerManager::JoinForTesting() {
@@ -569,8 +561,10 @@
     AutoSchedulerLock auto_lock(lock_);
     for (size_t i = 0; i < arraysize(shared_scheduler_workers_); ++i) {
       local_shared_scheduler_workers[i] = shared_scheduler_workers_[i];
+      shared_scheduler_workers_[i] = nullptr;
 #if defined(OS_WIN)
       local_shared_com_scheduler_workers[i] = shared_com_scheduler_workers_[i];
+      shared_com_scheduler_workers_[i] = nullptr;
 #endif
     }
   }
diff --git a/base/task_scheduler/scheduler_single_thread_task_runner_manager.h b/base/task_scheduler/scheduler_single_thread_task_runner_manager.h
index c6cd8ed..1b4e51a 100644
--- a/base/task_scheduler/scheduler_single_thread_task_runner_manager.h
+++ b/base/task_scheduler/scheduler_single_thread_task_runner_manager.h
@@ -40,9 +40,10 @@
 // Manages a pool of threads which are each associated with one or more
 // SingleThreadTaskRunners.
 //
-// SingleThreadTaskRunners using SingleThreadTaskRunnerThreadMode::SHARED, are
+// SingleThreadTaskRunners using SingleThreadTaskRunnerThreadMode::SHARED are
 // backed by shared SchedulerWorkers for each COM+task environment combination.
-// These workers are only reclaimed during JoinForTesting().
+// These workers are lazily instantiated and then only reclaimed during
+// JoinForTesting()
 //
 // No threads are created (and hence no tasks can run) before Start() is called.
 //
@@ -61,9 +62,7 @@
   // Creates a SingleThreadTaskRunner which runs tasks with |traits| on a thread
   // named "TaskSchedulerSingleThread[Shared]" + |name| +
   // kEnvironmentParams[GetEnvironmentIndexForTraits(traits)].name_suffix +
-  // index. "Shared" will be in the thread name when |thread_mode| is SHARED. If
-  // |thread_mode| is DEDICATED, a thread will be dedicated to the returned task
-  // runner, otherwise it could be shared with other SingleThreadTaskRunners.
+  // index.
   scoped_refptr<SingleThreadTaskRunner> CreateSingleThreadTaskRunnerWithTraits(
       const std::string& name,
       const TaskTraits& traits,
@@ -73,9 +72,7 @@
   // Creates a SingleThreadTaskRunner which runs tasks with |traits| on a COM
   // STA thread named "TaskSchedulerSingleThreadCOMSTA[Shared]" + |name| +
   // kEnvironmentParams[GetEnvironmentIndexForTraits(traits)].name_suffix +
-  // index. "Shared" will be in the thread name when |thread_mode| is SHARED. If
-  // |thread_mode| is DEDICATED, a thread will be dedicated to the returned task
-  // runner, otherwise it could be shared with other SingleThreadTaskRunners.
+  // index.
   scoped_refptr<SingleThreadTaskRunner> CreateCOMSTATaskRunnerWithTraits(
       const std::string& name,
       const TaskTraits& traits,
@@ -122,10 +119,10 @@
   std::vector<scoped_refptr<SchedulerWorker>> workers_;
   int next_worker_id_ = 0;
 
-  SchedulerWorker* shared_scheduler_workers_[4];
+  SchedulerWorker* shared_scheduler_workers_[ENVIRONMENT_COUNT] = {};
 
 #if defined(OS_WIN)
-  SchedulerWorker* shared_com_scheduler_workers_[4];
+  SchedulerWorker* shared_com_scheduler_workers_[ENVIRONMENT_COUNT] = {};
 #endif  // defined(OS_WIN)
 
   // Set to true when Start() is called.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 82b7ca0..faea5d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -51,6 +51,7 @@
 import org.chromium.chrome.browser.IntentHandler.TabOpenType;
 import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.bookmarks.BookmarkUtils;
+import org.chromium.chrome.browser.browseractions.BrowserActionsContextMenuItemDelegate;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
@@ -616,10 +617,9 @@
     @Override
     public void onStartWithNative() {
         super.onStartWithNative();
-        // If we don't have a current tab, show the overview mode.
-        if (getActivityTab() == null && !mLayoutManager.overviewVisible()) {
-            mLayoutManager.showOverview(false);
-        }
+
+        setInitialOverviewState();
+        BrowserActionsContextMenuItemDelegate.cancelBrowserActionsNotification();
 
         resetSavedInstanceState();
     }
@@ -673,6 +673,18 @@
         }
     }
 
+    private void setInitialOverviewState() {
+        boolean isOverviewVisible = mLayoutManager.overviewVisible();
+        if (getActivityTab() == null && !isOverviewVisible) {
+            toggleOverview();
+        }
+
+        if (BrowserActionsContextMenuItemDelegate.toggleOverviewByBrowserActions(
+                    getIntent(), isOverviewVisible)) {
+            toggleOverview();
+        }
+    }
+
     private void initializeUI() {
         try {
             TraceEvent.begin("ChromeTabbedActivity.initializeUI");
@@ -1823,8 +1835,12 @@
 
     private void toggleOverview() {
         Tab currentTab = getActivityTab();
-        ContentViewCore contentViewCore =
-                currentTab != null ? currentTab.getContentViewCore() : null;
+        // If we don't have a current tab, show the overview mode.
+        if (currentTab == null) {
+            mLayoutManager.showOverview(false);
+            return;
+        }
+        ContentViewCore contentViewCore = currentTab.getContentViewCore();
 
         if (!mLayoutManager.overviewVisible()) {
             getCompositorViewHolder().hideKeyboard(new Runnable() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsContextMenuItemDelegate.java
index 11854ef..7c2bd87ed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsContextMenuItemDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsContextMenuItemDelegate.java
@@ -4,35 +4,105 @@
 
 package org.chromium.chrome.browser.browseractions;
 
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.net.Uri;
 import android.provider.Browser;
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
+import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder;
+import org.chromium.chrome.browser.notifications.NotificationBuilderFactory;
+import org.chromium.chrome.browser.notifications.NotificationConstants;
+import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
+import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.ui.widget.Toast;
 
 /**
  * A delegate responsible for taking actions based on browser action context menu selections.
  */
 public class BrowserActionsContextMenuItemDelegate {
     private static final String TAG = "BrowserActionsItem";
+    /**
+     * Action to request open ChromeTabbedActivity in tab switcher mode.
+     */
+    public static final String ACTION_BROWSER_ACTIONS_OPEN_IN_BACKGROUND =
+            "org.chromium.chrome.browser.browseractions.browser_action_open_in_background";
+
+    public static final String PREF_HAS_BROWSER_ACTIONS_NOTIFICATION =
+            "org.chromium.chrome.browser.browseractions.HAS_BROWSER_ACTIONS_NOTIFICATION";
+
+    /**
+     * Extra that indicates whether to show a Tab for single url or the tab switcher for
+     * multiple urls.
+     */
+    public static final String EXTRA_IS_SINGLE_URL =
+            "org.chromium.chrome.browser.browseractions.is_single_url";
 
     private final Context mContext;
+    private final NotificationManager mNotificationManager;
+    private final SharedPreferences mSharedPreferences;
+
+    private void sendBrowserActionsNotification() {
+        ChromeNotificationBuilder builder = createNotificationBuilder();
+        mNotificationManager.notify(
+                NotificationConstants.NOTIFICATION_ID_BROWSER_ACTIONS, builder.build());
+        mSharedPreferences.edit().putBoolean(PREF_HAS_BROWSER_ACTIONS_NOTIFICATION, true).apply();
+        NotificationUmaTracker.getInstance().onNotificationShown(
+                NotificationUmaTracker.BROWSER_ACTIONS, ChannelDefinitions.CHANNEL_ID_BROWSER);
+    }
+
+    private ChromeNotificationBuilder createNotificationBuilder() {
+        ChromeNotificationBuilder builder =
+                NotificationBuilderFactory
+                        .createChromeNotificationBuilder(
+                                true /* preferCompat */, ChannelDefinitions.CHANNEL_ID_BROWSER)
+                        .setSmallIcon(R.drawable.infobar_chrome)
+                        .setLocalOnly(true)
+                        .setAutoCancel(true)
+                        .setContentText(
+                                mContext.getString(R.string.browser_actions_notification_text));
+        int titleResId = hasBrowserActionsNotification()
+                ? R.string.browser_actions_multi_links_open_notification_title
+                : R.string.browser_actions_single_link_open_notification_title;
+        builder.setContentTitle(mContext.getString(titleResId));
+        Intent intent = buildNotificationIntent();
+        PendingIntent notifyPendingIntent =
+                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        builder.setContentIntent(notifyPendingIntent);
+        return builder;
+    }
+
+    private Intent buildNotificationIntent() {
+        Intent intent = new Intent(mContext, ChromeLauncherActivity.class);
+        intent.setAction(ACTION_BROWSER_ACTIONS_OPEN_IN_BACKGROUND);
+        intent.putExtra(EXTRA_IS_SINGLE_URL, !hasBrowserActionsNotification());
+        return intent;
+    }
+
+    private boolean hasBrowserActionsNotification() {
+        return mSharedPreferences.getBoolean(PREF_HAS_BROWSER_ACTIONS_NOTIFICATION, false);
+    }
 
     /**
      * Builds a {@link BrowserActionsContextMenuItemDelegate} instance.
      */
     public BrowserActionsContextMenuItemDelegate() {
         mContext = ContextUtils.getApplicationContext();
+        mNotificationManager =
+                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        mSharedPreferences = ContextUtils.getAppSharedPreferences();
     }
 
     /**
@@ -66,7 +136,12 @@
      * Called when the {@code linkUrl} should be opened in Chrome in the background.
      * @param linkUrl The url to open.
      */
-    public void onOpenInBackground(String linkUrl) {}
+    public void onOpenInBackground(String linkUrl) {
+        sendBrowserActionsNotification();
+        Toast.makeText(mContext, R.string.browser_actions_open_in_background_toast_message,
+                     Toast.LENGTH_SHORT)
+                .show();
+    }
 
     /**
      * Called when a custom item of Browser action menu is selected.
@@ -91,4 +166,43 @@
      * @param linkUrl The url to share.
      */
     public void share(String linkUrl) {}
+
+    /**
+     * Cancel Browser Actions notification.
+     */
+    public static void cancelBrowserActionsNotification() {
+        NotificationManager notificationManager =
+                (NotificationManager) ContextUtils.getApplicationContext().getSystemService(
+                        Context.NOTIFICATION_SERVICE);
+        notificationManager.cancel(NotificationConstants.NOTIFICATION_ID_BROWSER_ACTIONS);
+        ContextUtils.getAppSharedPreferences()
+                .edit()
+                .putBoolean(
+                        BrowserActionsContextMenuItemDelegate.PREF_HAS_BROWSER_ACTIONS_NOTIFICATION,
+                        false)
+                .apply();
+    }
+
+    /**
+     * Checks whether Chrome should display tab switcher via Browser Actions Intent.
+     * @param intent The intent to open the Chrome.
+     * @param isOverviewVisible Whether tab switcher is shown.
+     */
+    public static boolean toggleOverviewByBrowserActions(Intent intent, boolean isOverviewVisible) {
+        boolean fromBrowserActions = isStartedByBrowserActions(intent);
+        boolean isSingleUrl = IntentUtils.safeGetBooleanExtra(
+                intent, BrowserActionsContextMenuItemDelegate.EXTRA_IS_SINGLE_URL, false);
+        if (fromBrowserActions) {
+            return isSingleUrl == isOverviewVisible;
+        }
+        return false;
+    }
+
+    private static boolean isStartedByBrowserActions(Intent intent) {
+        if (BrowserActionsContextMenuItemDelegate.ACTION_BROWSER_ACTIONS_OPEN_IN_BACKGROUND.equals(
+                    intent.getAction())) {
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
index 5d823ce..a2dca7f1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
@@ -56,6 +56,11 @@
     public static final int NOTIFICATION_ID_PHYSICAL_WEB = 3;
 
     /**
+     * Unique identifier for Browser Actions notification.
+     */
+    public static final int NOTIFICATION_ID_BROWSER_ACTIONS = 4;
+
+    /**
      * Unique identifier for the summary notification for downloads.  Using the ID this summary was
      * going to have before it was migrated here.
      * TODO(dtrainor): Clean up this ID and make sure it's in line with existing id counters without
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
index f74a3eb..e07f398 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -30,7 +30,8 @@
     private static final String TAG = "NotifsUMATracker";
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({DOWNLOAD_FILES, DOWNLOAD_PAGES, CLOSE_INCOGNITO, CONTENT_SUGGESTION, MEDIA_CAPTURE,
-            PHYSICAL_WEB, MEDIA, SITES, SYNC, WEBAPK, SYSTEM_NOTIFICATION_TYPE_BOUNDARY})
+            PHYSICAL_WEB, MEDIA, SITES, SYNC, WEBAPK, BROWSER_ACTIONS,
+            SYSTEM_NOTIFICATION_TYPE_BOUNDARY})
     public @interface SystemNotificationType {}
 
     /*
@@ -53,8 +54,9 @@
     public static final int SITES = 7;
     public static final int SYNC = 8;
     public static final int WEBAPK = 9;
+    public static final int BROWSER_ACTIONS = 10;
 
-    private static final int SYSTEM_NOTIFICATION_TYPE_BOUNDARY = 10;
+    private static final int SYSTEM_NOTIFICATION_TYPE_BOUNDARY = 11;
 
     private static final String LAST_SHOWN_NOTIFICATION_TYPE_KEY =
             "NotificationUmaTracker.LastShownNotificationType";
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 2fd8993c..d3c6a62 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1737,6 +1737,18 @@
       <message name="IDS_BROWSER_ACTIONS_SHARE" desc="Browser Actions menu item to share the url address of the selected link. [CHAR-LIMIT=30]">
         Share...
       </message>
+      <message name="IDS_BROWSER_ACTIONS_OPEN_IN_BACKGROUND_TOAST_MESSAGE" desc="Browser Actions toast message when to open a link in new Chrome tab in the backgoround. [CHAR-LIMIT=30]">
+        Link opened in Chrome
+      </message>
+      <message name="IDS_BROWSER_ACTIONS_SINGLE_LINK_OPEN_NOTIFICATION_TITLE" desc="Content title displayed in the notification when one link is opened in the background from Browser Actions. [CHAR-LIMIT=30]">
+        Link opened in Chrome
+      </message>
+      <message name="IDS_BROWSER_ACTIONS_MULTI_LINKS_OPEN_NOTIFICATION_TITLE" desc="Content title displayed in the notification when multiple links are opened in the background from Browser Actions. [CHAR-LIMIT=30]">
+        Multiple links opened in Chrome
+      </message>
+      <message name="IDS_BROWSER_ACTIONS_NOTIFICATION_TEXT" desc="Context text displayed in the notification when links are opened in the background from Browser Actions. [CHAR-LIMIT=30]">
+        Tap to view
+      </message>
 
       <!-- App banner strings -->
       <message name="IDS_APP_BANNER_INSTALLING" desc="Button text indicating that an application is being installed. [CHAR-LIMIT=25]">
diff --git a/chrome/app/bookmarks_strings.grdp b/chrome/app/bookmarks_strings.grdp
index a4c5b40..d6d070a 100644
--- a/chrome/app/bookmarks_strings.grdp
+++ b/chrome/app/bookmarks_strings.grdp
@@ -200,16 +200,16 @@
   <message name="IDS_BOOKMARK_AX_BUBBLE_PAGE_BOOKMARK" desc="Title of the bubble when re-clicking on a bookmark, read by spoken feedback">
     Edit bookmark
   </message>
-  <message name="IDS_BOOKMARK_BUBBLE_TITLE_TEXT" desc="Text preceding the title of the page that was bookmarked">
+  <message name="IDS_BOOKMARK_BUBBLE_NAME_LABEL" desc="Text preceding the title of the page that was bookmarked">
     Name:
   </message>
-  <message name="IDS_BOOKMARK_AX_BUBBLE_TITLE_TEXT" desc="Text preceding the title of the page that was bookmarked, read by spoken feedback">
+  <message name="IDS_BOOKMARK_AX_BUBBLE_NAME_LABEL" desc="Text preceding the title of the page that was bookmarked, read by spoken feedback">
     Bookmark name
   </message>
-  <message name="IDS_BOOKMARK_BUBBLE_FOLDER_TEXT" desc="Text preceding the folder selector">
+  <message name="IDS_BOOKMARK_BUBBLE_FOLDER_LABEL" desc="Text preceding the folder selector">
     Folder:
   </message>
-  <message name="IDS_BOOKMARK_AX_BUBBLE_FOLDER_TEXT" desc="Text preceding the folder selector">
+  <message name="IDS_BOOKMARK_AX_BUBBLE_FOLDER_LABEL" desc="Text preceding the folder selector">
     Bookmark folder
   </message>
   <message name="IDS_BOOKMARK_BUBBLE_OPTIONS" desc="Title of the button the user can click to edit details of the bookmark">
diff --git a/chrome/app/nibs/BookmarkBubble.xib b/chrome/app/nibs/BookmarkBubble.xib
index ddb1618..67b9672 100644
--- a/chrome/app/nibs/BookmarkBubble.xib
+++ b/chrome/app/nibs/BookmarkBubble.xib
@@ -87,7 +87,7 @@
                                     <textField verticalHuggingPriority="750" id="10">
                                         <rect key="frame" x="17" y="6" width="65" height="14"/>
                                         <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
-                                        <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="^IDS_BOOKMARK_BUBBLE_FOLDER_TEXT" id="11">
+                                        <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="^IDS_BOOKMARK_BUBBLE_FOLDER_LABEL" id="11">
                                             <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@@ -96,7 +96,7 @@
                                     <textField verticalHuggingPriority="750" id="8">
                                         <rect key="frame" x="17" y="31" width="65" height="14"/>
                                         <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
-                                        <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="^IDS_BOOKMARK_BUBBLE_TITLE_TEXT" id="9">
+                                        <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="^IDS_BOOKMARK_BUBBLE_NAME_LABEL" id="9">
                                             <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index dd8a2e27..0ae1b11 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -235,6 +235,15 @@
 
 const FeatureEntry::Choice kMarkHttpAsChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
+    {flag_descriptions::kMarkHttpAsNonSecureAfterEditing,
+     security_state::switches::kMarkHttpAs,
+     security_state::switches::kMarkHttpAsNonSecureAfterEditing},
+    {flag_descriptions::kMarkHttpAsNonSecureWhileIncognito,
+     security_state::switches::kMarkHttpAs,
+     security_state::switches::kMarkHttpAsNonSecureWhileIncognito},
+    {flag_descriptions::kMarkHttpAsNonSecureWhileIncognitoOrEditing,
+     security_state::switches::kMarkHttpAs,
+     security_state::switches::kMarkHttpAsNonSecureWhileIncognitoOrEditing},
     {flag_descriptions::kMarkHttpAsDangerous,
      security_state::switches::kMarkHttpAs,
      security_state::switches::kMarkHttpAsDangerous}};
@@ -1851,6 +1860,13 @@
      kOsDesktop,
      SINGLE_VALUE_TYPE(
          switches::kEnableMessageCenterAlwaysScrollUpUponNotificationRemoval)},
+    {"enable-message-center-new-style-notification",
+     flag_descriptions::kMessageCenterNewStyleNotificationName,
+     flag_descriptions::kMessageCenterNewStyleNotificationDescription,
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(
+         switches::kEnableMessageCenterNewStyleNotification,
+         switches::kDisableMessageCenterNewStyleNotification)},
 #endif  // !OS_ANDROID
     {"enable-md-policy-page",
      flag_descriptions::kEnableMaterialDesignPolicyPageName,
diff --git a/chrome/browser/background_sync/background_sync_permission_context.cc b/chrome/browser/background_sync/background_sync_permission_context.cc
index 84350dd..74a48d9 100644
--- a/chrome/browser/background_sync/background_sync_permission_context.cc
+++ b/chrome/browser/background_sync/background_sync_permission_context.cc
@@ -10,7 +10,8 @@
 BackgroundSyncPermissionContext::BackgroundSyncPermissionContext(
     Profile* profile)
     : PermissionContextBase(profile,
-                            CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC) {}
+                            CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC,
+                            blink::WebFeaturePolicyFeature::kNotFound) {}
 
 void BackgroundSyncPermissionContext::CancelPermissionRequest(
     content::WebContents* web_contents,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 10c3cc3..f22e7aa 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -977,6 +977,8 @@
     "login/ui/user_adding_screen_input_methods_controller.h",
     "login/ui/web_contents_forced_title.cc",
     "login/ui/web_contents_forced_title.h",
+    "login/ui/web_contents_set_background_color.cc",
+    "login/ui/web_contents_set_background_color.h",
     "login/ui/webui_login_display.cc",
     "login/ui/webui_login_display.h",
     "login/ui/webui_login_view.cc",
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
index 3137e46f..7fbfb56e 100644
--- a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
@@ -62,9 +62,9 @@
   callback_ = callback;
   dm_token_storage_ = base::MakeUnique<policy::DMTokenStorage>(
       g_browser_process->local_state());
-  dm_token_storage_->RetrieveDMToken(
-      base::Bind(&ArcActiveDirectoryEnrollmentTokenFetcher::OnDMTokenAvailable,
-                 weak_ptr_factory_.GetWeakPtr()));
+  dm_token_storage_->RetrieveDMToken(base::BindOnce(
+      &ArcActiveDirectoryEnrollmentTokenFetcher::OnDMTokenAvailable,
+      weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ArcActiveDirectoryEnrollmentTokenFetcher::OnDMTokenAvailable(
@@ -220,8 +220,8 @@
   if (close_saml_page) {
     content::BrowserThread::PostTask(
         content::BrowserThread::UI, FROM_HERE,
-        base::Bind(&chrome::CloseWebContents, browser_, web_contents,
-                   false /* add_to_history */));
+        base::BindOnce(&chrome::CloseWebContents, browser_, web_contents,
+                       false /* add_to_history */));
   }
   browser_ = nullptr;
 }
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
index ed82bb6..2f7d5e4 100644
--- a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
@@ -213,8 +213,8 @@
                                 net::NetworkDelegate* network_delegate) {
   content::BrowserThread::PostTask(
       content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&TabStripModel::CloseSelectedTabs,
-                 base::Unretained(browser->tab_strip_model())));
+      base::BindOnce(&TabStripModel::CloseSelectedTabs,
+                     base::Unretained(browser->tab_strip_model())));
 
   return nullptr;
 }
@@ -291,7 +291,7 @@
     auto dm_token_storage = base::MakeUnique<policy::DMTokenStorage>(
         g_browser_process->local_state());
     dm_token_storage->StoreDMToken(
-        kFakeDmToken, base::Bind(
+        kFakeDmToken, base::BindOnce(
                           [](base::RunLoop* run_loop, bool success) {
                             EXPECT_TRUE(success);
                             run_loop->Quit();
diff --git a/chrome/browser/chromeos/arc/downloads_watcher/arc_downloads_watcher_service.cc b/chrome/browser/chromeos/arc/downloads_watcher/arc_downloads_watcher_service.cc
index f57671f..3717476 100644
--- a/chrome/browser/chromeos/arc/downloads_watcher/arc_downloads_watcher_service.cc
+++ b/chrome/browser/chromeos/arc/downloads_watcher/arc_downloads_watcher_service.cc
@@ -266,8 +266,8 @@
     outstanding_task_ = true;
     BrowserThread::PostDelayedTask(
         BrowserThread::FILE, FROM_HERE,
-        base::Bind(&DownloadsWatcher::DelayBuildTimestampMap,
-                   weak_ptr_factory_.GetWeakPtr()),
+        base::BindOnce(&DownloadsWatcher::DelayBuildTimestampMap,
+                       weak_ptr_factory_.GetWeakPtr()),
         kBuildTimestampMapDelay);
   } else {
     last_notify_time_ = base::TimeTicks::Now();
@@ -301,7 +301,7 @@
   }
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(callback_, base::Passed(std::move(string_paths))));
+      base::BindOnce(callback_, base::Passed(std::move(string_paths))));
   if (last_notify_time_ > snapshot_time)
     DelayBuildTimestampMap();
   else
@@ -339,9 +339,9 @@
   watcher_ = base::MakeUnique<DownloadsWatcher>(
       base::Bind(&ArcDownloadsWatcherService::OnDownloadsChanged,
                  weak_ptr_factory_.GetWeakPtr()));
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&DownloadsWatcher::Start, base::Unretained(watcher_.get())));
+  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                          base::BindOnce(&DownloadsWatcher::Start,
+                                         base::Unretained(watcher_.get())));
 }
 
 void ArcDownloadsWatcherService::StopWatchingDownloads() {
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.cc
index 1a142f3f..b267fb3 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.cc
@@ -44,7 +44,7 @@
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(callback, base::Passed(base::File()), base::Closure()));
+      base::BindOnce(callback, base::Passed(base::File()), base::Closure()));
 }
 
 void ArcContentFileSystemAsyncFileUtil::EnsureFileExists(
@@ -53,7 +53,8 @@
     const EnsureFileExistsCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED, false));
+      FROM_HERE,
+      base::BindOnce(callback, base::File::FILE_ERROR_FAILED, false));
 }
 
 void ArcContentFileSystemAsyncFileUtil::CreateDirectory(
@@ -64,7 +65,7 @@
     const StatusCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED));
 }
 
 void ArcContentFileSystemAsyncFileUtil::GetFileInfo(
@@ -83,8 +84,8 @@
     const ReadDirectoryCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, base::File::FILE_ERROR_FAILED, EntryList(), false));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED,
+                                EntryList(), false));
 }
 
 void ArcContentFileSystemAsyncFileUtil::Touch(
@@ -95,7 +96,7 @@
     const StatusCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED));
 }
 
 void ArcContentFileSystemAsyncFileUtil::Truncate(
@@ -105,7 +106,7 @@
     const StatusCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED));
 }
 
 void ArcContentFileSystemAsyncFileUtil::CopyFileLocal(
@@ -117,7 +118,7 @@
     const StatusCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED));
 }
 
 void ArcContentFileSystemAsyncFileUtil::MoveFileLocal(
@@ -128,7 +129,7 @@
     const StatusCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED));
 }
 
 void ArcContentFileSystemAsyncFileUtil::CopyInForeignFile(
@@ -138,7 +139,7 @@
     const StatusCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED));
 }
 
 void ArcContentFileSystemAsyncFileUtil::DeleteFile(
@@ -147,7 +148,7 @@
     const StatusCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED));
 }
 
 void ArcContentFileSystemAsyncFileUtil::DeleteDirectory(
@@ -156,7 +157,7 @@
     const StatusCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED));
 }
 
 void ArcContentFileSystemAsyncFileUtil::DeleteRecursively(
@@ -165,7 +166,7 @@
     const StatusCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+      FROM_HERE, base::BindOnce(callback, base::File::FILE_ERROR_FAILED));
 }
 
 void ArcContentFileSystemAsyncFileUtil::CreateSnapshotFile(
@@ -174,9 +175,10 @@
     const CreateSnapshotFileCallback& callback) {
   NOTIMPLEMENTED();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED,
-                            base::File::Info(), base::FilePath(),
-                            scoped_refptr<storage::ShareableFileReference>()));
+      FROM_HERE,
+      base::BindOnce(callback, base::File::FILE_ERROR_FAILED,
+                     base::File::Info(), base::FilePath(),
+                     scoped_refptr<storage::ShareableFileReference>()));
 }
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
index 401d439..7ba4f61f 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
@@ -51,7 +51,8 @@
   // Use the task runner to destruct |file_| after the completion of all
   // in-flight operations.
   task_runner_->PostTask(
-      FROM_HERE, base::Bind(&base::DeletePointer<base::File>, file_.release()));
+      FROM_HERE,
+      base::BindOnce(&base::DeletePointer<base::File>, file_.release()));
 }
 
 int ArcContentFileSystemFileStreamReader::Read(
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.cc b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.cc
index d597e1ae..77bcfeb 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.cc
@@ -98,7 +98,7 @@
       arc_bridge_service()->file_system(), GetFileSize);
   if (!file_system_instance) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  base::Bind(callback, -1));
+                                                  base::BindOnce(callback, -1));
     return;
   }
   file_system_instance->GetFileSize(url.spec(), callback);
@@ -118,7 +118,8 @@
       arc_bridge_service()->file_system(), OpenFileToRead);
   if (!file_system_instance) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, base::Passed(mojo::ScopedHandle())));
+        FROM_HERE,
+        base::BindOnce(callback, base::Passed(mojo::ScopedHandle())));
     return;
   }
   file_system_instance->OpenFileToRead(url.spec(), callback);
@@ -139,7 +140,8 @@
       arc_bridge_service()->file_system(), GetDocument);
   if (!file_system_instance) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, base::Passed(mojom::DocumentPtr())));
+        FROM_HERE,
+        base::BindOnce(callback, base::Passed(mojom::DocumentPtr())));
     return;
   }
   file_system_instance->GetDocument(authority, document_id, callback);
@@ -161,7 +163,7 @@
       arc_bridge_service()->file_system(), GetChildDocuments);
   if (!file_system_instance) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, base::nullopt));
+        FROM_HERE, base::BindOnce(callback, base::nullopt));
     return;
   }
   file_system_instance->GetChildDocuments(authority, parent_document_id,
@@ -185,7 +187,7 @@
       arc_bridge_service()->file_system(), AddWatcher);
   if (!file_system_instance) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  base::Bind(callback, -1));
+                                                  base::BindOnce(callback, -1));
     return;
   }
   file_system_instance->AddWatcher(
@@ -201,8 +203,8 @@
   // RemoveWatcher() is never deferred since watchers do not persist across
   // container reboots.
   if (should_defer_) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  base::Bind(callback, false));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(callback, false));
     return;
   }
 
@@ -211,8 +213,8 @@
   // users must not assume registered callbacks are immediately invalidated.
   auto iter = watcher_callbacks_.find(watcher_id);
   if (iter == watcher_callbacks_.end()) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  base::Bind(callback, false));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(callback, false));
     return;
   }
   watcher_callbacks_.erase(iter);
@@ -220,8 +222,8 @@
   auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD(
       arc_bridge_service()->file_system(), AddWatcher);
   if (!file_system_instance) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  base::Bind(callback, false));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(callback, false));
     return;
   }
   file_system_instance->RemoveWatcher(watcher_id, callback);
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.cc b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.cc
index 4cbb0b5..424894bfd 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.cc
@@ -24,7 +24,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
-      base::Bind(callback, base::Passed(std::move(result))));
+      base::BindOnce(callback, base::Passed(std::move(result))));
 }
 
 void GetFileSizeOnUIThread(const GURL& url,
@@ -156,7 +156,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
-      base::Bind(&ObserverIOThreadWrapper::OnWatchersClearedOnIOThread, this));
+      base::BindOnce(&ObserverIOThreadWrapper::OnWatchersClearedOnIOThread,
+                     this));
 }
 
 void ObserverIOThreadWrapper::OnWatchersClearedOnIOThread() {
@@ -171,8 +172,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&GetFileSizeOnUIThread, url,
-                 base::Bind(&PostToIOThread<int64_t>, callback)));
+      base::BindOnce(&GetFileSizeOnUIThread, url,
+                     base::Bind(&PostToIOThread<int64_t>, callback)));
 }
 
 void OpenFileToReadOnIOThread(const GURL& url,
@@ -180,8 +181,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&OpenFileToReadOnUIThread, url,
-                 base::Bind(&PostToIOThread<mojo::ScopedHandle>, callback)));
+      base::BindOnce(
+          &OpenFileToReadOnUIThread, url,
+          base::Bind(&PostToIOThread<mojo::ScopedHandle>, callback)));
 }
 
 void GetDocumentOnIOThread(const std::string& authority,
@@ -190,8 +192,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&GetDocumentOnUIThread, authority, document_id,
-                 base::Bind(&PostToIOThread<mojom::DocumentPtr>, callback)));
+      base::BindOnce(
+          &GetDocumentOnUIThread, authority, document_id,
+          base::Bind(&PostToIOThread<mojom::DocumentPtr>, callback)));
 }
 
 void GetChildDocumentsOnIOThread(const std::string& authority,
@@ -200,7 +203,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(
+      base::BindOnce(
           &GetChildDocumentsOnUIThread, authority, parent_document_id,
           base::Bind(
               &PostToIOThread<base::Optional<std::vector<mojom::DocumentPtr>>>,
@@ -214,7 +217,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(
+      base::BindOnce(
           &AddWatcherOnUIThread, authority, document_id,
           base::Bind(&PostToIOThread<ArcFileSystemOperationRunner::ChangeType>,
                      watcher_callback),
@@ -226,14 +229,14 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&RemoveWatcherOnUIThread, watcher_id,
-                 base::Bind(&PostToIOThread<bool>, callback)));
+      base::BindOnce(&RemoveWatcherOnUIThread, watcher_id,
+                     base::Bind(&PostToIOThread<bool>, callback)));
 }
 
 void AddObserverOnIOThread(scoped_refptr<ObserverIOThreadWrapper> observer) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-                          base::Bind(&AddObserverOnUIThread, observer));
+                          base::BindOnce(&AddObserverOnUIThread, observer));
 }
 
 void RemoveObserverOnIOThread(scoped_refptr<ObserverIOThreadWrapper> observer) {
@@ -242,7 +245,7 @@
   // called after this function returns.
   observer->Disable();
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-                          base::Bind(&RemoveObserverOnUIThread, observer));
+                          base::BindOnce(&RemoveObserverOnUIThread, observer));
 }
 
 }  // namespace file_system_operation_runner_util
diff --git a/chrome/browser/chromeos/arc/policy/arc_android_management_checker.cc b/chrome/browser/chromeos/arc/policy/arc_android_management_checker.cc
index d95bb86f..5dfe3be 100644
--- a/chrome/browser/chromeos/arc/policy/arc_android_management_checker.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_android_management_checker.cc
@@ -134,8 +134,9 @@
   VLOG(2) << "Schedule next android management check in " << retry_delay_;
 
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&ArcAndroidManagementChecker::StartCheckInternal,
-                            weak_ptr_factory_.GetWeakPtr()),
+      FROM_HERE,
+      base::BindOnce(&ArcAndroidManagementChecker::StartCheckInternal,
+                     weak_ptr_factory_.GetWeakPtr()),
       retry_delay_);
   retry_delay_ = std::min(retry_delay_ * 2, kRetryDelayMax);
 }
diff --git a/chrome/browser/chromeos/arc/process/arc_process_service.cc b/chrome/browser/chromeos/arc/process/arc_process_service.cc
index ec6e417..e406736 100644
--- a/chrome/browser/chromeos/arc/process/arc_process_service.cc
+++ b/chrome/browser/chromeos/arc/process/arc_process_service.cc
@@ -273,7 +273,7 @@
 
 void ArcProcessService::OnInstanceReady() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  task_runner_->PostTask(FROM_HERE, base::Bind(&Reset, nspid_to_pid_));
+  task_runner_->PostTask(FROM_HERE, base::BindOnce(&Reset, nspid_to_pid_));
   instance_ready_ = true;
 }
 
diff --git a/chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.cc b/chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.cc
index 73004ea..be3ede1 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.cc
@@ -78,8 +78,8 @@
   if (!tracing_instance) {
     // Use PostTask as the convention of TracingAgent. The caller expects
     // callback to be called after this function returns.
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  base::Bind(callback, false));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(callback, false));
     return;
   }
 
@@ -100,8 +100,8 @@
   mojom::TracingInstance* tracing_instance =
       ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service()->tracing(), StopTracing);
   if (!tracing_instance) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  base::Bind(callback, false));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(callback, false));
     return;
   }
   tracing_instance->StopTracing(callback);
diff --git a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc
index 45066a60..43a9ab4 100644
--- a/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc
+++ b/chrome/browser/chromeos/arc/video/gpu_arc_video_service_host.cc
@@ -40,8 +40,8 @@
   void Create(mojom::VideoAcceleratorServiceRequest request) override {
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&ConnectToVideoAcceleratorServiceOnIOThread,
-                   base::Passed(&request)));
+        base::BindOnce(&ConnectToVideoAcceleratorServiceOnIOThread,
+                       base::Passed(&request)));
   }
 
  private:
diff --git a/ui/views/controls/webview/web_contents_set_background_color.cc b/chrome/browser/chromeos/login/ui/web_contents_set_background_color.cc
similarity index 85%
rename from ui/views/controls/webview/web_contents_set_background_color.cc
rename to chrome/browser/chromeos/login/ui/web_contents_set_background_color.cc
index e5de0e42..6b57011 100644
--- a/ui/views/controls/webview/web_contents_set_background_color.cc
+++ b/chrome/browser/chromeos/login/ui/web_contents_set_background_color.cc
@@ -1,17 +1,17 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// 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 "ui/views/controls/webview/web_contents_set_background_color.h"
+#include "chrome/browser/chromeos/login/ui/web_contents_set_background_color.h"
 
 #include "base/memory/ptr_util.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(views::WebContentsSetBackgroundColor);
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(chromeos::WebContentsSetBackgroundColor);
 
-namespace views {
+namespace chromeos {
 
 // static
 void WebContentsSetBackgroundColor::CreateForWebContentsWithColor(
@@ -54,4 +54,4 @@
   new_host->GetWidget()->GetView()->SetBackgroundColor(color_);
 }
 
-}  // namespace views
+}  // namespace chromeos
diff --git a/ui/views/controls/webview/web_contents_set_background_color.h b/chrome/browser/chromeos/login/ui/web_contents_set_background_color.h
similarity index 72%
rename from ui/views/controls/webview/web_contents_set_background_color.h
rename to chrome/browser/chromeos/login/ui/web_contents_set_background_color.h
index e10a3a3..024d310 100644
--- a/ui/views/controls/webview/web_contents_set_background_color.h
+++ b/chrome/browser/chromeos/login/ui/web_contents_set_background_color.h
@@ -2,17 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_VIEWS_CONTROLS_WEBVIEW_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_
-#define UI_VIEWS_CONTROLS_WEBVIEW_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_UI_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_UI_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_
 
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
-#include "ui/views/controls/webview/webview_export.h"
 
 // Defined in SkColor.h (32-bit ARGB color).
 using SkColor = unsigned int;
 
-namespace views {
+namespace chromeos {
 
 // Ensures that the background color of a given WebContents instance is always
 // set to a given color value.
@@ -20,9 +19,8 @@
     : public content::WebContentsObserver,
       public content::WebContentsUserData<WebContentsSetBackgroundColor> {
  public:
-  WEBVIEW_EXPORT static void CreateForWebContentsWithColor(
-      content::WebContents* web_contents,
-      SkColor color);
+  static void CreateForWebContentsWithColor(content::WebContents* web_contents,
+                                            SkColor color);
 
   ~WebContentsSetBackgroundColor() override;
 
@@ -41,6 +39,6 @@
   DISALLOW_COPY_AND_ASSIGN(WebContentsSetBackgroundColor);
 };
 
-}  // namespace views
+}  // namespace chromeos
 
-#endif  // UI_VIEWS_CONTROLS_WEBVIEW_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_UI_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc
index 78e038c8..89d498d 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/chromeos/login/ui/preloaded_web_view_factory.h"
 #include "chrome/browser/chromeos/login/ui/proxy_settings_dialog.h"
 #include "chrome/browser/chromeos/login/ui/web_contents_forced_title.h"
+#include "chrome/browser/chromeos/login/ui/web_contents_set_background_color.h"
 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
@@ -56,7 +57,6 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/keyboard/keyboard_controller.h"
-#include "ui/views/controls/webview/web_contents_set_background_color.h"
 #include "ui/views/controls/webview/webview.h"
 #include "ui/views/widget/widget.h"
 
@@ -220,7 +220,7 @@
   if (!title.empty())
     WebContentsForcedTitle::CreateForWebContentsWithTitle(web_contents, title);
 
-  views::WebContentsSetBackgroundColor::CreateForWebContentsWithColor(
+  WebContentsSetBackgroundColor::CreateForWebContentsWithColor(
       web_contents, SK_ColorTRANSPARENT);
 
   // Ensure that the login UI has a tab ID, which will allow the GAIA auth
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index c8a324b7..056ca964 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -171,8 +171,13 @@
 const char kMarkHttpAsName[] = "Mark non-secure origins as non-secure";
 
 const char kMarkHttpAsDescription[] = "Change the UI treatment for HTTP pages";
-
 const char kMarkHttpAsDangerous[] = "Always mark HTTP as actively dangerous";
+const char kMarkHttpAsNonSecureAfterEditing[] =
+    "Warn on HTTP after editing forms";
+const char kMarkHttpAsNonSecureWhileIncognito[] =
+    "Warn on HTTP while in Incognito mode";
+const char kMarkHttpAsNonSecureWhileIncognitoOrEditing[] =
+    "Warn on HTTP while in Incognito mode or after editing forms";
 
 //  Material design of the Incognito NTP.
 
@@ -2056,6 +2061,11 @@
     "Enables experiment that message center always scroll up when a "
     "notification is removed.";
 
+const char kMessageCenterNewStyleNotificationName[] = "New style notification";
+
+const char kMessageCenterNewStyleNotificationDescription[] =
+    "Enables the experiment style of material-design notification";
+
 const char kCastStreamingHwEncodingName[] =
     "Cast Streaming hardware video encoding";
 
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index c2df124f..d9e11a9 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -427,6 +427,9 @@
 extern const char kMarkHttpAsName[];
 extern const char kMarkHttpAsDescription[];
 extern const char kMarkHttpAsDangerous[];
+extern const char kMarkHttpAsNonSecureAfterEditing[];
+extern const char kMarkHttpAsNonSecureWhileIncognito[];
+extern const char kMarkHttpAsNonSecureWhileIncognitoOrEditing[];
 
 extern const char kMaterialDesignIncognitoNTPName[];
 extern const char kMaterialDesignIncognitoNTPDescription[];
@@ -440,6 +443,9 @@
 extern const char kMemoryCoordinatorName[];
 extern const char kMemoryCoordinatorDescription[];
 
+extern const char kMessageCenterNewStyleNotificationName[];
+extern const char kMessageCenterNewStyleNotificationDescription[];
+
 extern const char kMessageCenterAlwaysScrollUpUponRemovalName[];
 extern const char kMessageCenterAlwaysScrollUpUponRemovalDescription[];
 
diff --git a/chrome/browser/geolocation/geolocation_permission_context.cc b/chrome/browser/geolocation/geolocation_permission_context.cc
index 0283b6c..20358af 100644
--- a/chrome/browser/geolocation/geolocation_permission_context.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context.cc
@@ -16,7 +16,8 @@
 
 GeolocationPermissionContext::GeolocationPermissionContext(Profile* profile)
     : PermissionContextBase(profile,
-                            CONTENT_SETTINGS_TYPE_GEOLOCATION),
+                            CONTENT_SETTINGS_TYPE_GEOLOCATION,
+                            blink::WebFeaturePolicyFeature::kGeolocation),
       extensions_context_(profile) {}
 
 GeolocationPermissionContext::~GeolocationPermissionContext() {
diff --git a/chrome/browser/media/midi_permission_context.cc b/chrome/browser/media/midi_permission_context.cc
index 7e880138..f137ee5 100644
--- a/chrome/browser/media/midi_permission_context.cc
+++ b/chrome/browser/media/midi_permission_context.cc
@@ -5,7 +5,9 @@
 #include "chrome/browser/media/midi_permission_context.h"
 
 MidiPermissionContext::MidiPermissionContext(Profile* profile)
-    : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_MIDI) {}
+    : PermissionContextBase(profile,
+                            CONTENT_SETTINGS_TYPE_MIDI,
+                            blink::WebFeaturePolicyFeature::kMidiFeature) {}
 
 MidiPermissionContext::~MidiPermissionContext() {
 }
diff --git a/chrome/browser/media/midi_sysex_permission_context.cc b/chrome/browser/media/midi_sysex_permission_context.cc
index 689e141a..a09accf 100644
--- a/chrome/browser/media/midi_sysex_permission_context.cc
+++ b/chrome/browser/media/midi_sysex_permission_context.cc
@@ -10,7 +10,9 @@
 #include "url/gurl.h"
 
 MidiSysexPermissionContext::MidiSysexPermissionContext(Profile* profile)
-    : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {}
+    : PermissionContextBase(profile,
+                            CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
+                            blink::WebFeaturePolicyFeature::kMidiFeature) {}
 
 MidiSysexPermissionContext::~MidiSysexPermissionContext() {}
 
diff --git a/chrome/browser/media/protected_media_identifier_permission_context.cc b/chrome/browser/media/protected_media_identifier_permission_context.cc
index ebaa354..7fd089b 100644
--- a/chrome/browser/media/protected_media_identifier_permission_context.cc
+++ b/chrome/browser/media/protected_media_identifier_permission_context.cc
@@ -41,7 +41,8 @@
 ProtectedMediaIdentifierPermissionContext::
     ProtectedMediaIdentifierPermissionContext(Profile* profile)
     : PermissionContextBase(profile,
-                            CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER)
+                            CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
+                            blink::WebFeaturePolicyFeature::kEme)
 #if defined(OS_CHROMEOS)
       ,
       weak_factory_(this)
diff --git a/chrome/browser/media/webrtc/media_stream_device_permission_context.cc b/chrome/browser/media/webrtc/media_stream_device_permission_context.cc
index d31aeda..7a8813f03 100644
--- a/chrome/browser/media/webrtc/media_stream_device_permission_context.cc
+++ b/chrome/browser/media/webrtc/media_stream_device_permission_context.cc
@@ -14,10 +14,25 @@
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
 
+namespace {
+
+blink::WebFeaturePolicyFeature GetFeaturePolicyFeature(
+    ContentSettingsType type) {
+  if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)
+    return blink::WebFeaturePolicyFeature::kMicrophone;
+
+  DCHECK_EQ(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, type);
+  return blink::WebFeaturePolicyFeature::kCamera;
+}
+
+}  // namespace
+
 MediaStreamDevicePermissionContext::MediaStreamDevicePermissionContext(
     Profile* profile,
     const ContentSettingsType content_settings_type)
-    : PermissionContextBase(profile, content_settings_type),
+    : PermissionContextBase(profile,
+                            content_settings_type,
+                            GetFeaturePolicyFeature(content_settings_type)),
       content_settings_type_(content_settings_type) {
   DCHECK(content_settings_type_ == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
          content_settings_type_ == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
diff --git a/chrome/browser/notifications/notification_permission_context.cc b/chrome/browser/notifications/notification_permission_context.cc
index 261d3c62..a159d69 100644
--- a/chrome/browser/notifications/notification_permission_context.cc
+++ b/chrome/browser/notifications/notification_permission_context.cc
@@ -159,7 +159,9 @@
 NotificationPermissionContext::NotificationPermissionContext(
     Profile* profile,
     ContentSettingsType content_settings_type)
-    : PermissionContextBase(profile, content_settings_type),
+    : PermissionContextBase(profile,
+                            content_settings_type,
+                            blink::WebFeaturePolicyFeature::kNotFound),
       weak_factory_ui_thread_(this) {
   DCHECK(content_settings_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS ||
          content_settings_type == CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc
index 35af53f..3f263c4 100644
--- a/chrome/browser/permissions/permission_context_base.cc
+++ b/chrome/browser/permissions/permission_context_base.cc
@@ -35,6 +35,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/origin_util.h"
 #include "extensions/common/constants.h"
 #include "url/gurl.h"
@@ -83,9 +84,11 @@
 
 PermissionContextBase::PermissionContextBase(
     Profile* profile,
-    const ContentSettingsType content_settings_type)
+    ContentSettingsType content_settings_type,
+    blink::WebFeaturePolicyFeature feature_policy_feature)
     : profile_(profile),
       content_settings_type_(content_settings_type),
+      feature_policy_feature_(feature_policy_feature),
       weak_factory_(this) {
 #if defined(OS_ANDROID)
   permission_queue_controller_.reset(
@@ -244,6 +247,14 @@
     }
   }
 
+  // Check whether the feature is enabled for the frame by feature policy. We
+  // can only do this when a RenderFrameHost has been provided.
+  if (render_frame_host &&
+      !PermissionAllowedByFeaturePolicy(render_frame_host)) {
+    return PermissionResult(CONTENT_SETTING_BLOCK,
+                            PermissionStatusSource::UNSPECIFIED);
+  }
+
   ContentSetting content_setting = GetPermissionStatusInternal(
       render_frame_host, requesting_origin, embedding_origin);
   if (content_setting == CONTENT_SETTING_ASK) {
@@ -463,3 +474,18 @@
     return CONTENT_SETTINGS_TYPE_NOTIFICATIONS;
   return content_settings_type_;
 }
+
+bool PermissionContextBase::PermissionAllowedByFeaturePolicy(
+    content::RenderFrameHost* rfh) const {
+  if (!base::FeatureList::IsEnabled(
+          features::kUseFeaturePolicyForPermissions)) {
+    // Default to ignoring the feature policy.
+    return true;
+  }
+
+  // Some features don't have an associated feature policy yet. Allow those.
+  if (feature_policy_feature_ == blink::WebFeaturePolicyFeature::kNotFound)
+    return true;
+
+  return rfh->IsFeatureEnabled(feature_policy_feature_);
+}
diff --git a/chrome/browser/permissions/permission_context_base.h b/chrome/browser/permissions/permission_context_base.h
index 72ef40ee..e50a900b 100644
--- a/chrome/browser/permissions/permission_context_base.h
+++ b/chrome/browser/permissions/permission_context_base.h
@@ -16,6 +16,7 @@
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "third_party/WebKit/public/platform/WebFeaturePolicyFeature.h"
 
 #if defined(OS_ANDROID)
 class PermissionQueueController;
@@ -58,7 +59,8 @@
 class PermissionContextBase : public KeyedService {
  public:
   PermissionContextBase(Profile* profile,
-                        const ContentSettingsType content_settings_type);
+                        ContentSettingsType content_settings_type,
+                        blink::WebFeaturePolicyFeature feature_policy_feature);
   ~PermissionContextBase() override;
 
   // A field trial used to enable the global permissions kill switch.
@@ -180,6 +182,8 @@
  private:
   friend class PermissionContextBaseTests;
 
+  bool PermissionAllowedByFeaturePolicy(content::RenderFrameHost* rfh) const;
+
   // Called when a request is no longer used so it can be cleaned up.
   void CleanUpRequest(const PermissionRequestID& id);
 
@@ -204,6 +208,7 @@
 
   Profile* profile_;
   const ContentSettingsType content_settings_type_;
+  const blink::WebFeaturePolicyFeature feature_policy_feature_;
 #if defined(OS_ANDROID)
   std::unique_ptr<PermissionQueueController> permission_queue_controller_;
 #endif
diff --git a/chrome/browser/permissions/permission_context_base_feature_policy_unittest.cc b/chrome/browser/permissions/permission_context_base_feature_policy_unittest.cc
new file mode 100644
index 0000000..0029ba5
--- /dev/null
+++ b/chrome/browser/permissions/permission_context_base_feature_policy_unittest.cc
@@ -0,0 +1,178 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/geolocation/geolocation_permission_context.h"
+#include "chrome/browser/media/midi_permission_context.h"
+#include "chrome/browser/notifications/notification_permission_context.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "third_party/WebKit/public/platform/WebFeaturePolicyFeature.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+// Integration tests for querying permissions that have a feature policy set.
+// These tests are not meant to cover every edge case as the FeaturePolicy class
+// itself is tested thoroughly in feature_policy_unittest.cc and in
+// render_frame_host_feature_policy_unittest.cc. Instead they are meant to
+// ensure that integration with content::PermissionContextBase works correctly.
+class PermissionContextBaseFeaturePolicyTest
+    : public ChromeRenderViewHostTestHarness {
+ public:
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+    feature_list_.InitAndEnableFeature(
+        features::kUseFeaturePolicyForPermissions);
+  }
+
+ protected:
+  static constexpr const char* kOrigin1 = "https://google.com";
+  static constexpr const char* kOrigin2 = "https://maps.google.com";
+
+  content::RenderFrameHost* GetMainRFH(const char* origin) {
+    content::RenderFrameHost* result = web_contents()->GetMainFrame();
+    content::RenderFrameHostTester::For(result)
+        ->InitializeRenderFrameIfNeeded();
+    SimulateNavigation(&result, GURL(origin));
+    return result;
+  }
+
+  content::RenderFrameHost* AddChildRFH(content::RenderFrameHost* parent,
+                                        const char* origin) {
+    content::RenderFrameHost* result =
+        content::RenderFrameHostTester::For(parent)->AppendChild("");
+    content::RenderFrameHostTester::For(result)
+        ->InitializeRenderFrameIfNeeded();
+    SimulateNavigation(&result, GURL(origin));
+    return result;
+  }
+
+  // The header policy should only be set once on page load, so we refresh the
+  // page to simulate that.
+  void RefreshPageAndSetHeaderPolicy(content::RenderFrameHost** rfh,
+                                     blink::WebFeaturePolicyFeature feature,
+                                     const std::vector<std::string>& origins) {
+    content::RenderFrameHost* current = *rfh;
+    SimulateNavigation(&current, current->GetLastCommittedURL());
+    std::vector<url::Origin> parsed_origins;
+    for (const std::string& origin : origins)
+      parsed_origins.push_back(url::Origin(GURL(origin)));
+    content::RenderFrameHostTester::For(current)->SimulateFeaturePolicyHeader(
+        feature, parsed_origins);
+    *rfh = current;
+  }
+
+  ContentSetting GetPermissionForFrame(PermissionContextBase* pcb,
+                                       content::RenderFrameHost* rfh) {
+    return pcb
+        ->GetPermissionStatus(
+            rfh, rfh->GetLastCommittedURL(),
+            web_contents()->GetMainFrame()->GetLastCommittedURL())
+        .content_setting;
+  }
+
+ private:
+  void SimulateNavigation(content::RenderFrameHost** rfh, const GURL& url) {
+    auto navigation_simulator =
+        content::NavigationSimulator::CreateRendererInitiated(url, *rfh);
+    navigation_simulator->Commit();
+    *rfh = navigation_simulator->GetFinalRenderFrameHost();
+  }
+
+  base::test::ScopedFeatureList feature_list_;
+};
+
+// Feature policy should be ignored when the kUseFeaturePolicyForPermissions
+// feature is disabled.
+TEST_F(PermissionContextBaseFeaturePolicyTest, FeatureDisabled) {
+  // Disable the feature.
+  base::test::ScopedFeatureList feature_list;
+  feature_list.Init();
+
+  content::RenderFrameHost* parent = GetMainRFH(kOrigin1);
+
+  RefreshPageAndSetHeaderPolicy(&parent,
+                                blink::WebFeaturePolicyFeature::kMidiFeature,
+                                std::vector<std::string>());
+  MidiPermissionContext midi(profile());
+  EXPECT_EQ(CONTENT_SETTING_ALLOW, GetPermissionForFrame(&midi, parent));
+
+  RefreshPageAndSetHeaderPolicy(&parent,
+                                blink::WebFeaturePolicyFeature::kGeolocation,
+                                std::vector<std::string>());
+  GeolocationPermissionContext geolocation(profile());
+  EXPECT_EQ(CONTENT_SETTING_ASK, GetPermissionForFrame(&geolocation, parent));
+}
+
+TEST_F(PermissionContextBaseFeaturePolicyTest, DefaultPolicy) {
+  content::RenderFrameHost* parent = GetMainRFH(kOrigin1);
+  content::RenderFrameHost* child = AddChildRFH(parent, kOrigin2);
+
+  // Midi is allowed by default in the top level frame but not in subframes.
+  MidiPermissionContext midi(profile());
+  EXPECT_EQ(CONTENT_SETTING_ALLOW, GetPermissionForFrame(&midi, parent));
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, GetPermissionForFrame(&midi, child));
+
+  // Geolocation is ask by default in top level frames but not in subframes.
+  GeolocationPermissionContext geolocation(profile());
+  EXPECT_EQ(CONTENT_SETTING_ASK, GetPermissionForFrame(&geolocation, parent));
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, GetPermissionForFrame(&geolocation, child));
+
+  // Notifications doesn't have an associated feature policy so it should be ask
+  // by default in top level and subframes.
+  NotificationPermissionContext notifications(
+      profile(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+  EXPECT_EQ(CONTENT_SETTING_ASK, GetPermissionForFrame(&notifications, parent));
+  EXPECT_EQ(CONTENT_SETTING_ASK, GetPermissionForFrame(&notifications, child));
+}
+
+TEST_F(PermissionContextBaseFeaturePolicyTest, DisabledTopLevelFrame) {
+  content::RenderFrameHost* parent = GetMainRFH(kOrigin1);
+
+  // Disable midi in the top level frame.
+  RefreshPageAndSetHeaderPolicy(&parent,
+                                blink::WebFeaturePolicyFeature::kMidiFeature,
+                                std::vector<std::string>());
+  content::RenderFrameHost* child = AddChildRFH(parent, kOrigin2);
+  MidiPermissionContext midi(profile());
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, GetPermissionForFrame(&midi, parent));
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, GetPermissionForFrame(&midi, child));
+
+  // Disable geolocation in the top level frame.
+  RefreshPageAndSetHeaderPolicy(&parent,
+                                blink::WebFeaturePolicyFeature::kGeolocation,
+                                std::vector<std::string>());
+  child = AddChildRFH(parent, kOrigin2);
+  GeolocationPermissionContext geolocation(profile());
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, GetPermissionForFrame(&geolocation, parent));
+  EXPECT_EQ(CONTENT_SETTING_BLOCK, GetPermissionForFrame(&geolocation, child));
+}
+
+TEST_F(PermissionContextBaseFeaturePolicyTest, EnabledForChildFrame) {
+  content::RenderFrameHost* parent = GetMainRFH(kOrigin1);
+
+  // Enable midi for the child frame.
+  RefreshPageAndSetHeaderPolicy(&parent,
+                                blink::WebFeaturePolicyFeature::kMidiFeature,
+                                {kOrigin1, kOrigin2});
+  content::RenderFrameHost* child = AddChildRFH(parent, kOrigin2);
+  MidiPermissionContext midi(profile());
+  EXPECT_EQ(CONTENT_SETTING_ALLOW, GetPermissionForFrame(&midi, parent));
+  EXPECT_EQ(CONTENT_SETTING_ALLOW, GetPermissionForFrame(&midi, child));
+
+  // Enable geolocation for the child frame.
+  RefreshPageAndSetHeaderPolicy(&parent,
+                                blink::WebFeaturePolicyFeature::kGeolocation,
+                                {kOrigin1, kOrigin2});
+  child = AddChildRFH(parent, kOrigin2);
+  GeolocationPermissionContext geolocation(profile());
+  EXPECT_EQ(CONTENT_SETTING_ASK, GetPermissionForFrame(&geolocation, parent));
+  EXPECT_EQ(CONTENT_SETTING_ASK, GetPermissionForFrame(&geolocation, child));
+}
diff --git a/chrome/browser/permissions/permission_context_base_unittest.cc b/chrome/browser/permissions/permission_context_base_unittest.cc
index 655dcf2a..dd62e4a9 100644
--- a/chrome/browser/permissions/permission_context_base_unittest.cc
+++ b/chrome/browser/permissions/permission_context_base_unittest.cc
@@ -102,7 +102,9 @@
  public:
   TestPermissionContext(Profile* profile,
                         const ContentSettingsType content_settings_type)
-      : PermissionContextBase(profile, content_settings_type),
+      : PermissionContextBase(profile,
+                              content_settings_type,
+                              blink::WebFeaturePolicyFeature::kNotFound),
         tab_context_updated_(false) {}
 
   ~TestPermissionContext() override {}
diff --git a/chrome/browser/permissions/permission_request_impl.cc b/chrome/browser/permissions/permission_request_impl.cc
index 0d38dad..9d252f2 100644
--- a/chrome/browser/permissions/permission_request_impl.cc
+++ b/chrome/browser/permissions/permission_request_impl.cc
@@ -172,3 +172,7 @@
     const {
   return PermissionUtil::GetGestureType(has_gesture_);
 }
+
+ContentSettingsType PermissionRequestImpl::GetContentSettingsType() const {
+  return content_settings_type_;
+}
diff --git a/chrome/browser/permissions/permission_request_impl.h b/chrome/browser/permissions/permission_request_impl.h
index ea3eec0..035a5b6f 100644
--- a/chrome/browser/permissions/permission_request_impl.h
+++ b/chrome/browser/permissions/permission_request_impl.h
@@ -49,6 +49,7 @@
   bool ShouldShowPersistenceToggle() const override;
   PermissionRequestType GetPermissionRequestType() const override;
   PermissionRequestGestureType GetGestureType() const override;
+  ContentSettingsType GetContentSettingsType() const override;
 
   GURL request_origin_;
   ContentSettingsType content_settings_type_;
diff --git a/chrome/browser/plugins/flash_permission_context.cc b/chrome/browser/plugins/flash_permission_context.cc
index 1fd0711..5ff9ed8 100644
--- a/chrome/browser/plugins/flash_permission_context.cc
+++ b/chrome/browser/plugins/flash_permission_context.cc
@@ -32,7 +32,8 @@
 
 FlashPermissionContext::FlashPermissionContext(Profile* profile)
     : PermissionContextBase(profile,
-                            CONTENT_SETTINGS_TYPE_PLUGINS) {}
+                            CONTENT_SETTINGS_TYPE_PLUGINS,
+                            blink::WebFeaturePolicyFeature::kNotFound) {}
 
 FlashPermissionContext::~FlashPermissionContext() {}
 
diff --git a/chrome/browser/storage/durable_storage_permission_context.cc b/chrome/browser/storage/durable_storage_permission_context.cc
index eb31debc..9b898071 100644
--- a/chrome/browser/storage/durable_storage_permission_context.cc
+++ b/chrome/browser/storage/durable_storage_permission_context.cc
@@ -29,7 +29,8 @@
 DurableStoragePermissionContext::DurableStoragePermissionContext(
     Profile* profile)
     : PermissionContextBase(profile,
-                            CONTENT_SETTINGS_TYPE_DURABLE_STORAGE) {}
+                            CONTENT_SETTINGS_TYPE_DURABLE_STORAGE,
+                            blink::WebFeaturePolicyFeature::kNotFound) {}
 
 void DurableStoragePermissionContext::DecidePermission(
     content::WebContents* web_contents,
diff --git a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc b/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc
index a0f9487b..d9ba2e56 100644
--- a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc
+++ b/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc
@@ -21,7 +21,6 @@
 #include "ui/app_list/app_list_features.h"
 #include "ui/app_list/app_list_model.h"
 #include "ui/app_list/search_box_model.h"
-#include "ui/views/controls/webview/web_contents_set_background_color.h"
 #include "ui/views/controls/webview/webview.h"
 #include "ui/views/widget/widget.h"
 
@@ -106,11 +105,6 @@
     web_view_->SetFocusBehavior(views::View::FocusBehavior::NEVER);
 
   model->AddObserver(this);
-
-  // Make the webview transparent since it's going to be shown on top of a
-  // highlightable button.
-  views::WebContentsSetBackgroundColor::CreateForWebContentsWithColor(
-      web_contents_.get(), SK_ColorTRANSPARENT);
 }
 
 SearchAnswerWebContentsDelegate::~SearchAnswerWebContentsDelegate() {
@@ -174,7 +168,8 @@
       IsCardSizeOk(pref_size) || features::IsAnswerCardDarkRunEnabled();
   model_->SetSearchAnswerAvailable(is_card_size_ok_ && received_answer_ &&
                                    !web_contents_->IsLoading());
-  web_view_->SetPreferredSize(pref_size);
+  if (!features::IsAnswerCardDarkRunEnabled())
+    web_view_->SetPreferredSize(pref_size);
   if (!answer_loaded_time_.is_null()) {
     UMA_HISTOGRAM_TIMES("SearchAnswer.ResizeAfterLoadTime",
                         base::TimeTicks::Now() - answer_loaded_time_);
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
index a7dbcb9..6c0ece3 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
@@ -31,6 +31,7 @@
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_client_view.h"
 
 #if defined(OS_WIN)
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -42,8 +43,6 @@
 using base::UserMetricsAction;
 using bookmarks::BookmarkModel;
 using bookmarks::BookmarkNode;
-using views::ColumnSet;
-using views::GridLayout;
 
 namespace {
 
@@ -128,8 +127,17 @@
 // ui::DialogModel -------------------------------------------------------------
 
 int BookmarkBubbleView::GetDialogButtons() const {
-  // TODO(tapted): DialogClientView should manage the buttons.
-  return ui::DIALOG_BUTTON_NONE;
+  // TODO(tapted): DialogClientView should manage the ios promo buttons too.
+  return is_showing_ios_promotion_
+             ? ui::DIALOG_BUTTON_NONE
+             : (ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL);
+}
+
+base::string16 BookmarkBubbleView::GetDialogButtonLabel(
+    ui::DialogButton button) const {
+  return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK)
+                                       ? IDS_DONE
+                                       : IDS_BOOKMARK_BUBBLE_REMOVE_BOOKMARK);
 }
 
 // views::WidgetDelegate -------------------------------------------------------
@@ -178,6 +186,19 @@
 
 // views::DialogDelegate -------------------------------------------------------
 
+views::View* BookmarkBubbleView::CreateExtraView() {
+  edit_button_ = views::MdTextButton::CreateSecondaryUiButton(
+      this, l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_OPTIONS));
+  edit_button_->AddAccelerator(ui::Accelerator(ui::VKEY_E, ui::EF_ALT_DOWN));
+  return edit_button_;
+}
+
+bool BookmarkBubbleView::GetExtraViewPadding(int* padding) {
+  *padding = ChromeLayoutProvider::Get()->GetDistanceMetric(
+      DISTANCE_UNRELATED_CONTROL_HORIZONTAL_LARGE);
+  return true;
+}
+
 views::View* BookmarkBubbleView::CreateFootnoteView() {
 #if defined(OS_WIN)
   if (!is_showing_ios_promotion_ &&
@@ -198,31 +219,43 @@
   return footnote_view_;
 }
 
+bool BookmarkBubbleView::Cancel() {
+  base::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"));
+  // Set this so we remove the bookmark after the window closes.
+  remove_bookmark_ = true;
+  apply_edits_ = false;
+  return true;
+}
+
+bool BookmarkBubbleView::Accept() {
+#if defined(OS_WIN)
+  using desktop_ios_promotion::PromotionEntryPoint;
+  if (IsIOSPromotionEligible(PromotionEntryPoint::BOOKMARKS_BUBBLE)) {
+    ShowIOSPromotion(PromotionEntryPoint::BOOKMARKS_BUBBLE);
+    return false;
+  }
+#endif
+  return true;
+}
+
+bool BookmarkBubbleView::Close() {
+  // Allow closing when activation lost. Default would call Accept().
+  return true;
+}
+
+void BookmarkBubbleView::UpdateButton(views::LabelButton* button,
+                                      ui::DialogButton type) {
+  LocationBarBubbleDelegateView::UpdateButton(button, type);
+  if (type == ui::DIALOG_BUTTON_CANCEL)
+    button->AddAccelerator(ui::Accelerator(ui::VKEY_R, ui::EF_ALT_DOWN));
+}
+
 // views::View -----------------------------------------------------------------
 
 const char* BookmarkBubbleView::GetClassName() const {
   return "BookmarkBubbleView";
 }
 
-bool BookmarkBubbleView::AcceleratorPressed(
-    const ui::Accelerator& accelerator) {
-  ui::KeyboardCode key_code = accelerator.key_code();
-  if (key_code == ui::VKEY_RETURN) {
-    HandleButtonPressed(save_button_);
-    return true;
-  }
-  if (key_code == ui::VKEY_E && accelerator.IsAltDown()) {
-    HandleButtonPressed(edit_button_);
-    return true;
-  }
-  if (key_code == ui::VKEY_R && accelerator.IsAltDown()) {
-    HandleButtonPressed(remove_button_);
-    return true;
-  }
-
-  return LocationBarBubbleDelegateView::AcceleratorPressed(accelerator);
-}
-
 void BookmarkBubbleView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
   LocationBarBubbleDelegateView::GetAccessibleNodeData(node_data);
   node_data->SetName(l10n_util::GetStringUTF8(
@@ -234,7 +267,8 @@
 
 void BookmarkBubbleView::ButtonPressed(views::Button* sender,
                                        const ui::Event& event) {
-  HandleButtonPressed(sender);
+  base::RecordAction(UserMetricsAction("BookmarkBubble_Edit"));
+  ShowEditor();
 }
 
 // views::ComboboxListener -----------------------------------------------------
@@ -258,82 +292,54 @@
 // views::BubbleDialogDelegateView ---------------------------------------------
 
 void BookmarkBubbleView::Init() {
-  remove_button_ = views::MdTextButton::CreateSecondaryUiButton(
-      this, l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_REMOVE_BOOKMARK));
+  using views::GridLayout;
 
-  edit_button_ = views::MdTextButton::CreateSecondaryUiButton(
-      this, l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_OPTIONS));
-
-  save_button_ = views::MdTextButton::CreateSecondaryUiButton(
-      this, l10n_util::GetStringUTF16(IDS_DONE));
-  save_button_->SetIsDefault(true);
-
-  views::Label* combobox_label = new views::Label(
-      l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_FOLDER_TEXT));
-
-  parent_combobox_ = new UnsizedCombobox(&parent_model_);
-  parent_combobox_->set_listener(this);
-  parent_combobox_->SetAccessibleName(
-      l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_BUBBLE_FOLDER_TEXT));
-
-  SetLayoutManager(new views::FillLayout);
+  SetLayoutManager(new views::FillLayout());
   bookmark_contents_view_ = new views::View();
   GridLayout* layout = new GridLayout(bookmark_contents_view_);
   bookmark_contents_view_->SetLayoutManager(layout);
 
-  // This column set is used for the labels and textfields as well as the
-  // buttons at the bottom.
-  const int cs_id = 0;
-  ColumnSet* cs = layout->AddColumnSet(cs_id);
+  // This column set is used for the labels and textfields.
+  constexpr int kColumnId = 0;
+  constexpr float kFixed = 0.f;
+  constexpr float kStretchy = 1.f;
+  views::ColumnSet* cs = layout->AddColumnSet(kColumnId);
   ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
 
-  cs->AddColumn(provider->GetControlLabelGridAlignment(), GridLayout::CENTER, 0,
-                GridLayout::USE_PREF, 0, 0);
-  cs->AddPaddingColumn(
-      0, provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_HORIZONTAL));
-
-  cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, GridLayout::USE_PREF,
-                0, 0);
-  cs->AddPaddingColumn(1, provider->GetDistanceMetric(
-                              DISTANCE_UNRELATED_CONTROL_HORIZONTAL_LARGE));
-
-  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
-                GridLayout::USE_PREF, 0, 0);
-  cs->AddPaddingColumn(0, provider->GetDistanceMetric(
-                              views::DISTANCE_RELATED_BUTTON_HORIZONTAL));
-  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
+  cs->AddColumn(provider->GetControlLabelGridAlignment(), GridLayout::CENTER,
+                kFixed, GridLayout::USE_PREF, 0, 0);
+  cs->AddPaddingColumn(kFixed, provider->GetDistanceMetric(
+                                   DISTANCE_UNRELATED_CONTROL_HORIZONTAL));
+  cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, kStretchy,
                 GridLayout::USE_PREF, 0, 0);
 
-  layout->StartRow(0, cs_id);
+  layout->StartRow(kFixed, kColumnId);
   views::Label* label = new views::Label(
-      l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_TITLE_TEXT));
+      l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_NAME_LABEL));
   layout->AddView(label);
+
   name_field_ = new views::Textfield();
   name_field_->SetText(GetBookmarkName());
   name_field_->SetAccessibleName(
-      l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_BUBBLE_TITLE_TEXT));
+      l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_BUBBLE_NAME_LABEL));
+  layout->AddView(name_field_);
 
-  layout->AddView(name_field_, 5, 1);
-
-  layout->AddPaddingRow(
-      0, provider->GetInsetsMetric(views::INSETS_DIALOG_CONTENTS).top());
-
-  layout->StartRow(0, cs_id);
+  layout->StartRowWithPadding(
+      kFixed, kColumnId, kFixed,
+      provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL));
+  views::Label* combobox_label = new views::Label(
+      l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_FOLDER_LABEL));
   layout->AddView(combobox_label);
-  layout->AddView(parent_combobox_, 5, 1);
+
+  parent_combobox_ = new UnsizedCombobox(&parent_model_);
+  parent_combobox_->set_listener(this);
+  parent_combobox_->SetAccessibleName(
+      l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_BUBBLE_FOLDER_LABEL));
+  layout->AddView(parent_combobox_);
 
   layout->AddPaddingRow(
-      0, provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL));
-
-  layout->StartRow(0, cs_id);
-  layout->SkipColumns(2);
-  layout->AddView(remove_button_);
-  layout->AddView(edit_button_);
-  layout->AddView(save_button_);
-
-  AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
-  AddAccelerator(ui::Accelerator(ui::VKEY_E, ui::EF_ALT_DOWN));
-  AddAccelerator(ui::Accelerator(ui::VKEY_R, ui::EF_ALT_DOWN));
+      kFixed,
+      provider->GetInsetsMetric(views::INSETS_DIALOG_CONTENTS).bottom());
 
   AddChildView(bookmark_contents_view_);
 }
@@ -355,17 +361,7 @@
       newly_bookmarked_(newly_bookmarked),
       parent_model_(BookmarkModelFactory::GetForBrowserContext(profile_),
                     BookmarkModelFactory::GetForBrowserContext(profile_)
-                        ->GetMostRecentlyAddedUserNodeForURL(url)),
-      remove_button_(nullptr),
-      edit_button_(nullptr),
-      save_button_(nullptr),
-      name_field_(nullptr),
-      parent_combobox_(nullptr),
-      ios_promo_view_(nullptr),
-      footnote_view_(nullptr),
-      remove_bookmark_(false),
-      apply_edits_(true),
-      is_showing_ios_promotion_(false) {
+                        ->GetMostRecentlyAddedUserNodeForURL(url)) {
   chrome::RecordDialogCreation(chrome::DialogIdentifier::BOOKMARK);
 }
 
@@ -381,32 +377,6 @@
   return base::string16();
 }
 
-void BookmarkBubbleView::HandleButtonPressed(views::Button* sender) {
-  if (sender == remove_button_) {
-    base::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"));
-    // Set this so we remove the bookmark after the window closes.
-    remove_bookmark_ = true;
-    apply_edits_ = false;
-    GetWidget()->Close();
-  } else if (sender == edit_button_) {
-    base::RecordAction(UserMetricsAction("BookmarkBubble_Edit"));
-    ShowEditor();
-  } else {
-    DCHECK_EQ(save_button_, sender);
-#if defined(OS_WIN)
-    if (IsIOSPromotionEligible(
-            desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE)) {
-      ShowIOSPromotion(
-          desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE);
-    } else {
-      GetWidget()->Close();
-    }
-#else
-    GetWidget()->Close();
-#endif
-  }
-}
-
 void BookmarkBubbleView::ShowEditor() {
   const BookmarkNode* node =
       BookmarkModelFactory::GetForBrowserContext(profile_)
@@ -457,6 +427,7 @@
 void BookmarkBubbleView::ShowIOSPromotion(
     desktop_ios_promotion::PromotionEntryPoint entry_point) {
   DCHECK(!is_showing_ios_promotion_);
+  edit_button_->SetVisible(false);
   // Hide the contents, but don't delete. Its child views are accessed in the
   // destructor if there are edits to apply.
   bookmark_contents_view_->SetVisible(false);
@@ -467,7 +438,7 @@
   AddChildView(ios_promo_view_);
   GetWidget()->UpdateWindowIcon();
   GetWidget()->UpdateWindowTitle();
-  // Resize the bubble so it has the same width as the parent bubble.
-  ios_promo_view_->UpdateBubbleHeight();
+  GetDialogClientView()->UpdateDialogButtons();
+  SizeToContents();
 }
 #endif
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
index 0f279d4..8adbc07 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h
@@ -66,16 +66,22 @@
 
   ~BookmarkBubbleView() override;
 
-  // views::LocationBarBubbleDelegateView:
+  // LocationBarBubbleDelegateView:
   int GetDialogButtons() const override;
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   View* GetInitiallyFocusedView() override;
   base::string16 GetWindowTitle() const override;
   gfx::ImageSkia GetWindowIcon() override;
   bool ShouldShowWindowIcon() const override;
   void WindowClosing() override;
-  View* CreateFootnoteView() override;
+  views::View* CreateExtraView() override;
+  bool GetExtraViewPadding(int* padding) override;
+  views::View* CreateFootnoteView() override;
+  bool Cancel() override;
+  bool Accept() override;
+  bool Close() override;
+  void UpdateButton(views::LabelButton* button, ui::DialogButton type) override;
   const char* GetClassName() const override;
-  bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
 
   // views::ButtonListener:
@@ -88,7 +94,7 @@
   void OnIOSPromotionFootnoteLinkClicked() override;
 
  protected:
-  // views::LocationBarBubbleDelegateView:
+  // LocationBarBubbleDelegateView:
   void Init() override;
 
  private:
@@ -106,9 +112,6 @@
   // Returns the name of the bookmark.
   base::string16 GetBookmarkName();
 
-  // Closes the bubble, opens the edit dialog, or shows the iOS promo.
-  void HandleButtonPressed(views::Button* sender);
-
   // Shows the BookmarkEditor.
   void ShowEditor();
 
@@ -144,40 +147,34 @@
 
   RecentlyUsedFoldersComboModel parent_model_;
 
-  // Button for removing the bookmark.
-  views::LabelButton* remove_button_;
-
   // Button to bring up the editor.
-  views::LabelButton* edit_button_;
-
-  // Button to save the bookmark.
-  views::LabelButton* save_button_;
+  views::LabelButton* edit_button_ = nullptr;
 
   // Textfield showing the name of the bookmark.
-  views::Textfield* name_field_;
+  views::Textfield* name_field_ = nullptr;
 
   // Combobox showing a handful of folders the user can choose from, including
   // the current parent.
-  views::Combobox* parent_combobox_;
+  views::Combobox* parent_combobox_ = nullptr;
 
   // The regular bookmark bubble contents, with all the edit fields and dialog
   // buttons. TODO(tapted): Move the buttons to the DialogClientView.
-  views::View* bookmark_contents_view_;
+  views::View* bookmark_contents_view_ = nullptr;
 
   // iOS promotion view.
-  DesktopIOSPromotionBubbleView* ios_promo_view_;
+  DesktopIOSPromotionBubbleView* ios_promo_view_ = nullptr;
 
   // Footnote view.
-  views::View* footnote_view_;
+  views::View* footnote_view_ = nullptr;
 
   // When the destructor is invoked should the bookmark be removed?
-  bool remove_bookmark_;
+  bool remove_bookmark_ = false;
 
   // When the destructor is invoked should edits be applied?
-  bool apply_edits_;
+  bool apply_edits_ = true;
 
   // Whether the Windows to iOS promotion is shown to the user.
-  bool is_showing_ios_promotion_;
+  bool is_showing_ios_promotion_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(BookmarkBubbleView);
 };
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
index bbd98c4..2de79b0 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
@@ -17,6 +17,7 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
+#include "ui/views/window/dialog_client_view.h"
 
 namespace {
 
@@ -68,8 +69,11 @@
         nullptr, nullptr, nullptr, profile_.get(), GURL(kTestBookmarkURL),
         true);
     if (name == "ios_promotion") {
-      BookmarkBubbleView::bookmark_bubble()->HandleButtonPressed(
-          BookmarkBubbleView::bookmark_bubble()->save_button_);
+      BookmarkBubbleView::bookmark_bubble()
+          ->GetWidget()
+          ->client_view()
+          ->AsDialogClientView()
+          ->AcceptWindow();
     }
   }
 
diff --git a/chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bubble_view.cc b/chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bubble_view.cc
index f95e3f2..0dbee7b 100644
--- a/chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bubble_view.cc
+++ b/chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bubble_view.cc
@@ -96,19 +96,16 @@
   GetWidget()->Close();
 }
 
-void DesktopIOSPromotionBubbleView::UpdateBubbleHeight() {
-  gfx::Rect old_bounds = GetWidget()->GetWindowBoundsInScreen();
-  old_bounds.set_height(
-      GetWidget()->GetRootView()->GetHeightForWidth(old_bounds.width()));
-  GetWidget()->SetBounds(old_bounds);
-}
-
 void DesktopIOSPromotionBubbleView::UpdateRecoveryPhoneLabel() {
   std::string number = promotion_controller_->GetUsersRecoveryPhoneNumber();
   if (!number.empty()) {
     promotion_text_label_->SetText(desktop_ios_promotion::GetPromoText(
         promotion_controller_->entry_point(), number));
     Layout();
-    UpdateBubbleHeight();
+    views::Widget* widget = GetWidget();
+    gfx::Rect old_bounds = widget->GetWindowBoundsInScreen();
+    old_bounds.set_height(
+        widget->GetRootView()->GetHeightForWidth(old_bounds.width()));
+    widget->SetBounds(old_bounds);
   }
 }
diff --git a/chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bubble_view.h b/chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bubble_view.h
index d1084c7b..7fc48fb 100644
--- a/chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bubble_view.h
+++ b/chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bubble_view.h
@@ -28,9 +28,6 @@
       desktop_ios_promotion::PromotionEntryPoint entry_point);
   ~DesktopIOSPromotionBubbleView() override;
 
-  // Update Bubble Height to fit the content.
-  void UpdateBubbleHeight();
-
   // DesktopIOSPromotionView:
   void UpdateRecoveryPhoneLabel() override;
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cd80d9b..627c81ce 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3171,6 +3171,7 @@
     "../browser/password_manager/password_store_win_unittest.cc",
     "../browser/password_manager/password_store_x_unittest.cc",
     "../browser/permissions/chooser_context_base_unittest.cc",
+    "../browser/permissions/permission_context_base_feature_policy_unittest.cc",
     "../browser/permissions/permission_context_base_unittest.cc",
     "../browser/permissions/permission_decision_auto_blocker_unittest.cc",
     "../browser/permissions/permission_manager_unittest.cc",
diff --git a/components/security_state/core/security_state.cc b/components/security_state/core/security_state.cc
index aed4e42..a958bf3 100644
--- a/components/security_state/core/security_state.cc
+++ b/components/security_state/core/security_state.cc
@@ -17,12 +17,15 @@
 
 namespace {
 
-// Do not change or reorder this enum, and add new values at the end. It is used
-// in the MarkHttpAs histogram.
+// These values are written to logs. New enum values can be added, but existing
+// enums must never be renumbered or deleted and reused.
 enum MarkHttpStatus {
-  NEUTRAL /* deprecated */,
-  NON_SECURE,
-  HTTP_SHOW_WARNING_ON_SENSITIVE_FIELDS,
+  NEUTRAL = 0,  // Deprecated
+  NON_SECURE = 1,
+  HTTP_SHOW_WARNING_ON_SENSITIVE_FIELDS = 2,
+  NON_SECURE_AFTER_EDITING = 3,
+  NON_SECURE_WHILE_INCOGNITO = 4,
+  NON_SECURE_WHILE_INCOGNITO_OR_EDITING = 5,
   LAST_STATUS
 };
 
diff --git a/components/security_state/core/switches.cc b/components/security_state/core/switches.cc
index c8542f8..dddd8ae 100644
--- a/components/security_state/core/switches.cc
+++ b/components/security_state/core/switches.cc
@@ -10,6 +10,9 @@
 // Use to opt-in to marking HTTP as non-secure.
 const char kMarkHttpAs[] = "mark-non-secure-as";
 const char kMarkHttpAsDangerous[] = "non-secure";
-
+const char kMarkHttpAsNonSecureAfterEditing[] = "non-secure-after-editing";
+const char kMarkHttpAsNonSecureWhileIncognito[] = "non-secure-while-incognito";
+const char kMarkHttpAsNonSecureWhileIncognitoOrEditing[] =
+    "non-secure-while-incognito-or-editing";
 }  // namespace switches
 }  // namespace security_state
diff --git a/components/security_state/core/switches.h b/components/security_state/core/switches.h
index 4216cd2..df27238 100644
--- a/components/security_state/core/switches.h
+++ b/components/security_state/core/switches.h
@@ -10,6 +10,9 @@
 
 extern const char kMarkHttpAs[];
 extern const char kMarkHttpAsDangerous[];
+extern const char kMarkHttpAsNonSecureAfterEditing[];
+extern const char kMarkHttpAsNonSecureWhileIncognito[];
+extern const char kMarkHttpAsNonSecureWhileIncognitoOrEditing[];
 }
 }  // namespace security_state
 
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 00b6605e..b6f603b9 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -1218,6 +1218,11 @@
     return true;
   }
 
+  if (data.action == ui::AX_ACTION_FOCUS) {
+    manager_->SetFocus(*this);
+    return true;
+  }
+
   return false;
 }
 
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index 69a6ed8..ecd86fa 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -780,16 +780,7 @@
   if (!owner())
     return E_FAIL;
 
-  auto* manager = Manager();
-  if (!manager)
-    return E_FAIL;
-
-  if (flags_sel & SELFLAG_TAKEFOCUS) {
-    manager->SetFocus(*owner());
-    return S_OK;
-  }
-
-  return S_FALSE;
+  return AXPlatformNodeWin::accSelect(flags_sel, var_id);
 }
 
 STDMETHODIMP
diff --git a/content/browser/battery_monitor_browsertest.cc b/content/browser/battery_monitor_browsertest.cc
index c4bf62c..9977dea2 100644
--- a/content/browser/battery_monitor_browsertest.cc
+++ b/content/browser/battery_monitor_browsertest.cc
@@ -44,22 +44,20 @@
 
  private:
   // mojom::BatteryMonitor methods:
-  void QueryNextStatus(const QueryNextStatusCallback& callback) override {
+  void QueryNextStatus(QueryNextStatusCallback callback) override {
     if (!callback_.is_null()) {
       DVLOG(1) << "Overlapped call to QueryNextStatus!";
       binding_.Close();
       return;
     }
-    callback_ = callback;
+    callback_ = std::move(callback);
 
     if (status_to_report_)
       ReportStatus();
   }
 
   void ReportStatus() {
-    callback_.Run(status_.Clone());
-    callback_.Reset();
-
+    std::move(callback_).Run(status_.Clone());
     status_to_report_ = false;
   }
 
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
index aab62d8..099367d7 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -457,8 +457,6 @@
       client_id);
 }
 
-BrowserGpuMemoryBufferManager::BufferInfo::BufferInfo() = default;
-
 BrowserGpuMemoryBufferManager::BufferInfo::BufferInfo(
     const gfx::Size& size,
     gfx::GpuMemoryBufferType type,
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.h b/content/browser/gpu/browser_gpu_memory_buffer_manager.h
index a6468d77..b12409d 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.h
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.h
@@ -69,7 +69,6 @@
 
  private:
   struct BufferInfo {
-    BufferInfo();
     BufferInfo(const gfx::Size& size,
                gfx::GpuMemoryBufferType type,
                gfx::BufferFormat format,
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 849b8ee..f29936f 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -2022,9 +2022,6 @@
       !is_external_protocol;
 
   if (is_shutdown_ || non_web_url_in_guest ||
-      // TODO(davidben): Check ShouldServiceRequest here. This is important; it
-      // needs to be checked relative to the child that /requested/ the
-      // navigation. It's where file upload checks, etc., come in.
       (delegate_ && !delegate_->ShouldBeginRequest(
           info.common_params.method,
           info.common_params.url,
diff --git a/content/browser/permissions/permission_service_context.h b/content/browser/permissions/permission_service_context.h
index 347808e..d08b8ed1 100644
--- a/content/browser/permissions/permission_service_context.h
+++ b/content/browser/permissions/permission_service_context.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_PERMISSIONS_PERMISSION_SERVICE_CONTEXT_H_
 
 #include "base/macros.h"
+#include "content/common/content_export.h"
 #include "content/public/browser/permission_type.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "mojo/public/cpp/bindings/strong_binding_set.h"
@@ -29,7 +30,7 @@
 // There is one PermissionServiceContext per RenderFrameHost/RenderProcessHost
 // which owns it. It then owns all PermissionServiceImpl associated to their
 // owner.
-class PermissionServiceContext : public WebContentsObserver {
+class CONTENT_EXPORT PermissionServiceContext : public WebContentsObserver {
  public:
   explicit PermissionServiceContext(RenderFrameHost* render_frame_host);
   explicit PermissionServiceContext(RenderProcessHost* render_process_host);
diff --git a/content/browser/permissions/permission_service_impl.cc b/content/browser/permissions/permission_service_impl.cc
index a62913c..686bb31 100644
--- a/content/browser/permissions/permission_service_impl.cc
+++ b/content/browser/permissions/permission_service_impl.cc
@@ -10,10 +10,14 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/permission_manager.h"
 #include "content/public/browser/permission_type.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/common/content_features.h"
+#include "third_party/WebKit/public/platform/WebFeaturePolicy.h"
 
 using blink::mojom::PermissionDescriptorPtr;
 using blink::mojom::PermissionName;
@@ -56,8 +60,56 @@
   return PermissionType::NUM;
 }
 
-// This function allows the usage of the the multiple request map
-// with single requests.
+blink::WebFeaturePolicyFeature PermissionTypeToFeaturePolicyFeature(
+    PermissionType type) {
+  switch (type) {
+    case PermissionType::MIDI:
+    case PermissionType::MIDI_SYSEX:
+      return blink::WebFeaturePolicyFeature::kMidiFeature;
+    case PermissionType::GEOLOCATION:
+      return blink::WebFeaturePolicyFeature::kGeolocation;
+    case PermissionType::PROTECTED_MEDIA_IDENTIFIER:
+      return blink::WebFeaturePolicyFeature::kEme;
+    case PermissionType::AUDIO_CAPTURE:
+      return blink::WebFeaturePolicyFeature::kMicrophone;
+    case PermissionType::VIDEO_CAPTURE:
+      return blink::WebFeaturePolicyFeature::kCamera;
+    case PermissionType::PUSH_MESSAGING:
+    case PermissionType::NOTIFICATIONS:
+    case PermissionType::DURABLE_STORAGE:
+    case PermissionType::BACKGROUND_SYNC:
+    case PermissionType::FLASH:
+    case PermissionType::NUM:
+      // These aren't exposed by feature policy.
+      return blink::WebFeaturePolicyFeature::kNotFound;
+  }
+
+  NOTREACHED();
+  return blink::WebFeaturePolicyFeature::kNotFound;
+}
+
+bool AllowedByFeaturePolicy(RenderFrameHost* rfh, PermissionType type) {
+  if (!base::FeatureList::IsEnabled(
+          features::kUseFeaturePolicyForPermissions)) {
+    // Default to ignoring the feature policy.
+    return true;
+  }
+
+  blink::WebFeaturePolicyFeature feature_policy_feature =
+      PermissionTypeToFeaturePolicyFeature(type);
+  if (feature_policy_feature == blink::WebFeaturePolicyFeature::kNotFound)
+    return true;
+
+  // If there is no frame, there is no policy, so disable the feature for
+  // safety.
+  if (!rfh)
+    return false;
+
+  return rfh->IsFeatureEnabled(feature_policy_feature);
+}
+
+// This function allows the usage of the the multiple request map with single
+// requests.
 void PermissionRequestResponseCallbackWrapper(
     const base::Callback<void(PermissionStatus)>& callback,
     const std::vector<PermissionStatus>& vector) {
@@ -67,20 +119,56 @@
 
 } // anonymous namespace
 
-PermissionServiceImpl::PendingRequest::PendingRequest(
-    const RequestPermissionsCallback& callback,
-    int request_count)
-    : callback(callback),
-      request_count(request_count) {
-}
+class PermissionServiceImpl::PendingRequest {
+ public:
+  PendingRequest(std::vector<PermissionType> types,
+                 const RequestPermissionsCallback& callback)
+      : types_(types),
+        callback_(callback),
+        has_result_been_set_(types.size(), false),
+        results_(types.size(), PermissionStatus::DENIED) {}
 
-PermissionServiceImpl::PendingRequest::~PendingRequest() {
-  if (callback.is_null())
-    return;
+  ~PendingRequest() {
+    if (callback_.is_null())
+      return;
 
-  std::vector<PermissionStatus> result(request_count, PermissionStatus::DENIED);
-  callback.Run(result);
-}
+    std::vector<PermissionStatus> result(types_.size(),
+                                         PermissionStatus::DENIED);
+    callback_.Run(result);
+  }
+
+  int id() const { return id_; }
+  void set_id(int id) { id_ = id; }
+
+  size_t RequestSize() const { return types_.size(); }
+
+  void SetResult(int index, PermissionStatus result) {
+    DCHECK_EQ(false, has_result_been_set_[index]);
+    has_result_been_set_[index] = true;
+    results_[index] = result;
+  }
+
+  bool HasResultBeenSet(size_t index) const {
+    return has_result_been_set_[index];
+  }
+
+  void RunCallback() {
+    // Check that all results have been set.
+    DCHECK(std::find(has_result_been_set_.begin(), has_result_been_set_.end(),
+                     false) == has_result_been_set_.end());
+    callback_.Run(results_);
+    callback_.Reset();
+  }
+
+ private:
+  // Request ID received from the PermissionManager.
+  int id_;
+  std::vector<PermissionType> types_;
+  RequestPermissionsCallback callback_;
+
+  std::vector<bool> has_result_been_set_;
+  std::vector<PermissionStatus> results_;
+};
 
 PermissionServiceImpl::PermissionServiceImpl(PermissionServiceContext* context)
     : context_(context), weak_factory_(this) {}
@@ -96,7 +184,7 @@
   // Cancel pending requests.
   for (RequestsMap::Iterator<PendingRequest> it(&pending_requests_);
        !it.IsAtEnd(); it.Advance()) {
-    permission_manager->CancelPermissionRequest(it.GetCurrentValue()->id);
+    permission_manager->CancelPermissionRequest(it.GetCurrentValue()->id());
   }
   pending_requests_.Clear();
 }
@@ -140,30 +228,53 @@
   for (size_t i = 0; i < types.size(); ++i)
     types[i] = PermissionDescriptorToPermissionType(permissions[i]);
 
-  int pending_request_id = pending_requests_.Add(
-      base::MakeUnique<PendingRequest>(callback, permissions.size()));
+  std::unique_ptr<PendingRequest> pending_request =
+      base::MakeUnique<PendingRequest>(types, callback);
+  std::vector<PermissionType> request_types;
+  for (size_t i = 0; i < types.size(); ++i) {
+    // Check feature policy.
+    if (!AllowedByFeaturePolicy(context_->render_frame_host(), types[i]))
+      pending_request->SetResult(i, PermissionStatus::DENIED);
+    else
+      request_types.push_back(types[i]);
+  }
+
+  int pending_request_id = pending_requests_.Add(std::move(pending_request));
   int id = browser_context->GetPermissionManager()->RequestPermissions(
-      types, context_->render_frame_host(), origin.GetURL(), user_gesture,
+      request_types, context_->render_frame_host(), origin.GetURL(),
+      user_gesture,
       base::Bind(&PermissionServiceImpl::OnRequestPermissionsResponse,
                  weak_factory_.GetWeakPtr(), pending_request_id));
 
   // Check if the request still exists. It may have been removed by the
   // the response callback.
-  PendingRequest* pending_request = pending_requests_.Lookup(
-      pending_request_id);
-  if (!pending_request)
-      return;
-  pending_request->id = id;
+  PendingRequest* in_progress_request =
+      pending_requests_.Lookup(pending_request_id);
+  if (!in_progress_request)
+    return;
+  in_progress_request->set_id(id);
 }
 
 void PermissionServiceImpl::OnRequestPermissionsResponse(
     int pending_request_id,
-    const std::vector<PermissionStatus>& result) {
+    const std::vector<PermissionStatus>& partial_result) {
   PendingRequest* request = pending_requests_.Lookup(pending_request_id);
-  RequestPermissionsCallback callback(request->callback);
-  request->callback.Reset();
+  auto partial_result_it = partial_result.begin();
+  // Fill in the unset results in the request. Some results in the request are
+  // set synchronously because they are blocked by feature policy. Others are
+  // determined by a call to RequestPermission. All unset results will be
+  // contained in |partial_result| in the same order that they were requested.
+  // We fill in the unset results in the request with |partial_result|.
+  for (size_t i = 0; i < request->RequestSize(); ++i) {
+    if (!request->HasResultBeenSet(i)) {
+      request->SetResult(i, *partial_result_it);
+      ++partial_result_it;
+    }
+  }
+  DCHECK(partial_result.end() == partial_result_it);
+
+  request->RunCallback();
   pending_requests_.Remove(pending_request_id);
-  callback.Run(result);
 }
 
 void PermissionServiceImpl::HasPermission(
@@ -221,8 +332,10 @@
     const url::Origin& origin) {
   BrowserContext* browser_context = context_->GetBrowserContext();
   DCHECK(browser_context);
-  if (!browser_context->GetPermissionManager())
+  if (!browser_context->GetPermissionManager() ||
+      !AllowedByFeaturePolicy(context_->render_frame_host(), type)) {
     return PermissionStatus::DENIED;
+  }
 
   GURL requesting_origin(origin.Serialize());
   // If the embedding_origin is empty we'll use |origin| instead.
diff --git a/content/browser/permissions/permission_service_impl.h b/content/browser/permissions/permission_service_impl.h
index 9d8430d..bb7023a8 100644
--- a/content/browser/permissions/permission_service_impl.h
+++ b/content/browser/permissions/permission_service_impl.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "content/browser/permissions/permission_service_context.h"
+#include "content/common/content_export.h"
 #include "third_party/WebKit/public/platform/modules/permissions/permission.mojom.h"
 #include "url/origin.h"
 
@@ -24,25 +25,19 @@
 // to have some information about the current context. That enables the service
 // to know whether it can show UI and have knowledge of the associated
 // WebContents for example.
-class PermissionServiceImpl : public blink::mojom::PermissionService {
+class CONTENT_EXPORT PermissionServiceImpl
+    : public blink::mojom::PermissionService {
  public:
   PermissionServiceImpl(PermissionServiceContext* context);
   ~PermissionServiceImpl() override;
 
  private:
+  friend class PermissionServiceImplTest;
+
   using PermissionStatusCallback =
       base::Callback<void(blink::mojom::PermissionStatus)>;
 
-  struct PendingRequest {
-    PendingRequest(const RequestPermissionsCallback& callback,
-                   int request_count);
-    ~PendingRequest();
-
-    // Request ID received from the PermissionManager.
-    int id;
-    RequestPermissionsCallback callback;
-    int request_count;
-  };
+  class PendingRequest;
   using RequestsMap = IDMap<std::unique_ptr<PendingRequest>>;
 
   // blink::mojom::PermissionService.
diff --git a/content/browser/permissions/permission_service_impl_unittest.cc b/content/browser/permissions/permission_service_impl_unittest.cc
new file mode 100644
index 0000000..33f59d2
--- /dev/null
+++ b/content/browser/permissions/permission_service_impl_unittest.cc
@@ -0,0 +1,189 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/permissions/permission_service_impl.h"
+
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/browser/permissions/permission_service_context.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/test/mock_permission_manager.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "third_party/WebKit/public/platform/WebFeaturePolicy.h"
+#include "third_party/WebKit/public/platform/modules/permissions/permission.mojom.h"
+#include "url/origin.h"
+
+using blink::mojom::PermissionStatus;
+using blink::mojom::PermissionName;
+
+namespace content {
+
+namespace {
+
+blink::mojom::PermissionDescriptorPtr CreatePermissionDescriptor(
+    PermissionName name) {
+  auto descriptor = blink::mojom::PermissionDescriptor::New();
+  descriptor->name = name;
+  return descriptor;
+}
+
+class TestPermissionManager : public MockPermissionManager {
+ public:
+  ~TestPermissionManager() override = default;
+
+  PermissionStatus GetPermissionStatus(PermissionType permission,
+                                       const GURL& requesting_origin,
+                                       const GURL& embedding_origin) override {
+    // Always return granted.
+    return PermissionStatus::GRANTED;
+  }
+
+  int RequestPermissions(
+      const std::vector<PermissionType>& permissions,
+      RenderFrameHost* render_frame_host,
+      const GURL& requesting_origin,
+      bool user_gesture,
+      const base::Callback<void(const std::vector<PermissionStatus>&)>&
+          callback) override {
+    callback.Run(std::vector<PermissionStatus>(permissions.size(),
+                                               PermissionStatus::GRANTED));
+    return 0;
+  }
+};
+
+}  // namespace
+
+class PermissionServiceImplTest : public RenderViewHostTestHarness {
+ public:
+  PermissionServiceImplTest() : origin_(GURL("https://www.google.com")) {}
+
+  void SetUp() override {
+    RenderViewHostTestHarness::SetUp();
+    static_cast<TestBrowserContext*>(browser_context())
+        ->SetPermissionManager(base::MakeUnique<TestPermissionManager>());
+    NavigateAndCommit(origin_.GetURL());
+    service_context_.reset(new PermissionServiceContext(main_rfh()));
+    service_impl_.reset(new PermissionServiceImpl(service_context_.get()));
+  }
+
+  void TearDown() override {
+    service_impl_.reset();
+    service_context_.reset();
+    RenderViewHostTestHarness::TearDown();
+  }
+
+ protected:
+  // The header policy should only be set once on page load, so we refresh the
+  // page to simulate that.
+  void RefreshPageAndSetHeaderPolicy(blink::WebFeaturePolicyFeature feature,
+                                     bool enabled) {
+    NavigateAndCommit(origin_.GetURL());
+    std::vector<url::Origin> whitelist;
+    if (enabled)
+      whitelist.push_back(origin_);
+    RenderFrameHostTester::For(main_rfh())
+        ->SimulateFeaturePolicyHeader(feature, whitelist);
+  }
+
+  PermissionStatus HasPermission(PermissionName permission) {
+    base::Callback<void(PermissionStatus)> callback =
+        base::Bind(&PermissionServiceImplTest::PermissionStatusCallback,
+                   base::Unretained(this));
+    service_impl_->HasPermission(CreatePermissionDescriptor(permission),
+                                 origin_, callback);
+    EXPECT_EQ(1u, last_permission_statuses_.size());
+    return last_permission_statuses_[0];
+  }
+
+  std::vector<PermissionStatus> RequestPermissions(
+      const std::vector<PermissionName>& permissions) {
+    std::vector<blink::mojom::PermissionDescriptorPtr> descriptors;
+    for (PermissionName name : permissions)
+      descriptors.push_back(CreatePermissionDescriptor(name));
+    base::Callback<void(const std::vector<PermissionStatus>&)> callback =
+        base::Bind(&PermissionServiceImplTest::RequestPermissionsCallback,
+                   base::Unretained(this));
+    service_impl_->RequestPermissions(std::move(descriptors), origin_,
+                                      /*user_gesture=*/false, callback);
+    EXPECT_EQ(permissions.size(), last_permission_statuses_.size());
+    return last_permission_statuses_;
+  }
+
+ private:
+  void PermissionStatusCallback(blink::mojom::PermissionStatus status) {
+    last_permission_statuses_ = std::vector<PermissionStatus>{status};
+  }
+
+  void RequestPermissionsCallback(
+      const std::vector<PermissionStatus>& statuses) {
+    last_permission_statuses_ = statuses;
+  }
+
+  url::Origin origin_;
+
+  base::Closure quit_closure_;
+
+  std::vector<PermissionStatus> last_permission_statuses_;
+
+  std::unique_ptr<PermissionServiceImpl> service_impl_;
+  std::unique_ptr<PermissionServiceContext> service_context_;
+};
+
+// Basic tests for feature policy checks through the PermissionService.  These
+// tests are not meant to cover every edge case as the FeaturePolicy class
+// itself is tested thoroughly in feature_policy_unittest.cc and in
+// render_frame_host_feature_policy_unittest.cc.
+TEST_F(PermissionServiceImplTest, HasPermissionWithFeaturePolicy) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kUseFeaturePolicyForPermissions);
+  // Geolocation should be enabled by default for a frame (if permission is
+  // granted).
+  EXPECT_EQ(PermissionStatus::GRANTED,
+            HasPermission(PermissionName::GEOLOCATION));
+
+  RefreshPageAndSetHeaderPolicy(blink::WebFeaturePolicyFeature::kGeolocation,
+                                /*enabled=*/false);
+  EXPECT_EQ(PermissionStatus::DENIED,
+            HasPermission(PermissionName::GEOLOCATION));
+
+  // Midi should be allowed even though geolocation was disabled.
+  EXPECT_EQ(PermissionStatus::GRANTED, HasPermission(PermissionName::MIDI));
+
+  // Now block midi.
+  RefreshPageAndSetHeaderPolicy(blink::WebFeaturePolicyFeature::kMidiFeature,
+                                /*enabled=*/false);
+  EXPECT_EQ(PermissionStatus::DENIED, HasPermission(PermissionName::MIDI));
+
+  // Ensure that the policy is ignored if kUseFeaturePolicyForPermissions is
+  // disabled.
+  base::test::ScopedFeatureList empty_feature_list;
+  empty_feature_list.Init();
+  EXPECT_EQ(PermissionStatus::GRANTED, HasPermission(PermissionName::MIDI));
+}
+
+TEST_F(PermissionServiceImplTest, RequestPermissionsWithFeaturePolicy) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kUseFeaturePolicyForPermissions);
+
+  // Disable midi.
+  RefreshPageAndSetHeaderPolicy(blink::WebFeaturePolicyFeature::kMidiFeature,
+                                /*enabled=*/false);
+
+  std::vector<PermissionStatus> result =
+      RequestPermissions(std::vector<PermissionName>{PermissionName::MIDI});
+  EXPECT_EQ(1u, result.size());
+  EXPECT_EQ(PermissionStatus::DENIED, result[0]);
+
+  // Request midi along with geolocation. Geolocation should be granted.
+  result = RequestPermissions(std::vector<PermissionName>{
+      PermissionName::MIDI, PermissionName::GEOLOCATION});
+  EXPECT_EQ(2u, result.size());
+  EXPECT_EQ(PermissionStatus::DENIED, result[0]);
+  EXPECT_EQ(PermissionStatus::GRANTED, result[1]);
+}
+
+}  // namespace
\ No newline at end of file
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index 24a68af..21fde0e9 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -1022,7 +1022,12 @@
 #if defined(USE_AURA)
 // Tests that the acked events have correct state. (ui::Events are used only on
 // windows and aura)
-TEST_F(InputRouterImplTest, AckedTouchEventState) {
+#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_CHROMEOS)
+#define MAYBE_AckedTouchEventState DISABLED_AckedTouchEventState
+#else
+#define MAYBE_AckedTouchEventState AckedTouchEventState
+#endif
+TEST_F(InputRouterImplTest, MAYBE_AckedTouchEventState) {
   input_router_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
   EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
   EXPECT_TRUE(TouchEventQueueEmpty());
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 7ef395e1..d1bb82f 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -575,14 +575,16 @@
     int provider_id) {
   EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
   ASSERT_TRUE(worker);
+  ASSERT_TRUE(embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]);
+
   // Prepare a provider host to be used by following OnThreadStarted().
   std::unique_ptr<ServiceWorkerProviderHost> host =
       CreateProviderHostForServiceWorkerContext(
           worker->process_id(), provider_id, true /* is_parent_frame_secure */,
-          context()->AsWeakPtr());
+          context()->AsWeakPtr(),
+          &embedded_worker_id_remote_provider_map_[embedded_worker_id]);
   context()->AddProviderHost(std::move(host));
 
-  ASSERT_TRUE(embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]);
   embedded_worker_id_instance_host_ptr_map_[embedded_worker_id]
       ->OnThreadStarted(thread_id, provider_id);
   base::RunLoop().RunUntilIdle();
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index 6bc5789..c19b0773 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -18,6 +18,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/time/time.h"
+#include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/common/service_worker/embedded_worker.mojom.h"
 #include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
 #include "content/common/service_worker/service_worker_status_code.h"
@@ -348,6 +349,8 @@
       int /* embedded_worker_id */,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtr /* instance_host_ptr */>
       embedded_worker_id_instance_host_ptr_map_;
+  std::map<int /* embedded_worker_id */, ServiceWorkerRemoteProviderEndpoint>
+      embedded_worker_id_remote_provider_map_;
 
   std::vector<Event> events_;
 
diff --git a/content/browser/service_worker/foreign_fetch_request_handler_unittest.cc b/content/browser/service_worker/foreign_fetch_request_handler_unittest.cc
index f77f486..9ea84249 100644
--- a/content/browser/service_worker/foreign_fetch_request_handler_unittest.cc
+++ b/content/browser/service_worker/foreign_fetch_request_handler_unittest.cc
@@ -157,10 +157,12 @@
   }
 
   void CreateWindowTypeProviderHost() {
+    remote_endpoints_.emplace_back();
     std::unique_ptr<ServiceWorkerProviderHost> host =
         CreateProviderHostForWindow(
             helper_->mock_render_process_id(), kMockProviderId,
-            true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr());
+            true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
+            &remote_endpoints_.back());
     EXPECT_FALSE(
         context()->GetProviderHost(host->process_id(), host->provider_id()));
     host->SetDocumentUrl(GURL("https://host/scope/"));
@@ -169,10 +171,12 @@
   }
 
   void CreateServiceWorkerTypeProviderHost() {
+    remote_endpoints_.emplace_back();
     std::unique_ptr<ServiceWorkerProviderHost> host =
         CreateProviderHostForServiceWorkerContext(
             helper_->mock_render_process_id(), kMockProviderId,
-            true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr());
+            true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
+            &remote_endpoints_.back());
     EXPECT_FALSE(
         context()->GetProviderHost(host->process_id(), host->provider_id()));
     provider_host_ = host->AsWeakPtr();
@@ -235,6 +239,7 @@
   base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
   storage::BlobStorageContext blob_storage_context_;
   std::unique_ptr<net::URLRequest> request_;
+  std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_;
 
   DISALLOW_COPY_AND_ASSIGN(ForeignFetchRequestHandlerTest);
 };
diff --git a/content/browser/service_worker/link_header_support_unittest.cc b/content/browser/service_worker/link_header_support_unittest.cc
index ad8e2cd..d589fea 100644
--- a/content/browser/service_worker/link_header_support_unittest.cc
+++ b/content/browser/service_worker/link_header_support_unittest.cc
@@ -79,10 +79,12 @@
 
   void CreateDocumentProviderHost() {
     // An empty host.
+    remote_endpoints_.emplace_back();
     std::unique_ptr<ServiceWorkerProviderHost> host =
         CreateProviderHostForWindow(render_process_id(), kMockProviderId,
                                     true /* is_parent_frame_secure */,
-                                    context()->AsWeakPtr());
+                                    context()->AsWeakPtr(),
+                                    &remote_endpoints_.back());
     provider_host_ = host->AsWeakPtr();
     EXPECT_FALSE(
         context()->GetProviderHost(host->process_id(), host->provider_id()));
@@ -91,10 +93,12 @@
 
   void CreateInsecureDocumentProviderHost() {
     // An empty host.
+    remote_endpoints_.emplace_back();
     std::unique_ptr<ServiceWorkerProviderHost> host =
         CreateProviderHostForWindow(render_process_id(), kMockProviderId,
                                     false /* is_parent_frame_secure */,
-                                    context()->AsWeakPtr());
+                                    context()->AsWeakPtr(),
+                                    &remote_endpoints_.back());
     provider_host_ = host->AsWeakPtr();
     EXPECT_FALSE(
         context()->GetProviderHost(host->process_id(), host->provider_id()));
@@ -102,10 +106,12 @@
   }
 
   void CreateServiceWorkerProviderHost() {
+    remote_endpoints_.emplace_back();
     std::unique_ptr<ServiceWorkerProviderHost> host =
         CreateProviderHostForServiceWorkerContext(
             render_process_id(), kMockProviderId,
-            true /* is_parent_frame_secure */, context()->AsWeakPtr());
+            true /* is_parent_frame_secure */, context()->AsWeakPtr(),
+            &remote_endpoints_.back());
     provider_host_ = host->AsWeakPtr();
     EXPECT_FALSE(
         context()->GetProviderHost(host->process_id(), host->provider_id()));
@@ -161,7 +167,7 @@
     return registrations;
   }
 
- private:
+ protected:
   TestBrowserThreadBundle thread_bundle_;
   std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
   net::TestURLRequestContext request_context_;
@@ -169,6 +175,7 @@
   MockResourceContext resource_context_;
   base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
   storage::BlobStorageContext blob_storage_context_;
+  std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_;
 };
 
 TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_Basic) {
@@ -397,10 +404,12 @@
        InstallServiceWorker_FromWorkerWithControllees) {
   CreateServiceWorkerProviderHost();
 
+  remote_endpoints_.emplace_back();
   std::unique_ptr<ServiceWorkerProviderHost> controllee =
       CreateProviderHostForWindow(render_process_id(), kMockProviderId,
                                   true /* is_parent_frame_secure */,
-                                  context()->AsWeakPtr());
+                                  context()->AsWeakPtr(),
+                                  &remote_endpoints_.back());
   provider_host()->running_hosted_version()->AddControllee(controllee.get());
 
   ProcessLinkHeaderForRequest(
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 3f96ad84..0a9c1c3 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -573,6 +573,7 @@
   void TearDownOnIOThread() override {
     registration_ = NULL;
     version_ = NULL;
+    remote_endpoints_.clear();
   }
 
   void InstallTestHelper(const std::string& worker_url,
@@ -668,11 +669,12 @@
 
   void AddControlleeOnIOThread() {
     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+    remote_endpoints_.emplace_back();
     std::unique_ptr<ServiceWorkerProviderHost> host =
-        CreateProviderHostForWindow(33 /* dummy render process id */,
-                                    1 /* dummy provider_id */,
-                                    true /* is_parent_frame_secure */,
-                                    wrapper()->context()->AsWeakPtr());
+        CreateProviderHostForWindow(
+            33 /* dummy render process id */, 1 /* dummy provider_id */,
+            true /* is_parent_frame_secure */,
+            wrapper()->context()->AsWeakPtr(), &remote_endpoints_.back());
     host->SetDocumentUrl(
         embedded_test_server()->GetURL("/service_worker/host"));
     host->AssociateRegistration(registration_.get(),
@@ -919,6 +921,7 @@
   scoped_refptr<ServiceWorkerVersion> version_;
   scoped_refptr<ChromeBlobStorageContext> blob_context_;
   std::unique_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
+  std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_;
 };
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
diff --git a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
index 73e6040..5f08d23 100644
--- a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -91,7 +91,8 @@
     std::unique_ptr<ServiceWorkerProviderHost> host =
         CreateProviderHostForServiceWorkerContext(
             helper_->mock_render_process_id(), 1 /* provider_id */,
-            true /* is_parent_frame_secure */, context()->AsWeakPtr());
+            true /* is_parent_frame_secure */, context()->AsWeakPtr(),
+            &remote_endpoint_);
     provider_host_ = host->AsWeakPtr();
     context()->AddProviderHost(std::move(host));
     provider_host_->running_hosted_version_ = version_;
@@ -136,6 +137,7 @@
   GURL scope_;
   GURL script_url_;
   GURL import_script_url_;
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint_;
   storage::BlobStorageContext blob_storage_context_;
 };
 
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index 15aac69..ec1e0d4 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -583,33 +583,38 @@
   const GURL kOrigin1 = GURL("http://www.example.com/");
   const GURL kOrigin2 = GURL("https://www.example.com/");
   int provider_id = 1;
+  std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints;
 
   // Host1 (provider_id=1): process_id=1, origin1.
+  remote_endpoints.emplace_back();
   std::unique_ptr<ServiceWorkerProviderHost> host1 =
-      CreateProviderHostForWindow(kRenderProcessId1, provider_id++,
-                                  true /* is_parent_frame_secure */,
-                                  context()->AsWeakPtr());
+      CreateProviderHostForWindow(
+          kRenderProcessId1, provider_id++, true /* is_parent_frame_secure */,
+          context()->AsWeakPtr(), &remote_endpoints.back());
   host1->SetDocumentUrl(kOrigin1);
 
   // Host2 (provider_id=2): process_id=2, origin2.
+  remote_endpoints.emplace_back();
   std::unique_ptr<ServiceWorkerProviderHost> host2 =
-      CreateProviderHostForWindow(kRenderProcessId2, provider_id++,
-                                  true /* is_parent_frame_secure */,
-                                  context()->AsWeakPtr());
+      CreateProviderHostForWindow(
+          kRenderProcessId2, provider_id++, true /* is_parent_frame_secure */,
+          context()->AsWeakPtr(), &remote_endpoints.back());
   host2->SetDocumentUrl(kOrigin2);
 
   // Host3 (provider_id=3): process_id=2, origin1.
+  remote_endpoints.emplace_back();
   std::unique_ptr<ServiceWorkerProviderHost> host3 =
-      CreateProviderHostForWindow(kRenderProcessId2, provider_id++,
-                                  true /* is_parent_frame_secure */,
-                                  context()->AsWeakPtr());
+      CreateProviderHostForWindow(
+          kRenderProcessId2, provider_id++, true /* is_parent_frame_secure */,
+          context()->AsWeakPtr(), &remote_endpoints.back());
   host3->SetDocumentUrl(kOrigin1);
 
   // Host4 (provider_id=4): process_id=2, origin2, for ServiceWorker.
+  remote_endpoints.emplace_back();
   std::unique_ptr<ServiceWorkerProviderHost> host4 =
       CreateProviderHostForServiceWorkerContext(
           kRenderProcessId2, provider_id++, true /* is_parent_frame_secure */,
-          context()->AsWeakPtr());
+          context()->AsWeakPtr(), &remote_endpoints.back());
   host4->SetDocumentUrl(kOrigin2);
 
   ServiceWorkerProviderHost* host1_raw = host1.get();
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index fa176b91..5c4be2f 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -110,10 +110,12 @@
         EmbeddedWorkerTestHelper::CreateHttpResponseInfo());
 
     // An empty host.
+    remote_endpoints_.emplace_back();
     std::unique_ptr<ServiceWorkerProviderHost> host =
         CreateProviderHostForWindow(
             helper_->mock_render_process_id(), kMockProviderId,
-            true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr());
+            true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
+            &remote_endpoints_.back());
     provider_host_ = host->AsWeakPtr();
     context()->AddProviderHost(std::move(host));
 
@@ -140,6 +142,7 @@
   MockResourceContext mock_resource_context_;
   GURL scope_;
   GURL script_url_;
+  std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_;
 };
 
 class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 8fe3b3df..537f97cd 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -967,7 +967,7 @@
     // Otherwise, completed the initialization of the pre-created host.
     DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_WINDOW, info.type);
     provider_host->CompleteNavigationInitialized(render_process_id_,
-                                                 info.route_id, this);
+                                                 std::move(info), this);
     GetContext()->AddProviderHost(std::move(provider_host));
   } else {
     if (ServiceWorkerUtils::IsBrowserAssignedProviderId(info.provider_id)) {
@@ -980,26 +980,6 @@
   }
 }
 
-void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerDispatcherHost::OnProviderDestroyed");
-  if (!GetContext())
-    return;
-  if (!GetContext()->GetProviderHost(render_process_id_, provider_id)) {
-    // PlzNavigate: in some cancellation of navigation cases, it is possible
-    // for the pre-created hoist to have been destroyed before being claimed by
-    // the renderer. The provider is then destroyed in the renderer, and no
-    // matching host will be found.
-    if (!IsBrowserSideNavigationEnabled() ||
-        !ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id)) {
-      bad_message::ReceivedBadMessage(
-          this, bad_message::SWDH_PROVIDER_DESTROYED_NO_HOST);
-    }
-    return;
-  }
-  GetContext()->RemoveProviderHost(render_process_id_, provider_id);
-}
-
 void ServiceWorkerDispatcherHost::OnSetHostedVersionId(int provider_id,
                                                        int64_t version_id,
                                                        int embedded_worker_id) {
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index 4615fb6..f813389 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -101,7 +101,6 @@
 
   // mojom::ServiceWorkerDispatcherHost implementation
   void OnProviderCreated(ServiceWorkerProviderHostInfo info) override;
-  void OnProviderDestroyed(int provider_id) override;
   void OnSetHostedVersionId(int provider_id,
                             int64_t version_id,
                             int embedded_worker_id) override;
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index 46d5a7a4..5ccbba1 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -22,11 +22,13 @@
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_handle.h"
+#include "content/browser/service_worker/service_worker_navigation_handle_core.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/common/service_worker/embedded_worker_messages.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -50,6 +52,47 @@
   ports->push_back(MessagePort(std::move(pipe.handle0)));
 }
 
+struct RemoteProviderInfo {
+  mojom::ServiceWorkerProviderHostAssociatedPtr host_ptr;
+  mojom::ServiceWorkerProviderAssociatedRequest client_request;
+};
+
+RemoteProviderInfo SetupProviderHostInfoPtrs(
+    ServiceWorkerProviderHostInfo* host_info) {
+  RemoteProviderInfo remote_info;
+  mojom::ServiceWorkerProviderAssociatedPtr browser_side_client_ptr;
+  remote_info.client_request =
+      mojo::MakeIsolatedRequest(&browser_side_client_ptr);
+  host_info->host_request = mojo::MakeIsolatedRequest(&remote_info.host_ptr);
+  host_info->client_ptr_info = browser_side_client_ptr.PassInterface();
+  EXPECT_TRUE(host_info->host_request.is_pending());
+  EXPECT_TRUE(host_info->client_ptr_info.is_valid());
+  EXPECT_TRUE(remote_info.host_ptr.is_bound());
+  EXPECT_TRUE(remote_info.client_request.is_pending());
+  return remote_info;
+}
+
+std::unique_ptr<ServiceWorkerNavigationHandleCore> CreateNavigationHandleCore(
+    ServiceWorkerContextWrapper* context_wrapper) {
+  std::unique_ptr<ServiceWorkerNavigationHandleCore> navigation_handle_core;
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(
+          [](ServiceWorkerContextWrapper* wrapper) {
+            return base::MakeUnique<ServiceWorkerNavigationHandleCore>(nullptr,
+                                                                       wrapper);
+          },
+          context_wrapper),
+      base::Bind(
+          [](std::unique_ptr<ServiceWorkerNavigationHandleCore>* dest,
+             std::unique_ptr<ServiceWorkerNavigationHandleCore> src) {
+            *dest = std::move(src);
+          },
+          &navigation_handle_core));
+  base::RunLoop().RunUntilIdle();
+  return navigation_handle_core;
+}
+
 }  // namespace
 
 static const int kRenderFrameId = 1;
@@ -168,6 +211,8 @@
     const int64_t kProviderId = 99;
     ServiceWorkerProviderHostInfo info(kProviderId, MSG_ROUTING_NONE, type,
                                        true /* is_parent_frame_secure */);
+    remote_endpoint_.BindWithProviderHostInfo(&info);
+
     dispatcher_host_->OnProviderCreated(std::move(info));
     helper_->SimulateAddProcessToPattern(pattern,
                                          helper_->mock_render_process_id());
@@ -253,7 +298,7 @@
       int provider_id) {
     return CreateProviderHostWithDispatcherHost(
         helper_->mock_render_process_id(), provider_id, context()->AsWeakPtr(),
-        kRenderFrameId, dispatcher_host_.get());
+        kRenderFrameId, dispatcher_host_.get(), &remote_endpoint_);
   }
 
   TestBrowserThreadBundle browser_thread_bundle_;
@@ -263,6 +308,7 @@
   scoped_refptr<ServiceWorkerRegistration> registration_;
   scoped_refptr<ServiceWorkerVersion> version_;
   ServiceWorkerProviderHost* provider_host_;
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint_;
 };
 
 class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
@@ -509,32 +555,66 @@
 }
 
 TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) {
-  const int kProviderId = 1001;
+  // |kProviderId| must be -2 when PlzNavigate is enabled to match the
+  // pre-created provider host. Otherwise |kProviderId| is just a dummy value.
+  const int kProviderId = (IsBrowserSideNavigationEnabled() ? -2 : 1001);
   int process_id = helper_->mock_render_process_id();
 
-  dispatcher_host_->OnProviderCreated(ServiceWorkerProviderHostInfo(
-      kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
-      true /* is_parent_frame_secure */));
+  // Setup ServiceWorkerProviderHostInfo.
+  ServiceWorkerProviderHostInfo host_info_1(kProviderId, 1 /* route_id */,
+                                            SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+                                            true /* is_parent_frame_secure */);
+  ServiceWorkerProviderHostInfo host_info_2(kProviderId, 1 /* route_id */,
+                                            SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+                                            true /* is_parent_frame_secure */);
+  ServiceWorkerProviderHostInfo host_info_3(kProviderId, 1 /* route_id */,
+                                            SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+                                            true /* is_parent_frame_secure */);
+  RemoteProviderInfo remote_info_1 = SetupProviderHostInfoPtrs(&host_info_1);
+  RemoteProviderInfo remote_info_2 = SetupProviderHostInfoPtrs(&host_info_2);
+  RemoteProviderInfo remote_info_3 = SetupProviderHostInfoPtrs(&host_info_3);
+
+  // PlzNavigate
+  std::unique_ptr<ServiceWorkerNavigationHandleCore> navigation_handle_core;
+  if (IsBrowserSideNavigationEnabled()) {
+    navigation_handle_core =
+        CreateNavigationHandleCore(helper_->context_wrapper());
+    ASSERT_TRUE(navigation_handle_core);
+    // ProviderHost should be created before OnProviderCreated.
+    navigation_handle_core->DidPreCreateProviderHost(
+        ServiceWorkerProviderHost::PreCreateNavigationHost(
+            helper_->context()->AsWeakPtr(), true /* are_ancestors_secure */,
+            base::Callback<WebContents*(void)>()));
+  }
+
+  dispatcher_host_->OnProviderCreated(std::move(host_info_1));
   EXPECT_TRUE(context()->GetProviderHost(process_id, kProviderId));
 
   // Two with the same ID should be seen as a bad message.
-  dispatcher_host_->OnProviderCreated(ServiceWorkerProviderHostInfo(
-      kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
-      true /* is_parent_frame_secure */));
+  dispatcher_host_->OnProviderCreated(std::move(host_info_2));
   EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
 
-  dispatcher_host_->OnProviderDestroyed(kProviderId);
+  // Releasing the interface pointer destroys the counterpart.
+  remote_info_1.host_ptr.reset();
+  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(context()->GetProviderHost(process_id, kProviderId));
 
-  // Destroying an ID that does not exist warrants a bad message.
-  dispatcher_host_->OnProviderDestroyed(kProviderId);
-  EXPECT_EQ(2, dispatcher_host_->bad_messages_received_count_);
+  // PlzNavigate
+  // Prepare another navigation handle to create another provider host.
+  if (IsBrowserSideNavigationEnabled()) {
+    navigation_handle_core =
+        CreateNavigationHandleCore(helper_->context_wrapper());
+    ASSERT_TRUE(navigation_handle_core);
+    // ProviderHost should be created before OnProviderCreated.
+    navigation_handle_core->DidPreCreateProviderHost(
+        ServiceWorkerProviderHost::PreCreateNavigationHost(
+            helper_->context()->AsWeakPtr(), true /* are_ancestors_secure */,
+            base::Callback<WebContents*(void)>()));
+  }
 
   // Deletion of the dispatcher_host should cause providers for that
   // process to get deleted as well.
-  dispatcher_host_->OnProviderCreated(ServiceWorkerProviderHostInfo(
-      kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
-      true /* is_parent_frame_secure */));
+  dispatcher_host_->OnProviderCreated(std::move(host_info_3));
   EXPECT_TRUE(context()->GetProviderHost(process_id, kProviderId));
   EXPECT_TRUE(dispatcher_host_->HasOneRef());
   dispatcher_host_ = nullptr;
@@ -669,9 +749,12 @@
   // To show the new dispatcher can operate, simulate provider creation. Since
   // the old dispatcher cleaned up the old provider host, the new one won't
   // complain.
-  new_dispatcher_host->OnProviderCreated(ServiceWorkerProviderHostInfo(
-      provider_id, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
-      true /* is_parent_frame_secure */));
+  ServiceWorkerProviderHostInfo host_info(provider_id, MSG_ROUTING_NONE,
+                                          SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+                                          true /* is_parent_frame_secure */);
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint;
+  remote_endpoint.BindWithProviderHostInfo(&host_info);
+  new_dispatcher_host->OnProviderCreated(std::move(host_info));
   EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_);
 }
 
diff --git a/content/browser/service_worker/service_worker_handle_unittest.cc b/content/browser/service_worker/service_worker_handle_unittest.cc
index 4a76ba5d..f3cdc0969 100644
--- a/content/browser/service_worker/service_worker_handle_unittest.cc
+++ b/content/browser/service_worker/service_worker_handle_unittest.cc
@@ -113,8 +113,8 @@
 
     provider_host_ = CreateProviderHostWithDispatcherHost(
         helper_->mock_render_process_id(), 1 /* provider_id */,
-        helper_->context()->AsWeakPtr(), kRenderFrameId,
-        dispatcher_host_.get());
+        helper_->context()->AsWeakPtr(), kRenderFrameId, dispatcher_host_.get(),
+        &remote_endpoint_);
     helper_->SimulateAddProcessToPattern(pattern,
                                          helper_->mock_render_process_id());
   }
@@ -137,6 +137,7 @@
   scoped_refptr<ServiceWorkerRegistration> registration_;
   scoped_refptr<ServiceWorkerVersion> version_;
   scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_;
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerHandleTest);
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index ca7aea28..c8fed4d 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -173,6 +173,7 @@
 
   TestBrowserThreadBundle browser_thread_bundle_;
   std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
+  std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_;
 };
 
 scoped_refptr<ServiceWorkerRegistration> ServiceWorkerJobTest::RunRegisterJob(
@@ -219,9 +220,11 @@
 
 std::unique_ptr<ServiceWorkerProviderHost>
 ServiceWorkerJobTest::CreateControllee() {
+  remote_endpoints_.emplace_back();
   std::unique_ptr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
       33 /* dummy render process id */, 1 /* dummy provider_id */,
-      true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr());
+      true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
+      &remote_endpoints_.back());
   return host;
 }
 
diff --git a/content/browser/service_worker/service_worker_navigation_handle_core.h b/content/browser/service_worker/service_worker_navigation_handle_core.h
index 88e5013..8e98b05 100644
--- a/content/browser/service_worker/service_worker_navigation_handle_core.h
+++ b/content/browser/service_worker/service_worker_navigation_handle_core.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
 
 namespace content {
 
@@ -24,7 +25,7 @@
 // pendant of ServiceWorkerNavigationHandle. See the
 // ServiceWorkerNavigationHandle header for more details about the lifetime of
 // both classes.
-class ServiceWorkerNavigationHandleCore {
+class CONTENT_EXPORT ServiceWorkerNavigationHandleCore {
  public:
   ServiceWorkerNavigationHandleCore(
       base::WeakPtr<ServiceWorkerNavigationHandle> ui_handle,
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 4dd89cd..7671561 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -61,8 +61,8 @@
   // Called via custom URLRequestJobFactory.
   net::URLRequestJob* MaybeCreateJob(
       net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      ResourceContext* resource_context) override {
+      net::NetworkDelegate* /* network_delegate */,
+      ResourceContext* /* resource_context */) override {
     // |provider_host_| may have been deleted when the request is resumed.
     if (!provider_host_)
       return nullptr;
@@ -76,6 +76,26 @@
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLTrackingRequestHandler);
 };
 
+void RemoveProviderHost(base::WeakPtr<ServiceWorkerContextCore> context,
+                        int process_id,
+                        int provider_id) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerProviderHost::RemoveProviderHost");
+  if (!context)
+    return;
+  if (!context->GetProviderHost(process_id, provider_id)) {
+    // PlzNavigate: in some cancellation of navigation cases, it is possible
+    // for the pre-created host, whose |provider_id| is assigned by the browser
+    // process, to have been destroyed before being claimed by the renderer. The
+    // provider is then destroyed in the renderer, and no matching host will be
+    // found.
+    DCHECK(IsBrowserSideNavigationEnabled() &&
+           ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id));
+    return;
+  }
+  context->RemoveProviderHost(process_id, provider_id);
+}
+
 }  // anonymous namespace
 
 ServiceWorkerProviderHost::OneShotGetReadyCallback::OneShotGetReadyCallback(
@@ -152,7 +172,8 @@
       info_(std::move(info)),
       context_(context),
       dispatcher_host_(dispatcher_host),
-      allow_association_(true) {
+      allow_association_(true),
+      binding_(this) {
   DCHECK_NE(SERVICE_WORKER_PROVIDER_UNKNOWN, info_.type);
 
   // PlzNavigate
@@ -164,6 +185,18 @@
     render_thread_id_ = kInvalidEmbeddedWorkerThreadId;
   }
   context_->RegisterProviderHostByClientID(client_uuid_, this);
+
+  // PlzNavigate
+  // |provider_| and |binding_| will be bound on CompleteNavigationInitialized.
+  if (IsBrowserSideNavigationEnabled()) {
+    DCHECK(!info.client_ptr_info.is_valid() && !info.host_request.is_pending());
+    return;
+  }
+
+  provider_.Bind(std::move(info_.client_ptr_info));
+  binding_.Bind(std::move(info_.host_request));
+  binding_.set_connection_error_handler(base::Bind(
+      &RemoveProviderHost, context_, render_process_id, info_.provider_id));
 }
 
 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
@@ -210,7 +243,7 @@
 void ServiceWorkerProviderHost::OnVersionAttributesChanged(
     ServiceWorkerRegistration* registration,
     ChangedVersionAttributesMask changed_mask,
-    const ServiceWorkerRegistrationInfo& info) {
+    const ServiceWorkerRegistrationInfo& /* info */) {
   if (!get_ready_callback_ || get_ready_callback_->called)
     return;
   if (changed_mask.active_changed() && registration->active_version()) {
@@ -538,7 +571,10 @@
 
   std::unique_ptr<ServiceWorkerProviderHost> provisional_host =
       base::WrapUnique(new ServiceWorkerProviderHost(
-          process_id(), std::move(info_), context_, dispatcher_host()));
+          process_id(),
+          ServiceWorkerProviderHostInfo(std::move(info_), binding_.Unbind(),
+                                        provider_.PassInterface()),
+          context_, dispatcher_host()));
 
   for (const GURL& pattern : associated_patterns_)
     DecreaseProcessReference(pattern);
@@ -568,6 +604,15 @@
   render_thread_id_ = kDocumentMainThreadId;
   info_ = std::move(provisional_host->info_);
 
+  // Take the connection over from the provisional host.
+  DCHECK(!provider_.is_bound());
+  DCHECK(!binding_.is_bound());
+  provider_.Bind(provisional_host->provider_.PassInterface());
+  binding_.Bind(provisional_host->binding_.Unbind());
+  binding_.set_connection_error_handler(
+      base::Bind(&RemoveProviderHost, context_, provisional_host->process_id(),
+                 provider_id()));
+
   FinalizeInitialization(provisional_host->process_id(),
                          provisional_host->dispatcher_host());
 }
@@ -575,7 +620,7 @@
 // PlzNavigate
 void ServiceWorkerProviderHost::CompleteNavigationInitialized(
     int process_id,
-    int frame_routing_id,
+    ServiceWorkerProviderHostInfo info,
     ServiceWorkerDispatcherHost* dispatcher_host) {
   CHECK(IsBrowserSideNavigationEnabled());
   DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, render_process_id_);
@@ -583,9 +628,18 @@
   DCHECK_EQ(kDocumentMainThreadId, render_thread_id_);
 
   DCHECK_NE(ChildProcessHost::kInvalidUniqueID, process_id);
-  DCHECK_NE(MSG_ROUTING_NONE, frame_routing_id);
+  DCHECK_EQ(info_.provider_id, info.provider_id);
+  DCHECK_NE(MSG_ROUTING_NONE, info.route_id);
 
-  info_.route_id = frame_routing_id;
+  // Connect with the provider on the renderer.
+  DCHECK(!provider_.is_bound());
+  DCHECK(!binding_.is_bound());
+  provider_.Bind(std::move(info.client_ptr_info));
+  binding_.Bind(std::move(info.host_request));
+  binding_.set_connection_error_handler(
+      base::Bind(&RemoveProviderHost, context_, process_id, provider_id()));
+  info_.route_id = info.route_id;
+
   FinalizeInitialization(process_id, dispatcher_host);
 }
 
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 4aa814af..bf34ff1 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -22,11 +22,13 @@
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/common/content_export.h"
 #include "content/common/service_worker/service_worker_provider_host_info.h"
+#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/worker_url_loader_factory_provider.mojom.h"
 #include "content/public/common/request_context_frame_type.h"
 #include "content/public/common/request_context_type.h"
 #include "content/public/common/resource_type.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 
 namespace storage {
 class BlobStorageContext;
@@ -54,9 +56,20 @@
 //
 // For providers hosting a running service worker, this class will observe
 // resource loads made directly by the service worker.
+//
+// This instance is created when navigation is started and
+// ServiceWorkerNetworkProvider is create on the renderer process. Mojo's
+// connection from ServiceWorkerNetworkProvider is established on the creation
+// time, and the instance is destroyed on disconnection from the renderer side.
+// If PlzNavigate is turned on, this instance is pre-created on the browser
+// before ServiceWorkerNetworkProvider is created on the renderer because
+// navigation is possible to be initiated on the browser side. In that case,
+// establishment of Mojo's connection will be deferred until
+// ServiceWorkerNetworkProvider is created on the renderer.
 class CONTENT_EXPORT ServiceWorkerProviderHost
     : public NON_EXPORTED_BASE(ServiceWorkerRegistration::Listener),
-      public base::SupportsWeakPtr<ServiceWorkerProviderHost> {
+      public base::SupportsWeakPtr<ServiceWorkerProviderHost>,
+      public NON_EXPORTED_BASE(mojom::ServiceWorkerProviderHost) {
  public:
   using GetRegistrationForReadyCallback =
       base::Callback<void(ServiceWorkerRegistration* reigstration)>;
@@ -84,7 +97,7 @@
       base::WeakPtr<ServiceWorkerContextCore> context,
       ServiceWorkerDispatcherHost* dispatcher_host);
 
-  virtual ~ServiceWorkerProviderHost();
+  ~ServiceWorkerProviderHost() override;
 
   const std::string& client_uuid() const { return client_uuid_; }
   int process_id() const { return render_process_id_; }
@@ -250,7 +263,7 @@
   // Completes initialization of provider hosts used for navigation requests.
   void CompleteNavigationInitialized(
       int process_id,
-      int frame_routing_id,
+      ServiceWorkerProviderHostInfo info,
       ServiceWorkerDispatcherHost* dispatcher_host);
 
   // Sends event messages to the renderer. Events for the worker are queued up
@@ -318,7 +331,7 @@
     ~OneShotGetReadyCallback();
   };
 
-  ServiceWorkerProviderHost(int render_process_id,
+  ServiceWorkerProviderHost(int process_id,
                             ServiceWorkerProviderHostInfo info,
                             base::WeakPtr<ServiceWorkerContextCore> context,
                             ServiceWorkerDispatcherHost* dispatcher_host);
@@ -402,6 +415,14 @@
   ServiceWorkerDispatcherHost* dispatcher_host_;
   bool allow_association_;
 
+  // |provider_| is the renderer-side Mojo endpoint for provider.
+  mojom::ServiceWorkerProviderAssociatedPtr provider_;
+  // |binding_| is the Mojo binding that keeps the connection to the
+  // renderer-side counterpart (content::ServiceWorkerNetworkProvider). When the
+  // connection bound on |binding_| gets killed from the renderer side, this
+  // content::ServiceWorkerProviderHost will be destroyed.
+  mojo::AssociatedBinding<mojom::ServiceWorkerProviderHost> binding_;
+
   std::vector<base::Closure> queued_events_;
 
   // Keeps ServiceWorkerWorkerClient pointers of dedicated or shared workers
diff --git a/content/browser/service_worker/service_worker_provider_host_unittest.cc b/content/browser/service_worker/service_worker_provider_host_unittest.cc
index b41b982..b100d3b 100644
--- a/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -18,6 +18,7 @@
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/common/url_schemes.h"
+#include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/origin_util.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -41,7 +42,8 @@
  protected:
   ServiceWorkerProviderHostTest()
       : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
-        next_provider_id_(1) {
+        next_renderer_provided_id_(1),
+        next_browser_provided_id_(-2) {
     SetContentClient(&test_content_client_);
   }
   ~ServiceWorkerProviderHostTest() override {}
@@ -76,10 +78,26 @@
   }
 
   ServiceWorkerProviderHost* CreateProviderHost(const GURL& document_url) {
-    std::unique_ptr<ServiceWorkerProviderHost> host =
-        CreateProviderHostForWindow(
-            helper_->mock_render_process_id(), next_provider_id_++,
-            true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr());
+    remote_endpoints_.emplace_back();
+    std::unique_ptr<ServiceWorkerProviderHost> host;
+    if (IsBrowserSideNavigationEnabled()) {
+      host = ServiceWorkerProviderHost::PreCreateNavigationHost(
+          helper_->context()->AsWeakPtr(), true,
+          base::Callback<WebContents*(void)>());
+      ServiceWorkerProviderHostInfo info(next_browser_provided_id_--,
+                                         1 /* route_id */,
+                                         SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+                                         true /* is_parent_frame_secure */);
+      remote_endpoints_.back().BindWithProviderHostInfo(&info);
+      host->CompleteNavigationInitialized(helper_->mock_render_process_id(),
+                                          std::move(info), nullptr);
+    } else {
+      host = CreateProviderHostForWindow(
+          helper_->mock_render_process_id(), next_renderer_provided_id_++,
+          true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
+          &remote_endpoints_.back());
+    }
+
     ServiceWorkerProviderHost* host_raw = host.get();
     host->SetDocumentUrl(document_url);
     context_->AddProviderHost(std::move(host));
@@ -88,11 +106,12 @@
 
   ServiceWorkerProviderHost* CreateProviderHostWithInsecureParentFrame(
       const GURL& document_url) {
+    remote_endpoints_.emplace_back();
     std::unique_ptr<ServiceWorkerProviderHost> host =
-        CreateProviderHostForWindow(helper_->mock_render_process_id(),
-                                    next_provider_id_++,
-                                    false /* is_parent_frame_secure */,
-                                    helper_->context()->AsWeakPtr());
+        CreateProviderHostForWindow(
+            helper_->mock_render_process_id(), next_renderer_provided_id_++,
+            false /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
+            &remote_endpoints_.back());
     ServiceWorkerProviderHost* host_raw = host.get();
     host->SetDocumentUrl(document_url);
     context_->AddProviderHost(std::move(host));
@@ -109,7 +128,9 @@
   ServiceWorkerTestContentClient test_content_client_;
   TestContentBrowserClient test_content_browser_client_;
   ContentBrowserClient* old_content_browser_client_;
-  int next_provider_id_;
+  int next_renderer_provided_id_;
+  int next_browser_provided_id_;
+  std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHostTest);
@@ -226,6 +247,8 @@
 }
 
 TEST_F(ServiceWorkerProviderHostTest, CrossSiteTransfer) {
+  if (IsBrowserSideNavigationEnabled())
+    return;
   ServiceWorkerProviderHost* provider_host =
       CreateProviderHost(GURL("https://www.example.com/example.html"));
   const int process_id = provider_host->process_id();
@@ -269,4 +292,19 @@
   EXPECT_EQ(nullptr, provisional_host->dispatcher_host());
 }
 
+TEST_F(ServiceWorkerProviderHostTest, RemoveProvider) {
+  // Create a provider host connected with the renderer process.
+  ServiceWorkerProviderHost* provider_host =
+      CreateProviderHost(GURL("https://www.example.com/example1.html"));
+  int process_id = provider_host->process_id();
+  int provider_id = provider_host->provider_id();
+  EXPECT_TRUE(context_->GetProviderHost(process_id, provider_id));
+
+  // Disconnect the mojo pipe from the renderer side.
+  ASSERT_TRUE(remote_endpoints_.back().host_ptr()->is_bound());
+  remote_endpoints_.back().host_ptr()->reset();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(context_->GetProviderHost(process_id, provider_id));
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc
index 6e1b444..490f6ec 100644
--- a/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -258,7 +258,8 @@
     // Give the active version a controllee.
     host_ = CreateProviderHostForWindow(
         33 /* dummy render process id */, 1 /* dummy provider_id */,
-        true /* is_parent_frame_secure */, context()->AsWeakPtr());
+        true /* is_parent_frame_secure */, context()->AsWeakPtr(),
+        &remote_endpoint_);
     version_1->AddControllee(host_.get());
 
     // Give the active version an in-flight request.
@@ -292,6 +293,7 @@
  private:
   scoped_refptr<ServiceWorkerRegistration> registration_;
   std::unique_ptr<ServiceWorkerProviderHost> host_;
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint_;
   int inflight_request_id_ = -1;
 };
 
diff --git a/content/browser/service_worker/service_worker_request_handler_unittest.cc b/content/browser/service_worker/service_worker_request_handler_unittest.cc
index bc1e378..86f0d4d 100644
--- a/content/browser/service_worker/service_worker_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_request_handler_unittest.cc
@@ -44,9 +44,10 @@
 
     // An empty host.
     std::unique_ptr<ServiceWorkerProviderHost> host =
-        CreateProviderHostForWindow(
-            helper_->mock_render_process_id(), kMockProviderId,
-            true /* is_parent_frame_secure */, context()->AsWeakPtr());
+        CreateProviderHostForWindow(helper_->mock_render_process_id(),
+                                    kMockProviderId,
+                                    true /* is_parent_frame_secure */,
+                                    context()->AsWeakPtr(), &remote_endpoint_);
     provider_host_ = host->AsWeakPtr();
     context()->AddProviderHost(std::move(host));
   }
@@ -111,6 +112,7 @@
   net::URLRequestContext url_request_context_;
   net::TestDelegate url_request_delegate_;
   storage::BlobStorageContext blob_storage_context_;
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint_;
 };
 
 TEST_F(ServiceWorkerRequestHandlerTest, InitializeHandler_FTP) {
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc
index 262ba79..c74f8b9 100644
--- a/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -1346,9 +1346,11 @@
   registration_->SetActiveVersion(registration_->waiting_version());
   storage()->UpdateToActiveState(
       registration_.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint;
   std::unique_ptr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
       33 /* dummy render process id */, 1 /* dummy provider_id */,
-      true /* is_parent_frame_secure */, context()->AsWeakPtr());
+      true /* is_parent_frame_secure */, context()->AsWeakPtr(),
+      &remote_endpoint);
   registration_->active_version()->AddControllee(host.get());
 
   bool was_called = false;
@@ -1396,9 +1398,11 @@
   registration_->SetWaitingVersion(NULL);
   storage()->UpdateToActiveState(
       registration_.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint;
   std::unique_ptr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
       33 /* dummy render process id */, 1 /* dummy provider_id */,
-      true /* is_parent_frame_secure */, context()->AsWeakPtr());
+      true /* is_parent_frame_secure */, context()->AsWeakPtr(),
+      &remote_endpoint);
   registration_->active_version()->AddControllee(host.get());
 
   bool was_called = false;
@@ -1554,9 +1558,11 @@
   registration_->SetActiveVersion(registration_->waiting_version());
   storage()->UpdateToActiveState(
       registration_.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint;
   std::unique_ptr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
       33 /* dummy render process id */, 1 /* dummy provider_id */,
-      true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr());
+      true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
+      &remote_endpoint);
   registration_->active_version()->AddControllee(host.get());
 
   bool was_called = false;
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc
index 5b0ee5d9..4c8f7390 100644
--- a/content/browser/service_worker/service_worker_test_utils.cc
+++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -10,14 +10,32 @@
 
 namespace content {
 
+ServiceWorkerRemoteProviderEndpoint::ServiceWorkerRemoteProviderEndpoint() {}
+ServiceWorkerRemoteProviderEndpoint::ServiceWorkerRemoteProviderEndpoint(
+    ServiceWorkerRemoteProviderEndpoint&& other)
+    : host_ptr_(std::move(other.host_ptr_)),
+      client_request_(std::move(other.client_request_)) {}
+
+ServiceWorkerRemoteProviderEndpoint::~ServiceWorkerRemoteProviderEndpoint() {}
+
+void ServiceWorkerRemoteProviderEndpoint::BindWithProviderHostInfo(
+    content::ServiceWorkerProviderHostInfo* info) {
+  mojom::ServiceWorkerProviderAssociatedPtr client_ptr;
+  client_request_ = mojo::MakeIsolatedRequest(&client_ptr);
+  info->client_ptr_info = client_ptr.PassInterface();
+  info->host_request = mojo::MakeIsolatedRequest(&host_ptr_);
+}
+
 std::unique_ptr<ServiceWorkerProviderHost> CreateProviderHostForWindow(
     int process_id,
     int provider_id,
     bool is_parent_frame_secure,
-    base::WeakPtr<ServiceWorkerContextCore> context) {
+    base::WeakPtr<ServiceWorkerContextCore> context,
+    ServiceWorkerRemoteProviderEndpoint* output_endpoint) {
   ServiceWorkerProviderHostInfo info(provider_id, 1 /* route_id */,
                                      SERVICE_WORKER_PROVIDER_FOR_WINDOW,
                                      is_parent_frame_secure);
+  output_endpoint->BindWithProviderHostInfo(&info);
   return ServiceWorkerProviderHost::Create(process_id, std::move(info),
                                            std::move(context), nullptr);
 }
@@ -27,10 +45,12 @@
     int process_id,
     int provider_id,
     bool is_parent_frame_secure,
-    base::WeakPtr<ServiceWorkerContextCore> context) {
+    base::WeakPtr<ServiceWorkerContextCore> context,
+    ServiceWorkerRemoteProviderEndpoint* output_endpoint) {
   ServiceWorkerProviderHostInfo info(provider_id, MSG_ROUTING_NONE,
                                      SERVICE_WORKER_PROVIDER_FOR_CONTROLLER,
                                      is_parent_frame_secure);
+  output_endpoint->BindWithProviderHostInfo(&info);
   return ServiceWorkerProviderHost::Create(process_id, std::move(info),
                                            std::move(context), nullptr);
 }
@@ -40,9 +60,11 @@
     int provider_id,
     base::WeakPtr<ServiceWorkerContextCore> context,
     int route_id,
-    ServiceWorkerDispatcherHost* dispatcher_host) {
+    ServiceWorkerDispatcherHost* dispatcher_host,
+    ServiceWorkerRemoteProviderEndpoint* output_endpoint) {
   ServiceWorkerProviderHostInfo info(provider_id, route_id,
                                      SERVICE_WORKER_PROVIDER_FOR_WINDOW, true);
+  output_endpoint->BindWithProviderHostInfo(&info);
   return ServiceWorkerProviderHost::Create(process_id, std::move(info),
                                            std::move(context), dispatcher_host);
 }
diff --git a/content/browser/service_worker/service_worker_test_utils.h b/content/browser/service_worker/service_worker_test_utils.h
index 279faf3..2c9a086 100644
--- a/content/browser/service_worker/service_worker_test_utils.h
+++ b/content/browser/service_worker/service_worker_test_utils.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/memory/weak_ptr.h"
+#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -20,6 +21,7 @@
 class ServiceWorkerContextCore;
 class ServiceWorkerDispatcherHost;
 class ServiceWorkerProviderHost;
+struct ServiceWorkerProviderHostInfo;
 
 template <typename Arg>
 void ReceiveResult(BrowserThread::ID run_quit_thread,
@@ -46,25 +48,58 @@
   return base::Bind(&ReceiveResult<Arg>, id, quit, out);
 }
 
+// Container for keeping the Mojo connection to the service worker provider on
+// the renderer alive.
+class ServiceWorkerRemoteProviderEndpoint {
+ public:
+  ServiceWorkerRemoteProviderEndpoint();
+  ServiceWorkerRemoteProviderEndpoint(
+      ServiceWorkerRemoteProviderEndpoint&& other);
+  ~ServiceWorkerRemoteProviderEndpoint();
+
+  void BindWithProviderHostInfo(ServiceWorkerProviderHostInfo* info);
+
+  mojom::ServiceWorkerProviderHostAssociatedPtr* host_ptr() {
+    return &host_ptr_;
+  }
+
+  mojom::ServiceWorkerProviderAssociatedRequest* client_request() {
+    return &client_request_;
+  }
+
+ private:
+  // Bound with content::ServiceWorkerProviderHost. The provider host will be
+  // removed asynchronously when this pointer is closed.
+  mojom::ServiceWorkerProviderHostAssociatedPtr host_ptr_;
+  // This is the other end of ServiceWorkerProviderAssociatedPtr owned by
+  // content::ServiceWorkerProviderHost.
+  mojom::ServiceWorkerProviderAssociatedRequest client_request_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRemoteProviderEndpoint);
+};
+
 std::unique_ptr<ServiceWorkerProviderHost> CreateProviderHostForWindow(
     int process_id,
     int provider_id,
     bool is_parent_frame_secure,
-    base::WeakPtr<ServiceWorkerContextCore> context);
+    base::WeakPtr<ServiceWorkerContextCore> context,
+    ServiceWorkerRemoteProviderEndpoint* output_endpoint);
 
 std::unique_ptr<ServiceWorkerProviderHost>
 CreateProviderHostForServiceWorkerContext(
     int process_id,
     int provider_id,
     bool is_parent_frame_secure,
-    base::WeakPtr<ServiceWorkerContextCore> context);
+    base::WeakPtr<ServiceWorkerContextCore> context,
+    ServiceWorkerRemoteProviderEndpoint* output_endpoint);
 
 std::unique_ptr<ServiceWorkerProviderHost> CreateProviderHostWithDispatcherHost(
     int process_id,
     int provider_id,
     base::WeakPtr<ServiceWorkerContextCore> context,
     int route_id,
-    ServiceWorkerDispatcherHost* dispatcher_host);
+    ServiceWorkerDispatcherHost* dispatcher_host,
+    ServiceWorkerRemoteProviderEndpoint* output_endpoint);
 
 }  // namespace content
 
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 33378da..1c8ae85 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -196,7 +196,8 @@
     std::unique_ptr<ServiceWorkerProviderHost> provider_host =
         CreateProviderHostForWindow(
             helper_->mock_render_process_id(), kProviderID,
-            true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr());
+            true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
+            &remote_endpoint_);
     provider_host_ = provider_host->AsWeakPtr();
     provider_host->SetDocumentUrl(GURL("https://example.com/"));
     registration_->SetActiveVersion(version_);
@@ -355,6 +356,8 @@
 
   int times_prepare_to_restart_invoked_ = 0;
   base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint_;
+
   // Not owned.
   MockHttpProtocolHandler* http_protocol_handler_;
 
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 4531d0e..5dc91dc 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -627,9 +627,11 @@
   // Adding a controllee resets the idle time.
   version_->idle_time_ -= kOneSecond;
   idle_time = version_->idle_time_;
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint;
   std::unique_ptr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
       33 /* dummy render process id */, 1 /* dummy provider_id */,
-      true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr());
+      true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
+      &remote_endpoint);
   version_->AddControllee(host.get());
   EXPECT_TRUE(version_->timeout_timer_.IsRunning());
   EXPECT_LT(idle_time, version_->idle_time_);
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
index 6940bdc..544ba639 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
@@ -293,7 +293,7 @@
     std::unique_ptr<ServiceWorkerProviderHost> host =
         CreateProviderHostForServiceWorkerContext(
             process_id, provider_id, true /* is_parent_frame_secure */,
-            context()->AsWeakPtr());
+            context()->AsWeakPtr(), &remote_endpoint_);
     base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
     context()->AddProviderHost(std::move(host));
     provider_host->running_hosted_version_ = version;
@@ -441,6 +441,7 @@
 
   storage::BlobStorageContext blob_storage_context_;
   content::MockResourceContext resource_context_;
+  ServiceWorkerRemoteProviderEndpoint remote_endpoint_;
 
   net::TestDelegate url_request_delegate_;
   int next_provider_id_ = 1;
diff --git a/content/browser/vibration_browsertest.cc b/content/browser/vibration_browsertest.cc
index 0115896..1739fabd 100644
--- a/content/browser/vibration_browsertest.cc
+++ b/content/browser/vibration_browsertest.cc
@@ -60,12 +60,12 @@
 
  private:
   // device::mojom::VibrationManager:
-  void Vibrate(int64_t milliseconds, const VibrateCallback& callback) override {
+  void Vibrate(int64_t milliseconds, VibrateCallback callback) override {
     vibrate_milliseconds_ = milliseconds;
-    callback.Run();
+    std::move(callback).Run();
     vibrate_done_.Run();
   }
-  void Cancel(const CancelCallback& callback) override { callback.Run(); }
+  void Cancel(CancelCallback callback) override { std::move(callback).Run(); }
 
   int64_t vibrate_milliseconds_ = -1;
   base::Closure vibrate_done_;
diff --git a/content/child/service_worker/service_worker_dispatcher_unittest.cc b/content/child/service_worker/service_worker_dispatcher_unittest.cc
index 9f15581..93d25c2 100644
--- a/content/child/service_worker/service_worker_dispatcher_unittest.cc
+++ b/content/child/service_worker/service_worker_dispatcher_unittest.cc
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "content/child/service_worker/service_worker_dispatcher.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
-#include "content/child/service_worker/service_worker_dispatcher.h"
 #include "content/child/service_worker/service_worker_handle_reference.h"
 #include "content/child/service_worker/service_worker_provider_context.h"
 #include "content/child/service_worker/web_service_worker_impl.h"
 #include "content/child/service_worker/web_service_worker_registration_impl.h"
 #include "content/child/thread_safe_sender.h"
 #include "content/common/service_worker/service_worker_messages.h"
+#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "ipc/ipc_sync_message_filter.h"
 #include "ipc/ipc_test_sink.h"
@@ -195,9 +196,10 @@
   // Set up ServiceWorkerProviderContext for ServiceWorkerGlobalScope.
   const int kProviderId = 10;
   scoped_refptr<ServiceWorkerProviderContext> provider_context(
-      new ServiceWorkerProviderContext(kProviderId,
-                                       SERVICE_WORKER_PROVIDER_FOR_CONTROLLER,
-                                       thread_safe_sender()));
+      new ServiceWorkerProviderContext(
+          kProviderId, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER,
+          mojom::ServiceWorkerProviderAssociatedRequest(),
+          thread_safe_sender()));
 
   // The passed references should be adopted and owned by the provider context.
   OnAssociateRegistration(kDocumentMainThreadId, kProviderId, info, attrs);
@@ -228,9 +230,10 @@
   // Set up ServiceWorkerProviderContext for a document context.
   const int kProviderId = 10;
   scoped_refptr<ServiceWorkerProviderContext> provider_context(
-      new ServiceWorkerProviderContext(kProviderId,
-                                       SERVICE_WORKER_PROVIDER_FOR_WINDOW,
-                                       thread_safe_sender()));
+      new ServiceWorkerProviderContext(
+          kProviderId, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+          mojom::ServiceWorkerProviderAssociatedRequest(),
+          thread_safe_sender()));
 
   // The passed references should be adopted and only the registration reference
   // should be owned by the provider context.
@@ -277,9 +280,10 @@
   // the provider, the passed referecence should be adopted and owned by the
   // provider context.
   scoped_refptr<ServiceWorkerProviderContext> provider_context(
-      new ServiceWorkerProviderContext(kProviderId,
-                                       SERVICE_WORKER_PROVIDER_FOR_WINDOW,
-                                       thread_safe_sender()));
+      new ServiceWorkerProviderContext(
+          kProviderId, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+          mojom::ServiceWorkerProviderAssociatedRequest(),
+          thread_safe_sender()));
   OnAssociateRegistration(kDocumentMainThreadId, kProviderId, info, attrs);
   ipc_sink()->ClearMessages();
   OnSetControllerServiceWorker(kDocumentMainThreadId, kProviderId, attrs.active,
@@ -326,7 +330,8 @@
   // provider client and immediately released due to limitation of the mock
   // implementation.
   provider_context = new ServiceWorkerProviderContext(
-      kProviderId, SERVICE_WORKER_PROVIDER_FOR_WINDOW, thread_safe_sender());
+      kProviderId, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+      mojom::ServiceWorkerProviderAssociatedRequest(), thread_safe_sender());
   OnAssociateRegistration(kDocumentMainThreadId, kProviderId, info, attrs);
   provider_client.reset(
       new MockWebServiceWorkerProviderClientImpl(kProviderId, dispatcher()));
@@ -356,9 +361,10 @@
   std::unique_ptr<MockWebServiceWorkerProviderClientImpl> provider_client(
       new MockWebServiceWorkerProviderClientImpl(kProviderId, dispatcher()));
   scoped_refptr<ServiceWorkerProviderContext> provider_context(
-      new ServiceWorkerProviderContext(kProviderId,
-                                       SERVICE_WORKER_PROVIDER_FOR_WINDOW,
-                                       thread_safe_sender()));
+      new ServiceWorkerProviderContext(
+          kProviderId, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+          mojom::ServiceWorkerProviderAssociatedRequest(),
+          thread_safe_sender()));
 
   OnAssociateRegistration(kDocumentMainThreadId, kProviderId, info, attrs);
 
diff --git a/content/child/service_worker/service_worker_network_provider.cc b/content/child/service_worker/service_worker_network_provider.cc
index ffac7fc..82556e6 100644
--- a/content/child/service_worker/service_worker_network_provider.cc
+++ b/content/child/service_worker/service_worker_network_provider.cc
@@ -15,6 +15,7 @@
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "ipc/ipc_sync_channel.h"
+#include "mojo/public/cpp/bindings/associated_group.h"
 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
@@ -176,14 +177,21 @@
     return;
   if (!ChildThreadImpl::current())
     return;  // May be null in some tests.
-  ServiceWorkerProviderHostInfo provider_info(
-      provider_id_, route_id, provider_type, is_parent_frame_secure);
+
+  ServiceWorkerProviderHostInfo host_info(provider_id_, route_id, provider_type,
+                                          is_parent_frame_secure);
+  host_info.host_request = mojo::MakeRequest(&provider_host_);
+  mojom::ServiceWorkerProviderAssociatedRequest client_request =
+      mojo::MakeRequest(&host_info.client_ptr_info);
+
+  DCHECK(host_info.host_request.is_pending());
+  DCHECK(host_info.host_request.handle().is_valid());
   context_ = new ServiceWorkerProviderContext(
-      provider_id_, provider_type,
+      provider_id_, provider_type, std::move(client_request),
       ChildThreadImpl::current()->thread_safe_sender());
   ChildThreadImpl::current()->channel()->GetRemoteAssociatedInterface(
       &dispatcher_host_);
-  dispatcher_host_->OnProviderCreated(std::move(provider_info));
+  dispatcher_host_->OnProviderCreated(std::move(host_info));
 }
 
 ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider(
@@ -203,7 +211,7 @@
     return;
   if (!ChildThreadImpl::current())
     return;  // May be null in some tests.
-  dispatcher_host_->OnProviderDestroyed(provider_id());
+  provider_host_.reset();
 }
 
 void ServiceWorkerNetworkProvider::SetServiceWorkerVersionId(
diff --git a/content/child/service_worker/service_worker_network_provider.h b/content/child/service_worker/service_worker_network_provider.h
index 94afa943..113d260 100644
--- a/content/child/service_worker/service_worker_network_provider.h
+++ b/content/child/service_worker/service_worker_network_provider.h
@@ -78,6 +78,7 @@
   const int provider_id_;
   scoped_refptr<ServiceWorkerProviderContext> context_;
   mojom::ServiceWorkerDispatcherHostAssociatedPtr dispatcher_host_;
+  mojom::ServiceWorkerProviderHostAssociatedPtr provider_host_;
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNetworkProvider);
 };
 
diff --git a/content/child/service_worker/service_worker_provider_context.cc b/content/child/service_worker/service_worker_provider_context.cc
index 9203346..5b20204 100644
--- a/content/child/service_worker/service_worker_provider_context.cc
+++ b/content/child/service_worker/service_worker_provider_context.cc
@@ -46,9 +46,9 @@
 
   void AssociateRegistration(
       std::unique_ptr<ServiceWorkerRegistrationHandleReference> registration,
-      std::unique_ptr<ServiceWorkerHandleReference> installing,
-      std::unique_ptr<ServiceWorkerHandleReference> waiting,
-      std::unique_ptr<ServiceWorkerHandleReference> active) override {
+      std::unique_ptr<ServiceWorkerHandleReference> /* installing */,
+      std::unique_ptr<ServiceWorkerHandleReference> /* waiting */,
+      std::unique_ptr<ServiceWorkerHandleReference> /* active */) override {
     DCHECK(!registration_);
     registration_ = std::move(registration);
   }
@@ -69,8 +69,8 @@
   bool HasAssociatedRegistration() override { return !!registration_; }
 
   void GetAssociatedRegistration(
-      ServiceWorkerRegistrationObjectInfo* info,
-      ServiceWorkerVersionAttributes* attrs) override {
+      ServiceWorkerRegistrationObjectInfo* /* info */,
+      ServiceWorkerVersionAttributes* /* attrs */) override {
     NOTREACHED();
   }
 
@@ -111,7 +111,7 @@
   }
 
   void SetController(
-      std::unique_ptr<ServiceWorkerHandleReference> controller) override {
+      std::unique_ptr<ServiceWorkerHandleReference> /* controller */) override {
     NOTREACHED();
   }
 
@@ -147,10 +147,12 @@
 ServiceWorkerProviderContext::ServiceWorkerProviderContext(
     int provider_id,
     ServiceWorkerProviderType provider_type,
+    mojom::ServiceWorkerProviderAssociatedRequest request,
     ThreadSafeSender* thread_safe_sender)
     : provider_id_(provider_id),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      thread_safe_sender_(thread_safe_sender) {
+      thread_safe_sender_(thread_safe_sender),
+      binding_(this, std::move(request)) {
   if (provider_type == SERVICE_WORKER_PROVIDER_FOR_CONTROLLER)
     delegate_.reset(new ControllerDelegate);
   else
diff --git a/content/child/service_worker/service_worker_provider_context.h b/content/child/service_worker/service_worker_provider_context.h
index 192be96..26c8c0e 100644
--- a/content/child/service_worker/service_worker_provider_context.h
+++ b/content/child/service_worker/service_worker_provider_context.h
@@ -13,7 +13,9 @@
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner_helpers.h"
 #include "content/common/content_export.h"
+#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -44,11 +46,19 @@
 // ControlleeDelegate and ControllerDelegate.
 class CONTENT_EXPORT ServiceWorkerProviderContext
     : public base::RefCountedThreadSafe<ServiceWorkerProviderContext,
-                                        ServiceWorkerProviderContextDeleter> {
+                                        ServiceWorkerProviderContextDeleter>,
+      NON_EXPORTED_BASE(public mojom::ServiceWorkerProvider) {
  public:
-  ServiceWorkerProviderContext(int provider_id,
-                               ServiceWorkerProviderType provider_type,
-                               ThreadSafeSender* thread_safe_sender);
+  // |provider_id| specifies which host will receive the message from this
+  // provider. |provider_type| changes the behavior of this provider
+  // context. |request| is an endpoint which is connected to
+  // content::ServiceWorkerProviderHost which notifies changes of the
+  // registration's and workers' status. |request| is bound with |binding_|.
+  ServiceWorkerProviderContext(
+      int provider_id,
+      ServiceWorkerProviderType provider_type,
+      mojom::ServiceWorkerProviderAssociatedRequest request,
+      ThreadSafeSender* thread_safe_sender);
 
   // Called from ServiceWorkerDispatcher.
   void OnAssociateRegistration(
@@ -84,12 +94,16 @@
   class ControlleeDelegate;
   class ControllerDelegate;
 
-  ~ServiceWorkerProviderContext();
+  ~ServiceWorkerProviderContext() override;
   void DestructOnMainThread() const;
 
   const int provider_id_;
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+  // Mojo binding for the |request| passed to the constructor. This keeps the
+  // connection to the content::ServiceWorkerProviderHost in the browser process
+  // alive.
+  mojo::AssociatedBinding<mojom::ServiceWorkerProvider> binding_;
 
   std::unique_ptr<Delegate> delegate_;
 
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index e5e245e..144e2a2 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -618,6 +618,7 @@
     "service_worker/service_worker.mojom",
     "service_worker/service_worker_event_dispatcher.mojom",
     "service_worker/service_worker_provider.mojom",
+    "service_worker/service_worker_provider_interfaces.mojom",
     "service_worker/service_worker_types.mojom",
     "storage_partition_service.mojom",
     "url_loader.mojom",
diff --git a/content/common/service_worker/service_worker.mojom b/content/common/service_worker/service_worker.mojom
index cadade0..185e018 100644
--- a/content/common/service_worker/service_worker.mojom
+++ b/content/common/service_worker/service_worker.mojom
@@ -6,12 +6,19 @@
 
 import "content/common/service_worker/service_worker_provider.mojom";
 
-// Per-process browser-side interface bound to ServiceWorkerDispatcherHost.
-// Each InterfacePtrs on the same render process will be bound to the same
-// ServiceWorkerDispatcherHost.
+// Per-process browser-side interface bound to
+// content::ServiceWorkerDispatcherHost.
+// All InterfacePtrs on the same render process are bound to the same
+// content::ServiceWorkerDispatcherHost. The renderer uses this interface to
+// tell the browser when potential service worker clients are created and when
+// service workers are starting up.
 interface ServiceWorkerDispatcherHost {
+  // Creates a content::ServiceWorkerProviderHost on the browser
+  // process. |provider_info| has Mojo endpoints to connect the provider host
+  // and the provider on the renderer together. The lifetime of
+  // ServiceWorkerProviderHost will be tied to the
+  // mojom::ServiceWorkerProviderHost interface.
   OnProviderCreated(ServiceWorkerProviderHostInfo provider_info);
-  OnProviderDestroyed(int32 provider_id);
 
   // Informs the browser that a service worker is starting up. |provider_id|
   // identifies the ServiceWorkerProviderHost hosting the service
diff --git a/content/common/service_worker/service_worker_provider.mojom b/content/common/service_worker/service_worker_provider.mojom
index 6e512ed..6c897f8 100644
--- a/content/common/service_worker/service_worker_provider.mojom
+++ b/content/common/service_worker/service_worker_provider.mojom
@@ -4,10 +4,12 @@
 
 module content.mojom;
 
+import "content/common/service_worker/service_worker_provider_interfaces.mojom";
 import "content/common/service_worker/service_worker_types.mojom";
 
 // A container object carried from the renderer to the browser process.
-// This contains the params for the constructor of ServiceWorkerProviderHost.
+// This contains the params for the constructor of
+// content::ServiceWorkerProviderHost.
 // See also comments in
 // content/common/service_worker/service_worker_provider_host_info.h.
 struct ServiceWorkerProviderHostInfo {
@@ -15,4 +17,6 @@
   int32 route_id;
   ServiceWorkerProviderType type;
   bool is_parent_frame_secure;
+  associated ServiceWorkerProviderHost& host_request;
+  associated ServiceWorkerProvider client_ptr_info;
 };
\ No newline at end of file
diff --git a/content/common/service_worker/service_worker_provider_host_info.cc b/content/common/service_worker/service_worker_provider_host_info.cc
index d1cc98a..23ac817 100644
--- a/content/common/service_worker/service_worker_provider_host_info.cc
+++ b/content/common/service_worker/service_worker_provider_host_info.cc
@@ -30,7 +30,24 @@
     : provider_id(other.provider_id),
       route_id(other.route_id),
       type(other.type),
-      is_parent_frame_secure(other.is_parent_frame_secure) {
+      is_parent_frame_secure(other.is_parent_frame_secure),
+      host_request(std::move(other.host_request)),
+      client_ptr_info(std::move(other.client_ptr_info)) {
+  SetDefaultValues(&other);
+}
+
+ServiceWorkerProviderHostInfo::ServiceWorkerProviderHostInfo(
+    ServiceWorkerProviderHostInfo&& other,
+    mojom::ServiceWorkerProviderHostAssociatedRequest host_request,
+    mojom::ServiceWorkerProviderAssociatedPtrInfo client_ptr_info)
+    : provider_id(other.provider_id),
+      route_id(other.route_id),
+      type(other.type),
+      is_parent_frame_secure(other.is_parent_frame_secure),
+      host_request(std::move(host_request)),
+      client_ptr_info(std::move(client_ptr_info)) {
+  DCHECK(!other.host_request.is_pending());
+  DCHECK(!other.client_ptr_info.is_valid());
   SetDefaultValues(&other);
 }
 
diff --git a/content/common/service_worker/service_worker_provider_host_info.h b/content/common/service_worker/service_worker_provider_host_info.h
index b89e2cdf..e4418fa 100644
--- a/content/common/service_worker/service_worker_provider_host_info.h
+++ b/content/common/service_worker/service_worker_provider_host_info.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_HOST_INFO_H_
 #define CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_HOST_INFO_H_
 
+#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 
 namespace content {
@@ -13,6 +14,10 @@
 struct CONTENT_EXPORT ServiceWorkerProviderHostInfo {
   ServiceWorkerProviderHostInfo();
   ServiceWorkerProviderHostInfo(ServiceWorkerProviderHostInfo&& other);
+  ServiceWorkerProviderHostInfo(
+      ServiceWorkerProviderHostInfo&& other,
+      mojom::ServiceWorkerProviderHostAssociatedRequest host_request,
+      mojom::ServiceWorkerProviderAssociatedPtrInfo client_ptr_info);
   ServiceWorkerProviderHostInfo(int provider_id,
                                 int route_id,
                                 ServiceWorkerProviderType type,
@@ -48,6 +53,19 @@
   // is_parent_frame_secure| is true.
   bool is_parent_frame_secure;
 
+  // Mojo endpoint to send a message from the renderer to the browser. This
+  // will be associated with ServiceWorkerDisptacherHost. |host_request| should
+  // be valid when ServiceWorkerProviderHostInfo is passed to any Mojo methods.
+  // After used to create the ServiceWorkerProviderHost, this will be invalid.
+  mojom::ServiceWorkerProviderHostAssociatedRequest host_request;
+
+  // Mojo endpoint to send a message from the browser to the renderer. This
+  // will be associated with ServiceWorkerDisptacherHost. |client_ptr_info|
+  // should be valid when ServiceWorkerProviderHostInfo is passed to any Mojo
+  // methods.
+  // After used to create the ServiceWorkerProviderHost, this will be invalid.
+  mojom::ServiceWorkerProviderAssociatedPtrInfo client_ptr_info;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHostInfo);
 };
diff --git a/content/common/service_worker/service_worker_provider_interfaces.mojom b/content/common/service_worker/service_worker_provider_interfaces.mojom
new file mode 100644
index 0000000..9f62bba
--- /dev/null
+++ b/content/common/service_worker/service_worker_provider_interfaces.mojom
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module content.mojom;
+
+// mojom::ServiceWorkerProviderHost is a browser-side interface. The renderer
+// uses this interface to request the browser to do operations involving service
+// worker registrations.
+interface ServiceWorkerProviderHost {
+  // TODO(shimazu): implement them.
+  // register() => ();
+  // getRegistation() => ();
+  // getRegistrations() => ();
+  // getRegistrationForReady() => ();
+};
+
+// mojom::ServiceWorkerProvider is a renderer-side interface.
+// The browser process uses this interface to send messages to pages or
+// the service worker's context.
+interface ServiceWorkerProvider {
+  // TODO(shimazu): implement them.
+  // associateRegistration();
+  // disassociateRegistration();
+  // setControllerServiceWorker();
+  // messageToDocument();
+};
\ No newline at end of file
diff --git a/content/common/service_worker/service_worker_provider_struct_traits.cc b/content/common/service_worker/service_worker_provider_struct_traits.cc
index c4a4307..5202e30 100644
--- a/content/common/service_worker/service_worker_provider_struct_traits.cc
+++ b/content/common/service_worker/service_worker_provider_struct_traits.cc
@@ -16,6 +16,10 @@
   out->provider_id = in.provider_id();
   out->route_id = in.route_id();
   out->is_parent_frame_secure = in.is_parent_frame_secure();
+  out->host_request = in.TakeHostRequest<
+      content::mojom::ServiceWorkerProviderHostAssociatedRequest>();
+  out->client_ptr_info = in.TakeClientPtrInfo<
+      content::mojom::ServiceWorkerProviderAssociatedPtrInfo>();
   return true;
 }
 
diff --git a/content/common/service_worker/service_worker_provider_struct_traits.h b/content/common/service_worker/service_worker_provider_struct_traits.h
index e8cff44..bdab91f 100644
--- a/content/common/service_worker/service_worker_provider_struct_traits.h
+++ b/content/common/service_worker/service_worker_provider_struct_traits.h
@@ -31,6 +31,16 @@
     return info.is_parent_frame_secure;
   }
 
+  static content::mojom::ServiceWorkerProviderHostAssociatedRequest&
+  host_request(content::ServiceWorkerProviderHostInfo& info) {
+    return info.host_request;
+  }
+
+  static content::mojom::ServiceWorkerProviderAssociatedPtrInfo&
+  client_ptr_info(content::ServiceWorkerProviderHostInfo& info) {
+    return info.client_ptr_info;
+  }
+
   static bool Read(content::mojom::ServiceWorkerProviderHostInfoDataView in,
                    content::ServiceWorkerProviderHostInfo* out);
 };
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
index 65f3796..9e5db35 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
@@ -56,8 +56,8 @@
                         ChildProcessCreationParams creationParams,
                         ChildProcessConnection.StartCallback startCallback,
                         ChildProcessConnection.DeathCallback deathCallback) {
-                    boolean bindToCallerCheck = isServiceExternalFromCreationParams(
-                            creationParams, true /* sandboxed */);
+                    boolean bindToCallerCheck =
+                            creationParams == null ? false : creationParams.getBindToCallerCheck();
                     ChildConnectionAllocator allocator =
                             getConnectionAllocator(context, creationParams, true /* sandboxed */);
                     return ChildProcessLauncher.allocateBoundConnection(context, allocator,
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
index 7238025..d22e89e 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
@@ -408,10 +408,11 @@
         });
     }
 
-    @Test
-    @MediumTest
-    @Feature({"ProcessManagement"})
-    public void testWarmUp() {
+    private void testWarmUpWithCreationParams(ChildProcessCreationParams creationParams) {
+        if (creationParams != null) {
+            ChildProcessCreationParams.registerDefault(creationParams);
+        }
+
         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
         warmUpOnUiThreadBlocking(context);
 
@@ -419,7 +420,7 @@
 
         ChildProcessLauncherHelper launcherHelper = ChildProcessLauncherTestUtils.startForTesting(
                 context, true /* sandboxed */, false /* alwaysInForeground */, new String[0],
-                new FileDescriptorInfo[0], null);
+                new FileDescriptorInfo[0], creationParams /* creationParams */);
 
         final ChildProcessConnection conn = retrieveConnection(launcherHelper);
 
@@ -442,6 +443,25 @@
                 });
     }
 
+    @Test
+    @MediumTest
+    @Feature({"ProcessManagement"})
+    public void testWarmUp() {
+        // Use the default creation parameters.
+        testWarmUpWithCreationParams(null /* creationParams */);
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"ProcessManagement"})
+    public void testWarmUpWithBindToCaller() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        ChildProcessCreationParams creationParams = new ChildProcessCreationParams(
+                context.getPackageName(), false /* isExternalService */,
+                LibraryProcessType.PROCESS_CHILD, true /* bindToCallerCheck */);
+        testWarmUpWithCreationParams(creationParams);
+    }
+
     // Tests that the warm-up connection is freed from its allocator if it crashes.
     @Test
     @MediumTest
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 3588134..3b2ec58 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -254,6 +254,11 @@
 const base::Feature kTouchpadAndWheelScrollLatching{
     "TouchpadAndWheelScrollLatching", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Use Feature Policy to gate the use of permission features like midi,
+// geolocation, camera, microphone, etc.
+const base::Feature kUseFeaturePolicyForPermissions{
+    "UseFeaturePolicyForPermissions", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether vibrate requires user gesture.
 const base::Feature kVibrateRequiresUserGesture{
     "VibrateRequiresUserGesture", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 65da672..50f9f2f 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -67,6 +67,7 @@
 CONTENT_EXPORT extern const base::Feature kTokenBinding;
 CONTENT_EXPORT extern const base::Feature kTopDocumentIsolation;
 CONTENT_EXPORT extern const base::Feature kTouchpadAndWheelScrollLatching;
+CONTENT_EXPORT extern const base::Feature kUseFeaturePolicyForPermissions;
 CONTENT_EXPORT extern const base::Feature kVibrateRequiresUserGesture;
 CONTENT_EXPORT extern const base::Feature kVrShell;
 CONTENT_EXPORT extern const base::Feature kWebAssembly;
diff --git a/content/public/test/test_browser_thread_bundle.cc b/content/public/test/test_browser_thread_bundle.cc
index 6d0d4df2..fa85212 100644
--- a/content/public/test/test_browser_thread_bundle.cc
+++ b/content/public/test/test_browser_thread_bundle.cc
@@ -10,7 +10,6 @@
 #include "base/run_loop.h"
 #include "base/task_scheduler/task_scheduler.h"
 #include "base/test/scoped_async_task_scheduler.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread.h"
@@ -79,12 +78,6 @@
   // for DestructionObservers hooked to |message_loop_| to be able to invoke
   // BrowserThread::CurrentlyOn() -- ref. ~TestBrowserThread().
   message_loop_.reset();
-
-  // Disable redirection of SequencedWorkerPools to TaskScheduler. This is
-  // required in order to reset global state so that tests following this one in
-  // this process can still manage their own SequencedWorkerPool without using
-  // TestBrowserThreadBundle.
-  base::SequencedWorkerPool::EnableForProcess();
 }
 
 void TestBrowserThreadBundle::Init() {
@@ -130,9 +123,6 @@
         base::MakeUnique<base::test::ScopedAsyncTaskScheduler>();
   }
 
-  // Enable redirection of SequencedWorkerPools to TaskScheduler.
-  base::SequencedWorkerPool::EnableWithRedirectionToTaskSchedulerForProcess();
-
   if (options_ & REAL_DB_THREAD) {
     db_thread_ = base::MakeUnique<TestBrowserThread>(BrowserThread::DB);
     db_thread_->Start();
diff --git a/content/public/test/test_renderer_host.h b/content/public/test/test_renderer_host.h
index 8dc63b8..09c3e26 100644
--- a/content/public/test/test_renderer_host.h
+++ b/content/public/test/test_renderer_host.h
@@ -139,6 +139,14 @@
   // Simulate a renderer-initiated navigation up until commit.
   virtual void NavigateAndCommitRendererInitiated(bool did_create_new_entry,
                                                   const GURL& url) = 0;
+
+  // Set the feature policy header for the RenderFrameHost for test. Currently
+  // this is limited to setting a whitelist for a single feature. This function
+  // can be generalized as needed. Setting a header policy should only be done
+  // once per navigation of the RFH.
+  virtual void SimulateFeaturePolicyHeader(
+      blink::WebFeaturePolicyFeature feature,
+      const std::vector<url::Origin>& whitelist) = 0;
 };
 
 // An interface and utility for driving tests of RenderViewHost.
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 3373c12..dee0774 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -239,6 +239,8 @@
     "media/media_permission_dispatcher.h",
     "media/midi_message_filter.cc",
     "media/midi_message_filter.h",
+    "media/mojo_audio_output_ipc.cc",
+    "media/mojo_audio_output_ipc.h",
     "media/render_media_client.cc",
     "media/render_media_client.h",
     "media/render_media_log.cc",
diff --git a/content/renderer/media/mojo_audio_output_ipc.cc b/content/renderer/media/mojo_audio_output_ipc.cc
new file mode 100644
index 0000000..f3c6a54
--- /dev/null
+++ b/content/renderer/media/mojo_audio_output_ipc.cc
@@ -0,0 +1,200 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/mojo_audio_output_ipc.h"
+
+#include <utility>
+
+#include "media/audio/audio_device_description.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace content {
+
+namespace {
+
+void TrivialAuthorizedCallback(media::OutputDeviceStatus,
+                               const media::AudioParameters&,
+                               const std::string&) {}
+
+}  // namespace
+
+MojoAudioOutputIPC::MojoAudioOutputIPC(FactoryAccessorCB factory_accessor)
+    : factory_accessor_(std::move(factory_accessor)), weak_factory_(this) {
+  DETACH_FROM_THREAD(thread_checker_);
+}
+
+MojoAudioOutputIPC::~MojoAudioOutputIPC() {
+  DCHECK(!AuthorizationRequested() && !StreamCreationRequested())
+      << "CloseStream must be called before destructing the AudioOutputIPC";
+  // No thread check.
+  // Destructing |weak_factory_| on any thread is safe since it's not used after
+  // the final call to CloseStream, where its pointers are invalidated.
+}
+
+void MojoAudioOutputIPC::RequestDeviceAuthorization(
+    media::AudioOutputIPCDelegate* delegate,
+    int session_id,
+    const std::string& device_id,
+    const url::Origin& security_origin) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(delegate);
+  DCHECK(!delegate_);
+  DCHECK(!AuthorizationRequested());
+  DCHECK(!StreamCreationRequested());
+  delegate_ = delegate;
+
+  // We pass in a ScopedClosureRunner to detect the case when the mojo
+  // connection is terminated prior to receiving the response. In this case,
+  // the closure runner will be destructed and call ReceivedDeviceAuthorization
+  // with an error.
+  DoRequestDeviceAuthorization(
+      session_id, device_id,
+      base::BindOnce(
+          &MojoAudioOutputIPC::ReceivedDeviceAuthorization,
+          weak_factory_.GetWeakPtr(),
+          base::ScopedClosureRunner(base::Bind(
+              &MojoAudioOutputIPC::ReceivedDeviceAuthorization,
+              weak_factory_.GetWeakPtr(),
+              base::Passed(base::ScopedClosureRunner()),
+              media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL,
+              media::AudioParameters::UnavailableDeviceParams(),
+              std::string()))));
+}
+
+void MojoAudioOutputIPC::CreateStream(media::AudioOutputIPCDelegate* delegate,
+                                      const media::AudioParameters& params) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(delegate);
+  DCHECK(!StreamCreationRequested());
+  if (!AuthorizationRequested()) {
+    DCHECK(!delegate_);
+    delegate_ = delegate;
+    // No authorization requested yet. Request one for the default device.
+    // Since the delegate didn't explicitly request authorization, we shouldn't
+    // send a callback to it.
+    if (!DoRequestDeviceAuthorization(
+            0, media::AudioDeviceDescription::kDefaultDeviceId,
+            base::Bind(&TrivialAuthorizedCallback))) {
+      return;
+    }
+  }
+
+  DCHECK_EQ(delegate_, delegate);
+  // Since the creation callback won't fire if the provider binding is gone
+  // and |this| owns |stream_provider_|, unretained is safe.
+  stream_provider_->Acquire(
+      mojo::MakeRequest(&stream_), params,
+      base::Bind(&MojoAudioOutputIPC::StreamCreated, base::Unretained(this)));
+
+  // Unretained is safe because |delegate_| must remain valid until
+  // CloseStream is called, and |stream_provider_| is reset in CloseStream.
+  stream_.set_connection_error_handler(base::Bind(
+      &media::AudioOutputIPCDelegate::OnError, base::Unretained(delegate_)));
+}
+
+void MojoAudioOutputIPC::PlayStream() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (stream_.is_bound())
+    stream_->Play();
+}
+
+void MojoAudioOutputIPC::PauseStream() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (stream_.is_bound())
+    stream_->Pause();
+}
+
+void MojoAudioOutputIPC::CloseStream() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  stream_provider_.reset();
+  stream_.reset();
+  delegate_ = nullptr;
+
+  // Cancel any pending callbacks for this stream.
+  weak_factory_.InvalidateWeakPtrs();
+}
+
+void MojoAudioOutputIPC::SetVolume(double volume) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (stream_.is_bound())
+    stream_->SetVolume(volume);
+}
+
+bool MojoAudioOutputIPC::AuthorizationRequested() {
+  return stream_provider_.is_bound();
+}
+
+bool MojoAudioOutputIPC::StreamCreationRequested() {
+  return stream_.is_bound();
+}
+
+media::mojom::AudioOutputStreamProviderRequest
+MojoAudioOutputIPC::MakeProviderRequest() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(!AuthorizationRequested());
+  media::mojom::AudioOutputStreamProviderRequest request =
+      mojo::MakeRequest(&stream_provider_);
+
+  // Unretained is safe because |delegate_| must remain valid until
+  // CloseStream is called, and |stream_provider_| is reset in CloseStream.
+  stream_provider_.set_connection_error_handler(base::Bind(
+      &media::AudioOutputIPCDelegate::OnError, base::Unretained(delegate_)));
+  return request;
+}
+
+bool MojoAudioOutputIPC::DoRequestDeviceAuthorization(
+    int session_id,
+    const std::string& device_id,
+    AuthorizationCB callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  auto* factory = factory_accessor_.Run();
+  if (!factory) {
+    LOG(ERROR) << "MojoAudioOutputIPC failed to acquire factory";
+
+    media::AudioOutputIPCDelegate* delegate = delegate_;
+    CloseStream();
+    delegate->OnIPCClosed();  // deletes |this|.
+    return false;
+  }
+
+  factory->RequestDeviceAuthorization(MakeProviderRequest(), session_id,
+                                      device_id, std::move(callback));
+  return true;
+}
+
+void MojoAudioOutputIPC::ReceivedDeviceAuthorization(
+    base::ScopedClosureRunner fallback_closure,
+    media::OutputDeviceStatus status,
+    const media::AudioParameters& params,
+    const std::string& device_id) const {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(delegate_);
+  ignore_result(fallback_closure.Release());
+  delegate_->OnDeviceAuthorized(status, params, device_id);
+}
+
+void MojoAudioOutputIPC::StreamCreated(
+    mojo::ScopedSharedBufferHandle shared_memory,
+    mojo::ScopedHandle socket) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(delegate_);
+  DCHECK(socket.is_valid());
+  DCHECK(shared_memory.is_valid());
+
+  base::PlatformFile socket_handle;
+  auto result = mojo::UnwrapPlatformFile(std::move(socket), &socket_handle);
+  DCHECK_EQ(result, MOJO_RESULT_OK);
+
+  base::SharedMemoryHandle memory_handle;
+  bool read_only = false;
+  size_t memory_length = 0;
+  result = mojo::UnwrapSharedMemoryHandle(
+      std::move(shared_memory), &memory_handle, &memory_length, &read_only);
+  DCHECK_EQ(result, MOJO_RESULT_OK);
+  DCHECK(!read_only);
+
+  delegate_->OnStreamCreated(memory_handle, socket_handle, memory_length);
+}
+
+}  // namespace content
diff --git a/content/renderer/media/mojo_audio_output_ipc.h b/content/renderer/media/mojo_audio_output_ipc.h
new file mode 100644
index 0000000..b014e50
--- /dev/null
+++ b/content/renderer/media/mojo_audio_output_ipc.h
@@ -0,0 +1,85 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_MEDIA_MOJO_AUDIO_OUTPUT_IPC_H_
+#define CONTENT_RENDERER_MEDIA_MOJO_AUDIO_OUTPUT_IPC_H_
+
+#include <string>
+
+#include "base/callback_helpers.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "content/common/content_export.h"
+#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
+#include "media/audio/audio_output_ipc.h"
+
+namespace content {
+
+// MojoAudioOutputIPC is a renderer-side class for handling creation,
+// initialization and control of an output stream. May only be used on a single
+// thread.
+class CONTENT_EXPORT MojoAudioOutputIPC : public media::AudioOutputIPC {
+ public:
+  using FactoryAccessorCB =
+      base::RepeatingCallback<mojom::RendererAudioOutputStreamFactory*()>;
+
+  // |factory_accessor| is required to provide a
+  // RendererAudioOutputStreamFactory* if IPC is possible.
+  explicit MojoAudioOutputIPC(FactoryAccessorCB factory_accessor);
+
+  ~MojoAudioOutputIPC() override;
+
+  // AudioOutputIPC implementation.
+  void RequestDeviceAuthorization(media::AudioOutputIPCDelegate* delegate,
+                                  int session_id,
+                                  const std::string& device_id,
+                                  const url::Origin& security_origin) override;
+  void CreateStream(media::AudioOutputIPCDelegate* delegate,
+                    const media::AudioParameters& params) override;
+  void PlayStream() override;
+  void PauseStream() override;
+  void CloseStream() override;
+  void SetVolume(double volume) override;
+
+ private:
+  using AuthorizationCB = mojom::RendererAudioOutputStreamFactory::
+      RequestDeviceAuthorizationCallback;
+
+  bool AuthorizationRequested();
+  bool StreamCreationRequested();
+  media::mojom::AudioOutputStreamProviderRequest MakeProviderRequest();
+
+  // Tries to acquire a RendererAudioOutputStreamFactory, returns true on
+  // success. On failure, |this| has been deleted, so returning immediately
+  // is required.
+  bool DoRequestDeviceAuthorization(int session_id,
+                                    const std::string& device_id,
+                                    AuthorizationCB callback);
+
+  void ReceivedDeviceAuthorization(base::ScopedClosureRunner fallback_closure,
+                                   media::OutputDeviceStatus status,
+                                   const media::AudioParameters& params,
+                                   const std::string& device_id) const;
+
+  void StreamCreated(mojo::ScopedSharedBufferHandle shared_memory,
+                     mojo::ScopedHandle socket);
+
+  const FactoryAccessorCB factory_accessor_;
+
+  THREAD_CHECKER(thread_checker_);
+  media::mojom::AudioOutputStreamProviderPtr stream_provider_;
+  media::mojom::AudioOutputStreamPtr stream_;
+  media::AudioOutputIPCDelegate* delegate_ = nullptr;
+
+  // To make sure we don't send an "authorization completed" callback for a
+  // stream after it's closed, we use this weak factory.
+  base::WeakPtrFactory<MojoAudioOutputIPC> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoAudioOutputIPC);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_MOJO_AUDIO_OUTPUT_IPC_H_
diff --git a/content/renderer/media/mojo_audio_output_ipc_unittest.cc b/content/renderer/media/mojo_audio_output_ipc_unittest.cc
new file mode 100644
index 0000000..eac0ca0
--- /dev/null
+++ b/content/renderer/media/mojo_audio_output_ipc_unittest.cc
@@ -0,0 +1,556 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/mojo_audio_output_ipc.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/message_loop/message_loop.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/test/gtest_util.h"
+#include "media/audio/audio_device_description.h"
+#include "media/base/audio_parameters.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/origin.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::Mock;
+using testing::StrictMock;
+
+namespace content {
+
+namespace {
+
+const int kSessionId = 1234;
+const size_t kMemoryLength = 4321;
+const char kDeviceId[] = "device_id";
+const char kReturnedDeviceId[] = "returned_device_id";
+const double kNewVolume = 0.271828;
+
+url::Origin Origin() {
+  return {};
+}
+
+media::AudioParameters Params() {
+  return media::AudioParameters::UnavailableDeviceParams();
+}
+
+MojoAudioOutputIPC::FactoryAccessorCB NullAccessor() {
+  return base::BindRepeating(
+      []() -> mojom::RendererAudioOutputStreamFactory* { return nullptr; });
+}
+
+class TestRemoteFactory : public mojom::RendererAudioOutputStreamFactory {
+ public:
+  TestRemoteFactory()
+      : expect_request_(false),
+        binding_(this, mojo::MakeRequest(&this_proxy_)) {}
+
+  ~TestRemoteFactory() override {}
+
+  void RequestDeviceAuthorization(
+      media::mojom::AudioOutputStreamProviderRequest stream_provider_request,
+      int64_t session_id,
+      const std::string& device_id,
+      RequestDeviceAuthorizationCallback callback) override {
+    EXPECT_EQ(session_id, expected_session_id_);
+    EXPECT_EQ(device_id, expected_device_id_);
+    EXPECT_TRUE(expect_request_);
+    if (provider_) {
+      std::move(callback).Run(
+          media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, Params(),
+          std::string(kReturnedDeviceId));
+      provider_binding_.emplace(provider_.get(),
+                                std::move(stream_provider_request));
+    } else {
+      std::move(callback).Run(
+          media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
+          Params(), std::string(""));
+    }
+    expect_request_ = false;
+  }
+
+  void PrepareProviderForAuthorization(
+      int64_t session_id,
+      const std::string& device_id,
+      std::unique_ptr<media::mojom::AudioOutputStreamProvider> provider) {
+    EXPECT_FALSE(expect_request_);
+    expect_request_ = true;
+    expected_session_id_ = session_id;
+    expected_device_id_ = device_id;
+    provider_binding_.reset();
+    std::swap(provider_, provider);
+  }
+
+  void RefuseNextRequest(int64_t session_id, const std::string& device_id) {
+    EXPECT_FALSE(expect_request_);
+    expect_request_ = true;
+    expected_session_id_ = session_id;
+    expected_device_id_ = device_id;
+  }
+
+  void Disconnect() {
+    binding_.Close();
+    this_proxy_.reset();
+    binding_.Bind(mojo::MakeRequest(&this_proxy_));
+    provider_binding_.reset();
+    provider_.reset();
+    expect_request_ = false;
+  }
+
+  MojoAudioOutputIPC::FactoryAccessorCB GetAccessor() {
+    return base::BindRepeating(&TestRemoteFactory::get, base::Unretained(this));
+  }
+
+ private:
+  mojom::RendererAudioOutputStreamFactory* get() { return this_proxy_.get(); }
+
+  bool expect_request_;
+  int64_t expected_session_id_;
+  std::string expected_device_id_;
+
+  mojom::RendererAudioOutputStreamFactoryPtr this_proxy_;
+  mojo::Binding<mojom::RendererAudioOutputStreamFactory> binding_;
+  std::unique_ptr<media::mojom::AudioOutputStreamProvider> provider_;
+  base::Optional<mojo::Binding<media::mojom::AudioOutputStreamProvider>>
+      provider_binding_;
+};
+
+class TestStreamProvider : public media::mojom::AudioOutputStreamProvider {
+ public:
+  explicit TestStreamProvider(media::mojom::AudioOutputStream* stream)
+      : stream_(stream) {}
+
+  ~TestStreamProvider() override {
+    // If we expected a stream to be acquired, make sure it is so.
+    if (stream_)
+      EXPECT_TRUE(binding_);
+  }
+
+  void Acquire(media::mojom::AudioOutputStreamRequest stream_request,
+               const media::AudioParameters& params,
+               const AcquireCallback& callback) override {
+    EXPECT_EQ(binding_, base::nullopt);
+    EXPECT_NE(stream_, nullptr);
+    binding_.emplace(stream_, std::move(stream_request));
+    base::CancelableSyncSocket foreign_socket;
+    EXPECT_TRUE(
+        base::CancelableSyncSocket::CreatePair(&socket_, &foreign_socket));
+    std::move(callback).Run(mojo::SharedBufferHandle::Create(kMemoryLength),
+                            mojo::WrapPlatformFile(foreign_socket.Release()));
+  }
+
+ private:
+  media::mojom::AudioOutputStream* stream_;
+  base::Optional<mojo::Binding<media::mojom::AudioOutputStream>> binding_;
+  base::CancelableSyncSocket socket_;
+};
+
+class MockStream : public media::mojom::AudioOutputStream {
+ public:
+  MOCK_METHOD0(Play, void());
+  MOCK_METHOD0(Pause, void());
+  MOCK_METHOD1(SetVolume, void(double));
+};
+
+class MockDelegate : public media::AudioOutputIPCDelegate {
+ public:
+  MockDelegate() {}
+  ~MockDelegate() override {}
+
+  void OnStreamCreated(base::SharedMemoryHandle mem_handle,
+                       base::SyncSocket::Handle socket_handle,
+                       int length) {
+    base::SharedMemory sh_mem(
+        mem_handle, /*read_only*/ false);  // Releases the shared memory handle.
+    base::SyncSocket socket(socket_handle);  // Releases the socket descriptor.
+    GotOnStreamCreated(length);
+  }
+
+  MOCK_METHOD0(OnError, void());
+  MOCK_METHOD3(OnDeviceAuthorized,
+               void(media::OutputDeviceStatus device_status,
+                    const media::AudioParameters& output_params,
+                    const std::string& matched_device_id));
+  MOCK_METHOD1(GotOnStreamCreated, void(int length));
+  MOCK_METHOD0(OnIPCClosed, void());
+};
+
+}  // namespace
+
+TEST(MojoAudioOutputIPC, AuthorizeWithoutFactory_CallsOnIPCClosed) {
+  base::MessageLoopForIO message_loop;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(NullAccessor());
+
+  EXPECT_CALL(delegate, OnIPCClosed());
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, CreateWithoutFactoryOrAuthorization_CallsOnIPCClosed) {
+  base::MessageLoopForIO message_loop;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(NullAccessor());
+
+  EXPECT_CALL(delegate, OnIPCClosed());
+  ipc->CreateStream(&delegate, Params());
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, DeviceAuthorized_Propagates) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+  stream_factory.PrepareProviderForAuthorization(
+      kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(nullptr));
+
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  base::RunLoop().RunUntilIdle();
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, OnDeviceCreated_Propagates) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockStream> stream;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+  stream_factory.PrepareProviderForAuthorization(
+      kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
+
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+  ipc->CreateStream(&delegate, Params());
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
+  base::RunLoop().RunUntilIdle();
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC,
+     CreateWithoutAuthorization_RequestsAuthorizationFirst) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockStream> stream;
+  StrictMock<MockDelegate> delegate;
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+
+  // Note: This call implicitly EXPECTs that authorization is requested,
+  // and constructing the TestStreamProvider with a |&stream| EXPECTs that the
+  // stream is created. This implicit request should always be for the default
+  // device and no session id.
+  stream_factory.PrepareProviderForAuthorization(
+      0, std::string(media::AudioDeviceDescription::kDefaultDeviceId),
+      base::MakeUnique<TestStreamProvider>(&stream));
+
+  ipc->CreateStream(&delegate, Params());
+
+  EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
+  base::RunLoop().RunUntilIdle();
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, IsReusable) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockStream> stream;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+
+  for (int i = 0; i < 5; ++i) {
+    stream_factory.PrepareProviderForAuthorization(
+        kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
+
+    ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+    ipc->CreateStream(&delegate, Params());
+
+    EXPECT_CALL(
+        delegate,
+        OnDeviceAuthorized(media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                           _, std::string(kReturnedDeviceId)));
+    EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
+    base::RunLoop().RunUntilIdle();
+    Mock::VerifyAndClearExpectations(&delegate);
+
+    ipc->CloseStream();
+    base::RunLoop().RunUntilIdle();
+  }
+}
+
+TEST(MojoAudioOutputIPC, IsReusableAfterError) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockStream> stream;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+
+  stream_factory.PrepareProviderForAuthorization(
+      kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(nullptr));
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(&delegate);
+
+  EXPECT_CALL(delegate, OnError()).Times(AtLeast(1));
+  stream_factory.Disconnect();
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(&delegate);
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+
+  for (int i = 0; i < 5; ++i) {
+    stream_factory.PrepareProviderForAuthorization(
+        kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
+
+    ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+    ipc->CreateStream(&delegate, Params());
+
+    EXPECT_CALL(
+        delegate,
+        OnDeviceAuthorized(media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                           _, std::string(kReturnedDeviceId)));
+    EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
+    base::RunLoop().RunUntilIdle();
+    Mock::VerifyAndClearExpectations(&delegate);
+
+    ipc->CloseStream();
+    base::RunLoop().RunUntilIdle();
+  }
+}
+
+TEST(MojoAudioOutputIPC, DeviceNotAuthorized_Propagates) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+  stream_factory.RefuseNextRequest(kSessionId, kDeviceId);
+
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+
+  EXPECT_CALL(
+      delegate,
+      OnDeviceAuthorized(
+          media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
+          _, std::string()));
+  EXPECT_CALL(delegate, OnError()).Times(AtLeast(0));
+  base::RunLoop().RunUntilIdle();
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC,
+     FactoryDisconnectedBeforeAuthorizationReply_CallsAuthorizedAnyways) {
+  // The authorization IPC message might be aborted by the remote end
+  // disconnecting. In this case, the MojoAudioOutputIPC object must still
+  // send a notification to unblock the AudioOutputIPCDelegate.
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+
+  EXPECT_CALL(
+      delegate,
+      OnDeviceAuthorized(
+          media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, _,
+          std::string()));
+  stream_factory.Disconnect();
+  EXPECT_CALL(delegate, OnError());
+  base::RunLoop().RunUntilIdle();
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC,
+     FactoryDisconnectedAfterAuthorizationReply_CallsAuthorizedOnlyOnce) {
+  // This test makes sure that the MojoAudioOutputIPC doesn't callback for
+  // authorization when the factory disconnects if it already got a callback
+  // for authorization.
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  stream_factory.PrepareProviderForAuthorization(
+      kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(nullptr));
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  base::RunLoop().RunUntilIdle();
+
+  stream_factory.Disconnect();
+  EXPECT_CALL(delegate, OnError());
+  base::RunLoop().RunUntilIdle();
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, AuthorizeNoClose_DCHECKs) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockDelegate> delegate;
+
+  stream_factory.PrepareProviderForAuthorization(
+      kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(nullptr));
+
+  std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+  EXPECT_DCHECK_DEATH(ipc.reset());
+  ipc->CloseStream();
+  ipc.reset();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, CreateNoClose_DCHECKs) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockDelegate> delegate;
+  StrictMock<MockStream> stream;
+
+  stream_factory.PrepareProviderForAuthorization(
+      0, std::string(media::AudioDeviceDescription::kDefaultDeviceId),
+      base::MakeUnique<TestStreamProvider>(&stream));
+
+  std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+
+  ipc->CreateStream(&delegate, Params());
+  EXPECT_DCHECK_DEATH(ipc.reset());
+  ipc->CloseStream();
+  ipc.reset();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, Play_Plays) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockStream> stream;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+  stream_factory.PrepareProviderForAuthorization(
+      kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
+
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+  ipc->CreateStream(&delegate, Params());
+  ipc->PlayStream();
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
+  EXPECT_CALL(stream, Play());
+  base::RunLoop().RunUntilIdle();
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, Pause_Pauses) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockStream> stream;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+  stream_factory.PrepareProviderForAuthorization(
+      kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
+
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+  ipc->CreateStream(&delegate, Params());
+  ipc->PauseStream();
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
+  EXPECT_CALL(stream, Pause());
+  base::RunLoop().RunUntilIdle();
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(MojoAudioOutputIPC, SetVolume_SetsVolume) {
+  base::MessageLoopForIO message_loop;
+  TestRemoteFactory stream_factory;
+  StrictMock<MockStream> stream;
+  StrictMock<MockDelegate> delegate;
+
+  const std::unique_ptr<media::AudioOutputIPC> ipc =
+      base::MakeUnique<MojoAudioOutputIPC>(stream_factory.GetAccessor());
+  stream_factory.PrepareProviderForAuthorization(
+      kSessionId, kDeviceId, base::MakeUnique<TestStreamProvider>(&stream));
+
+  ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
+  ipc->CreateStream(&delegate, Params());
+  ipc->SetVolume(kNewVolume);
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  EXPECT_CALL(delegate, GotOnStreamCreated(kMemoryLength));
+  EXPECT_CALL(stream, SetVolume(kNewVolume));
+  base::RunLoop().RunUntilIdle();
+
+  ipc->CloseStream();
+  base::RunLoop().RunUntilIdle();
+}
+
+}  // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index d2ec9636..ff1edbd 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1219,6 +1219,7 @@
     "../browser/payments/payment_app_content_unittest_base.h",
     "../browser/payments/payment_app_provider_impl_unittest.cc",
     "../browser/payments/payment_manager_unittest.cc",
+    "../browser/permissions/permission_service_impl_unittest.cc",
     "../browser/presentation/presentation_service_impl_unittest.cc",
     "../browser/renderer_host/clipboard_message_filter_unittest.cc",
     "../browser/renderer_host/compositor_resize_lock_unittest.cc",
@@ -1416,6 +1417,7 @@
     "../renderer/media/audio_renderer_sink_cache_unittest.cc",
     "../renderer/media/mock_audio_device_factory.cc",
     "../renderer/media/mock_audio_device_factory.h",
+    "../renderer/media/mojo_audio_output_ipc_unittest.cc",
     "../renderer/media/render_media_log_unittest.cc",
     "../renderer/media/renderer_webaudiodevice_impl_unittest.cc",
     "../renderer/media/video_capture_impl_manager_unittest.cc",
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 8924bc2..f18014f7 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -267,6 +267,16 @@
   SendNavigate(0, did_create_new_entry, url);
 }
 
+void TestRenderFrameHost::SimulateFeaturePolicyHeader(
+    blink::WebFeaturePolicyFeature feature,
+    const std::vector<url::Origin>& whitelist) {
+  content::ParsedFeaturePolicyHeader header(1);
+  header[0].feature = feature;
+  header[0].matches_all_origins = false;
+  header[0].origins = whitelist;
+  OnDidSetFeaturePolicyHeader(header);
+}
+
 void TestRenderFrameHost::SendNavigate(int nav_entry_id,
                                        bool did_create_new_entry,
                                        const GURL& url) {
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h
index 8ec23008..bf9d93ed 100644
--- a/content/test/test_render_frame_host.h
+++ b/content/test/test_render_frame_host.h
@@ -78,6 +78,9 @@
   void SimulateSwapOutACK() override;
   void NavigateAndCommitRendererInitiated(bool did_create_new_entry,
                                           const GURL& url) override;
+  void SimulateFeaturePolicyHeader(
+      blink::WebFeaturePolicyFeature feature,
+      const std::vector<url::Origin>& whitelist) override;
 
   void SendNavigateWithReplacement(int nav_entry_id,
                                    bool did_create_new_entry,
diff --git a/device/geolocation/geolocation_service_impl.cc b/device/geolocation/geolocation_service_impl.cc
index 357d9cd..ebc145d 100644
--- a/device/geolocation/geolocation_service_impl.cc
+++ b/device/geolocation/geolocation_service_impl.cc
@@ -118,14 +118,14 @@
 }
 
 void GeolocationServiceImpl::QueryNextPosition(
-    const QueryNextPositionCallback& callback) {
+    QueryNextPositionCallback callback) {
   if (!position_callback_.is_null()) {
     DVLOG(1) << "Overlapped call to QueryNextPosition!";
     OnConnectionError();  // Simulate a connection error.
     return;
   }
 
-  position_callback_ = callback;
+  position_callback_ = std::move(callback);
 
   if (has_position_to_report_)
     ReportCurrentPosition();
@@ -178,8 +178,7 @@
 }
 
 void GeolocationServiceImpl::ReportCurrentPosition() {
-  position_callback_.Run(current_position_.Clone());
-  position_callback_.Reset();
+  std::move(position_callback_).Run(current_position_.Clone());
   has_position_to_report_ = false;
 }
 
diff --git a/device/geolocation/geolocation_service_impl.h b/device/geolocation/geolocation_service_impl.h
index 60ce117..a377cce 100644
--- a/device/geolocation/geolocation_service_impl.h
+++ b/device/geolocation/geolocation_service_impl.h
@@ -42,7 +42,7 @@
  private:
   // mojom::GeolocationService:
   void SetHighAccuracy(bool high_accuracy) override;
-  void QueryNextPosition(const QueryNextPositionCallback& callback) override;
+  void QueryNextPosition(QueryNextPositionCallback callback) override;
 
   void OnConnectionError();
 
diff --git a/device/geolocation/public/interfaces/BUILD.gn b/device/geolocation/public/interfaces/BUILD.gn
index 974c18e..65276d1 100644
--- a/device/geolocation/public/interfaces/BUILD.gn
+++ b/device/geolocation/public/interfaces/BUILD.gn
@@ -9,9 +9,6 @@
     "geolocation.mojom",
   ]
 
-  # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
-  use_once_callback = false
-
   # TODO(crbug.com/699569): Convert to use the new JS bindings.
   use_new_js_bindings = false
 }
diff --git a/gpu/command_buffer/service/scheduler.cc b/gpu/command_buffer/service/scheduler.cc
index b77287d..e854cf1 100644
--- a/gpu/command_buffer/service/scheduler.cc
+++ b/gpu/command_buffer/service/scheduler.cc
@@ -25,6 +25,10 @@
 
   SequenceId sequence_id() const { return sequence_id_; }
 
+  const scoped_refptr<SyncPointOrderData>& order_data() const {
+    return order_data_;
+  }
+
   const SchedulingState& scheduling_state() const { return scheduling_state_; }
 
   bool enabled() const { return enabled_; }
@@ -49,9 +53,8 @@
   // Sets running state to SCHEDULED.
   void SetScheduled();
 
-  // Called before running the next task on the sequence. Returns the closure
-  // for the task. Sets running state to RUNNING.
-  base::OnceClosure BeginTask();
+  // Returns the next order number and closure. Sets running state to RUNNING.
+  uint32_t BeginTask(base::OnceClosure* closure);
 
   // Called after running the closure returned by BeginTask. Sets running state
   // to IDLE.
@@ -206,7 +209,9 @@
 
 void Scheduler::Sequence::ContinueTask(base::OnceClosure closure) {
   DCHECK_EQ(running_state_, RUNNING);
-  tasks_.push_front({std::move(closure), order_data_->current_order_num()});
+  uint32_t order_num = order_data_->current_order_num();
+  tasks_.push_front({std::move(closure), order_num});
+  order_data_->PauseProcessingOrderNumber(order_num);
 }
 
 uint32_t Scheduler::Sequence::ScheduleTask(base::OnceClosure closure) {
@@ -215,32 +220,25 @@
   return order_num;
 }
 
-base::OnceClosure Scheduler::Sequence::BeginTask() {
+uint32_t Scheduler::Sequence::BeginTask(base::OnceClosure* closure) {
+  DCHECK(closure);
   DCHECK(!tasks_.empty());
 
   DCHECK_EQ(running_state_, SCHEDULED);
   running_state_ = RUNNING;
 
-  base::OnceClosure closure = std::move(tasks_.front().closure);
+  *closure = std::move(tasks_.front().closure);
   uint32_t order_num = tasks_.front().order_num;
   tasks_.pop_front();
 
-  order_data_->BeginProcessingOrderNumber(order_num);
-
   UpdateSchedulingState();
 
-  return closure;
+  return order_num;
 }
 
 void Scheduler::Sequence::FinishTask() {
   DCHECK_EQ(running_state_, RUNNING);
   running_state_ = IDLE;
-  uint32_t order_num = order_data_->current_order_num();
-  if (!tasks_.empty() && tasks_.front().order_num == order_num) {
-    order_data_->PauseProcessingOrderNumber(order_num);
-  } else {
-    order_data_->FinishProcessingOrderNumber(order_num);
-  }
   UpdateSchedulingState();
 }
 
@@ -472,16 +470,26 @@
 
   TRACE_EVENT1("gpu", "Scheduler::RunNextTask", "state", state.AsValue());
 
-  DCHECK(GetSequence(state.sequence_id));
-  base::OnceClosure closure = GetSequence(state.sequence_id)->BeginTask();
+  Sequence* sequence = GetSequence(state.sequence_id);
+  DCHECK(sequence);
 
+  base::OnceClosure closure;
+  uint32_t order_num = sequence->BeginTask(&closure);
+  DCHECK_EQ(order_num, state.order_num);
+
+  // Begin/FinishProcessingOrderNumber must be called with the lock released
+  // because they can renter the scheduler in Enable/DisableSequence.
+  scoped_refptr<SyncPointOrderData> order_data = sequence->order_data();
   {
     base::AutoUnlock auto_unlock(lock_);
+    order_data->BeginProcessingOrderNumber(order_num);
     std::move(closure).Run();
+    if (order_data->IsProcessingOrderNumber())
+      order_data->FinishProcessingOrderNumber(order_num);
   }
 
   // Check if sequence hasn't been destroyed.
-  Sequence* sequence = GetSequence(state.sequence_id);
+  sequence = GetSequence(state.sequence_id);
   if (sequence) {
     sequence->FinishTask();
     if (sequence->IsRunnable()) {
diff --git a/gpu/command_buffer/service/scheduler_unittest.cc b/gpu/command_buffer/service/scheduler_unittest.cc
index 43328b3..dd0adad 100644
--- a/gpu/command_buffer/service/scheduler_unittest.cc
+++ b/gpu/command_buffer/service/scheduler_unittest.cc
@@ -331,5 +331,59 @@
   release_state->Destroy();
 }
 
+TEST_F(SchedulerTest, ReentrantEnableSequenceShouldNotDeadlock) {
+  SequenceId sequence_id1 =
+      scheduler()->CreateSequence(SchedulingPriority::kHigh);
+  CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO;
+  CommandBufferId command_buffer_id1 = CommandBufferId::FromUnsafeValue(1);
+  scoped_refptr<SyncPointClientState> release_state1 =
+      sync_point_manager()->CreateSyncPointClientState(
+          namespace_id, command_buffer_id1, sequence_id1);
+
+  SequenceId sequence_id2 =
+      scheduler()->CreateSequence(SchedulingPriority::kNormal);
+  CommandBufferId command_buffer_id2 = CommandBufferId::FromUnsafeValue(2);
+  scoped_refptr<SyncPointClientState> release_state2 =
+      sync_point_manager()->CreateSyncPointClientState(
+          namespace_id, command_buffer_id2, sequence_id2);
+
+  uint64_t release = 1;
+  SyncToken sync_token(namespace_id, 0 /* extra_data_field */,
+                       command_buffer_id2, release);
+
+  bool ran1, ran2 = false;
+
+  // Schedule task on sequence 2 first so that the sync token wait isn't a nop.
+  // BeginProcessingOrderNumber for this task will run the EnableSequence
+  // callback. This should not deadlock.
+  scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { ran2 = true; }),
+                            std::vector<SyncToken>());
+
+  // This will run first because of the higher priority and no scheduling sync
+  // token dependencies.
+  scheduler()->ScheduleTask(
+      sequence_id1, GetClosure([&] {
+        ran1 = true;
+        release_state1->Wait(
+            sync_token,
+            base::Bind(&Scheduler::EnableSequence,
+                       base::Unretained(scheduler()), sequence_id1));
+        scheduler()->DisableSequence(sequence_id1);
+      }),
+      std::vector<SyncToken>());
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran1);
+  EXPECT_FALSE(ran2);
+  EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(sync_token));
+
+  task_runner()->RunPendingTasks();
+  EXPECT_TRUE(ran2);
+  EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(sync_token));
+
+  release_state1->Destroy();
+  release_state2->Destroy();
+}
+
 }  // namespace
 }  // namespace gpu
diff --git a/media/audio/audio_output_ipc.h b/media/audio/audio_output_ipc.h
index 403081b..b6fd58d 100644
--- a/media/audio/audio_output_ipc.h
+++ b/media/audio/audio_output_ipc.h
@@ -97,7 +97,10 @@
   virtual void PauseStream() = 0;
 
   // Closes the audio stream which should shut down the corresponding
-  // AudioOutputController in the peer process.
+  // AudioOutputController in the peer process. Usage of an AudioOutputIPC must
+  // always end with a call to CloseStream(), and the |delegate| passed to other
+  // method must remain valid until then. An exception is if OnIPCClosed is
+  // called first.
   virtual void CloseStream() = 0;
 
   // Sets the volume of the audio stream.
diff --git a/media/mojo/interfaces/audio_output_stream.mojom b/media/mojo/interfaces/audio_output_stream.mojom
index 67926c3d..5dccd9d4 100644
--- a/media/mojo/interfaces/audio_output_stream.mojom
+++ b/media/mojo/interfaces/audio_output_stream.mojom
@@ -25,7 +25,12 @@
 interface AudioOutputStreamProvider {
   // Creates a new AudioOutputStream using |params|. |shared_buffer| and
   // |socket_descriptor| are used to write data to the stream as defined
-  // in AudioDeviceThread. Can only be called once.
+  // in AudioDeviceThread. This means:
+  // * |shared_buffer| will be a writable handle to memory of the size needed
+  //   by AudioDeviceThread for the specified params.
+  // * |socket_descriptor| is a descriptor from which a
+  //   base::CancelableSyncSocket can be constructed.
+  // Can only be called once.
   Acquire(AudioOutputStream& output_stream, AudioParameters params)
   => (handle<shared_buffer> shared_buffer, handle socket_descriptor);
 };
diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc
index 0d60b48a..36b965b 100644
--- a/mojo/edk/system/core_unittest.cc
+++ b/mojo/edk/system/core_unittest.cc
@@ -258,50 +258,6 @@
   }
 }
 
-// These test invalid arguments that should cause death if we're being paranoid
-// about checking arguments (which we would want to do if, e.g., we were in a
-// true "kernel" situation, but we might not want to do otherwise for
-// performance reasons). Probably blatant errors like passing in null pointers
-// (for required pointer arguments) will still cause death, but perhaps not
-// predictably.
-TEST_F(CoreTest, InvalidArgumentsDeath) {
-#if defined(OFFICIAL_BUILD)
-  const char kMemoryCheckFailedRegex[] = "";
-#else
-  const char kMemoryCheckFailedRegex[] = "Check failed";
-#endif
-
-  // |CreateMessagePipe()|:
-  {
-    MojoHandle h;
-    ASSERT_DEATH_IF_SUPPORTED(
-        core()->CreateMessagePipe(nullptr, nullptr, nullptr),
-        kMemoryCheckFailedRegex);
-    ASSERT_DEATH_IF_SUPPORTED(
-        core()->CreateMessagePipe(nullptr, &h, nullptr),
-        kMemoryCheckFailedRegex);
-    ASSERT_DEATH_IF_SUPPORTED(
-        core()->CreateMessagePipe(nullptr, nullptr, &h),
-        kMemoryCheckFailedRegex);
-  }
-
-  // |ReadMessage()|:
-  // Only check arguments checked by |Core|, namely |handle|, |handles|, and
-  // |num_handles|.
-  {
-    MockHandleInfo info;
-    MojoHandle h = CreateMockHandle(&info);
-
-    uint32_t handle_count = 1;
-    ASSERT_DEATH_IF_SUPPORTED(
-        core()->ReadMessage(h, nullptr, nullptr, nullptr, &handle_count,
-                            MOJO_READ_MESSAGE_FLAG_NONE),
-        kMemoryCheckFailedRegex);
-
-    ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h));
-  }
-}
-
 TEST_F(CoreTest, MessagePipe) {
   MojoHandle h[2];
   MojoHandleSignalsState hss[2];
diff --git a/services/device/battery/battery_monitor_impl.cc b/services/device/battery/battery_monitor_impl.cc
index 1a134c0..f1f8dcb5 100644
--- a/services/device/battery/battery_monitor_impl.cc
+++ b/services/device/battery/battery_monitor_impl.cc
@@ -30,14 +30,13 @@
 
 BatteryMonitorImpl::~BatteryMonitorImpl() {}
 
-void BatteryMonitorImpl::QueryNextStatus(
-    const QueryNextStatusCallback& callback) {
+void BatteryMonitorImpl::QueryNextStatus(QueryNextStatusCallback callback) {
   if (!callback_.is_null()) {
     DVLOG(1) << "Overlapped call to QueryNextStatus!";
     binding_->Close();
     return;
   }
-  callback_ = callback;
+  callback_ = std::move(callback);
 
   if (status_to_report_)
     ReportStatus();
@@ -54,8 +53,7 @@
 }
 
 void BatteryMonitorImpl::ReportStatus() {
-  callback_.Run(status_.Clone());
-  callback_.Reset();
+  std::move(callback_).Run(status_.Clone());
 
   status_to_report_ = false;
 }
diff --git a/services/device/battery/battery_monitor_impl.h b/services/device/battery/battery_monitor_impl.h
index 1b8d67f..511e7396 100644
--- a/services/device/battery/battery_monitor_impl.h
+++ b/services/device/battery/battery_monitor_impl.h
@@ -23,7 +23,7 @@
 
  private:
   // mojom::BatteryMonitor methods:
-  void QueryNextStatus(const QueryNextStatusCallback& callback) override;
+  void QueryNextStatus(QueryNextStatusCallback callback) override;
 
   void RegisterSubscription();
   void DidChange(const mojom::BatteryStatus& battery_status);
diff --git a/services/device/fingerprint/fingerprint_chromeos.cc b/services/device/fingerprint/fingerprint_chromeos.cc
index 777f7e2..80ab433 100644
--- a/services/device/fingerprint/fingerprint_chromeos.cc
+++ b/services/device/fingerprint/fingerprint_chromeos.cc
@@ -17,9 +17,9 @@
 constexpr int64_t kFingerprintSessionTimeoutMs = 150;
 
 // Used to convert mojo Callback to VoidDbusMethodCallback.
-void RunFingerprintCallback(const base::Callback<void(bool)>& callback,
+void RunFingerprintCallback(base::OnceCallback<void(bool)> callback,
                             chromeos::DBusMethodCallStatus result) {
-  callback.Run(result == chromeos::DBUS_METHOD_CALL_SUCCESS);
+  std::move(callback).Run(result == chromeos::DBUS_METHOD_CALL_SUCCESS);
 }
 
 chromeos::BiodClient* GetBiodClient() {
@@ -44,10 +44,11 @@
 
 void FingerprintChromeOS::GetRecordsForUser(
     const std::string& user_id,
-    const GetRecordsForUserCallback& callback) {
+    GetRecordsForUserCallback callback) {
   chromeos::DBusThreadManager::Get()->GetBiodClient()->GetRecordsForUser(
-      user_id, base::Bind(&FingerprintChromeOS::OnGetRecordsForUser,
-                          weak_ptr_factory_.GetWeakPtr(), callback));
+      user_id,
+      base::Bind(&FingerprintChromeOS::OnGetRecordsForUser,
+                 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
 }
 
 void FingerprintChromeOS::StartEnrollSession(const std::string& user_id,
@@ -85,35 +86,37 @@
 }
 
 void FingerprintChromeOS::CancelCurrentEnrollSession(
-    const CancelCurrentEnrollSessionCallback& callback) {
+    CancelCurrentEnrollSessionCallback callback) {
   if (opened_session_ == FingerprintSession::ENROLL) {
     GetBiodClient()->CancelEnrollSession(
-        base::Bind(&RunFingerprintCallback, callback));
+        base::Bind(&RunFingerprintCallback, base::Passed(&callback)));
     opened_session_ = FingerprintSession::NONE;
   } else {
-    callback.Run(true);
+    std::move(callback).Run(true);
   }
 }
 
 void FingerprintChromeOS::RequestRecordLabel(
     const std::string& record_path,
-    const RequestRecordLabelCallback& callback) {
-  GetBiodClient()->RequestRecordLabel(dbus::ObjectPath(record_path), callback);
+    RequestRecordLabelCallback callback) {
+  GetBiodClient()->RequestRecordLabel(
+      dbus::ObjectPath(record_path),
+      base::AdaptCallbackForRepeating(std::move(callback)));
 }
 
-void FingerprintChromeOS::SetRecordLabel(
-    const std::string& new_label,
-    const std::string& record_path,
-    const SetRecordLabelCallback& callback) {
+void FingerprintChromeOS::SetRecordLabel(const std::string& new_label,
+                                         const std::string& record_path,
+                                         SetRecordLabelCallback callback) {
   GetBiodClient()->SetRecordLabel(
       dbus::ObjectPath(record_path), new_label,
-      base::Bind(&RunFingerprintCallback, callback));
+      base::Bind(&RunFingerprintCallback, base::Passed(&callback)));
 }
 
 void FingerprintChromeOS::RemoveRecord(const std::string& record_path,
-                                       const RemoveRecordCallback& callback) {
-  GetBiodClient()->RemoveRecord(dbus::ObjectPath(record_path),
-                                base::Bind(&RunFingerprintCallback, callback));
+                                       RemoveRecordCallback callback) {
+  GetBiodClient()->RemoveRecord(
+      dbus::ObjectPath(record_path),
+      base::Bind(&RunFingerprintCallback, base::Passed(&callback)));
 }
 
 void FingerprintChromeOS::StartAuthSession() {
@@ -146,24 +149,25 @@
 }
 
 void FingerprintChromeOS::EndCurrentAuthSession(
-    const EndCurrentAuthSessionCallback& callback) {
+    EndCurrentAuthSessionCallback callback) {
   if (opened_session_ == FingerprintSession::AUTH) {
     GetBiodClient()->EndAuthSession(
-        base::Bind(&RunFingerprintCallback, callback));
+        base::Bind(&RunFingerprintCallback, base::Passed(&callback)));
     opened_session_ = FingerprintSession::NONE;
   } else {
-    callback.Run(true);
+    std::move(callback).Run(true);
   }
 }
 
 void FingerprintChromeOS::DestroyAllRecords(
-    const DestroyAllRecordsCallback& callback) {
+    DestroyAllRecordsCallback callback) {
   GetBiodClient()->DestroyAllRecords(
-      base::Bind(&RunFingerprintCallback, callback));
+      base::Bind(&RunFingerprintCallback, base::Passed(&callback)));
 }
 
-void FingerprintChromeOS::RequestType(const RequestTypeCallback& callback) {
-  GetBiodClient()->RequestType(callback);
+void FingerprintChromeOS::RequestType(RequestTypeCallback callback) {
+  GetBiodClient()->RequestType(
+      base::AdaptCallbackForRepeating(std::move(callback)));
 }
 
 void FingerprintChromeOS::AddFingerprintObserver(
@@ -242,28 +246,28 @@
 }
 
 void FingerprintChromeOS::OnGetRecordsForUser(
-    const GetRecordsForUserCallback& callback,
+    GetRecordsForUserCallback callback,
     const std::vector<dbus::ObjectPath>& records) {
   records_path_to_label_.clear();
   if (records.size() == 0)
-    callback.Run(records_path_to_label_);
+    std::move(callback).Run(records_path_to_label_);
 
   for (auto& record : records) {
     GetBiodClient()->RequestRecordLabel(
         record, base::Bind(&FingerprintChromeOS::OnGetLabelFromRecordPath,
-                           weak_ptr_factory_.GetWeakPtr(), callback,
-                           records.size(), record));
+                           weak_ptr_factory_.GetWeakPtr(),
+                           base::Passed(&callback), records.size(), record));
   }
 }
 
 void FingerprintChromeOS::OnGetLabelFromRecordPath(
-    const GetRecordsForUserCallback& callback,
+    GetRecordsForUserCallback callback,
     size_t num_records,
     const dbus::ObjectPath& record_path,
     const std::string& label) {
   records_path_to_label_[record_path.value()] = label;
   if (records_path_to_label_.size() == num_records)
-    callback.Run(records_path_to_label_);
+    std::move(callback).Run(records_path_to_label_);
 }
 
 // static
diff --git a/services/device/fingerprint/fingerprint_chromeos.h b/services/device/fingerprint/fingerprint_chromeos.h
index 45d7274e..943e03a 100644
--- a/services/device/fingerprint/fingerprint_chromeos.h
+++ b/services/device/fingerprint/fingerprint_chromeos.h
@@ -33,23 +33,22 @@
 
   // mojom::Fingerprint:
   void GetRecordsForUser(const std::string& user_id,
-                         const GetRecordsForUserCallback& callback) override;
+                         GetRecordsForUserCallback callback) override;
   void StartEnrollSession(const std::string& user_id,
                           const std::string& label) override;
   void CancelCurrentEnrollSession(
-      const CancelCurrentEnrollSessionCallback& callback) override;
+      CancelCurrentEnrollSessionCallback callback) override;
   void RequestRecordLabel(const std::string& record_path,
-                          const RequestRecordLabelCallback& callback) override;
+                          RequestRecordLabelCallback callback) override;
   void SetRecordLabel(const std::string& record_path,
                       const std::string& new_label,
-                      const SetRecordLabelCallback& callback) override;
+                      SetRecordLabelCallback callback) override;
   void RemoveRecord(const std::string& record_path,
-                    const RemoveRecordCallback& callback) override;
+                    RemoveRecordCallback callback) override;
   void StartAuthSession() override;
-  void EndCurrentAuthSession(
-      const EndCurrentAuthSessionCallback& callback) override;
-  void DestroyAllRecords(const DestroyAllRecordsCallback& callback) override;
-  void RequestType(const RequestTypeCallback& callback) override;
+  void EndCurrentAuthSession(EndCurrentAuthSessionCallback callback) override;
+  void DestroyAllRecords(DestroyAllRecordsCallback callback) override;
+  void RequestType(RequestTypeCallback callback) override;
   void AddFingerprintObserver(mojom::FingerprintObserverPtr observer) override;
 
  private:
@@ -68,9 +67,9 @@
   void OnFingerprintObserverDisconnected(mojom::FingerprintObserver* observer);
   void OnStartEnrollSession(const dbus::ObjectPath& enroll_path);
   void OnStartAuthSession(const dbus::ObjectPath& auth_path);
-  void OnGetRecordsForUser(const GetRecordsForUserCallback& callback,
+  void OnGetRecordsForUser(GetRecordsForUserCallback callback,
                            const std::vector<dbus::ObjectPath>& record_paths);
-  void OnGetLabelFromRecordPath(const GetRecordsForUserCallback& callback,
+  void OnGetLabelFromRecordPath(GetRecordsForUserCallback callback,
                                 size_t num_records,
                                 const dbus::ObjectPath& record_path,
                                 const std::string& label);
diff --git a/services/device/public/interfaces/BUILD.gn b/services/device/public/interfaces/BUILD.gn
index ae3247b..b368d19 100644
--- a/services/device/public/interfaces/BUILD.gn
+++ b/services/device/public/interfaces/BUILD.gn
@@ -20,9 +20,6 @@
     ":constants",
   ]
 
-  # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
-  use_once_callback = false
-
   # TODO(crbug.com/699569): Convert to use the new JS bindings.
   use_new_js_bindings = false
 }
diff --git a/services/device/vibration/vibration_manager_impl_default.cc b/services/device/vibration/vibration_manager_impl_default.cc
index 60bfd11..5141bc71 100644
--- a/services/device/vibration/vibration_manager_impl_default.cc
+++ b/services/device/vibration/vibration_manager_impl_default.cc
@@ -22,14 +22,14 @@
   VibrationManagerEmptyImpl() {}
   ~VibrationManagerEmptyImpl() override {}
 
-  void Vibrate(int64_t milliseconds, const VibrateCallback& callback) override {
+  void Vibrate(int64_t milliseconds, VibrateCallback callback) override {
     VibrationManagerImpl::milli_seconds_for_testing_ = milliseconds;
-    callback.Run();
+    std::move(callback).Run();
   }
 
-  void Cancel(const CancelCallback& callback) override {
+  void Cancel(CancelCallback callback) override {
     VibrationManagerImpl::cancelled_for_testing_ = true;
-    callback.Run();
+    std::move(callback).Run();
   }
 };
 
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 096bd59..2d0a933e 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -435,9 +435,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-clear-014.xht [ Failure ]
 
 ### virtual/layout_ng/external/wpt/css/CSS2/linebox
-crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/border-padding-bleed-001.xht [ Failure ]
-crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/border-padding-bleed-002.xht [ Failure ]
-crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/border-padding-bleed-003.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/empty-inline-002.xht [ Crash Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/inline-formatting-context-001.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/inline-formatting-context-002.xht [ Failure ]
@@ -449,7 +446,6 @@
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/inline-formatting-context-010b.xht [ Skip ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/inline-formatting-context-012.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/inline-formatting-context-013.xht [ Failure ]
-crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/inline-formatting-context-022.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/inline-formatting-context-023.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/line-height-002.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/line-height-004.xht [ Failure ]
@@ -481,12 +477,9 @@
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/line-height-101.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/line-height-103.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/line-height-104.xht [ Failure ]
-crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/line-height-125.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/line-height-129.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/line-height-bleed-001.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/line-height-bleed-002.xht [ Failure ]
-crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/vertical-align-117a.xht [ Failure ]
-crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/vertical-align-118a.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/vertical-align-121.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/vertical-align-baseline-004a.xht [ Failure ]
 crbug.com/636993 virtual/layout_ng/external/wpt/css/CSS2/linebox/vertical-align-baseline-005a.xht [ Failure ]
@@ -3022,11 +3015,6 @@
 crbug.com/724392 [ Win ] fast/css/font-family-case-insensitive.html [ Failure Pass Timeout ]
 crbug.com/713094 [ Win ] fast/css/fontfaceset-check-platform-fonts.html [ Failure Pass ]
 
-# Sheriff failures 2017-05-17
-# Crashes
-crbug.com/723841 http/tests/dom/script-module-load-incomplete-no-crash.html [ Skip ]
-crbug.com/723841 virtual/mojo-loading/http/tests/dom/script-module-load-incomplete-no-crash.html [ Skip ]
-
 # Sheriff failures 2017-05-22
 crbug.com/725542 [ Debug ] editing/selection/doubleclick-beside-cr-span.html [ Pass Timeout ]
 crbug.com/725545 [ Debug ] fast/forms/number/number-stepup-stepdown-from-renderer.html [ Pass Timeout ]
@@ -3048,3 +3036,6 @@
 # Sheriff failures 2017-05-30
 # Failing on try (with patch) and Linux FYI too frequently.
 crbug.com/727505 [ Linux ] virtual/threaded/fast/compositorworker/basic-plumbing-main-to-worker.html [ Pass Crash ]
+
+# Sheriff failures 2017-05-31
+crbug.com/727991 [ Linux Mac ] virtual/threaded/fast/compositorworker/visual-update.html [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-scoping-1/css-scoping-shadow-host-namespace.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-scoping-1/css-scoping-shadow-host-namespace.html
new file mode 100644
index 0000000..46dffc8d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-scoping-1/css-scoping-shadow-host-namespace.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>CSS Scoping Module Level 1 - :host, :host-context, and default @namespace</title>
+    <link rel="author" title="Rune Lillesveen" href="mailto:rune@opera.com"/>
+    <link rel="help" href="https://www.w3.org/TR/css-scoping-1/#host-selector">
+    <link rel="help" href="https://www.w3.org/TR/css3-selectors/#typenmsp">
+    <link rel="help" href="https://www.w3.org/TR/css3-selectors/#univnmsp">
+    <link rel="match" href="reference/green-box.html"/>
+</head>
+<body>
+    <style>
+        .host {
+            display: block;
+            width: 100px;
+            height: 10px;
+            background: red;
+        }
+        #host-3, #host-5, #host-10 {
+            background: green;
+        }
+    </style>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div id="host-1" class="host">FAIL</div>
+    <div id="host-2" class="host">FAIL</div>
+    <div id="host-3" class="host">FAIL</div>
+    <div id="host-4" class="host">FAIL</div>
+    <div id="host-5" class="host">FAIL</div>
+    <div id="host-6" class="host">FAIL</div>
+    <div id="host-7" class="host">FAIL</div>
+    <div id="host-8" class="host">FAIL</div>
+    <div id="host-9" class="host">FAIL</div>
+    <div id="host-10" class="host">FAIL</div>
+    <script>
+        try {
+            var shadowHost = document.querySelector('#host-1');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://www.w3.org/1999/xhtml); :host { background: green !important; } </style>';
+
+            shadowHost = document.querySelector('#host-2');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://dummy); :host { background: green !important; } </style>';
+
+            shadowHost = document.querySelector('#host-3');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://dummy); :host(*) { background: red !important; } </style>';
+
+            shadowHost = document.querySelector('#host-4');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://dummy); :host(*|*) { background: green !important; } </style>';
+
+            shadowHost = document.querySelector('#host-5');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://dummy); :host-context(*) { background: red !important; } </style>';
+
+            shadowHost = document.querySelector('#host-6');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://dummy); :host-context(*|*) { background: green !important; } </style>';
+
+            shadowHost = document.querySelector('#host-7');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://www.w3.org/1999/xhtml); :host(*) { background: green !important; } </style>';
+
+            shadowHost = document.querySelector('#host-8');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://www.w3.org/1999/xhtml); :host-context(*) { background: green !important; } </style>';
+
+            shadowHost = document.querySelector('#host-9');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://www.w3.org/1999/xhtml); :host(div) { background: green !important; } </style>';
+
+            shadowHost = document.querySelector('#host-10');
+            shadowRoot = shadowHost.attachShadow({mode: 'open'});
+            shadowRoot.innerHTML = '<style>@namespace url(http://dummy); :host-context(html) { background: red !important; } </style>';
+
+        } catch (exception) {
+            document.body.appendChild(document.createTextNode(exception));
+        }
+
+    </script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/view-location-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/view-location-expected.txt
new file mode 100644
index 0000000..0bbce416
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/view-location-expected.txt
@@ -0,0 +1,18 @@
+Creating new TabbedLocation
+[]
+Appending three views
+["first","second","third"]
+Creating new TabbedLocation
+["first","second","third"]
+Re-order tabs
+["third","first","second"]
+Creating new TabbedLocation
+["third","first","second"]
+["third","first","second","fourth"]
+Creating new TabbedLocation
+["third","first","second","fourth"]
+Closing second tab
+["third","first","fourth"]
+Creating new TabbedLocation
+["third","first","fourth"]
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/view-location.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/view-location.js
new file mode 100644
index 0000000..ddce77fc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/view-location.js
@@ -0,0 +1,54 @@
+runtime._registerModule({
+  name: "mock-module",
+  extensions: ['first', 'second', 'third', 'fourth'].map(title => {
+    return {
+      "type": "view",
+      "location": "mock-location",
+      "id": title,
+      "title": title,
+      "persistence": "closeable",
+      "factoryName": "UI.Widget"
+    }
+  }),
+  scripts: []
+});
+
+var tabbedLocation;
+var viewManager;
+createTabbedLocation();
+dumpTabs();
+TestRunner.addResult('Appending three views')
+viewManager.showView('first');
+viewManager.showView('second');
+viewManager.showView('third');
+dumpTabs();
+createTabbedLocation();
+dumpTabs();
+TestRunner.addResult('Re-order tabs');
+tabbedLocation.tabbedPane()._insertBefore(tabbedLocation.tabbedPane()._tabsById.get("third"), 0);
+dumpTabs();
+createTabbedLocation();
+dumpTabs();
+viewManager.showView('fourth');
+dumpTabs();
+createTabbedLocation();
+dumpTabs();
+TestRunner.addResult('Closing second tab');
+tabbedLocation.tabbedPane().closeTab('second');
+dumpTabs();
+createTabbedLocation();
+dumpTabs();
+TestRunner.completeTest();
+
+function createTabbedLocation() {
+  TestRunner.addResult('Creating new TabbedLocation');
+  if (tabbedLocation)
+    tabbedLocation.tabbedPane().detach(true);
+  viewManager = new UI.ViewManager();
+  tabbedLocation = viewManager.createTabbedLocation(undefined, 'mock-location', true, true);
+  tabbedLocation.widget().show(UI.inspectorView.element);
+}
+
+function dumpTabs() {
+  TestRunner.addResult(JSON.stringify(tabbedLocation.tabbedPane().tabIds()));
+}
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-applyConstraints-getSettings.html b/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-applyConstraints-getSettings.html
index 7a183e6..f8a79852 100644
--- a/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-applyConstraints-getSettings.html
+++ b/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-applyConstraints-getSettings.html
@@ -2,6 +2,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
+<script src="resources/imagecapture-helpers.js"></script>
 <script src="resources/mock-imagecapture.js"></script>
 <body>
 <canvas id='canvas' width=10 height=10/>
@@ -59,10 +60,8 @@
       // TODO(mcasas): this shouldn't be needed, https://crbug.com/711524.
       return new Promise(resolve => setTimeout(resolve, 100));
     })
-    .then(function() {
-      return videoTrack.applyConstraints(constraints);
-    })
-    .then(function() {
+    .then(() => videoTrack.applyConstraints(constraints))
+    .then(appliedConstraints => {
 
       settings = videoTrack.getSettings();
       assert_equals(typeof settings, 'object');
@@ -74,16 +73,9 @@
       assert_equals(constraints.advanced[0].focusMode, settings.focusMode,
                     'focusMode');
 
-      assert_equals(constraints.advanced[0].pointsOfInterest.length,
-                    settings.pointsOfInterest.length, 'pointsOfInterest');
-      for (i = 0; i < constraints.advanced[0].pointsOfInterest.length; ++i) {
-        assert_approx_equals(constraints.advanced[0].pointsOfInterest[i].x,
-                             settings.pointsOfInterest[i].x, 0.01,
-                             'pointsOfInterest x');
-        assert_approx_equals(constraints.advanced[0].pointsOfInterest[i].y,
-                             settings.pointsOfInterest[i].y, 0.01,
-                             'pointsOfInterest y');
-      }
+      assert_point2d_array_approx_equals(
+          constraints.advanced[0].pointsOfInterest, settings.pointsOfInterest,
+          0.01);
 
       assert_equals(constraints.advanced[0].exposureCompensation,
                     settings.exposureCompensation, 'exposureCompensation');
diff --git a/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-applyConstraints.html b/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-applyConstraints.html
index d16ef04f..25013a4 100644
--- a/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-applyConstraints.html
+++ b/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-applyConstraints.html
@@ -2,6 +2,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
+<script src="resources/imagecapture-helpers.js"></script>
 <script src="resources/mock-imagecapture.js"></script>
 <body>
 <canvas id='canvas' width=10 height=10/>
@@ -58,50 +59,55 @@
     error => {
       assert_unreached("Error creating MockImageCapture: " + error);
     })
-    .then(function() {
-      return videoTrack.applyConstraints(constraints);
-    })
-    .then(function() {
-      assert_equals(constraints.advanced[0].whiteBalanceMode,
+    .then(() => videoTrack.applyConstraints(constraints))
+    .then(appliedConstraints => {
+
+      const constraintsDict = constraints.advanced[0];
+      const appliedConstraintsDict = appliedConstraints.advanced[0];
+
+      // Check that |appliedConstraints| and |constraints| are equal.
+      assert_equals(constraintsDict.length, appliedConstraintsDict.length);
+      Object.keys(appliedConstraintsDict).forEach((key, value) => {
+        assert_not_equals(constraintsDict[key], undefined, 'key ' + key);
+        if (key != "pointsOfInterest") {
+          assert_equals(constraintsDict[key], appliedConstraintsDict[key], key);
+        } else {
+          assert_point2d_array_approx_equals(constraintsDict[key],
+                                             appliedConstraintsDict[key], 0.01);
+        }
+      });
+
+      assert_equals(constraintsDict.whiteBalanceMode,
                     meteringModeNames[theMock.options().white_balance_mode],
                     'whiteBalanceMode');
-      assert_equals(constraints.advanced[0].exposureMode,
+      assert_equals(constraintsDict.exposureMode,
                     meteringModeNames[theMock.options().exposure_mode],
                     'exposureMode');
-      assert_equals(constraints.advanced[0].focusMode,
+      assert_equals(constraintsDict.focusMode,
                     meteringModeNames[theMock.options().focus_mode],
                     'focusMode');
 
-      assert_equals(constraints.advanced[0].pointsOfInterest.length,
-                    theMock.options().points_of_interest.length,
-                    'pointsOfInterest');
-      for (i = 0; i < constraints.advanced[0].pointsOfInterest.length; ++i) {
-        assert_approx_equals(constraints.advanced[0].pointsOfInterest[i].x,
-                             theMock.options().points_of_interest[i].x, 0.01,
-                             'pointsOfInterest x');
-        assert_approx_equals(constraints.advanced[0].pointsOfInterest[i].y,
-                             theMock.options().points_of_interest[i].y, 0.01,
-                             'pointsOfInterest y');
-      }
+      assert_point2d_array_approx_equals(constraintsDict.pointsOfInterest,
+                                         theMock.options().points_of_interest,
+                                         0.01);
 
-      assert_equals(constraints.advanced[0].exposureCompensation,
+      assert_equals(constraintsDict.exposureCompensation,
                     theMock.options().exposure_compensation,
                     'exposureCompensation');
-      assert_equals(constraints.advanced[0].colorTemperature,
+      assert_equals(constraintsDict.colorTemperature,
                     theMock.options().color_temperature, 'colorTemperature');
-      assert_equals(constraints.advanced[0].iso, theMock.options().iso, 'iso');
+      assert_equals(constraintsDict.iso, theMock.options().iso, 'iso');
 
-      assert_equals(constraints.advanced[0].brightness,
-                    theMock.options().brightness, 'brightness');
-      assert_equals(constraints.advanced[0].contrast,
-                    theMock.options().contrast, 'constrast');
-      assert_equals(constraints.advanced[0].saturation,
-                    theMock.options().saturation, 'saturation');
-      assert_equals(constraints.advanced[0].sharpness,
-                    theMock.options().sharpness, 'sharpness');
+      assert_equals(constraintsDict.brightness, theMock.options().brightness,
+                    'brightness');
+      assert_equals(constraintsDict.contrast, theMock.options().contrast,
+                    'constrast');
+      assert_equals(constraintsDict.saturation, theMock.options().saturation,
+                    'saturation');
+      assert_equals(constraintsDict.sharpness, theMock.options().sharpness,
+                    'sharpness');
 
-      assert_equals(constraints.advanced[0].torch, theMock.options().torch,
-                    'torch');
+      assert_equals(constraintsDict.torch, theMock.options().torch, 'torch');
 
       t.done();
     })
diff --git a/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-getSettings.html b/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-getSettings.html
index ef25073e..822d22be 100644
--- a/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-getSettings.html
+++ b/third_party/WebKit/LayoutTests/imagecapture/MediaStreamTrack-getSettings.html
@@ -2,6 +2,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
+<script src="resources/imagecapture-helpers.js"></script>
 <script src="resources/mock-imagecapture.js"></script>
 <body>
 <canvas id='canvas' width=10 height=10/>
@@ -48,17 +49,8 @@
                       meteringModeNames[mock_settings.current_focus_mode],
                       'focusMode');
 
-        assert_equals(settings.pointsOfInterest.length,
-                      mock_settings.points_of_interest.length,
-                      'pointsOfInterest');
-        for (i = 0; i < settings.pointsOfInterest.length; ++i) {
-          assert_approx_equals(settings.pointsOfInterest[i].x,
-                               mock_settings.points_of_interest[i].x, 0.01,
-                               'pointsOfInterest x');
-          assert_approx_equals(settings.pointsOfInterest[i].y,
-                               mock_settings.points_of_interest[i].y, 0.01,
-                               'pointsOfInterest y');
-        }
+        assert_point2d_array_approx_equals(
+            settings.pointsOfInterest, mock_settings.points_of_interest, 0.01);
 
         assert_equals(settings.exposureCompensation,
                       mock_settings.exposure_compensation.current);
diff --git a/third_party/WebKit/LayoutTests/imagecapture/resources/imagecapture-helpers.js b/third_party/WebKit/LayoutTests/imagecapture/resources/imagecapture-helpers.js
new file mode 100644
index 0000000..3eb14ca
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imagecapture/resources/imagecapture-helpers.js
@@ -0,0 +1,9 @@
+'use strict';
+
+function assert_point2d_array_approx_equals(actual, expected, epsilon) {
+  assert_equals(actual.length, expected.length, 'length');
+  for (var i = 0; i < actual.length; ++i) {
+    assert_approx_equals(actual[i].x, expected[i].x, epsilon, 'x');
+    assert_approx_equals(actual[i].y, expected[i].y, epsilon, 'y');
+  }
+}
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-allpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-allpass.html
deleted file mode 100644
index b902f42..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-allpass.html
+++ /dev/null
@@ -1,103 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Test Biquad Tail-Time</title>
-    <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
-    <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audit.js"></script>
-    <script src="../resources/biquad-filters.js"></script>
-    <script src="test-tail-time.js"></script>
-  </head>
-
-  <body>
-    <script>
-      let audit = Audit.createTaskRunner();
-
-      let sampleRate = 16384;
-      let renderSeconds = 1;
-      let renderFrames = renderSeconds * sampleRate;
-
-      // For an allpass filter:
-      //   b0 = 1 - alpha
-      //   b1 = -2*cos(w0)
-      //   b2 = 1 + alpha
-      //   a0 = 1 + alpha
-      //   a1 = -2*cos(w0)
-      //   a2 = 1 - alpha
-      //
-      // where alpha = sin(w0)/(2*Q) and w0 = 2*%pi*f0/Fs.
-      //
-      // Equivalently a1 = -2*cos(w0)/(1+alpha), a2 = (1-alpha)/(1+alpha).  The
-      // poles of this filter are at
-      //
-      //   (2*Q*cos(w0) +/- sqrt(1-4*Q^2)*sin(w0))/(2*Q + sin(w0))
-      //
-      // Thus, if 1-4*Q^2 < 0, the poles are complex.  For 1-4*Q^2 > 0, the
-      // poles are real and distinct.  For 1-4*Q^2 = 0, there are two identical
-      // real poles.
-
-      // Array of tests to run.  |descripton| is the task description for
-      // audit.define.  |parameters| is option for |testTailTime|.
-      let tests = [
-        {
-          description:
-              {label: 'allpass-complex-roots', description: 'complex roots'},
-          parameters: {
-            prefix: 'Complex roots',
-            // Choose a fairly large Q to make the tail long.  Frequency is
-            // fairly arbitrary.
-            filterOptions: {type: 'allpass', Q: 200, frequency: sampleRate / 4},
-            // This filter the actual real tail frame is 2317, and the node
-            // computed frame is 2316.81.  Thus, the tail output should be
-            // exactly 0.
-            threshold: 0
-          }
-        },
-        {
-          description: {
-            label: 'allpass-real-distinct-roots',
-            description: 'real distinct roots'
-          },
-          parameters: {
-            prefix: 'Distinct roots',
-            filterOptions: {
-              type: 'allpass',
-              Q: 0.001,
-              frequency: sampleRate / 8,
-            },
-            // With this particular filter, the real tail frame is 4822, but
-            // the node way overestimates it to be 7136.  Thus, the actual
-            // tail frames won't be exactly zero.
-            threshold: 1 / 32768
-          }
-        },
-        {
-          description: {
-            label: 'allpass-repeated-roots',
-            description: 'repeated real root'
-          },
-          parameters: {
-            prefix: 'Repeated roots',
-            // 1-4*Q^2 = 0 iff Q = 1/2.
-            filterOptions: {type: 'allpass', Q: 0.5, frequency: sampleRate / 8},
-            // The node estimated tail time is 16.8 frames, but the actual is
-            // 106.  Thus, the outupt should be exactly 0.
-            threshold: 0
-          }
-        }
-      ];
-
-      // Define an appropriate task for each test.
-      tests.forEach(entry => {
-        audit.define(entry.description, (task, should) => {
-          let context = new OfflineAudioContext(1, renderFrames, sampleRate);
-          testTailTime(should, context, entry.parameters)
-              .then(() => task.done());
-        });
-      });
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-bandpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-bandpass.html
deleted file mode 100644
index 6eb0ad1..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-bandpass.html
+++ /dev/null
@@ -1,95 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Test Biquad Tail-Time</title>
-    <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
-    <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audit.js"></script>
-    <script src="../resources/biquad-filters.js"></script>
-    <script src="test-tail-time.js"></script>
-  </head>
-
-  <body>
-    <script>
-      let audit = Audit.createTaskRunner();
-
-      let sampleRate = 16384;
-      let renderSeconds = 1;
-      let renderFrames = renderSeconds * sampleRate;
-
-      // For a bandpass filter:
-      //   b0 = alpha
-      //   b1 = 0
-      //   b2 = -alpha
-      //   a0 = 1 + alpha
-      //   a1 = -2*cos(w0)
-      //   a2 = 1 - alpha
-      //
-      // where alpha = sin(w0)/(2*Q) and w0 = 2*%pi*f0/Fs.
-      //
-      // Equivalently a1 = -2*cos(w0)/(1+alpha), a2 = (1-alpha)/(1+alpha).  The
-      // poles of this filter are at
-      //
-      //   (2*Q*cos(w0) +/- sqrt(1-4*Q^2)*sin(w0))/(2*Q + sin(w0))
-      //
-      // Thus, if 1-4*Q^2 < 0, the poles are complex.  For 1-4*Q^2 > 0, the
-      // poles are real and distinct.  For 1-4*Q^2 = 0, there are two identical
-      // real poles.
-
-      // Array of tests to run.  |descripton| is the task description for
-      // audit.define.  |parameters| is option for |testTailTime|.
-      let tests = [
-        {
-          descripton:
-              {label: 'bpf-complex-roots', description: 'complex roots'},
-          parameters: {
-            prefix: 'BPF complex roots',
-            filterOptions:
-                {type: 'bandpass', Q: 200, frequency: sampleRate / 4},
-            // The node estimated tail frame is 2039.55, which matches the
-            // true tail frame so output should be exactly 0
-            threshold: 0
-          }
-        },
-        {
-          descripton: {
-            label: 'bpf-real-distinct-roots',
-            description: 'real distinct roots'
-          },
-          parameters: {
-            prefix: 'BPF real distinct roots',
-            filterOptions:
-                {type: 'bandpass', Q: 0.001, frequency: sampleRate / 4},
-            // The node estimated tail frame is 2437, which matches the
-            // true tail frame so output should be exactly 0
-            threshold: 0
-          }
-        },
-        {
-          descripton:
-              {label: 'bpf-repeated-roots', description: 'repeated real root'},
-          parameters: {
-            prefix: 'BPF repeated roots',
-            filterOptions:
-                {type: 'bandpass', Q: 0.5, frequency: sampleRate / 8},
-            // The node estimated tail frame is 15.9, which matches the true
-            // tail frame so output should be exactly 0
-            threshold: 0
-          }
-        }
-      ];
-
-      // Define an appropriate task for each test.
-      tests.forEach(entry => {
-        audit.define(entry.descripton, (task, should) => {
-          let context = new OfflineAudioContext(1, renderFrames, sampleRate);
-          testTailTime(should, context, entry.parameters)
-              .then(() => task.done());
-        });
-      });
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-highpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-highpass.html
deleted file mode 100644
index 90bd15a3..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-highpass.html
+++ /dev/null
@@ -1,116 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Test Biquad Tail-Time</title>
-    <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
-    <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audit.js"></script>
-    <script src="../resources/biquad-filters.js"></script>
-    <script src="test-tail-time.js"></script>
-  </head>
-
-  <body>
-    <script>
-      let audit = Audit.createTaskRunner();
-
-      let sampleRate = 16384;
-      let renderSeconds = 1;
-      let renderFrames = renderSeconds * sampleRate;
-
-      // For a highpass filter:
-      //   b0 = (1+cos(w0))/2
-      //   b1 = -(1+cos(w0))
-      //   b2 = (1+cos(w0))/2
-      //   a0 = 1 + alpha
-      //   a1 = -2*cos(w0)
-      //   a2 = 1 - alpha
-      //
-      // where alpha = sin(w0)/(2*10^(Q/20)) and w0 = 2*%pi*f0/Fs.
-      //
-      // Equivalently a1 = -2*cos(w0)/(1+alpha), a2 = (1-alpha)/(1+alpha).  The
-      // poles of this filter are at
-      //
-      //   cos(w0)/(1+alpha) +/- sqrt(alpha^2-sin(w0)^2)/(1+alpha)
-      //
-      // But alpha^2-sin(w0)^2 = sin(w0)^2*(1/4/10^(Q/10) - 1).  Thus the poles
-      // are complex if 1/4/10^(Q/10) < 1; real distinct if 1/4/10^(Q/10) > 1;
-      // and repeated if 1/4/10^(Q/10) = 1.
-
-      // Array of tests to run.  |descripton| is the task description for
-      // audit.define.  |parameters| is option for |testTailTime|.
-      let tests = [
-        {
-          descripton:
-              {label: 'hpf-complex-roots', description: 'complex roots'},
-          parameters: {
-            prefix: 'HPF complex roots',
-            filterOptions: {type: 'highpass', Q: 40, frequency: sampleRate / 4},
-            // Node computed tail frame is 2079.4, which matches the actual tail
-            // frome so output should be exactly 0.
-            threshold: 0
-          }
-        },
-        {
-          descripton: {
-            label: 'hpf-real-distinct-roots',
-            description: 'real distinct roots'
-          },
-          parameters: {
-            prefix: 'HPF real distinct roots',
-            filterOptions:
-                {type: 'highpass', Q: -50, frequency: sampleRate / 8},
-            // With these filter parameters, the real tail time is 408, but
-            // the node overestimates it to be 2367.  Thus, the actual tail
-            // frames won't be exactly zero.
-            threshold: 1 / 32768
-          }
-        },
-        {
-          descripton:
-              {label: 'hpf-repeated-root', description: 'repeated real root'},
-          parameters: {
-            prefix: 'HPF repeated roots (approximately)',
-            // For a repeated root, we need 1/4/10^(Q/10) = 1, or Q =
-            // -10*log(4)/log(10). This isn't exactly representable as a float,
-            // so the roots might not actually be repeated.  In fact the roots
-            // are complex at 6.40239e-5*exp(i*1.570596).
-            filterOptions: {
-              type: 'highpass',
-              Q: -10 * Math.log10(4),
-              frequency: sampleRate / 4
-            },
-            // Node computed tail frame is 2.9, which matches the actual tail
-            // frome so output should be exactly 0.
-            threshold: 0
-          }
-        },
-        {
-          descripton: {label: 'hpf-real-roots-2', description: 'complex roots'},
-          parameters: {
-            prefix: 'HPF repeated roots 2',
-            // This tests an extreme case where approximate impulse response is
-            // h(n) = C*r^(n-1) and C < 1/32768.  Thus, the impulse response is
-            // always less than the response threshold of 1/32768.
-            filterOptions:
-                {type: 'highpass', Q: -100, frequency: sampleRate / 4},
-            // Node computed tail frame is 0, which matches the actual tail
-            // frame so output should be exactly 0.
-            threshold: 0
-          }
-        }
-      ];
-
-      // Define an appropriate task for each test.
-      tests.forEach(entry => {
-        audit.define(entry.descripton, (task, should) => {
-          let context = new OfflineAudioContext(1, renderFrames, sampleRate);
-          testTailTime(should, context, entry.parameters)
-              .then(() => task.done());
-        });
-      });
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-highshelf.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-highshelf.html
deleted file mode 100644
index 0b3a2ae..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-highshelf.html
+++ /dev/null
@@ -1,81 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Test Biquad Tail-Time</title>
-    <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
-    <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audit.js"></script>
-    <script src="../resources/biquad-filters.js"></script>
-    <script src="test-tail-time.js"></script>
-  </head>
-
-  <body>
-    <script>
-      let audit = Audit.createTaskRunner();
-
-      let sampleRate = 16384;
-      let renderSeconds = 1;
-      let renderFrames = renderSeconds * sampleRate;
-
-      // For a highshelf filter:
-      //   b0 = A*[(A+1)+(A−1)*cos(w0)+2*as*sqrt(A)]
-      //   b1 = 2*A*[(A-1)+(A+1)*cos(w0)]
-      //   b2 = A*[(A+1)+(A−1)*cos(w0)-2*as*sqrt(A)]
-      //   a0 = (A+1)-(A-1)*cos(w0)+2*as*sqrt(A)
-      //   a1 = -2*[(A-1)-(A+1)*cos(w0)]
-      //   a2 = (A+1)-(A-1)*cos(w0)-2*as*sqrt(A)
-      //
-      // where as = sin(w0)/sqrt(2), w0 = 2*%pi*f0/Fs, and A = 10^(G/40)
-      //
-      // The poles of this filter are
-      //
-      //   -a2/(2*a0) +/- sqrt(a1^2-4*a0*a2)/(2*a0).
-      //
-      // Thus, the poles depend on the sign of d = a1^2-4*a0*a2 =
-      // 16*A*(as^2-sin(w0)^2) = -8*A*sin(w0)^2.  Thus, the poles are always
-      // complex except if w0 = 0, in which case there is a repeated pole at 0.
-
-      // Array of tests to run.  |descripton| is the task description for
-      // audit.define.  |parameters| is option for |testTailTime|.
-      let tests = [
-        {
-          descripton:
-              {label: 'highshelf-complex-roots', description: 'complex roots'},
-          parameters: {
-            prefix: 'Highshelf complex roots',
-            filterOptions:
-                {type: 'highshelf', gain: 40, frequency: sampleRate / 8},
-            // Node computed tail frame is 18.6 frames, which matches the actual
-            // tail, so tail output should be exactly zero.
-            threshold: 0
-          }
-        },
-        {
-          descripton: {
-            label: 'highshelf-repeated-roots',
-            description: 'repeated real root'
-          },
-          parameters: {
-            prefix: 'Highshelf repeated roots',
-            filterOptions: {type: 'highshelf', gain: 40, frequency: 0},
-            // Node computed tail frame is 2 frames, which matches the actual
-            // tail, so tail output should be exactly zero.
-            threshold: 0
-          }
-        },
-      ];
-
-      // Define an appropriate task for each test.
-      tests.forEach(entry => {
-        audit.define(entry.descripton, (task, should) => {
-          let context = new OfflineAudioContext(1, renderFrames, sampleRate);
-          testTailTime(should, context, entry.parameters)
-              .then(() => task.done());
-        });
-      });
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-lowpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-lowpass.html
deleted file mode 100644
index dc042637..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-lowpass.html
+++ /dev/null
@@ -1,168 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Test Biquad Tail-Time</title>
-    <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
-    <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audit.js"></script>
-    <script src="../resources/biquad-filters.js"></script>
-    <script src="test-tail-time.js"></script>
-  </head>
-
-  <body>
-    <script>
-      let audit = Audit.createTaskRunner();
-
-      let sampleRate = 16384;
-      let renderSeconds = 1;
-
-      // For a lowpass filter:
-      //   b0 = (1-cos(w0))/2
-      //   b1 = 1-cos(w0)
-      //   b2 = (1-cos(w0))/2
-      //   a0 = 1 + alpha
-      //   a1 = -2*cos(w0)
-      //   a2 = 1 - alpha
-      //
-      // where alpha = sin(w0)/(2*10^(Q/20)) and w0 = 2*%pi*f0/Fs.
-      //
-      // Equivalently a1 = -2*cos(w0)/(1+alpha), a2 = (1-alpha)/(1+alpha).  The
-      // poles of this filter are at
-      //
-      //   cos(w0)/(1+alpha) +/- sqrt(alpha^2-sin(w0)^2)/(1+alpha)
-      //
-      // But alpha^2-sin(w0)^2 = sin(w0)^2*(1/4/10^(Q/10) - 1).  Thus the poles
-      // are complex if 1/4/10^(Q/10) < 1; real distinct if 1/4/10^(Q/10) > 1;
-      // and repeated if 1/4/10^(Q/10) = 1.
-
-      // Array of tests to run.  |descripton| is the task description for
-      // audit.define.  |parameters| is option for |testTailTime|.
-      let tests = [
-        {
-          descripton:
-              {label: 'lpf-complex-roots', description: 'complex roots'},
-          sampleRate: sampleRate,
-          renderDuration: renderSeconds,
-          parameters: {
-            prefix: 'LPF complex roots',
-            filterOptions: {type: 'lowpass', Q: 40, frequency: sampleRate / 4}
-          },
-          // Node computed tail frame is 2079.4 which matches the real tail, so
-          // tail output should be exactly 0.
-          threshold: 0,
-        },
-        {
-          descripton: {
-            label: 'lpf-real-distinct-roots',
-            description: 'real distinct roots'
-          },
-          sampleRate: sampleRate,
-          renderDuration: renderSeconds,
-          parameters: {
-            prefix: 'LPF real distinct roots',
-            filterOptions:
-                {type: 'lowpass', Q: -50, frequency: sampleRate / 8}
-          },
-          // Node computed tail frame is 1699 which matches the real tail, so
-          // tail output should be exactly 0.
-          threshold: 0,
-        },
-        {
-          descripton:
-              {label: 'lpf-repeated-root', description: 'repeated real root'},
-          sampleRate: sampleRate,
-          renderDuration: renderSeconds,
-          parameters: {
-            prefix: 'LPF repeated roots (approximately)',
-            // For a repeated root, we need 1/4/10^(Q/10) = 1, or Q =
-            // -10*log(4)/log(10). This isn't exactly representable as a float,
-            // we the roots might not actually be repeated.  In fact the roots
-            // are actually complex at 6.402396e-5*exp(i*1.570796).
-            filterOptions: {
-              type: 'lowpass',
-              Q: -10 * Math.log10(4),
-              frequency: sampleRate / 4
-            }
-          },
-          // Node computed tail frame is 2.9 which matches the real tail, so
-          // tail output should be exactly 0.
-          threshold: 0,
-        },
-        {
-          descripton: {label: 'lpf-real-roots-2', description: 'complex roots'},
-          sampleRate: sampleRate,
-          renderDuration: renderSeconds,
-          parameters: {
-            prefix: 'LPF repeated roots 2',
-            // This tests an extreme case where approximate impulse response is
-            // h(n) = C*r^(n-1) and C < 1/32768.  Thus, the impulse response is
-            // always less than the response threshold of 1/32768.
-            filterOptions:
-                {type: 'lowpass', Q: -100, frequency: sampleRate / 4}
-          },
-          // Node computed tail frame is 0 which matches the real tail, so
-          // tail output should be exactly 0.
-          threshold: 0,
-        },
-        {
-          descripton: 'huge tail',
-          // The BiquadFilter has an internal maximum tail of 30 sec so we want
-          // to render for at least 30 sec to test this.  Use the smallest
-          // sample rate we can to limit memory and CPU usage!
-          sampleRate: 3000,
-          renderDuration: 31,
-          parameters: {
-            prefix: 'LPF repeated roots (approximately)',
-            hugeTaileTime: true,
-            // For the record, for this lowpass filter, the computed tail time
-            // is approximately 2830.23 sec, with poles at
-            // 0.999998960442086*exp(i*0.209439510236777). This is very close to
-            // being marginally stable.
-            filterOptions: {
-              type: 'lowpass',
-              Q: 100,
-              frequency: 100,
-            },
-            // Node computed tail frame is 8.49069e6 which is clamped to 30 sec
-            // so tail output should be exactly 0 after 30 sec.
-            threshold: 0,
-          },
-        },
-        {
-          descripton: 'ginormous tail',
-          // Or this lowpass filter, the complex poles are actually computed to
-          // be on the unit circle so the tail infinite.  This just tests that
-          // nothing bad happens in computing the tail time. Thus, any small
-          // sample rate and short duration for the test; the results aren't
-          // really interesting. (But they must pass, of course!)
-          sampleRate: 3000,
-          renderDuration: 0.25,
-          parameters: {
-            prefix: 'LPF repeated roots (approximately)',
-            filterOptions: {
-              type: 'lowpass',
-              Q: 500,
-              frequency: 100,
-            },
-          },
-          // Node computed tail frame is 90000 which matches the real tail, so
-          // tail output should be exactly 0.
-          threshold: 0,
-        }
-      ]
-
-      // Define an appropriate task for each test.
-      tests.forEach(entry => {
-        audit.define(entry.descripton, (task, should) => {
-          let context = new OfflineAudioContext(
-              1, entry.renderDuration * entry.sampleRate, entry.sampleRate);
-          testTailTime(should, context, entry.parameters)
-              .then(() => task.done());
-        });
-      });
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-lowshelf.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-lowshelf.html
deleted file mode 100644
index b8af1f3..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-lowshelf.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Test Biquad Tail-Time</title>
-    <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
-    <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audit.js"></script>
-    <script src="../resources/biquad-filters.js"></script>
-    <script src="test-tail-time.js"></script>
-  </head>
-
-  <body>
-    <script>
-      let audit = Audit.createTaskRunner();
-
-      let sampleRate = 16384;
-      let renderSeconds = 1;
-      let renderFrames = renderSeconds * sampleRate;
-      let renderQuantumFrames = 128;
-
-      // For a lowshelf filter:
-      //   b0 = A*[(A+1)−(A−1)*cos(w0)+2*as*sqrt(A)]
-      //   b1 = 2*A*[(A+1)-(A-1)*cos(w0)]
-      //   b2 = A*[(A+1)−(A−1)*cos(w0)-2*as*sqrt(A)]
-      //   a0 = (A+1)+(A-1)*cos(w0)+2*as*sqrt(A)
-      //   a1 = -2*[(A-1)+(A+1)*cos(w0)]
-      //   a2 = (A+1)+(A-1)*cos(w0)-2*as*sqrt(A)
-      //
-      // where as = sin(w0)/sqrt(2), w0 = 2*%pi*f0/Fs, and A = 10^(G/40)
-      //
-      // The poles of this filter are
-      //
-      //   -a2/(2*a0) +/- sqrt(a1^2-4*a0*a2)/(2*a0).
-      //
-      // Thus, the poles depend on the sign of d = a1^2-4*a0*a2 =
-      // 16*A*(as^2-sin(w0)^2) = -8*A*sin(w0)^2.  Thus, the poles are always
-      // complex except if w0 = 0, in which case there is a repeated pole at 0.
-
-      // Array of tests to run.  |descripton| is the task description for
-      // audit.define.  |parameters| is option for |testTailTime|.
-      let tests = [
-        {
-          descripton:
-              {label: 'lowshelf-complex-roots', description: 'complex roots'},
-          parameters: {
-            prefix: 'Lowshelf complex roots',
-            filterOptions:
-                {type: 'lowshelf', gain: 40, frequency: sampleRate / 8},
-            // Node computed tail frame is 75.5 frames, which matches the actual
-            // tail, so tail output should be exactly zero.
-            threshold: 0
-          },
-        },
-        {
-          descripton: {
-            label: 'lowshelf-repeated-roots',
-            description: 'repeated real root'
-          },
-          parameters: {
-            prefix: 'Lowshelf repeated roots',
-            filterOptions:
-                {type: 'lowshelf', Q: 1 / 20, gain: 40, frequency: 0},
-            // Node computed tail frame is 2 frames, which matches the actual
-            // tail, so tail output should be exactly zero.
-            threshold: 0
-          },
-        },
-      ];
-
-      // Define an appropriate task for each test.
-      tests.forEach(entry => {
-        audit.define(entry.descripton, (task, should) => {
-          let context = new OfflineAudioContext(1, renderFrames, sampleRate);
-          testTailTime(should, context, entry.parameters)
-              .then(() => task.done());
-        });
-      });
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-notch.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-notch.html
deleted file mode 100644
index 0b38d4bc..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-notch.html
+++ /dev/null
@@ -1,98 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Test Biquad Tail-Time</title>
-    <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
-    <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audit.js"></script>
-    <script src="../resources/biquad-filters.js"></script>
-    <script src="test-tail-time.js"></script>
-  </head>
-
-  <body>
-    <script>
-      let audit = Audit.createTaskRunner();
-
-      let sampleRate = 16384;
-      let renderSeconds = 1;
-      let renderFrames = renderSeconds * sampleRate;
-      let renderQuantumFrames = 128;
-
-      // For a notch filter:
-      //   b0 = 1
-      //   b1 = -2*cos(w0)
-      //   b2 = 1
-      //   a0 = 1 + alpha
-      //   a1 = -2*cos(w0)
-      //   a2 = 1 - alpha
-      //
-      // where alpha = sin(w0)/(2*Q) and w0 = 2*%pi*f0/Fs.
-      //
-      // Equivalently a1 = -2*cos(w0)/(1+alpha), a2 = (1-alpha)/(1+alpha).  The
-      // poles of this filter are at
-      //
-      //   (2*Q*cos(w0) +/- sqrt(1-4*Q^2)*sin(w0))/(2*Q + sin(w0))
-      //
-      // Thus, if 1-4*Q^2 < 0, the poles are complex.  For 1-4*Q^2 > 0, the
-      // poles are real and distinct.  For 1-4*Q^2 = 0, there are two identical
-      // real poles.
-
-      // Array of tests to run.  |descripton| is the task description for
-      // audit.define.  |parameters| is option for |testTailTime|.
-      let tests = [
-        {
-          descripton:
-              {label: 'notch-complex-roots', description: 'complex roots'},
-          parameters: {
-            prefix: 'Notch complex roots',
-            filterOptions: {type: 'notch', Q: 200, frequency: sampleRate / 4},
-            // Node computed tail frame is 2039.5 frames, which matches the
-            // actual tail, so tail output should be exactly zero.
-            threshold: 0
-          },
-        },
-        {
-          descripton: {
-            label: 'notch-real-distinct-roots',
-            description: 'real distinct roots'
-          },
-          parameters: {
-            prefix: 'Notch real distinct roots',
-            filterOptions: {type: 'notch', Q: 0.001, frequency: sampleRate / 4},
-            // Node computed tail frame is 2437 frames, which matches the actual
-            // tail, so tail output should be exactly zero.
-            threshold: 0
-          },
-        },
-        {
-          descripton: {
-            label: 'notch-repeated-roots',
-            description: 'repeated real root'
-          },
-          parameters: {
-            prefix: 'Notch repeated roots',
-            // Note that while the roots are mathematically repeated,
-            // numerical roundoff in compute the filter coefficients causes
-            // the resulting filter to have roots at 0 and 6.123e-17.
-            filterOptions: {type: 'notch', Q: 0.5, frequency: sampleRate / 4},
-            // Node computed tail frame is 2 frames, which matches the actual
-            // tail, so tail output should be exactly zero.
-            threshold: 0
-          }
-        },
-      ];
-
-      // Define an appropriate task for each test.
-      tests.forEach(entry => {
-        audit.define(entry.descripton, (task, should) => {
-          let context = new OfflineAudioContext(1, renderFrames, sampleRate);
-          testTailTime(should, context, entry.parameters)
-              .then(() => task.done());
-        });
-      });
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-peaking.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-peaking.html
deleted file mode 100644
index 973d8361..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/tail-time-peaking.html
+++ /dev/null
@@ -1,115 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Test Biquad Tail-Time</title>
-    <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
-    <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audit.js"></script>
-    <script src="../resources/biquad-filters.js"></script>
-    <script src="test-tail-time.js"></script>
-  </head>
-
-  <body>
-    <script>
-      let audit = Audit.createTaskRunner();
-
-      let sampleRate = 16384;
-      let renderSeconds = 1;
-      let renderFrames = renderSeconds * sampleRate;
-
-      // For a peaking filter:
-      //   b0 = 1 - alpha*A
-      //   b1 = -2*cos(w0)
-      //   b2 = 1 + alpha*A
-      //   a0 = 1 + alpha/A
-      //   a1 = -2*cos(w0)
-      //   a2 = 1 - alpha/A
-      //
-      // where alpha = sin(w0)/(2*Q), w0 = 2*%pi*f0/Fs, and A = 10^(G/40)
-      //
-      // Equivalently a1 = -2*cos(w0)/(1+alpha/A), a2 = (1-alpha/A)/(1+alpha/A).
-      // The poles of this filter are at
-      //
-      //   A*cos(w0)/(A + alpha) +/- sqrt(alpha^2-A^2*sin(w0)^2)/(A + alpha)
-      //
-      // But alpha^2-A^2*sin(w0)^2 = sin(w0)^2*(1/4/Q^2-1).
-      // Thus, the poles are complex if 1/(4*Q^2) < A^2; real and distinct if
-      // 1/(4*Q^2)>A^2; and repeated if 1/(4*Q^2) = A^2 or w0 = 0.
-
-      // Array of tests to run.  |descripton| is the task description for
-      // audit.define.  |parameters| is option for |testTailTime|.
-      let tests = [
-        {
-          descripton:
-              {label: 'peaking-complex-roots', description: 'complex roots'},
-          parameters: {
-            prefix: 'Peaking complex roots',
-            // A gain of 40 gives A = 10.
-            filterOptions:
-                {type: 'peaking', Q: 10, gain: 40, frequency: sampleRate / 4},
-            // Node computed tail frame is 2077.4 frames, which matches the
-            // actual tail, so tail output should be exactly zero.
-            threshold: 0
-          }
-        },
-        {
-          descripton: {
-            label: 'peaking-real-distinct-roots',
-            description: 'real distinct roots'
-          },
-          parameters: {
-            prefix: 'Peaking real distinct roots',
-            filterOptions: {
-              type: 'peaking',
-              Q: 0.001,
-              gain: 40,
-              frequency: sampleRate / 4
-            },
-            // Node computed tail frame is 588 frames, which matches the actual
-            // tail, so tail output should be exactly zero.
-            threshold: 0
-          }
-        },
-        {
-          descripton: {
-            label: 'peaking-repeated-roots',
-            description: 'repeated real root'
-          },
-          parameters: {
-            prefix: 'Peaking repeated roots',
-            filterOptions:
-                {type: 'peaking', Q: 1 / 2, gain: 0, frequency: sampleRate / 8},
-            // Node computed tail frame is 0 frames, which matches the actual
-            // tail, so tail output should be exactly zero.
-            threshold: 0
-
-          }
-        },
-        {
-          descripton: {
-            label: 'peaking-repeated-roots 2',
-            description: 'repeated real root'
-          },
-          parameters: {
-            prefix: 'Peaking repeated roots 2',
-            filterOptions: {type: 'peaking', Q: 1, gain: 40, frequency: 0},
-            // Node computed tail frame is 1 frames, which matches the actual
-            // tail, so tail output should be exactly zero.
-            threshold: 0
-          }
-        }
-      ];
-
-      // Define an appropriate task for each test.
-      tests.forEach(entry => {
-        audit.define(entry.descripton, (task, should) => {
-          let context = new OfflineAudioContext(1, renderFrames, sampleRate);
-          testTailTime(should, context, entry.parameters).then(() => task.done());
-        });
-      });
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/test-tail-time.js b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/test-tail-time.js
deleted file mode 100644
index 94f1449..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/test-tail-time.js
+++ /dev/null
@@ -1,90 +0,0 @@
-function testTailTime(should, context, options) {
-  let src = new ConstantSourceNode(context, {offset: 1});
-  let f = new BiquadFilterNode(context, options.filterOptions);
-
-  src.connect(f).connect(context.destination);
-  src.start();
-  src.stop(1 / context.sampleRate);
-
-  let expectedTailFrame = computeTailFrame(f);
-
-  // The internal Biquad time computation limits he tail time to a
-  // maximum of 30 sec. We need to limit the computed tail frame to
-  // that limit as well.
-  expectedTailFrame = Math.min(expectedTailFrame, 30 * context.sampleRate);
-
-  return context.startRendering().then(renderedBuffer => {
-    let s = renderedBuffer.getChannelData(0);
-    let prefix = options.prefix + ': Biquad(' +
-        JSON.stringify(options.filterOptions) + ')';
-
-    // Round actual tail frame to a render boundary
-    let quantumIndex = Math.floor(expectedTailFrame / RENDER_QUANTUM_FRAMES);
-    let expectedTailBoundary = RENDER_QUANTUM_FRAMES * quantumIndex;
-
-    // Find the actual tail frame.  That is, the last point where the
-    // output is not zero.
-    let actualTailFrame;
-
-    for (actualTailFrame = s.length; actualTailFrame > 0; --actualTailFrame) {
-      if (Math.abs(s[actualTailFrame - 1]) > 0)
-        break;
-    }
-
-    should(actualTailFrame, `${prefix}: Actual Tail Frame ${actualTailFrame}`)
-        .beGreaterThanOrEqualTo(expectedTailFrame);
-
-    // Verify each render quanta is not identically zero up to the
-    // boundary.
-    for (let k = 0; k <= quantumIndex; ++k) {
-      let firstFrame = RENDER_QUANTUM_FRAMES * k;
-      let lastFrame = firstFrame + RENDER_QUANTUM_FRAMES - 1;
-      should(
-          s.slice(firstFrame, lastFrame + 1),
-          `${prefix}: output[${firstFrame}:${lastFrame}]`)
-          .notBeConstantValueOf(0);
-    }
-    // The frames after the tail should be zero.  Because the
-    // implementation uses approximations to simplify the
-    // computations, the nodes tail time may be greater than the real
-    // impulse response tail.  Thus, we just verify that the output
-    // over the tail is less than the tail threshold value.
-    let zero = new Float32Array(s.length);
-    should(
-        s.slice(expectedTailBoundary + RENDER_QUANTUM_FRAMES + 256),
-        prefix + ': output[' +
-            (expectedTailBoundary + RENDER_QUANTUM_FRAMES + 256) + ':]')
-        .beCloseToArray(
-            zero.slice(expectedTailBoundary + RENDER_QUANTUM_FRAMES + 256),
-            {absoluteThreshold: options.threshold || 0});
-  })
-}
-
-function computeTailFrame(filterNode) {
-  // Compute the impuluse response for the filter |filterNode| by
-  // filtering the impulse directly ourself.
-  let coef = createFilter(
-      filterNode.type,
-      filterNode.frequency.value / filterNode.context.sampleRate * 2,
-      filterNode.Q.value, filterNode.gain.value);
-
-  let impulse = new Float32Array(filterNode.context.length);
-  impulse[0] = 1;
-
-  let filtered = filterData(coef, impulse, impulse.length);
-
-  // Compute the magnitude and find out where the imuplse is small enough.
-  let tailFrame = 0;
-  if (Math.abs(filtered[filtered.length - 1]) >= 1 / 32768) {
-    tailFrame = filtered.length - 1;
-  } else {
-    for (let k = filtered.length - 1; k >= 0; --k) {
-      if (Math.abs(filtered[k]) >= 1 / 32768) {
-        tailFrame = k + 1;
-        break;
-      }
-    }
-  }
-
-  return tailFrame;
-}
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/audit-util.js b/third_party/WebKit/LayoutTests/webaudio/resources/audit-util.js
index 1e39c87..671bcf1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/audit-util.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/audit-util.js
@@ -8,8 +8,6 @@
  *                test.
  */
 
-// How many frames in a WebAudio render quantum.
-let RENDER_QUANTUM_FRAMES = 128;
 
 function writeString(s, a, offset) {
   for (let i = 0; i < s.length; ++i) {
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/group.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/group.tmpl
index 56d3f9d..956b974 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/group.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/group.tmpl
@@ -1,7 +1,7 @@
 {% from 'fields/field.tmpl' import encode, declare_storage, compare %}
 {% from 'macros.tmpl' import print_if %}
 {% macro define_field_group_class(group): -%}
-class {{group.type_name}} : public RefCountedCopyable<{{group.type_name}}> {
+class {{group.type_name}} : public RefCounted<{{group.type_name}}> {
  public:
   static PassRefPtr<{{group.type_name}}> Create() {
     return AdoptRef(new {{group.type_name}});
@@ -30,6 +30,10 @@
   {% endfor %}
   {}
 
-  {{group.type_name}}(const {{group.type_name}}&) = default;
+  {{group.type_name}}(const {{group.type_name}}& other) :
+  {% for field in group.fields %}
+      {{field.name}}(other.{{field.name}}){{print_if(not loop.last, ',')}}
+  {% endfor %}
+  {}
 };
 {%- endmacro %}
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 2b586df..b4610d2f 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1338,6 +1338,7 @@
     "layout/ng/inline/ng_inline_items_builder_test.cc",
     "layout/ng/inline/ng_inline_layout_algorithm_test.cc",
     "layout/ng/inline/ng_inline_node_test.cc",
+    "layout/ng/inline/ng_line_breaker_test.cc",
     "layout/ng/ng_absolute_utils_test.cc",
     "layout/ng/ng_base_layout_algorithm_test.cc",
     "layout/ng/ng_base_layout_algorithm_test.h",
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
index 2b0f5a4..f2ca431 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -874,49 +874,6 @@
 }
 
 template <>
-inline CSSIdentifierValue::CSSIdentifierValue(LineBreak e)
-    : CSSValue(kIdentifierClass) {
-  switch (e) {
-    case LineBreak::kAuto:
-      value_id_ = CSSValueAuto;
-      break;
-    case LineBreak::kLoose:
-      value_id_ = CSSValueLoose;
-      break;
-    case LineBreak::kNormal:
-      value_id_ = CSSValueNormal;
-      break;
-    case LineBreak::kStrict:
-      value_id_ = CSSValueStrict;
-      break;
-    case LineBreak::kAfterWhiteSpace:
-      value_id_ = CSSValueAfterWhiteSpace;
-      break;
-  }
-}
-
-template <>
-inline LineBreak CSSIdentifierValue::ConvertTo() const {
-  switch (value_id_) {
-    case CSSValueAuto:
-      return LineBreak::kAuto;
-    case CSSValueLoose:
-      return LineBreak::kLoose;
-    case CSSValueNormal:
-      return LineBreak::kNormal;
-    case CSSValueStrict:
-      return LineBreak::kStrict;
-    case CSSValueAfterWhiteSpace:
-      return LineBreak::kAfterWhiteSpace;
-    default:
-      break;
-  }
-
-  NOTREACHED();
-  return LineBreak::kAuto;
-}
-
-template <>
 inline CSSIdentifierValue::CSSIdentifierValue(EMarginCollapse e)
     : CSSValue(kIdentifierClass) {
   switch (e) {
@@ -1146,10 +1103,10 @@
 inline CSSIdentifierValue::CSSIdentifierValue(TextUnderlinePosition e)
     : CSSValue(kIdentifierClass) {
   switch (e) {
-    case kTextUnderlinePositionAuto:
+    case TextUnderlinePosition::kAuto:
       value_id_ = CSSValueAuto;
       break;
-    case kTextUnderlinePositionUnder:
+    case TextUnderlinePosition::kUnder:
       value_id_ = CSSValueUnder;
       break;
   }
@@ -1161,9 +1118,9 @@
 inline TextUnderlinePosition CSSIdentifierValue::ConvertTo() const {
   switch (value_id_) {
     case CSSValueAuto:
-      return kTextUnderlinePositionAuto;
+      return TextUnderlinePosition::kAuto;
     case CSSValueUnder:
-      return kTextUnderlinePositionUnder;
+      return TextUnderlinePosition::kUnder;
     default:
       break;
   }
@@ -1171,7 +1128,7 @@
   // FIXME: Implement support for 'under left' and 'under right' values.
 
   NOTREACHED();
-  return kTextUnderlinePositionAuto;
+  return TextUnderlinePosition::kAuto;
 }
 
 template <>
@@ -1387,34 +1344,6 @@
 }
 
 template <>
-inline CSSIdentifierValue::CSSIdentifierValue(RubyPosition position)
-    : CSSValue(kIdentifierClass) {
-  switch (position) {
-    case RubyPosition::kBefore:
-      value_id_ = CSSValueBefore;
-      break;
-    case RubyPosition::kAfter:
-      value_id_ = CSSValueAfter;
-      break;
-  }
-}
-
-template <>
-inline RubyPosition CSSIdentifierValue::ConvertTo() const {
-  switch (value_id_) {
-    case CSSValueBefore:
-      return RubyPosition::kBefore;
-    case CSSValueAfter:
-      return RubyPosition::kAfter;
-    default:
-      break;
-  }
-
-  NOTREACHED();
-  return RubyPosition::kBefore;
-}
-
-template <>
 inline CSSIdentifierValue::CSSIdentifierValue(TextEmphasisPosition position)
     : CSSValue(kIdentifierClass) {
   switch (position) {
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 55217e2..dbc65d5 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -2148,7 +2148,7 @@
       runtime_flag: "CSS3TextDecorations",
       field_template: "storage_only",
       type_name: "TextUnderlinePosition",
-      default_value: "kTextUnderlinePositionAuto",
+      default_value: "TextUnderlinePosition::kAuto",
       field_size: 1,
       field_group: "rare-inherited",
     },
@@ -2435,10 +2435,10 @@
     {
       name: "-webkit-line-break",
       inherited: true,
-      field_template: "storage_only",
+      field_template: "keyword",
       type_name: "LineBreak",
-      default_value: "LineBreak::kAuto",
-      field_size: 3,
+      keywords: ["auto", "loose", "normal", "strict", "after-white-space"],
+      default_value: "auto",
       field_group: "rare-inherited",
     },
     {
@@ -2571,10 +2571,10 @@
     {
       name: "-webkit-ruby-position",
       inherited: true,
-      field_template: "storage_only",
+      field_template: "keyword",
       type_name: "RubyPosition",
-      default_value: "RubyPosition::kBefore",
-      field_size: 1,
+      keywords: ["before", "after"],
+      default_value: "before",
       field_group: "rare-inherited",
     },
     {
@@ -2610,7 +2610,11 @@
     {
       name: "-webkit-text-emphasis-position",
       inherited: true,
+      field_template: "keyword",
       type_name: "TextEmphasisPosition",
+      default_value: "over",
+      keywords: ["over", "under"],
+      field_group: "rare-inherited",
     },
     {
       name: "-webkit-text-emphasis-style",
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
index 8038a50..a68b70f 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
+++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -429,10 +429,10 @@
     {
       name: "TextEmphasisFill",
       inherited: true,
-      field_template: "storage_only",
+      field_template: "keyword",
       type_name: "TextEmphasisFill",
-      default_value: "TextEmphasisFill::kFilled",
-      field_size: 1,
+      default_value: "filled",
+      keywords: ["filled", "open"],
       field_group: "rare-inherited",
     },
     {
@@ -445,15 +445,6 @@
       field_group: "rare-inherited",
     },
     {
-      name: "TextEmphasisPosition",
-      inherited: true,
-      field_template: "storage_only",
-      type_name: "TextEmphasisPosition",
-      default_value: "TextEmphasisPosition::kOver",
-      field_size: 1,
-      field_group: "rare-inherited",
-    },
-    {
       name: "TextIndentLine",
       inherited: true,
       field_template: "keyword",
@@ -538,7 +529,7 @@
     {
       name: "TextEmphasisCustomMark",
       inherited: true,
-      field_template: "storage_only",
+      field_template: "external",
       type_name: "AtomicString",
       include_paths: ["platform/wtf/text/AtomicString.h"],
       default_value: "AtomicString()",
diff --git a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
index 67295cfce..a5caa674 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
@@ -762,13 +762,15 @@
   // ::cue, ::shadow), we need a universal selector to set the combinator
   // (relation) on in the cases where there are no simple selectors preceding
   // the pseudo element.
-  bool explicit_for_host =
-      compound_selector->IsHostPseudoSelector() && !element_name.IsNull();
-  if (tag != AnyQName() || explicit_for_host ||
-      compound_selector->NeedsImplicitShadowCombinatorForMatching())
+  bool is_host_pseudo = compound_selector->IsHostPseudoSelector();
+  if (is_host_pseudo && element_name.IsNull() && namespace_prefix.IsNull())
+    return;
+  if (tag != AnyQName() || is_host_pseudo ||
+      compound_selector->NeedsImplicitShadowCombinatorForMatching()) {
     compound_selector->PrependTagSelector(
         tag, determined_prefix == g_null_atom &&
-                 determined_element_name == g_star_atom && !explicit_for_host);
+                 determined_element_name == g_star_atom && !is_host_pseudo);
+  }
 }
 
 std::unique_ptr<CSSParserSelector>
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index ca84712..4590346 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -1089,10 +1089,8 @@
   if (!CanEdit())
     return false;
 
-  VisiblePosition caret = GetFrame()
-                              .Selection()
-                              .ComputeVisibleSelectionInDOMTreeDeprecated()
-                              .VisibleStart();
+  VisiblePosition caret =
+      GetFrame().Selection().ComputeVisibleSelectionInDOMTree().VisibleStart();
   bool align_to_edge = IsEndOfEditableOrNonEditableContent(caret);
   DCHECK(GetFrame().GetDocument());
   if (!TypingCommand::InsertLineBreak(*GetFrame().GetDocument()))
@@ -1111,10 +1109,8 @@
   if (!CanEditRichly())
     return InsertLineBreak();
 
-  VisiblePosition caret = GetFrame()
-                              .Selection()
-                              .ComputeVisibleSelectionInDOMTreeDeprecated()
-                              .VisibleStart();
+  VisiblePosition caret =
+      GetFrame().Selection().ComputeVisibleSelectionInDOMTree().VisibleStart();
   bool align_to_edge = IsEndOfEditableOrNonEditableContent(caret);
   DCHECK(GetFrame().GetDocument());
   EditingState editing_state;
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index 91854ed..51ca7fe 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -170,13 +170,9 @@
   DCHECK(!start.GetDocument()->View() ||
          !start.GetDocument()->View()->NeedsLayout());
   DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate());
-
-  if (start.CompareTo(end) > 0) {
-    Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(),
-               start.ComputeContainerNode(),
-               start.ComputeOffsetInContainerNode());
-    return;
-  }
+  // To avoid renderer hang, we use |CHECK_LE()| to catch the bad callers
+  // in release build.
+  CHECK_LE(start, end);
   Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(),
              end.ComputeContainerNode(), end.ComputeOffsetInContainerNode());
 }
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
index b3b2c60..1accf9a 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
@@ -169,12 +169,6 @@
                                                     thick,
                                                     background_color)) {}
 
-DocumentMarker::DocumentMarker(const DocumentMarker& marker)
-    : type_(marker.GetType()),
-      start_offset_(marker.StartOffset()),
-      end_offset_(marker.EndOffset()),
-      details_(marker.Details()) {}
-
 Optional<DocumentMarker::MarkerOffsets>
 DocumentMarker::ComputeOffsetsAfterShift(unsigned offset,
                                          unsigned old_length,
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
index 6d76290..2a1dd7d 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
@@ -142,8 +142,6 @@
                  bool thick,
                  Color background_color);
 
-  DocumentMarker(const DocumentMarker&);
-
   MarkerType GetType() const { return type_; }
   unsigned StartOffset() const { return start_offset_; }
   unsigned EndOffset() const { return end_offset_; }
@@ -183,6 +181,8 @@
   unsigned start_offset_;
   unsigned end_offset_;
   Member<DocumentMarkerDetails> details_;
+
+  DISALLOW_COPY_AND_ASSIGN(DocumentMarker);
 };
 
 using DocumentMarkerVector = HeapVector<Member<DocumentMarker>>;
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp
index c37a4fe5..b629b20b 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp
@@ -66,7 +66,7 @@
         return start_offset < marker->EndOffset();
       });
   for (MarkerList::iterator i = start_pos; i != list->end();) {
-    DocumentMarker marker(*i->Get());
+    const DocumentMarker& marker = *i->Get();
 
     // markers are returned in order, so stop if we are now past the specified
     // range
diff --git a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
index c6c87b1..559f1a79 100644
--- a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
+++ b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
@@ -70,9 +70,6 @@
   bool IsValid() const { return state_ != State::kInvalid; }
 
  private:
-  explicit TextMatchMarker(const DocumentMarker& marker)
-      : DocumentMarker(marker), state_(State::kInvalid) {}
-
   LayoutRect rendered_rect_;
   State state_;
 };
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item.cc
index 61a5e31..6db6e70 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item.cc
@@ -4,6 +4,7 @@
 
 #include "core/layout/ng/inline/ng_inline_item.h"
 
+#include "core/layout/LayoutInline.h"
 #include "core/layout/LayoutObject.h"
 #include "platform/fonts/CharacterRange.h"
 #include "platform/fonts/shaping/ShapeResultBuffer.h"
@@ -123,6 +124,18 @@
   shape_result_->FallbackFonts(fallback_fonts);
 }
 
+bool NGInlineItem::HasStartEdge() const {
+  DCHECK(Type() == kOpenTag || Type() == kCloseTag);
+  // TODO(kojii): Should use break token when NG has its own tree building.
+  return !GetLayoutObject()->IsInlineElementContinuation();
+}
+
+bool NGInlineItem::HasEndEdge() const {
+  DCHECK(Type() == kOpenTag || Type() == kCloseTag);
+  // TODO(kojii): Should use break token when NG has its own tree building.
+  return !ToLayoutInline(GetLayoutObject())->Continuation();
+}
+
 NGInlineItemRange::NGInlineItemRange(Vector<NGInlineItem>* items,
                                      unsigned start_index,
                                      unsigned end_index)
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item.h
index 1d14bbfc..49bcd73 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item.h
@@ -93,6 +93,9 @@
                         unsigned start,
                         unsigned end) const;
 
+  bool HasStartEdge() const;
+  bool HasEndEdge() const;
+
   static void Split(Vector<NGInlineItem>&, unsigned index, unsigned offset);
   static unsigned SetBidiLevel(Vector<NGInlineItem>&,
                                unsigned index,
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.cc
index a4a467e..3c315cb33 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.cc
@@ -11,6 +11,10 @@
 NGInlineItemResult::NGInlineItemResult(unsigned index,
                                        unsigned start,
                                        unsigned end)
-    : item_index(index), start_offset(start), end_offset(end) {}
+    : item_index(index),
+      start_offset(start),
+      end_offset(end),
+      no_break_opportunities_inside(false),
+      prohibit_break_after(false) {}
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
index 0e52770..12dd1b6 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
@@ -42,6 +42,14 @@
   // NGBoxStrut for atomic inline items.
   NGBoxStrut margins;
 
+  // Inside of this is not breakable.
+  // Used only during line breaking.
+  unsigned no_break_opportunities_inside : 1;
+
+  // Lines must not break after this.
+  // Used only during line breaking.
+  unsigned prohibit_break_after : 1;
+
   NGInlineItemResult();
   NGInlineItemResult(unsigned index, unsigned start, unsigned end);
 };
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index fb30678..1a426a9 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -271,8 +271,10 @@
                                  borders.BlockSum() + paddings.BlockSum());
       }
     } else if (item.Type() == NGInlineItem::kCloseTag) {
+      position += item_result.inline_size;
       box = box_states_.OnCloseTag(item, &line_box, box, baseline_type_,
                                    position);
+      continue;
     } else if (item.Type() == NGInlineItem::kAtomicInline) {
       box = PlaceAtomicInline(item, &item_result, position, &line_box,
                               &text_builder);
@@ -303,8 +305,7 @@
 
   // The baselines are always placed at pixel boundaries. Not doing so results
   // in incorrect layout of text decorations, most notably underlines.
-  LayoutUnit baseline = content_size_ + line_box.Metrics().ascent +
-                        border_and_padding_.block_start;
+  LayoutUnit baseline = content_size_ + line_box.Metrics().ascent;
   baseline = LayoutUnit(baseline.Round());
 
   // Check if the line fits into the constraint space in block direction.
@@ -429,6 +430,10 @@
 }
 
 RefPtr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
+  // If we are resuming from a break token our start border and padding is
+  // within a previous fragment.
+  content_size_ = BreakToken() ? LayoutUnit() : border_and_padding_.block_start;
+
   NGLineBreaker line_breaker(Node(), constraint_space_, BreakToken());
   NGInlineItemResults item_results;
   while (true) {
@@ -440,7 +445,7 @@
   }
 
   // TODO(crbug.com/716930): Avoid calculating border/padding twice.
-  if (!Node()->Items().IsEmpty())
+  if (!BreakToken())
     content_size_ -= border_and_padding_.block_start;
 
   // TODO(kojii): Check if the line box width should be content or available.
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.h
index 4524c5d8..6cb3e091 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.h
@@ -93,6 +93,8 @@
   LayoutObject* start_inline_;
   LayoutNGBlockFlow* block_;
   Member<NGLayoutInputNode> next_sibling_;
+
+  friend class NGLineBreakerTest;
 };
 
 inline void NGInlineNode::AssertOffset(unsigned index, unsigned offset) const {
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
index d464a03..4656455 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
@@ -17,7 +17,6 @@
 #include "core/style/ComputedStyle.h"
 #include "platform/fonts/shaping/HarfBuzzShaper.h"
 #include "platform/fonts/shaping/ShapingLineBreaker.h"
-#include "platform/text/TextBreakIterator.h"
 
 namespace blink {
 
@@ -28,19 +27,7 @@
 
 #if defined(MOCK_SHAPE_LINE)
 // The mock for ShapingLineBreaker::ShapeLine().
-// Given the design of ShapingLineBreaker, expected semantics are:
-// - The returned offset is always > item.StartOffset().
-// - offset < item.EndOffset():
-//   - width <= available_width: the break opportunity to fit is found.
-//   - width > available_width: the first break opportunity did not fit.
-// - offset == item.EndOffset():
-//   - width <= available_width: the break opportunity at the end of the item
-//     fits.
-//   - width > available_width: the first break opportunity is at the end of
-//     the item and it does not fit.
-// - offset > item.EndOffset():, the first break opportunity is beyond the
-//   end of item and thus cannot measure. In this case, inline_size shows the
-//   width until the end of the item. It may fit or may not.
+// See BreakText() for the expected semantics.
 std::pair<unsigned, LayoutUnit> ShapeLineMock(
     const NGInlineItem& item,
     unsigned offset,
@@ -67,23 +54,16 @@
 }
 #endif
 
-LineBreakType GetLineBreakType(const ComputedStyle& style) {
-  if (style.AutoWrap()) {
-    if (style.WordBreak() == EWordBreak::kBreakAll ||
-        style.WordBreak() == EWordBreak::kBreakWord)
-      return LineBreakType::kBreakAll;
-    if (style.WordBreak() == EWordBreak::kKeepAll)
-      return LineBreakType::kKeepAll;
-  }
-  return LineBreakType::kNormal;
-}
-
 }  // namespace
 
 NGLineBreaker::NGLineBreaker(NGInlineNode* node,
                              const NGConstraintSpace* space,
                              NGInlineBreakToken* break_token)
-    : node_(node), constraint_space_(space), item_index_(0), offset_(0) {
+    : node_(node),
+      constraint_space_(space),
+      item_index_(0),
+      offset_(0),
+      break_iterator_(node->Text()) {
   if (break_token) {
     item_index_ = break_token->ItemIndex();
     offset_ = break_token->TextOffset();
@@ -106,130 +86,169 @@
                               NGInlineLayoutAlgorithm* algorithm) {
   DCHECK(item_results->IsEmpty());
   const Vector<NGInlineItem>& items = node_->Items();
-  const String& text = node_->Text();
   const ComputedStyle& style = node_->Style();
-  LazyLineBreakIterator break_iterator(text, style.LocaleForLineBreakIterator(),
-                                       GetLineBreakType(style));
+  UpdateBreakIterator(style);
 #if !defined(MOCK_SHAPE_LINE)
+  // TODO(kojii): Instantiate in the constructor.
   HarfBuzzShaper shaper(text.Characters16(), text.length());
 #endif
-  LayoutUnit available_width = algorithm->AvailableWidth();
-  LayoutUnit position;
+  available_width_ = algorithm->AvailableWidth();
+  position_ = LayoutUnit(0);
+  LineBreakState state = LineBreakState::kNotBreakable;
+
   while (item_index_ < items.size()) {
+    // CloseTag prohibits to break before.
     const NGInlineItem& item = items[item_index_];
+    if (item.Type() == NGInlineItem::kCloseTag) {
+      item_results->push_back(
+          NGInlineItemResult(item_index_, offset_, item.EndOffset()));
+      HandleCloseTag(item, &item_results->back());
+      continue;
+    }
+
+    if (state == LineBreakState::kBreakAfterTrailings)
+      return;
+    if (state == LineBreakState::kIsBreakable && position_ > available_width_)
+      return HandleOverflow(item_results);
+
     item_results->push_back(
         NGInlineItemResult(item_index_, offset_, item.EndOffset()));
     NGInlineItemResult* item_result = &item_results->back();
-
-    // If the start offset is at the item boundary, try to add the entire item.
-    if (offset_ == item.StartOffset()) {
-      if (item.Type() == NGInlineItem::kText) {
-        item_result->inline_size = item.InlineSize();
-      } else if (item.Type() == NGInlineItem::kAtomicInline) {
-        LayoutAtomicInline(item, item_result);
-      } else if (item.Type() == NGInlineItem::kControl) {
-        if (HandleControlItem(item, text, item_result, position)) {
-          MoveToNextOf(item);
-          break;
-        }
-      } else if (item.Type() == NGInlineItem::kFloating) {
-        algorithm->LayoutAndPositionFloat(position, item.GetLayoutObject());
-        // Floats may change the available width if they fit.
-        available_width = algorithm->AvailableWidth();
-        // Floats are already positioned in the container_builder.
-        item_results->pop_back();
-        MoveToNextOf(item);
-        continue;
-      } else {
-        MoveToNextOf(item);
-        continue;
-      }
-      LayoutUnit next_position = position + item_result->inline_size;
-      if (next_position <= available_width) {
-        MoveToNextOf(item);
-        position = next_position;
-        continue;
-      }
-
-      // The entire item does not fit. Handle non-text items as overflow,
-      // since only text item is breakable.
-      if (item.Type() != NGInlineItem::kText) {
-        MoveToNextOf(item);
-        return HandleOverflow(item_results, break_iterator);
-      }
-    }
-
-    // Either the start or the break is in the mid of a text item.
-    DCHECK_EQ(item.Type(), NGInlineItem::kText);
-    DCHECK_LT(offset_, item.EndOffset());
-    break_iterator.SetLocale(item.Style()->LocaleForLineBreakIterator());
-    break_iterator.SetBreakType(GetLineBreakType(*item.Style()));
-#if defined(MOCK_SHAPE_LINE)
-    unsigned break_offset;
-    std::tie(break_offset, item_result->inline_size) = ShapeLineMock(
-        item, offset_, available_width - position, break_iterator);
-#else
-    // TODO(kojii): We need to instantiate ShapingLineBreaker here because it
-    // has item-specific info as context. Should they be part of ShapeLine() to
-    // instantiate once, or is this just fine since instatiation is not
-    // expensive?
-    DCHECK_EQ(item.TextShapeResult()->StartIndexForResult(),
-              item.StartOffset());
-    DCHECK_EQ(item.TextShapeResult()->EndIndexForResult(), item.EndOffset());
-    ShapingLineBreaker breaker(&shaper, &item.Style()->GetFont(),
-                               item.TextShapeResult(), &break_iterator);
-    unsigned break_offset;
-    item_result->shape_result =
-        breaker.ShapeLine(offset_, available_width - position, &break_offset);
-    item_result->inline_size = item_result->shape_result->SnappedWidth();
-#endif
-    DCHECK_GT(break_offset, offset_);
-    position += item_result->inline_size;
-
-    // If the break found within the item, break here.
-    if (break_offset < item.EndOffset()) {
-      offset_ = item_result->end_offset = break_offset;
-      if (position <= available_width)
-        break;
-      // The first break opportunity of the item does not fit.
+    if (item.Type() == NGInlineItem::kText) {
+      state = HandleText(item, item_result);
+    } else if (item.Type() == NGInlineItem::kAtomicInline) {
+      state = HandleAtomicInline(item, item_result);
+    } else if (item.Type() == NGInlineItem::kControl) {
+      state = HandleControlItem(item, item_result);
+      if (state == LineBreakState::kForcedBreak)
+        return;
+    } else if (item.Type() == NGInlineItem::kOpenTag) {
+      HandleOpenTag(item, item_result);
+      state = LineBreakState::kNotBreakable;
+    } else if (item.Type() == NGInlineItem::kFloating) {
+      HandleFloat(item, item_results, algorithm);
     } else {
-      // No break opporunity in the item, or the first break opportunity is at
-      // the end of the item. If it fits, continue to the next item.
-      item_result->end_offset = item.EndOffset();
       MoveToNextOf(item);
-      if (position <= available_width)
-        continue;
     }
+  }
+  if (state == LineBreakState::kIsBreakable && position_ > available_width_)
+    return HandleOverflow(item_results);
+}
 
-    // We need to look at next item if we're overflowing, and the break
-    // opportunity is beyond this item.
-    if (break_offset > item.EndOffset())
-      continue;
-    return HandleOverflow(item_results, break_iterator);
+NGLineBreaker::LineBreakState NGLineBreaker::HandleText(
+    const NGInlineItem& item,
+    NGInlineItemResult* item_result) {
+  DCHECK_EQ(item.Type(), NGInlineItem::kText);
+
+  // If the start offset is at the item boundary, try to add the entire item.
+  if (offset_ == item.StartOffset()) {
+    item_result->inline_size = item.InlineSize();
+    LayoutUnit next_position = position_ + item_result->inline_size;
+    if (!auto_wrap_ || next_position <= available_width_) {
+      position_ = next_position;
+      MoveToNextOf(item);
+      if (auto_wrap_ && break_iterator_.IsBreakable(item.EndOffset()))
+        return LineBreakState::kIsBreakable;
+      item_result->prohibit_break_after = true;
+      return LineBreakState::kNotBreakable;
+    }
+  }
+
+  if (auto_wrap_) {
+    // Try to break inside of this text item.
+    BreakText(item_result, item, available_width_ - position_);
+    position_ += item_result->inline_size;
+
+    bool is_overflow = position_ > available_width_;
+    item_result->no_break_opportunities_inside = is_overflow;
+    if (item_result->end_offset < item.EndOffset()) {
+      offset_ = item_result->end_offset;
+      return is_overflow ? LineBreakState::kIsBreakable
+                         : LineBreakState::kBreakAfterTrailings;
+    }
+    MoveToNextOf(item);
+    return item_result->prohibit_break_after ? LineBreakState::kNotBreakable
+                                             : LineBreakState::kIsBreakable;
+  }
+
+  // Add the rest of the item if !auto_wrap.
+  // Because the start position may need to reshape, run ShapingLineBreaker
+  // with max available width.
+  DCHECK_NE(offset_, item.StartOffset());
+  BreakText(item_result, item, LayoutUnit::Max());
+  DCHECK_EQ(item_result->end_offset, item.EndOffset());
+  item_result->no_break_opportunities_inside = true;
+  item_result->prohibit_break_after = true;
+  position_ += item_result->inline_size;
+  MoveToNextOf(item);
+  return LineBreakState::kNotBreakable;
+}
+
+void NGLineBreaker::BreakText(NGInlineItemResult* item_result,
+                              const NGInlineItem& item,
+                              LayoutUnit available_width) {
+  DCHECK_EQ(item.Type(), NGInlineItem::kText);
+  item.AssertOffset(item_result->start_offset);
+
+#if defined(MOCK_SHAPE_LINE)
+  std::tie(item_result->end_offset, item_result->inline_size) = ShapeLineMock(
+      item, item_result->start_offset, available_width, break_iterator_);
+#else
+  // TODO(kojii): We need to instantiate ShapingLineBreaker here because it
+  // has item-specific info as context. Should they be part of ShapeLine() to
+  // instantiate once, or is this just fine since instatiation is not
+  // expensive?
+  DCHECK_EQ(item.TextShapeResult()->StartIndexForResult(), item.StartOffset());
+  DCHECK_EQ(item.TextShapeResult()->EndIndexForResult(), item.EndOffset());
+  ShapingLineBreaker breaker(&shaper, &item.Style()->GetFont(),
+                             item.TextShapeResult(), break_iterator_);
+  item_result->shape_result = breaker.ShapeLine(
+      item_result->start_offset, available_width, &item_result->end_offset);
+  item_result->inline_size = item_result->shape_result->SnappedWidth();
+#endif
+  DCHECK_GT(item_result->end_offset, item_result->start_offset);
+  // * If width <= available_width:
+  //   * If offset < item.EndOffset(): the break opportunity to fit is found.
+  //   * If offset == item.EndOffset(): the break opportunity at the end fits.
+  //     There may be room for more characters.
+  //   * If offset > item.EndOffset(): the first break opportunity is beyond
+  //     the end. There may be room for more characters.
+  // * If width > available_width: The first break opporunity does not fit.
+  //   offset is the first break opportunity, either inside, at the end, or
+  //   beyond the end.
+  if (item_result->end_offset <= item.EndOffset()) {
+    item_result->prohibit_break_after = false;
+  } else {
+    item_result->prohibit_break_after = true;
+    item_result->end_offset = item.EndOffset();
   }
 }
 
 // Measure control items; new lines and tab, that are similar to text, affect
 // layout, but do not need shaping/painting.
-bool NGLineBreaker::HandleControlItem(const NGInlineItem& item,
-                                      const String& text,
-                                      NGInlineItemResult* item_result,
-                                      LayoutUnit position) {
+NGLineBreaker::LineBreakState NGLineBreaker::HandleControlItem(
+    const NGInlineItem& item,
+    NGInlineItemResult* item_result) {
   DCHECK_EQ(item.Length(), 1u);
-  UChar character = text[item.StartOffset()];
-  if (character == kNewlineCharacter)
-    return true;
-
+  UChar character = node_->Text()[item.StartOffset()];
+  if (character == kNewlineCharacter) {
+    MoveToNextOf(item);
+    return LineBreakState::kForcedBreak;
+  }
   DCHECK_EQ(character, kTabulationCharacter);
   DCHECK(item.Style());
   const ComputedStyle& style = *item.Style();
   const Font& font = style.GetFont();
-  item_result->inline_size = font.TabWidth(style.GetTabSize(), position);
-  return false;
+  item_result->inline_size = font.TabWidth(style.GetTabSize(), position_);
+  position_ += item_result->inline_size;
+  MoveToNextOf(item);
+  // TODO(kojii): Implement break around the tab character.
+  return LineBreakState::kIsBreakable;
 }
 
-void NGLineBreaker::LayoutAtomicInline(const NGInlineItem& item,
-                                       NGInlineItemResult* item_result) {
+NGLineBreaker::LineBreakState NGLineBreaker::HandleAtomicInline(
+    const NGInlineItem& item,
+    NGInlineItemResult* item_result) {
   DCHECK_EQ(item.Type(), NGInlineItem::kAtomicInline);
   NGBlockNode* node = new NGBlockNode(item.GetLayoutObject());
   const ComputedStyle& style = node->Style();
@@ -251,65 +270,158 @@
       ComputeMargins(*constraint_space_, style,
                      constraint_space_->WritingMode(), style.Direction());
   item_result->inline_size += item_result->margins.InlineSum();
+
+  position_ += item_result->inline_size;
+  MoveToNextOf(item);
+  if (auto_wrap_)
+    return LineBreakState::kIsBreakable;
+  item_result->prohibit_break_after = true;
+  return LineBreakState::kNotBreakable;
+}
+
+void NGLineBreaker::HandleFloat(const NGInlineItem& item,
+                                NGInlineItemResults* item_results,
+                                NGInlineLayoutAlgorithm* algorithm) {
+  algorithm->LayoutAndPositionFloat(position_, item.GetLayoutObject());
+  // Floats may change the available width if they fit.
+  available_width_ = algorithm->AvailableWidth();
+  // Floats are already positioned in the container_builder.
+  item_results->pop_back();
+  MoveToNextOf(item);
+}
+
+void NGLineBreaker::HandleOpenTag(const NGInlineItem& item,
+                                  NGInlineItemResult* item_result) {
+  if (item.HasStartEdge()) {
+    DCHECK(item.Style());
+    // TODO(kojii): We compute 16 values and discard 12 out of that, and do it 3
+    // times per element. We may want to cache this. crrev.com/2865903002/#msg14
+    NGBoxStrut margins = ComputeMargins(*constraint_space_, *item.Style(),
+                                        constraint_space_->WritingMode(),
+                                        constraint_space_->Direction());
+    NGBoxStrut borders = ComputeBorders(*constraint_space_, *item.Style());
+    NGBoxStrut paddings = ComputePadding(*constraint_space_, *item.Style());
+    item_result->inline_size =
+        margins.inline_start + borders.inline_start + paddings.inline_start;
+    position_ += item_result->inline_size;
+  }
+  UpdateBreakIterator(*item.Style());
+  MoveToNextOf(item);
+}
+
+void NGLineBreaker::HandleCloseTag(const NGInlineItem& item,
+                                   NGInlineItemResult* item_result) {
+  if (item.HasEndEdge()) {
+    DCHECK(item.Style());
+    NGBoxStrut margins = ComputeMargins(*constraint_space_, *item.Style(),
+                                        constraint_space_->WritingMode(),
+                                        constraint_space_->Direction());
+    NGBoxStrut borders = ComputeBorders(*constraint_space_, *item.Style());
+    NGBoxStrut paddings = ComputePadding(*constraint_space_, *item.Style());
+    item_result->inline_size =
+        margins.inline_end + borders.inline_end + paddings.inline_end;
+    position_ += item_result->inline_size;
+  }
+  DCHECK(item.GetLayoutObject() && item.GetLayoutObject()->Parent());
+  UpdateBreakIterator(item.GetLayoutObject()->Parent()->StyleRef());
+  MoveToNextOf(item);
 }
 
 // Handles when the last item overflows.
 // At this point, item_results does not fit into the current line, and there
 // are no break opportunities in item_results.back().
-void NGLineBreaker::HandleOverflow(
-    NGInlineItemResults* item_results,
-    const LazyLineBreakIterator& break_iterator) {
-  DCHECK_GT(offset_, 0u);
-
-  // Find the last break opportunity. If none, let this line overflow.
-  unsigned line_start_offset = item_results->front().start_offset;
-  unsigned break_offset =
-      break_iterator.PreviousBreakOpportunity(offset_ - 1, line_start_offset);
-  if (!break_offset || break_offset <= line_start_offset) {
-    AppendCloseTags(item_results);
-    return;
-  }
-
-  // Truncate the end of the line to the break opportunity.
+void NGLineBreaker::HandleOverflow(NGInlineItemResults* item_results) {
   const Vector<NGInlineItem>& items = node_->Items();
-  unsigned new_end = item_results->size();
-  while (true) {
-    NGInlineItemResult* item_result = &(*item_results)[--new_end];
-    if (item_result->start_offset < break_offset) {
-      // The break is at the mid of the item. Adjust the end_offset to the new
-      // break offset.
-      const NGInlineItem& item = items[item_result->item_index];
-      item.AssertEndOffset(break_offset);
-      DCHECK_EQ(item.Type(), NGInlineItem::kText);
-      DCHECK_NE(item_result->end_offset, break_offset);
-      item_result->end_offset = break_offset;
-      item_result->inline_size =
-          item.InlineSize(item_result->start_offset, item_result->end_offset);
-      // TODO(kojii): May need to reshape. Add to ShapingLineBreaker?
-      new_end++;
-      break;
-    }
-    if (item_result->start_offset == break_offset) {
-      // The new break offset is at the item boundary. Remove items up to the
-      // new break offset.
-      // TODO(kojii): Remove open tags as well.
-      break;
+  LayoutUnit rewind_width = available_width_ - position_;
+  DCHECK_LT(rewind_width, 0);
+
+  // Search for a break opportunity that can fit.
+  // Also keep track of the first break opportunity in case of overflow.
+  unsigned break_before = 0;
+  unsigned break_before_if_before_allow = 0;
+  LayoutUnit rewind_width_if_before_allow;
+  bool last_item_prohibits_break_before = true;
+  for (unsigned i = item_results->size(); i;) {
+    NGInlineItemResult* item_result = &(*item_results)[--i];
+    const NGInlineItem& item = items[item_result->item_index];
+    rewind_width += item_result->inline_size;
+    if (item.Type() == NGInlineItem::kText ||
+        item.Type() == NGInlineItem::kAtomicInline) {
+      // Try to break inside of this item.
+      if (item.Type() == NGInlineItem::kText && rewind_width >= 0 &&
+          !item_result->no_break_opportunities_inside) {
+        // When the text fits but its right margin does not, the break point
+        // must not be at the end.
+        LayoutUnit item_available_width =
+            std::min(rewind_width, item_result->inline_size - 1);
+        BreakText(item_result, item, item_available_width);
+        if (item_result->inline_size <= item_available_width) {
+          DCHECK_LT(item_result->end_offset, item.EndOffset());
+          DCHECK(!item_result->prohibit_break_after);
+          return Rewind(item_results, i + 1);
+        }
+        if (!item_result->prohibit_break_after &&
+            !last_item_prohibits_break_before) {
+          break_before = i + 1;
+        }
+      }
+
+      // Try to break after this item.
+      if (break_before_if_before_allow && !item_result->prohibit_break_after) {
+        if (rewind_width_if_before_allow >= 0)
+          return Rewind(item_results, break_before_if_before_allow);
+        break_before = break_before_if_before_allow;
+      }
+
+      // Otherwise, before this item is a possible break point.
+      break_before_if_before_allow = i;
+      rewind_width_if_before_allow = rewind_width;
+      last_item_prohibits_break_before = false;
+    } else if (item.Type() == NGInlineItem::kCloseTag) {
+      last_item_prohibits_break_before = true;
+    } else {
+      if (i + 1 == break_before_if_before_allow) {
+        break_before_if_before_allow = i;
+        rewind_width_if_before_allow = rewind_width;
+      }
+      last_item_prohibits_break_before = false;
     }
   }
-  DCHECK_GT(new_end, 0u);
 
+  // The rewind point did not found, let this line overflow.
+  // If there was a break opporunity, the overflow should stop there.
+  if (break_before)
+    Rewind(item_results, break_before);
+}
+
+void NGLineBreaker::Rewind(NGInlineItemResults* item_results,
+                           unsigned new_end) {
   // TODO(kojii): Should we keep results for the next line? We don't need to
   // re-layout atomic inlines.
   // TODO(kojii): Removing processed floats is likely a problematic. Keep
   // floats in this line, or keep it for the next line.
   item_results->Shrink(new_end);
 
-  // Update the current item index and offset to the new break point.
-  const NGInlineItemResult& last_item_result = item_results->back();
-  offset_ = last_item_result.end_offset;
-  item_index_ = last_item_result.item_index;
-  if (items[item_index_].EndOffset() == offset_)
-    item_index_++;
+  MoveToNextOf(item_results->back());
+}
+
+void NGLineBreaker::UpdateBreakIterator(const ComputedStyle& style) {
+  auto_wrap_ = style.AutoWrap();
+
+  if (auto_wrap_) {
+    break_iterator_.SetLocale(style.LocaleForLineBreakIterator());
+
+    if (style.WordBreak() == EWordBreak::kBreakAll ||
+        style.WordBreak() == EWordBreak::kBreakWord) {
+      break_iterator_.SetBreakType(LineBreakType::kBreakAll);
+    } else if (style.WordBreak() == EWordBreak::kKeepAll) {
+      break_iterator_.SetBreakType(LineBreakType::kKeepAll);
+    } else {
+      break_iterator_.SetBreakType(LineBreakType::kNormal);
+    }
+
+    // TODO(kojii): Implement word-wrap/overflow-wrap property
+  }
 }
 
 void NGLineBreaker::MoveToNextOf(const NGInlineItem& item) {
@@ -318,6 +430,14 @@
   item_index_++;
 }
 
+void NGLineBreaker::MoveToNextOf(const NGInlineItemResult& item_result) {
+  offset_ = item_result.end_offset;
+  item_index_ = item_result.item_index;
+  const NGInlineItem& item = node_->Items()[item_result.item_index];
+  if (offset_ == item.EndOffset())
+    item_index_++;
+}
+
 void NGLineBreaker::SkipCollapsibleWhitespaces() {
   const Vector<NGInlineItem>& items = node_->Items();
   if (item_index_ >= items.size())
@@ -336,17 +456,6 @@
   }
 }
 
-void NGLineBreaker::AppendCloseTags(NGInlineItemResults* item_results) {
-  const Vector<NGInlineItem>& items = node_->Items();
-  for (; item_index_ < items.size(); item_index_++) {
-    const NGInlineItem& item = items[item_index_];
-    if (item.Type() != NGInlineItem::kCloseTag)
-      break;
-    DCHECK_EQ(offset_, item.EndOffset());
-    item_results->push_back(NGInlineItemResult(item_index_, offset_, offset_));
-  }
-}
-
 RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const {
   const Vector<NGInlineItem>& items = node_->Items();
   if (item_index_ >= items.size())
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.h
index 3823bd94..9260b0ac 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.h
@@ -8,11 +8,12 @@
 #include "core/CoreExport.h"
 #include "core/layout/ng/inline/ng_inline_item_result.h"
 #include "platform/heap/Handle.h"
+#include "platform/text/TextBreakIterator.h"
+#include "platform/wtf/Allocator.h"
 #include "platform/wtf/text/AtomicString.h"
 
 namespace blink {
 
-class LazyLineBreakIterator;
 class NGInlineBreakToken;
 class NGInlineItem;
 class NGInlineNode;
@@ -43,24 +44,50 @@
  private:
   void BreakLine(NGInlineItemResults*, NGInlineLayoutAlgorithm*);
 
-  bool HandleControlItem(const NGInlineItem&,
-                         const String& text,
-                         NGInlineItemResult*,
-                         LayoutUnit position);
-  void LayoutAtomicInline(const NGInlineItem&, NGInlineItemResult*);
+  enum class LineBreakState {
+    // The current position is not breakable.
+    kNotBreakable,
+    // The current position is breakable.
+    kIsBreakable,
+    // Break by including trailing items (CloseTag).
+    kBreakAfterTrailings,
+    // Break immediately.
+    kForcedBreak
+  };
 
-  void HandleOverflow(NGInlineItemResults*, const LazyLineBreakIterator&);
+  LineBreakState HandleText(const NGInlineItem&, NGInlineItemResult*);
+  void BreakText(NGInlineItemResult*,
+                 const NGInlineItem&,
+                 LayoutUnit available_width);
+
+  LineBreakState HandleControlItem(const NGInlineItem&, NGInlineItemResult*);
+  LineBreakState HandleAtomicInline(const NGInlineItem&, NGInlineItemResult*);
+  void HandleFloat(const NGInlineItem&,
+                   NGInlineItemResults*,
+                   NGInlineLayoutAlgorithm*);
+
+  void HandleOpenTag(const NGInlineItem&, NGInlineItemResult*);
+  void HandleCloseTag(const NGInlineItem&, NGInlineItemResult*);
+
+  void HandleOverflow(NGInlineItemResults*);
+  void Rewind(NGInlineItemResults*, unsigned new_end);
+
+  void UpdateBreakIterator(const ComputedStyle&);
 
   void MoveToNextOf(const NGInlineItem&);
+  void MoveToNextOf(const NGInlineItemResult&);
   void SkipCollapsibleWhitespaces();
 
-  void AppendCloseTags(NGInlineItemResults*);
-
   Persistent<NGInlineNode> node_;
   const NGConstraintSpace* constraint_space_;
   const AtomicString locale_;
   unsigned item_index_;
   unsigned offset_;
+  LayoutUnit available_width_;
+  LayoutUnit position_;
+  LazyLineBreakIterator break_iterator_;
+
+  unsigned auto_wrap_ : 1;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker_test.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker_test.cc
new file mode 100644
index 0000000..e3d8a98
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker_test.cc
@@ -0,0 +1,252 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/layout/ng/ng_base_layout_algorithm_test.h"
+
+#include "core/layout/ng/inline/ng_inline_layout_algorithm.h"
+#include "core/layout/ng/inline/ng_inline_node.h"
+#include "core/layout/ng/inline/ng_line_breaker.h"
+#include "core/layout/ng/layout_ng_block_flow.h"
+#include "core/layout/ng/ng_constraint_space_builder.h"
+#include "platform/wtf/text/StringBuilder.h"
+
+namespace blink {
+
+class NGLineBreakerTest : public NGBaseLayoutAlgorithmTest {
+ protected:
+  NGInlineNode* CreateInlineNode(const String& html_content) {
+    SetBodyInnerHTML(html_content);
+
+    LayoutNGBlockFlow* block_flow =
+        ToLayoutNGBlockFlow(GetLayoutObjectByElementId("container"));
+    NGInlineNode* inline_node =
+        new NGInlineNode(block_flow->FirstChild(), block_flow);
+
+    return inline_node;
+  }
+
+  // Break lines using the specified available width.
+  Vector<NGInlineItemResults> BreakLines(NGInlineNode* node,
+                                         LayoutUnit available_width) {
+    if (!node->IsPrepareLayoutFinished())
+      node->PrepareLayout();
+
+    RefPtr<NGConstraintSpace> space =
+        NGConstraintSpaceBuilder(NGWritingMode::kHorizontalTopBottom)
+            .SetAvailableSize({available_width, NGSizeIndefinite})
+            .ToConstraintSpace(NGWritingMode::kHorizontalTopBottom);
+    NGLineBreaker line_breaker(node, space.Get());
+    NGInlineLayoutAlgorithm algorithm(node, space.Get());
+    Vector<NGInlineItemResults> lines;
+    while (true) {
+      NGInlineItemResults item_results;
+      line_breaker.NextLine(&item_results, &algorithm);
+      if (item_results.IsEmpty())
+        break;
+      lines.push_back(item_results);
+    }
+    return lines;
+  }
+};
+
+namespace {
+
+String ToString(NGInlineItemResults line, NGInlineNode* node) {
+  StringBuilder builder;
+  for (const auto& item_result : line) {
+    builder.Append(
+        node->Text(item_result.start_offset, item_result.end_offset));
+  }
+  return builder.ToString();
+}
+
+TEST_F(NGLineBreakerTest, SingleNode) {
+  LoadAhem();
+  NGInlineNode* node = CreateInlineNode(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #container {
+      font: 10px/1 Ahem;
+    }
+    </style>
+    <div id=container>123 456 789</div>
+  )HTML");
+
+  Vector<NGInlineItemResults> lines;
+  lines = BreakLines(node, LayoutUnit(80));
+  EXPECT_EQ(2u, lines.size());
+  EXPECT_EQ("123 456", ToString(lines[0], node));
+  EXPECT_EQ("789", ToString(lines[1], node));
+
+  lines = BreakLines(node, LayoutUnit(60));
+  EXPECT_EQ(3u, lines.size());
+  EXPECT_EQ("123", ToString(lines[0], node));
+  EXPECT_EQ("456", ToString(lines[1], node));
+  EXPECT_EQ("789", ToString(lines[2], node));
+}
+
+TEST_F(NGLineBreakerTest, OverflowWord) {
+  LoadAhem();
+  NGInlineNode* node = CreateInlineNode(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #container {
+      font: 10px/1 Ahem;
+    }
+    </style>
+    <div id=container>12345 678</div>
+  )HTML");
+
+  // The first line overflows, but the last line does not.
+  Vector<NGInlineItemResults> lines;
+  lines = BreakLines(node, LayoutUnit(40));
+  EXPECT_EQ(2u, lines.size());
+  EXPECT_EQ("12345", ToString(lines[0], node));
+  EXPECT_EQ("678", ToString(lines[1], node));
+
+  // Both lines overflow.
+  lines = BreakLines(node, LayoutUnit(20));
+  EXPECT_EQ(2u, lines.size());
+  EXPECT_EQ("12345", ToString(lines[0], node));
+  EXPECT_EQ("678", ToString(lines[1], node));
+}
+
+TEST_F(NGLineBreakerTest, OverflowAtomicInline) {
+  LoadAhem();
+  NGInlineNode* node = CreateInlineNode(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #container {
+      font: 10px/1 Ahem;
+    }
+    span {
+      display: inline-block;
+      width: 30px;
+      height: 10px;
+    }
+    </style>
+    <div id=container>12345<span></span>678</div>
+  )HTML");
+
+  Vector<NGInlineItemResults> lines;
+  lines = BreakLines(node, LayoutUnit(80));
+  EXPECT_EQ(2u, lines.size());
+  EXPECT_EQ(String(u"12345\uFFFC"), ToString(lines[0], node));
+  EXPECT_EQ("678", ToString(lines[1], node));
+
+  lines = BreakLines(node, LayoutUnit(70));
+  EXPECT_EQ(2u, lines.size());
+  EXPECT_EQ("12345", ToString(lines[0], node));
+  EXPECT_EQ(String(u"\uFFFC678"), ToString(lines[1], node));
+
+  lines = BreakLines(node, LayoutUnit(40));
+  EXPECT_EQ(3u, lines.size());
+  EXPECT_EQ("12345", ToString(lines[0], node));
+  EXPECT_EQ(String(u"\uFFFC"), ToString(lines[1], node));
+  EXPECT_EQ("678", ToString(lines[2], node));
+
+  lines = BreakLines(node, LayoutUnit(20));
+  EXPECT_EQ(3u, lines.size());
+  EXPECT_EQ("12345", ToString(lines[0], node));
+  EXPECT_EQ(String(u"\uFFFC"), ToString(lines[1], node));
+  EXPECT_EQ("678", ToString(lines[2], node));
+}
+
+TEST_F(NGLineBreakerTest, OverflowMargin) {
+  LoadAhem();
+  NGInlineNode* node = CreateInlineNode(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #container {
+      font: 10px/1 Ahem;
+    }
+    span {
+      margin-right: 4em;
+    }
+    </style>
+    <div id=container><span>123 456</span> 789</div>
+  )HTML");
+  const Vector<NGInlineItem>& items = node->Items();
+
+  // While "123 456" can fit in a line, "456" has a right margin that cannot
+  // fit. Since "456" and its right margin is not breakable, "456" should be on
+  // the next line.
+  Vector<NGInlineItemResults> lines;
+  lines = BreakLines(node, LayoutUnit(80));
+  EXPECT_EQ(3u, lines.size());
+  EXPECT_EQ("123", ToString(lines[0], node));
+  EXPECT_EQ("456", ToString(lines[1], node));
+  DCHECK_EQ(NGInlineItem::kCloseTag, items[lines[1].back().item_index].Type());
+  EXPECT_EQ("789", ToString(lines[2], node));
+
+  // Same as above, but this time "456" overflows the line because it is 70px.
+  lines = BreakLines(node, LayoutUnit(60));
+  EXPECT_EQ(3u, lines.size());
+  EXPECT_EQ("123", ToString(lines[0], node));
+  EXPECT_EQ("456", ToString(lines[1], node));
+  DCHECK_EQ(NGInlineItem::kCloseTag, items[lines[1].back().item_index].Type());
+  EXPECT_EQ("789", ToString(lines[2], node));
+}
+
+TEST_F(NGLineBreakerTest, BoundaryInWord) {
+  LoadAhem();
+  NGInlineNode* node = CreateInlineNode(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #container {
+      font: 10px/1 Ahem;
+    }
+    </style>
+    <div id=container><span>123 456</span>789 abc</div>
+  )HTML");
+
+  // The element boundary within "456789" should not cause a break.
+  // Since "789" does not fit, it should go to the next line along with "456".
+  Vector<NGInlineItemResults> lines;
+  lines = BreakLines(node, LayoutUnit(80));
+  EXPECT_EQ(3u, lines.size());
+  EXPECT_EQ("123", ToString(lines[0], node));
+  EXPECT_EQ("456789", ToString(lines[1], node));
+  EXPECT_EQ("abc", ToString(lines[2], node));
+
+  // Same as above, but this time "456789" overflows the line because it is
+  // 60px.
+  lines = BreakLines(node, LayoutUnit(50));
+  EXPECT_EQ(3u, lines.size());
+  EXPECT_EQ("123", ToString(lines[0], node));
+  EXPECT_EQ("456789", ToString(lines[1], node));
+  EXPECT_EQ("abc", ToString(lines[2], node));
+}
+
+TEST_F(NGLineBreakerTest, BoundaryInFirstWord) {
+  LoadAhem();
+  NGInlineNode* node = CreateInlineNode(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #container {
+      font: 10px/1 Ahem;
+    }
+    </style>
+    <div id=container><span>123</span>456 789</div>
+  )HTML");
+
+  Vector<NGInlineItemResults> lines;
+  lines = BreakLines(node, LayoutUnit(80));
+  EXPECT_EQ(2u, lines.size());
+  EXPECT_EQ("123456", ToString(lines[0], node));
+  EXPECT_EQ("789", ToString(lines[1], node));
+
+  lines = BreakLines(node, LayoutUnit(50));
+  EXPECT_EQ(2u, lines.size());
+  EXPECT_EQ("123456", ToString(lines[0], node));
+  EXPECT_EQ("789", ToString(lines[1], node));
+
+  lines = BreakLines(node, LayoutUnit(20));
+  EXPECT_EQ(2u, lines.size());
+  EXPECT_EQ("123456", ToString(lines[0], node));
+  EXPECT_EQ("789", ToString(lines[1], node));
+}
+
+}  // namespace
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/TextPainterBase.cpp b/third_party/WebKit/Source/core/paint/TextPainterBase.cpp
index bdfbac04..9f11fca4 100644
--- a/third_party/WebKit/Source/core/paint/TextPainterBase.cpp
+++ b/third_party/WebKit/Source/core/paint/TextPainterBase.cpp
@@ -199,9 +199,9 @@
   switch (baseline_type) {
     case kAlphabeticBaseline:
       switch (style.GetTextUnderlinePosition()) {
-        case kTextUnderlinePositionAuto:
+        case TextUnderlinePosition::kAuto:
           return ResolvedUnderlinePosition::kRoman;
-        case kTextUnderlinePositionUnder:
+        case TextUnderlinePosition::kUnder:
           return ResolvedUnderlinePosition::kUnder;
       }
       break;
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index 5a5a4a57..3bb53f5 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -570,14 +570,14 @@
   if (rare_non_inherited_data_.Get() != other.rare_non_inherited_data_.Get()) {
     if (rare_non_inherited_data_->appearance_ !=
             other.rare_non_inherited_data_->appearance_ ||
-        rare_non_inherited_data_->margin_before_collapse !=
-            other.rare_non_inherited_data_->margin_before_collapse ||
-        rare_non_inherited_data_->margin_after_collapse !=
-            other.rare_non_inherited_data_->margin_after_collapse ||
-        rare_non_inherited_data_->line_clamp !=
-            other.rare_non_inherited_data_->line_clamp ||
-        rare_non_inherited_data_->text_overflow !=
-            other.rare_non_inherited_data_->text_overflow ||
+        rare_non_inherited_data_->margin_before_collapse_ !=
+            other.rare_non_inherited_data_->margin_before_collapse_ ||
+        rare_non_inherited_data_->margin_after_collapse_ !=
+            other.rare_non_inherited_data_->margin_after_collapse_ ||
+        rare_non_inherited_data_->line_clamp_ !=
+            other.rare_non_inherited_data_->line_clamp_ ||
+        rare_non_inherited_data_->text_overflow_ !=
+            other.rare_non_inherited_data_->text_overflow_ ||
         rare_non_inherited_data_->shape_margin_ !=
             other.rare_non_inherited_data_->shape_margin_ ||
         rare_non_inherited_data_->order_ !=
@@ -745,8 +745,8 @@
     return true;
 
   if (rare_non_inherited_data_.Get() != other.rare_non_inherited_data_.Get()) {
-    if (rare_non_inherited_data_->user_drag !=
-            other.rare_non_inherited_data_->user_drag ||
+    if (rare_non_inherited_data_->user_drag_ !=
+            other.rare_non_inherited_data_->user_drag_ ||
         rare_non_inherited_data_->object_fit_ !=
             other.rare_non_inherited_data_->object_fit_ ||
         rare_non_inherited_data_->object_position_ !=
@@ -852,8 +852,8 @@
   }
 
   if (rare_non_inherited_data_.Get() != other.rare_non_inherited_data_.Get()) {
-    if (rare_non_inherited_data_->opacity !=
-        other.rare_non_inherited_data_->opacity)
+    if (rare_non_inherited_data_->opacity_ !=
+        other.rare_non_inherited_data_->opacity_)
       diff.SetOpacityChanged();
   }
 
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index aec4bd46..b93502c 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -1034,10 +1034,10 @@
   }
   EMarginCollapse MarginAfterCollapse() const {
     return static_cast<EMarginCollapse>(
-        rare_non_inherited_data_->margin_after_collapse);
+        rare_non_inherited_data_->margin_after_collapse_);
   }
   void SetMarginBeforeCollapse(EMarginCollapse c) {
-    SET_VAR(rare_non_inherited_data_, margin_before_collapse, c);
+    SET_VAR(rare_non_inherited_data_, margin_before_collapse_, c);
   }
 
   // -webkit-margin-after-collapse (aka -webkit-margin-bottom-collapse)
@@ -1046,10 +1046,10 @@
   }
   EMarginCollapse MarginBeforeCollapse() const {
     return static_cast<EMarginCollapse>(
-        rare_non_inherited_data_->margin_before_collapse);
+        rare_non_inherited_data_->margin_before_collapse_);
   }
   void SetMarginAfterCollapse(EMarginCollapse c) {
-    SET_VAR(rare_non_inherited_data_, margin_after_collapse, c);
+    SET_VAR(rare_non_inherited_data_, margin_after_collapse_, c);
   }
 
   // mix-blend-mode
@@ -1137,10 +1137,10 @@
 
   // opacity (aka -webkit-opacity)
   static float InitialOpacity() { return 1.0f; }
-  float Opacity() const { return rare_non_inherited_data_->opacity; }
+  float Opacity() const { return rare_non_inherited_data_->opacity_; }
   void SetOpacity(float f) {
     float v = clampTo<float>(f, 0, 1);
-    SET_VAR(rare_non_inherited_data_, opacity, v);
+    SET_VAR(rare_non_inherited_data_, opacity_, v);
   }
 
   // order (aka -webkit-order)
@@ -1266,10 +1266,10 @@
   }
   ETransformStyle3D TransformStyle3D() const {
     return static_cast<ETransformStyle3D>(
-        rare_non_inherited_data_->transform_style3d_);
+        rare_non_inherited_data_->transform_style_3d_);
   }
   void SetTransformStyle3D(ETransformStyle3D b) {
-    SET_VAR(rare_non_inherited_data_, transform_style3d_, b);
+    SET_VAR(rare_non_inherited_data_, transform_style_3d_, b);
   }
 
   // -webkit-transform-origin-x
@@ -1475,14 +1475,15 @@
 
   // text-underline-position
   static TextUnderlinePosition InitialTextUnderlinePosition() {
-    return kTextUnderlinePositionAuto;
+    return TextUnderlinePosition::kAuto;
   }
   TextUnderlinePosition GetTextUnderlinePosition() const {
     return static_cast<TextUnderlinePosition>(
         rare_inherited_data_->text_underline_position_);
   }
   void SetTextUnderlinePosition(TextUnderlinePosition v) {
-    SET_VAR(rare_inherited_data_, text_underline_position_, v);
+    SET_VAR(rare_inherited_data_, text_underline_position_,
+            static_cast<unsigned>(v));
   }
 
   // text-decoration-skip
@@ -1501,10 +1502,10 @@
   // text-overflow
   static TextOverflow InitialTextOverflow() { return kTextOverflowClip; }
   TextOverflow GetTextOverflow() const {
-    return static_cast<TextOverflow>(rare_non_inherited_data_->text_overflow);
+    return static_cast<TextOverflow>(rare_non_inherited_data_->text_overflow_);
   }
   void SetTextOverflow(TextOverflow overflow) {
-    SET_VAR(rare_non_inherited_data_, text_overflow, overflow);
+    SET_VAR(rare_non_inherited_data_, text_overflow_, overflow);
   }
 
   // touch-action
@@ -1705,45 +1706,16 @@
 
   bool TextShadowDataEquivalent(const ComputedStyle&) const;
 
-  // -webkit-line-break
-  static LineBreak InitialLineBreak() { return LineBreak::kAuto; }
-  LineBreak GetLineBreak() const {
-    return static_cast<LineBreak>(rare_inherited_data_->line_break_);
-  }
-  void SetLineBreak(LineBreak b) {
-    SET_VAR(rare_inherited_data_, line_break_, static_cast<unsigned>(b));
-  }
-
   // Text emphasis properties.
-  static TextEmphasisFill InitialTextEmphasisFill() {
-    return TextEmphasisFill::kFilled;
-  }
   static TextEmphasisMark InitialTextEmphasisMark() {
     return TextEmphasisMark::kNone;
   }
-  static const AtomicString& InitialTextEmphasisCustomMark() {
-    return g_null_atom;
-  }
-  TextEmphasisFill GetTextEmphasisFill() const {
-    return static_cast<TextEmphasisFill>(
-        rare_inherited_data_->text_emphasis_fill_);
-  }
   TextEmphasisMark GetTextEmphasisMark() const;
-  const AtomicString& TextEmphasisCustomMark() const {
-    return rare_inherited_data_->text_emphasis_custom_mark_;
-  }
-  const AtomicString& TextEmphasisMarkString() const;
-  void SetTextEmphasisFill(TextEmphasisFill fill) {
-    SET_VAR(rare_inherited_data_, text_emphasis_fill_,
-            static_cast<unsigned>(fill));
-  }
   void SetTextEmphasisMark(TextEmphasisMark mark) {
     SET_VAR(rare_inherited_data_, text_emphasis_mark_,
             static_cast<unsigned>(mark));
   }
-  void SetTextEmphasisCustomMark(const AtomicString& mark) {
-    SET_VAR(rare_inherited_data_, text_emphasis_custom_mark_, mark);
-  }
+  const AtomicString& TextEmphasisMarkString() const;
 
   // -webkit-text-emphasis-color (aka -epub-text-emphasis-color)
   void SetTextEmphasisColor(const StyleColor& color) {
@@ -1752,36 +1724,13 @@
             color.IsCurrentColor());
   }
 
-  // -webkit-text-emphasis-position
-  static TextEmphasisPosition InitialTextEmphasisPosition() {
-    return TextEmphasisPosition::kOver;
-  }
-  TextEmphasisPosition GetTextEmphasisPosition() const {
-    return static_cast<TextEmphasisPosition>(
-        rare_inherited_data_->text_emphasis_position_);
-  }
-  void SetTextEmphasisPosition(TextEmphasisPosition position) {
-    SET_VAR(rare_inherited_data_, text_emphasis_position_,
-            static_cast<unsigned>(position));
-  }
-
   // -webkit-line-clamp
   static LineClampValue InitialLineClamp() { return LineClampValue(); }
   const LineClampValue& LineClamp() const {
-    return rare_non_inherited_data_->line_clamp;
+    return rare_non_inherited_data_->line_clamp_;
   }
   void SetLineClamp(LineClampValue c) {
-    SET_VAR(rare_non_inherited_data_, line_clamp, c);
-  }
-
-  // -webkit-ruby-position
-  static RubyPosition InitialRubyPosition() { return RubyPosition::kBefore; }
-  RubyPosition GetRubyPosition() const {
-    return static_cast<RubyPosition>(rare_inherited_data_->ruby_position_);
-  }
-  void SetRubyPosition(RubyPosition position) {
-    SET_VAR(rare_inherited_data_, ruby_position_,
-            static_cast<unsigned>(position));
+    SET_VAR(rare_non_inherited_data_, line_clamp_, c);
   }
 
   // -webkit-text-fill-color
@@ -1801,10 +1750,10 @@
   // -webkit-user-drag
   static EUserDrag InitialUserDrag() { return DRAG_AUTO; }
   EUserDrag UserDrag() const {
-    return static_cast<EUserDrag>(rare_non_inherited_data_->user_drag);
+    return static_cast<EUserDrag>(rare_non_inherited_data_->user_drag_);
   }
   void SetUserDrag(EUserDrag d) {
-    SET_VAR(rare_non_inherited_data_, user_drag, d);
+    SET_VAR(rare_non_inherited_data_, user_drag_, d);
   }
 
   // -webkit-user-modify
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index 42b84ced..45238ad 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -194,8 +194,6 @@
   kObjectFitScaleDown
 };
 
-enum class LineBreak { kAuto, kLoose, kNormal, kStrict, kAfterWhiteSpace };
-
 enum EResize { RESIZE_NONE, RESIZE_BOTH, RESIZE_HORIZONTAL, RESIZE_VERTICAL };
 
 enum QuoteType { OPEN_QUOTE, CLOSE_QUOTE, NO_OPEN_QUOTE, NO_CLOSE_QUOTE };
@@ -248,10 +246,10 @@
   return a = a | b;
 }
 
-enum TextUnderlinePosition {
+enum class TextUnderlinePosition {
   // FIXME: Implement support for 'under left' and 'under right' values.
-  kTextUnderlinePositionAuto,
-  kTextUnderlinePositionUnder
+  kAuto,
+  kUnder
 };
 
 enum ETransformStyle3D { kTransformStyle3DFlat, kTransformStyle3DPreserve3D };
@@ -265,8 +263,6 @@
 
 enum ELineClampType { kLineClampLineCount, kLineClampPercentage };
 
-enum class TextEmphasisFill { kFilled, kOpen };
-
 enum class TextEmphasisMark {
   kNone,
   kAuto,
@@ -278,8 +274,6 @@
   kCustom
 };
 
-enum class TextEmphasisPosition { kOver, kUnder };
-
 enum class TextOrientation { kMixed, kUpright, kSideways };
 
 enum TextOverflow { kTextOverflowClip = 0, kTextOverflowEllipsis };
@@ -292,8 +286,6 @@
   kPixelated
 };
 
-enum class RubyPosition { kBefore, kAfter };
-
 static const size_t kGridAutoFlowBits = 4;
 enum InternalGridAutoFlowAlgorithm {
   kInternalAutoFlowAlgorithmSparse = 0x1,
diff --git a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
index 5a43faa..5ec1022 100644
--- a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
+++ b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
@@ -71,13 +71,13 @@
               "StyleRareNonInheritedData_should_stay_small");
 
 StyleRareNonInheritedData::StyleRareNonInheritedData()
-    : opacity(ComputedStyle::InitialOpacity()),
+    : opacity_(ComputedStyle::InitialOpacity()),
       perspective_(ComputedStyle::InitialPerspective()),
       shape_image_threshold_(ComputedStyle::InitialShapeImageThreshold()),
       order_(ComputedStyle::InitialOrder()),
       perspective_origin_(ComputedStyle::InitialPerspectiveOrigin()),
       object_position_(ComputedStyle::InitialObjectPosition()),
-      line_clamp(ComputedStyle::InitialLineClamp()),
+      line_clamp_(ComputedStyle::InitialLineClamp()),
       draggable_region_mode_(static_cast<unsigned>(kDraggableRegionNone)),
       shape_outside_(ComputedStyle::InitialShapeOutside()),
       clip_path_(ComputedStyle::InitialClipPath()),
@@ -101,12 +101,12 @@
       justify_items_(ComputedStyle::InitialSelfAlignment()),
       justify_self_(ComputedStyle::InitialSelfAlignment()),
       page_size_type_(static_cast<unsigned>(PageSizeType::kAuto)),
-      transform_style3d_(ComputedStyle::InitialTransformStyle3D()),
+      transform_style_3d_(ComputedStyle::InitialTransformStyle3D()),
       backface_visibility_(ComputedStyle::InitialBackfaceVisibility()),
-      user_drag(ComputedStyle::InitialUserDrag()),
-      text_overflow(ComputedStyle::InitialTextOverflow()),
-      margin_before_collapse(kMarginCollapseCollapse),
-      margin_after_collapse(kMarginCollapseCollapse),
+      user_drag_(ComputedStyle::InitialUserDrag()),
+      text_overflow_(ComputedStyle::InitialTextOverflow()),
+      margin_before_collapse_(kMarginCollapseCollapse),
+      margin_after_collapse_(kMarginCollapseCollapse),
       appearance_(ComputedStyle::InitialAppearance()),
       text_decoration_style_(ComputedStyle::InitialTextDecorationStyle()),
       has_current_opacity_animation_(false),
@@ -135,13 +135,13 @@
 StyleRareNonInheritedData::StyleRareNonInheritedData(
     const StyleRareNonInheritedData& o)
     : RefCounted<StyleRareNonInheritedData>(),
-      opacity(o.opacity),
+      opacity_(o.opacity_),
       perspective_(o.perspective_),
       shape_image_threshold_(o.shape_image_threshold_),
       order_(o.order_),
       perspective_origin_(o.perspective_origin_),
       object_position_(o.object_position_),
-      line_clamp(o.line_clamp),
+      line_clamp_(o.line_clamp_),
       draggable_region_mode_(o.draggable_region_mode_),
       deprecated_flexible_box_(o.deprecated_flexible_box_),
       flexible_box_(o.flexible_box_),
@@ -184,12 +184,12 @@
       justify_items_(o.justify_items_),
       justify_self_(o.justify_self_),
       page_size_type_(o.page_size_type_),
-      transform_style3d_(o.transform_style3d_),
+      transform_style_3d_(o.transform_style_3d_),
       backface_visibility_(o.backface_visibility_),
-      user_drag(o.user_drag),
-      text_overflow(o.text_overflow),
-      margin_before_collapse(o.margin_before_collapse),
-      margin_after_collapse(o.margin_after_collapse),
+      user_drag_(o.user_drag_),
+      text_overflow_(o.text_overflow_),
+      margin_before_collapse_(o.margin_before_collapse_),
+      margin_after_collapse_(o.margin_after_collapse_),
       appearance_(o.appearance_),
       text_decoration_style_(o.text_decoration_style_),
       has_current_opacity_animation_(o.has_current_opacity_animation_),
@@ -225,10 +225,11 @@
 
 bool StyleRareNonInheritedData::operator==(
     const StyleRareNonInheritedData& o) const {
-  return opacity == o.opacity && perspective_ == o.perspective_ &&
+  return opacity_ == o.opacity_ && perspective_ == o.perspective_ &&
          shape_image_threshold_ == o.shape_image_threshold_ &&
          order_ == o.order_ && perspective_origin_ == o.perspective_origin_ &&
-         object_position_ == o.object_position_ && line_clamp == o.line_clamp &&
+         object_position_ == o.object_position_ &&
+         line_clamp_ == o.line_clamp_ &&
          draggable_region_mode_ == o.draggable_region_mode_ &&
          deprecated_flexible_box_ == o.deprecated_flexible_box_ &&
          flexible_box_ == o.flexible_box_ && multi_col_ == o.multi_col_ &&
@@ -265,11 +266,11 @@
          justify_items_ == o.justify_items_ &&
          justify_self_ == o.justify_self_ &&
          page_size_type_ == o.page_size_type_ &&
-         transform_style3d_ == o.transform_style3d_ &&
+         transform_style_3d_ == o.transform_style_3d_ &&
          backface_visibility_ == o.backface_visibility_ &&
-         user_drag == o.user_drag && text_overflow == o.text_overflow &&
-         margin_before_collapse == o.margin_before_collapse &&
-         margin_after_collapse == o.margin_after_collapse &&
+         user_drag_ == o.user_drag_ && text_overflow_ == o.text_overflow_ &&
+         margin_before_collapse_ == o.margin_before_collapse_ &&
+         margin_after_collapse_ == o.margin_after_collapse_ &&
          appearance_ == o.appearance_ &&
          text_decoration_style_ == o.text_decoration_style_ &&
          has_current_opacity_animation_ == o.has_current_opacity_animation_ &&
diff --git a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
index cef14d2..912ff09 100644
--- a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
+++ b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
@@ -86,7 +86,7 @@
     return !(*this == o);
   }
 
-  float opacity;  // Whether or not we're transparent.
+  float opacity_;  // Whether or not we're transparent.
 
   float perspective_;
   float shape_image_threshold_;
@@ -96,7 +96,7 @@
   LengthPoint perspective_origin_;
   LengthPoint object_position_;
 
-  LineClampValue line_clamp;  // An Apple extension.
+  LineClampValue line_clamp_;           // An Apple extension.
   unsigned draggable_region_mode_ : 2;  // DraggableRegionMode
 
   DataRef<StyleDeprecatedFlexibleBoxData>
@@ -159,14 +159,14 @@
   StyleSelfAlignmentData justify_self_;
 
   unsigned page_size_type_ : 2;       // PageSizeType
-  unsigned transform_style3d_ : 1;    // ETransformStyle3D
+  unsigned transform_style_3d_ : 1;   // ETransformStyle3D
   unsigned backface_visibility_ : 1;  // EBackfaceVisibility
 
-  unsigned user_drag : 2;      // EUserDrag
-  unsigned text_overflow : 1;  // Whether or not lines that spill out should be
-                               // truncated with "..."
-  unsigned margin_before_collapse : 2;  // EMarginCollapse
-  unsigned margin_after_collapse : 2;   // EMarginCollapse
+  unsigned user_drag_ : 2;      // EUserDrag
+  unsigned text_overflow_ : 1;  // Whether or not lines that spill out should be
+                                // truncated with "..."
+  unsigned margin_before_collapse_ : 2;  // EMarginCollapse
+  unsigned margin_after_collapse_ : 2;   // EMarginCollapse
   unsigned appearance_ : 6;             // EAppearance
 
   unsigned text_decoration_style_ : 3;  // TextDecorationStyle
diff --git a/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp b/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp
index 3f5a977..4ff8973 100644
--- a/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp
+++ b/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp
@@ -13,26 +13,9 @@
 #include "core/workers/WorkletPendingTasks.h"
 #include "platform/WebTaskRunner.h"
 #include "platform/wtf/WTF.h"
-#include "public/platform/WebURLRequest.h"
 
 namespace blink {
 
-namespace {
-
-WebURLRequest::FetchCredentialsMode ParseCredentialsOption(
-    const String& credentials_option) {
-  if (credentials_option == "omit")
-    return WebURLRequest::kFetchCredentialsModeOmit;
-  if (credentials_option == "same-origin")
-    return WebURLRequest::kFetchCredentialsModeSameOrigin;
-  if (credentials_option == "include")
-    return WebURLRequest::kFetchCredentialsModeInclude;
-  NOTREACHED();
-  return WebURLRequest::kFetchCredentialsModeOmit;
-}
-
-}  // namespace
-
 MainThreadWorklet::MainThreadWorklet(LocalFrame* frame) : Worklet(frame) {}
 
 WorkletGlobalScopeProxy* MainThreadWorklet::FindAvailableGlobalScope() const {
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorklet.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorklet.cpp
index 06b37398..7a873ded 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorklet.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorklet.cpp
@@ -9,16 +9,25 @@
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
+#include "core/dom/TaskRunnerHelper.h"
 #include "core/frame/LocalFrame.h"
 #include "core/workers/WorkletGlobalScopeProxy.h"
+#include "core/workers/WorkletPendingTasks.h"
+#include "platform/WebTaskRunner.h"
 #include "platform/wtf/WTF.h"
 
 namespace blink {
 
 ThreadedWorklet::ThreadedWorklet(LocalFrame* frame) : Worklet(frame) {}
 
+// Implementation of the second half of the "addModule(moduleURL, options)"
+// algorithm:
+// https://drafts.css-houdini.org/worklets/#dom-worklet-addmodule
+// TODO(nhiroki): MainThreadWorklet::FetchAndInvokeScript will be moved to the
+// parent class (i.e., Worklet) and this function will be replaced with it.
+// (https://crbug.com/727194)
 void ThreadedWorklet::FetchAndInvokeScript(const KURL& module_url_record,
-                                           const WorkletOptions&,
+                                           const WorkletOptions& options,
                                            ScriptPromiseResolver* resolver) {
   DCHECK(IsMainThread());
   if (!GetExecutionContext())
@@ -27,39 +36,60 @@
   if (!IsInitialized())
     Initialize();
 
-  WorkletScriptLoader* script_loader = WorkletScriptLoader::Create(
-      ToDocument(GetExecutionContext())->Fetcher(), this);
-  loader_to_resolver_map_.Set(script_loader, resolver);
-  script_loader->FetchScript(module_url_record);
-}
+  // Step 6: "Let credentialOptions be the credentials member of options."
+  // TODO(nhiroki): Add tests for credentialOptions (https://crbug.com/710837).
+  WebURLRequest::FetchCredentialsMode credentials_mode =
+      ParseCredentialsOption(options.credentials());
 
-void ThreadedWorklet::NotifyWorkletScriptLoadingFinished(
-    WorkletScriptLoader* script_loader,
-    const ScriptSourceCode& source_code) {
-  DCHECK(IsMainThread());
-  ScriptPromiseResolver* resolver = loader_to_resolver_map_.at(script_loader);
-  loader_to_resolver_map_.erase(script_loader);
+  // Step 7: "Let outsideSettings be the relevant settings object of this."
+  // In the specification, outsideSettings is used for posting a task to the
+  // document's responsible event loop. In our implementation, we use the
+  // document's UnspecedLoading task runner as that is what we commonly use for
+  // module loading.
+  RefPtr<WebTaskRunner> outside_settings_task_runner =
+      TaskRunnerHelper::Get(TaskType::kUnspecedLoading, GetExecutionContext());
 
-  if (!script_loader->WasScriptLoadSuccessful()) {
-    resolver->Reject(DOMException::Create(kNetworkError));
-    return;
-  }
+  // Step 8: "Let moduleResponsesMap be worklet's module responses map."
+  // TODO(nhiroki): Implement moduleResponsesMap (https://crbug.com/627945).
 
-  GetWorkletGlobalScopeProxy()->EvaluateScript(source_code);
-  resolver->Resolve();
+  // Step 9: "Let workletGlobalScopeType be worklet's worklet global scope
+  // type."
+  // workletGlobalScopeType is encoded into the class name (e.g., PaintWorklet).
+
+  // Step 10: "If the worklet's WorkletGlobalScopes is empty, run the following
+  // steps:"
+  //   10.1: "Create a WorkletGlobalScope given workletGlobalScopeType,
+  //          moduleResponsesMap, and outsideSettings."
+  //   10.2: "Add the WorkletGlobalScope to worklet's WorkletGlobalScopes."
+  // "Depending on the type of worklet the user agent may create additional
+  // WorkletGlobalScopes at this time."
+  // TODO(nhiroki): These steps will be supported after MainThreadWorklet and
+  // ThreadedWorklet are merged into Worklet (https://crbug.com/727194)
+
+  // Step 11: "Let pendingTaskStruct be a new pending tasks struct with counter
+  // initialized to the length of worklet's WorkletGlobalScopes."
+  const int kNumberOfGlobalScopes = 1;
+  WorkletPendingTasks* pending_tasks =
+      new WorkletPendingTasks(kNumberOfGlobalScopes, resolver);
+
+  // Step 12: "For each workletGlobalScope in the worklet's
+  // WorkletGlobalScopes, queue a task on the workletGlobalScope to fetch and
+  // invoke a worklet script given workletGlobalScope, moduleURLRecord,
+  // moduleResponsesMap, credentialOptions, outsideSettings, pendingTaskStruct,
+  // and promise."
+  // TODO(nhiroki): Queue a task instead of executing this here.
+  GetWorkletGlobalScopeProxy()->FetchAndInvokeScript(
+      module_url_record, credentials_mode,
+      std::move(outside_settings_task_runner), pending_tasks);
 }
 
 void ThreadedWorklet::ContextDestroyed(ExecutionContext* execution_context) {
   DCHECK(IsMainThread());
-  for (const auto& script_loader : loader_to_resolver_map_.Keys())
-    script_loader->Cancel();
-  loader_to_resolver_map_.clear();
   if (IsInitialized())
     GetWorkletGlobalScopeProxy()->TerminateWorkletGlobalScope();
 }
 
 DEFINE_TRACE(ThreadedWorklet) {
-  visitor->Trace(loader_to_resolver_map_);
   Worklet::Trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorklet.h b/third_party/WebKit/Source/core/workers/ThreadedWorklet.h
index e7a2921..297d997 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorklet.h
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorklet.h
@@ -9,7 +9,6 @@
 
 #include "bindings/core/v8/ScriptPromiseResolver.h"
 #include "core/CoreExport.h"
-#include "core/loader/WorkletScriptLoader.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
@@ -22,18 +21,13 @@
 // threaded worklets while module loading is being implemented for main thread
 // worklets. This and MainThreadWorklet will be merged into the base Worklet
 // class once threaded worklets are also ready to use module loading.
-class CORE_EXPORT ThreadedWorklet : public Worklet,
-                                    public WorkletScriptLoader::Client {
+class CORE_EXPORT ThreadedWorklet : public Worklet {
   USING_GARBAGE_COLLECTED_MIXIN(ThreadedWorklet);
   WTF_MAKE_NONCOPYABLE(ThreadedWorklet);
 
  public:
   virtual ~ThreadedWorklet() = default;
 
-  // WorkletScriptLoader::Client
-  void NotifyWorkletScriptLoadingFinished(WorkletScriptLoader*,
-                                          const ScriptSourceCode&) final;
-
   // ContextLifecycleObserver
   void ContextDestroyed(ExecutionContext*) final;
 
@@ -54,9 +48,6 @@
   // Called when addModule() is called for the first time.
   virtual void Initialize() = 0;
   virtual bool IsInitialized() const = 0;
-
-  HeapHashMap<Member<WorkletScriptLoader>, Member<ScriptPromiseResolver>>
-      loader_to_resolver_map_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.cpp
index cf38c7b..83d35477 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.cpp
@@ -19,6 +19,61 @@
 
 namespace blink {
 
+// TODO(nhiroki): This should be in sync with WorkletModuleTreeClient as much as
+// possible because this will be replaced with that when module loading is ready
+// for threaded worklets (https://crbug.com/727194).
+class ThreadedWorkletMessagingProxy::LoaderClient final
+    : public GarbageCollectedFinalized<
+          ThreadedWorkletMessagingProxy::LoaderClient>,
+      public WorkletScriptLoader::Client {
+  USING_GARBAGE_COLLECTED_MIXIN(LoaderClient);
+
+ public:
+  LoaderClient(RefPtr<WebTaskRunner> outside_settings_task_runner,
+               WorkletPendingTasks* pending_tasks,
+               ThreadedWorkletMessagingProxy* proxy)
+      : outside_settings_task_runner_(std::move(outside_settings_task_runner)),
+        pending_tasks_(pending_tasks),
+        proxy_(proxy) {}
+
+  // Implementation of the second half of the "fetch and invoke a worklet
+  // script" algorithm:
+  // https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script
+  void NotifyWorkletScriptLoadingFinished(
+      WorkletScriptLoader* loader,
+      const ScriptSourceCode& source_code) final {
+    DCHECK(IsMainThread());
+    proxy_->NotifyLoadingFinished(loader);
+
+    if (!loader->WasScriptLoadSuccessful()) {
+      // Step 3: "If script is null, then queue a task on outsideSettings's
+      // responsible event loop to run these steps:"
+      // The steps are implemented in WorkletPendingTasks::Abort().
+      outside_settings_task_runner_->PostTask(
+          BLINK_FROM_HERE, WTF::Bind(&WorkletPendingTasks::Abort,
+                                     WrapPersistent(pending_tasks_.Get())));
+      return;
+    }
+
+    // Step 4: "Run a module script given script."
+    proxy_->EvaluateScript(source_code);
+
+    // Step 5: "Queue a task on outsideSettings's responsible event loop to run
+    // these steps:"
+    // The steps are implemented in WorkletPendingTasks::DecrementCounter().
+    outside_settings_task_runner_->PostTask(
+        BLINK_FROM_HERE, WTF::Bind(&WorkletPendingTasks::DecrementCounter,
+                                   WrapPersistent(pending_tasks_.Get())));
+  }
+
+  DEFINE_INLINE_TRACE() { visitor->Trace(pending_tasks_); }
+
+ private:
+  RefPtr<WebTaskRunner> outside_settings_task_runner_;
+  Member<WorkletPendingTasks> pending_tasks_;
+  ThreadedWorkletMessagingProxy* proxy_;
+};
+
 ThreadedWorkletMessagingProxy::ThreadedWorkletMessagingProxy(
     ExecutionContext* execution_context)
     : ThreadedMessagingProxyBase(execution_context), weak_ptr_factory_(this) {
@@ -27,7 +82,7 @@
 }
 
 void ThreadedWorkletMessagingProxy::Initialize() {
-  DCHECK(IsParentContextThread());
+  DCHECK(IsMainThread());
   if (AskedToTerminate())
     return;
 
@@ -57,8 +112,36 @@
                                                  script_url);
 }
 
+void ThreadedWorkletMessagingProxy::FetchAndInvokeScript(
+    const KURL& module_url_record,
+    WebURLRequest::FetchCredentialsMode credentials_mode,
+    RefPtr<WebTaskRunner> outside_settings_task_runner,
+    WorkletPendingTasks* pending_tasks) {
+  DCHECK(IsMainThread());
+  LoaderClient* client = new LoaderClient(
+      std::move(outside_settings_task_runner), pending_tasks, this);
+  WorkletScriptLoader* loader = WorkletScriptLoader::Create(
+      ToDocument(GetExecutionContext())->Fetcher(), client);
+  loaders_.insert(loader);
+  loader->FetchScript(module_url_record);
+}
+
+void ThreadedWorkletMessagingProxy::TerminateWorkletGlobalScope() {
+  DCHECK(IsMainThread());
+  for (const auto& loader : loaders_)
+    loader->Cancel();
+  loaders_.clear();
+  TerminateGlobalScope();
+}
+
+void ThreadedWorkletMessagingProxy::NotifyLoadingFinished(
+    WorkletScriptLoader* loader) {
+  loaders_.erase(loader);
+}
+
 void ThreadedWorkletMessagingProxy::EvaluateScript(
     const ScriptSourceCode& script_source_code) {
+  DCHECK(IsMainThread());
   TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI, GetWorkerThread())
       ->PostTask(
           BLINK_FROM_HERE,
@@ -68,8 +151,4 @@
                           CrossThreadUnretained(GetWorkerThread())));
 }
 
-void ThreadedWorkletMessagingProxy::TerminateWorkletGlobalScope() {
-  TerminateGlobalScope();
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.h b/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.h
index 3e288c7..a096d09 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.h
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.h
@@ -6,12 +6,15 @@
 #define ThreadedWorkletMessagingProxy_h
 
 #include "core/CoreExport.h"
+#include "core/loader/WorkletScriptLoader.h"
 #include "core/workers/ThreadedMessagingProxyBase.h"
 #include "core/workers/WorkletGlobalScopeProxy.h"
+#include "core/workers/WorkletPendingTasks.h"
 #include "platform/wtf/WeakPtr.h"
 
 namespace blink {
 
+class ScriptSourceCode;
 class ThreadedWorkletObjectProxy;
 
 class CORE_EXPORT ThreadedWorkletMessagingProxy
@@ -19,7 +22,10 @@
       public WorkletGlobalScopeProxy {
  public:
   // WorkletGlobalScopeProxy implementation.
-  void EvaluateScript(const ScriptSourceCode&) final;
+  void FetchAndInvokeScript(const KURL& module_url_record,
+                            WebURLRequest::FetchCredentialsMode,
+                            RefPtr<WebTaskRunner> outside_settings_task_runner,
+                            WorkletPendingTasks*) final;
   void TerminateWorkletGlobalScope() final;
 
   void Initialize();
@@ -33,9 +39,15 @@
 
  private:
   friend class ThreadedWorkletMessagingProxyForTest;
+  class LoaderClient;
+
+  void NotifyLoadingFinished(WorkletScriptLoader*);
+  void EvaluateScript(const ScriptSourceCode&);
 
   std::unique_ptr<ThreadedWorkletObjectProxy> worklet_object_proxy_;
 
+  HashSet<Persistent<WorkletScriptLoader>> loaders_;
+
   WeakPtrFactory<ThreadedWorkletMessagingProxy> weak_ptr_factory_;
 };
 
diff --git a/third_party/WebKit/Source/core/workers/Worklet.cpp b/third_party/WebKit/Source/core/workers/Worklet.cpp
index 6620d822..deb56b048 100644
--- a/third_party/WebKit/Source/core/workers/Worklet.cpp
+++ b/third_party/WebKit/Source/core/workers/Worklet.cpp
@@ -62,6 +62,18 @@
   return promise;
 }
 
+WebURLRequest::FetchCredentialsMode Worklet::ParseCredentialsOption(
+    const String& credentials_option) {
+  if (credentials_option == "omit")
+    return WebURLRequest::kFetchCredentialsModeOmit;
+  if (credentials_option == "same-origin")
+    return WebURLRequest::kFetchCredentialsModeSameOrigin;
+  if (credentials_option == "include")
+    return WebURLRequest::kFetchCredentialsModeInclude;
+  NOTREACHED();
+  return WebURLRequest::kFetchCredentialsModeOmit;
+}
+
 DEFINE_TRACE(Worklet) {
   ContextLifecycleObserver::Trace(visitor);
 }
diff --git a/third_party/WebKit/Source/core/workers/Worklet.h b/third_party/WebKit/Source/core/workers/Worklet.h
index 7c2c2f2..690d9aa 100644
--- a/third_party/WebKit/Source/core/workers/Worklet.h
+++ b/third_party/WebKit/Source/core/workers/Worklet.h
@@ -11,6 +11,7 @@
 #include "core/workers/WorkletOptions.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
+#include "public/platform/WebURLRequest.h"
 
 namespace blink {
 
@@ -43,6 +44,9 @@
   // The Worklet inherits the url and userAgent from the frame->document().
   explicit Worklet(LocalFrame*);
 
+  static WebURLRequest::FetchCredentialsMode ParseCredentialsOption(
+      const String& credentials_option);
+
  private:
   virtual void FetchAndInvokeScript(const KURL& module_url_record,
                                     const WorkletOptions&,
diff --git a/third_party/WebKit/Source/core/workers/WorkletGlobalScopeProxy.h b/third_party/WebKit/Source/core/workers/WorkletGlobalScopeProxy.h
index 5fd7dec77..c26f9bf 100644
--- a/third_party/WebKit/Source/core/workers/WorkletGlobalScopeProxy.h
+++ b/third_party/WebKit/Source/core/workers/WorkletGlobalScopeProxy.h
@@ -12,7 +12,6 @@
 
 namespace blink {
 
-class ScriptSourceCode;
 class WorkletPendingTasks;
 
 // Abstracts communication from (Main/Threaded)Worklet on the main thread to
@@ -30,10 +29,6 @@
       RefPtr<WebTaskRunner> outside_settings_task_runner,
       WorkletPendingTasks*) {}
 
-  // Evaluates the given script source code. This should be called only for
-  // threaded worklets that still use classic script loading.
-  virtual void EvaluateScript(const ScriptSourceCode&) = 0;
-
   // Terminates the worklet global scope from the main thread.
   virtual void TerminateWorkletGlobalScope() = 0;
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js b/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
index fc8cf5f..9f0a6ad 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
@@ -46,7 +46,7 @@
 
     // Create drawer tabbed pane.
     this._drawerTabbedLocation =
-        UI.viewManager.createTabbedLocation(this._showDrawer.bind(this, false), 'drawer-view', true);
+        UI.viewManager.createTabbedLocation(this._showDrawer.bind(this, false), 'drawer-view', true, true);
     this._drawerTabbedLocation.enableMoreTabsButton();
     this._drawerTabbedPane = this._drawerTabbedLocation.tabbedPane();
     this._drawerTabbedPane.setMinimumSize(0, 27);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js b/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
index 2004274f..f237768 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
@@ -816,7 +816,7 @@
    * @param {number} index
    */
   _insertBefore(tab, index) {
-    this._tabsElement.insertBefore(tab._tabElement || null, this._tabsElement.childNodes[index]);
+    this._tabsElement.insertBefore(tab.tabElement, this._tabsElement.childNodes[index]);
     var oldIndex = this._tabs.indexOf(tab);
     this._tabs.splice(oldIndex, 1);
     if (oldIndex < index)
@@ -1081,7 +1081,6 @@
     tabElement.id = 'tab-' + this._id;
     UI.ARIAUtils.markAsTab(tabElement);
     UI.ARIAUtils.setSelected(tabElement, false);
-    tabElement.selectTabForTest = this._tabbedPane.selectTab.bind(this._tabbedPane, this.id, true);
 
     var titleElement = tabElement.createChild('span', 'tabbed-pane-header-tab-title');
     titleElement.textContent = this.title;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
index 678d1e9b..fc8404cb 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
@@ -45,6 +45,7 @@
     this._currentSuggestion = '';
     this._completionRequestId = 0;
     this._ghostTextElement = createElementWithClass('span', 'auto-complete-text');
+    this._ghostTextElement.setAttribute('contenteditable', 'false');
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/View.js b/third_party/WebKit/Source/devtools/front_end/ui/View.js
index 7343e1dc..3a7ce3ef 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/View.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/View.js
@@ -712,6 +712,16 @@
       }
     }
     this._appendTab(view, index);
+
+    if (view.isCloseable()) {
+      var tabs = this._closeableTabSetting.get();
+      var tabId = view.viewId();
+      if (!tabs[tabId]) {
+        tabs[tabId] = true;
+        this._closeableTabSetting.set(tabs);
+      }
+    }
+    this._persistTabOrder();
   }
 
   /**
@@ -750,17 +760,6 @@
     var tabId = /** @type {string} */ (event.data.tabId);
     if (this._lastSelectedTabSetting && event.data['isUserGesture'])
       this._lastSelectedTabSetting.set(tabId);
-    var view = this._views.get(tabId);
-    if (!view)
-      return;
-
-    if (view.isCloseable()) {
-      var tabs = this._closeableTabSetting.get();
-      if (!tabs[tabId]) {
-        tabs[tabId] = true;
-        this._closeableTabSetting.set(tabs);
-      }
-    }
   }
 
   /**
@@ -775,10 +774,7 @@
     }
   }
 
-  /**
-   * @param {!Common.Event} event
-   */
-  _persistTabOrder(event) {
+  _persistTabOrder() {
     var tabIds = this._tabbedPane.tabIds();
     var tabOrders = {};
     for (var i = 0; i < tabIds.length; i++)
diff --git a/third_party/WebKit/Source/modules/csspaint/PaintWorkletGlobalScopeProxy.cpp b/third_party/WebKit/Source/modules/csspaint/PaintWorkletGlobalScopeProxy.cpp
index 5a047fb..aaa6fe7 100644
--- a/third_party/WebKit/Source/modules/csspaint/PaintWorkletGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/modules/csspaint/PaintWorkletGlobalScopeProxy.cpp
@@ -40,13 +40,6 @@
                                       pending_tasks);
 }
 
-void PaintWorkletGlobalScopeProxy::EvaluateScript(
-    const ScriptSourceCode& script_source_code) {
-  // This should be called only for threaded worklets that still use classic
-  // script loading.
-  NOTREACHED();
-}
-
 void PaintWorkletGlobalScopeProxy::TerminateWorkletGlobalScope() {
   DCHECK(IsMainThread());
   global_scope_->Terminate();
diff --git a/third_party/WebKit/Source/modules/csspaint/PaintWorkletGlobalScopeProxy.h b/third_party/WebKit/Source/modules/csspaint/PaintWorkletGlobalScopeProxy.h
index f79293f..e6e81ad 100644
--- a/third_party/WebKit/Source/modules/csspaint/PaintWorkletGlobalScopeProxy.h
+++ b/third_party/WebKit/Source/modules/csspaint/PaintWorkletGlobalScopeProxy.h
@@ -30,7 +30,6 @@
                             WebURLRequest::FetchCredentialsMode,
                             RefPtr<WebTaskRunner> outside_settings_task_runner,
                             WorkletPendingTasks*) override;
-  void EvaluateScript(const ScriptSourceCode&) override;
   void TerminateWorkletGlobalScope() override;
 
   CSSPaintDefinition* FindDefinition(const String& name);
diff --git a/third_party/WebKit/Source/modules/imagecapture/ImageCapture.cpp b/third_party/WebKit/Source/modules/imagecapture/ImageCapture.cpp
index 13644c5..95506429 100644
--- a/third_party/WebKit/Source/modules/imagecapture/ImageCapture.cpp
+++ b/third_party/WebKit/Source/modules/imagecapture/ImageCapture.cpp
@@ -128,7 +128,7 @@
     resolver->Reject(DOMException::Create(kNotFoundError, kNoServiceError));
     return promise;
   }
-  service_requests_.insert(resolver);
+  service_requests_.insert(resolver, HeapVector<MediaTrackConstraintSet>());
 
   // m_streamTrack->component()->source()->id() is the renderer "name" of the
   // camera;
@@ -158,7 +158,7 @@
     resolver->Reject(DOMException::Create(kNotFoundError, kNoServiceError));
     return promise;
   }
-  service_requests_.insert(resolver);
+  service_requests_.insert(resolver, HeapVector<MediaTrackConstraintSet>());
 
   // TODO(mcasas): should be using a mojo::StructTraits instead.
   auto settings = media::mojom::blink::PhotoSettings::New();
@@ -233,7 +233,7 @@
     return promise;
   }
 
-  service_requests_.insert(resolver);
+  service_requests_.insert(resolver, HeapVector<MediaTrackConstraintSet>());
 
   // m_streamTrack->component()->source()->id() is the renderer "name" of the
   // camera;
@@ -294,10 +294,8 @@
     resolver->Reject(DOMException::Create(kNotFoundError, kNoServiceError));
     return;
   }
-  service_requests_.insert(resolver);
-
   // TODO(mcasas): add support more than one single advanced constraint.
-  const auto constraints = constraints_vector[0];
+  auto constraints = constraints_vector[0];
 
   if ((constraints.hasWhiteBalanceMode() &&
        !capabilities_.hasWhiteBalanceMode()) ||
@@ -501,6 +499,8 @@
 
   current_constraints_ = temp_constraints;
 
+  service_requests_.insert(resolver, constraints_vector);
+
   service_->SetOptions(
       stream_track_->Component()->Source()->Id(), std::move(settings),
       ConvertToBaseCallback(
@@ -637,7 +637,19 @@
     return;
   }
 
-  resolver->Resolve(photo_capabilities_);
+  // If this is a response to a SetMediaTrackConstraints() request, it will have
+  // the original constraints to apply: Resolve() with those; Resolve() with the
+  // |photo_capabilities_| otherwise.
+  const HeapVector<MediaTrackConstraintSet>& originalConstraints =
+      service_requests_.at(resolver);
+  if (originalConstraints.IsEmpty()) {
+    resolver->Resolve(photo_capabilities_);
+  } else {
+    MediaTrackConstraints constraints;
+    constraints.setAdvanced(originalConstraints);
+    resolver->Resolve(constraints);
+  }
+
   service_requests_.erase(resolver);
 }
 
@@ -778,8 +790,8 @@
 
 void ImageCapture::OnServiceConnectionError() {
   service_.reset();
-  for (ScriptPromiseResolver* resolver : service_requests_)
-    resolver->Reject(DOMException::Create(kNotFoundError, kNoServiceError));
+  for (const auto& resolver : service_requests_)
+    resolver.key->Reject(DOMException::Create(kNotFoundError, kNoServiceError));
   service_requests_.clear();
 }
 
diff --git a/third_party/WebKit/Source/modules/imagecapture/ImageCapture.h b/third_party/WebKit/Source/modules/imagecapture/ImageCapture.h
index 7f0056b..0e81c2c 100644
--- a/third_party/WebKit/Source/modules/imagecapture/ImageCapture.h
+++ b/third_party/WebKit/Source/modules/imagecapture/ImageCapture.h
@@ -102,7 +102,9 @@
 
   Member<PhotoCapabilities> photo_capabilities_;
 
-  HeapHashSet<Member<ScriptPromiseResolver>> service_requests_;
+  HeapHashMap<Member<ScriptPromiseResolver>,
+              HeapVector<MediaTrackConstraintSet>>
+      service_requests_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
index 950f06b2..e5e701a0 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
@@ -53,5 +53,8 @@
     [RuntimeEnabled=MediaTrackCapabilities] MediaTrackCapabilities getCapabilities();
     MediaTrackConstraints getConstraints();
     MediaTrackSettings getSettings();
-    [RuntimeEnabled=MediaTrackApplyConstraints, CallWith=ScriptState] Promise<void> applyConstraints(optional MediaTrackConstraints constraints);
+    // Spec resolves applyConstraints() with void, here we resolve with the
+    // applied MediaTrackConstraints instead:
+    // https://github.com/w3c/mediacapture-main/issues/462
+    [RuntimeEnabled=MediaTrackApplyConstraints, CallWith=ScriptState] Promise<MediaTrackConstraints> applyConstraints(optional MediaTrackConstraints constraints);
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.cpp b/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.cpp
index 1b2c73d..85fda7f 100644
--- a/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.cpp
@@ -31,6 +31,13 @@
 
 namespace blink {
 
+// FIXME: As a recursive linear filter, depending on its parameters, a biquad
+// filter can have an infinite tailTime. In practice, Biquad filters do not
+// usually (except for very high resonance values) have a tailTime of longer
+// than approx. 200ms. This value could possibly be calculated based on the
+// settings of the Biquad.
+static const double kMaxBiquadDelayTime = 0.2;
+
 void BiquadDSPKernel::UpdateCoefficientsIfNecessary(int frames_to_process) {
   if (GetBiquadProcessor()->FilterCoefficientsDirty()) {
     float cutoff_frequency[AudioUtilities::kRenderQuantumFrames];
@@ -114,23 +121,6 @@
         break;
     }
   }
-
-  UpdateTailTime(number_of_frames - 1);
-}
-
-void BiquadDSPKernel::UpdateTailTime(int coef_index) {
-  // A reasonable upper limit for the tail time.  While it's easy to
-  // create biquad filters whose tail time can be much larger than
-  // this, limit the maximum to this value so that we don't keep such
-  // nodes alive "forever".
-  // TODO: What is a reasonable upper limit?
-  const double kMaxTailTime = 30;
-
-  double sample_rate = SampleRate();
-  double tail =
-      biquad_.TailFrame(coef_index, kMaxTailTime * sample_rate) / sample_rate;
-
-  tail_time_ = clampTo(tail, 0.0, kMaxTailTime);
 }
 
 void BiquadDSPKernel::Process(const float* source,
@@ -209,7 +199,7 @@
 }
 
 double BiquadDSPKernel::TailTime() const {
-  return tail_time_;
+  return kMaxBiquadDelayTime;
 }
 
 double BiquadDSPKernel::LatencyTime() const {
diff --git a/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.h b/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.h
index 99069ef..efeb3eb0 100644
--- a/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.h
+++ b/third_party/WebKit/Source/modules/webaudio/BiquadDSPKernel.h
@@ -75,15 +75,8 @@
                           const float* detune);
 
  private:
-  // Compute the tail time using the BiquadFilter coefficients at
-  // index |coef_index|.
-  void UpdateTailTime(int coef_index);
-
   // Synchronize process() with getting and setting the filter coefficients.
   mutable Mutex process_lock_;
-
-  // The current tail time for biquad filter.
-  double tail_time_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/Biquad.cpp b/third_party/WebKit/Source/platform/audio/Biquad.cpp
index 8505bda..64d6b26 100644
--- a/third_party/WebKit/Source/platform/audio/Biquad.cpp
+++ b/third_party/WebKit/Source/platform/audio/Biquad.cpp
@@ -591,298 +591,4 @@
   }
 }
 
-static double RepeatedRootResponse(double n,
-                                   double c1,
-                                   double c2,
-                                   double r,
-                                   double log_eps) {
-  // The response is h(n) = r^(n-2)*[c1*(n+1)*r^2+c2]. We're looking
-  // for n such that |h(n)| = eps.  Equivalently, we want a root
-  // of the equation log(|h(n)|) - log(eps) = 0 or
-  //
-  //   (n-2)*log(r) + log(|c1*(n+1)*r^2+c2|) - log(eps)
-  //
-  // This helps with finding a nuemrical solution because this
-  // approximately linearizes the response for large n.
-
-  return (n - 2) * log(r) + log(fabs(c1 * (n + 1) * r * r + c2)) - log_eps;
-}
-
-// Regula Falsi root finder, Illinois variant
-// (https://en.wikipedia.org/wiki/False_position_method#The_Illinois_algorithm).
-//
-// This finds a root of the repeated root response where the root is
-// assumed to lie between |low| and |high|.  The response is given by
-// |c1|, |c2|, and |r| as determined by |RepeatedRootResponse|.
-// |log_eps| is the log the the maximum allowed amplitude in the
-// response.
-static double RootFinder(double low,
-                         double high,
-                         double log_eps,
-                         double c1,
-                         double c2,
-                         double r) {
-  // Desired accuray of the root (in frames).  This doesn't need to be
-  // super-accurate, so half frame is good enough, and should be less
-  // than 1 because the algorithm may prematurely terminate.
-  const double kAccuracyThreshold = 0.5;
-  // Max number of iterations to do.  If we haven't converged by now,
-  // just return whatever we've found.
-  const int kMaxIterations = 10;
-
-  int side = 0;
-  double root = 0;
-  double f_low = RepeatedRootResponse(low, c1, c2, r, log_eps);
-  double f_high = RepeatedRootResponse(high, c1, c2, r, log_eps);
-
-  // The function values must be finite and have opposite signs!
-  DCHECK(std::isfinite(f_low));
-  DCHECK(std::isfinite(f_high));
-  DCHECK_LE(f_low * f_high, 0);
-
-  int iteration;
-  for (iteration = 0; iteration < kMaxIterations; ++iteration) {
-    root = (f_low * high - f_high * low) / (f_low - f_high);
-    if (fabs(high - low) < kAccuracyThreshold * fabs(high + low))
-      break;
-    double fr = RepeatedRootResponse(root, c1, c2, r, log_eps);
-
-    DCHECK(std::isfinite(fr));
-
-    if (fr * f_high > 0) {
-      // fr and f_high have same sign.  Copy root to f_high
-      high = root;
-      f_high = fr;
-      side = -1;
-    } else if (f_low * fr > 0) {
-      // fr and f_low have same sign. Copy root to f_low
-      low = root;
-      f_low = fr;
-      if (side == 1)
-        f_high /= 2;
-      side = 1;
-    } else {
-      // f_low * fr looks like zero, so assume we've converged.
-      break;
-    }
-  }
-
-  // Want to know if the max number of iterations is ever exceeded so
-  // we can understand why that happened.
-  DCHECK_LT(iteration, kMaxIterations);
-
-  return root;
-}
-
-double Biquad::TailFrame(int coef_index, double max_frame) {
-  // The Biquad filter is given by
-  //
-  //   H(z) = (b0 + b1/z + b2/z^2)/(1 + a1/z + a2/z^2).
-  //
-  // To compute the tail time, compute the impulse response, h(n), of
-  // H(z), which we can do analytically.  From this impulse response,
-  // find the value n0 where |h(n)| <= eps for n >= n0.
-  //
-  // Assume first that the two poles of H(z) are not repeated, say r1
-  // and r2.  Then, we can compute a partial fraction expansion of
-  // H(z):
-  //
-  //   H(z) = (b0+b1/z+b2/z^2)/[(1-r1/z)*(1-r2/z)]
-  //        = b0 + C2/(z-r2) - C1/(z-r1)
-  //
-  //  where
-  //    C2 = (b0*r2^2+b1*r2+b2)/(r2-r1)
-  //    C1 = (b0*r1^2+b1*r1+b2)/(r2-r1)
-  //
-  // Expand H(z) then this in powers of 1/z gives:
-  //
-  //   H(z) = b0 -(C2/r2+C1/r1) + sum(C2*r2^(i-1)/z^i + C1*r1^(i-1)/z^i)
-  //
-  // Thus, for n > 1 (we don't care about small n),
-  //
-  //   h(n) = C2*r2^(n-1) + C1*r1^(n-1)
-  //
-  // We need to find n0 such that |h(n)| < eps for n > n0.
-  //
-  // Case 1: r1 and r2 are real and distinct, with |r1|>=|r2|.
-  //
-  // Then
-  //
-  //   h(n) = C1*r1^(n-1)*(1 + C2/C1*(r2/r1)^(n-1))
-  //
-  // so
-  //
-  //   |h(n)| = |C1|*|r|^(n-1)*|1+C2/C1*(r2/r1)^(n-1)|
-  //          <= |C1|*|r|^(n-1)*[1 + |C2/C1|*|r2/r1|^(n-1)]
-  //          <= |C1|*|r|^(n-1)*[1 + |C2/C1|]
-  //
-  // by using the triangle inequality and the fact that |r2|<=|r1|.
-  // And we want |h(n)|<=eps which is true if
-  //
-  //   |C1|*|r|^(n-1)*[1 + |C2/C1|] <= eps
-  //
-  // or
-  //
-  //   n >= 1 + log(eps/C)/log(|r1|)
-  //
-  // where C = |C1|*[1+|C2/C1|] = |C1| + |C2|.
-  //
-  // Case 2: r1 and r2 are complex
-  //
-  // Thne we can write r1=r*exp(i*p) and r2=r*exp(-i*p).  So,
-  //
-  //   |h(n)| = |C2*r^(n-1)*exp(-i*p*(n-1)) + C1*r^(n-1)*exp(i*p*(n-1))|
-  //          = |C1|*r^(n-1)*|1 + C2/C1*exp(-i*p*(n-1))/exp(i*n*(n-1))|
-  //          <= |C1|*r^(n-1)*[1 + |C2/C1|]
-  //
-  // Again, this is easily solved to give
-  //
-  //   n >= 1 + log(eps/C)/log(r)
-  //
-  // where C = |C1|*[1+|C2/C1|] = |C1| + |C2|.
-  //
-  // Case 3: Repeated roots, r1=r2=r.
-  //
-  // In this case,
-  //
-  //   H(z) = (b0+b1/z+b2/z^2)/[(1-r/z)^2
-  //
-  // Expanding this in powers of 1/z gives:
-  //
-  //   H(z) = C1*sum((i+1)*r^i/z^i) - C2 * sum(r^(i-2)/z^i) + b2/r^2
-  //        = b2/r^2 + sum([C1*(i+1)*r^i + C2*r^(i-2)]/z^i)
-  // where
-  //   C1 = (b0*r^2+b1*r+b2)/r^2
-  //   C2 = b1*r+2*b2
-  //
-  // Thus, the impulse response is
-  //
-  //   h(n) = C1*(n+1)*r^n + C2*r^(n-2)
-  //        = r^(n-2)*[C1*(n+1)*r^2+C2]
-  //
-  // So
-  //
-  //   |h(n)| = |r|^(n-2)*|C1*(n+1)*r^2+C2|
-  //
-  // To find n such that |h(n)| < eps, we need a numerical method in
-  // general, so there's no real reason to simplify this or use other
-  // approximations.  Just solve |h(n)|=eps directly.
-  //
-  // Thus, for an set of filter coefficients, we can compute the tail
-  // time.
-  //
-
-  // If the maximum amplitude of the impulse response is less than
-  // this, we assume that we've reached the tail of the response.
-  // Currently, this means that the impulse is less than 1 bit of a
-  // 16-bit PCM value.
-  const double kMaxTailAmplitude = 1 / 32768.0;
-
-  // Find the roots of 1+a1/z+a2/z^2 = 0.  Or equivalently,
-  // z^2+a1*z+a2 = 0.  From the quadratic formula the roots are
-  // (-a1+/-sqrt(a1^2-4*a2))/2.
-
-  double a1 = a1_[coef_index];
-  double a2 = a2_[coef_index];
-  double b0 = b0_[coef_index];
-  double b1 = b1_[coef_index];
-  double b2 = b2_[coef_index];
-
-  double tail_frame = 0;
-  double discrim = a1 * a1 - 4 * a2;
-
-  if (discrim > 0) {
-    // Compute the real roots so that r1 has the largest magnitude.
-    double r1;
-    double r2;
-    if (a1 < 0) {
-      r1 = (-a1 + sqrt(discrim)) / 2;
-    } else {
-      r1 = (-a1 - sqrt(discrim)) / 2;
-    }
-    r2 = a2 / r1;
-
-    double c1 = (b0 * r1 * r1 + b1 * r1 + b2) / (r2 - r1);
-    double c2 = (b0 * r2 * r2 + b1 * r2 + b2) / (r2 - r1);
-
-    DCHECK(std::isfinite(r1));
-    DCHECK(std::isfinite(r2));
-    DCHECK(std::isfinite(c1));
-    DCHECK(std::isfinite(c2));
-
-    // It's possible for kMaxTailAmplitude to be greater than c1 + c2.
-    // This may produce a negative tail frame.  Just clamp the tail
-    // frame to 0.
-    tail_frame = clampTo(
-        1 + log(kMaxTailAmplitude / (fabs(c1) + fabs(c2))) / log(r1), 0);
-
-    DCHECK(std::isfinite(tail_frame));
-  } else if (discrim < 0) {
-    // Two complex roots.
-    // One root is -a1/2 + i*sqrt(-discrim)/2.
-    double x = -a1 / 2;
-    double y = sqrt(-discrim) / 2;
-    std::complex<double> r1(x, y);
-    std::complex<double> r2(x, -y);
-    double r = hypot(x, y);
-
-    DCHECK(std::isfinite(r));
-
-    // It's possible for r to be 1. (LPF with Q very large can cause this.)
-    if (r == 1) {
-      tail_frame = max_frame;
-    } else {
-      double c1 = abs((b0 * r1 * r1 + b1 * r1 + b2) / (r2 - r1));
-      double c2 = abs((b0 * r2 * r2 + b1 * r2 + b2) / (r2 - r1));
-
-      DCHECK(std::isfinite(c1));
-      DCHECK(std::isfinite(c2));
-
-      tail_frame = 1 + log(kMaxTailAmplitude / (c1 + c2)) / log(r);
-      DCHECK(std::isfinite(tail_frame));
-    }
-  } else {
-    // Repeated roots.  This should be pretty rare because all the
-    // coefficients need to be just the right values to get a
-    // discriminant of exactly zero.
-    double r = -a1 / 2;
-
-    if (r == 0) {
-      // Double pole at 0.  This just delays the signal by 2 frames,
-      // so set the tail frame to 2.
-      tail_frame = 2;
-    } else {
-      double c1 = (b0 * r * r + b1 * r + b2) / (r * r);
-      double c2 = b1 * r + 2 * b2;
-
-      DCHECK(std::isfinite(c1));
-      DCHECK(std::isfinite(c2));
-
-      // It can happen that c1=c2=0.  This basically means that H(z) =
-      // constant, which is the limiting case for several of the
-      // biquad filters.
-      if (c1 == 0 && c2 == 0) {
-        tail_frame = 0;
-      } else {
-        // The function c*(n+1)*r^n is not monotonic, but it's easy to
-        // find the max point since the derivative is
-        // c*r^n*(1+(n+1)*log(r)).  This has a root at
-        // -(1+log(r))/log(r). so we can start our search from that
-        // point to max_frames.
-
-        double low = clampTo(-(1 + log(r)) / log(r), 1.0,
-                             static_cast<double>(max_frame - 1));
-        double high = max_frame;
-
-        DCHECK(std::isfinite(low));
-        DCHECK(std::isfinite(high));
-
-        tail_frame = RootFinder(low, high, log(kMaxTailAmplitude), c1, c2, r);
-      }
-    }
-  }
-
-  return tail_frame;
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/Biquad.h b/third_party/WebKit/Source/platform/audio/Biquad.h
index 9d51ba3..7a6bde19 100644
--- a/third_party/WebKit/Source/platform/audio/Biquad.h
+++ b/third_party/WebKit/Source/platform/audio/Biquad.h
@@ -70,13 +70,6 @@
   // Resets filter state
   void Reset();
 
-  // Compute tail frame based on the filter coefficents at index
-  // |coef_index|.  The tail frame is the frame number where the
-  // impulse response of the filter falls below a threshold value.
-  // The maximum allowed frame value is given by |max_frame|.  This
-  // limits how much work is done in computing the frame numer.
-  double TailFrame(int coef_index, double max_frame);
-
   // Filter response at a set of n frequencies. The magnitude and
   // phase response are returned in magResponse and phaseResponse.
   // The phase response is in radians.
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
index 33fbe792d..3af733ca 100644
--- a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
+++ b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
@@ -391,7 +391,7 @@
 }
 
 unsigned LazyLineBreakIterator::NextBreakOpportunity(unsigned offset) const {
-  int next_break = 0;
+  int next_break = -1;
   IsBreakable(offset, next_break);
   return next_break;
 }
@@ -400,8 +400,7 @@
                                                          unsigned min) const {
   unsigned pos = std::min(offset, string_.length());
   for (; pos > min; pos--) {
-    int next_break = 0;
-    if (IsBreakable(pos, next_break))
+    if (IsBreakable(pos))
       return pos;
   }
   return min;
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIterator.h b/third_party/WebKit/Source/platform/text/TextBreakIterator.h
index 88b63e5..3a587a5 100644
--- a/third_party/WebKit/Source/platform/text/TextBreakIterator.h
+++ b/third_party/WebKit/Source/platform/text/TextBreakIterator.h
@@ -217,6 +217,11 @@
     return IsBreakable(pos, next_breakable, break_type_);
   }
 
+  inline bool IsBreakable(int pos) const {
+    int next_breakable = -1;
+    return IsBreakable(pos, next_breakable, break_type_);
+  }
+
   // Returns the break opportunity at or after |offset|.
   unsigned NextBreakOpportunity(unsigned offset) const;
 
diff --git a/tools/checkteamtags/checkteamtags.py b/tools/checkteamtags/checkteamtags.py
index c06c354..02bbe516 100755
--- a/tools/checkteamtags/checkteamtags.py
+++ b/tools/checkteamtags/checkteamtags.py
@@ -90,9 +90,11 @@
     error_message = 'The component "%s" has more than one team: ' % component
     team_details = []
     for team in teams:
+      offending_dirs = [d for d in team_to_dir[team]
+                        if new_dir_to_component[d] == component]
       team_details.append('%(team)s is used in %(paths)s' % {
           'team': team,
-          'paths': ', '.join(team_to_dir[team]),
+          'paths': ', '.join(offending_dirs),
       })
     error_message += '; '.join(team_details)
     result.append({
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index cb0382b..b107d9bd 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -21554,6 +21554,7 @@
   <int value="-2040471724" label="CrOSComponent:disabled"/>
   <int value="-2040115518" label="load-media-router-component-extension"/>
   <int value="-2036149591" label="FaviconsFromWebManifest:disabled"/>
+  <int value="-2035126988" label="enabled-new-style-notification"/>
   <int value="-2033225430" label="NTPMostLikelyFaviconsFromServer:disabled"/>
   <int value="-2029912304" label="StaleWhileRevalidate2:enabled"/>
   <int value="-2025367104" label="enable-material-design-ntp"/>
@@ -22207,6 +22208,7 @@
   <int value="334802038" label="OfflinePreviews:disabled"/>
   <int value="346711293" label="enable-save-password-bubble"/>
   <int value="348854923" label="v8-cache-strategies-for-cache-storage"/>
+  <int value="352191859" label="disabled-new-style-notification"/>
   <int value="358399482" label="enable-high-dpi-fixed-position-compositing"/>
   <int value="358493847" label="BackgroundLoader:disabled"/>
   <int value="360391863" label="NTPOfflineBadge:enabled"/>
@@ -23691,9 +23693,16 @@
   <int value="0" label="Neutral (deprecated February 2017)"/>
   <int value="1" label="Non-Secure"/>
   <int value="2" label="Neutral with a verbose warning on sensitive fields"/>
+  <int value="3" label="Neutral with a verbose warning after editing a form"/>
+  <int value="4" label="Neutral with a verbose warning in Incognito mode"/>
+  <int value="5" label="Neutral with a verbose warning after editing a form or
+      in Incognito mode"/>
 </enum>
 
 <enum name="MarkNonSecureAsStatus" type="int">
+  <obsolete>
+    Deprecated 09/2016 and replaced with MarkHttpAsStatus.
+  </obsolete>
   <int value="0" label="Neutral"/>
   <int value="1" label="Dubious (deprecated August 2015)"/>
   <int value="2" label="Non-Secure"/>
@@ -35140,6 +35149,7 @@
   <int value="7" label="Sites"/>
   <int value="8" label="Sync"/>
   <int value="9" label="WebApk"/>
+  <int value="10" label="Browser Actions"/>
 </enum>
 
 <enum name="TabBackgroundLoadStatus" type="int">
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py
index 582dc53..cd7fb321 100644
--- a/tools/perf/page_sets/webrtc_cases.py
+++ b/tools/perf/page_sets/webrtc_cases.py
@@ -152,7 +152,3 @@
     self.DisableStory('audio_call_isac/1600_10s',
                       [story.expectations.ALL],
                       'crbug.com/468732')
-
-    self.DisableStory('30s_datachannel_transfer',
-                      [story.expectations.ALL_DESKTOP],
-                      'crbug.com/726811')
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 44af7cd..603f69a 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -550,8 +550,6 @@
   return E_FAIL;
 }
 
-// IAccessible functions not supported.
-
 STDMETHODIMP AXPlatformNodeWin::get_accSelection(VARIANT* selected) {
   COM_OBJECT_VALIDATE_1_ARG(selected);
   if (selected)
@@ -561,7 +559,17 @@
 
 STDMETHODIMP AXPlatformNodeWin::accSelect(
     LONG flagsSelect, VARIANT var_id) {
-  return E_NOTIMPL;
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_AND_GET_TARGET(var_id, target);
+
+  if (flagsSelect & SELFLAG_TAKEFOCUS) {
+    ui::AXActionData action_data;
+    action_data.action = ui::AX_ACTION_FOCUS;
+    target->delegate_->AccessibilityPerformAction(action_data);
+    return S_OK;
+  }
+
+  return S_FALSE;
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_accHelpTopic(
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index ce45400..dd99897 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -140,8 +140,6 @@
       "views/search_result_actions_view.cc",
       "views/search_result_actions_view.h",
       "views/search_result_actions_view_delegate.h",
-      "views/search_result_answer_card_view.cc",
-      "views/search_result_answer_card_view.h",
       "views/search_result_container_view.cc",
       "views/search_result_container_view.h",
       "views/search_result_list_view.cc",
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index bb8218b..aad1125 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -17,23 +17,56 @@
 #include "ui/app_list/views/apps_grid_view.h"
 #include "ui/app_list/views/custom_launcher_page_view.h"
 #include "ui/app_list/views/search_box_view.h"
-#include "ui/app_list/views/search_result_answer_card_view.h"
 #include "ui/app_list/views/search_result_list_view.h"
 #include "ui/app_list/views/search_result_page_view.h"
 #include "ui/app_list/views/search_result_tile_item_list_view.h"
 #include "ui/app_list/views/start_page_view.h"
 #include "ui/events/event.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/view_model.h"
 #include "ui/views/widget/widget.h"
 
 namespace app_list {
 
+namespace {
+
+// Container of the search answer view.
+class SearchAnswerContainerView : public views::View {
+ public:
+  explicit SearchAnswerContainerView(views::View* search_results_page_view)
+      : search_results_page_view_(search_results_page_view) {
+    views::BoxLayout* answer_container_layout =
+        new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
+    answer_container_layout->set_main_axis_alignment(
+        views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
+    SetLayoutManager(answer_container_layout);
+  }
+
+  // views::View overrides:
+  void ChildPreferredSizeChanged(View* child) override {
+    if (visible())
+      search_results_page_view_->Layout();
+  }
+
+  const char* GetClassName() const override {
+    return "SearchAnswerContainerView";
+  }
+
+ private:
+  views::View* const search_results_page_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(SearchAnswerContainerView);
+};
+
+}  // namespace
+
 ContentsView::ContentsView(AppListMainView* app_list_main_view)
     : model_(nullptr),
       apps_container_view_(nullptr),
       search_results_page_view_(nullptr),
       start_page_view_(nullptr),
       custom_page_view_(nullptr),
+      search_answer_container_view_(nullptr),
       app_list_main_view_(app_list_main_view),
       page_before_search_(0) {
   pagination_model_.SetTransitionDurations(kPageTransitionDurationInMs,
@@ -43,6 +76,8 @@
 
 ContentsView::~ContentsView() {
   pagination_model_.RemoveObserver(this);
+  if (model_)
+    model_->RemoveObserver(this);
 }
 
 void ContentsView::Init(AppListModel* model) {
@@ -69,14 +104,14 @@
   // Search results UI.
   search_results_page_view_ = new SearchResultPageView();
 
-  // Search result containers.
-  views::View* const search_answer_view =
-      view_delegate->GetSearchAnswerWebView();
-  if (search_answer_view) {
-    search_results_page_view_->AddSearchResultContainerView(
-        nullptr, new SearchResultAnswerCardView(
-                     model_, search_results_page_view_, search_answer_view));
-  }
+  // Search answer container UI.
+  search_answer_container_view_ =
+      new SearchAnswerContainerView(search_results_page_view_);
+  search_answer_container_view_->SetVisible(false);
+  views::View* search_answer_view = view_delegate->GetSearchAnswerWebView();
+  if (search_answer_view)
+    search_answer_container_view_->AddChildView(search_answer_view);
+  search_results_page_view_->AddChildView(search_answer_container_view_);
 
   AppListModel::SearchResults* results = view_delegate->GetModel()->results();
   search_results_page_view_->AddSearchResultContainerView(
@@ -107,6 +142,8 @@
   pagination_model_.SelectPage(initial_page_index, false);
 
   ActivePageChanged();
+
+  model_->AddObserver(this);
 }
 
 void ContentsView::CancelDrag() {
@@ -487,4 +524,12 @@
   UpdatePageBounds();
 }
 
+void ContentsView::OnSearchAnswerAvailableChanged(bool has_answer) {
+  if (has_answer == search_answer_container_view_->visible())
+    return;
+
+  search_answer_container_view_->SetVisible(has_answer);
+  search_results_page_view_->Layout();
+}
+
 }  // namespace app_list
diff --git a/ui/app_list/views/contents_view.h b/ui/app_list/views/contents_view.h
index 62a52cd2..435ff00 100644
--- a/ui/app_list/views/contents_view.h
+++ b/ui/app_list/views/contents_view.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "ui/app_list/app_list_export.h"
 #include "ui/app_list/app_list_model.h"
+#include "ui/app_list/app_list_model_observer.h"
 #include "ui/app_list/pagination_model.h"
 #include "ui/app_list/pagination_model_observer.h"
 #include "ui/views/view.h"
@@ -42,7 +43,8 @@
 // interface for switching between launcher pages, and animates the transition
 // between them.
 class APP_LIST_EXPORT ContentsView : public views::View,
-                                     public PaginationModelObserver {
+                                     public PaginationModelObserver,
+                                     public AppListModelObserver {
  public:
   explicit ContentsView(AppListMainView* app_list_main_view);
   ~ContentsView() override;
@@ -134,6 +136,9 @@
   void TransitionStarted() override;
   void TransitionChanged() override;
 
+  // Overridden from AppListModelObserver:
+  void OnSearchAnswerAvailableChanged(bool has_answer) override;
+
  private:
   // Sets the active launcher page, accounting for whether the change is for
   // search results.
@@ -185,6 +190,10 @@
   StartPageView* start_page_view_;
   CustomLauncherPageView* custom_page_view_;
 
+  // Unowned pointer to the container of the search answer web view. This
+  // container view is a sub-view of search_results_page_view_.
+  View* search_answer_container_view_;
+
   // The child page views. Owned by the views hierarchy.
   std::vector<AppListPage*> app_list_pages_;
 
diff --git a/ui/app_list/views/search_result_answer_card_view.cc b/ui/app_list/views/search_result_answer_card_view.cc
deleted file mode 100644
index 89078c0..0000000
--- a/ui/app_list/views/search_result_answer_card_view.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/app_list/views/search_result_answer_card_view.h"
-
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_features.h"
-#include "ui/app_list/views/search_result_page_view.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/button/custom_button.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/fill_layout.h"
-
-namespace app_list {
-
-namespace {
-
-// Answer card relevance is high to always have it first.
-constexpr double kSearchAnswerCardRelevance = 100;
-
-// Container of the search answer view.
-class SearchAnswerContainerView : public views::CustomButton {
- public:
-  explicit SearchAnswerContainerView(views::View* search_results_page_view)
-      : CustomButton(nullptr),
-        search_results_page_view_(search_results_page_view) {
-    // Center the card horizontally in the container.
-    views::BoxLayout* answer_container_layout =
-        new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
-    answer_container_layout->set_main_axis_alignment(
-        views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
-    SetLayoutManager(answer_container_layout);
-  }
-
-  void SetSelected(bool selected) {
-    if (selected == selected_)
-      return;
-    selected_ = selected;
-    UpdateBackgroundColor();
-  }
-
-  // views::CustomButton overrides:
-  void ChildPreferredSizeChanged(View* child) override {
-    // Card size changed.
-    if (visible())
-      search_results_page_view_->Layout();
-  }
-
-  int GetHeightForWidth(int w) const override {
-    return visible() ? CustomButton::GetHeightForWidth(w) : 0;
-  }
-
-  const char* GetClassName() const override {
-    return "SearchAnswerContainerView";
-  }
-
-  void StateChanged(ButtonState old_state) override { UpdateBackgroundColor(); }
-
- private:
-  void UpdateBackgroundColor() {
-    views::Background* background = nullptr;
-
-    if (selected_) {
-      background = views::Background::CreateSolidBackground(kSelectedColor);
-    } else if (state() == STATE_HOVERED || state() == STATE_PRESSED) {
-      background = views::Background::CreateSolidBackground(kHighlightedColor);
-    }
-
-    set_background(background);
-    SchedulePaint();
-  }
-
-  views::View* const search_results_page_view_;
-  bool selected_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(SearchAnswerContainerView);
-};
-
-}  // namespace
-
-SearchResultAnswerCardView::SearchResultAnswerCardView(
-    AppListModel* model,
-    SearchResultPageView* search_results_page_view,
-    views::View* search_answer_view)
-    : model_(model),
-      search_answer_container_view_(
-          new SearchAnswerContainerView(search_results_page_view)) {
-  search_answer_container_view_->SetVisible(false);
-  search_answer_container_view_->AddChildView(search_answer_view);
-  AddChildView(search_answer_container_view_);
-  model->AddObserver(this);
-  SetLayoutManager(new views::FillLayout);
-}
-
-SearchResultAnswerCardView::~SearchResultAnswerCardView() {
-  model_->RemoveObserver(this);
-}
-
-const char* SearchResultAnswerCardView::GetClassName() const {
-  return "SearchResultAnswerCardView";
-}
-
-void SearchResultAnswerCardView::OnContainerSelected(
-    bool from_bottom,
-    bool directional_movement) {
-  if (num_results() == 0)
-    return;
-
-  SetSelectedIndex(0);
-}
-
-int SearchResultAnswerCardView::GetYSize() {
-  return num_results();
-}
-
-int SearchResultAnswerCardView::DoUpdate() {
-  const bool have_result = search_answer_container_view_->visible();
-  set_container_score(have_result ? kSearchAnswerCardRelevance : 0);
-  return have_result ? 1 : 0;
-}
-
-void SearchResultAnswerCardView::UpdateSelectedIndex(int old_selected,
-                                                     int new_selected) {
-  if (new_selected == old_selected)
-    return;
-
-  const bool is_selected = new_selected == 0;
-  search_answer_container_view_->SetSelected(is_selected);
-  if (is_selected)
-    NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
-}
-
-void SearchResultAnswerCardView::OnSearchAnswerAvailableChanged(
-    bool has_answer) {
-  const bool visible = has_answer && !features::IsAnswerCardDarkRunEnabled();
-  if (visible == search_answer_container_view_->visible())
-    return;
-
-  search_answer_container_view_->SetVisible(visible);
-  ScheduleUpdate();
-}
-
-}  // namespace app_list
diff --git a/ui/app_list/views/search_result_answer_card_view.h b/ui/app_list/views/search_result_answer_card_view.h
deleted file mode 100644
index 8c985f0..0000000
--- a/ui/app_list/views/search_result_answer_card_view.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_
-#define UI_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_
-
-#include "ui/app_list/app_list_model_observer.h"
-#include "ui/app_list/views/search_result_container_view.h"
-
-namespace app_list {
-
-class AppListModel;
-class SearchResultPageView;
-
-namespace {
-class SearchAnswerContainerView;
-}
-
-// Result container for the search answer card.
-class APP_LIST_EXPORT SearchResultAnswerCardView
-    : public SearchResultContainerView,
-      public AppListModelObserver {
- public:
-  SearchResultAnswerCardView(AppListModel* model,
-                             SearchResultPageView* search_results_page_view,
-                             views::View* search_answer_view);
-  ~SearchResultAnswerCardView() override;
-
- private:
-  // Overridden from views::View:
-  const char* GetClassName() const override;
-
-  // Overridden from SearchResultContainerView:
-  void OnContainerSelected(bool from_bottom,
-                           bool directional_movement) override;
-  void NotifyFirstResultYIndex(int y_index) override {}
-  int GetYSize() override;
-  int DoUpdate() override;
-  void UpdateSelectedIndex(int old_selected, int new_selected) override;
-
-  // Overridden from AppListModelObserver
-  void OnSearchAnswerAvailableChanged(bool has_answer) override;
-
-  // Unowned pointer to application list model.
-  AppListModel* const model_;
-
-  // Pointer to the container of the search answer; owned by the view hierarchy.
-  // It's visible iff we have a search answer result.
-  SearchAnswerContainerView* const search_answer_container_view_;
-
-  DISALLOW_COPY_AND_ASSIGN(SearchResultAnswerCardView);
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_
diff --git a/ui/app_list/views/search_result_container_view.h b/ui/app_list/views/search_result_container_view.h
index 19c02c13..b5f8496 100644
--- a/ui/app_list/views/search_result_container_view.h
+++ b/ui/app_list/views/search_result_container_view.h
@@ -84,12 +84,11 @@
   virtual void OnContainerSelected(bool from_bottom,
                                    bool directional_movement) = 0;
 
- protected:
+ private:
   // Schedules an Update call using |update_factory_|. Do nothing if there is a
   // pending call.
   void ScheduleUpdate();
 
- private:
   // Updates UI with model. Returns the number of visible results.
   virtual int DoUpdate() = 0;
 
diff --git a/ui/arc/notification/arc_custom_notification_view.cc b/ui/arc/notification/arc_custom_notification_view.cc
index c84e6464..d5ec3161 100644
--- a/ui/arc/notification/arc_custom_notification_view.cc
+++ b/ui/arc/notification/arc_custom_notification_view.cc
@@ -10,6 +10,7 @@
 #include "components/exo/notification_surface.h"
 #include "components/exo/surface.h"
 #include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_node_data.h"
 #include "ui/arc/notification/arc_notification_view.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -251,6 +252,7 @@
   // Create a layer as an anchor to insert surface copy during a slide.
   SetPaintToLayer();
   UpdatePreferredSize();
+  UpdateAccessibleName();
 }
 
 ArcCustomNotificationView::~ArcCustomNotificationView() {
@@ -483,6 +485,14 @@
   return false;
 }
 
+void ArcCustomNotificationView::UpdateAccessibleName() {
+  // Don't update the accessible name when we are about to be destroyed.
+  if (!item_)
+    return;
+
+  accessible_name_ = item_->GetAccessibleName();
+}
+
 void ArcCustomNotificationView::ViewHierarchyChanged(
     const views::View::ViewHierarchyChangedDetails& details) {
   views::Widget* widget = GetWidget();
@@ -623,6 +633,12 @@
   return false;
 }
 
+void ArcCustomNotificationView::GetAccessibleNodeData(
+    ui::AXNodeData* node_data) {
+  node_data->role = ui::AX_ROLE_BUTTON;
+  node_data->SetName(accessible_name_);
+}
+
 void ArcCustomNotificationView::ButtonPressed(views::Button* sender,
                                               const ui::Event& event) {
   if (item_ && !item_->GetPinned() && sender == close_button_.get()) {
@@ -659,6 +675,7 @@
 }
 
 void ArcCustomNotificationView::OnItemUpdated() {
+  UpdateAccessibleName();
   UpdatePinnedState();
   UpdateSnapshot();
   if (ShouldUpdateControlButtonsColor())
diff --git a/ui/arc/notification/arc_custom_notification_view.h b/ui/arc/notification/arc_custom_notification_view.h
index ce2d65d..0257b3d 100644
--- a/ui/arc/notification/arc_custom_notification_view.h
+++ b/ui/arc/notification/arc_custom_notification_view.h
@@ -87,6 +87,7 @@
   void ActivateToast();
   void StartControlButtonsColorAnimation();
   bool ShouldUpdateControlButtonsColor() const;
+  void UpdateAccessibleName();
 
   // views::NativeViewHost
   void ViewHierarchyChanged(
@@ -99,6 +100,7 @@
   void OnBlur() override;
   views::FocusTraversable* GetFocusTraversable() override;
   bool HandleAccessibleAction(const ui::AXActionData& action) override;
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
 
   // views::ButtonListener
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
@@ -154,6 +156,8 @@
 
   std::unique_ptr<gfx::LinearAnimation> control_button_color_animation_;
 
+  base::string16 accessible_name_;
+
   DISALLOW_COPY_AND_ASSIGN(ArcCustomNotificationView);
 };
 
diff --git a/ui/arc/notification/arc_notification_item.h b/ui/arc/notification/arc_notification_item.h
index 5dac895..397b324 100644
--- a/ui/arc/notification/arc_notification_item.h
+++ b/ui/arc/notification/arc_notification_item.h
@@ -77,6 +77,8 @@
   virtual const std::string& GetNotificationKey() const = 0;
   // Returns the notification ID used in the Chrome message center.
   virtual const std::string& GetNotificationId() const = 0;
+  // Returnes the accessible name of the notification.
+  virtual const base::string16& GetAccessibleName() const = 0;
 };
 
 }  // namespace arc
diff --git a/ui/arc/notification/arc_notification_item_impl.cc b/ui/arc/notification/arc_notification_item_impl.cc
index 610b4e1..18ac549 100644
--- a/ui/arc/notification/arc_notification_item_impl.cc
+++ b/ui/arc/notification/arc_notification_item_impl.cc
@@ -77,8 +77,14 @@
   rich_data.priority = ConvertAndroidPriority(data->priority);
   if (data->small_icon)
     rich_data.small_image = gfx::Image::CreateFrom1xBitmap(*data->small_icon);
-  if (data->accessible_name.has_value())
-    rich_data.accessible_name = base::UTF8ToUTF16(*data->accessible_name);
+  if (data->accessible_name.has_value()) {
+    accessible_name_ = base::UTF8ToUTF16(*data->accessible_name);
+  } else {
+    accessible_name_ = base::JoinString(
+        {base::UTF8ToUTF16(data->title), base::UTF8ToUTF16(data->message)},
+        base::ASCIIToUTF16("\n"));
+  }
+  rich_data.accessible_name = accessible_name_;
 
   message_center::NotifierId notifier_id(
       message_center::NotifierId::SYSTEM_COMPONENT, kNotifierId);
@@ -195,4 +201,8 @@
   return notification_id_;
 }
 
+const base::string16& ArcNotificationItemImpl::GetAccessibleName() const {
+  return accessible_name_;
+}
+
 }  // namespace arc
diff --git a/ui/arc/notification/arc_notification_item_impl.h b/ui/arc/notification/arc_notification_item_impl.h
index 2fbf3147..9f69b57 100644
--- a/ui/arc/notification/arc_notification_item_impl.h
+++ b/ui/arc/notification/arc_notification_item_impl.h
@@ -48,6 +48,7 @@
   mojom::ArcNotificationShownContents GetShownContents() const override;
   const std::string& GetNotificationKey() const override;
   const std::string& GetNotificationId() const override;
+  const base::string16& GetAccessibleName() const override;
 
  private:
   // Return true if it's on the thread this instance is created on.
@@ -68,6 +69,8 @@
       mojom::ArcNotificationShownContents::CONTENTS_SHOWN;
   // The reference counter of the window.
   int window_ref_count_ = 0;
+  // The accessible name of the latest notification.
+  base::string16 accessible_name_;
 
   base::ObserverList<Observer> observers_;
 
diff --git a/ui/gfx/color_space.cc b/ui/gfx/color_space.cc
index 8f72e63..9230410 100644
--- a/ui/gfx/color_space.cc
+++ b/ui/gfx/color_space.cc
@@ -455,6 +455,17 @@
       primaries.fWY = 0.3290f;
       break;
 
+    case ColorSpace::PrimaryID::WIDE_GAMUT_COLOR_SPIN:
+      primaries.fRX = 0.01f;
+      primaries.fRY = 0.01f;
+      primaries.fGX = 0.98f;
+      primaries.fGY = 0.01f;
+      primaries.fBX = 0.01f;
+      primaries.fBY = 0.98f;
+      primaries.fWX = 0.3127f;
+      primaries.fWY = 0.3290f;
+      break;
+
     case ColorSpace::PrimaryID::FILM:
       primaries.fRX = 0.681f;
       primaries.fRY = 0.319f;
diff --git a/ui/gfx/color_space.h b/ui/gfx/color_space.h
index aaca2de..35d3425 100644
--- a/ui/gfx/color_space.h
+++ b/ui/gfx/color_space.h
@@ -45,6 +45,8 @@
     // Corresponds the the primaries of the "Generic RGB" profile used in the
     // Apple ColorSync application, used by layout tests on Mac.
     APPLE_GENERIC_RGB,
+    // A very wide gamut space with rotated primaries. Used by layout tests.
+    WIDE_GAMUT_COLOR_SPIN,
     // Primaries defined by the primary matrix |custom_primary_matrix_|.
     CUSTOM,
     // For color spaces defined by an ICC profile which cannot be represented
diff --git a/ui/gfx/color_space_win.cc b/ui/gfx/color_space_win.cc
index a012e1f..4189aff62 100644
--- a/ui/gfx/color_space_win.cc
+++ b/ui/gfx/color_space_win.cc
@@ -79,6 +79,7 @@
     case gfx::ColorSpace::PrimaryID::XYZ_D50:
     case gfx::ColorSpace::PrimaryID::ADOBE_RGB:
     case gfx::ColorSpace::PrimaryID::APPLE_GENERIC_RGB:
+    case gfx::ColorSpace::PrimaryID::WIDE_GAMUT_COLOR_SPIN:
     case gfx::ColorSpace::PrimaryID::ICC_BASED:
     case gfx::ColorSpace::PrimaryID::CUSTOM:
     case gfx::ColorSpace::PrimaryID::INVALID:
diff --git a/ui/gfx/icc_profile.cc b/ui/gfx/icc_profile.cc
index f22c9cf..723d062 100644
--- a/ui/gfx/icc_profile.cc
+++ b/ui/gfx/icc_profile.cc
@@ -132,10 +132,11 @@
     ColorSpace generic_rgb_color_space(ColorSpace::PrimaryID::APPLE_GENERIC_RGB,
                                        ColorSpace::TransferID::GAMMA18);
     generic_rgb_color_space.GetICCProfile(&icc_profile);
-  } else if (value == "bt2020-gamma18") {
-    ColorSpace generic_rgb_color_space(ColorSpace::PrimaryID::BT2020,
-                                       ColorSpace::TransferID::GAMMA18);
-    generic_rgb_color_space.GetICCProfile(&icc_profile);
+  } else if (value == "color-spin-gamma24") {
+    ColorSpace color_spin_color_space(
+        ColorSpace::PrimaryID::WIDE_GAMUT_COLOR_SPIN,
+        ColorSpace::TransferID::GAMMA24);
+    color_spin_color_space.GetICCProfile(&icc_profile);
   } else {
     LOG(ERROR) << "Invalid forced color profile";
   }
diff --git a/ui/gfx/switches.cc b/ui/gfx/switches.cc
index f991cd8..0219b5e 100644
--- a/ui/gfx/switches.cc
+++ b/ui/gfx/switches.cc
@@ -27,8 +27,7 @@
 
 // Force all monitors to be treated as though they have the specified color
 // profile. Accepted values are "srgb" and "generic-rgb" (currently used by Mac
-// layout tests) and "bt2020-gamma18" (to be used by Mac layout tests in the
-// future).
+// layout tests) and "color-spin-gamma24" (used by layout tests).
 const char kForceColorProfile[] = "force-color-profile";
 
 }  // namespace switches
diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h
index e72b1ec..69f4c38 100644
--- a/ui/gl/gl_context.h
+++ b/ui/gl/gl_context.h
@@ -39,6 +39,19 @@
 class RealGLApi;
 class TraceGLApi;
 
+// Where available, choose a GL context priority for devices that support it.
+// Currently this requires the EGL_IMG_context_priority extension that is
+// present on Daydream ready Android devices. Default is Medium, and the
+// attribute is ignored if the extension is missing.
+//
+// "High" priority must only be used for special cases with strong realtime
+// requirements, it is incompatible with other critical system GL work such as
+// the GVR library's asynchronous reprojection for VR viewing. Please avoid
+// using it for any GL contexts that may be used during VR presentation,
+// see crbug.com/727800.
+//
+// Instead, consider using "Low" priority for possibly-slow GL work such as
+// user WebGL content.
 enum ContextPriority {
   ContextPriorityLow,
   ContextPriorityMedium,
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn
index a01d1709..51f90da 100644
--- a/ui/message_center/BUILD.gn
+++ b/ui/message_center/BUILD.gn
@@ -15,6 +15,8 @@
     "notification_settings_button.icon",
     "notification_close_button.1x.icon",
     "notification_close_button.icon",
+    "product.1x.icon",
+    "product.icon",
   ]
 }
 
@@ -138,6 +140,8 @@
         "views/notification_button.h",
         "views/notification_view.cc",
         "views/notification_view.h",
+        "views/notification_view_md.cc",
+        "views/notification_view_md.h",
         "views/notifier_settings_view.cc",
         "views/notifier_settings_view.h",
         "views/padded_button.cc",
diff --git a/ui/message_center/message_center_switches.cc b/ui/message_center/message_center_switches.cc
index 4caba23f..44f45888 100644
--- a/ui/message_center/message_center_switches.cc
+++ b/ui/message_center/message_center_switches.cc
@@ -17,4 +17,11 @@
 const char kMessageCenterChangesWhileOpen[] =
     "message-center-changes-while-open";
 
+// Flag to enable or disable new-style notification. This flag will be removed
+// once the feature gets stable.
+const char kEnableMessageCenterNewStyleNotification[] =
+    "enabled-new-style-notification";
+const char kDisableMessageCenterNewStyleNotification[] =
+    "disabled-new-style-notification";
+
 }  // namespace switches
diff --git a/ui/message_center/message_center_switches.h b/ui/message_center/message_center_switches.h
index f0c37962..8093b6c 100644
--- a/ui/message_center/message_center_switches.h
+++ b/ui/message_center/message_center_switches.h
@@ -18,6 +18,11 @@
 // This flag will be removed once the feature gets stable.
 MESSAGE_CENTER_EXPORT extern const char kMessageCenterChangesWhileOpen[];
 
+MESSAGE_CENTER_EXPORT extern const char
+    kEnableMessageCenterNewStyleNotification[];
+MESSAGE_CENTER_EXPORT extern const char
+    kDisableMessageCenterNewStyleNotification[];
+
 }  // namespace switches
 
 #endif  // UI_MESSAGE_CENTER_MESSAGE_CENTER_SWITCHES_H_
diff --git a/ui/message_center/vector_icons/product.1x.icon b/ui/message_center/vector_icons/product.1x.icon
new file mode 100644
index 0000000..4997801
--- /dev/null
+++ b/ui/message_center/vector_icons/product.1x.icon
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 16,
+MOVE_TO, 8, 5.3f,
+LINE_TO, 13.34f, 5.3f,
+CUBIC_TO, 12.38f, 3.32f, 10.34f, 2, 8, 2,
+CUBIC_TO, 6.14f, 2, 4.46f, 2.84f, 3.38f, 4.16f,
+LINE_TO, 5.36f, 7.58f,
+CUBIC_TO, 5.54f, 6.32f, 6.68f, 5.3f, 8, 5.3f,
+LINE_TO, 8, 5.3f,
+CLOSE,
+MOVE_TO, 8, 10.7f,
+CUBIC_TO, 6.98f, 10.7f, 6.14f, 10.16f, 5.66f, 9.32f,
+LINE_TO, 2.96f, 4.7f,
+CUBIC_TO, 2.36f, 5.66f, 2, 6.8f, 2, 8,
+CUBIC_TO, 2, 11, 4.16f, 13.46f, 7.04f, 13.94f,
+LINE_TO, 9.02f, 10.52f,
+CUBIC_TO, 8.66f, 10.64f, 8.36f, 10.7f, 8, 10.7f,
+LINE_TO, 8, 10.7f,
+CLOSE,
+MOVE_TO, 10.7f, 8,
+CUBIC_TO, 10.7f, 8.48f, 10.58f, 8.96f, 10.34f, 9.32f,
+LINE_TO, 7.64f, 14,
+LINE_TO, 8, 14,
+CUBIC_TO, 11.3f, 14, 14, 11.3f, 14, 8,
+CUBIC_TO, 14, 7.28f, 13.88f, 6.56f, 13.64f, 5.9f,
+LINE_TO, 9.68f, 5.9f,
+CUBIC_TO, 10.28f, 6.38f, 10.7f, 7.16f, 10.7f, 8,
+CLOSE,
+MOVE_TO, 8, 10.1f,
+CUBIC_TO, 9.16f, 10.1f, 10.1f, 9.16f, 10.1f, 8,
+CUBIC_TO, 10.1f, 6.84f, 9.16f, 5.9f, 8, 5.9f,
+CUBIC_TO, 6.84f, 5.9f, 5.9f, 6.84f, 5.9f, 8,
+CUBIC_TO, 5.9f, 9.16f, 6.84f, 10.1f, 8, 10.1f,
+CLOSE,
+END
diff --git a/ui/message_center/vector_icons/product.icon b/ui/message_center/vector_icons/product.icon
new file mode 100644
index 0000000..98ce8d51
--- /dev/null
+++ b/ui/message_center/vector_icons/product.icon
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 32,
+MOVE_TO, 16, 10.6f,
+LINE_TO, 26.68f, 10.6f,
+CUBIC_TO, 24.76f, 6.64f, 20.68f, 4, 16, 4,
+CUBIC_TO, 12.28f, 4, 8.92f, 5.68f, 6.76f, 8.32f,
+LINE_TO, 10.72f, 15.16f,
+CUBIC_TO, 11.08f, 12.64f, 13.36f, 10.6f, 16, 10.6f,
+LINE_TO, 16, 10.6f,
+CLOSE,
+MOVE_TO, 16, 21.4f,
+CUBIC_TO, 13.96f, 21.4f, 12.28f, 20.32f, 11.32f, 18.64f,
+LINE_TO, 5.92f, 9.4f,
+CUBIC_TO, 4.72f, 11.32f, 4, 13.6f, 4, 16,
+CUBIC_TO, 4, 22, 8.32f, 26.92f, 14.08f, 27.88f,
+LINE_TO, 18.04f, 21.04f,
+CUBIC_TO, 17.32f, 21.28f, 16.72f, 21.4f, 16, 21.4f,
+LINE_TO, 16, 21.4f,
+CLOSE,
+MOVE_TO, 21.4f, 16,
+CUBIC_TO, 21.4f, 16.96f, 21.16f, 17.92f, 20.68f, 18.64f,
+LINE_TO, 15.28f, 28,
+LINE_TO, 16, 28,
+CUBIC_TO, 22.6f, 28, 28, 22.6f, 28, 16,
+CUBIC_TO, 28, 14.56f, 27.76f, 13.12f, 27.28f, 11.8f,
+LINE_TO, 19.36f, 11.8f,
+CUBIC_TO, 20.56f, 12.76f, 21.4f, 14.32f, 21.4f, 16,
+CLOSE,
+MOVE_TO, 16, 20.2f,
+CUBIC_TO, 18.32f, 20.2f, 20.2f, 18.32f, 20.2f, 16,
+CUBIC_TO, 20.2f, 13.68f, 18.32f, 11.8f, 16, 11.8f,
+CUBIC_TO, 13.68f, 11.8f, 11.8f, 13.68f, 11.8f, 16,
+CUBIC_TO, 11.8f, 18.32f, 13.68f, 20.2f, 16, 20.2f,
+CLOSE,
+END
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc
index f7a5d4b..6559660 100644
--- a/ui/message_center/views/message_view.cc
+++ b/ui/message_center/views/message_view.cc
@@ -171,6 +171,8 @@
 }
 
 void MessageView::Layout() {
+  views::View::Layout();
+
   gfx::Rect content_bounds = GetContentsBounds();
 
   // Background.
diff --git a/ui/message_center/views/message_view_factory.cc b/ui/message_center/views/message_view_factory.cc
index f1c982f4..60567af 100644
--- a/ui/message_center/views/message_view_factory.cc
+++ b/ui/message_center/views/message_view_factory.cc
@@ -4,8 +4,11 @@
 
 #include "ui/message_center/views/message_view_factory.h"
 
+#include "base/command_line.h"
+#include "ui/message_center/message_center_switches.h"
 #include "ui/message_center/notification_types.h"
 #include "ui/message_center/views/notification_view.h"
+#include "ui/message_center/views/notification_view_md.h"
 
 #if defined(OS_WIN)
 #include "ui/base/win/shell.h"
@@ -23,10 +26,23 @@
     case NOTIFICATION_TYPE_IMAGE:
     case NOTIFICATION_TYPE_MULTIPLE:
     case NOTIFICATION_TYPE_SIMPLE:
-    case NOTIFICATION_TYPE_PROGRESS:
+    case NOTIFICATION_TYPE_PROGRESS: {
+      bool new_style_notification_enabled = false;  // default value
+      if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+              switches::kEnableMessageCenterNewStyleNotification)) {
+        new_style_notification_enabled = true;
+      } else if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+                     switches::kDisableMessageCenterNewStyleNotification)) {
+        new_style_notification_enabled = false;
+      }
+
       // All above roads lead to the generic NotificationView.
-      notification_view = new NotificationView(controller, notification);
+      if (new_style_notification_enabled)
+        notification_view = new NotificationViewMD(controller, notification);
+      else
+        notification_view = new NotificationView(controller, notification);
       break;
+    }
 #if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
     case NOTIFICATION_TYPE_CUSTOM:
       notification_view =
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
new file mode 100644
index 0000000..5bc79bc9
--- /dev/null
+++ b/ui/message_center/views/notification_view_md.cc
@@ -0,0 +1,455 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/message_center/views/notification_view_md.h"
+
+#include <stddef.h>
+
+#include "base/strings/string_util.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/text_elider.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/message_center_style.h"
+#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_types.h"
+#include "ui/message_center/vector_icons.h"
+#include "ui/message_center/views/bounded_label.h"
+#include "ui/message_center/views/constants.h"
+#include "ui/message_center/views/message_center_controller.h"
+#include "ui/message_center/views/notification_button.h"
+#include "ui/message_center/views/padded_button.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/native_cursor.h"
+#include "ui/views/view_targeter.h"
+
+namespace message_center {
+
+namespace {
+
+// Dimensions.
+constexpr int kNotificationRightPadding = 13;
+constexpr int kNotificationLeftPadding = 13;
+constexpr int kNotificationTopPadding = 6;
+constexpr int kNotificationBottomPadding = 10;
+constexpr gfx::Insets kNotificationPadding(kNotificationTopPadding,
+                                           kNotificationLeftPadding,
+                                           kNotificationBottomPadding,
+                                           kNotificationRightPadding);
+
+constexpr int kMaxContextTitleLines = 1;
+
+// Foreground of small icon image.
+constexpr SkColor kSmallImageBackgroundColor = SK_ColorWHITE;
+// Background of small icon image.
+const SkColor kSmallImageColor = SkColorSetRGB(0x43, 0x43, 0x43);
+
+const gfx::ImageSkia CreateSolidColorImage(int width,
+                                           int height,
+                                           SkColor color) {
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(width, height);
+  bitmap.eraseColor(color);
+  return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+}
+
+// Take the alpha channel of icon, mask it with the foreground,
+// then add the masked foreground on top of the background
+const gfx::ImageSkia GetMaskedIcon(const gfx::ImageSkia& icon) {
+  int width = icon.width();
+  int height = icon.height();
+
+  // Background color grey
+  const gfx::ImageSkia background = CreateSolidColorImage(
+      width, height, message_center::kSmallImageBackgroundColor);
+  // Foreground color white
+  const gfx::ImageSkia foreground =
+      CreateSolidColorImage(width, height, message_center::kSmallImageColor);
+  const gfx::ImageSkia masked_small_image =
+      gfx::ImageSkiaOperations::CreateMaskedImage(foreground, icon);
+  return gfx::ImageSkiaOperations::CreateSuperimposedImage(background,
+                                                           masked_small_image);
+}
+
+const gfx::ImageSkia GetProductIcon() {
+  return gfx::CreateVectorIcon(kProductIcon, kSmallImageColor);
+}
+
+}  // anonymous namespace
+
+// ////////////////////////////////////////////////////////////
+// NotificationViewMD
+// ////////////////////////////////////////////////////////////
+
+views::View* NotificationViewMD::TargetForRect(views::View* root,
+                                               const gfx::Rect& rect) {
+  CHECK_EQ(root, this);
+
+  // TODO(tdanderson): Modify this function to support rect-based event
+  // targeting. Using the center point of |rect| preserves this function's
+  // expected behavior for the time being.
+  gfx::Point point = rect.CenterPoint();
+
+  // Want to return this for underlying views, otherwise GetCursor is not
+  // called. But buttons are exceptions, they'll have their own event handlings.
+  std::vector<views::View*> buttons(action_buttons_.begin(),
+                                    action_buttons_.end());
+  if (settings_button_)
+    buttons.push_back(settings_button_.get());
+  if (close_button_)
+    buttons.push_back(close_button_.get());
+
+  for (size_t i = 0; i < buttons.size(); ++i) {
+    gfx::Point point_in_child = point;
+    ConvertPointToTarget(this, buttons[i], &point_in_child);
+    if (buttons[i]->HitTestPoint(point_in_child))
+      return buttons[i]->GetEventHandlerForPoint(point_in_child);
+  }
+
+  return root;
+}
+
+void NotificationViewMD::CreateOrUpdateViews(const Notification& notification) {
+  CreateOrUpdateContextTitleView(notification);
+  CreateOrUpdateTitleView(notification);
+  CreateOrUpdateMessageView(notification);
+  CreateOrUpdateProgressBarView(notification);
+  CreateOrUpdateListItemViews(notification);
+  CreateOrUpdateIconView(notification);
+  CreateOrUpdateSmallIconView(notification);
+  CreateOrUpdateImageView(notification);
+  CreateOrUpdateActionButtonViews(notification);
+  CreateOrUpdateCloseButtonView(notification);
+  CreateOrUpdateSettingsButtonView(notification);
+}
+
+NotificationViewMD::NotificationViewMD(MessageCenterController* controller,
+                                       const Notification& notification)
+    : MessageView(controller, notification),
+      clickable_(notification.clickable()) {
+  layout_ = new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 2);
+  layout_->set_inside_border_insets(kNotificationPadding);
+  SetLayoutManager(layout_);
+
+  // Create the top_view_, which collects into a vertical box all content
+  // at the top of the notification (to the right of the icon) except for the
+  // close button.
+  top_view_ = new views::View();
+  views::BoxLayout* top_box_layout =
+      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 1, 5);
+  top_box_layout->set_cross_axis_alignment(
+      views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
+  top_view_->SetLayoutManager(top_box_layout);
+  AddChildView(top_view_);
+
+  main_view_ = new views::View();
+  main_view_->SetLayoutManager(
+      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
+  AddChildView(main_view_);
+
+  // Create the bottom_view_, which collects notification icon.
+  bottom_view_ = new views::View();
+  bottom_view_->SetLayoutManager(
+      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
+  AddChildView(bottom_view_);
+
+  views::ImageView* small_image_view = new views::ImageView();
+  small_image_view->SetImageSize(gfx::Size(kSmallImageSize, kSmallImageSize));
+  small_image_view->set_owned_by_client();
+  small_image_view_.reset(small_image_view);
+  top_view_->AddChildView(small_image_view_.get());
+
+  CreateOrUpdateViews(notification);
+
+  SetEventTargeter(
+      std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
+}
+
+NotificationViewMD::~NotificationViewMD() {}
+
+void NotificationViewMD::Layout() {
+  MessageView::Layout();
+
+  // Before any resizing, set or adjust the number of message lines.
+  int title_lines = 0;
+  if (title_view_) {
+    title_lines = title_view_->GetLinesForWidthAndLimit(title_view_->width(),
+                                                        kMaxTitleLines);
+  }
+  if (message_view_) {
+    message_view_->SetLineLimit(
+        std::max(0, message_center::kMessageExpandedLineLimit - title_lines));
+  }
+
+  // Settings & Bottom views.
+  if (settings_button_) {
+    gfx::Rect content_bounds = GetContentsBounds();
+    const gfx::Size settings_size(settings_button_->GetPreferredSize());
+    int marginFromRight = settings_size.width() + kControlButtonPadding;
+    if (close_button_)
+      marginFromRight += close_button_->GetPreferredSize().width();
+    gfx::Rect settings_rect(content_bounds.right() - marginFromRight,
+                            GetContentsBounds().y() + kControlButtonPadding,
+                            settings_size.width(), settings_size.height());
+    settings_button_->SetBoundsRect(settings_rect);
+  }
+
+  // Close button.
+  if (close_button_) {
+    gfx::Rect content_bounds = GetContentsBounds();
+    gfx::Size close_size(close_button_->GetPreferredSize());
+    gfx::Rect close_rect(
+        content_bounds.right() - close_size.width() - kControlButtonPadding,
+        content_bounds.y() + kControlButtonPadding, close_size.width(),
+        close_size.height());
+    close_button_->SetBoundsRect(close_rect);
+  }
+}
+
+void NotificationViewMD::OnFocus() {
+  MessageView::OnFocus();
+  ScrollRectToVisible(GetLocalBounds());
+}
+
+void NotificationViewMD::ScrollRectToVisible(const gfx::Rect& rect) {
+  // Notification want to show the whole notification when a part of it (like
+  // a button) gets focused.
+  views::View::ScrollRectToVisible(GetLocalBounds());
+}
+
+gfx::NativeCursor NotificationViewMD::GetCursor(const ui::MouseEvent& event) {
+  if (!clickable_ || !controller()->HasClickedListener(notification_id()))
+    return views::View::GetCursor(event);
+
+  return views::GetNativeHandCursor();
+}
+
+void NotificationViewMD::OnMouseEntered(const ui::MouseEvent& event) {
+  MessageView::OnMouseEntered(event);
+  UpdateControlButtonsVisibility();
+}
+
+void NotificationViewMD::OnMouseExited(const ui::MouseEvent& event) {
+  MessageView::OnMouseExited(event);
+  UpdateControlButtonsVisibility();
+}
+
+void NotificationViewMD::UpdateWithNotification(
+    const Notification& notification) {
+  MessageView::UpdateWithNotification(notification);
+
+  CreateOrUpdateViews(notification);
+  Layout();
+  SchedulePaint();
+}
+
+void NotificationViewMD::ButtonPressed(views::Button* sender,
+                                       const ui::Event& event) {
+  // Certain operations can cause |this| to be destructed, so copy the members
+  // we send to other parts of the code.
+  // TODO(dewittj): Remove this hack.
+  std::string id(notification_id());
+
+  if (close_button_ && sender == close_button_.get()) {
+    // Warning: This causes the NotificationViewMD itself to be deleted, so
+    // don't do anything afterwards.
+    OnCloseButtonPressed();
+    return;
+  }
+
+  if (sender == settings_button_.get()) {
+    controller()->ClickOnSettingsButton(id);
+    return;
+  }
+
+  // See if the button pressed was an action button.
+  for (size_t i = 0; i < action_buttons_.size(); ++i) {
+    if (sender == action_buttons_[i]) {
+      controller()->ClickOnNotificationButton(id, i);
+      return;
+    }
+  }
+}
+
+bool NotificationViewMD::IsCloseButtonFocused() const {
+  if (!close_button_)
+    return false;
+
+  const views::FocusManager* focus_manager = GetFocusManager();
+  return focus_manager &&
+         focus_manager->GetFocusedView() == close_button_.get();
+}
+
+void NotificationViewMD::RequestFocusOnCloseButton() {
+  if (close_button_)
+    close_button_->RequestFocus();
+}
+
+void NotificationViewMD::CreateOrUpdateContextTitleView(
+    const Notification& notification) {
+  DCHECK(top_view_);
+
+  const gfx::FontList& font_list = views::Label().font_list().Derive(
+      -2, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
+
+  base::string16 sub_title = notification.display_source();
+  if (!context_title_view_) {
+    context_title_view_ = new BoundedLabel(sub_title, font_list);
+    context_title_view_->SetLineHeight(kTitleLineHeight);
+    context_title_view_->SetLineLimit(kMaxContextTitleLines);
+    top_view_->AddChildView(context_title_view_);
+  } else {
+    context_title_view_->SetText(sub_title);
+  }
+}
+
+void NotificationViewMD::CreateOrUpdateTitleView(
+    const Notification& notification) {
+  DCHECK(top_view_ != NULL);
+
+  const gfx::FontList& font_list = views::Label().font_list().Derive(
+      1, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
+
+  int title_character_limit =
+      kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacter;
+
+  base::string16 title = gfx::TruncateString(
+      notification.title(), title_character_limit, gfx::WORD_BREAK);
+  if (!title_view_) {
+    title_view_ = new BoundedLabel(title, font_list);
+    title_view_->SetLineHeight(kMessageLineHeight);
+    title_view_->SetColors(message_center::kRegularTextColor,
+                           kDimTextBackgroundColor);
+    main_view_->AddChildView(title_view_);
+  } else {
+    title_view_->SetText(title);
+  }
+}
+
+void NotificationViewMD::CreateOrUpdateMessageView(
+    const Notification& notification) {
+  if (notification.message().empty()) {
+    // Deletion will also remove |context_message_view_| from its parent.
+    delete message_view_;
+    message_view_ = nullptr;
+    return;
+  }
+
+  DCHECK(top_view_ != NULL);
+
+  base::string16 text = gfx::TruncateString(
+      notification.message(), kMessageCharacterLimit, gfx::WORD_BREAK);
+
+  const gfx::FontList& font_list = views::Label().font_list().Derive(
+      1, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
+
+  if (!message_view_) {
+    message_view_ = new BoundedLabel(text, font_list);
+    message_view_->SetLineLimit(message_center::kMessageExpandedLineLimit);
+    message_view_->SetColors(message_center::kDimTextColor,
+                             kContextTextBackgroundColor);
+    main_view_->AddChildView(message_view_);
+  } else {
+    message_view_->SetText(text);
+  }
+}
+
+void NotificationViewMD::CreateOrUpdateProgressBarView(
+    const Notification& notification) {
+  // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateListItemViews(
+    const Notification& notification) {
+  // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateIconView(
+    const Notification& notification) {
+  // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateSmallIconView(
+    const Notification& notification) {
+  gfx::ImageSkia icon =
+      notification.small_image().IsEmpty()
+          ? GetProductIcon()
+          : GetMaskedIcon(notification.small_image().AsImageSkia());
+
+  small_image_view_->SetImage(icon);
+}
+
+void NotificationViewMD::CreateOrUpdateImageView(
+    const Notification& notification) {
+  // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateActionButtonViews(
+    const Notification& notification) {
+  // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateCloseButtonView(
+    const Notification& notification) {
+  if (!notification.pinned() && !close_button_) {
+    close_button_ = base::MakeUnique<PaddedButton>(this);
+    close_button_->SetImage(views::Button::STATE_NORMAL, GetCloseIcon());
+    close_button_->SetAccessibleName(l10n_util::GetStringUTF16(
+        IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME));
+    close_button_->SetTooltipText(l10n_util::GetStringUTF16(
+        IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_TOOLTIP));
+    close_button_->set_owned_by_client();
+    AddChildView(close_button_.get());
+    UpdateControlButtonsVisibility();
+  } else if (notification.pinned() && close_button_) {
+    close_button_.reset();
+  }
+}
+
+void NotificationViewMD::CreateOrUpdateSettingsButtonView(
+    const Notification& notification) {
+  if (!settings_button_ && notification.delegate() &&
+      notification.delegate()->ShouldDisplaySettingsButton()) {
+    settings_button_ = base::MakeUnique<PaddedButton>(this);
+    settings_button_->SetImage(views::Button::STATE_NORMAL, GetSettingsIcon());
+    settings_button_->SetAccessibleName(l10n_util::GetStringUTF16(
+        IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
+    settings_button_->SetTooltipText(l10n_util::GetStringUTF16(
+        IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
+    settings_button_->set_owned_by_client();
+    AddChildView(settings_button_.get());
+  } else {
+    settings_button_.reset();
+  }
+  UpdateControlButtonsVisibility();
+}
+
+void NotificationViewMD::UpdateControlButtonsVisibility() {
+  const bool target_visibility =
+      IsMouseHovered() || HasFocus() ||
+      (close_button_ && close_button_->HasFocus()) ||
+      (settings_button_ && settings_button_->HasFocus());
+
+  if (close_button_) {
+    if (target_visibility != close_button_->visible())
+      close_button_->SetVisible(target_visibility);
+  }
+
+  if (settings_button_) {
+    if (target_visibility != settings_button_->visible())
+      settings_button_->SetVisible(target_visibility);
+  }
+}
+
+}  // namespace message_center
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h
new file mode 100644
index 0000000..c4d76ecf
--- /dev/null
+++ b/ui/message_center/views/notification_view_md.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_MD_H_
+#define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_MD_H_
+
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "ui/message_center/message_center_export.h"
+#include "ui/message_center/views/message_view.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/view_targeter_delegate.h"
+
+namespace views {
+class BoxLayout;
+class ImageView;
+}
+
+namespace message_center {
+
+class BoundedLabel;
+class NotificationButton;
+
+// View that displays all current types of notification (web, basic, image, and
+// list) except the custom notification. Future notification types may be
+// handled by other classes, in which case instances of those classes would be
+// returned by the Create() factory method below.
+class MESSAGE_CENTER_EXPORT NotificationViewMD
+    : public MessageView,
+      public views::ButtonListener,
+      public views::ViewTargeterDelegate {
+ public:
+  NotificationViewMD(MessageCenterController* controller,
+                     const Notification& notification);
+  ~NotificationViewMD() override;
+
+  // Overridden from views::View:
+  void Layout() override;
+  void OnFocus() override;
+  void ScrollRectToVisible(const gfx::Rect& rect) override;
+  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  void OnMouseEntered(const ui::MouseEvent& event) override;
+  void OnMouseExited(const ui::MouseEvent& event) override;
+
+  // Overridden from MessageView:
+  void UpdateWithNotification(const Notification& notification) override;
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+  bool IsCloseButtonFocused() const override;
+  void RequestFocusOnCloseButton() override;
+  void UpdateControlButtonsVisibility() override;
+
+  // views::ViewTargeterDelegate:
+  views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
+
+ private:
+  void CreateOrUpdateViews(const Notification& notification);
+
+  void CreateOrUpdateContextTitleView(const Notification& notification);
+  void CreateOrUpdateTitleView(const Notification& notification);
+  void CreateOrUpdateMessageView(const Notification& notification);
+  void CreateOrUpdateProgressBarView(const Notification& notification);
+  void CreateOrUpdateListItemViews(const Notification& notification);
+  void CreateOrUpdateIconView(const Notification& notification);
+  void CreateOrUpdateSmallIconView(const Notification& notification);
+  void CreateOrUpdateImageView(const Notification& notification);
+  void CreateOrUpdateActionButtonViews(const Notification& notification);
+  void CreateOrUpdateCloseButtonView(const Notification& notification);
+  void CreateOrUpdateSettingsButtonView(const Notification& notification);
+
+  // Describes whether the view should display a hand pointer or not.
+  bool clickable_;
+
+  // Views in the top view
+  views::BoxLayout* layout_ = nullptr;
+
+  // Views in the top view
+  views::View* top_view_ = nullptr;
+  BoundedLabel* context_title_view_ = nullptr;
+
+  // Views in the main view
+  views::View* main_view_ = nullptr;
+  BoundedLabel* title_view_ = nullptr;
+  BoundedLabel* message_view_ = nullptr;
+
+  // Views in the bottom view
+  views::View* bottom_view_ = nullptr;
+
+  // Views in the floating controller
+  std::unique_ptr<views::ImageButton> settings_button_;
+  std::unique_ptr<views::ImageButton> close_button_;
+  std::unique_ptr<views::ImageView> small_image_view_;
+
+  std::vector<NotificationButton*> action_buttons_;
+
+  DISALLOW_COPY_AND_ASSIGN(NotificationViewMD);
+};
+
+}  // namespace message_center
+
+#endif  // UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_MD_H_
diff --git a/ui/views/controls/webview/BUILD.gn b/ui/views/controls/webview/BUILD.gn
index 2836c31..b8daeebab 100644
--- a/ui/views/controls/webview/BUILD.gn
+++ b/ui/views/controls/webview/BUILD.gn
@@ -8,8 +8,6 @@
     "unhandled_keyboard_event_handler.h",
     "unhandled_keyboard_event_handler_mac.mm",
     "unhandled_keyboard_event_handler_win.cc",
-    "web_contents_set_background_color.cc",
-    "web_contents_set_background_color.h",
     "web_dialog_view.cc",
     "web_dialog_view.h",
     "webview.cc",