diff --git a/chrome/android/java/src/org/chromium/chrome/browser/PasswordManagerHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/PasswordManagerHandler.java
new file mode 100644
index 0000000..ead4749
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/PasswordManagerHandler.java
@@ -0,0 +1,64 @@
+// 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;
+
+/**
+ * Interface for retrieving passwords and password exceptions (websites for which Chrome should not
+ * save password) from native code.
+ */
+public interface PasswordManagerHandler {
+    /**
+     * An interface which a client can use to listen to changes to password and password exception
+     * lists.
+     */
+    public interface PasswordListObserver {
+        /**
+         * Called when passwords list is updated.
+         * @param count Number of entries in the password list.
+         */
+        void passwordListAvailable(int count);
+
+        /**
+         * Called when password exceptions list is updated.
+         * @param count Number of entries in the password exception list.
+         */
+        void passwordExceptionListAvailable(int count);
+    }
+
+    /**
+     * Called to start fetching password and exception lists.
+     */
+    public void updatePasswordLists();
+
+    /**
+     * Get the saved password entry at index.
+     *
+     * @param index Index of Password.
+     * @return SavedPasswordEntry at index.
+     */
+    public SavedPasswordEntry getSavedPasswordEntry(int index);
+
+    /**
+     * Get saved password exception at index.
+     *
+     * @param index of exception
+     * @return Origin of password exception.
+     */
+    public String getSavedPasswordException(int index);
+
+    /**
+     * Remove saved password entry at index.
+     *
+     * @param index of password entry to remove.
+     */
+    public void removeSavedPasswordEntry(int index);
+
+    /**
+     * Remove saved exception entry at index.
+     *
+     * @param index of exception entry.
+     */
+    public void removeSavedPasswordException(int index);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java b/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java
index b51ba809..2c0172d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java
@@ -4,147 +4,77 @@
 
 package org.chromium.chrome.browser;
 
-import org.chromium.base.ObserverList;
 import org.chromium.base.annotations.CalledByNative;
 
 /**
- * Class for retrieving passwords and password exceptions (websites for which Chrome should not save
- * password) from native code.
+ * Production implementation of PasswordManagerHandler, making calls to native C++ code to retrieve
+ * the data.
  */
-public final class PasswordUIView {
-
-    /**
-     * Class representing information about a saved password entry.
-     */
-    public static final class SavedPasswordEntry {
-        private final String mUrl;
-        private final String mName;
-        private final String mPassword;
-
-        private SavedPasswordEntry(String url, String name, String password) {
-            mUrl = url;
-            mName = name;
-            mPassword = password;
-        }
-
-        public String getUrl() {
-            return mUrl;
-        }
-
-        public String getUserName() {
-            return mName;
-        }
-
-        public String getPassword() {
-            return mPassword;
-        }
-    }
-
+public final class PasswordUIView implements PasswordManagerHandler {
     @CalledByNative
     private static SavedPasswordEntry createSavedPasswordEntry(
             String url, String name, String password) {
         return new SavedPasswordEntry(url, name, password);
     }
 
-    /**
-     * Interface which client can use to listen to changes to password and password exception lists.
-     * Clients can register and unregister themselves with addObserver and removeObserver.
-     */
-    public interface PasswordListObserver {
-        /**
-         * Called when passwords list is updated.
-         * @param count Number of entries in the password list.
-         */
-        void passwordListAvailable(int count);
-
-        /**
-         * Called when password exceptions list is updated.
-         * @param count Number of entries in the password exception list.
-         */
-        void passwordExceptionListAvailable(int count);
-    }
-
-    private ObserverList<PasswordListObserver> mObservers =
-            new ObserverList<PasswordListObserver>();
-
     // Pointer to native implementation, set to 0 in destroy().
     private long mNativePasswordUIViewAndroid;
 
+    // This class has exactly one observer, set on construction and expected to last at least as
+    // long as this object (a good candidate is the owner of this object).
+    private final PasswordListObserver mObserver;
+
     /**
      * Constructor creates the native object as well. Callers should call destroy() after usage.
+     * @param PasswordListObserver The only observer.
      */
-    public PasswordUIView() {
+    public PasswordUIView(PasswordListObserver observer) {
         mNativePasswordUIViewAndroid = nativeInit();
+        mObserver = observer;
     }
 
     @CalledByNative
     private void passwordListAvailable(int count) {
-        for (PasswordListObserver observer : mObservers) {
-            observer.passwordListAvailable(count);
-        }
+        mObserver.passwordListAvailable(count);
     }
 
     @CalledByNative
     private void passwordExceptionListAvailable(int count) {
-        for (PasswordListObserver observer : mObservers) {
-            observer.passwordExceptionListAvailable(count);
-        }
+        mObserver.passwordExceptionListAvailable(count);
     }
 
-    public void addObserver(PasswordListObserver observer) {
-        mObservers.addObserver(observer);
-    }
-
-    public void removeObserver(PasswordListObserver observer) {
-        mObservers.removeObserver(observer);
-    }
-
-    /**
-     * Calls native to refresh password and exception lists. Observers are notified when fetch to
-     * passwords is complete.
-     */
+    // Calls native to refresh password and exception lists. The native code calls back into
+    // passwordListAvailable and passwordExceptionListAvailable.
+    @Override
     public void updatePasswordLists() {
         nativeUpdatePasswordLists(mNativePasswordUIViewAndroid);
     }
 
-    /**
-     * Get the saved password entry at index.
-     *
-     * @param index Index of Password.
-     * @return SavedPasswordEntry at index.
-     */
+    @Override
     public SavedPasswordEntry getSavedPasswordEntry(int index) {
         return nativeGetSavedPasswordEntry(mNativePasswordUIViewAndroid, index);
     }
 
-    /**
-     * Get saved password exception at index.
-     *
-     * @param index of exception
-     * @return Origin of password exception.
-     */
+    @Override
     public String getSavedPasswordException(int index) {
         return nativeGetSavedPasswordException(mNativePasswordUIViewAndroid, index);
     }
 
-    /**
-     * Remove saved password entry at index.
-     *
-     * @param index of password entry to remove.
-     */
+    @Override
     public void removeSavedPasswordEntry(int index) {
         nativeHandleRemoveSavedPasswordEntry(mNativePasswordUIViewAndroid, index);
     }
 
-    /**
-     * Remove saved exception entry at index.
-     *
-     * @param index of exception entry.
-     */
+    @Override
     public void removeSavedPasswordException(int index) {
         nativeHandleRemoveSavedPasswordException(mNativePasswordUIViewAndroid, index);
     }
 
+    /**
+     * Returns the URL for the website for managing one's passwords without the need to use Chrome
+     * with the user's profile signed in.
+     * @return The string with the URL.
+     */
     public static String getAccountDashboardURL() {
         return nativeGetAccountDashboardURL();
     }
@@ -157,7 +87,6 @@
             nativeDestroy(mNativePasswordUIViewAndroid);
             mNativePasswordUIViewAndroid = 0;
         }
-        mObservers.clear();
     }
 
     private native long nativeInit();
@@ -165,8 +94,7 @@
     private native void nativeUpdatePasswordLists(long nativePasswordUIViewAndroid);
 
     private native SavedPasswordEntry nativeGetSavedPasswordEntry(
-            long nativePasswordUIViewAndroid,
-            int index);
+            long nativePasswordUIViewAndroid, int index);
 
     private native String nativeGetSavedPasswordException(long nativePasswordUIViewAndroid,
             int index);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SavedPasswordEntry.java b/chrome/android/java/src/org/chromium/chrome/browser/SavedPasswordEntry.java
new file mode 100644
index 0000000..032ba7d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/SavedPasswordEntry.java
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+/**
+ * A class representing information about a saved password entry in Chrome's settngs.
+ *
+ * Note: This could be a nested class in the PasswordManagerHandler interface, but that would mean
+ * that PasswordUIView, which implements that interface and references SavedPasswordEntry in some of
+ * its JNI-registered methods, would need an explicit import of PasswordManagerHandler. That again
+ * would violate our presubmit checks, and https://crbug.com/424792 indicates that the preferred
+ * solution is to move the nested class to top-level.
+ */
+public final class SavedPasswordEntry {
+    private final String mUrl;
+    private final String mName;
+    private final String mPassword;
+
+    public SavedPasswordEntry(String url, String name, String password) {
+        mUrl = url;
+        mName = name;
+        mPassword = password;
+    }
+
+    public String getUrl() {
+        return mUrl;
+    }
+
+    public String getUserName() {
+        return mName;
+    }
+
+    public String getPassword() {
+        return mPassword;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
index eb8a82c..44781481 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -34,8 +34,8 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.PasswordManagerHandler.PasswordListObserver;
 import org.chromium.chrome.browser.PasswordUIView;
-import org.chromium.chrome.browser.PasswordUIView.PasswordListObserver;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.components.sync.AndroidSyncSettings;
 import org.chromium.ui.text.SpanApplier;
@@ -214,7 +214,6 @@
 
     // Delete was clicked.
     private void removeItem() {
-        final PasswordUIView passwordUIView = new PasswordUIView();
         final PasswordListObserver passwordDeleter = new PasswordListObserver() {
             @Override
             public void passwordListAvailable(int count) {
@@ -222,8 +221,10 @@
                     RecordHistogram.recordEnumeratedHistogram(
                             "PasswordManager.Android.PasswordCredentialEntry",
                             PASSWORD_ENTRY_ACTION_DELETED, PASSWORD_ENTRY_ACTION_BOUNDARY);
-                    passwordUIView.removeSavedPasswordEntry(mID);
-                    passwordUIView.destroy();
+                    PasswordManagerHandlerProvider.getInstance()
+                            .getPasswordManagerHandler()
+                            .removeSavedPasswordEntry(mID);
+                    PasswordManagerHandlerProvider.getInstance().removeObserver(this);
                     Toast.makeText(getActivity().getApplicationContext(), R.string.deleted,
                                  Toast.LENGTH_SHORT)
                             .show();
@@ -237,8 +238,10 @@
                     RecordHistogram.recordEnumeratedHistogram(
                             "PasswordManager.Android.PasswordExceptionEntry",
                             PASSWORD_ENTRY_ACTION_DELETED, PASSWORD_ENTRY_ACTION_BOUNDARY);
-                    passwordUIView.removeSavedPasswordException(mID);
-                    passwordUIView.destroy();
+                    PasswordManagerHandlerProvider.getInstance()
+                            .getPasswordManagerHandler()
+                            .removeSavedPasswordException(mID);
+                    PasswordManagerHandlerProvider.getInstance().removeObserver(this);
                     Toast.makeText(getActivity().getApplicationContext(), R.string.deleted,
                                  Toast.LENGTH_SHORT)
                             .show();
@@ -247,8 +250,10 @@
             }
         };
 
-        passwordUIView.addObserver(passwordDeleter);
-        passwordUIView.updatePasswordLists();
+        PasswordManagerHandlerProvider.getInstance().addObserver(passwordDeleter);
+        PasswordManagerHandlerProvider.getInstance()
+                .getPasswordManagerHandler()
+                .updatePasswordLists();
     }
 
     private void hookupCopyUsernameButton(View usernameView) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandlerProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandlerProvider.java
new file mode 100644
index 0000000..52341247
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandlerProvider.java
@@ -0,0 +1,117 @@
+// 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.preferences.password;
+
+import org.chromium.base.ObserverList;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.PasswordManagerHandler;
+import org.chromium.chrome.browser.PasswordUIView;
+
+/**
+ * A provider for PasswordManagerHandler implementations, handling the choice of the proper one
+ * (production vs. testing), its lifetime and multiple observers.
+ *
+ * This class is used by the code responsible for Chrome's passwords settings. There can only be one
+ * instance of Chrome's passwords settings opened at a time (although more clients of
+ * PasswordManagerHandler can live as nested settings pages). Therefore, the provider can be just
+ * one. However, it cannot be just a collection of static data members and methods, because the
+ * managed PasswordManagerHandler instances need to refer to it as an observer. For that reason, the
+ * provider is a singleton.
+ */
+public class PasswordManagerHandlerProvider implements PasswordManagerHandler.PasswordListObserver {
+    private static final class LazyHolder {
+        private static final PasswordManagerHandlerProvider INSTANCE =
+                new PasswordManagerHandlerProvider();
+    }
+
+    /** Private constructor, use GetInstance() instead. */
+    private PasswordManagerHandlerProvider() {}
+
+    public static PasswordManagerHandlerProvider getInstance() {
+        return LazyHolder.INSTANCE;
+    }
+
+    // The production implementation of PasswordManagerHandler is |sPasswordUIView|, instantiated on
+    // demand. Tests might want to override that by providing a fake implementation through
+    // setPasswordManagerHandlerForTest, which is then kept in |mTestPasswordManagerHandler|.
+    private PasswordUIView mPasswordUIView;
+    private PasswordManagerHandler mTestPasswordManagerHandler;
+
+    // This class is itself a PasswordListObserver, listening directly to a PasswordManagerHandler
+    // implementation. But it also keeps a list of other observers, to which it forwards the events.
+    private final ObserverList<PasswordManagerHandler.PasswordListObserver> mObservers =
+            new ObserverList<PasswordManagerHandler.PasswordListObserver>();
+
+    /**
+     * Sets a testing implementation of PasswordManagerHandler to be used. It overrides the
+     * production one even if it exists. The caller needs to ensure that |this| becomes an observer
+     * of |passwordManagerHandler|. Also, this must not be called when there are already some
+     * observers in |mObservers|, because of special handling of the production implementation of
+     * PasswordManagerHandler on removing the last observer.
+     */
+    @VisibleForTesting
+    public void setPasswordManagerHandlerForTest(PasswordManagerHandler passwordManagerHandler) {
+        ThreadUtils.assertOnUiThread();
+        assert mObservers.isEmpty();
+        mTestPasswordManagerHandler = passwordManagerHandler;
+    }
+
+    /**
+     * A convenience function to choose between the production and test PasswordManagerHandler
+     * implementation.
+     */
+    public PasswordManagerHandler getPasswordManagerHandler() {
+        ThreadUtils.assertOnUiThread();
+        if (mTestPasswordManagerHandler != null) return mTestPasswordManagerHandler;
+        return mPasswordUIView;
+    }
+
+    /**
+     * This method creates the production implementation of PasswordManagerHandler and saves it into
+     * mPasswordUIView.
+     */
+    private void createPasswordManagerHandler() {
+        ThreadUtils.assertOnUiThread();
+        assert mPasswordUIView == null;
+        mPasswordUIView = new PasswordUIView(this);
+    }
+
+    /**
+     * Starts forwarding events from the PasswordManagerHandler implementation to |observer|.
+     */
+    public void addObserver(PasswordManagerHandler.PasswordListObserver observer) {
+        ThreadUtils.assertOnUiThread();
+        if (getPasswordManagerHandler() == null) createPasswordManagerHandler();
+        mObservers.addObserver(observer);
+    }
+
+    public void removeObserver(PasswordManagerHandler.PasswordListObserver observer) {
+        ThreadUtils.assertOnUiThread();
+        mObservers.removeObserver(observer);
+        // If this was the last observer of the production implementation of PasswordManagerHandler,
+        // call destroy on it to close the connection to the native C++ code.
+        if (mObservers.isEmpty() && mTestPasswordManagerHandler == null) {
+            mPasswordUIView.destroy();
+            mPasswordUIView = null;
+        }
+    }
+
+    @Override
+    public void passwordListAvailable(int count) {
+        ThreadUtils.assertOnUiThread();
+        for (PasswordManagerHandler.PasswordListObserver observer : mObservers) {
+            observer.passwordListAvailable(count);
+        }
+    }
+
+    @Override
+    public void passwordExceptionListAvailable(int count) {
+        ThreadUtils.assertOnUiThread();
+        for (PasswordManagerHandler.PasswordListObserver observer : mObservers) {
+            observer.passwordExceptionListAvailable(count);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
index 296f5f8..4611618 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
@@ -21,8 +21,9 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.PasswordManagerHandler;
 import org.chromium.chrome.browser.PasswordUIView;
-import org.chromium.chrome.browser.PasswordUIView.PasswordListObserver;
+import org.chromium.chrome.browser.SavedPasswordEntry;
 import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
 import org.chromium.chrome.browser.preferences.ChromeBasePreference;
 import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
@@ -37,8 +38,9 @@
  * The "Save passwords" screen in Settings, which allows the user to enable or disable password
  * saving, to view saved passwords (just the username and URL), and to delete saved passwords.
  */
-public class SavePasswordsPreferences extends PreferenceFragment
-        implements PasswordListObserver, Preference.OnPreferenceClickListener {
+public class SavePasswordsPreferences
+        extends PreferenceFragment implements PasswordManagerHandler.PasswordListObserver,
+                                              Preference.OnPreferenceClickListener {
     // Keys for name/password dictionaries.
     public static final String PASSWORD_LIST_URL = "url";
     public static final String PASSWORD_LIST_NAME = "name";
@@ -65,7 +67,6 @@
     private static final int ORDER_EXCEPTIONS = 4;
     private static final int ORDER_SAVED_PASSWORDS_NO_TEXT = 5;
 
-    private final PasswordUIView mPasswordManagerHandler = new PasswordUIView();
     private boolean mNoPasswords;
     private boolean mNoPasswordExceptions;
     private Preference mLinkPref;
@@ -78,7 +79,7 @@
         super.onCreate(savedInstanceState);
         getActivity().setTitle(R.string.prefs_saved_passwords);
         setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity()));
-        mPasswordManagerHandler.addObserver(this);
+        PasswordManagerHandlerProvider.getInstance().addObserver(this);
         if (ChromeFeatureList.isEnabled(EXPORT_PASSWORDS)) {
             setHasOptionsMenu(true);
         }
@@ -123,7 +124,9 @@
         getPreferenceScreen().removeAll();
         createSavePasswordsSwitch();
         createAutoSignInCheckbox();
-        mPasswordManagerHandler.updatePasswordLists();
+        PasswordManagerHandlerProvider.getInstance()
+                .getPasswordManagerHandler()
+                .updatePasswordLists();
     }
 
     /**
@@ -168,8 +171,9 @@
         profileCategory.setOrder(ORDER_SAVED_PASSWORDS);
         getPreferenceScreen().addPreference(profileCategory);
         for (int i = 0; i < count; i++) {
-            PasswordUIView.SavedPasswordEntry saved =
-                    mPasswordManagerHandler.getSavedPasswordEntry(i);
+            SavedPasswordEntry saved = PasswordManagerHandlerProvider.getInstance()
+                                               .getPasswordManagerHandler()
+                                               .getSavedPasswordEntry(i);
             PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getActivity());
             String url = saved.getUrl();
             String name = saved.getUserName();
@@ -205,7 +209,9 @@
         profileCategory.setOrder(ORDER_EXCEPTIONS);
         getPreferenceScreen().addPreference(profileCategory);
         for (int i = 0; i < count; i++) {
-            String exception = mPasswordManagerHandler.getSavedPasswordException(i);
+            String exception = PasswordManagerHandlerProvider.getInstance()
+                                       .getPasswordManagerHandler()
+                                       .getSavedPasswordException(i);
             PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getActivity());
             screen.setTitle(exception);
             screen.setOnPreferenceClickListener(this);
@@ -225,7 +231,7 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
-        mPasswordManagerHandler.destroy();
+        PasswordManagerHandlerProvider.getInstance().removeObserver(this);
     }
 
     /**
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 8792d5b..123d912 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -56,9 +56,11 @@
   "java/src/org/chromium/chrome/browser/NativePageHost.java",
   "java/src/org/chromium/chrome/browser/NavigationPopup.java",
   "java/src/org/chromium/chrome/browser/NearOomMonitor.java",
+  "java/src/org/chromium/chrome/browser/PasswordManagerHandler.java",
   "java/src/org/chromium/chrome/browser/PasswordUIView.java",
   "java/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java",
   "java/src/org/chromium/chrome/browser/RepostFormWarningDialog.java",
+  "java/src/org/chromium/chrome/browser/SavedPasswordEntry.java",
   "java/src/org/chromium/chrome/browser/SearchGeolocationDisclosureTabHelper.java",
   "java/src/org/chromium/chrome/browser/ServiceTabLauncher.java",
   "java/src/org/chromium/chrome/browser/SingleTabActivity.java",
@@ -967,11 +969,12 @@
   "java/src/org/chromium/chrome/browser/preferences/languages/LanguageListBaseAdapter.java",
   "java/src/org/chromium/chrome/browser/preferences/languages/LanguageListPreference.java",
   "java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java",
+  "java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandlerProvider.java",
+  "java/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragment.java",
+  "java/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManager.java",
   "java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java",
   "java/src/org/chromium/chrome/browser/preferences/privacy/BandwidthType.java",
   "java/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataBridge.java",
-  "java/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragment.java",
-  "java/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManager.java",
   "java/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataCounterBridge.java",
   "java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java",
   "java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesAdvanced.java",
diff --git a/chrome/browser/search/README.md b/chrome/browser/search/README.md
new file mode 100644
index 0000000..bb545d2
--- /dev/null
+++ b/chrome/browser/search/README.md
@@ -0,0 +1,147 @@
+New Tab Page (Desktop)
+======================
+
+On Desktop (ChromeOS, Windows, Mac, and Linux), there are multiple
+variants of the **New Tab Page** (**NTP**). The variant is selected
+according to the user’s **Default Search Engine** (**DSE**). All
+variants are implemented as HTML/CSS/JS, but differ in where they are
+hosted.
+
+*   **Google**: either the **[Remote NTP][remote-ntp]** (as of
+    2017-12-05, the default) or the **[Local NTP][local-ntp]**, with
+    Google branding (as of 2017-12-05, planned to replace the Remote NTP
+    and in experiments on Beta).
+
+*   **Bing**, **Yandex**: a **[Third-Party NTP][third-party-ntp]**,
+    where the NTP is hosted on third-party servers but Chrome provides
+    some of the content via <iframe> elements.
+
+*   **Other**: the **Local NTP** with no branding.
+
+As of 2017-12-05, Bing and Yandex have implemented third-party NTPs. The
+full list is in [`prepopulated_engines.json`][engines], under the key
+`"new_tab_url"`.
+
+All variants show up to 8 **NTP Tiles**. Each NTP tile represents a site
+that Chrome believes the user is likely to want to visit. On Desktop,
+NTP tiles have a title, a thumbnail, and an “X” button so that the user
+can remove tiles that they don’t want.
+
+[remote-ntp]:       #remote-ntp
+[local-ntp]:        #local-ntp
+[third-party-ntp]:  #third_party-ntp
+[engines]:          https://chromium.googlesource.com/chromium/src/+/master/components/search_engines/prepopulated_engines.json
+
+Variants
+--------
+
+### Local NTP
+
+#### Google branding
+
+##### One Google Bar
+
+The **One Google Bar** (**OGB**) is at the top of the NTP. The NTP
+fetches the OGB from Google servers each time it loads.
+
+##### Google Logo
+
+The **Google Logo** is below the OGB. By default, it is the regular
+Google logo. It can also be a **Doodle**, if a Google Doodle is running
+for a particular combination of (today’s date, user’s country, user’s
+birthday).
+
+###### No Doodle
+
+On a day when there is no Doodle (in the user’s current country), the
+NTP shows the Google logo. It comes in two variants:
+
+*   Colorful, if the user is using the default theme, or on any other
+    theme with a solid black (L=0%), white (L=100%), or gray (S=0%)
+    background color.
+*   White, if the user’s theme has a background image, or if the
+    background is a solid color, but not black, white, or gray.
+
+Also, even on days when there is a Doodle, if the user’s theme’s
+background is not solid white, new NTPs show the Google logo by default.
+In this case, an animated spinner advertises the Doodle. If the user
+clicks on the spinner, then the NTP resets to the default theme and
+shows the Doodle.
+
+###### Static Doodles
+
+A **Static Doodle** shows as a single static image. When clicked, it
+triggers a navigation to the Doodle’s target URL.
+
+###### Animated Doodles
+
+An **Animated Doodle** initially shows a static **Call-to-Action**
+(**CTA**) image, usually with a “play” icon. When clicked, it swaps out
+the CTA image for an animated image. When clicked a second time, it
+triggers a navigation to the Doodle’s target URL.
+
+###### Interactive Doodles
+
+An **Interactive Doodle** is embedded into the NTP as an `<iframe>`.
+The framed content usually contains a CTA image, but this is opaque to
+the containing NTP.
+
+The embedded Doodle can ask the containing NTP to resize the `<iframe>`
+tag to enlarge the space available for the Doodle. To do this, it sends
+a `postMessage()` call to `window.parent`. The event data supports these
+parameters:
+
+*   `cmd` (required string): must be `"resizeDoodle"`.
+*   `width` (optional string): a CSS width (with units) or `null`.
+    Because the Doodle cannot know the size of the outer page, only
+    `null` (default width) or values based on `"100%"` (`"100%"`,
+    `"calc(100% - 50px)"`) are recommended.
+*   `height` (optional string): a CSS height (with units) or `null` for
+    the default (`"200px"`). Must not be a percentage, but otherwise any
+    units are OK.
+*   `duration` (optional string): a CSS duration, such as `"130ms"` or
+    `"1s"`. If `null` or absent, `"0s"` (no transition) is assumed.
+
+For example:
+
+    // Reset to initial width and height.
+    window.parent.postMessage({cmd: "resizeDoodle"});
+
+    // Transition smoothly to full-width, 350px tall.
+    window.parent.postMessage({
+        cmd: "resizeDoodle",
+        width: "100%",
+        height: "350px",
+        duration: "1s",
+    });
+
+##### Fakebox
+
+The **Fakebox** looks like a search bar, so that the NTP mimics the
+appearance of the Google homepage. It’s not actually a real search bar,
+and if the user interacts with it, the NTP moves keyboard focus and any
+text to the Omnibox and hides the Fakebox.
+
+##### Promos
+
+Below the NTP tiles, there is space for a **Promo**. A Promo is
+typically a short string, typically used for disasters (e.g. “Affected
+by the Boston Molassacre? Find a relief center near you.”) or an
+advertisement (e.g. “Try the all-new new Chromebook, with included
+toaster oven.”).
+
+As of 2017-12-05, the Local NTP does not yet support Promos.
+
+#### Non-Google Local NTP
+
+A non-Google local NTP shows only NTP tiles, with no branding. The tiles
+are centered within the page.
+
+### Remote NTP
+
+The Remote NTP is hosted on Google servers. It is intended for removal,
+and is not documented here.
+
+### Third-Party NTP
+
+TODO(sfiera)
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.cc b/chrome/browser/sync/test/integration/bookmarks_helper.cc
index 08ebdd52..c392f30 100644
--- a/chrome/browser/sync/test/integration/bookmarks_helper.cc
+++ b/chrome/browser/sync/test/integration/bookmarks_helper.cc
@@ -87,13 +87,15 @@
   }
   ~FaviconChangeObserver() override { model_->RemoveObserver(this); }
   void WaitForGetFavicon() {
+    DCHECK(!run_loop_.running());
     wait_for_load_ = true;
-    content::RunMessageLoop();
+    content::RunThisRunLoop(&run_loop_);
     ASSERT_TRUE(node_->is_favicon_loaded());
   }
   void WaitForSetFavicon() {
+    DCHECK(!run_loop_.running());
     wait_for_load_ = false;
-    content::RunMessageLoop();
+    content::RunThisRunLoop(&run_loop_);
   }
 
   // bookmarks::BookmarkModelObserver:
@@ -125,9 +127,9 @@
                                      const BookmarkNode* node) override {}
   void BookmarkNodeFaviconChanged(BookmarkModel* model,
                                   const BookmarkNode* node) override {
-    if (model == model_ && node == node_) {
+    if (model == model_ && node == node_ && run_loop_.running()) {
       if (!wait_for_load_ || (wait_for_load_ && node->is_favicon_loaded()))
-        base::RunLoop::QuitCurrentWhenIdleDeprecated();
+        run_loop_.Quit();
     }
   }
 
@@ -135,6 +137,7 @@
   BookmarkModel* model_;
   const BookmarkNode* node_;
   bool wait_for_load_;
+  base::RunLoop run_loop_;
   DISALLOW_COPY_AND_ASSIGN(FaviconChangeObserver);
 };
 
diff --git a/chrome/browser/sync/test/integration/passwords_helper.cc b/chrome/browser/sync/test/integration/passwords_helper.cc
index 6559ce5..22ef0fff 100644
--- a/chrome/browser/sync/test/integration/passwords_helper.cc
+++ b/chrome/browser/sync/test/integration/passwords_helper.cc
@@ -49,15 +49,17 @@
   void OnGetPasswordStoreResults(
       std::vector<std::unique_ptr<PasswordForm>> results) override {
     result_.swap(results);
-    // Quit the message loop to wake up passwords_helper::GetLogins.
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
+    run_loop_.Quit();
   }
 
-  std::vector<std::unique_ptr<PasswordForm>> result() {
+  std::vector<std::unique_ptr<PasswordForm>> WaitForResult() {
+    DCHECK(!run_loop_.running());
+    content::RunThisRunLoop(&run_loop_);
     return std::move(result_);
   }
 
  private:
+  base::RunLoop run_loop_;
   std::vector<std::unique_ptr<PasswordForm>> result_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper);
@@ -101,8 +103,7 @@
       PasswordForm::SCHEME_HTML, kFakeSignonRealm, GURL()};
   PasswordStoreConsumerHelper consumer;
   store->GetLogins(matcher_form, &consumer);
-  content::RunMessageLoop();
-  return consumer.result();
+  return consumer.WaitForResult();
 }
 
 void RemoveLogin(PasswordStore* store, const PasswordForm& form) {
diff --git a/chrome/browser/sync/test/integration/status_change_checker.cc b/chrome/browser/sync/test/integration/status_change_checker.cc
index 364ecb5..7194b0e 100644
--- a/chrome/browser/sync/test/integration/status_change_checker.cc
+++ b/chrome/browser/sync/test/integration/status_change_checker.cc
@@ -8,7 +8,9 @@
 #include "base/run_loop.h"
 #include "base/timer/timer.h"
 
-StatusChangeChecker::StatusChangeChecker() : timed_out_(false) {}
+StatusChangeChecker::StatusChangeChecker()
+    : run_loop_(base::RunLoop::Type::kNestableTasksAllowed),
+      timed_out_(false) {}
 
 StatusChangeChecker::~StatusChangeChecker() {}
 
@@ -30,18 +32,9 @@
   return base::TimeDelta::FromSeconds(45);
 }
 
-void StatusChangeChecker::StartBlockingWait() {
-  base::OneShotTimer timer;
-  timer.Start(FROM_HERE,
-              GetTimeoutDuration(),
-              base::Bind(&StatusChangeChecker::OnTimeout,
-                         base::Unretained(this)));
-
-  base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).Run();
-}
-
 void StatusChangeChecker::StopWaiting() {
-  base::RunLoop::QuitCurrentWhenIdleDeprecated();
+  if (run_loop_.running())
+    run_loop_.Quit();
 }
 
 void StatusChangeChecker::CheckExitCondition() {
@@ -52,6 +45,17 @@
   }
 }
 
+void StatusChangeChecker::StartBlockingWait() {
+  DCHECK(!run_loop_.running());
+
+  base::OneShotTimer timer;
+  timer.Start(FROM_HERE, GetTimeoutDuration(),
+              base::BindRepeating(&StatusChangeChecker::OnTimeout,
+                                  base::Unretained(this)));
+
+  run_loop_.Run();
+}
+
 void StatusChangeChecker::OnTimeout() {
   DVLOG(1) << "Await -> Timed out: " << GetDebugMessage();
   timed_out_ = true;
diff --git a/chrome/browser/sync/test/integration/status_change_checker.h b/chrome/browser/sync/test/integration/status_change_checker.h
index 1716b35..d78ca105 100644
--- a/chrome/browser/sync/test/integration/status_change_checker.h
+++ b/chrome/browser/sync/test/integration/status_change_checker.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/run_loop.h"
 #include "base/time/time.h"
 
 // Interface for a helper class that can pump the message loop while waiting
@@ -45,14 +46,6 @@
   // Timeout length when blocking.
   virtual base::TimeDelta GetTimeoutDuration();
 
-  // Helper function to start running the nested run loop.
-  //
-  // Will exit if IsExitConditionSatisfied() returns true when called from
-  // CheckExitCondition(), if a timeout occurs, or if StopWaiting() is called.
-  //
-  // The timeout length is specified with GetTimeoutDuration().
-  void StartBlockingWait();
-
   // Stop the nested running of the message loop started in StartBlockingWait().
   void StopWaiting();
 
@@ -60,9 +53,19 @@
   // true.
   void CheckExitCondition();
 
+ private:
+  // Helper function to start running the nested run loop (run_loop_).
+  //
+  // Will exit if IsExitConditionSatisfied() returns true when called from
+  // CheckExitCondition(), if a timeout occurs, or if StopWaiting() is called.
+  //
+  // The timeout length is specified with GetTimeoutDuration().
+  void StartBlockingWait();
+
   // Called when the blocking wait timeout is exceeded.
   void OnTimeout();
 
+  base::RunLoop run_loop_;
   bool timed_out_;
 };
 
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 889729b0..d2f02e7 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10171.0.0
\ No newline at end of file
+10190.0.0
\ No newline at end of file
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 9be9762b..2c733eed 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -820,8 +820,6 @@
       "media/webrtc/track_observer.cc",
       "media/webrtc/track_observer.h",
       "media/webrtc/two_keys_adapter_map.h",
-      "media/webrtc/video_codec_factory.cc",
-      "media/webrtc/video_codec_factory.h",
       "media/webrtc/webrtc_audio_sink.cc",
       "media/webrtc/webrtc_audio_sink.h",
       "media/webrtc/webrtc_media_stream_adapter.cc",
diff --git a/content/renderer/media/gpu/rtc_video_decoder.cc b/content/renderer/media/gpu/rtc_video_decoder.cc
index 311227ae..d81d406 100644
--- a/content/renderer/media/gpu/rtc_video_decoder.cc
+++ b/content/renderer/media/gpu/rtc_video_decoder.cc
@@ -133,6 +133,12 @@
   return decoder;
 }
 
+// static
+void RTCVideoDecoder::Destroy(webrtc::VideoDecoder* decoder,
+                              media::GpuVideoAcceleratorFactories* factories) {
+  factories->GetTaskRunner()->DeleteSoon(FROM_HERE, decoder);
+}
+
 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings,
                                     int32_t /*numberOfCores*/) {
   DVLOG(2) << "InitDecode";
@@ -271,10 +277,6 @@
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
-const char* RTCVideoDecoder::ImplementationName() const {
-  return "RTCVideoDecoder";
-}
-
 int32_t RTCVideoDecoder::Release() {
   DVLOG(2) << "Release";
   // Do not destroy VDA because WebRTC can call InitDecode and start decoding
diff --git a/content/renderer/media/gpu/rtc_video_decoder.h b/content/renderer/media/gpu/rtc_video_decoder.h
index 23afb14..25a7eba2 100644
--- a/content/renderer/media/gpu/rtc_video_decoder.h
+++ b/content/renderer/media/gpu/rtc_video_decoder.h
@@ -85,8 +85,6 @@
   // this runs.
   int32_t Release() override;
 
-  const char* ImplementationName() const override;
-
   // VideoDecodeAccelerator::Client implementation.
   void ProvidePictureBuffers(uint32_t count,
                              media::VideoPixelFormat format,
diff --git a/content/renderer/media/gpu/rtc_video_decoder_factory.cc b/content/renderer/media/gpu/rtc_video_decoder_factory.cc
index f1f0b7a..8df7c448 100644
--- a/content/renderer/media/gpu/rtc_video_decoder_factory.cc
+++ b/content/renderer/media/gpu/rtc_video_decoder_factory.cc
@@ -6,89 +6,31 @@
 
 #include <memory>
 
-#include "base/memory/ptr_util.h"
 #include "content/renderer/media/gpu/rtc_video_decoder.h"
 #include "media/video/gpu_video_accelerator_factories.h"
-#include "third_party/webrtc/api/video_codecs/sdp_video_format.h"
 
 namespace content {
 
-namespace {
-
-// This extra indirection is needed so that we can delete the decoder on the
-// correct thread.
-class ScopedVideoDecoder : public webrtc::VideoDecoder {
- public:
-  ScopedVideoDecoder(
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-      std::unique_ptr<webrtc::VideoDecoder> decoder)
-      : task_runner_(task_runner), decoder_(std::move(decoder)) {}
-
-  int32_t InitDecode(const webrtc::VideoCodec* codec_settings,
-                     int32_t number_of_cores) override {
-    return decoder_->InitDecode(codec_settings, number_of_cores);
-  }
-  int32_t RegisterDecodeCompleteCallback(
-      webrtc::DecodedImageCallback* callback) override {
-    return decoder_->RegisterDecodeCompleteCallback(callback);
-  }
-  int32_t Release() override { return decoder_->Release(); }
-  int32_t Decode(const webrtc::EncodedImage& input_image,
-                 bool missing_frames,
-                 const webrtc::RTPFragmentationHeader* fragmentation,
-                 const webrtc::CodecSpecificInfo* codec_specific_info,
-                 int64_t render_time_ms) override {
-    return decoder_->Decode(input_image, missing_frames, fragmentation,
-                            codec_specific_info, render_time_ms);
-  }
-  bool PrefersLateDecoding() const override {
-    return decoder_->PrefersLateDecoding();
-  }
-  const char* ImplementationName() const override {
-    return decoder_->ImplementationName();
-  }
-
-  // Runs on Chrome_libJingle_WorkerThread. The child thread is blocked while
-  // this runs.
-  ~ScopedVideoDecoder() override {
-    task_runner_->DeleteSoon(FROM_HERE, decoder_.release());
-  }
-
- private:
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  std::unique_ptr<webrtc::VideoDecoder> decoder_;
-};
-
-}  // namespace
-
 RTCVideoDecoderFactory::RTCVideoDecoderFactory(
     media::GpuVideoAcceleratorFactories* gpu_factories)
     : gpu_factories_(gpu_factories) {
   DVLOG(2) << __func__;
 }
 
-std::vector<webrtc::SdpVideoFormat>
-RTCVideoDecoderFactory::GetSupportedFormats() const {
-  // TODO(magjed): Implement this based on
-  // gpu_factories_->GetVideoDecodeAcceleratorSupportedProfiles(). This function
-  // is currently unused by WebRTC.
-  return std::vector<webrtc::SdpVideoFormat>();
-}
-
 RTCVideoDecoderFactory::~RTCVideoDecoderFactory() {
   DVLOG(2) << __func__;
 }
 
-std::unique_ptr<webrtc::VideoDecoder>
-RTCVideoDecoderFactory::CreateVideoDecoder(
-    const webrtc::SdpVideoFormat& format) {
+webrtc::VideoDecoder* RTCVideoDecoderFactory::CreateVideoDecoder(
+    webrtc::VideoCodecType type) {
   DVLOG(2) << __func__;
-  std::unique_ptr<webrtc::VideoDecoder> decoder = RTCVideoDecoder::Create(
-      webrtc::PayloadStringToCodecType(format.name), gpu_factories_);
-  // Make sure the decoder is destructed on the correct thread.
-  return decoder ? base::MakeUnique<ScopedVideoDecoder>(
-                       gpu_factories_->GetTaskRunner(), std::move(decoder))
-                 : nullptr;
+  return RTCVideoDecoder::Create(type, gpu_factories_).release();
+}
+
+void RTCVideoDecoderFactory::DestroyVideoDecoder(
+    webrtc::VideoDecoder* decoder) {
+  DVLOG(2) << __func__;
+  RTCVideoDecoder::Destroy(decoder, gpu_factories_);
 }
 
 }  // namespace content
diff --git a/content/renderer/media/gpu/rtc_video_decoder_factory.h b/content/renderer/media/gpu/rtc_video_decoder_factory.h
index e9e0eea..7a4e45b 100644
--- a/content/renderer/media/gpu/rtc_video_decoder_factory.h
+++ b/content/renderer/media/gpu/rtc_video_decoder_factory.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/threading/thread.h"
 #include "content/common/content_export.h"
-#include "third_party/webrtc/api/video_codecs/video_decoder_factory.h"
+#include "third_party/webrtc/media/engine/webrtcvideodecoderfactory.h"
 #include "third_party/webrtc/modules/video_coding/include/video_codec_interface.h"
 
 namespace webrtc {
@@ -23,7 +23,7 @@
 
 // TODO(wuchengli): add unittest.
 class CONTENT_EXPORT RTCVideoDecoderFactory
-    : public webrtc::VideoDecoderFactory {
+    : public cricket::WebRtcVideoDecoderFactory {
  public:
   explicit RTCVideoDecoderFactory(
       media::GpuVideoAcceleratorFactories* gpu_factories);
@@ -31,10 +31,12 @@
 
   // Runs on Chrome_libJingle_WorkerThread. The child thread is blocked while
   // this runs.
-  std::unique_ptr<webrtc::VideoDecoder> CreateVideoDecoder(
-      const webrtc::SdpVideoFormat& format) override;
+  webrtc::VideoDecoder* CreateVideoDecoder(
+      webrtc::VideoCodecType type) override;
 
-  std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override;
+  // Runs on Chrome_libJingle_WorkerThread. The child thread is blocked while
+  // this runs.
+  void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) override;
 
  private:
   media::GpuVideoAcceleratorFactories* gpu_factories_;
diff --git a/content/renderer/media/gpu/rtc_video_encoder.cc b/content/renderer/media/gpu/rtc_video_encoder.cc
index f7e8366..8a2a2d3 100644
--- a/content/renderer/media/gpu/rtc_video_encoder.cc
+++ b/content/renderer/media/gpu/rtc_video_encoder.cc
@@ -941,8 +941,4 @@
   return true;
 }
 
-const char* RTCVideoEncoder::ImplementationName() const {
-  return "RTCVideoEncoder";
-}
-
 }  // namespace content
diff --git a/content/renderer/media/gpu/rtc_video_encoder.h b/content/renderer/media/gpu/rtc_video_encoder.h
index 155a3317..9612e025 100644
--- a/content/renderer/media/gpu/rtc_video_encoder.h
+++ b/content/renderer/media/gpu/rtc_video_encoder.h
@@ -59,7 +59,6 @@
   int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override;
   int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) override;
   bool SupportsNativeHandle() const override;
-  const char* ImplementationName() const override;
 
  private:
   class Impl;
diff --git a/content/renderer/media/gpu/rtc_video_encoder_factory.cc b/content/renderer/media/gpu/rtc_video_encoder_factory.cc
index fc61ac2..152f7104 100644
--- a/content/renderer/media/gpu/rtc_video_encoder_factory.cc
+++ b/content/renderer/media/gpu/rtc_video_encoder_factory.cc
@@ -11,24 +11,23 @@
 #include "content/renderer/media/gpu/rtc_video_encoder.h"
 #include "media/gpu/ipc/client/gpu_video_encode_accelerator_host.h"
 #include "media/video/gpu_video_accelerator_factories.h"
-#include "third_party/webrtc/api/video_codecs/sdp_video_format.h"
 #include "third_party/webrtc/common_video/h264/profile_level_id.h"
-#include "third_party/webrtc/media/base/codec.h"
 
 namespace content {
 
 namespace {
 
 // Translate from media::VideoEncodeAccelerator::SupportedProfile to
-// webrtc::SdpVideoFormat, or return nothing if the profile isn't supported.
-base::Optional<webrtc::SdpVideoFormat> VEAToWebRTCFormat(
+// 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)) {
-      return webrtc::SdpVideoFormat("VP8");
+      return base::Optional<cricket::VideoCodec>(cricket::VideoCodec("VP8"));
     }
   } else if (profile.profile >= media::H264PROFILE_MIN &&
              profile.profile <= media::H264PROFILE_MAX) {
@@ -55,7 +54,7 @@
           break;
         default:
           // Unsupported H264 profile in WebRTC.
-          return base::nullopt;
+          return base::Optional<cricket::VideoCodec>();
       }
 
       const int width = profile.max_resolution.width();
@@ -68,22 +67,15 @@
       const webrtc::H264::ProfileLevelId profile_level_id(
           h264_profile, h264_level.value_or(webrtc::H264::kLevel1));
 
-      webrtc::SdpVideoFormat format("H264");
-      format.parameters = {
-          {cricket::kH264FmtpProfileLevelId,
-           *webrtc::H264::ProfileLevelIdToString(profile_level_id)},
-          {cricket::kH264FmtpLevelAsymmetryAllowed, "1"},
-          {cricket::kH264FmtpPacketizationMode, "1"}};
-      return format;
+      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::nullopt;
-}
-
-bool IsSameFormat(const webrtc::SdpVideoFormat& format1,
-                  const webrtc::SdpVideoFormat& format2) {
-  return cricket::IsSameCodec(format1.name, format2.parameters, format2.name,
-                              format2.parameters);
+  return base::Optional<cricket::VideoCodec>();
 }
 
 }  // anonymous namespace
@@ -94,45 +86,47 @@
   const media::VideoEncodeAccelerator::SupportedProfiles& profiles =
       gpu_factories_->GetVideoEncodeAcceleratorSupportedProfiles();
   for (const auto& profile : profiles) {
-    base::Optional<webrtc::SdpVideoFormat> format = VEAToWebRTCFormat(profile);
-    if (format) {
-      supported_formats_.push_back(std::move(*format));
+    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
-  // webrtc::SdpVideoFormat.
-  CHECK_EQ(profiles_.size(), supported_formats_.size());
+  // cricket::VideoCodec.
+  CHECK_EQ(profiles_.size(), supported_codecs_.size());
 }
 
 RTCVideoEncoderFactory::~RTCVideoEncoderFactory() {}
 
-std::unique_ptr<webrtc::VideoEncoder>
-RTCVideoEncoderFactory::CreateVideoEncoder(
-    const webrtc::SdpVideoFormat& format) {
-  for (size_t i = 0; i < supported_formats_.size(); ++i) {
-    if (IsSameFormat(format, supported_formats_[i])) {
-      // There should be a 1:1 mapping between media::VideoCodecProfile and
-      // webrtc::SdpVideoFormat.
-      CHECK_EQ(profiles_.size(), supported_formats_.size());
-      return base::MakeUnique<RTCVideoEncoder>(profiles_[i], gpu_factories_);
+webrtc::VideoEncoder* RTCVideoEncoderFactory::CreateVideoEncoder(
+    const cricket::VideoCodec& codec) {
+  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;
 }
 
-std::vector<webrtc::SdpVideoFormat>
-RTCVideoEncoderFactory::GetSupportedFormats() const {
-  return supported_formats_;
+const std::vector<cricket::VideoCodec>&
+RTCVideoEncoderFactory::supported_codecs() const {
+  return supported_codecs_;
 }
 
-webrtc::VideoEncoderFactory::CodecInfo
-RTCVideoEncoderFactory::QueryVideoEncoder(
-    const webrtc::SdpVideoFormat& format) const {
-  CodecInfo info;
-  info.has_internal_source = false;
-  info.is_hardware_accelerated = true;
-  return info;
+void RTCVideoEncoderFactory::DestroyVideoEncoder(
+    webrtc::VideoEncoder* encoder) {
+  delete encoder;
 }
 
 }  // namespace content
diff --git a/content/renderer/media/gpu/rtc_video_encoder_factory.h b/content/renderer/media/gpu/rtc_video_encoder_factory.h
index 904d82e..baf30df9 100644
--- a/content/renderer/media/gpu/rtc_video_encoder_factory.h
+++ b/content/renderer/media/gpu/rtc_video_encoder_factory.h
@@ -12,7 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "content/common/content_export.h"
 #include "media/base/video_codecs.h"
-#include "third_party/webrtc/api/video_codecs/video_encoder_factory.h"
+#include "third_party/webrtc/media/engine/webrtcvideoencoderfactory.h"
 
 namespace media {
 class GpuVideoAcceleratorFactories;
@@ -23,27 +23,26 @@
 // This class creates RTCVideoEncoder instances (each wrapping a
 // media::VideoEncodeAccelerator) on behalf of the WebRTC stack.
 class CONTENT_EXPORT RTCVideoEncoderFactory
-    : public webrtc::VideoEncoderFactory {
+    : public cricket::WebRtcVideoEncoderFactory {
  public:
   explicit RTCVideoEncoderFactory(
       media::GpuVideoAcceleratorFactories* gpu_factories);
   ~RTCVideoEncoderFactory() override;
 
-  // webrtc::VideoEncoderFactory implementation.
-  std::unique_ptr<webrtc::VideoEncoder> CreateVideoEncoder(
-      const webrtc::SdpVideoFormat& format) override;
-  std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override;
-  webrtc::VideoEncoderFactory::CodecInfo QueryVideoEncoder(
-      const webrtc::SdpVideoFormat& format) const override;
+  // cricket::WebRtcVideoEncoderFactory implementation.
+  webrtc::VideoEncoder* CreateVideoEncoder(
+      const cricket::VideoCodec& codec) override;
+  const std::vector<cricket::VideoCodec>& supported_codecs() const override;
+  void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) override;
 
  private:
   media::GpuVideoAcceleratorFactories* gpu_factories_;
 
-  // List of supported webrtc::SdpVideoFormat. |profiles_| and
-  // |supported_formats_| have the same length and the profile for
-  // |supported_formats_[i]| is |profiles_[i]|.
+  // 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<webrtc::SdpVideoFormat> supported_formats_;
+  std::vector<cricket::VideoCodec> supported_codecs_;
 
   DISALLOW_COPY_AND_ASSIGN(RTCVideoEncoderFactory);
 };
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index d687fd4f..d8e343c 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -31,12 +31,13 @@
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/webrtc_ip_handling_policy.h"
 #include "content/public/renderer/content_renderer_client.h"
+#include "content/renderer/media/gpu/rtc_video_decoder_factory.h"
+#include "content/renderer/media/gpu/rtc_video_encoder_factory.h"
 #include "content/renderer/media/media_stream_video_source.h"
 #include "content/renderer/media/media_stream_video_track.h"
 #include "content/renderer/media/rtc_peer_connection_handler.h"
 #include "content/renderer/media/webrtc/audio_codec_factory.h"
 #include "content/renderer/media/webrtc/stun_field_trial.h"
-#include "content/renderer/media/webrtc/video_codec_factory.h"
 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h"
 #include "content/renderer/media/webrtc_audio_device_impl.h"
 #include "content/renderer/media/webrtc_logging.h"
@@ -62,11 +63,18 @@
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/webrtc/api/mediaconstraintsinterface.h"
+#include "third_party/webrtc/api/video_codecs/video_decoder_factory.h"
+#include "third_party/webrtc/api/video_codecs/video_encoder_factory.h"
 #include "third_party/webrtc/api/videosourceproxy.h"
+#include "third_party/webrtc/media/engine/convert_legacy_video_factory.h"
 #include "third_party/webrtc/modules/video_coding/codecs/h264/include/h264.h"
 #include "third_party/webrtc/rtc_base/refcountedobject.h"
 #include "third_party/webrtc/rtc_base/ssladapter.h"
 
+#if defined(OS_ANDROID)
+#include "media/base/android/media_codec_util.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -230,15 +238,35 @@
   socket_factory_.reset(
       new IpcPacketSocketFactory(p2p_socket_dispatcher_.get()));
 
-  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+  std::unique_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
+  std::unique_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
 
+  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+  if (gpu_factories && gpu_factories->IsGpuVideoAcceleratorEnabled()) {
+    if (!cmd_line->HasSwitch(switches::kDisableWebRtcHWDecoding))
+      decoder_factory.reset(new RTCVideoDecoderFactory(gpu_factories));
+
+    if (!cmd_line->HasSwitch(switches::kDisableWebRtcHWEncoding)) {
+      encoder_factory.reset(new RTCVideoEncoderFactory(gpu_factories));
+    }
+  }
+
+#if defined(OS_ANDROID)
+  if (!media::MediaCodecUtil::SupportsSetParameters())
+    encoder_factory.reset();
+#endif
+
+  // TODO(magjed): Update RTCVideoEncoderFactory/RTCVideoDecoderFactory to new
+  // interface and let Chromium be responsible in what order video codecs are
+  // listed, instead of using
+  // cricket::ConvertVideoEncoderFactory/cricket::ConvertVideoDecoderFactory.
   pc_factory_ = webrtc::CreatePeerConnectionFactory(
       worker_thread_ /* network thread */, worker_thread_, signaling_thread_,
       audio_device_.get(), CreateWebrtcAudioEncoderFactory(),
       CreateWebrtcAudioDecoderFactory(),
-      CreateWebrtcVideoEncoderFactory(gpu_factories),
-      CreateWebrtcVideoDecoderFactory(gpu_factories), nullptr /* audio_mixer */,
-      nullptr /* audio_processing */);
+      cricket::ConvertVideoEncoderFactory(std::move(encoder_factory)),
+      cricket::ConvertVideoDecoderFactory(std::move(decoder_factory)),
+      nullptr /* audio_mixer */, nullptr /* audio_processing */);
   CHECK(pc_factory_.get());
 
   webrtc::PeerConnectionFactoryInterface::Options factory_options;
diff --git a/content/renderer/media/webrtc/video_codec_factory.cc b/content/renderer/media/webrtc/video_codec_factory.cc
deleted file mode 100644
index 0c48ad2..0000000
--- a/content/renderer/media/webrtc/video_codec_factory.cc
+++ /dev/null
@@ -1,201 +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 "content/renderer/media/webrtc/video_codec_factory.h"
-
-#include "base/base_switches.h"
-#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
-#include "build/build_config.h"
-#include "content/public/common/content_switches.h"
-#include "content/renderer/media/gpu/rtc_video_decoder_factory.h"
-#include "content/renderer/media/gpu/rtc_video_encoder_factory.h"
-#include "third_party/webrtc/media/base/codec.h"
-#include "third_party/webrtc/media/engine/internaldecoderfactory.h"
-#include "third_party/webrtc/media/engine/internalencoderfactory.h"
-#include "third_party/webrtc/media/engine/simulcast_encoder_adapter.h"
-#include "third_party/webrtc/media/engine/videodecodersoftwarefallbackwrapper.h"
-#include "third_party/webrtc/media/engine/videoencodersoftwarefallbackwrapper.h"
-#include "third_party/webrtc/media/engine/vp8_encoder_simulcast_proxy.h"
-
-#if defined(OS_ANDROID)
-#include "media/base/android/media_codec_util.h"
-#endif
-
-namespace content {
-
-namespace {
-
-bool IsFormatSupported(
-    const std::vector<webrtc::SdpVideoFormat>& supported_formats,
-    const webrtc::SdpVideoFormat& format) {
-  for (const webrtc::SdpVideoFormat& supported_format : supported_formats) {
-    if (cricket::IsSameCodec(format.name, format.parameters,
-                             supported_format.name,
-                             supported_format.parameters)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-template <typename Factory>
-bool IsFormatSupported(Factory* factory, const webrtc::SdpVideoFormat& format) {
-  return factory && IsFormatSupported(factory->GetSupportedFormats(), format);
-}
-
-// Merge |formats1| and |formats2|, but avoid adding duplicate formats.
-std::vector<webrtc::SdpVideoFormat> MergeFormats(
-    std::vector<webrtc::SdpVideoFormat> formats1,
-    std::vector<webrtc::SdpVideoFormat> formats2) {
-  for (const webrtc::SdpVideoFormat& format : formats2) {
-    // Don't add same format twice.
-    if (!IsFormatSupported(formats1, format))
-      formats1.push_back(format);
-  }
-  return formats1;
-}
-
-std::unique_ptr<webrtc::VideoDecoder> CreateDecoder(
-    webrtc::VideoDecoderFactory* factory,
-    const webrtc::SdpVideoFormat& format) {
-  return IsFormatSupported(factory, format)
-             ? factory->CreateVideoDecoder(format)
-             : nullptr;
-}
-
-template <typename SoftwareWrapperClass, typename CoderClass>
-std::unique_ptr<CoderClass> Wrap(std::unique_ptr<CoderClass> internal_coder,
-                                 std::unique_ptr<CoderClass> external_coder) {
-  if (internal_coder && external_coder) {
-    return base::MakeUnique<SoftwareWrapperClass>(std::move(internal_coder),
-                                                  std::move(external_coder));
-  }
-  return external_coder ? std::move(external_coder) : std::move(internal_coder);
-}
-
-// This class combines an external factory with the internal factory and adds
-// internal SW codecs, simulcast, and SW fallback wrappers.
-class EncoderAdapter : public webrtc::VideoEncoderFactory {
- public:
-  explicit EncoderAdapter(
-      std::unique_ptr<webrtc::VideoEncoderFactory> external_encoder_factory)
-      : external_encoder_factory_(std::move(external_encoder_factory)) {}
-
-  webrtc::VideoEncoderFactory::CodecInfo QueryVideoEncoder(
-      const webrtc::SdpVideoFormat& format) const override {
-    const webrtc::VideoEncoderFactory* factory =
-        IsFormatSupported(external_encoder_factory_.get(), format)
-            ? external_encoder_factory_.get()
-            : &internal_encoder_factory_;
-    return factory->QueryVideoEncoder(format);
-  }
-
-  std::unique_ptr<webrtc::VideoEncoder> CreateVideoEncoder(
-      const webrtc::SdpVideoFormat& format) override {
-    std::unique_ptr<webrtc::VideoEncoder> internal_encoder;
-    if (IsFormatSupported(internal_encoder_factory_.GetSupportedFormats(),
-                          format)) {
-      internal_encoder =
-          cricket::CodecNamesEq(format.name.c_str(), cricket::kVp8CodecName)
-              ? base::MakeUnique<webrtc::VP8EncoderSimulcastProxy>(
-                    &internal_encoder_factory_)
-              : internal_encoder_factory_.CreateVideoEncoder(format);
-    }
-
-    std::unique_ptr<webrtc::VideoEncoder> external_encoder;
-    if (IsFormatSupported(external_encoder_factory_.get(), format)) {
-      external_encoder =
-          cricket::CodecNamesEq(format.name.c_str(), cricket::kVp8CodecName)
-              ? base::MakeUnique<webrtc::SimulcastEncoderAdapter>(
-                    external_encoder_factory_.get())
-              : external_encoder_factory_->CreateVideoEncoder(format);
-    }
-
-    return Wrap<webrtc::VideoEncoderSoftwareFallbackWrapper>(
-        std::move(internal_encoder), std::move(external_encoder));
-  }
-
-  std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override {
-    std::vector<webrtc::SdpVideoFormat> internal_formats =
-        internal_encoder_factory_.GetSupportedFormats();
-    return external_encoder_factory_
-               ? MergeFormats(internal_formats,
-                              external_encoder_factory_->GetSupportedFormats())
-               : internal_formats;
-  }
-
- private:
-  webrtc::InternalEncoderFactory internal_encoder_factory_;
-  const std::unique_ptr<webrtc::VideoEncoderFactory> external_encoder_factory_;
-};
-
-// This class combines an external factory with the internal factory and adds
-// internal SW codecs and SW fallback wrappers.
-class DecoderAdapter : public webrtc::VideoDecoderFactory {
- public:
-  explicit DecoderAdapter(
-      std::unique_ptr<webrtc::VideoDecoderFactory> external_decoder_factory)
-      : external_decoder_factory_(std::move(external_decoder_factory)) {}
-
-  std::unique_ptr<webrtc::VideoDecoder> CreateVideoDecoder(
-      const webrtc::SdpVideoFormat& format) override {
-    std::unique_ptr<webrtc::VideoDecoder> internal_decoder =
-        CreateDecoder(&internal_decoder_factory_, format);
-
-    std::unique_ptr<webrtc::VideoDecoder> external_decoder =
-        CreateDecoder(external_decoder_factory_.get(), format);
-
-    return Wrap<webrtc::VideoDecoderSoftwareFallbackWrapper>(
-        std::move(internal_decoder), std::move(external_decoder));
-  }
-
-  std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override {
-    std::vector<webrtc::SdpVideoFormat> internal_formats =
-        internal_decoder_factory_.GetSupportedFormats();
-    return external_decoder_factory_
-               ? MergeFormats(internal_formats,
-                              external_decoder_factory_->GetSupportedFormats())
-               : internal_formats;
-  }
-
- private:
-  webrtc::InternalDecoderFactory internal_decoder_factory_;
-  const std::unique_ptr<webrtc::VideoDecoderFactory> external_decoder_factory_;
-};
-
-}  // namespace
-
-std::unique_ptr<webrtc::VideoEncoderFactory> CreateWebrtcVideoEncoderFactory(
-    media::GpuVideoAcceleratorFactories* gpu_factories) {
-  std::unique_ptr<webrtc::VideoEncoderFactory> encoder_factory;
-
-  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
-  if (gpu_factories && gpu_factories->IsGpuVideoAcceleratorEnabled() &&
-      !cmd_line->HasSwitch(switches::kDisableWebRtcHWEncoding)) {
-    encoder_factory.reset(new RTCVideoEncoderFactory(gpu_factories));
-  }
-
-#if defined(OS_ANDROID)
-  if (!media::MediaCodecUtil::SupportsSetParameters())
-    encoder_factory.reset();
-#endif
-
-  return base::MakeUnique<EncoderAdapter>(std::move(encoder_factory));
-}
-
-std::unique_ptr<webrtc::VideoDecoderFactory> CreateWebrtcVideoDecoderFactory(
-    media::GpuVideoAcceleratorFactories* gpu_factories) {
-  std::unique_ptr<webrtc::VideoDecoderFactory> decoder_factory;
-
-  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
-  if (gpu_factories && gpu_factories->IsGpuVideoAcceleratorEnabled() &&
-      !cmd_line->HasSwitch(switches::kDisableWebRtcHWDecoding)) {
-    decoder_factory.reset(new RTCVideoDecoderFactory(gpu_factories));
-  }
-
-  return base::MakeUnique<DecoderAdapter>(std::move(decoder_factory));
-}
-
-}  // namespace content
diff --git a/content/renderer/media/webrtc/video_codec_factory.h b/content/renderer/media/webrtc/video_codec_factory.h
deleted file mode 100644
index 2935358..0000000
--- a/content/renderer/media/webrtc/video_codec_factory.h
+++ /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.
-
-#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_VIDEO_CODEC_FACTORY_H_
-#define CONTENT_RENDERER_MEDIA_WEBRTC_VIDEO_CODEC_FACTORY_H_
-
-#include "media/video/gpu_video_accelerator_factories.h"
-#include "third_party/webrtc/api/video_codecs/video_decoder_factory.h"
-#include "third_party/webrtc/api/video_codecs/video_encoder_factory.h"
-
-namespace content {
-
-std::unique_ptr<webrtc::VideoEncoderFactory> CreateWebrtcVideoEncoderFactory(
-    media::GpuVideoAcceleratorFactories* gpu_factories);
-std::unique_ptr<webrtc::VideoDecoderFactory> CreateWebrtcVideoDecoderFactory(
-    media::GpuVideoAcceleratorFactories* gpu_factories);
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_WEBRTC_VIDEO_CODEC_FACTORY_H_
diff --git a/device/u2f/OWNERS b/device/u2f/OWNERS
new file mode 100644
index 0000000..bf052cb
--- /dev/null
+++ b/device/u2f/OWNERS
@@ -0,0 +1,3 @@
+jdoerrie@chromium.org
+
+# COMPONENT: Blink>WebAuthentication
diff --git a/third_party/WebKit/LayoutTests/media/track/opera/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/media/track/opera/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html
rename to third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html
index fa39685..e29f2b0 100644
--- a/third_party/WebKit/LayoutTests/media/track/opera/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLMediaElement/crossOrigin.html
@@ -1,7 +1,7 @@
 <!doctype html>
 <title>HTMLMediaElement.crossOrigin</title>
-<script src=../../../../../../resources/testharness.js></script>
-<script src=../../../../../../resources/testharnessreport.js></script>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
 <div id=log></div>
 <script>
 test(function(){
diff --git a/third_party/WebKit/LayoutTests/media/track/opera/interfaces/HTMLElement/HTMLMediaElement/addTextTrack.html b/third_party/WebKit/LayoutTests/media/track/opera/interfaces/HTMLElement/HTMLMediaElement/addTextTrack.html
deleted file mode 100644
index 6893212a..0000000
--- a/third_party/WebKit/LayoutTests/media/track/opera/interfaces/HTMLElement/HTMLMediaElement/addTextTrack.html
+++ /dev/null
@@ -1,107 +0,0 @@
-<!doctype html>
-<title>HTMLMediaElement.addTextTrack</title>
-<script src=../../../../../../resources/testharness.js></script>
-<script src=../../../../../../resources/testharnessreport.js></script>
-<div id=log></div>
-<script>
-var video = document.createElement('video');
-test(function(){
-    assert_throws(new TypeError, function(){
-        video.addTextTrack('foo');
-    });
-    assert_throws(new TypeError, function(){
-        video.addTextTrack(undefined);
-    });
-    assert_throws(new TypeError, function(){
-        video.addTextTrack(null);
-    });
-}, document.title + ' bogus first arg');
-
-test(function(){
-    assert_throws(new TypeError, function(){
-        video.addTextTrack('SUBTITLES');
-    });
-}, document.title + ' uppercase first arg');
-
-test(function(){
-    var t = video.addTextTrack('subtitles');
-    assert_equals(t.kind, 'subtitles');
-    assert_equals(t.label, '');
-    assert_equals(t.language, '');
-    assert_equals(t.mode, 'hidden');
-    assert_equals(t.cues.length, 0);
-}, document.title + ' subtitles first arg');
-
-test(function(){
-    var t = video.addTextTrack('captions');
-    assert_equals(t.kind, 'captions');
-    assert_equals(t.label, '');
-    assert_equals(t.language, '');
-    assert_equals(t.mode, 'hidden');
-    assert_equals(t.cues.length, 0);
-}, document.title + ' captions first arg');
-
-test(function(){
-    var t = video.addTextTrack('descriptions');
-    assert_equals(t.kind, 'descriptions');
-    assert_equals(t.label, '');
-    assert_equals(t.language, '');
-    assert_equals(t.mode, 'hidden');
-    assert_equals(t.cues.length, 0);
-}, document.title + ' descriptions first arg');
-
-test(function(){
-    var t = video.addTextTrack('chapters');
-    assert_equals(t.kind, 'chapters');
-    assert_equals(t.label, '');
-    assert_equals(t.language, '');
-    assert_equals(t.mode, 'hidden');
-    assert_equals(t.cues.length, 0);
-}, document.title + ' chapters first arg');
-
-test(function(){
-    var t = video.addTextTrack('metadata');
-    assert_equals(t.kind, 'metadata');
-    assert_equals(t.label, '');
-    assert_equals(t.language, '');
-    assert_equals(t.mode, 'hidden');
-    assert_equals(t.cues.length, 0);
-}, document.title + ' metadata first arg');
-
-test(function(){
-    var t = video.addTextTrack('subtitles', undefined, undefined);
-    assert_equals(t.kind, 'subtitles');
-    assert_equals(t.label, '');
-    assert_equals(t.language, '');
-    assert_equals(t.mode, 'hidden');
-    assert_equals(t.cues.length, 0);
-}, document.title + ' undefined second and third arg');
-
-test(function(){
-    var t = video.addTextTrack('subtitles', null, null);
-    assert_equals(t.kind, 'subtitles');
-    assert_equals(t.label, 'null');
-    assert_equals(t.language, 'null');
-    assert_equals(t.mode, 'hidden');
-    assert_equals(t.cues.length, 0);
-}, document.title + ' null second and third arg');
-
-test(function(){
-    var t = video.addTextTrack('subtitles', 'foo', 'bar');
-    assert_equals(t.kind, 'subtitles');
-    assert_equals(t.label, 'foo');
-    assert_equals(t.language, 'bar');
-    assert_equals(t.mode, 'hidden');
-    assert_equals(t.cues.length, 0);
-}, document.title + ' foo and bar second and third arg');
-
-test(function(){
-    var t = video.addTextTrack('subtitles', 'foo');
-    assert_equals(t.kind, 'subtitles');
-    assert_equals(t.label, 'foo');
-    assert_equals(t.language, '');
-    assert_equals(t.mode, 'hidden');
-    assert_equals(t.cues.length, 0);
-}, document.title + ' foo second arg, third arg omitted');
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/media/track/opera/interfaces/HTMLElement/HTMLMediaElement/textTracks.html b/third_party/WebKit/LayoutTests/media/track/opera/interfaces/HTMLElement/HTMLMediaElement/textTracks.html
deleted file mode 100644
index c63d2f8..0000000
--- a/third_party/WebKit/LayoutTests/media/track/opera/interfaces/HTMLElement/HTMLMediaElement/textTracks.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!doctype html>
-<title>HTMLMediaElement.textTracks</title>
-<script src=../../../../../../resources/testharness.js></script>
-<script src=../../../../../../resources/testharnessreport.js></script>
-<div id=log></div>
-<script>
-var video = document.createElement('video');
-test(function(){
-    assert_equals(video.textTracks, video.textTracks);
-    assert_equals(video.textTracks.length, 0);
-});
-
-</script>
\ No newline at end of file