diff --git a/DEPS b/DEPS
index d9206ee7..3208f77 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # 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': 'fca6d7563e4fad451e9bff85e96f6490596cc9dd',
+  'v8_revision': '7b7658d8c800e8a42d2c0b5bc9bbe63155a69a22',
   # 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': '95988f7874231b1cfd67eaf9d6d97731de4d6e0a',
+  'catapult_revision': '0327c967ed7f2960c26f33ef34ba3f95b6d69da7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 36b6696..6703118 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -824,7 +824,7 @@
      * items and there is no search provider logo.
      */
     private void updateTileGridPlaceholderVisibility() {
-        boolean showPlaceholder = mTileGroup.hasReceivedData() && mTileGroup.getTiles().length == 0
+        boolean showPlaceholder = mTileGroup.hasReceivedData() && mTileGroup.getAllTiles().isEmpty()
                 && !mSearchProviderHasLogo;
 
         mNoSearchLogoSpacer.setVisibility(
@@ -909,7 +909,7 @@
 
     @Override
     public void onTileDataChanged() {
-        mTileGroup.renderTileViews(mTileGridLayout);
+        mTileGroup.renderTiles(mTileGridLayout);
         mSnapshotTileGridChanged = true;
 
         // The page contents are initially hidden; otherwise they'll be drawn centered on the page
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
index 5014c16..2b12e3a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
@@ -31,6 +31,7 @@
 import org.chromium.components.signin.AccountManagerDelegateException;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerResult;
+import org.chromium.components.signin.AccountsChangeObserver;
 import org.chromium.components.signin.GmsAvailabilityException;
 import org.chromium.components.signin.GmsJustUpdatedException;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
@@ -120,6 +121,7 @@
     /** "Undo" button calls {@link Listener#onAccountSelectionCanceled()}. */
     public static final int UNDO_ABORT = 2;
 
+    private final AccountsChangeObserver mAccountsChangedObserver;
     private final ProfileDataCache.Observer mProfileDataCacheObserver;
     private List<String> mAccountNames;
     private AccountSigninChooseView mSigninChooseView;
@@ -148,6 +150,12 @@
 
     public AccountSigninView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mAccountsChangedObserver = new AccountsChangeObserver() {
+            @Override
+            public void onAccountsChanged() {
+                triggerUpdateAccounts();
+            }
+        };
         mProfileDataCacheObserver = new ProfileDataCache.Observer() {
             @Override
             public void onProfileDataUpdated(String accountId) {
@@ -243,6 +251,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         triggerUpdateAccounts();
+        AccountManagerFacade.get().addObserver(mAccountsChangedObserver);
         if (mProfileData != null) {
             mProfileData.addObserver(mProfileDataCacheObserver);
         }
@@ -253,6 +262,7 @@
         if (mProfileData != null) {
             mProfileData.removeObserver(mProfileDataCacheObserver);
         }
+        AccountManagerFacade.get().removeObserver(mAccountsChangedObserver);
         super.onDetachedFromWindow();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java
index 027ee09..0d17d9f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java
@@ -16,6 +16,9 @@
     private final String mWhitelistIconPath;
     private final int mIndex;
 
+    @TileGroup.TileSectionType
+    private final int mSectionType;
+
     @TileSource
     private final int mSource;
 
@@ -45,6 +48,8 @@
         mUrl = url;
         mWhitelistIconPath = whitelistIconPath;
         mIndex = index;
+        // TODO(dgn): get data from C++ after https://crrev/c/593659 lands.
+        mSectionType = TileGroup.TileSectionType.PERSONALIZED;
         mSource = source;
     }
 
@@ -62,11 +67,12 @@
      * difference between the two that would require a redraw.
      * Assumes that the current tile and the old tile (if provided) both describe the same site,
      * so the URLs have to be the same.
+     *
+     * @return Whether non-transient data is different and the tile should be redrawn.
      */
-    public boolean importData(@Nullable Tile tile) {
-        if (tile == null) return true;
-
+    public boolean importData(Tile tile) {
         assert tile.getUrl().equals(mUrl);
+        assert tile.getSectionType() == mSectionType;
 
         mType = tile.getType();
         mIcon = tile.getIcon();
@@ -170,4 +176,9 @@
     public void setIcon(@Nullable Drawable icon) {
         mIcon = icon;
     }
+
+    @TileGroup.TileSectionType
+    public int getSectionType() {
+        return mSectionType;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
index 950b6dc..884e7d55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
@@ -68,7 +68,7 @@
 
     @Override
     public void onTileDataChanged() {
-        setVisibilityInternal(mTileGroup.getTiles().length != 0);
+        setVisibilityInternal(!mTileGroup.getAllTiles().isEmpty());
         if (isVisible()) notifyItemChanged(0, new ViewHolder.UpdateTilesCallback(mTileGroup));
     }
 
@@ -118,7 +118,7 @@
         }
 
         public void updateTiles(TileGroup tileGroup) {
-            tileGroup.renderTileViews(mLayout);
+            tileGroup.renderTiles(mLayout);
         }
 
         public void updateIconView(Tile tile) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
index 2d5cbee5..6e53d55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
@@ -5,45 +5,31 @@
 package org.chromium.chrome.browser.suggestions;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
-import android.os.AsyncTask;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
-import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
-import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.util.SparseArray;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.ViewGroup;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Callback;
-import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
+import org.chromium.chrome.browser.favicon.LargeIconBridge;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.ContextMenuManager.ContextMenuItemId;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.widget.RoundedIconGenerator;
 import org.chromium.ui.mojom.WindowOpenDisposition;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
 /**
  * The model and controller for a group of site suggestion tiles.
@@ -112,6 +98,23 @@
     }
 
     /**
+     * A delegate to allow {@link TileRenderer} to setup behaviours for the newly created views
+     * associated to a Tile.
+     */
+    public interface TileSetupDelegate {
+        /**
+         * Returns a delegate that will handle user interactions with the view created for the tile.
+         */
+        TileInteractionDelegate createInteractionDelegate(Tile tile);
+
+        /**
+         * Returns a callback to be invoked when the icon for the provided tile is loaded. It will
+         * be responsible for updating the tile data and triggering the visual refresh.
+         */
+        LargeIconBridge.LargeIconCallback createIconLoadCallback(Tile tile);
+    }
+
+    /**
      * Constants used to track the current operations on the group and notify the {@link Delegate}
      * when the expected sequence of potentially asynchronous operations is complete.
      */
@@ -139,17 +142,18 @@
         int FETCH_ICON = 3;
     }
 
-    private static final String TAG = "TileGroup";
+    // TODO(dgn) should be generated from C++ enum. Remove when https://crrev.com/c/593651 lands.
+    @IntDef({TileSectionType.PERSONALIZED})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface TileSectionType {
+        int PERSONALIZED = 0;
+    }
 
-    private static final int ICON_CORNER_RADIUS_DP = 4;
-    private static final int ICON_TEXT_SIZE_DP = 20;
-    private static final int ICON_MIN_SIZE_PX = 48;
-
-    private final Context mContext;
     private final SuggestionsUiDelegate mUiDelegate;
     private final ContextMenuManager mContextMenuManager;
     private final Delegate mTileGroupDelegate;
     private final Observer mObserver;
+    private final TileRenderer mTileRenderer;
 
     /**
      * Tracks the tasks currently in flight.
@@ -159,13 +163,6 @@
      */
     private final Collection<Integer> mPendingTasks = new ArrayList<>();
 
-    @TileView.Style
-    private final int mTileStyle;
-    private final int mTitleLinesCount;
-    private final int mMinIconSize;
-    private final int mDesiredIconSize;
-    private final RoundedIconGenerator mIconGenerator;
-
     /**
      * Access point to offline related features. Will be {@code null} when the badges are disabled.
      * @see ChromeFeatureList#NTP_OFFLINE_PAGES_FEATURE_NAME
@@ -177,9 +174,12 @@
      * Source of truth for the tile data. Since the objects can change when the data is updated,
      * other objects should not hold references to them but keep track of the URL instead, and use
      * it to retrieve a {@link Tile}.
-     * @see #getTile(String)
+     * TODO(dgn): If we don't recreate them when loading native data we could keep them around and
+     * simplify a few things.
+     * @see #findTile(String, int)
+     * @see #findTiles(String)
      */
-    private Tile[] mTiles = new Tile[0];
+    private SparseArray<List<Tile>> mTileSections = createEmptyTileData();
 
     /** Most recently received tile data that has not been displayed yet. */
     @Nullable
@@ -206,10 +206,28 @@
      * The number of columns tiles get rendered in. Precalculated upon calling
      * {@link #startObserving(int, int)} and constant from then on. Used for pinning the home page
      * tile to the first tile row.
-     * @see #renderTileViews(ViewGroup)
+     * @see #renderTiles(ViewGroup)
      */
     private int mNumColumns;
 
+    // TODO(dgn): Attempt to avoid cycling dependencies with TileRenderer. Is there a better way?
+    private final TileSetupDelegate mTileSetupDelegate = new TileSetupDelegate() {
+        @Override
+        public TileInteractionDelegate createInteractionDelegate(Tile tile) {
+            return new TileInteractionDelegate(tile.getUrl(), tile.getSectionType());
+        }
+
+        @Override
+        public LargeIconBridge.LargeIconCallback createIconLoadCallback(Tile tile) {
+            // TODO(dgn): We could save on fetches by avoiding a new one when there is one pending
+            // for the same URL, and applying the result to all matched URLs.
+            boolean trackLoad =
+                    isLoadTracked() && tile.getSectionType() == TileSectionType.PERSONALIZED;
+            if (trackLoad) addTask(TileTask.FETCH_ICON);
+            return new LargeIconCallbackImpl(tile, trackLoad);
+        }
+    };
+
     /**
      * @param context Used for initialisation and resolving resources.
      * @param uiDelegate Delegate used to interact with the rest of the system.
@@ -222,32 +240,12 @@
     public TileGroup(Context context, SuggestionsUiDelegate uiDelegate,
             ContextMenuManager contextMenuManager, Delegate tileGroupDelegate, Observer observer,
             OfflinePageBridge offlinePageBridge, int titleLines, @TileView.Style int tileStyle) {
-        mContext = context;
         mUiDelegate = uiDelegate;
         mContextMenuManager = contextMenuManager;
         mTileGroupDelegate = tileGroupDelegate;
         mObserver = observer;
-        mTitleLinesCount = titleLines;
-        mTileStyle = tileStyle;
-
-        Resources resources = mContext.getResources();
-        mDesiredIconSize = resources.getDimensionPixelSize(R.dimen.tile_view_icon_size);
-        // On ldpi devices, mDesiredIconSize could be even smaller than ICON_MIN_SIZE_PX.
-        mMinIconSize = Math.min(mDesiredIconSize, ICON_MIN_SIZE_PX);
-        int desiredIconSizeDp =
-                Math.round(mDesiredIconSize / resources.getDisplayMetrics().density);
-
-        int cornerRadiusDp;
-        if (SuggestionsConfig.useModern()) {
-            cornerRadiusDp = desiredIconSizeDp / 2;
-        } else {
-            cornerRadiusDp = ICON_CORNER_RADIUS_DP;
-        }
-
-        int iconColor =
-                ApiCompatibilityUtils.getColor(resources, R.color.default_favicon_background_color);
-        mIconGenerator = new RoundedIconGenerator(mContext, desiredIconSizeDp, desiredIconSizeDp,
-                cornerRadiusDp, iconColor, ICON_TEXT_SIZE_DP);
+        mTileRenderer =
+                new TileRenderer(context, tileStyle, titleLines, uiDelegate.getImageFetcher());
 
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_OFFLINE_PAGES_FEATURE_NAME)) {
             mOfflineModelObserver = new OfflineModelObserver(offlinePageBridge);
@@ -259,16 +257,14 @@
 
     @Override
     public void onSiteSuggestionsAvailable(List<SiteSuggestion> siteSuggestions) {
+        // Only transforms the incoming tiles and stores them in a buffer for when we decide to
+        // refresh the tiles in the UI.
+
         boolean removalCompleted = mPendingRemovalUrl != null;
         boolean insertionCompleted = mPendingInsertionUrl == null;
 
-        Set<String> addedUrls = new HashSet<>();
         mPendingTiles = new ArrayList<>();
         for (SiteSuggestion suggestion : siteSuggestions) {
-            // TODO(dgn): Checking this should not even be necessary as the backend is supposed to
-            // send non dupes URLs. Remove once https://crbug.com/703628 is fixed.
-            if (addedUrls.contains(suggestion.url)) continue;
-
             // The home page tile is pinned to the first row of tiles. It will appear on
             // the position corresponding to its ranking among all tiles (obtained from the
             // ntp_tiles C++ component). If its position is larger than the number of tiles
@@ -282,8 +278,9 @@
                 mPendingTiles.add(new Tile(suggestion, mPendingTiles.size()));
             }
 
-            addedUrls.add(suggestion.url);
-
+            // TODO(dgn): Rebase and enable code.
+            // Only tiles in the personal section can be modified.
+            // if (suggestion.section != TileSectionType.PERSONALIZED) continue;
             if (suggestion.url.equals(mPendingRemovalUrl)) removalCompleted = false;
             if (suggestion.url.equals(mPendingInsertionUrl)) insertionCompleted = true;
         }
@@ -303,12 +300,10 @@
 
     @Override
     public void onIconMadeAvailable(String siteUrl) {
-        Tile tile = getTile(siteUrl);
-        if (tile == null) return; // The tile might have been removed.
-
-        LargeIconCallback iconCallback =
-                new LargeIconCallbackImpl(siteUrl, /* trackLoadTask = */ false);
-        mUiDelegate.getImageFetcher().makeLargeIconRequest(siteUrl, mMinIconSize, iconCallback);
+        for (Tile tile : findTiles(siteUrl)) {
+            mTileRenderer.updateIcon(
+                    tile, new LargeIconCallbackImpl(tile, /* trackLoadTask = */ false));
+        }
     }
 
     /**
@@ -324,40 +319,42 @@
     }
 
     /**
-     * Renders tile views in the given {@link TileGridLayout}, reusing existing tile views where
-     * possible because view inflation and icon loading are slow.
+     * Renders tile views in the given {@link TileGridLayout}.
      * @param parent The layout to render the tile views into.
      */
-    public void renderTileViews(ViewGroup parent) {
-        // Map the old tile views by url so they can be reused later.
-        Map<String, TileView> oldTileViews = new HashMap<>();
-        int childCount = parent.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TileView tileView = (TileView) parent.getChildAt(i);
-            oldTileViews.put(tileView.getUrl(), tileView);
+    public void renderTiles(ViewGroup parent) {
+        // TODO(dgn, galinap): Support extra sections in the UI.
+        assert mTileSections.size() == 1;
+        assert mTileSections.keyAt(0) == TileSectionType.PERSONALIZED;
+
+        for (int i = 0; i < mTileSections.size(); ++i) {
+            mTileRenderer.renderTileSection(mTileSections.valueAt(i), parent, mTileSetupDelegate);
         }
-
-        // Remove all views from the layout because even if they are reused later they'll have to be
-        // added back in the correct order.
-        parent.removeAllViews();
-
-        for (Tile tile : mTiles) {
-            TileView tileView = oldTileViews.get(tile.getUrl());
-            if (tileView == null) {
-                tileView = buildTileView(tile, parent);
-            } else {
-                tileView.updateIfDataChanged(tile);
-            }
-
-            parent.addView(tileView);
-        }
-
         // Icon fetch scheduling was done when building the tile views.
         if (isLoadTracked()) removeTask(TileTask.SCHEDULE_ICON_FETCH);
     }
 
+    /** @deprecated use {@link #getTiles(int)} or {@link #getAllTiles()} instead. */
+    @Deprecated
     public Tile[] getTiles() {
-        return Arrays.copyOf(mTiles, mTiles.length);
+        return getTiles(TileSectionType.PERSONALIZED);
+    }
+
+    /** @return The tiles currently loaded in the group for the provided section. */
+    public Tile[] getTiles(@TileSectionType int section) {
+        List<Tile> sectionTiles = mTileSections.get(section);
+        if (sectionTiles == null) return new Tile[0];
+        return sectionTiles.toArray(new Tile[sectionTiles.size()]);
+    }
+
+    /**
+     * @return All the tiles currently loaded in the group. Multiple tiles might be returned for
+     * the same URL, but they would be in different sections.
+     */
+    public List<Tile> getAllTiles() {
+        List<Tile> tiles = new ArrayList<>();
+        for (int i = 0; i < mTileSections.size(); ++i) tiles.addAll(mTileSections.valueAt(i));
+        return tiles;
     }
 
     public boolean hasReceivedData() {
@@ -375,62 +372,6 @@
         if (trackLoadTask) removeTask(TileTask.FETCH_DATA);
     }
 
-    /**
-     * Inflates a new tile view, initializes it, and loads an icon for it.
-     * @param tile The tile that holds the data to populate the new tile view.
-     * @param parentView The parent of the new tile view.
-     * @return The new tile view.
-     */
-    @VisibleForTesting
-    TileView buildTileView(Tile tile, ViewGroup parentView) {
-        TileView tileView = (TileView) LayoutInflater.from(parentView.getContext())
-                                    .inflate(R.layout.tile_view, parentView, false);
-        tileView.initialize(tile, mTitleLinesCount, mTileStyle);
-
-        if (isLoadTracked()) addTask(TileTask.FETCH_ICON);
-
-        // Note: It is important that the callbacks below don't keep a reference to the tile or
-        // modify them as there is no guarantee that the same tile would be used to update the view.
-        LargeIconCallback iconCallback = new LargeIconCallbackImpl(tile.getUrl(), isLoadTracked());
-        loadWhitelistIcon(tile, iconCallback);
-
-        TileInteractionDelegate delegate = new TileInteractionDelegate(tile.getUrl());
-        tileView.setOnClickListener(delegate);
-        tileView.setOnCreateContextMenuListener(delegate);
-
-        return tileView;
-    }
-
-    private void loadWhitelistIcon(final Tile tile, final LargeIconCallback iconCallback) {
-        if (tile.getWhitelistIconPath().isEmpty()) {
-            mUiDelegate.getImageFetcher().makeLargeIconRequest(
-                    tile.getUrl(), mMinIconSize, iconCallback);
-            return;
-        }
-
-        AsyncTask<Void, Void, Bitmap> task = new AsyncTask<Void, Void, Bitmap>() {
-            @Override
-            protected Bitmap doInBackground(Void... params) {
-                Bitmap bitmap = BitmapFactory.decodeFile(tile.getWhitelistIconPath());
-                if (bitmap == null) {
-                    Log.d(TAG, "Image decoding failed: %s", tile.getWhitelistIconPath());
-                }
-                return bitmap;
-            }
-
-            @Override
-            protected void onPostExecute(Bitmap icon) {
-                if (icon == null) {
-                    mUiDelegate.getImageFetcher().makeLargeIconRequest(
-                            tile.getUrl(), mMinIconSize, iconCallback);
-                } else {
-                    iconCallback.onLargeIconAvailable(icon, Color.BLACK, false);
-                }
-            }
-        };
-        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-    }
-
     /** Loads tile data from {@link #mPendingTiles} and clears it afterwards. */
     private void loadTiles() {
         assert mPendingTiles != null;
@@ -438,15 +379,40 @@
         boolean isInitialLoad = !mHasReceivedData;
         mHasReceivedData = true;
 
-        boolean countChanged = isInitialLoad || mTiles.length != mPendingTiles.size();
-        boolean dataChanged = countChanged;
+        boolean dataChanged = isInitialLoad;
+        List<Tile> personalisedTiles = mTileSections.get(TileSectionType.PERSONALIZED);
+        int oldPersonalisedTilesCount = personalisedTiles == null ? 0 : personalisedTiles.size();
+
+        SparseArray<List<Tile>> newSites = createEmptyTileData();
         for (Tile newTile : mPendingTiles) {
-            if (newTile.importData(getTile(newTile.getUrl()))) dataChanged = true;
+            @TileSectionType
+            int category = newTile.getSectionType();
+            Tile matchingTile = findTile(newTile.getUrl(), category);
+            if (matchingTile == null || newTile.importData(matchingTile)) dataChanged = true;
+
+            List<Tile> sectionTiles = newSites.get(category);
+            if (sectionTiles == null) {
+                sectionTiles = new ArrayList<>(category);
+                newSites.append(category, sectionTiles);
+            }
+
+            // TODO(dgn): Do we know if it still ever happens? Remove or replace with an assert if
+            // it never gets hit. See https://crbug.com/703628
+            if (findTile(newTile.getUrl(), sectionTiles) != null) throw new IllegalStateException();
+
+            sectionTiles.add(newTile);
         }
 
-        mTiles = mPendingTiles.toArray(new Tile[mPendingTiles.size()]);
+        mTileSections = newSites;
         mPendingTiles = null;
 
+        // TODO(dgn): change these events, maybe introduce new ones or just change semantics? This
+        // will depend on the UI to be implemented and the desired refresh behaviour.
+        boolean countChanged = isInitialLoad
+                || mTileSections.get(TileSectionType.PERSONALIZED).size()
+                        != oldPersonalisedTilesCount;
+        dataChanged = dataChanged || countChanged;
+
         if (!dataChanged) return;
 
         if (mOfflineModelObserver != null) {
@@ -461,15 +427,36 @@
         if (isInitialLoad) removeTask(TileTask.FETCH_DATA);
     }
 
-    /** @return A tile matching the provided URL, or {@code null} if none is found. */
+    /** @return A tile matching the provided URL and section, or {@code null} if none is found. */
     @Nullable
-    private Tile getTile(String url) {
-        for (Tile tile : mTiles) {
+    private Tile findTile(String url, @TileSectionType int section) {
+        if (mTileSections.get(section) == null) return null;
+        for (Tile tile : mTileSections.get(section)) {
+            if (tile.getUrl().equals(url)) return tile;
+        }
+        return findTile(url, mTileSections.get(section));
+    }
+
+    /** @return A tile matching the provided URL and section, or {@code null} if none is found. */
+    private Tile findTile(String url, @Nullable List<Tile> tiles) {
+        if (tiles == null) return null;
+        for (Tile tile : tiles) {
             if (tile.getUrl().equals(url)) return tile;
         }
         return null;
     }
 
+    /** @return All tiles matching the provided URL, or an empty list if none is found. */
+    private List<Tile> findTiles(String url) {
+        List<Tile> tiles = new ArrayList<>();
+        for (int i = 0; i < mTileSections.size(); ++i) {
+            for (Tile tile : mTileSections.valueAt(i)) {
+                if (tile.getUrl().equals(url)) tiles.add(tile);
+            }
+        }
+        return tiles;
+    }
+
     private void addTask(@TileTask int task) {
         mPendingTasks.add(task);
     }
@@ -478,7 +465,13 @@
         boolean removedTask = mPendingTasks.remove(Integer.valueOf(task));
         assert removedTask;
 
-        if (mPendingTasks.isEmpty()) mTileGroupDelegate.onLoadingComplete(getTiles());
+        if (mPendingTasks.isEmpty()) {
+            // TODO(dgn): We only notify about the personal tiles because that's the only ones we
+            // wait for to be loaded. We also currently rely on the tile order in the returned
+            // array as the reported position in UMA, but this is not accurate and would be broken
+            // if we returned all the tiles regardless of sections.
+            mTileGroupDelegate.onLoadingComplete(getTiles(TileSectionType.PERSONALIZED));
+        }
     }
 
     /**
@@ -496,38 +489,51 @@
         return mPendingTasks.contains(task);
     }
 
-    private class LargeIconCallbackImpl implements LargeIconCallback {
+    @VisibleForTesting
+    TileRenderer getTileRenderer() {
+        return mTileRenderer;
+    }
+
+    @VisibleForTesting
+    TileSetupDelegate getTileSetupDelegate() {
+        return mTileSetupDelegate;
+    }
+
+    private static SparseArray<List<Tile>> createEmptyTileData() {
+        SparseArray<List<Tile>> newTileData = new SparseArray<>();
+
+        // TODO(dgn): How do we want to handle empty states and sections that have no tiles?
+        // Have an empty list for now that can be rendered as-is without causing issues or too much
+        // state checking. We will have to decide if we want empty lists or no section at all for
+        // the others.
+        newTileData.put(TileSectionType.PERSONALIZED, new ArrayList<Tile>());
+
+        return newTileData;
+    }
+
+    // TODO(dgn): I would like to move that to TileRenderer, but setting the data on the tile,
+    // notifying the observer and updating the tasks make it awkward.
+    private class LargeIconCallbackImpl implements LargeIconBridge.LargeIconCallback {
+        @TileSectionType
+        private final int mSection;
         private final String mUrl;
         private final boolean mTrackLoadTask;
 
-        private LargeIconCallbackImpl(String url, boolean trackLoadTask) {
-            mUrl = url;
+        private LargeIconCallbackImpl(Tile tile, boolean trackLoadTask) {
+            mUrl = tile.getUrl();
+            mSection = tile.getSectionType();
             mTrackLoadTask = trackLoadTask;
         }
 
         @Override
         public void onLargeIconAvailable(
                 @Nullable Bitmap icon, int fallbackColor, boolean isFallbackColorDefault) {
-            Tile tile = getTile(mUrl);
-            if (tile != null) { // The tile might have been removed.
+            Tile tile = findTile(mUrl, mSection);
+            if (tile != null) { // Do nothing if the tile was removed.
                 if (icon == null) {
-                    mIconGenerator.setBackgroundColor(fallbackColor);
-                    icon = mIconGenerator.generateIconForUrl(mUrl);
-                    tile.setIcon(new BitmapDrawable(mContext.getResources(), icon));
-                    tile.setType(isFallbackColorDefault ? TileVisualType.ICON_DEFAULT
-                                                        : TileVisualType.ICON_COLOR);
+                    mTileRenderer.setTileIconFromColor(tile, fallbackColor, isFallbackColorDefault);
                 } else {
-                    RoundedBitmapDrawable roundedIcon =
-                            RoundedBitmapDrawableFactory.create(mContext.getResources(), icon);
-                    int cornerRadius = Math.round(ICON_CORNER_RADIUS_DP
-                            * mContext.getResources().getDisplayMetrics().density * icon.getWidth()
-                            / mDesiredIconSize);
-                    roundedIcon.setCornerRadius(cornerRadius);
-                    roundedIcon.setAntiAlias(true);
-                    roundedIcon.setFilterBitmap(true);
-
-                    tile.setIcon(roundedIcon);
-                    tile.setType(TileVisualType.ICON_REAL);
+                    mTileRenderer.setTileIconFromBitmap(tile, icon);
                 }
 
                 mObserver.onTileIconChanged(tile);
@@ -538,17 +544,23 @@
         }
     }
 
-    private class TileInteractionDelegate
+    /**
+     * Implements various listener and delegate interfaces to handle user interactions with tiles.
+     */
+    public class TileInteractionDelegate
             implements ContextMenuManager.Delegate, OnClickListener, OnCreateContextMenuListener {
+        @TileSectionType
+        private final int mSection;
         private final String mUrl;
 
-        public TileInteractionDelegate(String url) {
+        public TileInteractionDelegate(String url, int section) {
             mUrl = url;
+            mSection = section;
         }
 
         @Override
         public void onClick(View view) {
-            Tile tile = getTile(mUrl);
+            Tile tile = findTile(mUrl, mSection);
             if (tile == null) return;
 
             SuggestionsMetrics.recordTileTapped();
@@ -557,7 +569,7 @@
 
         @Override
         public void openItem(int windowDisposition) {
-            Tile tile = getTile(mUrl);
+            Tile tile = findTile(mUrl, mSection);
             if (tile == null) return;
 
             mTileGroupDelegate.openMostVisitedItem(windowDisposition, tile);
@@ -565,7 +577,7 @@
 
         @Override
         public void removeItem() {
-            Tile tile = getTile(mUrl);
+            Tile tile = findTile(mUrl, mSection);
             if (tile == null) return;
 
             // Note: This does not track all the removals, but will track the most recent one. If
@@ -607,11 +619,7 @@
         }
 
         @Override
-        public void onSuggestionOfflineIdChanged(Tile suggestion, @Nullable Long id) {
-            // Retrieve a tile from the internal data, to make sure we don't update a stale object.
-            Tile tile = getTile(suggestion.getUrl());
-            if (tile == null) return;
-
+        public void onSuggestionOfflineIdChanged(Tile tile, @Nullable Long id) {
             boolean oldOfflineAvailable = tile.isOfflineAvailable();
             tile.setOfflinePageOfflineId(id);
 
@@ -622,7 +630,7 @@
 
         @Override
         public Iterable<Tile> getOfflinableSuggestions() {
-            return Arrays.asList(mTiles);
+            return getAllTiles();
         }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java
new file mode 100644
index 0000000..63639d57
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java
@@ -0,0 +1,188 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.suggestions;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.AsyncTask;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.favicon.LargeIconBridge;
+import org.chromium.chrome.browser.widget.RoundedIconGenerator;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Utility class that renders {@link Tile}s into a provided {@link ViewGroup}, creating and
+ * manipulating the views as needed.
+ */
+public class TileRenderer {
+    private static final String TAG = "TileRenderer";
+
+    private static final int ICON_CORNER_RADIUS_DP = 4;
+    private static final int ICON_TEXT_SIZE_DP = 20;
+    private static final int ICON_MIN_SIZE_PX = 48;
+
+    private final Context mContext;
+    private final ImageFetcher mImageFetcher;
+    private final RoundedIconGenerator mIconGenerator;
+
+    @TileView.Style
+    private final int mTileStyle;
+    private final int mTitleLinesCount;
+    private final int mDesiredIconSize;
+    private final int mMinIconSize;
+
+    public TileRenderer(Context context, int tileStyle, int titleLines, ImageFetcher imageFetcher) {
+        mContext = context;
+        mImageFetcher = imageFetcher;
+        mTileStyle = tileStyle;
+        mTitleLinesCount = titleLines;
+
+        Resources resources = mContext.getResources();
+        mDesiredIconSize = resources.getDimensionPixelSize(R.dimen.tile_view_icon_size);
+        // On ldpi devices, mDesiredIconSize could be even smaller than ICON_MIN_SIZE_PX.
+        mMinIconSize = Math.min(mDesiredIconSize, ICON_MIN_SIZE_PX);
+        int desiredIconSizeDp =
+                Math.round(mDesiredIconSize / resources.getDisplayMetrics().density);
+
+        int cornerRadiusDp;
+        if (tileStyle == TileView.Style.MODERN) {
+            cornerRadiusDp = desiredIconSizeDp / 2;
+        } else {
+            cornerRadiusDp = ICON_CORNER_RADIUS_DP;
+        }
+
+        int iconColor =
+                ApiCompatibilityUtils.getColor(resources, R.color.default_favicon_background_color);
+        mIconGenerator = new RoundedIconGenerator(mContext, desiredIconSizeDp, desiredIconSizeDp,
+                cornerRadiusDp, iconColor, ICON_TEXT_SIZE_DP);
+    }
+
+    /**
+     * Renders tile views in the given {@link ViewGroup}, reusing existing tile views where
+     * possible because view inflation and icon loading are slow.
+     * @param parent The layout to render the tile views into.
+     * @param sectionTiles Tiles to render.
+     * @param setupDelegate Delegate used to setup callbacks and listeners for the new views.
+     */
+    public void renderTileSection(
+            List<Tile> sectionTiles, ViewGroup parent, TileGroup.TileSetupDelegate setupDelegate) {
+        // Map the old tile views by url so they can be reused later.
+        Map<String, TileView> oldTileViews = new HashMap<>();
+        int childCount = parent.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            TileView tileView = (TileView) parent.getChildAt(i);
+            oldTileViews.put(tileView.getUrl(), tileView);
+        }
+
+        // Remove all views from the layout because even if they are reused later they'll have to be
+        // added back in the correct order.
+        parent.removeAllViews();
+
+        for (Tile tile : sectionTiles) {
+            TileView tileView = oldTileViews.get(tile.getUrl());
+            if (tileView == null) {
+                tileView = buildTileView(tile, parent, setupDelegate);
+            } else {
+                tileView.updateIfDataChanged(tile);
+            }
+
+            parent.addView(tileView);
+        }
+    }
+
+    /**
+     * Inflates a new tile view, initializes it, and loads an icon for it.
+     * @param tile The tile that holds the data to populate the new tile view.
+     * @param parentView The parent of the new tile view.
+     * @param setupDelegate The delegate used to setup callbacks and listeners for the new view.
+     * @return The new tile view.
+     */
+    @VisibleForTesting
+    TileView buildTileView(
+            Tile tile, ViewGroup parentView, TileGroup.TileSetupDelegate setupDelegate) {
+        TileView tileView = (TileView) LayoutInflater.from(parentView.getContext())
+                                    .inflate(R.layout.tile_view, parentView, false);
+        tileView.initialize(tile, mTitleLinesCount, mTileStyle);
+
+        // Note: It is important that the callbacks below don't keep a reference to the tile or
+        // modify them as there is no guarantee that the same tile would be used to update the view.
+        fetchIcon(tile, setupDelegate.createIconLoadCallback(tile));
+
+        TileGroup.TileInteractionDelegate delegate = setupDelegate.createInteractionDelegate(tile);
+        tileView.setOnClickListener(delegate);
+        tileView.setOnCreateContextMenuListener(delegate);
+
+        return tileView;
+    }
+
+    private void fetchIcon(final Tile tile, final LargeIconBridge.LargeIconCallback iconCallback) {
+        if (tile.getWhitelistIconPath().isEmpty()) {
+            mImageFetcher.makeLargeIconRequest(tile.getUrl(), mMinIconSize, iconCallback);
+            return;
+        }
+
+        AsyncTask<Void, Void, Bitmap> task = new AsyncTask<Void, Void, Bitmap>() {
+            @Override
+            protected Bitmap doInBackground(Void... params) {
+                Bitmap bitmap = BitmapFactory.decodeFile(tile.getWhitelistIconPath());
+                if (bitmap == null) {
+                    Log.d(TAG, "Image decoding failed: %s", tile.getWhitelistIconPath());
+                }
+                return bitmap;
+            }
+
+            @Override
+            protected void onPostExecute(Bitmap icon) {
+                if (icon == null) {
+                    mImageFetcher.makeLargeIconRequest(tile.getUrl(), mMinIconSize, iconCallback);
+                } else {
+                    iconCallback.onLargeIconAvailable(icon, Color.BLACK, false);
+                }
+            }
+        };
+        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    public void updateIcon(Tile tile, LargeIconBridge.LargeIconCallback iconCallback) {
+        mImageFetcher.makeLargeIconRequest(tile.getUrl(), mMinIconSize, iconCallback);
+    }
+
+    public void setTileIconFromBitmap(Tile tile, Bitmap icon) {
+        RoundedBitmapDrawable roundedIcon =
+                RoundedBitmapDrawableFactory.create(mContext.getResources(), icon);
+        int cornerRadius = Math.round(ICON_CORNER_RADIUS_DP
+                * mContext.getResources().getDisplayMetrics().density * icon.getWidth()
+                / mDesiredIconSize);
+        roundedIcon.setCornerRadius(cornerRadius);
+        roundedIcon.setAntiAlias(true);
+        roundedIcon.setFilterBitmap(true);
+
+        tile.setIcon(roundedIcon);
+        tile.setType(TileVisualType.ICON_REAL);
+    }
+
+    public void setTileIconFromColor(Tile tile, int fallbackColor, boolean isFallbackColorDefault) {
+        mIconGenerator.setBackgroundColor(fallbackColor);
+        Bitmap icon = mIconGenerator.generateIconForUrl(tile.getUrl());
+        tile.setIcon(new BitmapDrawable(mContext.getResources(), icon));
+        tile.setType(
+                isFallbackColorDefault ? TileVisualType.ICON_DEFAULT : TileVisualType.ICON_COLOR);
+    }
+}
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 21914378..7636bc4 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1046,6 +1046,7 @@
   "java/src/org/chromium/chrome/browser/suggestions/SuggestionsOfflineModelObserver.java",
   "java/src/org/chromium/chrome/browser/suggestions/TileGroup.java",
   "java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java",
+  "java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java",
   "java/src/org/chromium/chrome/browser/suggestions/TileView.java",
   "java/src/org/chromium/chrome/browser/suggestions/NavigationRecorder.java",
   "java/src/org/chromium/chrome/browser/suggestions/SuggestionsDependencyFactory.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
index dd20e4d..5cc76931 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
@@ -151,6 +151,7 @@
     }
 
     @MediumTest
+    @RetryOnFailure
     public void testSpaceDisplay() throws Exception {
         // This first check is a Criteria because initialization of the Adapter is asynchronous.
         CriteriaHelper.pollUiThread(new Criteria() {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java
index 04de1ddb..1cbf0e6 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java
@@ -273,14 +273,14 @@
         notifyTileUrlsAvailable(URLS);
 
         // Render them to the layout.
-        tileGroup.renderTileViews(layout);
+        tileGroup.renderTiles(layout);
         assertThat(layout.getChildCount(), is(2));
         assertThat(((TileView) layout.getChildAt(0)).getUrl(), is(URLS[0]));
         assertThat(((TileView) layout.getChildAt(1)).getUrl(), is(URLS[1]));
     }
 
     /** Check for https://crbug.com/703628: handle duplicated URLs by ignoring them. */
-    @Test
+    @Test(expected = IllegalStateException.class)
     public void testRenderTileViewWithDuplicatedUrl() {
         SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
         when(uiDelegate.getImageFetcher()).thenReturn(mock(ImageFetcher.class));
@@ -293,11 +293,8 @@
         // Initialise the internal list of tiles
         notifyTileUrlsAvailable(URLS[0], URLS[1], URLS[0]);
 
-        // Render them to the layout. The duplicated URL is skipped.
-        tileGroup.renderTileViews(layout);
-        assertThat(layout.getChildCount(), is(2));
-        assertThat(((TileView) layout.getChildAt(0)).getUrl(), is(URLS[0]));
-        assertThat(((TileView) layout.getChildAt(1)).getUrl(), is(URLS[1]));
+        // Render them to the layout. The duplicated URL should trigger the exception.
+        tileGroup.renderTiles(layout);
     }
 
     @Test
@@ -319,7 +316,7 @@
         layout.addView(view2);
 
         // The tiles should be updated, the old ones removed.
-        tileGroup.renderTileViews(layout);
+        tileGroup.renderTiles(layout);
         assertThat(layout.getChildCount(), is(2));
         assertThat(layout.indexOfChild(view1), is(-1));
         assertThat(layout.indexOfChild(view2), is(-1));
@@ -347,7 +344,7 @@
         layout.addView(view2);
 
         // The tiles should be updated, the old ones reused.
-        tileGroup.renderTileViews(layout);
+        tileGroup.renderTiles(layout);
         assertThat(layout.getChildCount(), is(2));
         assertThat(layout.getChildAt(0), CoreMatchers.<View>is(view1));
         assertThat(layout.getChildAt(1), CoreMatchers.<View>is(view2));
@@ -377,7 +374,7 @@
         Tile tile = new Tile("title", URLS[0], "", 0, TileSource.POPULAR);
 
         ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
-        tileGroup.buildTileView(tile, layout);
+        buildTileView(tile, layout, tileGroup);
 
         // Ensure we run the callback for the new tile.
         assertEquals(1, mImageFetcher.getPendingIconCallbackCount());
@@ -395,7 +392,7 @@
         // Notify for a second set.
         notifyTileUrlsAvailable(URLS);
         ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
-        tileGroup.renderTileViews(layout);
+        tileGroup.renderTiles(layout);
         mImageFetcher.fulfillLargeIconRequests();
 
         // Data changed but no loading complete event is sent
@@ -414,7 +411,7 @@
         notifyTileUrlsAvailable(URLS);
         tileGroup.onSwitchToForeground(/* trackLoadTask: */ false);
         ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
-        tileGroup.renderTileViews(layout);
+        tileGroup.renderTiles(layout);
         mImageFetcher.fulfillLargeIconRequests();
 
         // Data changed but no loading complete event is sent (same as sync)
@@ -433,7 +430,7 @@
         notifyTileUrlsAvailable(URLS);
         tileGroup.onSwitchToForeground(/* trackLoadTask: */ true);
         ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
-        tileGroup.renderTileViews(layout);
+        tileGroup.renderTiles(layout);
         mImageFetcher.fulfillLargeIconRequests();
 
         // Data changed but no loading complete event is sent
@@ -482,13 +479,17 @@
         notifyTileUrlsAvailable(urls);
 
         ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
-        tileGroup.renderTileViews(layout);
+        tileGroup.renderTiles(layout);
 
         reset(mTileGroupObserver);
         reset(mTileGroupDelegate);
         return tileGroup;
     }
 
+    private void buildTileView(Tile tile, ViewGroup layout, TileGroup tileGroup) {
+        tileGroup.getTileRenderer().buildTileView(tile, layout, tileGroup.getTileSetupDelegate());
+    }
+
     private class FakeTileGroupDelegate implements TileGroup.Delegate {
         public MostVisitedSites.Observer mObserver;
 
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
index 66ea5b59..e99d991 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
@@ -30,6 +30,7 @@
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/strings/grit/components_strings.h"
 #include "extensions/browser/event_router.h"
+#include "extensions/browser/extensions_browser_client.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "url/url_util.h"
@@ -240,7 +241,8 @@
              IDS_FEEDBACK_SRT_PROMPT_DECLINE_BUTTON);
 #undef SET_STRING
 
-  const std::string& app_locale = g_browser_process->GetApplicationLocale();
+  const std::string& app_locale =
+      ExtensionsBrowserClient::Get()->GetApplicationLocale();
   webui::SetLoadTimeDataDefaults(app_locale, dict.get());
 
 
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_service.cc b/chrome/browser/extensions/api/feedback_private/feedback_service.cc
index a533dd2..9411431 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_service.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_service.cc
@@ -9,12 +9,12 @@
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/feedback/system_logs/chrome_system_logs_fetcher.h"
 #include "chrome/common/chrome_content_client.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/blob_reader.h"
+#include "extensions/browser/extensions_browser_client.h"
 #include "net/base/network_change_notifier.h"
 
 using content::BrowserThread;
@@ -31,7 +31,8 @@
 void FeedbackService::SendFeedback(content::BrowserContext* browser_context,
                                    scoped_refptr<FeedbackData> feedback_data,
                                    const SendFeedbackCallback& callback) {
-  feedback_data->set_locale(g_browser_process->GetApplicationLocale());
+  feedback_data->set_locale(
+      ExtensionsBrowserClient::Get()->GetApplicationLocale());
   feedback_data->set_user_agent(GetUserAgent());
 
   if (!feedback_data->attached_file_uuid().empty()) {
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc b/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc
index 59b5d22..eba03820 100644
--- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc
+++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc
@@ -147,14 +147,7 @@
   DISALLOW_COPY_AND_ASSIGN(SyncFileSystemTest);
 };
 
-#if defined(OS_CHROMEOS)
-// Flaky on ChromiumOS, http://crbug.com/750800.
-#define MAYBE_AuthorizationTest DISABLED_AuthorizationTest
-#else
-#define MAYBE_AuthorizationTest AuthorizationTest
-#endif
-
-IN_PROC_BROWSER_TEST_F(SyncFileSystemTest, MAYBE_AuthorizationTest) {
+IN_PROC_BROWSER_TEST_F(SyncFileSystemTest, AuthorizationTest) {
   ExtensionTestMessageListener open_failure(
       "checkpoint: Failed to get syncfs", true);
   ExtensionTestMessageListener bar_created(
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 29abf9c..2f1540e5 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -462,6 +462,10 @@
 #endif
 }
 
+std::string ChromeExtensionsBrowserClient::GetApplicationLocale() {
+  return g_browser_process->GetApplicationLocale();
+}
+
 // static
 void ChromeExtensionsBrowserClient::set_did_chrome_update_for_testing(
     bool did_update) {
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
index 505a341..e61c9ed 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.h
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -127,6 +127,7 @@
       net::URLRequest* request) override;
   KioskDelegate* GetKioskDelegate() override;
   bool IsLockScreenContext(content::BrowserContext* context) override;
+  std::string GetApplicationLocale() override;
 
   static void set_did_chrome_update_for_testing(bool did_update);
 
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc
index 80d206f..6829eed 100644
--- a/chrome/browser/extensions/user_script_listener_unittest.cc
+++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -60,7 +60,6 @@
   // ResourceThrottle::Delegate implementation:
   void Resume() override { request_->Start(); }
   void Cancel() override { NOTREACHED(); }
-  void CancelAndIgnore() override { NOTREACHED(); }
   void CancelWithError(int error_code) override { NOTREACHED(); }
 
  private:
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest.cc b/chrome/browser/media/webrtc/webrtc_browsertest.cc
index 3fce926..70b5ba7 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest.cc
@@ -52,6 +52,7 @@
 
   void RunsAudioVideoWebRTCCallInTwoTabs(
       const std::string& video_codec = WebRtcTestBase::kUseDefaultVideoCodec,
+      bool prefer_hw_video_codec = false,
       const std::string& offer_cert_keygen_alg =
           WebRtcTestBase::kUseDefaultCertKeygen,
       const std::string& answer_cert_keygen_alg =
@@ -62,8 +63,8 @@
     SetupPeerconnectionWithLocalStream(right_tab_, answer_cert_keygen_alg);
 
     if (!video_codec.empty()) {
-      SetDefaultVideoCodec(left_tab_, video_codec);
-      SetDefaultVideoCodec(right_tab_, video_codec);
+      SetDefaultVideoCodec(left_tab_, video_codec, prefer_hw_video_codec);
+      SetDefaultVideoCodec(right_tab_, video_codec, prefer_hw_video_codec);
     }
     NegotiateCall(left_tab_, right_tab_);
 
@@ -137,7 +138,7 @@
         "(test \"OK\")";
     return;
   }
-  RunsAudioVideoWebRTCCallInTwoTabs("H264");
+  RunsAudioVideoWebRTCCallInTwoTabs("H264", true /* prefer_hw_video_codec */);
 }
 
 #endif  // BUILDFLAG(RTC_USE_H264)
@@ -160,15 +161,15 @@
 IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerRsa) {
   RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
-                                    kKeygenAlgorithmRsa,
-                                    kKeygenAlgorithmRsa);
+                                    false /* prefer_hw_video_codec */,
+                                    kKeygenAlgorithmRsa, kKeygenAlgorithmRsa);
 }
 
 IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerEcdsa) {
-  RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
-                                    kKeygenAlgorithmEcdsa,
-                                    kKeygenAlgorithmEcdsa);
+  RunsAudioVideoWebRTCCallInTwoTabs(
+      WebRtcTestBase::kUseDefaultVideoCodec, false /* prefer_hw_video_codec */,
+      kKeygenAlgorithmEcdsa, kKeygenAlgorithmEcdsa);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -186,15 +187,15 @@
 IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerEcdsa) {
   RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
-                                    kKeygenAlgorithmRsa,
-                                    kKeygenAlgorithmEcdsa);
+                                    false /* prefer_hw_video_codec */,
+                                    kKeygenAlgorithmRsa, kKeygenAlgorithmEcdsa);
 }
 
 IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerRsa) {
   RunsAudioVideoWebRTCCallInTwoTabs(WebRtcTestBase::kUseDefaultVideoCodec,
-                                    kKeygenAlgorithmEcdsa,
-                                    kKeygenAlgorithmRsa);
+                                    false /* prefer_hw_video_codec */,
+                                    kKeygenAlgorithmEcdsa, kKeygenAlgorithmRsa);
 }
 
 IN_PROC_BROWSER_TEST_F(WebRtcBrowserTest,
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
index d7c6c9d..76f9303 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
@@ -559,11 +559,13 @@
       "setDefaultAudioCodec('" + audio_codec + "')", tab));
 }
 
-void WebRtcTestBase::SetDefaultVideoCodec(
-    content::WebContents* tab,
-    const std::string& video_codec) const {
-  EXPECT_EQ("ok", ExecuteJavascript(
-      "setDefaultVideoCodec('" + video_codec + "')", tab));
+void WebRtcTestBase::SetDefaultVideoCodec(content::WebContents* tab,
+                                          const std::string& video_codec,
+                                          bool prefer_hw_codec) const {
+  EXPECT_EQ("ok",
+            ExecuteJavascript("setDefaultVideoCodec('" + video_codec + "'," +
+                                  (prefer_hw_codec ? "true" : "false") + ")",
+                              tab));
 }
 
 void WebRtcTestBase::EnableOpusDtx(content::WebContents* tab) const {
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.h b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
index 5eadac5..f0b670b 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.h
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
@@ -193,8 +193,13 @@
   // Change the default audio/video codec in the offer SDP.
   void SetDefaultAudioCodec(content::WebContents* tab,
                             const std::string& audio_codec) const;
+  // |prefer_hw_codec| controls if the first or last codec with name
+  // |video_codec| should be selected. External video codecs are currently at
+  // the end of the SDP list. This parameter only matters if there are multiple
+  // codecs with the same name, which can be the case for H264.
   void SetDefaultVideoCodec(content::WebContents* tab,
-                            const std::string& video_codec) const;
+                            const std::string& video_codec,
+                            bool prefer_hw_codec = false) const;
 
   // Add 'usedtx=1' to the offer SDP.
   void EnableOpusDtx(content::WebContents* tab) const;
diff --git a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
index 8647eff..fcd03a3 100644
--- a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
@@ -114,7 +114,8 @@
   }
 
   void RunsAudioVideoCall60SecsAndLogsInternalMetrics(
-      const std::string& video_codec) {
+      const std::string& video_codec,
+      bool prefer_hw_video_codec) {
     ASSERT_TRUE(test::HasReferenceFilesInCheckout());
     ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -131,8 +132,8 @@
     SetupPeerconnectionWithLocalStream(right_tab);
 
     if (!video_codec.empty()) {
-      SetDefaultVideoCodec(left_tab, video_codec);
-      SetDefaultVideoCodec(right_tab, video_codec);
+      SetDefaultVideoCodec(left_tab, video_codec, prefer_hw_video_codec);
+      SetDefaultVideoCodec(right_tab, video_codec, prefer_hw_video_codec);
     }
     NegotiateCall(left_tab, right_tab);
 
@@ -179,8 +180,8 @@
     SetupPeerconnectionWithoutLocalStream(right_tab);
 
     if (!video_codec.empty()) {
-      SetDefaultVideoCodec(left_tab, video_codec);
-      SetDefaultVideoCodec(right_tab, video_codec);
+      SetDefaultVideoCodec(left_tab, video_codec, false /* prefer_hw_codec */);
+      SetDefaultVideoCodec(right_tab, video_codec, false /* prefer_hw_codec */);
     }
     if (opus_dtx) {
       EnableOpusDtx(left_tab);
@@ -228,14 +229,16 @@
     WebRtcInternalsPerfBrowserTest,
     MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp8) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  RunsAudioVideoCall60SecsAndLogsInternalMetrics("VP8");
+  RunsAudioVideoCall60SecsAndLogsInternalMetrics(
+      "VP8", false /* prefer_hw_video_codec */);
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebRtcInternalsPerfBrowserTest,
     MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp9) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  RunsAudioVideoCall60SecsAndLogsInternalMetrics("VP9");
+  RunsAudioVideoCall60SecsAndLogsInternalMetrics(
+      "VP9", false /* prefer_hw_video_codec */);
 }
 
 #if BUILDFLAG(RTC_USE_H264)
@@ -252,7 +255,8 @@
         "\"OK\")";
     return;
   }
-  RunsAudioVideoCall60SecsAndLogsInternalMetrics("H264");
+  RunsAudioVideoCall60SecsAndLogsInternalMetrics(
+      "H264", true /* prefer_hw_video_codec */);
 }
 
 #endif  // BUILDFLAG(RTC_USE_H264)
diff --git a/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc b/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc
index c393a760..cd287217 100644
--- a/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc
@@ -88,7 +88,8 @@
   }
 
   void StartCall(const std::string& audio_codec,
-                 const std::string& video_codec) {
+                 const std::string& video_codec,
+                 bool prefer_hw_video_codec) {
     ASSERT_TRUE(test::HasReferenceFilesInCheckout());
     ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -103,8 +104,8 @@
     SetupPeerconnectionWithLocalStream(right_tab_);
     SetDefaultAudioCodec(left_tab_, audio_codec);
     SetDefaultAudioCodec(right_tab_, audio_codec);
-    SetDefaultVideoCodec(left_tab_, video_codec);
-    SetDefaultVideoCodec(right_tab_, video_codec);
+    SetDefaultVideoCodec(left_tab_, video_codec, prefer_hw_video_codec);
+    SetDefaultVideoCodec(right_tab_, video_codec, prefer_hw_video_codec);
     CreateDataChannel(left_tab_, "data");
     CreateDataChannel(right_tab_, "data");
     NegotiateCall(left_tab_, right_tab_);
@@ -121,9 +122,23 @@
       HangUp(right_tab_);
   }
 
-  void RunsAudioAndVideoCallCollectingMetrics(
-      const std::string& audio_codec, const std::string& video_codec) {
-    StartCall(audio_codec, video_codec);
+  void RunsAudioAndVideoCallCollectingMetricsWithAudioCodec(
+      const std::string& audio_codec) {
+    RunsAudioAndVideoCallCollectingMetrics(audio_codec, kUseDefaultVideoCodec,
+                                           false /* prefer_hw_video_codec */);
+  }
+
+  void RunsAudioAndVideoCallCollectingMetricsWithVideoCodec(
+      const std::string& video_codec,
+      bool prefer_hw_video_codec) {
+    RunsAudioAndVideoCallCollectingMetrics(kUseDefaultAudioCodec, video_codec,
+                                           prefer_hw_video_codec);
+  }
+
+  void RunsAudioAndVideoCallCollectingMetrics(const std::string& audio_codec,
+                                              const std::string& video_codec,
+                                              bool prefer_hw_video_codec) {
+    StartCall(audio_codec, video_codec, prefer_hw_video_codec);
 
     // Call for 60 seconds so that values may stabilize, bandwidth ramp up, etc.
     test::SleepInJavascript(left_tab_, 60000);
@@ -199,7 +214,8 @@
       GetStatsVariation variation) {
     EXPECT_TRUE(base::TimeTicks::IsHighResolution());
 
-    StartCall(kUseDefaultAudioCodec, kUseDefaultVideoCodec);
+    StartCall(kUseDefaultAudioCodec, kUseDefaultVideoCodec,
+              false /* prefer_hw_video_codec */);
 
     double invocation_time = 0.0;
     switch (variation) {
@@ -234,49 +250,51 @@
     WebRtcStatsPerfBrowserTest,
     MANUAL_RunsAudioAndVideoCallCollectingMetrics_AudioCodec_opus) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  RunsAudioAndVideoCallCollectingMetrics("opus", kUseDefaultVideoCodec);
+  RunsAudioAndVideoCallCollectingMetricsWithAudioCodec("opus");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebRtcStatsPerfBrowserTest,
     MANUAL_RunsAudioAndVideoCallCollectingMetrics_AudioCodec_ISAC) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  RunsAudioAndVideoCallCollectingMetrics("ISAC", kUseDefaultVideoCodec);
+  RunsAudioAndVideoCallCollectingMetricsWithAudioCodec("ISAC");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebRtcStatsPerfBrowserTest,
     MANUAL_RunsAudioAndVideoCallCollectingMetrics_AudioCodec_G722) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  RunsAudioAndVideoCallCollectingMetrics("G722", kUseDefaultVideoCodec);
+  RunsAudioAndVideoCallCollectingMetricsWithAudioCodec("G722");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebRtcStatsPerfBrowserTest,
     MANUAL_RunsAudioAndVideoCallCollectingMetrics_AudioCodec_PCMU) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  RunsAudioAndVideoCallCollectingMetrics("PCMU", kUseDefaultVideoCodec);
+  RunsAudioAndVideoCallCollectingMetricsWithAudioCodec("PCMU");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebRtcStatsPerfBrowserTest,
     MANUAL_RunsAudioAndVideoCallCollectingMetrics_AudioCodec_PCMA) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  RunsAudioAndVideoCallCollectingMetrics("PCMA", kUseDefaultVideoCodec);
+  RunsAudioAndVideoCallCollectingMetricsWithAudioCodec("PCMA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebRtcStatsPerfBrowserTest,
     MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP8) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  RunsAudioAndVideoCallCollectingMetrics(kUseDefaultAudioCodec, "VP8");
+  RunsAudioAndVideoCallCollectingMetricsWithVideoCodec(
+      "VP8", false /* prefer_hw_video_codec */);
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebRtcStatsPerfBrowserTest,
     MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP9) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  RunsAudioAndVideoCallCollectingMetrics(kUseDefaultAudioCodec, "VP9");
+  RunsAudioAndVideoCallCollectingMetricsWithVideoCodec(
+      "VP9", false /* prefer_hw_video_codec */);
 }
 
 #if BUILDFLAG(RTC_USE_H264)
@@ -293,7 +311,8 @@
         "\"OK\")";
     return;
   }
-  RunsAudioAndVideoCallCollectingMetrics(kUseDefaultAudioCodec, "H264");
+  RunsAudioAndVideoCallCollectingMetricsWithVideoCodec(
+      "H264", true /* prefer_hw_video_codec */);
 }
 
 #endif  // BUILDFLAG(RTC_USE_H264)
diff --git a/chrome/browser/media/webrtc/webrtc_video_quality_browsertest.cc b/chrome/browser/media/webrtc/webrtc_video_quality_browsertest.cc
index a8ca4227..cf591000 100644
--- a/chrome/browser/media/webrtc/webrtc_video_quality_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_video_quality_browsertest.cc
@@ -259,7 +259,8 @@
     return true;
   }
 
-  void TestVideoQuality(const std::string& video_codec) {
+  void TestVideoQuality(const std::string& video_codec,
+                        bool prefer_hw_video_codec) {
     ASSERT_GE(TestTimeouts::action_max_timeout().InSeconds(), 150)
         << "This is a long-running test; you must specify "
            "--ui-test-action-max-timeout to have a value of at least 150000.";
@@ -279,8 +280,8 @@
     SetupPeerconnectionWithLocalStream(right_tab);
 
     if (!video_codec.empty()) {
-      SetDefaultVideoCodec(left_tab, video_codec);
-      SetDefaultVideoCodec(right_tab, video_codec);
+      SetDefaultVideoCodec(left_tab, video_codec, prefer_hw_video_codec);
+      SetDefaultVideoCodec(right_tab, video_codec, prefer_hw_video_codec);
     }
     NegotiateCall(left_tab, right_tab);
 
@@ -346,13 +347,13 @@
 IN_PROC_BROWSER_TEST_P(WebRtcVideoQualityBrowserTest,
                        MANUAL_TestVideoQualityVp8) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  TestVideoQuality("VP8");
+  TestVideoQuality("VP8", false /* prefer_hw_video_codec */);
 }
 
 IN_PROC_BROWSER_TEST_P(WebRtcVideoQualityBrowserTest,
                        MANUAL_TestVideoQualityVp9) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  TestVideoQuality("VP9");
+  TestVideoQuality("VP9", false /* prefer_hw_video_codec */);
 }
 
 #if BUILDFLAG(RTC_USE_H264)
@@ -367,7 +368,7 @@
         "(test \"OK\")";
     return;
   }
-  TestVideoQuality("H264");
+  TestVideoQuality("H264", true /* prefer_hw_video_codec */);
 }
 
 #endif  // BUILDFLAG(RTC_USE_H264)
diff --git a/chrome/browser/prerender/prerender_resource_throttle_unittest.cc b/chrome/browser/prerender/prerender_resource_throttle_unittest.cc
index 5fde791..9837b20f 100644
--- a/chrome/browser/prerender/prerender_resource_throttle_unittest.cc
+++ b/chrome/browser/prerender/prerender_resource_throttle_unittest.cc
@@ -138,7 +138,6 @@
     cancel_called_ = true;
     run_loop_->Quit();
   }
-  void CancelAndIgnore() override { Cancel(); }
   void CancelWithError(int error_code) override { Cancel(); }
   void Resume() override {
     EXPECT_TRUE(was_deferred_);
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_task_token.cc b/chrome/browser/sync_file_system/drive_backend/sync_task_token.cc
index b701de4..96920f27 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_task_token.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_task_token.cc
@@ -59,25 +59,7 @@
   DVLOG(2) << "Token updated: " << location_.ToString();
 }
 
-SyncTaskToken::~SyncTaskToken() {
-  // All task on Client must hold TaskToken instance to ensure
-  // no other tasks are running. Also, as soon as a task finishes to work,
-  // it must return the token to TaskManager.
-  // Destroying a token with valid |client| indicates the token was
-  // dropped by a task without returning.
-  if (task_runner_.get() && task_runner_->RunsTasksInCurrentSequence() &&
-      manager_ && manager_->IsRunningTask(token_id_)) {
-    NOTREACHED()
-        << "Unexpected TaskToken deletion from: " << location_.ToString();
-
-    // Reinitializes the token.
-    SyncTaskManager::NotifyTaskDone(
-        base::WrapUnique(new SyncTaskToken(manager_, task_runner_.get(),
-                                           token_id_, std::move(task_blocker_),
-                                           SyncStatusCallback())),
-        SYNC_STATUS_OK);
-  }
-}
+SyncTaskToken::~SyncTaskToken() {}
 
 // static
 SyncStatusCallback SyncTaskToken::WrapToCallback(
diff --git a/chrome/renderer/extensions/extension_localization_peer.cc b/chrome/renderer/extensions/extension_localization_peer.cc
index 49a5804..702edc6 100644
--- a/chrome/renderer/extensions/extension_localization_peer.cc
+++ b/chrome/renderer/extensions/extension_localization_peer.cc
@@ -91,7 +91,6 @@
 
 void ExtensionLocalizationPeer::OnCompletedRequest(
     int error_code,
-    bool was_ignored_by_handler,
     bool stale_copy_in_cache,
     const base::TimeTicks& completion_time,
     int64_t total_transfer_size,
@@ -101,9 +100,9 @@
   if (error_code != net::OK) {
     // We failed to load the resource.
     original_peer_->OnReceivedResponse(response_info_);
-    original_peer_->OnCompletedRequest(
-        net::ERR_ABORTED, false, stale_copy_in_cache, completion_time,
-        total_transfer_size, encoded_body_size, decoded_body_size);
+    original_peer_->OnCompletedRequest(net::ERR_ABORTED, stale_copy_in_cache,
+                                       completion_time, total_transfer_size,
+                                       encoded_body_size, decoded_body_size);
     return;
   }
 
@@ -112,9 +111,9 @@
   original_peer_->OnReceivedResponse(response_info_);
   if (!data_.empty())
     original_peer_->OnReceivedData(base::MakeUnique<StringData>(data_));
-  original_peer_->OnCompletedRequest(
-      error_code, was_ignored_by_handler, stale_copy_in_cache, completion_time,
-      total_transfer_size, encoded_body_size, decoded_body_size);
+  original_peer_->OnCompletedRequest(error_code, stale_copy_in_cache,
+                                     completion_time, total_transfer_size,
+                                     encoded_body_size, decoded_body_size);
 }
 
 void ExtensionLocalizationPeer::ReplaceMessages() {
diff --git a/chrome/renderer/extensions/extension_localization_peer.h b/chrome/renderer/extensions/extension_localization_peer.h
index 894580a..15236d6a 100644
--- a/chrome/renderer/extensions/extension_localization_peer.h
+++ b/chrome/renderer/extensions/extension_localization_peer.h
@@ -44,7 +44,6 @@
   void OnReceivedData(std::unique_ptr<ReceivedData> data) override;
   void OnTransferSizeUpdated(int transfer_size_diff) override;
   void OnCompletedRequest(int error_code,
-                          bool was_ignored_by_handler,
                           bool stale_copy_in_cache,
                           const base::TimeTicks& completion_time,
                           int64_t total_transfer_size,
diff --git a/chrome/renderer/extensions/extension_localization_peer_unittest.cc b/chrome/renderer/extensions/extension_localization_peer_unittest.cc
index cff64be..d737d30 100644
--- a/chrome/renderer/extensions/extension_localization_peer_unittest.cc
+++ b/chrome/renderer/extensions/extension_localization_peer_unittest.cc
@@ -76,9 +76,8 @@
   }
   MOCK_METHOD2(OnReceivedDataInternal, void(const char* data, int data_length));
   MOCK_METHOD1(OnTransferSizeUpdated, void(int transfer_size_diff));
-  MOCK_METHOD7(OnCompletedRequest,
+  MOCK_METHOD6(OnCompletedRequest,
                void(int error_code,
-                    bool was_ignored_by_handler,
                     bool stale_copy_in_cache,
                     const base::TimeTicks& completion_time,
                     int64_t total_transfer_size,
@@ -152,12 +151,11 @@
   SetUpExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_1));
 
   EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
-  EXPECT_CALL(*original_peer_,
-              OnCompletedRequest(net::ERR_ABORTED, false, false,
-                                 base::TimeTicks(), -1, 0, 0));
+  EXPECT_CALL(*original_peer_, OnCompletedRequest(net::ERR_ABORTED, false,
+                                                  base::TimeTicks(), -1, 0, 0));
 
-  filter_peer_->OnCompletedRequest(net::ERR_FAILED, false, false,
-                                   base::TimeTicks(), -1, 0, 0);
+  filter_peer_->OnCompletedRequest(net::ERR_FAILED, false, base::TimeTicks(),
+                                   -1, 0, 0);
 }
 
 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestEmptyData) {
@@ -167,11 +165,10 @@
   EXPECT_CALL(*sender_, Send(_)).Times(0);
 
   EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
-  EXPECT_CALL(*original_peer_, OnCompletedRequest(net::OK, false, false,
-                                                  base::TimeTicks(), -1, 0, 0));
+  EXPECT_CALL(*original_peer_,
+              OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, 0, 0));
 
-  filter_peer_->OnCompletedRequest(net::OK, false, false, base::TimeTicks(), -1,
-                                   0, 0);
+  filter_peer_->OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, 0, 0);
 }
 
 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestNoCatalogs) {
@@ -186,13 +183,12 @@
   EXPECT_CALL(*original_peer_,
               OnReceivedDataInternal(StrEq(data.c_str()), data.length()))
       .Times(1);
-  EXPECT_CALL(
-      *original_peer_,
-      OnCompletedRequest(net::OK, false, false, base::TimeTicks(), -1, -1, -1))
+  EXPECT_CALL(*original_peer_,
+              OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, -1, -1))
       .Times(1);
 
-  filter_peer_->OnCompletedRequest(net::OK, false, false, base::TimeTicks(), -1,
-                                   -1, -1);
+  filter_peer_->OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, -1,
+                                   -1);
 
   // Test if Send gets called again (it shouldn't be) when first call returned
   // an empty dictionary.
@@ -201,13 +197,12 @@
   EXPECT_CALL(*original_peer_,
               OnReceivedDataInternal(StrEq(data.c_str()), data.length()))
       .Times(1);
-  EXPECT_CALL(
-      *original_peer_,
-      OnCompletedRequest(net::OK, false, false, base::TimeTicks(), -1, -1, -1))
+  EXPECT_CALL(*original_peer_,
+              OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, -1, -1))
       .Times(1);
   SetData("some text");
-  filter_peer_->OnCompletedRequest(net::OK, false, false, base::TimeTicks(), -1,
-                                   -1, -1);
+  filter_peer_->OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, -1,
+                                   -1);
 }
 
 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestWithCatalogs) {
@@ -232,10 +227,10 @@
 
   EXPECT_CALL(
       *original_peer_,
-      OnCompletedRequest(net::OK, false, false, base::TimeTicks(), -1, -1, -1));
+      OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, -1, -1));
 
-  filter_peer_->OnCompletedRequest(net::OK, false, false, base::TimeTicks(), -1,
-                                   -1, -1);
+  filter_peer_->OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, -1,
+                                   -1);
 }
 
 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestReplaceMessagesFails) {
@@ -258,9 +253,8 @@
   EXPECT_CALL(*original_peer_,
               OnReceivedDataInternal(StrEq(message.c_str()), message.length()));
 
-  EXPECT_CALL(*original_peer_, OnCompletedRequest(net::OK, false, false,
-                                                  base::TimeTicks(), -1, 0, 0));
+  EXPECT_CALL(*original_peer_,
+              OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, 0, 0));
 
-  filter_peer_->OnCompletedRequest(net::OK, false, false, base::TimeTicks(), -1,
-                                   0, 0);
+  filter_peer_->OnCompletedRequest(net::OK, false, base::TimeTicks(), -1, 0, 0);
 }
diff --git a/chrome/renderer/security_filter_peer.cc b/chrome/renderer/security_filter_peer.cc
index fe880825..9d1db5c 100644
--- a/chrome/renderer/security_filter_peer.cc
+++ b/chrome/renderer/security_filter_peer.cc
@@ -138,7 +138,6 @@
 
 void ReplaceContentPeer::OnCompletedRequest(
     int error_code,
-    bool was_ignored_by_handler,
     bool stale_copy_in_cache,
     const base::TimeTicks& completion_time,
     int64_t total_transfer_size,
@@ -152,7 +151,7 @@
     original_peer_->OnReceivedData(base::MakeUnique<content::FixedReceivedData>(
         data_.data(), data_.size()));
   }
-  original_peer_->OnCompletedRequest(net::OK, false, stale_copy_in_cache,
+  original_peer_->OnCompletedRequest(net::OK, stale_copy_in_cache,
                                      completion_time, total_transfer_size,
                                      encoded_body_size, decoded_body_size);
 }
diff --git a/chrome/renderer/security_filter_peer.h b/chrome/renderer/security_filter_peer.h
index a0767b80..70e0c4c 100644
--- a/chrome/renderer/security_filter_peer.h
+++ b/chrome/renderer/security_filter_peer.h
@@ -67,7 +67,6 @@
   void OnReceivedResponse(const content::ResourceResponseInfo& info) override;
   void OnReceivedData(std::unique_ptr<ReceivedData> data) override;
   void OnCompletedRequest(int error_code,
-                          bool was_ignored_by_handler,
                           bool stale_copy_in_cache,
                           const base::TimeTicks& completion_time,
                           int64_t total_transfer_size,
diff --git a/chrome/test/data/webrtc/munge_sdp.js b/chrome/test/data/webrtc/munge_sdp.js
index 70ed1e62..c8baaa0 100644
--- a/chrome/test/data/webrtc/munge_sdp.js
+++ b/chrome/test/data/webrtc/munge_sdp.js
@@ -8,14 +8,14 @@
  * See |setSdpDefaultCodec|.
  */
 function setSdpDefaultAudioCodec(sdp, codec) {
-  return setSdpDefaultCodec(sdp, 'audio', codec);
+  return setSdpDefaultCodec(sdp, 'audio', codec, false /* preferHwCodec */);
 }
 
 /**
  * See |setSdpDefaultCodec|.
  */
-function setSdpDefaultVideoCodec(sdp, codec) {
-  return setSdpDefaultCodec(sdp, 'video', codec);
+function setSdpDefaultVideoCodec(sdp, codec, preferHwCodec) {
+  return setSdpDefaultCodec(sdp, 'video', codec, preferHwCodec);
 }
 
 /**
@@ -55,14 +55,17 @@
 /**
  * Returns a modified version of |sdp| where the |codec| has been promoted to be
  * the default codec, i.e. the codec whose ID is first in the list of codecs on
- * the 'm=|type|' line, where |type| is 'audio' or 'video'.
+ * the 'm=|type|' line, where |type| is 'audio' or 'video'. If |preferHwCodec|
+ * is true, it will select the last codec with the given name, and if false, it
+ * will select the first codec with the given name, because HW codecs are listed
+ * after SW codecs in the SDP list.
  * @private
  */
-function setSdpDefaultCodec(sdp, type, codec) {
+function setSdpDefaultCodec(sdp, type, codec, preferHwCodec) {
   var sdpLines = splitSdpLines(sdp);
 
   // Find codec ID, e.g. 100 for 'VP8' if 'a=rtpmap:100 VP8/9000'.
-  var codecId = findRtpmapId(sdpLines, codec);
+  var codecId = findRtpmapId(sdpLines, codec, preferHwCodec);
   if (codecId === null) {
     failure('setSdpDefaultCodec',
             'Unknown ID for |codec| = \'' + codec + '\'.');
@@ -129,13 +132,15 @@
 /**
  * Searches through all |sdpLines| for the 'a=rtpmap:' line for the codec of
  * the specified name, returning its ID as an int if found, or null otherwise.
- * |codec| is the case-sensitive name of the codec.
+ * |codec| is the case-sensitive name of the codec. If |lastInstance|
+ * is true, it will return the last such ID, and if false, it will return the
+ * first such ID.
  * For example, if |sdpLines| contains 'a=rtpmap:100 VP8/9000' and |codec| is
  * 'VP8', this function returns 100.
  * @private
  */
-function findRtpmapId(sdpLines, codec) {
-  var lineNo = findRtpmapLine(sdpLines, codec);
+function findRtpmapId(sdpLines, codec, lastInstance) {
+  var lineNo = findRtpmapLine(sdpLines, codec, lastInstance);
   if (lineNo === null)
     return null;
   // Parse <id> from 'a=rtpmap:<id> <codec>/<rate>'.
@@ -163,28 +168,46 @@
 }
 
 /**
- * Finds the first 'a=rtpmap:' line from |sdpLines| that contains |contains| and
- * returns its line index, or null if no such line was found. |contains| may be
- * the codec ID, codec name or bitrate. An 'a=rtpmap:' line looks like this:
- * 'a=rtpmap:<id> <codec>/<rate>'.
+ * Finds a 'a=rtpmap:' line from |sdpLines| that contains |contains| and returns
+ * its line index, or null if no such line was found. |contains| may be the
+ * codec ID, codec name or bitrate. If |lastInstance| is true, it will return
+ * the last such line index, and if false, it will return the first such line
+ * index.
+ * An 'a=rtpmap:' line looks like this: 'a=rtpmap:<id> <codec>/<rate>'.
  */
-function findRtpmapLine(sdpLines, contains) {
-  for (var i = 0; i < sdpLines.length; i++) {
-    // Is 'a=rtpmap:' line containing |contains| string?
-    if (sdpLines[i].startsWith('a=rtpmap:') &&
-        sdpLines[i].indexOf(contains) != -1) {
-      // Expecting pattern 'a=rtpmap:<id> <codec>/<rate>'.
-      var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+');
-      if (!sdpLines[i].match(pattern))
-        failure('findRtpmapLine', 'Unexpected "a=rtpmap:" pattern.');
-      // Return line index.
-      return i;
+function findRtpmapLine(sdpLines, contains, lastInstance) {
+  if (lastInstance === true) {
+    for (var i = sdpLines.length - 1; i >= 0 ; i--) {
+      if (isRtpmapLine(sdpLines[i], contains))
+        return i;
+    }
+  } else {
+    for (var i = 0; i < sdpLines.length; i++) {
+      if (isRtpmapLine(sdpLines[i], contains))
+        return i;
     }
   }
   return null;
 }
 
 /**
+ * Returns true if |sdpLine| contains |contains| and is of pattern
+ * 'a=rtpmap:<id> <codec>/<rate>'.
+ */
+function isRtpmapLine(sdpLine, contains) {
+  // Is 'a=rtpmap:' line containing |contains| string?
+  if (sdpLine.startsWith('a=rtpmap:') &&
+      sdpLine.indexOf(contains) != -1) {
+    // Expecting pattern 'a=rtpmap:<id> <codec>/<rate>'.
+    var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+');
+    if (!sdpLine.match(pattern))
+      failure('isRtpmapLine', 'Unexpected "a=rtpmap:" pattern.');
+    return true;
+  }
+  return false;
+}
+
+/**
  * Finds the fmtp line in |sdpLines| for the given |codecId|, and returns its
  * line number. The line starts with 'a=fmtp:<codecId>'.
  * @private
diff --git a/chrome/test/data/webrtc/peerconnection.js b/chrome/test/data/webrtc/peerconnection.js
index c51ff11..13441c2 100644
--- a/chrome/test/data/webrtc/peerconnection.js
+++ b/chrome/test/data/webrtc/peerconnection.js
@@ -41,6 +41,12 @@
 var gDefaultVideoCodec = null;
 
 /**
+ * Flag to indicate if HW or SW video codec is preferred.
+ * @private
+ */
+var gDefaultPreferHwVideoCodec = null;
+
+/**
  * Flag to indicate if Opus Dtx should be enabled.
  * @private
  */
@@ -122,9 +128,14 @@
  *     video codec, e.g. the first one in the list on the 'm=video' SDP offer
  *     line. |videoCodec| is the case-sensitive codec name, e.g. 'VP8' or
  *     'H264'.
+ * @param {bool} preferHwVideoCodec specifies what codec to use from the
+ *     'm=video' line when there are multiple codecs with the name |videoCodec|.
+ *     If true, it will return the last codec with that name, and if false, it
+ *     will return the first codec with that name.
  */
-function setDefaultVideoCodec(videoCodec) {
+function setDefaultVideoCodec(videoCodec, preferHwVideoCodec) {
   gDefaultVideoCodec = videoCodec;
+  gDefaultPreferHwVideoCodec = preferHwVideoCodec;
   returnToTest('ok');
 }
 
@@ -156,7 +167,8 @@
         }
         if (gDefaultVideoCodec !== null) {
           localOffer.sdp = setSdpDefaultVideoCodec(localOffer.sdp,
-                                                   gDefaultVideoCodec);
+                                                   gDefaultVideoCodec,
+                                                   gDefaultPreferHwVideoCodec);
         }
         if (gOpusDtx) {
           localOffer.sdp = setOpusDtxEnabled(localOffer.sdp);
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
index 0c41c15..911fc5e0 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
@@ -20,6 +20,7 @@
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.PatternMatcher;
 import android.os.Process;
 import android.os.SystemClock;
 
@@ -53,10 +54,12 @@
 
     private static final String TAG = "Auth";
 
+    @SuppressWarnings("deprecation")
     public SystemAccountManagerDelegate() {
-        mAccountManager = AccountManager.get(ContextUtils.getApplicationContext());
+        Context context = ContextUtils.getApplicationContext();
+        mAccountManager = AccountManager.get(context);
 
-        BroadcastReceiver accountsChangedBroadcastReceiver = new BroadcastReceiver() {
+        BroadcastReceiver receiver = new BroadcastReceiver() {
             @Override
             public void onReceive(final Context context, final Intent intent) {
                 fireOnAccountsChangedNotification();
@@ -64,8 +67,15 @@
         };
         IntentFilter accountsChangedIntentFilter = new IntentFilter();
         accountsChangedIntentFilter.addAction(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
-        ContextUtils.getApplicationContext().registerReceiver(
-                accountsChangedBroadcastReceiver, accountsChangedIntentFilter);
+        context.registerReceiver(receiver, accountsChangedIntentFilter);
+
+        IntentFilter gmsPackageReplacedFilter = new IntentFilter();
+        gmsPackageReplacedFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        gmsPackageReplacedFilter.addDataScheme("package");
+        gmsPackageReplacedFilter.addDataPath(
+                "com.google.android.gms", PatternMatcher.PATTERN_PREFIX);
+
+        context.registerReceiver(receiver, gmsPackageReplacedFilter);
     }
 
     protected void checkCanUseGooglePlayServices() throws AccountManagerDelegateException {
diff --git a/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc b/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc
index 933bb326..89bf250 100644
--- a/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc
+++ b/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc
@@ -27,7 +27,6 @@
         quit_closure_(quit_closure) {}
 
   void Cancel() override {}
-  void CancelAndIgnore() override {}
   void CancelWithError(int error_code) override {
     cancel_with_error_called_ = true;
     error_code_ = error_code;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 4fa45f3..c5e533a 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1370,6 +1370,8 @@
     "service_manager/common_browser_interfaces.h",
     "service_manager/service_manager_context.cc",
     "service_manager/service_manager_context.h",
+    "service_worker/browser_side_service_worker_event_dispatcher.cc",
+    "service_worker/browser_side_service_worker_event_dispatcher.h",
     "service_worker/embedded_worker_instance.cc",
     "service_worker/embedded_worker_instance.h",
     "service_worker/embedded_worker_registry.cc",
diff --git a/content/browser/fileapi/file_system_operation_runner_unittest.cc b/content/browser/fileapi/file_system_operation_runner_unittest.cc
index 168d52e..e20a4e85 100644
--- a/content/browser/fileapi/file_system_operation_runner_unittest.cc
+++ b/content/browser/fileapi/file_system_operation_runner_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_scheduler.h"
 #include "base/task_scheduler/task_traits.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_restrictions.h"
@@ -238,13 +239,8 @@
       base::Bind(&DidOpenFile));
   operation_runner()->Shutdown();
 
-  // Wait until the task posted on FILE thread is done.
-  base::RunLoop run_loop;
-  BrowserThread::PostTaskAndReply(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&base::DoNothing),
-      run_loop.QuitClosure());
-  run_loop.Run();
+  // Wait until the task posted on the blocking thread is done.
+  base::TaskScheduler::GetInstance()->FlushForTesting();
   // This should finish without thread assertion failure on debug build.
 }
 
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc
index c8c8dd0..f4a980f 100644
--- a/content/browser/loader/async_resource_handler.cc
+++ b/content/browser/loader/async_resource_handler.cc
@@ -364,18 +364,11 @@
         sent_received_response_msg_);
 
   int error_code = status.error();
-  const ResourceRequestInfoImpl* info = GetRequestInfo();
-  bool was_ignored_by_handler = info->WasIgnoredByHandler();
 
   DCHECK(status.status() != net::URLRequestStatus::IO_PENDING);
-  // If this check fails, then we're in an inconsistent state because all
-  // requests ignored by the handler should be canceled (which should result in
-  // the ERR_ABORTED error code).
-  DCHECK(!was_ignored_by_handler || error_code == net::ERR_ABORTED);
 
   ResourceRequestCompletionStatus request_complete_data;
   request_complete_data.error_code = error_code;
-  request_complete_data.was_ignored_by_handler = was_ignored_by_handler;
   request_complete_data.exists_in_cache = request()->response_info().was_cached;
   request_complete_data.completion_time = TimeTicks::Now();
   request_complete_data.encoded_data_length =
diff --git a/content/browser/loader/detachable_resource_handler.cc b/content/browser/loader/detachable_resource_handler.cc
index 63e22d5..0042087 100644
--- a/content/browser/loader/detachable_resource_handler.cc
+++ b/content/browser/loader/detachable_resource_handler.cc
@@ -45,11 +45,6 @@
     detachable_handler_->Cancel();
   }
 
-  void CancelAndIgnore() override {
-    MarkAsUsed();
-    detachable_handler_->CancelAndIgnore();
-  }
-
   void CancelWithError(int error_code) override {
     MarkAsUsed();
     detachable_handler_->CancelWithError(error_code);
diff --git a/content/browser/loader/intercepting_resource_handler.cc b/content/browser/loader/intercepting_resource_handler.cc
index 77b28b4..9444b791 100644
--- a/content/browser/loader/intercepting_resource_handler.cc
+++ b/content/browser/loader/intercepting_resource_handler.cc
@@ -35,11 +35,6 @@
     intercepting_handler_->Cancel();
   }
 
-  void CancelAndIgnore() override {
-    MarkAsUsed();
-    intercepting_handler_->CancelAndIgnore();
-  }
-
   void CancelWithError(int error_code) override {
     MarkAsUsed();
     intercepting_handler_->CancelWithError(error_code);
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc
index 112a3ef..6233b89 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -82,11 +82,6 @@
     mime_handler_->Cancel();
   }
 
-  void CancelAndIgnore() override {
-    MarkAsUsed();
-    mime_handler_->CancelAndIgnore();
-  }
-
   void CancelWithError(int error_code) override {
     MarkAsUsed();
     mime_handler_->CancelWithError(error_code);
diff --git a/content/browser/loader/mock_resource_loader.cc b/content/browser/loader/mock_resource_loader.cc
index acadbfc..6971ab41 100644
--- a/content/browser/loader/mock_resource_loader.cc
+++ b/content/browser/loader/mock_resource_loader.cc
@@ -27,11 +27,6 @@
 
   void Cancel() override { CancelWithError(net::ERR_ABORTED); }
 
-  void CancelAndIgnore() override {
-    ADD_FAILURE() << "Unexpected CancelAndIgnore call.";
-    Cancel();
-  }
-
   void CancelWithError(int error_code) override {
     mock_loader_->OnCancel(error_code);
   }
diff --git a/content/browser/loader/mojo_async_resource_handler.cc b/content/browser/loader/mojo_async_resource_handler.cc
index 8abde0c..d021503 100644
--- a/content/browser/loader/mojo_async_resource_handler.cc
+++ b/content/browser/loader/mojo_async_resource_handler.cc
@@ -433,8 +433,6 @@
   buffer_ = nullptr;
   handle_watcher_.Cancel();
 
-  const ResourceRequestInfoImpl* info = GetRequestInfo();
-
   // TODO(gavinp): Remove this CHECK when we figure out the cause of
   // http://crbug.com/124680 . This check mirrors closely check in
   // WebURLLoaderImpl::OnCompletedRequest that routes this message to a WebCore
@@ -444,17 +442,11 @@
         sent_received_response_message_);
 
   int error_code = status.error();
-  bool was_ignored_by_handler = info->WasIgnoredByHandler();
 
   DCHECK_NE(status.status(), net::URLRequestStatus::IO_PENDING);
-  // If this check fails, then we're in an inconsistent state because all
-  // requests ignored by the handler should be canceled (which should result in
-  // the ERR_ABORTED error code).
-  DCHECK(!was_ignored_by_handler || error_code == net::ERR_ABORTED);
 
   ResourceRequestCompletionStatus request_complete_data;
   request_complete_data.error_code = error_code;
-  request_complete_data.was_ignored_by_handler = was_ignored_by_handler;
   request_complete_data.exists_in_cache = request()->response_info().was_cached;
   request_complete_data.completion_time = base::TimeTicks::Now();
   request_complete_data.encoded_data_length =
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc
index d1cc894..02871bfa 100644
--- a/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -615,8 +615,6 @@
 TEST_F(MojoAsyncResourceHandlerTest, OnResponseCompleted) {
   ASSERT_TRUE(CallOnWillStartAndOnResponseStarted());
 
-  ResourceRequestInfoImpl::ForRequest(request_.get())
-      ->set_was_ignored_by_handler(false);
   net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, net::OK);
 
   base::TimeTicks now1 = base::TimeTicks::Now();
@@ -627,7 +625,6 @@
   url_loader_client_.RunUntilComplete();
   EXPECT_TRUE(url_loader_client_.has_received_completion());
   EXPECT_EQ(net::OK, url_loader_client_.completion_status().error_code);
-  EXPECT_FALSE(url_loader_client_.completion_status().was_ignored_by_handler);
   EXPECT_LE(now1, url_loader_client_.completion_status().completion_time);
   EXPECT_LE(url_loader_client_.completion_status().completion_time, now2);
   EXPECT_EQ(request_->GetTotalReceivedBytes(),
@@ -647,8 +644,6 @@
   ASSERT_FALSE(url_loader_client_.has_received_response());
   url_loader_client_.RunUntilResponseReceived();
 
-  ResourceRequestInfoImpl::ForRequest(request_.get())
-      ->set_was_ignored_by_handler(true);
   net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
                                net::ERR_ABORTED);
 
@@ -661,7 +656,6 @@
   EXPECT_TRUE(url_loader_client_.has_received_completion());
   EXPECT_EQ(net::ERR_ABORTED,
             url_loader_client_.completion_status().error_code);
-  EXPECT_TRUE(url_loader_client_.completion_status().was_ignored_by_handler);
   EXPECT_LE(now1, url_loader_client_.completion_status().completion_time);
   EXPECT_LE(url_loader_client_.completion_status().completion_time, now2);
   EXPECT_EQ(request_->GetTotalReceivedBytes(),
diff --git a/content/browser/loader/navigation_resource_handler.cc b/content/browser/loader/navigation_resource_handler.cc
index 9a4cc38..57361300 100644
--- a/content/browser/loader/navigation_resource_handler.cc
+++ b/content/browser/loader/navigation_resource_handler.cc
@@ -57,7 +57,7 @@
   if (core_) {
     DetachFromCore();
     if (has_controller()) {
-      CancelAndIgnore();
+      LayeredResourceHandler::Cancel();
     } else {
       OutOfBandCancel(net::ERR_ABORTED, true /* tell_renderer */);
     }
@@ -92,7 +92,7 @@
 
   // The UI thread already cancelled the navigation. Do not proceed.
   if (!core_) {
-    controller->CancelAndIgnore();
+    controller->Cancel();
     return;
   }
 
@@ -112,7 +112,7 @@
 
   // The UI thread already cancelled the navigation. Do not proceed.
   if (!core_) {
-    controller->CancelAndIgnore();
+    controller->Cancel();
     return;
   }
 
diff --git a/content/browser/loader/navigation_resource_throttle.cc b/content/browser/loader/navigation_resource_throttle.cc
index 0d79161..76f618c 100644
--- a/content/browser/loader/navigation_resource_throttle.cc
+++ b/content/browser/loader/navigation_resource_throttle.cc
@@ -349,9 +349,8 @@
     return;
   }
 
-  if (result == NavigationThrottle::CANCEL_AND_IGNORE) {
-    CancelAndIgnore();
-  } else if (result == NavigationThrottle::CANCEL) {
+  if (result == NavigationThrottle::CANCEL_AND_IGNORE ||
+      result == NavigationThrottle::CANCEL) {
     Cancel();
   } else if (result == NavigationThrottle::BLOCK_REQUEST ||
              result == NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE) {
diff --git a/content/browser/loader/null_resource_controller.cc b/content/browser/loader/null_resource_controller.cc
index 05c3164..da79bb5 100644
--- a/content/browser/loader/null_resource_controller.cc
+++ b/content/browser/loader/null_resource_controller.cc
@@ -19,10 +19,6 @@
   DCHECK(!*was_resumed_);
 }
 
-void NullResourceController::CancelAndIgnore() {
-  DCHECK(!*was_resumed_);
-}
-
 void NullResourceController::CancelWithError(int error_code) {
   DCHECK(!*was_resumed_);
 }
diff --git a/content/browser/loader/null_resource_controller.h b/content/browser/loader/null_resource_controller.h
index b9e6caf..8dd10f7 100644
--- a/content/browser/loader/null_resource_controller.h
+++ b/content/browser/loader/null_resource_controller.h
@@ -21,7 +21,6 @@
 
   // ResourceController implementation:
   void Cancel() override;
-  void CancelAndIgnore() override;
   void CancelWithError(int error_code) override;
   void Resume() override;
 
diff --git a/content/browser/loader/resource_controller.h b/content/browser/loader/resource_controller.h
index 85672556..8278534 100644
--- a/content/browser/loader/resource_controller.h
+++ b/content/browser/loader/resource_controller.h
@@ -19,7 +19,6 @@
   virtual ~ResourceController() {}
 
   virtual void Cancel() = 0;
-  virtual void CancelAndIgnore() = 0;
   virtual void CancelWithError(int error_code) = 0;
 
   // Resumes the request. May only be called if the request was previously
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 0775a685..f880762 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -223,7 +223,6 @@
     // Tell the renderer that this request was disallowed.
     ResourceRequestCompletionStatus request_complete_data;
     request_complete_data.error_code = net::ERR_ABORTED;
-    request_complete_data.was_ignored_by_handler = false;
     request_complete_data.exists_in_cache = false;
     // No security info needed, connection not established.
     request_complete_data.completion_time = base::TimeTicks();
diff --git a/content/browser/loader/resource_handler.cc b/content/browser/loader/resource_handler.cc
index 0f87551..57c0bc2 100644
--- a/content/browser/loader/resource_handler.cc
+++ b/content/browser/loader/resource_handler.cc
@@ -42,10 +42,6 @@
   ReleaseController()->Cancel();
 }
 
-void ResourceHandler::CancelAndIgnore() {
-  ReleaseController()->CancelAndIgnore();
-}
-
 void ResourceHandler::CancelWithError(int error_code) {
   ReleaseController()->CancelWithError(error_code);
 }
diff --git a/content/browser/loader/resource_handler.h b/content/browser/loader/resource_handler.h
index 2b67e0c4..b787b9c 100644
--- a/content/browser/loader/resource_handler.h
+++ b/content/browser/loader/resource_handler.h
@@ -154,7 +154,6 @@
   // passed to HoldController and then destroy it.
   void Resume();
   void Cancel();
-  void CancelAndIgnore();
   void CancelWithError(int error_code);
 
   // Cancels the request when the class does not currently have ownership of the
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 3a18593..82ca8ef 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -147,11 +147,6 @@
     resource_loader_->Cancel();
   }
 
-  void CancelAndIgnore() override {
-    MarkAsUsed();
-    resource_loader_->CancelAndIgnore();
-  }
-
   void CancelWithError(int error_code) override {
     MarkAsUsed();
     resource_loader_->CancelWithError(error_code);
@@ -251,12 +246,6 @@
   CancelRequestInternal(net::ERR_ABORTED, from_renderer);
 }
 
-void ResourceLoader::CancelAndIgnore() {
-  ResourceRequestInfoImpl* info = GetRequestInfo();
-  info->set_was_ignored_by_handler(true);
-  CancelRequest(false);
-}
-
 void ResourceLoader::CancelWithError(int error_code) {
   TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CancelWithError", this,
                          TRACE_EVENT_FLAG_FLOW_IN);
@@ -360,7 +349,7 @@
   } else {
     *defer = false;
     if (delegate_->HandleExternalProtocol(this, redirect_info.new_url))
-      CancelAndIgnore();
+      Cancel();
   }
 }
 
@@ -566,7 +555,7 @@
   }
 
   if (delegate_->HandleExternalProtocol(this, request_->url())) {
-    CancelAndIgnore();
+    Cancel();
     return;
   }
 
@@ -627,7 +616,7 @@
   GURL redirect_url = deferred_redirect_url_;
   deferred_redirect_url_ = GURL();
   if (delegate_->HandleExternalProtocol(this, redirect_url)) {
-    CancelAndIgnore();
+    Cancel();
   } else {
     request_->FollowDeferredRedirect();
   }
diff --git a/content/browser/loader/resource_loader.h b/content/browser/loader/resource_loader.h
index 49ce93a..18efa50 100644
--- a/content/browser/loader/resource_loader.h
+++ b/content/browser/loader/resource_loader.h
@@ -95,7 +95,6 @@
   // otherwise.
   void Resume(bool called_from_resource_controller);
   void Cancel();
-  void CancelAndIgnore();
   void CancelWithError(int error_code);
 
   void StartRequestInternal();
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index 489376cd..7b39aef 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -169,7 +169,6 @@
       enable_load_timing_(enable_load_timing),
       enable_upload_progress_(enable_upload_progress),
       do_not_prompt_for_login_(do_not_prompt_for_login),
-      was_ignored_by_handler_(false),
       counted_as_in_flight_request_(false),
       resource_type_(resource_type),
       transition_type_(transition_type),
@@ -289,10 +288,6 @@
   return has_user_gesture_;
 }
 
-bool ResourceRequestInfoImpl::WasIgnoredByHandler() const {
-  return was_ignored_by_handler_;
-}
-
 bool ResourceRequestInfoImpl::GetAssociatedRenderFrame(
     int* render_process_id,
     int* render_frame_id) const {
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h
index 1758ab4..56d24b39 100644
--- a/content/browser/loader/resource_request_info_impl.h
+++ b/content/browser/loader/resource_request_info_impl.h
@@ -94,7 +94,6 @@
   blink::WebPageVisibilityState GetVisibilityState() const override;
   ui::PageTransition GetPageTransition() const override;
   bool HasUserGesture() const override;
-  bool WasIgnoredByHandler() const override;
   bool GetAssociatedRenderFrame(int* render_process_id,
                                 int* render_frame_id) const override;
   bool IsAsync() const override;
@@ -155,10 +154,6 @@
   bool is_stream() const { return is_stream_; }
   void set_is_stream(bool stream) { is_stream_ = stream; }
 
-  void set_was_ignored_by_handler(bool value) {
-    was_ignored_by_handler_ = value;
-  }
-
   // Whether this request has been counted towards the number of in flight
   // requests, which is only true for requests that require a file descriptor
   // for their shared memory buffer.
@@ -228,7 +223,6 @@
   bool enable_load_timing_;
   bool enable_upload_progress_;
   bool do_not_prompt_for_login_;
-  bool was_ignored_by_handler_;
   bool counted_as_in_flight_request_;
   ResourceType resource_type_;
   ui::PageTransition transition_type_;
diff --git a/content/browser/loader/resource_scheduler_unittest.cc b/content/browser/loader/resource_scheduler_unittest.cc
index 99344d2..c3d9877 100644
--- a/content/browser/loader/resource_scheduler_unittest.cc
+++ b/content/browser/loader/resource_scheduler_unittest.cc
@@ -102,7 +102,6 @@
 
  protected:
   // ResourceThrottle::Delegate interface:
-  void CancelAndIgnore() override {}
   void CancelWithError(int error_code) override {}
   void Resume() override { started_ = true; }
 
diff --git a/content/browser/loader/throttling_resource_handler.cc b/content/browser/loader/throttling_resource_handler.cc
index a106f05..e3f89d50 100644
--- a/content/browser/loader/throttling_resource_handler.cc
+++ b/content/browser/loader/throttling_resource_handler.cc
@@ -126,15 +126,6 @@
   ResourceHandler::Cancel();
 }
 
-void ThrottlingResourceHandler::CancelAndIgnore() {
-  if (!has_controller()) {
-    OutOfBandCancel(net::ERR_ABORTED, false /* tell_renderer */);
-    return;
-  }
-  cancelled_by_resource_throttle_ = true;
-  ResourceHandler::CancelAndIgnore();
-}
-
 void ThrottlingResourceHandler::CancelWithError(int error_code) {
   if (!has_controller()) {
     OutOfBandCancel(error_code, false /* tell_renderer */);
diff --git a/content/browser/loader/throttling_resource_handler.h b/content/browser/loader/throttling_resource_handler.h
index c089979a..518ec5c 100644
--- a/content/browser/loader/throttling_resource_handler.h
+++ b/content/browser/loader/throttling_resource_handler.h
@@ -50,7 +50,6 @@
 
   // ResourceThrottle::Delegate implementation:
   void Cancel() override;
-  void CancelAndIgnore() override;
   void CancelWithError(int error_code) override;
   void Resume() override;
 
diff --git a/content/browser/service_worker/browser_side_service_worker_event_dispatcher.cc b/content/browser/service_worker/browser_side_service_worker_event_dispatcher.cc
new file mode 100644
index 0000000..1f202c4
--- /dev/null
+++ b/content/browser/service_worker/browser_side_service_worker_event_dispatcher.cc
@@ -0,0 +1,131 @@
+// 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/service_worker/browser_side_service_worker_event_dispatcher.h"
+
+#include "content/browser/service_worker/service_worker_version.h"
+
+namespace content {
+
+BrowserSideServiceWorkerEventDispatcher::
+    BrowserSideServiceWorkerEventDispatcher(
+        ServiceWorkerVersion* receiver_version)
+    : receiver_version_(receiver_version) {
+  DCHECK(receiver_version_);
+}
+
+BrowserSideServiceWorkerEventDispatcher::
+    ~BrowserSideServiceWorkerEventDispatcher() = default;
+
+mojom::ServiceWorkerEventDispatcherPtrInfo
+BrowserSideServiceWorkerEventDispatcher::CreateEventDispatcherPtrInfo() {
+  mojom::ServiceWorkerEventDispatcherPtrInfo dispatcher_ptr_info;
+  incoming_event_bindings_.AddBinding(this,
+                                      mojo::MakeRequest(&dispatcher_ptr_info));
+  return dispatcher_ptr_info;
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchInstallEvent(
+    mojom::ServiceWorkerInstallEventMethodsAssociatedPtrInfo client,
+    DispatchInstallEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchActivateEvent(
+    DispatchActivateEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchBackgroundFetchAbortEvent(
+    const std::string& tag,
+    DispatchBackgroundFetchAbortEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchBackgroundFetchClickEvent(
+    const std::string& tag,
+    mojom::BackgroundFetchState state,
+    DispatchBackgroundFetchClickEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchBackgroundFetchFailEvent(
+    const std::string& tag,
+    const std::vector<BackgroundFetchSettledFetch>& fetches,
+    DispatchBackgroundFetchFailEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchBackgroundFetchedEvent(
+    const std::string& tag,
+    const std::vector<BackgroundFetchSettledFetch>& fetches,
+    DispatchBackgroundFetchedEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchExtendableMessageEvent(
+    mojom::ExtendableMessageEventPtr event,
+    DispatchExtendableMessageEventCallback callback) {
+  NOTIMPLEMENTED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchFetchEvent(
+    int fetch_event_id,
+    const ServiceWorkerFetchRequest& request,
+    mojom::FetchEventPreloadHandlePtr preload_handle,
+    mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+    DispatchFetchEventCallback callback) {
+  NOTIMPLEMENTED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchNotificationClickEvent(
+    const std::string& notification_id,
+    const PlatformNotificationData& notification_data,
+    int action_index,
+    const base::Optional<base::string16>& reply,
+    DispatchNotificationClickEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchNotificationCloseEvent(
+    const std::string& notification_id,
+    const PlatformNotificationData& notification_data,
+    DispatchNotificationCloseEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchPushEvent(
+    const PushEventPayload& payload,
+    DispatchPushEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchSyncEvent(
+    const std::string& tag,
+    blink::mojom::BackgroundSyncEventLastChance last_chance,
+    DispatchSyncEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchCanMakePaymentEvent(
+    int payment_request_id,
+    payments::mojom::CanMakePaymentEventDataPtr event_data,
+    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+    DispatchCanMakePaymentEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::DispatchPaymentRequestEvent(
+    int payment_request_id,
+    payments::mojom::PaymentRequestEventDataPtr event_data,
+    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+    DispatchPaymentRequestEventCallback callback) {
+  NOTREACHED();
+}
+
+void BrowserSideServiceWorkerEventDispatcher::Ping(PingCallback callback) {
+  NOTREACHED();
+}
+
+}  // namespace content
diff --git a/content/browser/service_worker/browser_side_service_worker_event_dispatcher.h b/content/browser/service_worker/browser_side_service_worker_event_dispatcher.h
new file mode 100644
index 0000000..c1067fb
--- /dev/null
+++ b/content/browser/service_worker/browser_side_service_worker_event_dispatcher.h
@@ -0,0 +1,112 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_BROWSER_SIDE_SERVICE_WORKER_EVENT_DISPATCHER_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_BROWSER_SIDE_SERVICE_WORKER_EVENT_DISPATCHER_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+
+namespace content {
+
+class ServiceWorkerVersion;
+
+// Temporary class until we start to have ServiceWorkerVersion-like object
+// in the renderer.
+//
+// BrowserSideServiceWorkerEventDispatcher forward events to a
+// ServiceWorkerVersion. It's the browser-side implementation of
+// mojom::ServiceWorkerEventDispatcher, used by the renderer to dispatch
+// events initiated by a controllee to its controlling service worker.
+// The short-term plan is for it to be used to dispatch fetch events directly
+// to the service worker instead of relying on ServiceWorkerURLRequestJob.
+// The (slightly) longer term plan is to have this in the renderer and
+// dispatch events directly from the page to the ServiceWorker without going
+// through the browser process.
+//
+// TODO(kinuko): this should probably eventually replace ServiceWorkerHandle
+// and get state changes.
+class BrowserSideServiceWorkerEventDispatcher
+    : public mojom::ServiceWorkerEventDispatcher {
+ public:
+  explicit BrowserSideServiceWorkerEventDispatcher(
+      ServiceWorkerVersion* receiver_version);
+  ~BrowserSideServiceWorkerEventDispatcher() override;
+
+  mojom::ServiceWorkerEventDispatcherPtrInfo CreateEventDispatcherPtrInfo();
+
+  // mojom::ServiceWorkerEventDispatcher:
+  void DispatchInstallEvent(
+      mojom::ServiceWorkerInstallEventMethodsAssociatedPtrInfo client,
+      DispatchInstallEventCallback callback) override;
+  void DispatchActivateEvent(DispatchActivateEventCallback callback) override;
+  void DispatchBackgroundFetchAbortEvent(
+      const std::string& tag,
+      DispatchBackgroundFetchAbortEventCallback callback) override;
+  void DispatchBackgroundFetchClickEvent(
+      const std::string& tag,
+      mojom::BackgroundFetchState state,
+      DispatchBackgroundFetchClickEventCallback callback) override;
+  void DispatchBackgroundFetchFailEvent(
+      const std::string& tag,
+      const std::vector<BackgroundFetchSettledFetch>& fetches,
+      DispatchBackgroundFetchFailEventCallback callback) override;
+  void DispatchBackgroundFetchedEvent(
+      const std::string& tag,
+      const std::vector<BackgroundFetchSettledFetch>& fetches,
+      DispatchBackgroundFetchedEventCallback callback) override;
+  void DispatchExtendableMessageEvent(
+      mojom::ExtendableMessageEventPtr event,
+      DispatchExtendableMessageEventCallback callback) override;
+  void DispatchFetchEvent(
+      int fetch_event_id,
+      const ServiceWorkerFetchRequest& request,
+      mojom::FetchEventPreloadHandlePtr preload_handle,
+      mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+      DispatchFetchEventCallback callback) override;
+  void DispatchNotificationClickEvent(
+      const std::string& notification_id,
+      const PlatformNotificationData& notification_data,
+      int action_index,
+      const base::Optional<base::string16>& reply,
+      DispatchNotificationClickEventCallback callback) override;
+  void DispatchNotificationCloseEvent(
+      const std::string& notification_id,
+      const PlatformNotificationData& notification_data,
+      DispatchNotificationCloseEventCallback callback) override;
+  void DispatchPushEvent(const PushEventPayload& payload,
+                         DispatchPushEventCallback callback) override;
+  void DispatchSyncEvent(
+      const std::string& tag,
+      blink::mojom::BackgroundSyncEventLastChance last_chance,
+      DispatchSyncEventCallback callback) override;
+  void DispatchCanMakePaymentEvent(
+      int payment_request_id,
+      payments::mojom::CanMakePaymentEventDataPtr event_data,
+      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      DispatchCanMakePaymentEventCallback callback) override;
+  void DispatchPaymentRequestEvent(
+      int payment_request_id,
+      payments::mojom::PaymentRequestEventDataPtr event_data,
+      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
+      DispatchPaymentRequestEventCallback callback) override;
+  void Ping(PingCallback callback) override;
+
+ private:
+  // Connected to ServiceWorkerNetworkProvider's of the controllees (and of the
+  // browser, when this object starts to live in the renderer process).
+  mojo::BindingSet<mojom::ServiceWorkerEventDispatcher>
+      incoming_event_bindings_;
+
+  // Not owned; this proxy should go away before the version goes away.
+  ServiceWorkerVersion* receiver_version_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserSideServiceWorkerEventDispatcher);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_SERVICE_WORKER_BROWSER_SIDE_SERVICE_WORKER_EVENT_DISPATCHER_H_
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 8f0bede..85ef5491 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "base/time/time.h"
+#include "content/browser/service_worker/browser_side_service_worker_event_dispatcher.h"
 #include "content/browser/service_worker/embedded_worker_status.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_request_handler.h"
@@ -542,8 +543,14 @@
 
   scoped_refptr<ServiceWorkerVersion> previous_version = controlling_version_;
   controlling_version_ = version;
+
+  // This will drop the message pipes to the client pages as well.
+  controlling_version_event_dispatcher_.reset();
+
   if (version) {
     version->AddControllee(this);
+    controlling_version_event_dispatcher_ =
+        base::MakeUnique<BrowserSideServiceWorkerEventDispatcher>(version);
     for (const auto& pair : worker_clients_) {
       pair.second->SetControllerServiceWorker(version->version_id());
     }
@@ -556,10 +563,19 @@
 
   // SetController message should be sent only for controllees.
   DCHECK(IsProviderForClient());
-  Send(new ServiceWorkerMsg_SetControllerServiceWorker(
-      render_thread_id_, provider_id(), GetOrCreateServiceWorkerHandle(version),
-      notify_controllerchange,
-      version ? version->used_features() : std::set<uint32_t>()));
+  ServiceWorkerMsg_SetControllerServiceWorker_Params params;
+  params.thread_id = render_thread_id_;
+  params.provider_id = provider_id();
+  params.object_info = GetOrCreateServiceWorkerHandle(version);
+  params.should_notify_controllerchange = notify_controllerchange;
+  if (version) {
+    params.used_features = version->used_features();
+    params.controller_event_dispatcher =
+        controlling_version_event_dispatcher_->CreateEventDispatcherPtrInfo()
+            .PassHandle()
+            .release();
+  }
+  Send(new ServiceWorkerMsg_SetControllerServiceWorker(params));
 }
 
 bool ServiceWorkerProviderHost::IsProviderForClient() const {
@@ -1120,12 +1136,16 @@
   if (associated_registration_.get()) {
     SendAssociateRegistrationMessage();
     if (dispatcher_host_ && associated_registration_->active_version()) {
-      Send(new ServiceWorkerMsg_SetControllerServiceWorker(
-          render_thread_id_, provider_id(),
-          GetOrCreateServiceWorkerHandle(
-              associated_registration_->active_version()),
-          false /* shouldNotifyControllerChange */,
-          associated_registration_->active_version()->used_features()));
+      ServiceWorkerMsg_SetControllerServiceWorker_Params params;
+      params.thread_id = render_thread_id_;
+      params.provider_id = provider_id();
+      params.object_info = GetOrCreateServiceWorkerHandle(
+          associated_registration_->active_version());
+      params.should_notify_controllerchange = false;
+      params.used_features =
+          associated_registration_->active_version()->used_features();
+      // TODO(kinuko): Fill controller_event_dispatcher
+      Send(new ServiceWorkerMsg_SetControllerServiceWorker(params));
     }
   }
 }
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index b4cec2af2..0a07363 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -22,6 +22,7 @@
 #include "base/time/time.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/common/content_export.h"
+#include "content/common/service_worker/service_worker_event_dispatcher.mojom.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"
@@ -44,6 +45,7 @@
 class ServiceWorkerDispatcherHost;
 class ServiceWorkerRequestHandler;
 class ServiceWorkerVersion;
+class BrowserSideServiceWorkerEventDispatcher;
 class WebContents;
 
 // This class is the browser-process representation of a service worker
@@ -440,6 +442,8 @@
 
   std::unique_ptr<OneShotGetReadyCallback> get_ready_callback_;
   scoped_refptr<ServiceWorkerVersion> controlling_version_;
+  std::unique_ptr<BrowserSideServiceWorkerEventDispatcher>
+      controlling_version_event_dispatcher_;
   scoped_refptr<ServiceWorkerVersion> running_hosted_version_;
   base::WeakPtr<ServiceWorkerContextCore> context_;
   ServiceWorkerDispatcherHost* dispatcher_host_;
diff --git a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
index 8f8acbf..e61bb3c2 100644
--- a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
+++ b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
@@ -1504,4 +1504,39 @@
                 "failTestAfterTimeout('Got no mute event', 1500);"));
 }
 
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, SrcObjectAddVideoTrack) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+  NavigateToURL(shell(), url);
+  ExecuteJavascriptAndWaitForOk("srcObjectAddVideoTrack()");
+}
+
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+                       SrcObjectRemoveVideoTrack) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+  NavigateToURL(shell(), url);
+  ExecuteJavascriptAndWaitForOk("srcObjectRemoveVideoTrack()");
+}
+
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+                       SrcObjectRemoveFirstOfTwoVideoTracks) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+  NavigateToURL(shell(), url);
+  ExecuteJavascriptAndWaitForOk("srcObjectRemoveFirstOfTwoVideoTracks()");
+}
+
+// TODO(guidou): Add SrcObjectAddAudioTrack and SrcObjectRemoveAudioTrack tests
+// when a straightforward mechanism to detect the presence/absence of audio in a
+// media element with an assigned MediaStream becomes available.
+
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+                       SrcObjectReassignSameObject) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+  NavigateToURL(shell(), url);
+  ExecuteJavascriptAndWaitForOk("srcObjectReassignSameObject()");
+}
+
 }  // namespace content
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index 4c86d90..5df6e50 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -372,7 +372,6 @@
   // but the past attempt to change it seems to have caused crashes.
   // (crbug.com/547047)
   peer->OnCompletedRequest(request_complete_data.error_code,
-                           request_complete_data.was_ignored_by_handler,
                            request_complete_data.exists_in_cache,
                            renderer_completion_time,
                            request_complete_data.encoded_data_length,
@@ -828,7 +827,6 @@
   // TODO(kinuko): Fill this properly.
   ResourceRequestCompletionStatus completion_status;
   completion_status.error_code = net::OK;
-  completion_status.was_ignored_by_handler = false;
   completion_status.exists_in_cache = false;
   completion_status.completion_time = base::TimeTicks::Now();
   completion_status.encoded_data_length = -1;
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc
index 7d13c5c3..9407a7f9 100644
--- a/content/child/resource_dispatcher_unittest.cc
+++ b/content/child/resource_dispatcher_unittest.cc
@@ -194,7 +194,6 @@
   void NotifyRequestComplete(int request_id, size_t total_size) {
     ResourceRequestCompletionStatus request_complete_data;
     request_complete_data.error_code = net::OK;
-    request_complete_data.was_ignored_by_handler = false;
     request_complete_data.exists_in_cache = false;
     request_complete_data.encoded_data_length = total_size;
     EXPECT_TRUE(dispatcher_->OnMessageReceived(
@@ -426,7 +425,6 @@
     void OnTransferSizeUpdated(int transfer_size_diff) override {}
 
     void OnCompletedRequest(int error_code,
-                            bool was_ignored_by_handler,
                             bool stale_copy_in_cache,
                             const base::TimeTicks& completion_time,
                             int64_t total_transfer_size,
@@ -437,10 +435,9 @@
         original_peer_->OnReceivedData(
             base::MakeUnique<FixedReceivedData>(data_.data(), data_.size()));
       }
-      original_peer_->OnCompletedRequest(error_code, was_ignored_by_handler,
-                                         stale_copy_in_cache, completion_time,
-                                         total_transfer_size, encoded_body_size,
-                                         decoded_body_size);
+      original_peer_->OnCompletedRequest(error_code, stale_copy_in_cache,
+                                         completion_time, total_transfer_size,
+                                         encoded_body_size, decoded_body_size);
     }
 
    private:
diff --git a/content/child/service_worker/service_worker_dispatcher.cc b/content/child/service_worker/service_worker_dispatcher.cc
index a3694b2..c951f79 100644
--- a/content/child/service_worker/service_worker_dispatcher.cc
+++ b/content/child/service_worker/service_worker_dispatcher.cc
@@ -21,6 +21,7 @@
 #include "content/child/service_worker/web_service_worker_registration_impl.h"
 #include "content/child/thread_safe_sender.h"
 #include "content/child/webmessageportchannel_impl.h"
+#include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/content_constants.h"
@@ -820,37 +821,45 @@
 }
 
 void ServiceWorkerDispatcher::OnSetControllerServiceWorker(
-    int thread_id,
-    int provider_id,
-    const ServiceWorkerObjectInfo& info,
-    bool should_notify_controllerchange,
-    const std::set<uint32_t>& used_features) {
-  TRACE_EVENT2("ServiceWorker",
-               "ServiceWorkerDispatcher::OnSetControllerServiceWorker",
-               "Thread ID", thread_id,
-               "Provider ID", provider_id);
+    const ServiceWorkerMsg_SetControllerServiceWorker_Params& params) {
+  TRACE_EVENT2(
+      "ServiceWorker", "ServiceWorkerDispatcher::OnSetControllerServiceWorker",
+      "Thread ID", params.thread_id, "Provider ID", params.provider_id);
+
+  mojom::ServiceWorkerEventDispatcherPtrInfo event_dispatcher_ptr_info;
+  if (params.controller_event_dispatcher.is_valid()) {
+    // Chrome doesn't use interface versioning.
+    event_dispatcher_ptr_info = mojom::ServiceWorkerEventDispatcherPtrInfo(
+        mojo::ScopedMessagePipeHandle(params.controller_event_dispatcher),
+        0u /* version */);
+  }
 
   // Adopt the reference sent from the browser process and pass it to the
   // provider context if it exists.
-  std::unique_ptr<ServiceWorkerHandleReference> handle_ref = Adopt(info);
-  ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
+  std::unique_ptr<ServiceWorkerHandleReference> handle_ref =
+      Adopt(params.object_info);
+  ProviderContextMap::iterator provider =
+      provider_contexts_.find(params.provider_id);
   if (provider != provider_contexts_.end()) {
-    provider->second->OnSetControllerServiceWorker(std::move(handle_ref),
-                                                   used_features);
+    provider->second->OnSetControllerServiceWorker(
+        std::move(handle_ref), params.used_features,
+        std::move(event_dispatcher_ptr_info));
   }
 
-  ProviderClientMap::iterator found = provider_clients_.find(provider_id);
+  ProviderClientMap::iterator found =
+      provider_clients_.find(params.provider_id);
   if (found != provider_clients_.end()) {
     // Sync the controllee's use counter with the service worker's one.
-    for (uint32_t feature : used_features)
+    for (uint32_t feature : params.used_features)
       found->second->CountFeature(feature);
 
     // Get the existing worker object or create a new one with a new reference
     // to populate the .controller field.
-    scoped_refptr<WebServiceWorkerImpl> worker = GetOrCreateServiceWorker(
-        ServiceWorkerHandleReference::Create(info, thread_safe_sender_.get()));
+    scoped_refptr<WebServiceWorkerImpl> worker =
+        GetOrCreateServiceWorker(ServiceWorkerHandleReference::Create(
+            params.object_info, thread_safe_sender_.get()));
     found->second->SetController(WebServiceWorkerImpl::CreateHandle(worker),
-                                 should_notify_controllerchange);
+                                 params.should_notify_controllerchange);
     // You must not access |found| after setController() because it may fire the
     // controllerchange event that may remove the provider client, for example,
     // by detaching an iframe.
diff --git a/content/child/service_worker/service_worker_dispatcher.h b/content/child/service_worker/service_worker_dispatcher.h
index 83619d3dd7..51d51eb 100644
--- a/content/child/service_worker/service_worker_dispatcher.h
+++ b/content/child/service_worker/service_worker_dispatcher.h
@@ -18,6 +18,7 @@
 #include "base/strings/string16.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/child/worker_thread.h"
+#include "mojo/public/cpp/system/message_pipe.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerProvider.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRegistration.h"
@@ -34,6 +35,7 @@
 }
 
 struct ServiceWorkerMsg_MessageToDocument_Params;
+struct ServiceWorkerMsg_SetControllerServiceWorker_Params;
 
 namespace content {
 
@@ -290,11 +292,8 @@
                               const ServiceWorkerVersionAttributes& attributes);
   void OnUpdateFound(int thread_id,
                      int registration_handle_id);
-  void OnSetControllerServiceWorker(int thread_id,
-                                    int provider_id,
-                                    const ServiceWorkerObjectInfo& info,
-                                    bool should_notify_controllerchange,
-                                    const std::set<uint32_t>& used_features);
+  void OnSetControllerServiceWorker(
+      const ServiceWorkerMsg_SetControllerServiceWorker_Params& params);
   void OnPostMessage(const ServiceWorkerMsg_MessageToDocument_Params& params);
   void OnCountFeature(int thread_id, int provider_id, uint32_t feature);
 
diff --git a/content/child/service_worker/service_worker_dispatcher_unittest.cc b/content/child/service_worker/service_worker_dispatcher_unittest.cc
index 93d25c2..8d27229 100644
--- a/content/child/service_worker/service_worker_dispatcher_unittest.cc
+++ b/content/child/service_worker/service_worker_dispatcher_unittest.cc
@@ -89,9 +89,13 @@
                                     const ServiceWorkerObjectInfo& info,
                                     bool should_notify_controllerchange,
                                     const std::set<uint32_t>& used_features) {
-    dispatcher_->OnSetControllerServiceWorker(thread_id, provider_id, info,
-                                              should_notify_controllerchange,
-                                              used_features);
+    ServiceWorkerMsg_SetControllerServiceWorker_Params params;
+    params.thread_id = thread_id;
+    params.provider_id = provider_id;
+    params.object_info = info;
+    params.should_notify_controllerchange = should_notify_controllerchange;
+    params.used_features = used_features;
+    dispatcher_->OnSetControllerServiceWorker(params);
   }
 
   void OnPostMessage(const ServiceWorkerMsg_MessageToDocument_Params& params) {
diff --git a/content/child/service_worker/service_worker_message_filter.cc b/content/child/service_worker/service_worker_message_filter.cc
index 47d7787be..eafb69b 100644
--- a/content/child/service_worker/service_worker_message_filter.cc
+++ b/content/child/service_worker/service_worker_message_filter.cc
@@ -140,12 +140,9 @@
 }
 
 void ServiceWorkerMessageFilter::OnStaleSetControllerServiceWorker(
-    int thread_id,
-    int provider_id,
-    const ServiceWorkerObjectInfo& info,
-    bool should_notify_controllerchange,
-    const std::set<uint32_t>& used_features) {
-  SendServiceWorkerObjectDestroyed(thread_safe_sender(), info.handle_id);
+    const ServiceWorkerMsg_SetControllerServiceWorker_Params& params) {
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
+                                   params.object_info.handle_id);
 }
 
 void ServiceWorkerMessageFilter::OnStaleMessageToDocument(
diff --git a/content/child/service_worker/service_worker_message_filter.h b/content/child/service_worker/service_worker_message_filter.h
index de0b266..1d3842c 100644
--- a/content/child/service_worker/service_worker_message_filter.h
+++ b/content/child/service_worker/service_worker_message_filter.h
@@ -13,10 +13,10 @@
 #include "content/common/content_export.h"
 
 struct ServiceWorkerMsg_MessageToDocument_Params;
+struct ServiceWorkerMsg_SetControllerServiceWorker_Params;
 
 namespace content {
 
-struct ServiceWorkerObjectInfo;
 struct ServiceWorkerRegistrationObjectInfo;
 struct ServiceWorkerVersionAttributes;
 
@@ -59,11 +59,7 @@
       int changed_mask,
       const ServiceWorkerVersionAttributes& attrs);
   void OnStaleSetControllerServiceWorker(
-      int thread_id,
-      int provider_id,
-      const ServiceWorkerObjectInfo& info,
-      bool should_notify_controllerchange,
-      const std::set<uint32_t>& used_features);
+      const ServiceWorkerMsg_SetControllerServiceWorker_Params& params);
   void OnStaleMessageToDocument(
       const ServiceWorkerMsg_MessageToDocument_Params& params);
 
diff --git a/content/child/service_worker/service_worker_network_provider.cc b/content/child/service_worker/service_worker_network_provider.cc
index 4d1c795b..4ccc613 100644
--- a/content/child/service_worker/service_worker_network_provider.cc
+++ b/content/child/service_worker/service_worker_network_provider.cc
@@ -92,6 +92,18 @@
 
   ServiceWorkerNetworkProvider* provider() { return provider_.get(); }
 
+  std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
+      const blink::WebURLRequest& request,
+      base::SingleThreadTaskRunner* task_runner) override {
+    if (!ServiceWorkerUtils::IsServicificationEnabled() ||
+        !provider_->context() || !provider_->context()->event_dispatcher())
+      return nullptr;
+
+    // TODO(kinuko): Set up URLLoaderFactory with NetworkProvider's
+    // event_dispatcher_ for fetch event handling.
+    return nullptr;
+  }
+
  private:
   std::unique_ptr<ServiceWorkerNetworkProvider> provider_;
 };
@@ -139,28 +151,40 @@
     const bool is_parent_frame_secure = IsFrameSecure(frame->Parent());
 
     if (service_worker_provider_id == kInvalidServiceWorkerProviderId) {
-      network_provider = std::unique_ptr<ServiceWorkerNetworkProvider>(
-          new ServiceWorkerNetworkProvider(route_id,
-                                           SERVICE_WORKER_PROVIDER_FOR_WINDOW,
-                                           is_parent_frame_secure));
+      network_provider = base::WrapUnique(new ServiceWorkerNetworkProvider(
+          route_id, SERVICE_WORKER_PROVIDER_FOR_WINDOW, GetNextProviderId(),
+          is_parent_frame_secure));
     } else {
       CHECK(browser_side_navigation);
       DCHECK(ServiceWorkerUtils::IsBrowserAssignedProviderId(
           service_worker_provider_id));
-      network_provider = std::unique_ptr<ServiceWorkerNetworkProvider>(
-          new ServiceWorkerNetworkProvider(
-              route_id, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
-              service_worker_provider_id, is_parent_frame_secure));
+      network_provider = base::WrapUnique(new ServiceWorkerNetworkProvider(
+          route_id, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
+          service_worker_provider_id, is_parent_frame_secure));
     }
   } else {
-    network_provider = std::unique_ptr<ServiceWorkerNetworkProvider>(
-        new ServiceWorkerNetworkProvider());
+    network_provider = base::WrapUnique(new ServiceWorkerNetworkProvider());
   }
   return base::MakeUnique<WebServiceWorkerNetworkProviderForFrame>(
       std::move(network_provider));
 }
 
 // static
+std::unique_ptr<ServiceWorkerNetworkProvider>
+ServiceWorkerNetworkProvider::CreateForSharedWorker(int route_id) {
+  return base::WrapUnique(new ServiceWorkerNetworkProvider(
+      route_id, SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER, GetNextProviderId(),
+      true /* is_parent_frame_secure */));
+}
+
+// static
+std::unique_ptr<ServiceWorkerNetworkProvider>
+ServiceWorkerNetworkProvider::CreateForController(
+    mojom::ServiceWorkerProviderInfoForStartWorkerPtr info) {
+  return base::WrapUnique(new ServiceWorkerNetworkProvider(std::move(info)));
+}
+
+// static
 ServiceWorkerNetworkProvider*
 ServiceWorkerNetworkProvider::FromWebServiceWorkerNetworkProvider(
     blink::WebServiceWorkerNetworkProvider* provider) {
@@ -172,6 +196,26 @@
       ->provider();
 }
 
+ServiceWorkerNetworkProvider::~ServiceWorkerNetworkProvider() {
+  if (provider_id_ == kInvalidServiceWorkerProviderId)
+    return;
+  if (!ChildThreadImpl::current())
+    return;  // May be null in some tests.
+  provider_host_.reset();
+}
+
+bool ServiceWorkerNetworkProvider::IsControlledByServiceWorker() const {
+  if (ServiceWorkerUtils::IsServicificationEnabled()) {
+    // Interception for subresource loading is not working (yet)
+    // when servicification is enabled.
+    return false;
+  }
+  return context() && context()->controller();
+}
+
+ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider()
+    : provider_id_(kInvalidServiceWorkerProviderId) {}
+
 ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider(
     int route_id,
     ServiceWorkerProviderType provider_type,
@@ -183,6 +227,11 @@
   if (!ChildThreadImpl::current())
     return;  // May be null in some tests.
 
+  // We don't support dedicated worker (WORKER) as an independent service
+  // worker client yet.
+  DCHECK(provider_type == SERVICE_WORKER_PROVIDER_FOR_WINDOW ||
+         provider_type == SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER);
+
   ServiceWorkerProviderHostInfo host_info(provider_id_, route_id, provider_type,
                                           is_parent_frame_secure);
   host_info.host_request = mojo::MakeRequest(&provider_host_);
@@ -194,22 +243,12 @@
   context_ = new ServiceWorkerProviderContext(
       provider_id_, provider_type, std::move(client_request),
       ChildThreadImpl::current()->thread_safe_sender());
-
   ChildThreadImpl::current()->channel()->GetRemoteAssociatedInterface(
       &dispatcher_host_);
   dispatcher_host_->OnProviderCreated(std::move(host_info));
 }
 
 ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider(
-    int route_id,
-    ServiceWorkerProviderType provider_type,
-    bool is_parent_frame_secure)
-    : ServiceWorkerNetworkProvider(route_id,
-                                   provider_type,
-                                   GetNextProviderId(),
-                                   is_parent_frame_secure) {}
-
-ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider(
     mojom::ServiceWorkerProviderInfoForStartWorkerPtr info)
     : provider_id_(info->provider_id) {
   context_ = new ServiceWorkerProviderContext(
@@ -233,24 +272,4 @@
   provider_host_.Bind(std::move(info->host_ptr_info));
 }
 
-ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider()
-    : provider_id_(kInvalidServiceWorkerProviderId) {}
-
-ServiceWorkerNetworkProvider::~ServiceWorkerNetworkProvider() {
-  if (provider_id_ == kInvalidServiceWorkerProviderId)
-    return;
-  if (!ChildThreadImpl::current())
-    return;  // May be null in some tests.
-  provider_host_.reset();
-}
-
-bool ServiceWorkerNetworkProvider::IsControlledByServiceWorker() const {
-  if (ServiceWorkerUtils::IsServicificationEnabled()) {
-    // Interception for subresource loading is not working (yet)
-    // when servicification is enabled.
-    return false;
-  }
-  return context() && context()->controller();
-}
-
 }  // namespace content
diff --git a/content/child/service_worker/service_worker_network_provider.h b/content/child/service_worker/service_worker_network_provider.h
index bd3fcba..bf5bb6f 100644
--- a/content/child/service_worker/service_worker_network_provider.h
+++ b/content/child/service_worker/service_worker_network_provider.h
@@ -47,26 +47,21 @@
                       blink::WebLocalFrame* frame,
                       bool content_initiated);
 
+  // Creates a ServiceWorkerNetworkProvider for a shared worker (as a
+  // non-document service worker client).
+  static std::unique_ptr<ServiceWorkerNetworkProvider> CreateForSharedWorker(
+      int route_id);
+
+  // Creates a ServiceWorkerNetworkProvider for a "controller" (i.e.
+  // a service worker execution context).
+  static std::unique_ptr<ServiceWorkerNetworkProvider> CreateForController(
+      mojom::ServiceWorkerProviderInfoForStartWorkerPtr info);
+
   // Valid only for WebServiceWorkerNetworkProvider created by
   // CreateForNavigation.
   static ServiceWorkerNetworkProvider* FromWebServiceWorkerNetworkProvider(
       blink::WebServiceWorkerNetworkProvider*);
 
-  // PlzNavigate
-  // The |browser_provider_id| is initialized by the browser for navigations.
-  ServiceWorkerNetworkProvider(int route_id,
-                               ServiceWorkerProviderType type,
-                               int browser_provider_id,
-                               bool is_parent_frame_secure);
-  // This is for service worker clients.
-  ServiceWorkerNetworkProvider(int route_id,
-                               ServiceWorkerProviderType type,
-                               bool is_parent_frame_secure);
-  // This is for controllers.
-  explicit ServiceWorkerNetworkProvider(
-      mojom::ServiceWorkerProviderInfoForStartWorkerPtr info);
-
-  ServiceWorkerNetworkProvider();
   ~ServiceWorkerNetworkProvider();
 
   int provider_id() const { return provider_id_; }
@@ -79,6 +74,23 @@
   bool IsControlledByServiceWorker() const;
 
  private:
+  ServiceWorkerNetworkProvider();
+
+  // This is for service worker clients (used in CreateForNavigation and
+  // CreateForSharedWorker). |provider_id| is provided by the browser process
+  // for navigations (with PlzNavigate, which is default).
+  // |type| must be either one of SERVICE_WORKER_PROVIDER_FOR_{WINDOW,
+  // SHARED_WORKER,WORKER} (while currently we don't have code for WORKER).
+  // |is_parent_frame_secure| is only relevant when the |type| is WINDOW.
+  ServiceWorkerNetworkProvider(int route_id,
+                               ServiceWorkerProviderType type,
+                               int provider_id,
+                               bool is_parent_frame_secure);
+
+  // This is for controllers, used in CreateForController.
+  explicit ServiceWorkerNetworkProvider(
+      mojom::ServiceWorkerProviderInfoForStartWorkerPtr info);
+
   const int provider_id_;
   scoped_refptr<ServiceWorkerProviderContext> context_;
   mojom::ServiceWorkerDispatcherHostAssociatedPtr dispatcher_host_;
diff --git a/content/child/service_worker/service_worker_provider_context.cc b/content/child/service_worker/service_worker_provider_context.cc
index 136422d..2552f9c0 100644
--- a/content/child/service_worker/service_worker_provider_context.cc
+++ b/content/child/service_worker/service_worker_provider_context.cc
@@ -190,10 +190,13 @@
 
 void ServiceWorkerProviderContext::OnSetControllerServiceWorker(
     std::unique_ptr<ServiceWorkerHandleReference> controller,
-    const std::set<uint32_t>& used_features) {
+    const std::set<uint32_t>& used_features,
+    mojom::ServiceWorkerEventDispatcherPtrInfo event_dispatcher_ptr_info) {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   delegate_->SetController(std::move(controller));
   used_features_ = used_features;
+  if (event_dispatcher_ptr_info.is_valid())
+    event_dispatcher_.Bind(std::move(event_dispatcher_ptr_info));
 }
 
 void ServiceWorkerProviderContext::GetAssociatedRegistration(
diff --git a/content/child/service_worker/service_worker_provider_context.h b/content/child/service_worker/service_worker_provider_context.h
index 69808a49..0d40d44 100644
--- a/content/child/service_worker/service_worker_provider_context.h
+++ b/content/child/service_worker/service_worker_provider_context.h
@@ -13,6 +13,7 @@
 #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_event_dispatcher.mojom.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"
@@ -77,7 +78,8 @@
   void OnDisassociateRegistration();
   void OnSetControllerServiceWorker(
       std::unique_ptr<ServiceWorkerHandleReference> controller,
-      const std::set<uint32_t>& used_features);
+      const std::set<uint32_t>& used_features,
+      mojom::ServiceWorkerEventDispatcherPtrInfo event_dispatcher_ptr_info);
 
   // Called on the worker thread. Used for initializing
   // ServiceWorkerGlobalScope.
@@ -89,6 +91,10 @@
 
   int provider_id() const { return provider_id_; }
 
+  mojom::ServiceWorkerEventDispatcher* event_dispatcher() {
+    return event_dispatcher_.get();
+  }
+
   ServiceWorkerHandleReference* controller();
   void CountFeature(uint32_t feature);
   const std::set<uint32_t>& used_features() const { return used_features_; }
@@ -114,6 +120,9 @@
   // alive.
   mojo::AssociatedBinding<mojom::ServiceWorkerProvider> binding_;
 
+  // To dispatch events to the controller ServiceWorker.
+  mojom::ServiceWorkerEventDispatcherPtr event_dispatcher_;
+
   std::unique_ptr<Delegate> delegate_;
 
   // Only used for controllee contexts.
diff --git a/content/child/test_request_peer.cc b/content/child/test_request_peer.cc
index b487f64..6ae6497 100644
--- a/content/child/test_request_peer.cc
+++ b/content/child/test_request_peer.cc
@@ -81,7 +81,6 @@
 }
 
 void TestRequestPeer::OnCompletedRequest(int error_code,
-                                         bool was_ignored_by_handler,
                                          bool stale_copy_in_cache,
                                          const base::TimeTicks& completion_time,
                                          int64_t total_transfer_size,
diff --git a/content/child/test_request_peer.h b/content/child/test_request_peer.h
index df0e98f5..f224d49 100644
--- a/content/child/test_request_peer.h
+++ b/content/child/test_request_peer.h
@@ -39,7 +39,6 @@
   void OnTransferSizeUpdated(int transfer_size_diff) override;
   void OnReceivedCachedMetadata(const char* data, int len) override;
   void OnCompletedRequest(int error_code,
-                          bool was_ignored_by_handler,
                           bool stale_copy_in_cache,
                           const base::TimeTicks& completion_time,
                           int64_t total_transfer_size,
diff --git a/content/child/url_response_body_consumer_unittest.cc b/content/child/url_response_body_consumer_unittest.cc
index f29fb2d3..7cb43e8 100644
--- a/content/child/url_response_body_consumer_unittest.cc
+++ b/content/child/url_response_body_consumer_unittest.cc
@@ -64,7 +64,6 @@
   void OnTransferSizeUpdated(int transfer_size_diff) override {}
 
   void OnCompletedRequest(int error_code,
-                          bool was_ignored_by_handler,
                           bool stale_copy_in_cache,
                           const base::TimeTicks& completion_time,
                           int64_t total_transfer_size,
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index 5aa5c2a..01bf7c4 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -391,7 +391,6 @@
   void OnTransferSizeUpdated(int transfer_size_diff);
   void OnReceivedCachedMetadata(const char* data, int len);
   void OnCompletedRequest(int error_code,
-                          bool was_ignored_by_handler,
                           bool stale_copy_in_cache,
                           const base::TimeTicks& completion_time,
                           int64_t total_transfer_size,
@@ -451,7 +450,6 @@
   void OnTransferSizeUpdated(int transfer_size_diff) override;
   void OnReceivedCachedMetadata(const char* data, int len) override;
   void OnCompletedRequest(int error_code,
-                          bool was_ignored_by_handler,
                           bool stale_copy_in_cache,
                           const base::TimeTicks& completion_time,
                           int64_t total_transfer_size,
@@ -864,7 +862,6 @@
 
 void WebURLLoaderImpl::Context::OnCompletedRequest(
     int error_code,
-    bool was_ignored_by_handler,
     bool stale_copy_in_cache,
     const base::TimeTicks& completion_time,
     int64_t total_transfer_size,
@@ -1001,8 +998,8 @@
       OnReceivedData(base::MakeUnique<FixedReceivedData>(data.data(), size));
   }
 
-  OnCompletedRequest(error_code, false, false, base::TimeTicks::Now(), 0,
-                     data.size(), data.size());
+  OnCompletedRequest(error_code, false, base::TimeTicks::Now(), 0, data.size(),
+                     data.size());
 }
 
 // WebURLLoaderImpl::RequestPeerImpl ------------------------------------------
@@ -1050,15 +1047,14 @@
 
 void WebURLLoaderImpl::RequestPeerImpl::OnCompletedRequest(
     int error_code,
-    bool was_ignored_by_handler,
     bool stale_copy_in_cache,
     const base::TimeTicks& completion_time,
     int64_t total_transfer_size,
     int64_t encoded_body_size,
     int64_t decoded_body_size) {
-  context_->OnCompletedRequest(
-      error_code, was_ignored_by_handler, stale_copy_in_cache, completion_time,
-      total_transfer_size, encoded_body_size, decoded_body_size);
+  context_->OnCompletedRequest(error_code, stale_copy_in_cache, completion_time,
+                               total_transfer_size, encoded_body_size,
+                               decoded_body_size);
 }
 
 // WebURLLoaderImpl -----------------------------------------------------------
diff --git a/content/child/web_url_loader_impl_unittest.cc b/content/child/web_url_loader_impl_unittest.cc
index b63d8fd..9296fd35 100644
--- a/content/child/web_url_loader_impl_unittest.cc
+++ b/content/child/web_url_loader_impl_unittest.cc
@@ -323,7 +323,7 @@
 
   void DoCompleteRequest() {
     EXPECT_FALSE(client()->did_finish());
-    peer()->OnCompletedRequest(net::OK, false, false, base::TimeTicks(),
+    peer()->OnCompletedRequest(net::OK, false, base::TimeTicks(),
                                strlen(kTestData), strlen(kTestData),
                                strlen(kTestData));
     EXPECT_TRUE(client()->did_finish());
@@ -334,7 +334,7 @@
 
   void DoFailRequest() {
     EXPECT_FALSE(client()->did_finish());
-    peer()->OnCompletedRequest(net::ERR_FAILED, false, false, base::TimeTicks(),
+    peer()->OnCompletedRequest(net::ERR_FAILED, false, base::TimeTicks(),
                                strlen(kTestData), strlen(kTestData),
                                strlen(kTestData));
     EXPECT_FALSE(client()->did_finish());
@@ -562,7 +562,7 @@
   // Directory listings are only parsed once the request completes, so this will
   // cancel in DoReceiveDataFtp, before the request finishes.
   client()->set_delete_on_receive_data();
-  peer()->OnCompletedRequest(net::OK, false, false, base::TimeTicks(),
+  peer()->OnCompletedRequest(net::OK, false, base::TimeTicks(),
                              strlen(kTestData), strlen(kTestData),
                              strlen(kTestData));
   EXPECT_FALSE(client()->did_finish());
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index a7d4153..e0e0364 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -299,7 +299,6 @@
 // Parameters for a ResourceMsg_RequestComplete
 IPC_STRUCT_TRAITS_BEGIN(content::ResourceRequestCompletionStatus)
   IPC_STRUCT_TRAITS_MEMBER(error_code)
-  IPC_STRUCT_TRAITS_MEMBER(was_ignored_by_handler)
   IPC_STRUCT_TRAITS_MEMBER(exists_in_cache)
   IPC_STRUCT_TRAITS_MEMBER(completion_time)
   IPC_STRUCT_TRAITS_MEMBER(encoded_data_length)
diff --git a/content/common/service_worker/service_worker_event_dispatcher.mojom b/content/common/service_worker/service_worker_event_dispatcher.mojom
index 9f35ef4d..6c24be7 100644
--- a/content/common/service_worker/service_worker_event_dispatcher.mojom
+++ b/content/common/service_worker/service_worker_event_dispatcher.mojom
@@ -72,8 +72,15 @@
   OnFallback(mojo.common.mojom.Time dispatch_event_time);
 };
 
-// Renderer-side interface bound to ServiceWorkerContextClient for dispatching
-// events.
+// An interface for dispatching events to a ServiceWorker. This interface is
+// implemented both in the renderer-side and browser-side for the time being.
+// - This is implemented by ServiceWorkerContextClient that lives in the
+//   renderer-side to dispatch events from the browser-side.
+// - This is also implemented by BrowserSideServiceWorkerEventDispatcher that
+//   lives in the browser-side, which is used to dispatch events directly from
+//   the controllees that live in renderer(s). This code is only used when
+//   IsServicificationEnabled() is true.
+//
 // Those events expecting such response
 // (blink.mojom.ServiceWorkerEventStatus, mojo.common.mojom.Time) are considered
 // 'simple events'. ServiceWorkerVersion::CreateSimpleEventCallback can be used
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index 4a367032..e4c15cdc 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -152,6 +152,20 @@
   IPC_STRUCT_TRAITS_MEMBER(is_null)
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_BEGIN(ServiceWorkerMsg_SetControllerServiceWorker_Params)
+  IPC_STRUCT_MEMBER(int, thread_id)
+  IPC_STRUCT_MEMBER(int, provider_id)
+  IPC_STRUCT_MEMBER(content::ServiceWorkerObjectInfo, object_info)
+  IPC_STRUCT_MEMBER(bool, should_notify_controllerchange)
+
+  // |used_features| is the set of features that the worker has used.
+  // The values must be from blink::UseCounter::Feature enum.
+  IPC_STRUCT_MEMBER(std::set<uint32_t>, used_features)
+
+  // Mojo endpoint to dispatch events to the controller.
+  IPC_STRUCT_MEMBER(mojo::MessagePipeHandle, controller_event_dispatcher)
+IPC_STRUCT_END()
+
 //---------------------------------------------------------------------------
 // Messages sent from the child process to the browser.
 
@@ -426,14 +440,9 @@
                      int /* registration_handle_id */)
 
 // Tells the child process to set the controller ServiceWorker for the given
-// provider. |used_features| is the set of features that the worker has used.
-// The values must be from blink::UseCounter::Feature enum.
-IPC_MESSAGE_CONTROL5(ServiceWorkerMsg_SetControllerServiceWorker,
-                     int /* thread_id */,
-                     int /* provider_id */,
-                     content::ServiceWorkerObjectInfo,
-                     bool /* should_notify_controllerchange */,
-                     std::set<uint32_t> /* used_features */)
+// provider.
+IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_SetControllerServiceWorker,
+                     ServiceWorkerMsg_SetControllerServiceWorker_Params)
 
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidEnableNavigationPreload,
                      int /* thread_id */,
diff --git a/content/public/browser/resource_request_info.h b/content/public/browser/resource_request_info.h
index 33830f8e..24f4d93 100644
--- a/content/public/browser/resource_request_info.h
+++ b/content/public/browser/resource_request_info.h
@@ -158,10 +158,6 @@
   // DO NOT BASE SECURITY DECISIONS ON THIS FLAG!
   virtual bool HasUserGesture() const = 0;
 
-  // True if ResourceController::CancelAndIgnore() was called.  For example,
-  // the requested URL may be being loaded by an external program.
-  virtual bool WasIgnoredByHandler() const = 0;
-
   // Returns false if there is NOT an associated render frame.
   virtual bool GetAssociatedRenderFrame(int* render_process_id,
                                         int* render_frame_id) const = 0;
diff --git a/content/public/browser/resource_throttle.cc b/content/public/browser/resource_throttle.cc
index 53b1e219..8e51bc16 100644
--- a/content/public/browser/resource_throttle.cc
+++ b/content/public/browser/resource_throttle.cc
@@ -14,10 +14,6 @@
   delegate_->Cancel();
 }
 
-void ResourceThrottle::CancelAndIgnore() {
-  delegate_->CancelAndIgnore();
-}
-
 void ResourceThrottle::CancelWithError(int error_code) {
   delegate_->CancelWithError(error_code);
 }
diff --git a/content/public/browser/resource_throttle.h b/content/public/browser/resource_throttle.h
index 4ac8fd4..b1adaca 100644
--- a/content/public/browser/resource_throttle.h
+++ b/content/public/browser/resource_throttle.h
@@ -31,9 +31,6 @@
    public:
     // Cancels the resource load.
     virtual void Cancel() = 0;
-    // Marks the resource load as ignored by the resource handler, and then
-    // cancels the resource load.
-    virtual void CancelAndIgnore() = 0;
     // Cancels the resource load with the specified error code.
     virtual void CancelWithError(int error_code) = 0;
     // Tells the delegate to resume the deferred resource load.
@@ -78,7 +75,6 @@
   // Helper methods for subclasses. When these methods are called, methods with
   // the same name on |delegate_| are called.
   void Cancel();
-  void CancelAndIgnore();
   void CancelWithError(int error_code);
   void Resume();
 
diff --git a/content/public/child/request_peer.h b/content/public/child/request_peer.h
index 5402ddb..3ecdf0e 100644
--- a/content/public/child/request_peer.h
+++ b/content/public/child/request_peer.h
@@ -94,7 +94,6 @@
   // Called when the response is complete.  This method signals completion of
   // the resource load.
   virtual void OnCompletedRequest(int error_code,
-                                  bool was_ignored_by_handler,
                                   bool stale_copy_in_cache,
                                   const base::TimeTicks& completion_time,
                                   int64_t total_transfer_size,
diff --git a/content/public/common/resource_request_completion_status.h b/content/public/common/resource_request_completion_status.h
index 2a50977..376e8c2 100644
--- a/content/public/common/resource_request_completion_status.h
+++ b/content/public/common/resource_request_completion_status.h
@@ -25,9 +25,6 @@
   // The error code.
   int error_code = 0;
 
-  // Was ignored by the request handler.
-  bool was_ignored_by_handler = false;
-
   // A copy of the data requested exists in the cache.
   bool exists_in_cache = false;
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index cd2d66f6..dd979e43 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -775,6 +775,7 @@
       "//third_party/webrtc/api:video_frame_api",
       "//third_party/webrtc/api/audio_codecs:builtin_audio_decoder_factory",
       "//third_party/webrtc/api/audio_codecs:builtin_audio_encoder_factory",
+      "//third_party/webrtc/common_video:common_video",
       "//third_party/webrtc/media:rtc_media",
       "//third_party/webrtc/media:rtc_media_base",
       "//third_party/webrtc/modules/audio_device",
diff --git a/content/renderer/media/gpu/rtc_video_encoder.cc b/content/renderer/media/gpu/rtc_video_encoder.cc
index dc153db4..b07b30d 100644
--- a/content/renderer/media/gpu/rtc_video_encoder.cc
+++ b/content/renderer/media/gpu/rtc_video_encoder.cc
@@ -47,25 +47,16 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(RTCTimestamps);
 };
 
-// Translate from webrtc::VideoCodecType and webrtc::VideoCodec to
-// media::VideoCodecProfile.
-media::VideoCodecProfile WebRTCVideoCodecToVideoCodecProfile(
-    webrtc::VideoCodecType type,
-    const webrtc::VideoCodec* codec_settings) {
-  DCHECK_EQ(type, codec_settings->codecType);
-  switch (type) {
-    case webrtc::kVideoCodecVP8:
-      return media::VP8PROFILE_ANY;
-    case webrtc::kVideoCodecVP9:
-      return media::VP9PROFILE_MIN;
-    case webrtc::kVideoCodecH264:
-      // TODO(magjed): WebRTC is only using Baseline profile for now. Update
-      // once http://crbug/webrtc/6337 is fixed.
-      return media::H264PROFILE_BASELINE;
-    default:
-      NOTREACHED() << "Unrecognized video codec type";
-      return media::VIDEO_CODEC_PROFILE_UNKNOWN;
+webrtc::VideoCodecType ProfileToWebRtcVideoCodecType(
+    media::VideoCodecProfile profile) {
+  if (profile >= media::VP8PROFILE_MIN && profile <= media::VP8PROFILE_MAX) {
+    return webrtc::kVideoCodecVP8;
+  } else if (profile >= media::H264PROFILE_MIN &&
+             profile <= media::H264PROFILE_MAX) {
+    return webrtc::kVideoCodecH264;
   }
+  NOTREACHED() << "Invalid profile " << GetProfileName(profile);
+  return webrtc::kVideoCodecUnknown;
 }
 
 // Populates struct webrtc::RTPFragmentationHeader for H264 codec.
@@ -798,12 +789,12 @@
 }
 
 RTCVideoEncoder::RTCVideoEncoder(
-    webrtc::VideoCodecType type,
+    media::VideoCodecProfile profile,
     media::GpuVideoAcceleratorFactories* gpu_factories)
-    : video_codec_type_(type),
+    : profile_(profile),
       gpu_factories_(gpu_factories),
       gpu_task_runner_(gpu_factories->GetTaskRunner()) {
-  DVLOG(1) << __func__ << " codec type=" << type;
+  DVLOG(1) << "RTCVideoEncoder(): profile=" << GetProfileName(profile);
 }
 
 RTCVideoEncoder::~RTCVideoEncoder() {
@@ -822,9 +813,7 @@
   if (impl_)
     Release();
 
-  impl_ = new Impl(gpu_factories_, video_codec_type_);
-  const media::VideoCodecProfile profile = WebRTCVideoCodecToVideoCodecProfile(
-      impl_->video_codec_type(), codec_settings);
+  impl_ = new Impl(gpu_factories_, ProfileToWebRtcVideoCodecType(profile_));
 
   base::WaitableEvent initialization_waiter(
       base::WaitableEvent::ResetPolicy::MANUAL,
@@ -832,17 +821,14 @@
   int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
   gpu_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
-                 impl_,
+      base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA, impl_,
                  gfx::Size(codec_settings->width, codec_settings->height),
-                 codec_settings->startBitrate,
-                 profile,
-                 &initialization_waiter,
+                 codec_settings->startBitrate, profile_, &initialization_waiter,
                  &initialization_retval));
 
   // webrtc::VideoEncoder expects this call to be synchronous.
   initialization_waiter.Wait();
-  RecordInitEncodeUMA(initialization_retval, profile);
+  RecordInitEncodeUMA(initialization_retval, profile_);
   return initialization_retval;
 }
 
diff --git a/content/renderer/media/gpu/rtc_video_encoder.h b/content/renderer/media/gpu/rtc_video_encoder.h
index 390dc7b..a5c09fd5 100644
--- a/content/renderer/media/gpu/rtc_video_encoder.h
+++ b/content/renderer/media/gpu/rtc_video_encoder.h
@@ -41,7 +41,7 @@
 class CONTENT_EXPORT RTCVideoEncoder
     : NON_EXPORTED_BASE(public webrtc::VideoEncoder) {
  public:
-  RTCVideoEncoder(webrtc::VideoCodecType type,
+  RTCVideoEncoder(media::VideoCodecProfile profile,
                   media::GpuVideoAcceleratorFactories* gpu_factories);
   ~RTCVideoEncoder() override;
 
@@ -65,8 +65,7 @@
   class Impl;
   friend class RTCVideoEncoder::Impl;
 
-  // The video codec type, as reported to WebRTC.
-  const webrtc::VideoCodecType video_codec_type_;
+  const media::VideoCodecProfile profile_;
 
   // Factory for creating VEAs, shared memory buffers, etc.
   media::GpuVideoAcceleratorFactories* gpu_factories_;
diff --git a/content/renderer/media/gpu/rtc_video_encoder_factory.cc b/content/renderer/media/gpu/rtc_video_encoder_factory.cc
index f3189de..bbece0d 100644
--- a/content/renderer/media/gpu/rtc_video_encoder_factory.cc
+++ b/content/renderer/media/gpu/rtc_video_encoder_factory.cc
@@ -11,23 +11,23 @@
 #include "content/renderer/media/gpu/rtc_video_encoder.h"
 #include "media/gpu/ipc/client/gpu_video_encode_accelerator_host.h"
 #include "media/renderers/gpu_video_accelerator_factories.h"
-#include "media/video/video_encode_accelerator.h"
+#include "third_party/webrtc/common_video/h264/profile_level_id.h"
 
 namespace content {
 
 namespace {
 
 // Translate from media::VideoEncodeAccelerator::SupportedProfile to
-// one or more instances of cricket::WebRtcVideoEncoderFactory::VideoCodec
-void VEAToWebRTCCodecs(
-    std::vector<cricket::VideoCodec>* codecs,
+// cricket::WebRtcVideoEncoderFactory::VideoCodec, or return nothing if the
+// profile isn't supported.
+base::Optional<cricket::VideoCodec> VEAToWebRTCCodec(
     const media::VideoEncodeAccelerator::SupportedProfile& profile) {
   DCHECK_EQ(profile.max_framerate_denominator, 1U);
 
   if (profile.profile >= media::VP8PROFILE_MIN &&
       profile.profile <= media::VP8PROFILE_MAX) {
     if (base::FeatureList::IsEnabled(features::kWebRtcHWVP8Encoding)) {
-      codecs->push_back(cricket::VideoCodec("VP8"));
+      return base::Optional<cricket::VideoCodec>(cricket::VideoCodec("VP8"));
     }
   } else if (profile.profile >= media::H264PROFILE_MIN &&
              profile.profile <= media::H264PROFILE_MAX) {
@@ -41,10 +41,41 @@
 #endif  // BUILDFLAG(RTC_USE_H264) && !defined(MEDIA_DISABLE_FFMPEG)
     if (webrtc_h264_sw_enabled ||
         base::FeatureList::IsEnabled(features::kWebRtcHWH264Encoding)) {
-      // TODO(magjed): Propagate H264 profile information.
-      codecs->push_back(cricket::VideoCodec("H264"));
+      webrtc::H264::Profile h264_profile;
+      switch (profile.profile) {
+        case media::H264PROFILE_BASELINE:
+          h264_profile = webrtc::H264::kProfileBaseline;
+          break;
+        case media::H264PROFILE_MAIN:
+          h264_profile = webrtc::H264::kProfileMain;
+          break;
+        case media::H264PROFILE_HIGH:
+          h264_profile = webrtc::H264::kProfileHigh;
+          break;
+        default:
+          // Unsupported H264 profile in WebRTC.
+          return base::Optional<cricket::VideoCodec>();
+      }
+
+      const int width = profile.max_resolution.width();
+      const int height = profile.max_resolution.height();
+      const int fps = profile.max_framerate_numerator;
+      DCHECK_EQ(1u, profile.max_framerate_denominator);
+
+      const rtc::Optional<webrtc::H264::Level> h264_level =
+          webrtc::H264::SupportedLevel(width * height, fps);
+      const webrtc::H264::ProfileLevelId profile_level_id(
+          h264_profile, h264_level.value_or(webrtc::H264::kLevel1));
+
+      cricket::VideoCodec codec("H264");
+      codec.SetParam(cricket::kH264FmtpProfileLevelId,
+                     *webrtc::H264::ProfileLevelIdToString(profile_level_id));
+      codec.SetParam(cricket::kH264FmtpLevelAsymmetryAllowed, "1");
+      codec.SetParam(cricket::kH264FmtpPacketizationMode, "1");
+      return base::Optional<cricket::VideoCodec>(codec);
     }
   }
+  return base::Optional<cricket::VideoCodec>();
 }
 
 }  // anonymous namespace
@@ -54,20 +85,36 @@
     : gpu_factories_(gpu_factories) {
   const media::VideoEncodeAccelerator::SupportedProfiles& profiles =
       gpu_factories_->GetVideoEncodeAcceleratorSupportedProfiles();
-  for (const auto& profile : profiles)
-    VEAToWebRTCCodecs(&supported_codecs_, profile);
+  for (const auto& profile : profiles) {
+    base::Optional<cricket::VideoCodec> codec = VEAToWebRTCCodec(profile);
+    if (codec) {
+      supported_codecs_.push_back(std::move(*codec));
+      profiles_.push_back(profile.profile);
+    }
+  }
+  // There should be a 1:1 mapping between media::VideoCodecProfile and
+  // cricket::VideoCodec.
+  CHECK_EQ(profiles_.size(), supported_codecs_.size());
 }
 
 RTCVideoEncoderFactory::~RTCVideoEncoderFactory() {}
 
 webrtc::VideoEncoder* RTCVideoEncoderFactory::CreateVideoEncoder(
     const cricket::VideoCodec& codec) {
-  for (const cricket::VideoCodec& supported_codec : supported_codecs_) {
-    if (cricket::CodecNamesEq(codec.name, supported_codec.name)) {
-      webrtc::VideoCodecType type = webrtc::PayloadNameToCodecType(codec.name)
-                                        .value_or(webrtc::kVideoCodecUnknown);
-      return new RTCVideoEncoder(type, gpu_factories_);
+  for (size_t i = 0; i < supported_codecs_.size(); ++i) {
+    if (!cricket::CodecNamesEq(codec.name, supported_codecs_[i].name))
+      continue;
+    // Check H264 profile.
+    using webrtc::H264::ParseSdpProfileLevelId;
+    if (cricket::CodecNamesEq(codec.name.c_str(), cricket::kH264CodecName) &&
+        ParseSdpProfileLevelId(codec.params)->profile !=
+            ParseSdpProfileLevelId(supported_codecs_[i].params)->profile) {
+      continue;
     }
+    // There should be a 1:1 mapping between media::VideoCodecProfile and
+    // cricket::VideoCodec.
+    CHECK_EQ(profiles_.size(), supported_codecs_.size());
+    return new RTCVideoEncoder(profiles_[i], gpu_factories_);
   }
   return nullptr;
 }
diff --git a/content/renderer/media/gpu/rtc_video_encoder_factory.h b/content/renderer/media/gpu/rtc_video_encoder_factory.h
index 307f8f92..c5bcde0 100644
--- a/content/renderer/media/gpu/rtc_video_encoder_factory.h
+++ b/content/renderer/media/gpu/rtc_video_encoder_factory.h
@@ -39,6 +39,9 @@
   media::GpuVideoAcceleratorFactories* gpu_factories_;
 
   // List of supported cricket::WebRtcVideoEncoderFactory::VideoCodec.
+  // |profiles_| and |supported_codecs_| have the same length and the profile
+  // for |supported_codecs_[i]| is |profiles_[i]|.
+  std::vector<media::VideoCodecProfile> profiles_;
   std::vector<cricket::VideoCodec> supported_codecs_;
 
   DISALLOW_COPY_AND_ASSIGN(RTCVideoEncoderFactory);
diff --git a/content/renderer/media/gpu/rtc_video_encoder_unittest.cc b/content/renderer/media/gpu/rtc_video_encoder_unittest.cc
index 3fd7a91b..889b024 100644
--- a/content/renderer/media/gpu/rtc_video_encoder_unittest.cc
+++ b/content/renderer/media/gpu/rtc_video_encoder_unittest.cc
@@ -113,7 +113,19 @@
 
   void CreateEncoder(webrtc::VideoCodecType codec_type) {
     DVLOG(3) << __func__;
-    rtc_encoder_ = base::MakeUnique<RTCVideoEncoder>(codec_type,
+    media::VideoCodecProfile media_profile;
+    switch (codec_type) {
+      case webrtc::kVideoCodecVP8:
+        media_profile = media::VP8PROFILE_ANY;
+        break;
+      case webrtc::kVideoCodecH264:
+        media_profile = media::H264PROFILE_BASELINE;
+        break;
+      default:
+        ADD_FAILURE() << "Unexpected codec type: " << codec_type;
+        media_profile = media::VIDEO_CODEC_PROFILE_UNKNOWN;
+    }
+    rtc_encoder_ = base::MakeUnique<RTCVideoEncoder>(media_profile,
                                                      mock_gpu_factories_.get());
   }
 
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc
index 87ab3a76d..e9c0723 100644
--- a/content/renderer/media/webmediaplayer_ms.cc
+++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -20,6 +20,8 @@
 #include "content/public/renderer/media_stream_audio_renderer.h"
 #include "content/public/renderer/media_stream_renderer_factory.h"
 #include "content/public/renderer/media_stream_video_renderer.h"
+#include "content/renderer/media/media_stream_audio_track.h"
+#include "content/renderer/media/media_stream_video_track.h"
 #include "content/renderer/media/web_media_element_source_utils.h"
 #include "content/renderer/media/webmediaplayer_ms_compositor.h"
 #include "content/renderer/media/webrtc_logging.h"
@@ -39,6 +41,14 @@
 #include "third_party/WebKit/public/platform/WebSize.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 
+namespace {
+enum class RendererReloadAction {
+  KEEP_RENDERER,
+  REMOVE_RENDERER,
+  NEW_RENDERER
+};
+}  // namespace
+
 namespace content {
 
 // FrameDeliverer is responsible for delivering frames received on
@@ -191,6 +201,12 @@
   DVLOG(1) << __func__;
   DCHECK(thread_checker_.CalledOnValidThread());
 
+  if (!web_stream_.IsNull()) {
+    MediaStream* native_stream = MediaStream::GetMediaStream(web_stream_);
+    if (native_stream)
+      native_stream->RemoveObserver(this);
+  }
+
   // Destruct compositor resources in the proper order.
   get_client()->SetWebLayer(nullptr);
   if (video_weblayer_)
@@ -224,24 +240,29 @@
   // TODO(acolwell): Change this to DCHECK_EQ(load_type, LoadTypeMediaStream)
   // once Blink-side changes land.
   DCHECK_NE(load_type, kLoadTypeMediaSource);
-  blink::WebMediaStream web_stream =
-      GetWebMediaStreamFromWebMediaPlayerSource(source);
+  web_stream_ = GetWebMediaStreamFromWebMediaPlayerSource(source);
+  if (!web_stream_.IsNull()) {
+    MediaStream* native_stream = MediaStream::GetMediaStream(web_stream_);
+    if (native_stream)
+      native_stream->AddObserver(this);
+  }
 
   compositor_ = new WebMediaPlayerMSCompositor(
-      compositor_task_runner_, io_task_runner_, web_stream, AsWeakPtr());
+      compositor_task_runner_, io_task_runner_, web_stream_, AsWeakPtr());
 
   SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
   SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
   std::string stream_id =
-      web_stream.IsNull() ? std::string() : web_stream.Id().Utf8();
+      web_stream_.IsNull() ? std::string() : web_stream_.Id().Utf8();
   media_log_->AddEvent(media_log_->CreateLoadEvent(stream_id));
 
   frame_deliverer_.reset(new WebMediaPlayerMS::FrameDeliverer(
       AsWeakPtr(),
       base::Bind(&WebMediaPlayerMSCompositor::EnqueueFrame, compositor_)));
   video_frame_provider_ = renderer_factory_->GetVideoRenderer(
-      web_stream, media::BindToCurrentLoop(base::Bind(
-                      &WebMediaPlayerMS::OnSourceError, AsWeakPtr())),
+      web_stream_,
+      media::BindToCurrentLoop(
+          base::Bind(&WebMediaPlayerMS::OnSourceError, AsWeakPtr())),
       frame_deliverer_->GetRepaintCallback(), io_task_runner_,
       media_task_runner_, worker_task_runner_, gpu_factories_);
 
@@ -258,7 +279,7 @@
   }
 
   audio_renderer_ = renderer_factory_->GetAudioRenderer(
-      web_stream, routing_id, initial_audio_output_device_id_,
+      web_stream_, routing_id, initial_audio_output_device_id_,
       initial_security_origin_);
 
   if (!audio_renderer_)
@@ -272,10 +293,27 @@
   if (audio_renderer_) {
     audio_renderer_->SetVolume(volume_);
     audio_renderer_->Start();
+
+    // Store the ID of audio track being played in |current_video_track_id_|
+    blink::WebVector<blink::WebMediaStreamTrack> audio_tracks;
+    if (!web_stream_.IsNull()) {
+      web_stream_.AudioTracks(audio_tracks);
+      DCHECK_GT(audio_tracks.size(), 0U);
+      current_audio_track_id_ = audio_tracks[0].Id();
+    }
   }
-  if (video_frame_provider_)
+
+  if (video_frame_provider_) {
     video_frame_provider_->Start();
 
+    // Store the ID of video track being played in |current_video_track_id_|
+    if (!web_stream_.IsNull()) {
+      blink::WebVector<blink::WebMediaStreamTrack> video_tracks;
+      web_stream_.VideoTracks(video_tracks);
+      DCHECK_GT(video_tracks.size(), 0U);
+      current_video_track_id_ = video_tracks[0].Id();
+    }
+  }
   // When associated with an <audio> element, we don't want to wait for the
   // first video fram to become available as we do for <video> elements
   // (<audio> elements can also be assigned video tracks).
@@ -288,6 +326,113 @@
   }
 }
 
+void WebMediaPlayerMS::TrackAdded(const blink::WebMediaStreamTrack& track) {
+  Reload();
+}
+
+void WebMediaPlayerMS::TrackRemoved(const blink::WebMediaStreamTrack& track) {
+  Reload();
+}
+
+void WebMediaPlayerMS::Reload() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (web_stream_.IsNull())
+    return;
+
+  ReloadVideo();
+  ReloadAudio();
+}
+
+void WebMediaPlayerMS::ReloadVideo() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!web_stream_.IsNull());
+  blink::WebVector<blink::WebMediaStreamTrack> video_tracks;
+  // VideoTracks() is a getter.
+  web_stream_.VideoTracks(video_tracks);
+
+  RendererReloadAction renderer_action = RendererReloadAction::KEEP_RENDERER;
+  if (video_tracks.IsEmpty()) {
+    if (video_frame_provider_)
+      renderer_action = RendererReloadAction::REMOVE_RENDERER;
+    current_video_track_id_ = blink::WebString();
+  } else if (video_tracks[0].Id() != current_video_track_id_) {
+    renderer_action = RendererReloadAction::NEW_RENDERER;
+    current_video_track_id_ = video_tracks[0].Id();
+  }
+
+  switch (renderer_action) {
+    case RendererReloadAction::NEW_RENDERER:
+      if (video_frame_provider_)
+        video_frame_provider_->Stop();
+
+      video_frame_provider_ = renderer_factory_->GetVideoRenderer(
+          web_stream_,
+          media::BindToCurrentLoop(
+              base::Bind(&WebMediaPlayerMS::OnSourceError, AsWeakPtr())),
+          frame_deliverer_->GetRepaintCallback(), io_task_runner_,
+          media_task_runner_, worker_task_runner_, gpu_factories_);
+      DCHECK(video_frame_provider_);
+      video_frame_provider_->Start();
+      break;
+
+    case RendererReloadAction::REMOVE_RENDERER:
+      video_frame_provider_->Stop();
+      video_frame_provider_ = nullptr;
+      break;
+
+    default:
+      return;
+  }
+
+  DCHECK_NE(renderer_action, RendererReloadAction::KEEP_RENDERER);
+  if (!paused_)
+    delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
+}
+
+void WebMediaPlayerMS::ReloadAudio() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!web_stream_.IsNull());
+  RenderFrame* const frame = RenderFrame::FromWebFrame(frame_);
+  if (!frame)
+    return;
+
+  blink::WebVector<blink::WebMediaStreamTrack> audio_tracks;
+  // AudioTracks() is a getter.
+  web_stream_.AudioTracks(audio_tracks);
+
+  RendererReloadAction renderer_action = RendererReloadAction::KEEP_RENDERER;
+  if (audio_tracks.IsEmpty()) {
+    if (audio_renderer_)
+      renderer_action = RendererReloadAction::REMOVE_RENDERER;
+    current_audio_track_id_ = blink::WebString();
+  } else if (audio_tracks[0].Id() != current_video_track_id_) {
+    renderer_action = RendererReloadAction::NEW_RENDERER;
+    current_audio_track_id_ = audio_tracks[0].Id();
+  }
+
+  switch (renderer_action) {
+    case RendererReloadAction::NEW_RENDERER:
+      if (audio_renderer_)
+        audio_renderer_->Stop();
+
+      audio_renderer_ = renderer_factory_->GetAudioRenderer(
+          web_stream_, frame->GetRoutingID(), initial_audio_output_device_id_,
+          initial_security_origin_);
+      audio_renderer_->SetVolume(volume_);
+      audio_renderer_->Start();
+      audio_renderer_->Play();
+      break;
+
+    case RendererReloadAction::REMOVE_RENDERER:
+      audio_renderer_->Stop();
+      audio_renderer_ = nullptr;
+      break;
+
+    default:
+      break;
+  }
+}
+
 void WebMediaPlayerMS::Play() {
   DVLOG(1) << __func__;
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -394,6 +539,9 @@
 
 blink::WebSize WebMediaPlayerMS::NaturalSize() const {
   DCHECK(thread_checker_.CalledOnValidThread());
+  if (!video_frame_provider_)
+    return blink::WebSize();
+
   if (video_rotation_ == media::VIDEO_ROTATION_90 ||
       video_rotation_ == media::VideoRotation::VIDEO_ROTATION_270) {
     const gfx::Size& current_size = compositor_->GetCurrentSize();
diff --git a/content/renderer/media/webmediaplayer_ms.h b/content/renderer/media/webmediaplayer_ms.h
index 24f34c0..07c84c2 100644
--- a/content/renderer/media/webmediaplayer_ms.h
+++ b/content/renderer/media/webmediaplayer_ms.h
@@ -14,6 +14,7 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "content/common/content_export.h"
+#include "content/renderer/media/media_stream.h"
 #include "media/blink/webmediaplayer_delegate.h"
 #include "media/blink/webmediaplayer_util.h"
 #include "media/renderers/gpu_video_accelerator_factories.h"
@@ -62,7 +63,8 @@
 // blink::WebMediaPlayerClient
 //   WebKit client of this media player object.
 class CONTENT_EXPORT WebMediaPlayerMS
-    : public NON_EXPORTED_BASE(blink::WebMediaPlayer),
+    : public NON_EXPORTED_BASE(MediaStreamObserver),
+      public NON_EXPORTED_BASE(blink::WebMediaPlayer),
       public NON_EXPORTED_BASE(media::WebMediaPlayerDelegate::Observer),
       public NON_EXPORTED_BASE(base::SupportsWeakPtr<WebMediaPlayerMS>) {
  public:
@@ -179,6 +181,10 @@
                     bool flip_y,
                     bool premultiply_alpha) override;
 
+  // MediaStreamObserver implementation
+  void TrackAdded(const blink::WebMediaStreamTrack& track) override;
+  void TrackRemoved(const blink::WebMediaStreamTrack& track) override;
+
  private:
   friend class WebMediaPlayerMSTest;
 
@@ -201,6 +207,11 @@
   // Getter method to |client_|.
   blink::WebMediaPlayerClient* get_client() { return client_; }
 
+  // To be run when tracks are added or removed.
+  void Reload();
+  void ReloadVideo();
+  void ReloadAudio();
+
   blink::WebLocalFrame* const frame_;
 
   blink::WebMediaPlayer::NetworkState network_state_;
@@ -266,6 +277,10 @@
   // True if playback should be started upon the next call to OnShown(). Only
   // used on Android.
   bool should_play_upon_shown_;
+  blink::WebMediaStream web_stream_;
+  // IDs of the tracks currently played.
+  blink::WebString current_video_track_id_;
+  blink::WebString current_audio_track_id_;
 
   DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerMS);
 };
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index fe9e770..879ca23 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -615,8 +615,8 @@
           std::move(instance_host), main_thread_task_runner_);
   // Create a content::ServiceWorkerNetworkProvider for this data source so
   // we can observe its requests.
-  pending_network_provider_ =
-      base::MakeUnique<ServiceWorkerNetworkProvider>(std::move(provider_info));
+  pending_network_provider_ = ServiceWorkerNetworkProvider::CreateForController(
+      std::move(provider_info));
   provider_context_ = pending_network_provider_->context();
 
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("ServiceWorker",
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index da7afd23..ea6edd6 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -233,9 +233,7 @@
   // Create a content::ServiceWorkerNetworkProvider for this data source so
   // we can observe its requests.
   std::unique_ptr<ServiceWorkerNetworkProvider> provider(
-      new ServiceWorkerNetworkProvider(
-          route_id_, SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER,
-          true /* is_parent_frame_secure */));
+      ServiceWorkerNetworkProvider::CreateForSharedWorker(route_id_));
 
   // Blink is responsible for deleting the returned object.
   return base::MakeUnique<WebServiceWorkerNetworkProviderImpl>(
diff --git a/content/shell/test_runner/mock_web_user_media_client.cc b/content/shell/test_runner/mock_web_user_media_client.cc
index e5de057..77066d3 100644
--- a/content/shell/test_runner/mock_web_user_media_client.cc
+++ b/content/shell/test_runner/mock_web_user_media_client.cc
@@ -33,8 +33,6 @@
 
 namespace test_runner {
 
-class MockExtraData : public WebMediaStream::ExtraData {};
-
 MockWebUserMediaClient::MockWebUserMediaClient(WebTestDelegate* delegate)
     : delegate_(delegate),
       should_enumerate_extra_device_(false),
@@ -57,7 +55,6 @@
   WebMediaStream stream;
   stream.Initialize(WebVector<WebMediaStreamTrack>(),
                     WebVector<WebMediaStreamTrack>());
-  stream.SetExtraData(new MockExtraData());
 
   if (request.Audio() &&
       !delegate_->AddMediaStreamAudioSourceAndTrack(&stream)) {
diff --git a/content/test/data/media/getusermedia.html b/content/test/data/media/getusermedia.html
index d03e49b0..27a9307d 100644
--- a/content/test/data/media/getusermedia.html
+++ b/content/test/data/media/getusermedia.html
@@ -612,6 +612,144 @@
         failTest("Unexpected error: " + e)
       });
   }
+
+  function srcObjectAddVideoTrack() {
+    var video = document.createElement('video');
+    video.autoplay = true;
+    assertEquals(video.srcObject, null);
+    navigator.mediaDevices.getUserMedia({audio: true, video: true})
+      .then(stream => {
+        video.onplaying = function() {
+          video.onplaying = null;
+          video.onloadstart = function() {
+            failTest("loadstart should not be called");
+          }
+
+          video.onresize = function() {
+            assertNotEquals(video.srcObject, null);
+            assertTrue(video.videoHeight > 0);
+            assertTrue(video.videoWidth > 0);
+            reportTestSuccess();
+          }
+
+          assertNotEquals(video.srcObject, null);
+          assertEquals(video.videoWidth, 0);
+          assertEquals(video.videoHeight, 0);
+          video.srcObject.addTrack(stream.getVideoTracks()[0]);
+        }
+        video.srcObject = new MediaStream(stream.getAudioTracks());
+      })
+    .catch(e => {
+      failTest("Unexpected error: " + e)
+    });
+  }
+
+  function srcObjectRemoveVideoTrack() {
+    var video = document.createElement('video');
+    video.autoplay = true;
+    assertEquals(video.srcObject, null);
+    navigator.mediaDevices.getUserMedia({audio: true, video: true})
+      .then(stream => {
+        video.onplaying = function() {
+          video.onplaying = null;
+          video.onloadstart = function() {
+            failTest("loadstart should not be called");
+          }
+
+          video.onresize = function() {
+            assertNotEquals(video.srcObject, null);
+            assertEquals(0, video.videoHeight);
+            assertEquals(0, video.videoWidth);
+            reportTestSuccess();
+          }
+
+          assertNotEquals(video.srcObject, null);
+          assertTrue(video.videoWidth > 0);
+          assertTrue(video.videoHeight > 0);
+          stream.removeTrack(stream.getVideoTracks()[0]);
+        }
+        video.srcObject = stream;
+      })
+    .catch(e => {
+      failTest("Unexpected error: " + e)
+    });
+  }
+
+  function srcObjectRemoveFirstOfTwoVideoTracks() {
+    var canvas = document.createElement('canvas');
+    var canvas_stream = canvas.captureStream();
+    var canvas_width = canvas_stream.getVideoTracks()[0].getSettings().width;
+    var canvas_height = canvas_stream.getVideoTracks()[0].getSettings().height;
+    assertTrue(canvas_width > 1);
+    assertTrue(canvas_height > 1);
+
+    // Paint something on the canvas, so that it produces frames.
+    var ctx = canvas.getContext("2d");
+    ctx.moveTo(0,0);
+    ctx.lineTo(200,100);
+    ctx.stroke();
+
+    var video = document.createElement('video');
+    video.autoplay = true;
+    assertEquals(video.srcObject, null);
+    var gum_width = canvas_width + 1;
+    var gum_height = canvas_height + 1;
+    navigator.mediaDevices.getUserMedia({
+        video: {
+          width: {exact: gum_width},
+          height: {exact: gum_height}
+        }
+      }).then(gum_stream => {
+        var gum_settings = gum_stream.getVideoTracks()[0].getSettings();
+        assertEquals(gum_width, gum_settings.width)
+        assertEquals(gum_height, gum_settings.height)
+        var big_stream = new MediaStream();
+        big_stream.addTrack(canvas_stream.getVideoTracks()[0]);
+        big_stream.addTrack(gum_stream.getVideoTracks()[0]);
+        video.onprogress = function() {
+          assertEquals(canvas_width, video.videoWidth);
+          assertEquals(canvas_height, video.videoHeight);
+          assertNotEquals(video.videoWidth, gum_width)
+          assertNotEquals(video.videoHeight, gum_height)
+          video.onprogress = function() {
+            assertEquals(gum_width, video.videoWidth);
+            assertEquals(gum_height, video.videoHeight);
+            assertNotEquals(video.videoWidth, canvas_width)
+            assertNotEquals(video.videoHeight, canvas_height)
+            reportTestSuccess();
+          }
+          big_stream.removeTrack(big_stream.getVideoTracks()[0]);
+        }
+        video.srcObject = big_stream;
+    })
+    .catch(e => {
+      failTest("Unexpected error: " + e)
+    });
+  }
+
+  function srcObjectReassignSameObject() {
+    var video = document.createElement('video');
+    video.autoplay = true;
+    assertEquals(video.srcObject, null);
+    navigator.mediaDevices.getUserMedia({audio: true, video: true})
+      .then(stream => {
+        video.onplaying = function() {
+          video.onplaying = null;
+          video.onloadstart = function() {
+            reportTestSuccess();
+          }
+          assertNotEquals(video.srcObject, null);
+          assertTrue(video.videoWidth > 0);
+          assertTrue(video.videoHeight > 0);
+          // Reassigning the same object should trigger the load algorithm.
+          video.srcObject = video.srcObject;
+        }
+        video.srcObject = stream;
+      })
+    .catch(e => {
+      failTest("Unexpected error: " + e)
+    });
+  }
   </script>
 </head>
 <body>
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
index 96803e45..0c70794 100644
--- a/extensions/browser/extensions_browser_client.h
+++ b/extensions/browser/extensions_browser_client.h
@@ -270,6 +270,9 @@
   // Whether the browser context is associated with Chrome OS lock screen.
   virtual bool IsLockScreenContext(content::BrowserContext* context) = 0;
 
+  // Returns the locale used by the application.
+  virtual std::string GetApplicationLocale() = 0;
+
   // Returns the single instance of |this|.
   static ExtensionsBrowserClient* Get();
 
diff --git a/extensions/browser/test_extensions_browser_client.cc b/extensions/browser/test_extensions_browser_client.cc
index 22f09eaf..87c4c96c9 100644
--- a/extensions/browser/test_extensions_browser_client.cc
+++ b/extensions/browser/test_extensions_browser_client.cc
@@ -10,6 +10,7 @@
 #include "extensions/browser/extension_host_delegate.h"
 #include "extensions/browser/test_runtime_api_delegate.h"
 #include "extensions/browser/updater/null_extension_cache.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/login/login_state.h"
@@ -230,4 +231,8 @@
   return lock_screen_context_ && context == lock_screen_context_;
 }
 
+std::string TestExtensionsBrowserClient::GetApplicationLocale() {
+  return l10n_util::GetApplicationLocale(std::string());
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/test_extensions_browser_client.h b/extensions/browser/test_extensions_browser_client.h
index 8ea62be..c750a3d 100644
--- a/extensions/browser/test_extensions_browser_client.h
+++ b/extensions/browser/test_extensions_browser_client.h
@@ -121,6 +121,7 @@
   scoped_refptr<update_client::UpdateClient> CreateUpdateClient(
       content::BrowserContext* context) override;
   bool IsLockScreenContext(content::BrowserContext* context) override;
+  std::string GetApplicationLocale() override;
 
   ExtensionSystemProvider* extension_system_factory() {
     return extension_system_factory_;
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc
index fa73cbf..8a66329 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.cc
+++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -30,6 +30,7 @@
 #include "extensions/shell/browser/shell_extensions_api_client.h"
 #include "extensions/shell/browser/shell_navigation_ui_data.h"
 #include "extensions/shell/browser/shell_runtime_api_delegate.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/login/login_state.h"
@@ -281,4 +282,8 @@
   return false;
 }
 
+std::string ShellExtensionsBrowserClient::GetApplicationLocale() {
+  return l10n_util::GetApplicationLocale(std::string());
+}
+
 }  // namespace extensions
diff --git a/extensions/shell/browser/shell_extensions_browser_client.h b/extensions/shell/browser/shell_extensions_browser_client.h
index 5f3d516..6d20f68c 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.h
+++ b/extensions/shell/browser/shell_extensions_browser_client.h
@@ -98,6 +98,7 @@
       net::URLRequest* request) override;
   KioskDelegate* GetKioskDelegate() override;
   bool IsLockScreenContext(content::BrowserContext* context) override;
+  std::string GetApplicationLocale() override;
 
   // Sets the API client.
   void SetAPIClientForTest(ExtensionsAPIClient* api_client);
diff --git a/ios/chrome/browser/translate/before_translate_infobar_controller.h b/ios/chrome/browser/translate/before_translate_infobar_controller.h
index 6028f2e1..0966b76 100644
--- a/ios/chrome/browser/translate/before_translate_infobar_controller.h
+++ b/ios/chrome/browser/translate/before_translate_infobar_controller.h
@@ -7,12 +7,6 @@
 
 #include "ios/chrome/browser/infobars/infobar_controller.h"
 
-// The accessibility identifier of the cancel button on language picker view.
-extern NSString* const kLanguagePickerCancelButtonId;
-
-// The accessibility identifier of the done button on language picker view.
-extern NSString* const kLanguagePickerDoneButtonId;
-
 @interface BeforeTranslateInfoBarController : InfoBarController
 
 @end
diff --git a/ios/chrome/browser/translate/before_translate_infobar_controller.mm b/ios/chrome/browser/translate/before_translate_infobar_controller.mm
index 9763b6c..d94714a0 100644
--- a/ios/chrome/browser/translate/before_translate_infobar_controller.mm
+++ b/ios/chrome/browser/translate/before_translate_infobar_controller.mm
@@ -22,9 +22,6 @@
 #error "This file requires ARC support."
 #endif
 
-NSString* const kLanguagePickerCancelButtonId = @"LanguagePickerCancelButton";
-NSString* const kLanguagePickerDoneButtonId = @"LanguagePickerDoneButton";
-
 namespace {
 
 CGFloat kNavigationBarHeight = 44;
@@ -305,12 +302,10 @@
       initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                            target:self
                            action:@selector(languageSelectionDone)];
-  [doneButton setAccessibilityIdentifier:kLanguagePickerDoneButtonId];
   UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc]
       initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
                            target:self
                            action:@selector(dismissLanguageSelectionView)];
-  [cancelButton setAccessibilityIdentifier:kLanguagePickerCancelButtonId];
   UINavigationItem* item = [[UINavigationItem alloc] initWithTitle:@""];
   [item setRightBarButtonItem:doneButton];
   [item setLeftBarButtonItem:cancelButton];
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm
index 6629560..271be0f 100644
--- a/ios/chrome/browser/translate/translate_egtest.mm
+++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -19,7 +19,6 @@
 #import "components/translate/ios/browser/js_translate_manager.h"
 #import "components/translate/ios/browser/language_detection_controller.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/translate/before_translate_infobar_controller.h"
 #include "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/app/tab_test_util.h"
@@ -108,6 +107,20 @@
       IDS_TRANSLATE_INFOBAR_ALWAYS_TRANSLATE, base::UTF8ToUTF16(language)));
 }
 
+// Returns a matcher for the button with label "Cancel" in the language picker.
+// TODO(crbug.com/750344): Change the matcher to use accessibility ID.
+id<GREYMatcher> LanguagePickerCancelButton() {
+  return grey_allOf(chrome_test_util::ButtonWithAccessibilityLabel(@"Cancel"),
+                    grey_userInteractionEnabled(), nil);
+}
+
+// Returns a matcher for the button with label "Done" in the language picker.
+// TODO(crbug.com/750344): Change the matcher to use accessibility ID.
+id<GREYMatcher> LanguagePickerDoneButton() {
+  return grey_allOf(chrome_test_util::ButtonWithAccessibilityLabel(@"Done"),
+                    grey_userInteractionEnabled(), nil);
+}
+
 #pragma mark - TestResponseProvider
 
 // A ResponseProvider that provides html responses of texts in different
@@ -602,8 +615,9 @@
       selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabel(
                                    kFrench)] performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                          kLanguagePickerCancelButtonId)]
+  // The language picker uses the system accessibility labels (thus no
+  // IDS_CANCEL here).
+  [[EarlGrey selectElementWithMatcher:LanguagePickerCancelButton()]
       assertWithMatcher:grey_notNil()];
 
   // Change the language using the picker.
@@ -614,8 +628,7 @@
   [[EarlGrey selectElementWithMatcher:languageMatcher]
       performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                          kLanguagePickerDoneButtonId)]
+  [[EarlGrey selectElementWithMatcher:LanguagePickerDoneButton()]
       performAction:grey_tap()];
   [[EarlGrey
       selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabel(
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index ad04141..3d6ac574 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -486,8 +486,6 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPIAutoOrString.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBackgroundAttachment.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBackgroundBlendMode.h",
-    "$blink_core_output_dir/css/properties/CSSPropertyAPIBackgroundBox.h",
-    "$blink_core_output_dir/css/properties/CSSPropertyAPIBackgroundOrMaskImage.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBaselineShift.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBorderColor.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBorderImageOutset.h",
@@ -513,8 +511,6 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPICounterReset.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPICursor.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPID.h",
-    "$blink_core_output_dir/css/properties/CSSPropertyAPIDelay.h",
-    "$blink_core_output_dir/css/properties/CSSPropertyAPIDuration.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFilter.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFlexBasis.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFlexGrowOrShrink.h",
@@ -531,7 +527,6 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFragmentation.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridAutoFlow.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridAutoLine.h",
-    "$blink_core_output_dir/css/properties/CSSPropertyAPIGridGap.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridLine.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridTemplateAreas.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridTemplateLine.h",
@@ -584,7 +579,6 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPITextShadow.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITextSizeAdjust.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITextUnderlinePosition.h",
-    "$blink_core_output_dir/css/properties/CSSPropertyAPITimingFunction.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITouchAction.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITransform.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITransformOrigin.h",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index 850f2460..1b9a0e4 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -383,8 +383,6 @@
     "properties/CSSPropertyAPIAutoOrString.cpp",
     "properties/CSSPropertyAPIBackgroundAttachment.cpp",
     "properties/CSSPropertyAPIBackgroundBlendMode.cpp",
-    "properties/CSSPropertyAPIBackgroundBox.cpp",
-    "properties/CSSPropertyAPIBackgroundOrMaskImage.cpp",
     "properties/CSSPropertyAPIBaselineShift.cpp",
     "properties/CSSPropertyAPIBorderColor.cpp",
     "properties/CSSPropertyAPIBorderImageOutset.cpp",
@@ -410,8 +408,6 @@
     "properties/CSSPropertyAPICounterReset.cpp",
     "properties/CSSPropertyAPICursor.cpp",
     "properties/CSSPropertyAPID.cpp",
-    "properties/CSSPropertyAPIDelay.cpp",
-    "properties/CSSPropertyAPIDuration.cpp",
     "properties/CSSPropertyAPIFilter.cpp",
     "properties/CSSPropertyAPIFlexBasis.cpp",
     "properties/CSSPropertyAPIFlexGrowOrShrink.cpp",
@@ -429,7 +425,6 @@
     "properties/CSSPropertyAPIFragmentation.cpp",
     "properties/CSSPropertyAPIGridAutoFlow.cpp",
     "properties/CSSPropertyAPIGridAutoLine.cpp",
-    "properties/CSSPropertyAPIGridGap.cpp",
     "properties/CSSPropertyAPIGridLine.cpp",
     "properties/CSSPropertyAPIGridTemplateAreas.cpp",
     "properties/CSSPropertyAPIGridTemplateLine.cpp",
@@ -482,7 +477,6 @@
     "properties/CSSPropertyAPITextShadow.cpp",
     "properties/CSSPropertyAPITextSizeAdjust.cpp",
     "properties/CSSPropertyAPITextUnderlinePosition.cpp",
-    "properties/CSSPropertyAPITimingFunction.cpp",
     "properties/CSSPropertyAPITouchAction.cpp",
     "properties/CSSPropertyAPITransform.cpp",
     "properties/CSSPropertyAPITransformOrigin.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSDefaultStyleSheets.cpp b/third_party/WebKit/Source/core/css/CSSDefaultStyleSheets.cpp
index 692da6d..411e5797 100644
--- a/third_party/WebKit/Source/core/css/CSSDefaultStyleSheets.cpp
+++ b/third_party/WebKit/Source/core/css/CSSDefaultStyleSheets.cpp
@@ -172,7 +172,6 @@
   }
 
   DCHECK(!default_style_->Features().HasIdsInSelectors());
-  DCHECK(!default_style_->Features().UsesSiblingRules());
   return changed_default_style;
 }
 
diff --git a/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.cpp b/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.cpp
index ad92a27..13eb875 100644
--- a/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.cpp
+++ b/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.cpp
@@ -29,20 +29,6 @@
   }
 }
 
-static RuleSet* MakeRuleSet(const HeapVector<RuleFeature>& rules) {
-  size_t size = rules.size();
-  if (!size)
-    return nullptr;
-  RuleSet* rule_set = RuleSet::Create();
-  for (size_t i = 0; i < size; ++i) {
-    rule_set->AddRule(rules[i].rule, rules[i].selector_index,
-                      rules[i].has_document_security_origin
-                          ? kRuleHasDocumentSecurityOrigin
-                          : kRuleHasNoSpecialState);
-  }
-  return rule_set;
-}
-
 void CSSGlobalRuleSet::Update(Document& document) {
   if (!is_dirty_)
     return;
@@ -65,25 +51,16 @@
     features_.Add(watched_selectors_rule_set_->Features());
 
   document.GetStyleEngine().CollectScopedStyleFeaturesTo(features_);
-
-  sibling_rule_set_ = MakeRuleSet(features_.SiblingRules());
-  uncommon_attribute_rule_set_ =
-      MakeRuleSet(features_.UncommonAttributeRules());
 }
 
 void CSSGlobalRuleSet::Dispose() {
   features_.Clear();
-  sibling_rule_set_ = nullptr;
-  uncommon_attribute_rule_set_ = nullptr;
   watched_selectors_rule_set_ = nullptr;
   has_fullscreen_ua_style_ = false;
   is_dirty_ = true;
 }
 
 DEFINE_TRACE(CSSGlobalRuleSet) {
-  visitor->Trace(features_);
-  visitor->Trace(sibling_rule_set_);
-  visitor->Trace(uncommon_attribute_rule_set_);
   visitor->Trace(watched_selectors_rule_set_);
 }
 
diff --git a/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.h b/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.h
index 204c2a3..1de0f21 100644
--- a/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.h
+++ b/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.h
@@ -37,10 +37,6 @@
     CHECK(features_.IsAlive());
     return features_;
   }
-  RuleSet* SiblingRuleSet() const { return sibling_rule_set_; }
-  RuleSet* UncommonAttributeRuleSet() const {
-    return uncommon_attribute_rule_set_;
-  }
   RuleSet* WatchedSelectorsRuleSet() const {
     return watched_selectors_rule_set_;
   }
@@ -53,8 +49,6 @@
   // Constructed from rules in all TreeScopes including UA style and style
   // injected from extensions.
   RuleFeatureSet features_;
-  Member<RuleSet> sibling_rule_set_;
-  Member<RuleSet> uncommon_attribute_rule_set_;
 
   // Rules injected from extensions.
   Member<RuleSet> watched_selectors_rule_set_;
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 02aa490..e4caa11f 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -319,8 +319,6 @@
     // Animation Priority properties
     {
       name: "animation-delay",
-      api_class: "CSSPropertyAPIDelay",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
@@ -335,8 +333,6 @@
     },
     {
       name: "animation-duration",
-      api_class: "CSSPropertyAPIDuration",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
@@ -372,22 +368,16 @@
     },
     {
       name: "animation-timing-function",
-      api_class: "CSSPropertyAPITimingFunction",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
     {
       name: "transition-delay",
-      api_class: "CSSPropertyAPIDelay",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
     {
       name: "transition-duration",
-      api_class: "CSSPropertyAPIDuration",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
@@ -400,8 +390,6 @@
     },
     {
       name: "transition-timing-function",
-      api_class: "CSSPropertyAPITimingFunction",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
@@ -710,8 +698,6 @@
     },
     {
       name: "background-clip",
-      api_class: "CSSPropertyAPIBackgroundBox",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
     },
     {
@@ -729,8 +715,6 @@
     },
     {
       name: "background-image",
-      api_class: "CSSPropertyAPIBackgroundOrMaskImage",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
       keywords: ["auto", "none"],
@@ -738,8 +722,6 @@
     },
     {
       name: "background-origin",
-      api_class: "CSSPropertyAPIBackgroundBox",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
     },
     {
@@ -844,20 +826,17 @@
     {
       name: "border-image-outset",
       api_class: "CSSPropertyAPIBorderImageOutset",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
     {
       name: "border-image-repeat",
       api_class: "CSSPropertyAPIBorderImageRepeat",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
     },
     {
       name: "border-image-slice",
       api_class: "CSSPropertyAPIBorderImageSlice",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -873,7 +852,6 @@
     {
       name: "border-image-width",
       api_class: "CSSPropertyAPIBorderImageWidth",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -1412,8 +1390,6 @@
     },
     {
       name: "grid-column-gap",
-      api_class: "CSSPropertyAPIGridGap",
-      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       runtime_flag: "CSSGridLayout",
       field_template: "<length>",
@@ -1444,8 +1420,6 @@
     },
     {
       name: "grid-row-gap",
-      api_class: "CSSPropertyAPIGridGap",
-      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       runtime_flag: "CSSGridLayout",
       field_template: "<length>",
@@ -3162,20 +3136,17 @@
     {
       name: "-webkit-mask-box-image-outset",
       api_class: "CSSPropertyAPIBorderImageOutset",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
     {
       name: "-webkit-mask-box-image-repeat",
       api_class: "CSSPropertyAPIBorderImageRepeat",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
     },
     {
       name: "-webkit-mask-box-image-slice",
       api_class: "CSSPropertyAPIBorderImageSlice",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -3189,7 +3160,6 @@
     {
       name: "-webkit-mask-box-image-width",
       api_class: "CSSPropertyAPIBorderImageWidth",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -3205,8 +3175,6 @@
     },
     {
       name: "-webkit-mask-image",
-      api_class: "CSSPropertyAPIBackgroundOrMaskImage",
-      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -3242,14 +3210,12 @@
     {
       name: "-webkit-perspective-origin-x",
       api_class: "CSSPropertyAPIWebkitOriginX",
-      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       interpolable: true,
     },
     {
       name: "-webkit-perspective-origin-y",
       api_class: "CSSPropertyAPIWebkitOriginY",
-      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       interpolable: true,
     },
@@ -3373,14 +3339,12 @@
     {
       name: "-webkit-transform-origin-x",
       api_class: "CSSPropertyAPIWebkitOriginX",
-      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       interpolable: true,
     },
     {
       name: "-webkit-transform-origin-y",
       api_class: "CSSPropertyAPIWebkitOriginY",
-      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       interpolable: true,
     },
diff --git a/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp b/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp
index 9665219..673c1a5 100644
--- a/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp
+++ b/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp
@@ -342,9 +342,6 @@
       return;
     style_->SetHasPseudoStyle(dynamic_pseudo);
   } else {
-    if (style_ && rule_data.ContainsUncommonAttributeSelector())
-      style_->SetUnique();
-
     matched_rules_.push_back(MatchedRule(
         &rule_data, result.specificity, cascade_order,
         match_request.style_sheet_index, match_request.style_sheet));
diff --git a/third_party/WebKit/Source/core/css/RuleFeature.cpp b/third_party/WebKit/Source/core/css/RuleFeature.cpp
index e5f2454..35d4be5 100644
--- a/third_party/WebKit/Source/core/css/RuleFeature.cpp
+++ b/third_party/WebKit/Source/core/css/RuleFeature.cpp
@@ -266,17 +266,6 @@
 
 }  // anonymous namespace
 
-RuleFeature::RuleFeature(StyleRule* rule,
-                         unsigned selector_index,
-                         bool has_document_security_origin)
-    : rule(rule),
-      selector_index(selector_index),
-      has_document_security_origin(has_document_security_origin) {}
-
-DEFINE_TRACE(RuleFeature) {
-  visitor->Trace(rule);
-}
-
 RuleFeatureSet::RuleFeatureSet() : is_alive_(true) {}
 
 RuleFeatureSet::~RuleFeatureSet() {
@@ -820,17 +809,6 @@
 
   metadata_.Add(metadata);
 
-  if (metadata.found_sibling_selector) {
-    sibling_rules_.push_back(
-        RuleFeature(rule_data.Rule(), rule_data.SelectorIndex(),
-                    rule_data.HasDocumentSecurityOrigin()));
-  }
-  if (rule_data.ContainsUncommonAttributeSelector()) {
-    uncommon_attribute_rules_.push_back(
-        RuleFeature(rule_data.Rule(), rule_data.SelectorIndex(),
-                    rule_data.HasDocumentSecurityOrigin()));
-  }
-
   UpdateInvalidationSets(rule_data);
   return kSelectorMayMatch;
 }
@@ -851,20 +829,6 @@
       case CSSSelector::kPseudoWindowInactive:
         metadata.uses_window_inactive_selector = true;
         break;
-      case CSSSelector::kPseudoEmpty:
-      case CSSSelector::kPseudoFirstChild:
-      case CSSSelector::kPseudoFirstOfType:
-      case CSSSelector::kPseudoLastChild:
-      case CSSSelector::kPseudoLastOfType:
-      case CSSSelector::kPseudoOnlyChild:
-      case CSSSelector::kPseudoOnlyOfType:
-      case CSSSelector::kPseudoNthChild:
-      case CSSSelector::kPseudoNthOfType:
-      case CSSSelector::kPseudoNthLastChild:
-      case CSSSelector::kPseudoNthLastOfType:
-        if (!metadata.found_insertion_point_crossing)
-          metadata.found_sibling_selector = true;
-        break;
       case CSSSelector::kPseudoHost:
       case CSSSelector::kPseudoHostContext:
         if (!found_host_pseudo && relation == CSSSelector::kSubSelector)
@@ -905,10 +869,6 @@
         metadata.max_direct_adjacent_selectors = max_direct_adjacent_selectors;
       max_direct_adjacent_selectors = 0;
     }
-
-    if (!metadata.found_insertion_point_crossing &&
-        current->IsAdjacentSelector())
-      metadata.found_sibling_selector = true;
   }
 
   DCHECK(!max_direct_adjacent_selectors);
@@ -925,7 +885,6 @@
 void RuleFeatureSet::FeatureMetadata::Clear() {
   uses_first_line_rules = false;
   uses_window_inactive_selector = false;
-  found_sibling_selector = false;
   found_insertion_point_crossing = false;
   needs_full_recalc_for_rule_set_invalidation = false;
   max_direct_adjacent_selectors = 0;
@@ -960,8 +919,6 @@
 
   metadata_.Add(other.metadata_);
 
-  sibling_rules_.AppendVector(other.sibling_rules_);
-  uncommon_attribute_rules_.AppendVector(other.uncommon_attribute_rules_);
   viewport_dependent_media_query_results_.AppendVector(
       other.viewport_dependent_media_query_results_);
   device_dependent_media_query_results_.AppendVector(
@@ -970,8 +927,6 @@
 
 void RuleFeatureSet::Clear() {
   CHECK(is_alive_);
-  sibling_rules_.clear();
-  uncommon_attribute_rules_.clear();
   metadata_.Clear();
   class_invalidation_sets_.clear();
   attribute_invalidation_sets_.clear();
@@ -1214,11 +1169,6 @@
                                  descendant_features);
 }
 
-DEFINE_TRACE(RuleFeatureSet) {
-  visitor->Trace(sibling_rules_);
-  visitor->Trace(uncommon_attribute_rules_);
-}
-
 void RuleFeatureSet::InvalidationSetFeatures::Add(
     const InvalidationSetFeatures& other) {
   classes.AppendVector(other.classes);
diff --git a/third_party/WebKit/Source/core/css/RuleFeature.h b/third_party/WebKit/Source/core/css/RuleFeature.h
index 3235328..7105754 100644
--- a/third_party/WebKit/Source/core/css/RuleFeature.h
+++ b/third_party/WebKit/Source/core/css/RuleFeature.h
@@ -38,30 +38,6 @@
 struct InvalidationLists;
 class QualifiedName;
 class RuleData;
-class StyleRule;
-
-struct RuleFeature {
-  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-
- public:
-  RuleFeature(StyleRule*,
-              unsigned selector_index,
-              bool has_document_security_origin);
-
-  DECLARE_TRACE();
-
-  Member<StyleRule> rule;
-  unsigned selector_index;
-  bool has_document_security_origin;
-};
-
-}  // namespace blink
-
-// Declare the VectorTraits specialization before RuleFeatureSet
-// declares its vector members below.
-WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(blink::RuleFeature);
-
-namespace blink {
 
 class CORE_EXPORT RuleFeatureSet {
   DISALLOW_NEW();
@@ -78,7 +54,6 @@
 
   SelectorPreMatch CollectFeaturesFromRuleData(const RuleData&);
 
-  bool UsesSiblingRules() const { return !sibling_rules_.IsEmpty(); }
   bool UsesFirstLineRules() const { return metadata_.uses_first_line_rules; }
   bool UsesWindowInactiveSelector() const {
     return metadata_.uses_window_inactive_selector;
@@ -105,11 +80,6 @@
     return id_invalidation_sets_.Contains(id_value);
   }
 
-  const HeapVector<RuleFeature>& SiblingRules() const { return sibling_rules_; }
-  const HeapVector<RuleFeature>& UncommonAttributeRules() const {
-    return uncommon_attribute_rules_;
-  }
-
   const MediaQueryResultList& ViewportDependentMediaQueryResults() const {
     return viewport_dependent_media_query_results_;
   }
@@ -160,8 +130,6 @@
 
   bool HasIdsInSelectors() const { return id_invalidation_sets_.size() > 0; }
 
-  DECLARE_TRACE();
-
   bool IsAlive() const { return is_alive_; }
 
  protected:
@@ -187,7 +155,6 @@
 
     bool uses_first_line_rules = false;
     bool uses_window_inactive_selector = false;
-    bool found_sibling_selector = false;
     bool found_insertion_point_crossing = false;
     bool needs_full_recalc_for_rule_set_invalidation = false;
     unsigned max_direct_adjacent_selectors = 0;
@@ -295,8 +262,6 @@
   RefPtr<SiblingInvalidationSet> universal_sibling_invalidation_set_;
   RefPtr<DescendantInvalidationSet> nth_invalidation_set_;
   RefPtr<DescendantInvalidationSet> type_rule_invalidation_set_;
-  HeapVector<RuleFeature> sibling_rules_;
-  HeapVector<RuleFeature> uncommon_attribute_rules_;
   MediaQueryResultList viewport_dependent_media_query_results_;
   MediaQueryResultList device_dependent_media_query_results_;
 
diff --git a/third_party/WebKit/Source/core/css/RuleFeatureSetTest.cpp b/third_party/WebKit/Source/core/css/RuleFeatureSetTest.cpp
index 3f1eb16..6b67d1d 100644
--- a/third_party/WebKit/Source/core/css/RuleFeatureSetTest.cpp
+++ b/third_party/WebKit/Source/core/css/RuleFeatureSetTest.cpp
@@ -19,38 +19,6 @@
 
 namespace blink {
 
-// TODO(sof): consider making these part object helper abstractions
-// available from platform/heap/.
-
-template <typename T>
-class HeapPartObject final
-    : public GarbageCollectedFinalized<HeapPartObject<T>> {
- public:
-  static HeapPartObject* Create() { return new HeapPartObject; }
-
-  T* Get() { return &part_; }
-
-  DEFINE_INLINE_TRACE() { visitor->Trace(part_); }
-
- private:
-  HeapPartObject() {}
-
-  T part_;
-};
-
-template <typename T>
-class PersistentPartObject final {
-  DISALLOW_NEW();
-
- public:
-  PersistentPartObject() : part_(HeapPartObject<T>::Create()) {}
-
-  T* operator->() const { return (*part_).Get(); }
-
- private:
-  Persistent<HeapPartObject<T>> part_;
-};
-
 class RuleFeatureSetTest : public ::testing::Test {
  public:
   RuleFeatureSetTest() {}
@@ -73,25 +41,25 @@
         StyleRule::Create(std::move(selector_list),
                           MutableStylePropertySet::Create(kHTMLStandardMode));
     RuleData rule_data(style_rule, 0, 0, kRuleHasNoSpecialState);
-    return rule_feature_set_->CollectFeaturesFromRuleData(rule_data);
+    return rule_feature_set_.CollectFeaturesFromRuleData(rule_data);
   }
 
-  void ClearFeatures() { rule_feature_set_->Clear(); }
+  void ClearFeatures() { rule_feature_set_.Clear(); }
 
   void CollectInvalidationSetsForClass(InvalidationLists& invalidation_lists,
                                        const AtomicString& class_name) const {
     Element* element = Traversal<HTMLElement>::FirstChild(
         *Traversal<HTMLElement>::FirstChild(*document_->body()));
-    rule_feature_set_->CollectInvalidationSetsForClass(invalidation_lists,
-                                                       *element, class_name);
+    rule_feature_set_.CollectInvalidationSetsForClass(invalidation_lists,
+                                                      *element, class_name);
   }
 
   void CollectInvalidationSetsForId(InvalidationLists& invalidation_lists,
                                     const AtomicString& id) const {
     Element* element = Traversal<HTMLElement>::FirstChild(
         *Traversal<HTMLElement>::FirstChild(*document_->body()));
-    rule_feature_set_->CollectInvalidationSetsForId(invalidation_lists,
-                                                    *element, id);
+    rule_feature_set_.CollectInvalidationSetsForId(invalidation_lists, *element,
+                                                   id);
   }
 
   void CollectInvalidationSetsForAttribute(
@@ -99,7 +67,7 @@
       const QualifiedName& attribute_name) const {
     Element* element = Traversal<HTMLElement>::FirstChild(
         *Traversal<HTMLElement>::FirstChild(*document_->body()));
-    rule_feature_set_->CollectInvalidationSetsForAttribute(
+    rule_feature_set_.CollectInvalidationSetsForAttribute(
         invalidation_lists, *element, attribute_name);
   }
 
@@ -108,18 +76,18 @@
       CSSSelector::PseudoType pseudo) const {
     Element* element = Traversal<HTMLElement>::FirstChild(
         *Traversal<HTMLElement>::FirstChild(*document_->body()));
-    rule_feature_set_->CollectInvalidationSetsForPseudoClass(invalidation_lists,
-                                                             *element, pseudo);
+    rule_feature_set_.CollectInvalidationSetsForPseudoClass(invalidation_lists,
+                                                            *element, pseudo);
   }
 
   void CollectUniversalSiblingInvalidationSet(
       InvalidationLists& invalidation_lists) {
-    rule_feature_set_->CollectUniversalSiblingInvalidationSet(
-        invalidation_lists, 1);
+    rule_feature_set_.CollectUniversalSiblingInvalidationSet(invalidation_lists,
+                                                             1);
   }
 
   void CollectNthInvalidationSet(InvalidationLists& invalidation_lists) {
-    rule_feature_set_->CollectNthInvalidationSet(invalidation_lists);
+    rule_feature_set_.CollectNthInvalidationSet(invalidation_lists);
   }
 
   const HashSet<AtomicString>& ClassSet(
@@ -256,21 +224,13 @@
     EXPECT_TRUE(attributes.Contains(attribute));
   }
 
-  void ExpectSiblingRuleCount(unsigned count) {
-    EXPECT_EQ(count, rule_feature_set_->SiblingRules().size());
-  }
-
-  void ExpectUncommonAttributeRuleCount(unsigned count) {
-    EXPECT_EQ(count, rule_feature_set_->UncommonAttributeRules().size());
-  }
-
   void ExpectFullRecalcForRuleSetInvalidation(bool expected) {
     EXPECT_EQ(expected,
-              rule_feature_set_->NeedsFullRecalcForRuleSetInvalidation());
+              rule_feature_set_.NeedsFullRecalcForRuleSetInvalidation());
   }
 
  private:
-  PersistentPartObject<RuleFeatureSet> rule_feature_set_;
+  RuleFeatureSet rule_feature_set_;
   Persistent<Document> document_;
 };
 
@@ -477,143 +437,6 @@
   ExpectNoInvalidation(invalidation_lists.descendants);
 }
 
-TEST_F(RuleFeatureSetTest, siblingRulesBeforeContentPseudo) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures("a + b ::content .c"));
-  ExpectSiblingRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, siblingRulesBeforeContentPseudo2) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures("a + ::content .b"));
-  ExpectSiblingRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, siblingRulesAfterContentPseudo) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures(".a ::content .b + .c"));
-  ExpectSiblingRuleCount(1);
-}
-
-TEST_F(RuleFeatureSetTest, siblingRulesNthBeforeContentPseudo) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures(":nth-child(2) ::content .a"));
-  ExpectSiblingRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, siblingRulesNthAfterContentPseudo) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures(".a ::content :nth-child(2)"));
-  ExpectSiblingRuleCount(1);
-}
-
-TEST_F(RuleFeatureSetTest, siblingRulesBeforeSlotted) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures(".a + ::slotted(.b)"));
-  ExpectSiblingRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, siblingRulesBeforeHost) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
-            CollectFeatures(".a + :host(.b)"));
-  ExpectSiblingRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, siblingRulesBeforeHostContext) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
-            CollectFeatures(".a + :host-context(.b)"));
-  ExpectSiblingRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterContentPseudo) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures("div ::content [attr]"));
-  ExpectUncommonAttributeRuleCount(1);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeContentPseudo) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures("[attr] ::content div"));
-  ExpectUncommonAttributeRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesSlotted) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures("::slotted([attr])"));
-  ExpectUncommonAttributeRuleCount(1);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeSlotted) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures("[attr]::slotted(*)"));
-  ExpectUncommonAttributeRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHost) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures(":host([attr])"));
-  ExpectUncommonAttributeRuleCount(1);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHost) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
-            CollectFeatures("[attr] :host"));
-  ExpectUncommonAttributeRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHost) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
-            CollectFeatures(":host[attr]"));
-  ExpectUncommonAttributeRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHost2) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":host [attr]"));
-  ExpectUncommonAttributeRuleCount(1);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHostBeforePseudo) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures(":host([attr])::before"));
-  ExpectUncommonAttributeRuleCount(1);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHostContext) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures(":host-context([attr])"));
-  ExpectUncommonAttributeRuleCount(1);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHostContext) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
-            CollectFeatures("[attr] :host-context(div)"));
-  ExpectUncommonAttributeRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHostContext2) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
-            CollectFeatures("[attr]:host-context(div)"));
-  ExpectUncommonAttributeRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHostContext) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
-            CollectFeatures(":host-context(*)[attr]"));
-  ExpectUncommonAttributeRuleCount(0);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHostContext2) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures(":host-context(*) [attr]"));
-  ExpectUncommonAttributeRuleCount(1);
-}
-
-TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHostContextBeforePseudo) {
-  EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
-            CollectFeatures(":host-context([attr])::before"));
-  ExpectUncommonAttributeRuleCount(1);
-}
-
 TEST_F(RuleFeatureSetTest, universalSiblingInvalidationDirectAdjacent) {
   EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("* + .a"));
 
diff --git a/third_party/WebKit/Source/core/css/RuleSet.cpp b/third_party/WebKit/Source/core/css/RuleSet.cpp
index a3ae17a..916922b 100644
--- a/third_party/WebKit/Source/core/css/RuleSet.cpp
+++ b/third_party/WebKit/Source/core/css/RuleSet.cpp
@@ -49,57 +49,6 @@
 
 using namespace HTMLNames;
 
-// -----------------------------------------------------------------
-
-static bool ContainsUncommonAttributeSelector(const CSSSelector&);
-
-static inline bool SelectorListContainsUncommonAttributeSelector(
-    const CSSSelector* selector) {
-  const CSSSelectorList* selector_list = selector->SelectorList();
-  if (!selector_list)
-    return false;
-  for (const CSSSelector* selector = selector_list->First(); selector;
-       selector = CSSSelectorList::Next(*selector)) {
-    if (ContainsUncommonAttributeSelector(*selector))
-      return true;
-  }
-  return false;
-}
-
-static inline bool IsCommonAttributeSelectorAttribute(
-    const QualifiedName& attribute) {
-  // These are explicitly tested for equality in canShareStyleWithElement.
-  return attribute == typeAttr || attribute == readonlyAttr;
-}
-
-static bool ContainsUncommonAttributeSelector(const CSSSelector& selector) {
-  const CSSSelector* current = &selector;
-  for (; current; current = current->TagHistory()) {
-    // Allow certain common attributes (used in the default style) in the
-    // selectors that match the current element.
-    if (current->IsAttributeSelector() &&
-        !IsCommonAttributeSelectorAttribute(current->Attribute()))
-      return true;
-    if (SelectorListContainsUncommonAttributeSelector(current))
-      return true;
-    if (current->RelationIsAffectedByPseudoContent() ||
-        current->GetPseudoType() == CSSSelector::kPseudoSlotted)
-      return false;
-    if (current->Relation() != CSSSelector::kSubSelector) {
-      current = current->TagHistory();
-      break;
-    }
-  }
-
-  for (; current; current = current->TagHistory()) {
-    if (current->IsAttributeSelector())
-      return true;
-    if (SelectorListContainsUncommonAttributeSelector(current))
-      return true;
-  }
-  return false;
-}
-
 static inline PropertyWhitelistType DeterminePropertyWhitelistType(
     const AddRuleFlags add_rule_flags,
     const CSSSelector& selector) {
@@ -124,8 +73,6 @@
       is_last_in_array_(false),
       position_(position),
       specificity_(Selector().Specificity()),
-      contains_uncommon_attribute_selector_(
-          blink::ContainsUncommonAttributeSelector(Selector())),
       link_match_type_(Selector().ComputeLinkMatchType()),
       has_document_security_origin_(add_rule_flags &
                                     kRuleHasDocumentSecurityOrigin),
@@ -441,7 +388,6 @@
   visitor->Trace(placeholder_pseudo_rules_);
   visitor->Trace(universal_rules_);
   visitor->Trace(shadow_host_rules_);
-  visitor->Trace(features_);
   visitor->Trace(page_rules_);
   visitor->Trace(font_face_rules_);
   visitor->Trace(keyframes_rules_);
diff --git a/third_party/WebKit/Source/core/css/SelectorChecker.cpp b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
index 94c86d5a..fce4200 100644
--- a/third_party/WebKit/Source/core/css/SelectorChecker.cpp
+++ b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
@@ -761,9 +761,7 @@
         element.SetStyleAffectedByEmpty();
         if (context.in_rightmost_compound)
           element_style_->SetEmptyState(result);
-        else if (element.GetComputedStyle() &&
-                 (element.GetDocument().GetStyleEngine().UsesSiblingRules() ||
-                  element.GetComputedStyle()->Unique()))
+        else if (element.GetComputedStyle())
           element.MutableComputedStyle()->SetEmptyState(result);
       }
       return result;
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 4986186..7d55803b 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -304,6 +304,11 @@
   return nullptr;
 }
 
+static CSSValue* ConsumeBackgroundBox(CSSParserTokenRange& range) {
+  return ConsumeIdent<CSSValueBorderBox, CSSValuePaddingBox,
+                      CSSValueContentBox>(range);
+}
+
 static CSSValue* ConsumePrefixedBackgroundBox(CSSParserTokenRange& range,
                                               const CSSParserContext* context,
                                               bool allow_text_value) {
@@ -351,13 +356,13 @@
                                             const CSSParserContext* context) {
   switch (unresolved_property) {
     case CSSPropertyBackgroundClip:
-      return CSSPropertyBackgroundUtils::ConsumeBackgroundBox(range);
+      return ConsumeBackgroundBox(range);
     case CSSPropertyBackgroundBlendMode:
       return CSSPropertyBackgroundUtils::ConsumeBackgroundBlendMode(range);
     case CSSPropertyBackgroundAttachment:
       return CSSPropertyBackgroundUtils::ConsumeBackgroundAttachment(range);
     case CSSPropertyBackgroundOrigin:
-      return CSSPropertyBackgroundUtils::ConsumeBackgroundBox(range);
+      return ConsumeBackgroundBox(range);
     case CSSPropertyWebkitMaskComposite:
       return CSSPropertyBackgroundUtils::ConsumeBackgroundComposite(range);
     case CSSPropertyMaskSourceType:
@@ -667,10 +672,55 @@
     case CSSPropertyWebkitLogicalWidth:
     case CSSPropertyWebkitLogicalHeight:
       return CSSPropertyLengthUtils::ConsumeWidthOrHeight(range_, *context_);
+    case CSSPropertyAnimationDelay:
+    case CSSPropertyTransitionDelay:
+      return ConsumeCommaSeparatedList(ConsumeTime, range_, kValueRangeAll);
+    case CSSPropertyAnimationDuration:
+    case CSSPropertyTransitionDuration:
+      return ConsumeCommaSeparatedList(ConsumeTime, range_,
+                                       kValueRangeNonNegative);
+    case CSSPropertyAnimationTimingFunction:
+    case CSSPropertyTransitionTimingFunction:
+      return ConsumeCommaSeparatedList(CSSPropertyAnimationTimingFunctionUtils::
+                                           ConsumeAnimationTimingFunction,
+                                       range_);
+    case CSSPropertyGridColumnGap:
+    case CSSPropertyGridRowGap:
+      return ConsumeLengthOrPercent(range_, context_->Mode(),
+                                    kValueRangeNonNegative);
     case CSSPropertyTextDecoration:
       DCHECK(!RuntimeEnabledFeatures::CSS3TextDecorationsEnabled());
       return CSSPropertyTextDecorationLineUtils::ConsumeTextDecorationLine(
           range_);
+    case CSSPropertyWebkitTransformOriginX:
+    case CSSPropertyWebkitPerspectiveOriginX:
+      return CSSPropertyPositionUtils::ConsumePositionLonghand<CSSValueLeft,
+                                                               CSSValueRight>(
+          range_, context_->Mode());
+    case CSSPropertyWebkitTransformOriginY:
+    case CSSPropertyWebkitPerspectiveOriginY:
+      return CSSPropertyPositionUtils::ConsumePositionLonghand<CSSValueTop,
+                                                               CSSValueBottom>(
+          range_, context_->Mode());
+    case CSSPropertyBorderImageRepeat:
+    case CSSPropertyWebkitMaskBoxImageRepeat:
+      return CSSPropertyBorderImageUtils::ConsumeBorderImageRepeat(range_);
+    case CSSPropertyBorderImageSlice:
+    case CSSPropertyWebkitMaskBoxImageSlice:
+      return CSSPropertyBorderImageUtils::ConsumeBorderImageSlice(
+          range_, false /* default_fill */);
+    case CSSPropertyBorderImageOutset:
+    case CSSPropertyWebkitMaskBoxImageOutset:
+      return CSSPropertyBorderImageUtils::ConsumeBorderImageOutset(range_);
+    case CSSPropertyBorderImageWidth:
+    case CSSPropertyWebkitMaskBoxImageWidth:
+      return CSSPropertyBorderImageUtils::ConsumeBorderImageWidth(range_);
+    case CSSPropertyBackgroundClip:
+    case CSSPropertyBackgroundOrigin:
+      return ConsumeCommaSeparatedList(ConsumeBackgroundBox, range_);
+    case CSSPropertyBackgroundImage:
+    case CSSPropertyWebkitMaskImage:
+      return ConsumeCommaSeparatedList(ConsumeImageOrNone, range_, context_);
     case CSSPropertyBackgroundPositionX:
     case CSSPropertyWebkitMaskPositionX:
       return ConsumeCommaSeparatedList(
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundBox.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundBox.cpp
deleted file mode 100644
index 6f768fc..0000000
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundBox.cpp
+++ /dev/null
@@ -1,20 +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 "core/css/properties/CSSPropertyAPIBackgroundBox.h"
-
-#include "core/css/parser/CSSPropertyParserHelpers.h"
-#include "core/css/properties/CSSPropertyBackgroundUtils.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIBackgroundBox::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext&,
-    const CSSParserLocalContext&) {
-  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
-      CSSPropertyBackgroundUtils::ConsumeBackgroundBox, range);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundOrMaskImage.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundOrMaskImage.cpp
deleted file mode 100644
index fc421a0..0000000
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundOrMaskImage.cpp
+++ /dev/null
@@ -1,19 +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 "core/css/properties/CSSPropertyAPIBackgroundOrMaskImage.h"
-
-#include "core/css/parser/CSSPropertyParserHelpers.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIBackgroundOrMaskImage::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    const CSSParserLocalContext&) {
-  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
-      CSSPropertyParserHelpers::ConsumeImageOrNone, range, &context);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageOutset.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageOutset.cpp
index ec4e37fc..8836bd0 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageOutset.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageOutset.cpp
@@ -4,15 +4,4 @@
 
 #include "core/css/properties/CSSPropertyAPIBorderImageOutset.h"
 
-#include "core/css/properties/CSSPropertyBorderImageUtils.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIBorderImageOutset::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext&,
-    const CSSParserLocalContext&) {
-  return CSSPropertyBorderImageUtils::ConsumeBorderImageOutset(range);
-}
-
-}  // namespace blink
+namespace blink {}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageRepeat.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageRepeat.cpp
index ba6846e..e7b74980 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageRepeat.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageRepeat.cpp
@@ -4,15 +4,4 @@
 
 #include "core/css/properties/CSSPropertyAPIBorderImageRepeat.h"
 
-#include "core/css/properties/CSSPropertyBorderImageUtils.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIBorderImageRepeat::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext&,
-    const CSSParserLocalContext&) {
-  return CSSPropertyBorderImageUtils::ConsumeBorderImageRepeat(range);
-}
-
-}  // namespace blink
+namespace blink {}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageSlice.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageSlice.cpp
index 13fc7e6b..6d6a7eb1 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageSlice.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageSlice.cpp
@@ -4,16 +4,4 @@
 
 #include "core/css/properties/CSSPropertyAPIBorderImageSlice.h"
 
-#include "core/css/properties/CSSPropertyBorderImageUtils.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIBorderImageSlice::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext&,
-    const CSSParserLocalContext&) {
-  return CSSPropertyBorderImageUtils::ConsumeBorderImageSlice(
-      range, DefaultFill::kNoFill);
-}
-
-}  // namespace blink
+namespace blink {}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageWidth.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageWidth.cpp
index ec6b4782..bcc64fa 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageWidth.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageWidth.cpp
@@ -4,15 +4,4 @@
 
 #include "core/css/properties/CSSPropertyAPIBorderImageWidth.h"
 
-#include "core/css/properties/CSSPropertyBorderImageUtils.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIBorderImageWidth::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext&,
-    const CSSParserLocalContext&) {
-  return CSSPropertyBorderImageUtils::ConsumeBorderImageWidth(range);
-}
-
-}  // namespace blink
+namespace blink {}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDelay.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDelay.cpp
deleted file mode 100644
index e0c153a..0000000
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDelay.cpp
+++ /dev/null
@@ -1,20 +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 "core/css/properties/CSSPropertyAPIDelay.h"
-
-#include "core/css/parser/CSSPropertyParserHelpers.h"
-#include "platform/Length.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIDelay::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext&,
-    const CSSParserLocalContext&) {
-  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
-      CSSPropertyParserHelpers::ConsumeTime, range, kValueRangeAll);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDuration.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDuration.cpp
deleted file mode 100644
index c8121ac..0000000
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDuration.cpp
+++ /dev/null
@@ -1,20 +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 "core/css/properties/CSSPropertyAPIDuration.h"
-
-#include "core/css/parser/CSSPropertyParserHelpers.h"
-#include "platform/Length.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIDuration::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext&,
-    const CSSParserLocalContext&) {
-  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
-      CSSPropertyParserHelpers::ConsumeTime, range, kValueRangeNonNegative);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridGap.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridGap.cpp
deleted file mode 100644
index 81ac4c9..0000000
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridGap.cpp
+++ /dev/null
@@ -1,21 +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 "core/css/properties/CSSPropertyAPIGridGap.h"
-
-#include "core/css/parser/CSSParserContext.h"
-#include "core/css/parser/CSSPropertyParserHelpers.h"
-#include "platform/Length.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIGridGap::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    const CSSParserLocalContext&) {
-  return CSSPropertyParserHelpers::ConsumeLengthOrPercent(
-      range, context.Mode(), kValueRangeNonNegative);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITimingFunction.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITimingFunction.cpp
deleted file mode 100644
index c8e71935..0000000
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITimingFunction.cpp
+++ /dev/null
@@ -1,21 +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 "core/css/properties/CSSPropertyAPITimingFunction.h"
-
-#include "core/css/parser/CSSPropertyParserHelpers.h"
-#include "core/css/properties/CSSPropertyAnimationTimingFunctionUtils.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPITimingFunction::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext&,
-    const CSSParserLocalContext&) {
-  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
-      CSSPropertyAnimationTimingFunctionUtils::ConsumeAnimationTimingFunction,
-      range);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginX.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginX.cpp
index be6ce92..24ecc2c2 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginX.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginX.cpp
@@ -4,19 +4,4 @@
 
 #include "core/css/properties/CSSPropertyAPIWebkitOriginX.h"
 
-#include "core/CSSValueKeywords.h"
-#include "core/css/parser/CSSParserContext.h"
-#include "core/css/properties/CSSPropertyPositionUtils.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIWebkitOriginX::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    const CSSParserLocalContext&) {
-  return CSSPropertyPositionUtils::ConsumePositionLonghand<CSSValueLeft,
-                                                           CSSValueRight>(
-      range, context.Mode());
-}
-
-}  // namespace blink
+namespace blink {}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginY.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginY.cpp
index d080353..08483ce 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginY.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginY.cpp
@@ -4,19 +4,4 @@
 
 #include "core/css/properties/CSSPropertyAPIWebkitOriginY.h"
 
-#include "core/CSSValueKeywords.h"
-#include "core/css/parser/CSSParserContext.h"
-#include "core/css/properties/CSSPropertyPositionUtils.h"
-
-namespace blink {
-
-const CSSValue* CSSPropertyAPIWebkitOriginY::parseSingleValue(
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    const CSSParserLocalContext&) {
-  return CSSPropertyPositionUtils::ConsumePositionLonghand<CSSValueTop,
-                                                           CSSValueBottom>(
-      range, context.Mode());
-}
-
-}  // namespace blink
+namespace blink {}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.cpp
index b993d52..16bfeeb 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.cpp
@@ -43,12 +43,6 @@
   return nullptr;
 }
 
-CSSValue* CSSPropertyBackgroundUtils::ConsumeBackgroundBox(
-    CSSParserTokenRange& range) {
-  return CSSPropertyParserHelpers::ConsumeIdent<
-      CSSValueBorderBox, CSSValuePaddingBox, CSSValueContentBox>(range);
-}
-
 CSSValue* CSSPropertyBackgroundUtils::ConsumeBackgroundComposite(
     CSSParserTokenRange& range) {
   return CSSPropertyParserHelpers::ConsumeIdentRange(range, CSSValueClear,
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.h b/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.h
index 7885bf73c..6511178 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.h
@@ -24,7 +24,6 @@
 
   static CSSValue* ConsumeBackgroundAttachment(CSSParserTokenRange&);
   static CSSValue* ConsumeBackgroundBlendMode(CSSParserTokenRange&);
-  static CSSValue* ConsumeBackgroundBox(CSSParserTokenRange&);
   static CSSValue* ConsumeBackgroundComposite(CSSParserTokenRange&);
   static CSSValue* ConsumeMaskSourceType(CSSParserTokenRange&);
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.cpp
index 98ec279..4905104 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.cpp
@@ -34,7 +34,7 @@
   CSSValue* outset = nullptr;
   CSSValue* repeat = nullptr;
   if (ConsumeBorderImageComponents(range, context, source, slice, width, outset,
-                                   repeat, DefaultFill::kFill))
+                                   repeat, true /* default_fill */))
     return CreateBorderImageValue(source, slice, width, outset, repeat);
   return nullptr;
 }
@@ -47,7 +47,7 @@
     CSSValue*& width,
     CSSValue*& outset,
     CSSValue*& repeat,
-    DefaultFill default_fill) {
+    bool default_fill) {
   do {
     if (!source) {
       source = CSSPropertyParserHelpers::ConsumeImageOrNone(range, &context);
@@ -99,7 +99,7 @@
 
 CSSValue* CSSPropertyBorderImageUtils::ConsumeBorderImageSlice(
     CSSParserTokenRange& range,
-    DefaultFill default_fill) {
+    bool default_fill) {
   bool fill = CSSPropertyParserHelpers::ConsumeIdent<CSSValueFill>(range);
   CSSValue* slices[4] = {0};
 
@@ -122,7 +122,7 @@
     fill = true;
   }
   CSSPropertyParserHelpers::Complete4Sides(slices);
-  if (default_fill == DefaultFill::kFill)
+  if (default_fill)
     fill = true;
   return CSSBorderImageSliceValue::Create(
       CSSQuadValue::Create(slices[0], slices[1], slices[2], slices[3],
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.h b/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.h
index b00b5ba9..20a6182 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.h
@@ -13,8 +13,6 @@
 class CSSParserTokenRange;
 class CSSValue;
 
-enum class DefaultFill { kFill, kNoFill };
-
 class CSSPropertyBorderImageUtils {
   STATIC_ONLY(CSSPropertyBorderImageUtils);
 
@@ -28,9 +26,10 @@
                                            CSSValue*& width,
                                            CSSValue*& outset,
                                            CSSValue*& repeat,
-                                           DefaultFill);
+                                           bool default_fill);
   static CSSValue* ConsumeBorderImageRepeat(CSSParserTokenRange&);
-  static CSSValue* ConsumeBorderImageSlice(CSSParserTokenRange&, DefaultFill);
+  static CSSValue* ConsumeBorderImageSlice(CSSParserTokenRange&,
+                                           bool default_fill);
   static CSSValue* ConsumeBorderImageWidth(CSSParserTokenRange&);
   static CSSValue* ConsumeBorderImageOutset(CSSParserTokenRange&);
 };
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyPositionUtils.h b/third_party/WebKit/Source/core/css/properties/CSSPropertyPositionUtils.h
index 4cf4137..d3e3cb6 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyPositionUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyPositionUtils.h
@@ -6,8 +6,6 @@
 
 #include "core/CSSValueKeywords.h"
 #include "core/css/parser/CSSParserMode.h"
-#include "core/css/parser/CSSParserTokenRange.h"
-#include "core/css/parser/CSSPropertyParserHelpers.h"
 
 #include "platform/wtf/Allocator.h"
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp
index 32c44f6..b17bf4f 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp
@@ -24,8 +24,7 @@
   CSSValue* repeat = nullptr;
 
   if (!CSSPropertyBorderImageUtils::ConsumeBorderImageComponents(
-          range, context, source, slice, width, outset, repeat,
-          DefaultFill::kNoFill)) {
+          range, context, source, slice, width, outset, repeat, false)) {
     return false;
   }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp
index 031deba..b4f49c9 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp
@@ -24,8 +24,7 @@
   CSSValue* repeat = nullptr;
 
   if (!CSSPropertyBorderImageUtils::ConsumeBorderImageComponents(
-          range, context, source, slice, width, outset, repeat,
-          DefaultFill::kFill)) {
+          range, context, source, slice, width, outset, repeat, true)) {
     return false;
   }
 
diff --git a/third_party/WebKit/Source/core/dom/ElementShadowV0.cpp b/third_party/WebKit/Source/core/dom/ElementShadowV0.cpp
index 184c2ee0..8194216 100644
--- a/third_party/WebKit/Source/core/dom/ElementShadowV0.cpp
+++ b/third_party/WebKit/Source/core/dom/ElementShadowV0.cpp
@@ -260,7 +260,6 @@
 DEFINE_TRACE(ElementShadowV0) {
   visitor->Trace(element_shadow_);
   visitor->Trace(node_to_insertion_points_);
-  visitor->Trace(select_features_);
 }
 
 DEFINE_TRACE_WRAPPERS(ElementShadowV0) {}
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.h b/third_party/WebKit/Source/core/dom/StyleEngine.h
index a7f4b82..7955aea 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.h
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.h
@@ -168,9 +168,6 @@
   unsigned MaxDirectAdjacentSelectors() const {
     return GetRuleFeatureSet().MaxDirectAdjacentSelectors();
   }
-  bool UsesSiblingRules() const {
-    return GetRuleFeatureSet().UsesSiblingRules();
-  }
   bool UsesFirstLineRules() const {
     return GetRuleFeatureSet().UsesFirstLineRules();
   }
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp
index fafb4aa..a670b4f 100644
--- a/third_party/WebKit/Source/core/editing/SelectionController.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -667,18 +667,17 @@
   Element* url_element = result.GetHitTestResult().URLElement();
   const VisiblePositionInFlatTree pos =
       VisiblePositionOfHitTestResult(result.GetHitTestResult());
-  const VisibleSelectionInFlatTree& new_selection =
+  const SelectionInFlatTree& new_selection =
       pos.IsNotNull() &&
               pos.DeepEquivalent().AnchorNode()->IsDescendantOf(url_element)
-          ? CreateVisibleSelection(SelectionInFlatTree::Builder()
-                                       .SelectAllChildren(*url_element)
-                                       .Build())
-          : VisibleSelectionInFlatTree();
+          ? SelectionInFlatTree::Builder()
+                .SelectAllChildren(*url_element)
+                .Build()
+          : SelectionInFlatTree();
 
   UpdateSelectionForMouseDownDispatchingSelectStart(
       inner_node,
-      ExpandSelectionToRespectUserSelectAll(inner_node,
-                                            new_selection.AsSelection()),
+      ExpandSelectionToRespectUserSelectAll(inner_node, new_selection),
       TextGranularity::kWord, HandleVisibility::kNotVisible);
 }
 
diff --git a/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp b/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp
index 67ddff6..0637959 100644
--- a/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp
+++ b/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp
@@ -57,17 +57,13 @@
 }
 
 void WorkerShadowPage::SetContentSecurityPolicyAndReferrerPolicy(
-    ContentSecurityPolicyResponseHeaders csp_headers,
+    ContentSecurityPolicy* content_security_policy,
     String referrer_policy) {
   DCHECK(IsMainThread());
-  Document* document = main_frame_->GetFrame()->GetDocument();
-  ContentSecurityPolicy* content_security_policy =
-      ContentSecurityPolicy::Create();
-  content_security_policy->SetOverrideURLForSelf(document->Url());
-  content_security_policy->DidReceiveHeaders(csp_headers);
-  document->InitContentSecurityPolicy(content_security_policy);
+  content_security_policy->SetOverrideURLForSelf(GetDocument()->Url());
+  GetDocument()->InitContentSecurityPolicy(content_security_policy);
   if (!referrer_policy.IsNull())
-    document->ParseAndSetReferrerPolicy(referrer_policy);
+    GetDocument()->ParseAndSetReferrerPolicy(referrer_policy);
 }
 
 void WorkerShadowPage::DidFinishDocumentLoad() {
diff --git a/third_party/WebKit/Source/core/exported/WorkerShadowPage.h b/third_party/WebKit/Source/core/exported/WorkerShadowPage.h
index e60dbd0..69e1b97 100644
--- a/third_party/WebKit/Source/core/exported/WorkerShadowPage.h
+++ b/third_party/WebKit/Source/core/exported/WorkerShadowPage.h
@@ -6,7 +6,6 @@
 #define WorkerShadowPage_h
 
 #include "core/frame/WebLocalFrameImpl.h"
-#include "platform/network/ContentSecurityPolicyResponseHeaders.h"
 #include "public/web/WebDevToolsAgentClient.h"
 #include "public/web/WebDocumentLoader.h"
 #include "public/web/WebFrameClient.h"
@@ -15,6 +14,7 @@
 
 namespace blink {
 
+class ContentSecurityPolicy;
 class WebApplicationCacheHost;
 class WebApplicationCacheHostClient;
 class WebSettings;
@@ -53,9 +53,8 @@
   // Calls Client::OnShadowPageInitialized() when complete.
   void Initialize(const KURL& script_url);
 
-  void SetContentSecurityPolicyAndReferrerPolicy(
-      ContentSecurityPolicyResponseHeaders csp_headers,
-      String referrer_policy);
+  void SetContentSecurityPolicyAndReferrerPolicy(ContentSecurityPolicy*,
+                                                 String referrer_policy);
 
   // WebFrameClient overrides.
   std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
diff --git a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp
index 4a4216ce..0874fbd 100644
--- a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp
@@ -56,12 +56,9 @@
 #include "platform/Histogram.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/SharedBuffer.h"
-#include "platform/WaitableEvent.h"
 #include "platform/heap/Handle.h"
 #include "platform/instrumentation/tracing/TraceEvent.h"
 #include "platform/loader/fetch/SubstituteData.h"
-#include "platform/network/ContentSecurityPolicyParsers.h"
-#include "platform/network/ContentSecurityPolicyResponseHeaders.h"
 #include "platform/network/NetworkUtils.h"
 #include "platform/weborigin/SecurityOrigin.h"
 #include "platform/wtf/Functional.h"
@@ -267,12 +264,11 @@
 }
 
 void WebEmbeddedWorkerImpl::SetContentSecurityPolicyAndReferrerPolicy(
-    ContentSecurityPolicyResponseHeaders csp_headers,
-    String referrer_policy,
-    WaitableEvent* event) {
+    ContentSecurityPolicy* content_security_policy,
+    String referrer_policy) {
+  DCHECK(IsMainThread());
   shadow_page_->SetContentSecurityPolicyAndReferrerPolicy(
-      std::move(csp_headers), std::move(referrer_policy));
-  event->Signal();
+      content_security_policy, std::move(referrer_policy));
 }
 
 std::unique_ptr<WebApplicationCacheHost>
@@ -413,12 +409,9 @@
   if (main_script_loader_) {
     // We need to set the CSP to both the shadow page's document and the
     // ServiceWorkerGlobalScope.
-    document->InitContentSecurityPolicy(
-        main_script_loader_->ReleaseContentSecurityPolicy());
-    if (!main_script_loader_->GetReferrerPolicy().IsNull()) {
-      document->ParseAndSetReferrerPolicy(
-          main_script_loader_->GetReferrerPolicy());
-    }
+    SetContentSecurityPolicyAndReferrerPolicy(
+        main_script_loader_->ReleaseContentSecurityPolicy(),
+        main_script_loader_->GetReferrerPolicy());
     global_scope_creation_params = WTF::MakeUnique<GlobalScopeCreationParams>(
         worker_start_data_.script_url, worker_start_data_.user_agent,
         main_script_loader_->SourceText(),
diff --git a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.h b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.h
index eeab61f4..9310781b 100644
--- a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.h
+++ b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.h
@@ -38,7 +38,6 @@
 #include "modules/ModulesExport.h"
 #include "platform/WebTaskRunner.h"
 #include "platform/heap/Handle.h"
-#include "public/platform/WebContentSecurityPolicy.h"
 #include "public/web/WebDevToolsAgentClient.h"
 #include "public/web/WebEmbeddedWorker.h"
 #include "public/web/WebEmbeddedWorkerStartData.h"
@@ -46,9 +45,9 @@
 
 namespace blink {
 
+class ContentSecurityPolicy;
 class ServiceWorkerGlobalScopeProxy;
 class ServiceWorkerInstalledScriptsManager;
-class WaitableEvent;
 class WorkerInspectorProxy;
 class WorkerScriptLoader;
 class WorkerThread;
@@ -84,13 +83,10 @@
 
   // Applies the specified CSP and referrer policy to the worker, so that
   // fetches initiated by the worker (other than for the main worker script
-  // itself) are affected by these policies. The WaitableEvent is signaled when
-  // the policies are set. This enables the caller to ensure that policies are
-  // set before starting script execution on the worker thread.
-  void SetContentSecurityPolicyAndReferrerPolicy(
-      ContentSecurityPolicyResponseHeaders,
-      WTF::String referrer_policy,
-      WaitableEvent*);
+  // itself) are affected by these policies. This must be called before starting
+  // script execution on the worker thread.
+  void SetContentSecurityPolicyAndReferrerPolicy(ContentSecurityPolicy*,
+                                                 String referrer_policy);
 
   // WorkerShadowPage::Client overrides.
   std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
index 4030f70..ceae493 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
@@ -79,6 +79,7 @@
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/WaitableEvent.h"
 #include "platform/loader/fetch/ResourceResponse.h"
+#include "platform/network/ContentSecurityPolicyResponseHeaders.h"
 #include "platform/wtf/Assertions.h"
 #include "platform/wtf/Functional.h"
 #include "platform/wtf/PtrUtil.h"
@@ -90,6 +91,24 @@
 
 namespace blink {
 
+namespace {
+
+void SetContentSecurityPolicyAndReferrerPolicyOnMainThread(
+    WebEmbeddedWorkerImpl* embedded_worker,
+    ContentSecurityPolicyResponseHeaders csp_headers,
+    String referrer_policy,
+    WaitableEvent* waitable_event) {
+  DCHECK(IsMainThread());
+  ContentSecurityPolicy* content_security_policy =
+      ContentSecurityPolicy::Create();
+  content_security_policy->DidReceiveHeaders(csp_headers);
+  embedded_worker->SetContentSecurityPolicyAndReferrerPolicy(
+      content_security_policy, std::move(referrer_policy));
+  waitable_event->Signal();
+}
+
+}  // namespace
+
 ServiceWorkerGlobalScopeProxy* ServiceWorkerGlobalScopeProxy::Create(
     WebEmbeddedWorkerImpl& embedded_worker,
     WebServiceWorkerContextClient& client) {
@@ -576,7 +595,7 @@
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(
-              &WebEmbeddedWorkerImpl::SetContentSecurityPolicyAndReferrerPolicy,
+              &SetContentSecurityPolicyAndReferrerPolicyOnMainThread,
               CrossThreadUnretained(embedded_worker_),
               csp_headers_on_worker_thread, referrer_policy_on_worker_thread,
               CrossThreadUnretained(&waitable_event)));
diff --git a/third_party/WebKit/public/web/WebBlob.h b/third_party/WebKit/public/web/WebBlob.h
index 6deda49a..093872fe 100644
--- a/third_party/WebKit/public/web/WebBlob.h
+++ b/third_party/WebKit/public/web/WebBlob.h
@@ -37,10 +37,6 @@
 #include "public/platform/WebString.h"
 #include "public/platform/WebURL.h"
 
-#if BLINK_IMPLEMENTATION
-#include "platform/heap/Handle.h"
-#endif
-
 namespace v8 {
 class Isolate;
 class Object;
diff --git a/third_party/WebKit/public/web/WebDOMFileSystem.h b/third_party/WebKit/public/web/WebDOMFileSystem.h
index bf4dbe7..e591579 100644
--- a/third_party/WebKit/public/web/WebDOMFileSystem.h
+++ b/third_party/WebKit/public/web/WebDOMFileSystem.h
@@ -37,10 +37,6 @@
 #include "public/platform/WebURL.h"
 #include "WebFrame.h"
 
-#if BLINK_IMPLEMENTATION
-#include "platform/heap/Handle.h"
-#endif
-
 namespace v8 {
 class Isolate;
 class Object;
diff --git a/third_party/WebKit/public/web/WebDOMMediaStreamTrack.h b/third_party/WebKit/public/web/WebDOMMediaStreamTrack.h
index e6e3561..bc57dc8 100644
--- a/third_party/WebKit/public/web/WebDOMMediaStreamTrack.h
+++ b/third_party/WebKit/public/web/WebDOMMediaStreamTrack.h
@@ -34,10 +34,6 @@
 #include "public/platform/WebMediaStreamTrack.h"
 #include "public/platform/WebPrivatePtr.h"
 
-#if BLINK_IMPLEMENTATION
-#include "platform/wtf/PassRefPtr.h"
-#endif
-
 namespace v8 {
 class Value;
 template <class T>