diff --git a/DEPS b/DEPS
index e7f9cd5..dd8d2d5 100644
--- a/DEPS
+++ b/DEPS
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '4f34c64914be17966f2d91591921dec635582061',
+  'pdfium_revision': '3db875920a253a8541642a2aa913f474b125d67f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
diff --git a/android_webview/browser/aw_safe_browsing_resource_throttle.cc b/android_webview/browser/aw_safe_browsing_resource_throttle.cc
index 99b122da..bdde48d3 100644
--- a/android_webview/browser/aw_safe_browsing_resource_throttle.cc
+++ b/android_webview/browser/aw_safe_browsing_resource_throttle.cc
@@ -51,4 +51,17 @@
   Cancel();
 }
 
+void AwSafeBrowsingResourceThrottle::OnCheckBrowseUrlResult(
+    const GURL& url,
+    SBThreatType threat_type,
+    const ThreatMetadata& metadata) {
+  if (threat_type != safe_browsing::SB_THREAT_TYPE_URL_PHISHING &&
+      threat_type != safe_browsing::SB_THREAT_TYPE_URL_MALWARE) {
+    // If we don't recognize the threat type, just mark it as safe
+    threat_type = safe_browsing::SB_THREAT_TYPE_SAFE;
+  }
+
+  BaseResourceThrottle::OnCheckBrowseUrlResult(url, threat_type, metadata);
+}
+
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_safe_browsing_resource_throttle.h b/android_webview/browser/aw_safe_browsing_resource_throttle.h
index ea3f55b..5991c84bb 100644
--- a/android_webview/browser/aw_safe_browsing_resource_throttle.h
+++ b/android_webview/browser/aw_safe_browsing_resource_throttle.h
@@ -16,6 +16,9 @@
 class URLRequest;
 }
 
+using safe_browsing::ThreatMetadata;
+using safe_browsing::SBThreatType;
+
 namespace android_webview {
 
 class AwSafeBrowsingResourceThrottle
@@ -32,6 +35,10 @@
 
   static const void* kUserDataKey;
 
+  void OnCheckBrowseUrlResult(const GURL& url,
+                              SBThreatType threat_type,
+                              const ThreatMetadata& metadata) override;
+
  private:
   AwSafeBrowsingResourceThrottle(
       net::URLRequest* request,
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
index cb9c5ef2..21e32499 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
@@ -60,9 +60,12 @@
     // A blank green page
     private static final String GREEN_HTML_PATH = RESOURCE_PATH + "/green.html";
 
-    // Two blank blue pages, one which we treat as a malicious page
+    // Blank blue pages
     private static final String SAFE_HTML_PATH = RESOURCE_PATH + "/safe.html";
+    private static final String PHISHING_HTML_PATH = RESOURCE_PATH + "/phishing.html";
     private static final String MALWARE_HTML_PATH = RESOURCE_PATH + "/malware.html";
+    private static final String UNWANTED_SOFTWARE_HTML_PATH =
+            RESOURCE_PATH + "/unwanted_software.html";
 
     // A gray page with an iframe to MALWARE_HTML_PATH
     private static final String IFRAME_HTML_PATH = RESOURCE_PATH + "/iframe.html";
@@ -76,7 +79,10 @@
     public static class MockSafeBrowsingApiHandler implements SafeBrowsingApiHandler {
         private Observer mObserver;
         private static final String SAFE_METADATA = "{}";
-        private static final String MALWARE_METADATA = "{\"matches\":[{\"threat_type\":\"5\"}]}";
+        private static final String PHISHING_METADATA = "{\"matches\":[{\"threat_type\":\"5\"}]}";
+        private static final String MALWARE_METADATA = "{\"matches\":[{\"threat_type\":\"4\"}]}";
+        private static final String UNWANTED_SOFTWARE_METADATA =
+                "{\"matches\":[{\"threat_type\":\"3\"}]}";
 
         @Override
         public boolean init(Context context, Observer result) {
@@ -86,20 +92,24 @@
 
         @Override
         public void startUriLookup(final long callbackId, String uri, int[] threatsOfInterest) {
-            final int resultStatus = STATUS_SUCCESS;
-            final String metadata = isMaliciousUrl(uri) ? MALWARE_METADATA : SAFE_METADATA;
+            final String metadata;
+            if (uri.endsWith(PHISHING_HTML_PATH)) {
+                metadata = PHISHING_METADATA;
+            } else if (uri.endsWith(MALWARE_HTML_PATH)) {
+                metadata = MALWARE_METADATA;
+            } else if (uri.endsWith(UNWANTED_SOFTWARE_HTML_PATH)) {
+                metadata = UNWANTED_SOFTWARE_METADATA;
+            } else {
+                metadata = SAFE_METADATA;
+            }
 
             ThreadUtils.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
-                    mObserver.onUrlCheckDone(callbackId, resultStatus, metadata);
+                    mObserver.onUrlCheckDone(callbackId, STATUS_SUCCESS, metadata);
                 }
             });
         }
-
-        private static boolean isMaliciousUrl(String uri) {
-            return uri.endsWith(MALWARE_HTML_PATH);
-        }
     }
 
     /**
@@ -269,6 +279,41 @@
     @SmallTest
     @Feature({"AndroidWebView"})
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingDoesNotBlockUnwantedSoftwarePages() throws Throwable {
+        // TODO(ntfschr): this is a temporary check until we add support for Unwanted Software
+        // warnings
+        loadGreenPage();
+        final String responseUrl = mTestServer.getURL(UNWANTED_SOFTWARE_HTML_PATH);
+        loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), responseUrl);
+        waitForVisualStateCallback(mAwContents);
+        assertEquals("Target page should be visible", MALWARE_PAGE_BACKGROUND_COLOR,
+                GraphicsTestUtils.getPixelColorAtCenterOfView(mAwContents, mContainerView));
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingBlocksPhishingPages() throws Throwable {
+        loadGreenPage();
+        int count = mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
+        final String responseUrl = mTestServer.getURL(PHISHING_HTML_PATH);
+        loadUrlAsync(mAwContents, responseUrl);
+        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(count);
+        assertTrue("Original page should not be showing",
+                GREEN_PAGE_BACKGROUND_COLOR
+                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
+                                   mAwContents, mContainerView));
+        assertTrue("Target page should not be visible",
+                MALWARE_PAGE_BACKGROUND_COLOR
+                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
+                                   mAwContents, mContainerView));
+        // Assume that we are rendering the interstitial, since we see neither the previous page nor
+        // the target page
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingShowsInterstitialForMainFrame() throws Throwable {
         loadGreenPage();
         int count = mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
@@ -479,4 +524,24 @@
                         != GraphicsTestUtils.getPixelColorAtCenterOfView(
                                    mAwContents, mContainerView));
     }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingCanShowQuietPhishingInterstitial() throws Throwable {
+        mAwContents.setCanShowBigInterstitial(false);
+        loadGreenPage();
+        int count = mWebContentsObserver.getAttachedInterstitialPageHelper().getCallCount();
+        final String responseUrl = mTestServer.getURL(PHISHING_HTML_PATH);
+        loadUrlAsync(mAwContents, responseUrl);
+        mWebContentsObserver.getAttachedInterstitialPageHelper().waitForCallback(count);
+        assertTrue("Original page should not be showing",
+                GREEN_PAGE_BACKGROUND_COLOR
+                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
+                                   mAwContents, mContainerView));
+        assertTrue("Target page should not be visible",
+                MALWARE_PAGE_BACKGROUND_COLOR
+                        != GraphicsTestUtils.getPixelColorAtCenterOfView(
+                                   mAwContents, mContainerView));
+    }
 }
diff --git a/android_webview/test/data/phishing.html b/android_webview/test/data/phishing.html
new file mode 100644
index 0000000..ba2a808
--- /dev/null
+++ b/android_webview/test/data/phishing.html
@@ -0,0 +1,14 @@
+<html>
+  <head>
+    <style>
+      div {
+        background-color: rgb(0,0,255);
+        height: 100%;
+        width: 100%;
+      }
+    </style>
+  </head>
+  <body>
+    <div></div>
+  </body>
+</html>
diff --git a/android_webview/test/data/unwanted_software.html b/android_webview/test/data/unwanted_software.html
new file mode 100644
index 0000000..ba2a808
--- /dev/null
+++ b/android_webview/test/data/unwanted_software.html
@@ -0,0 +1,14 @@
+<html>
+  <head>
+    <style>
+      div {
+        background-color: rgb(0,0,255);
+        height: 100%;
+        width: 100%;
+      }
+    </style>
+  </head>
+  <body>
+    <div></div>
+  </body>
+</html>
diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc
index 402a072..e629cc2 100644
--- a/base/files/file_enumerator_win.cc
+++ b/base/files/file_enumerator_win.cc
@@ -9,7 +9,6 @@
 
 #include "base/logging.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/win/windows_version.h"
 
 namespace base {
 
@@ -102,18 +101,14 @@
       else
         src = src.Append(pattern_);
 
-      if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
-        // Use a "large fetch" on newer Windows which should speed up large
-        // enumerations (we seldom abort in the middle).
-        find_handle_ = FindFirstFileEx(src.value().c_str(),
-                                       FindExInfoBasic,  // Omit short name.
-                                       &find_data_,
-                                       FindExSearchNameMatch,
-                                       NULL,
-                                       FIND_FIRST_EX_LARGE_FETCH);
-      } else {
-        find_handle_ = FindFirstFile(src.value().c_str(), &find_data_);
-      }
+      // Use a "large fetch" which should speed up large enumerations (we seldom
+      // abort in the middle).
+      find_handle_ = FindFirstFileEx(src.value().c_str(),
+                                     FindExInfoBasic,  // Omit short name.
+                                     &find_data_,
+                                     FindExSearchNameMatch,
+                                     NULL,
+                                     FIND_FIRST_EX_LARGE_FETCH);
       has_find_data_ = true;
     } else {
       // Search for the next file/directory.
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc
index d86bc0f..ad3334a 100644
--- a/base/path_service_unittest.cc
+++ b/base/path_service_unittest.cc
@@ -42,13 +42,6 @@
   if (dir_type == DIR_USER_DESKTOP)
     check_path_exists = false;
 #endif
-#if defined(OS_WIN)
-  if (dir_type == DIR_TASKBAR_PINS) {
-    // There is no pinned-to-taskbar shortcuts prior to Win7.
-    if (base::win::GetVersion() < base::win::VERSION_WIN7)
-      check_path_exists = false;
-  }
-#endif
 #if defined(OS_MACOSX)
   if (dir_type != DIR_EXE && dir_type != DIR_MODULE &&
       dir_type != FILE_EXE && dir_type != FILE_MODULE) {
diff --git a/base/sequence_checker.h b/base/sequence_checker.h
index db0de45..f5014f9 100644
--- a/base/sequence_checker.h
+++ b/base/sequence_checker.h
@@ -37,7 +37,7 @@
 //       // otherwise knows usage on the associated sequence is done. If you're
 //       // not detaching in the constructor, you probably want to explicitly
 //       // check in the destructor.
-//       DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_);
+//       DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
 //     }
 //     void MyMethod() {
 //       DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
diff --git a/base/test/test_shortcut_win.cc b/base/test/test_shortcut_win.cc
index 25dc372..196cee9 100644
--- a/base/test/test_shortcut_win.cc
+++ b/base/test/test_shortcut_win.cc
@@ -14,7 +14,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_propvariant.h"
-#include "base/win/windows_version.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -113,44 +112,42 @@
     EXPECT_EQ(properties.icon_index, read_icon_index);
   }
 
-  if (GetVersion() >= VERSION_WIN7) {
-    ScopedComPtr<IPropertyStore> property_store;
-    EXPECT_TRUE(
-        SUCCEEDED(hr = i_shell_link.CopyTo(property_store.GetAddressOf())));
-    if (FAILED(hr))
-      return;
+  ScopedComPtr<IPropertyStore> property_store;
+  EXPECT_TRUE(
+      SUCCEEDED(hr = i_shell_link.CopyTo(property_store.GetAddressOf())));
+  if (FAILED(hr))
+    return;
 
-    if (properties.options & ShortcutProperties::PROPERTIES_APP_ID) {
-      ScopedPropVariant pv_app_id;
-      EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_ID,
-                                               pv_app_id.Receive()));
-      switch (pv_app_id.get().vt) {
-        case VT_EMPTY:
-          EXPECT_TRUE(properties.app_id.empty());
-          break;
-        case VT_LPWSTR:
-          EXPECT_EQ(properties.app_id, pv_app_id.get().pwszVal);
-          break;
-        default:
-          ADD_FAILURE() << "Unexpected variant type: " << pv_app_id.get().vt;
-      }
+  if (properties.options & ShortcutProperties::PROPERTIES_APP_ID) {
+    ScopedPropVariant pv_app_id;
+    EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_ID,
+                                             pv_app_id.Receive()));
+    switch (pv_app_id.get().vt) {
+      case VT_EMPTY:
+        EXPECT_TRUE(properties.app_id.empty());
+        break;
+      case VT_LPWSTR:
+        EXPECT_EQ(properties.app_id, pv_app_id.get().pwszVal);
+        break;
+      default:
+        ADD_FAILURE() << "Unexpected variant type: " << pv_app_id.get().vt;
     }
+  }
 
-    if (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) {
-      ScopedPropVariant pv_dual_mode;
-      EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_IsDualMode,
-                                               pv_dual_mode.Receive()));
-      switch (pv_dual_mode.get().vt) {
-        case VT_EMPTY:
-          EXPECT_FALSE(properties.dual_mode);
-          break;
-        case VT_BOOL:
-          EXPECT_EQ(properties.dual_mode,
-                    static_cast<bool>(pv_dual_mode.get().boolVal));
-          break;
-        default:
-          ADD_FAILURE() << "Unexpected variant type: " << pv_dual_mode.get().vt;
-      }
+  if (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) {
+    ScopedPropVariant pv_dual_mode;
+    EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_IsDualMode,
+                                             pv_dual_mode.Receive()));
+    switch (pv_dual_mode.get().vt) {
+      case VT_EMPTY:
+        EXPECT_FALSE(properties.dual_mode);
+        break;
+      case VT_BOOL:
+        EXPECT_EQ(properties.dual_mode,
+                  static_cast<bool>(pv_dual_mode.get().boolVal));
+        break;
+      default:
+        ADD_FAILURE() << "Unexpected variant type: " << pv_dual_mode.get().vt;
     }
   }
 }
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
index 8cabf38..95adfce0 100644
--- a/base/win/shortcut.cc
+++ b/base/win/shortcut.cc
@@ -137,8 +137,7 @@
       (properties.options & ShortcutProperties::PROPERTIES_APP_ID) != 0;
   bool has_dual_mode =
       (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) != 0;
-  if ((has_app_id || has_dual_mode) &&
-      GetVersion() >= VERSION_WIN7) {
+  if (has_app_id || has_dual_mode) {
     ScopedComPtr<IPropertyStore> property_store;
     if (FAILED(i_shell_link.CopyTo(property_store.GetAddressOf())) ||
         !property_store.Get())
@@ -248,9 +247,7 @@
     properties->set_icon(FilePath(temp), temp_index);
   }
 
-  // Windows 7+ options, avoiding unnecessary work.
-  if ((options & ShortcutProperties::PROPERTIES_WIN7) &&
-      GetVersion() >= VERSION_WIN7) {
+  if (options & ShortcutProperties::PROPERTIES_WIN7) {
     ScopedComPtr<IPropertyStore> property_store;
     if (FAILED(i_shell_link.CopyTo(property_store.GetAddressOf())))
       return false;
@@ -319,9 +316,8 @@
 }
 
 bool CanPinShortcutToTaskbar() {
-  // "Pin to taskbar" appeared in Windows 7 and stopped being supported in
-  // Windows 10.
-  return GetVersion() >= VERSION_WIN7 && GetVersion() < VERSION_WIN10;
+  // "Pin to taskbar" stopped being supported in Windows 10.
+  return GetVersion() < VERSION_WIN10;
 }
 
 bool PinShortcutToTaskbar(const FilePath& shortcut) {
@@ -336,11 +332,6 @@
 bool UnpinShortcutFromTaskbar(const FilePath& shortcut) {
   base::ThreadRestrictions::AssertIOAllowed();
 
-  // "Unpin from taskbar" is only supported after Win7. It is possible to remove
-  // a shortcut pinned by a user on Windows 10+.
-  if (GetVersion() < VERSION_WIN7)
-    return false;
-
   intptr_t result = reinterpret_cast<intptr_t>(ShellExecute(
       NULL, L"taskbarunpin", shortcut.value().c_str(), NULL, NULL, 0));
   return result > 32;
diff --git a/base/win/shortcut.h b/base/win/shortcut.h
index c48ec12..3cd70fc9 100644
--- a/base/win/shortcut.h
+++ b/base/win/shortcut.h
@@ -46,6 +46,8 @@
         PROPERTIES_ARGUMENTS |
         PROPERTIES_DESCRIPTION |
         PROPERTIES_ICON,
+    // TODO(pmonette): Get rid of PROPERTIES_WIN7 now that Windows 7 is the last
+    // supported Windows version.
     PROPERTIES_WIN7 = PROPERTIES_APP_ID | PROPERTIES_DUAL_MODE,
     PROPERTIES_ALL = PROPERTIES_BASIC | PROPERTIES_WIN7
   };
diff --git a/base/win/shortcut_unittest.cc b/base/win/shortcut_unittest.cc
index 1bb6325..b1d9345 100644
--- a/base/win/shortcut_unittest.cc
+++ b/base/win/shortcut_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/test/test_file_util.h"
 #include "base/test/test_shortcut_win.h"
 #include "base/win/scoped_com_initializer.h"
-#include "base/win/windows_version.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -84,8 +83,7 @@
 
 TEST_F(ShortcutTest, CreateAndResolveShortcutProperties) {
   uint32_t valid_properties = ShortcutProperties::PROPERTIES_BASIC;
-  if (GetVersion() >= VERSION_WIN7)
-    valid_properties |= ShortcutProperties::PROPERTIES_WIN7;
+  valid_properties |= ShortcutProperties::PROPERTIES_WIN7;
 
   // Test all properties.
   FilePath file_1(temp_dir_.GetPath().Append(L"Link1.lnk"));
@@ -103,10 +101,8 @@
   EXPECT_EQ(link_properties_.description, properties_read_1.description);
   ValidatePathsAreEqual(link_properties_.icon, properties_read_1.icon);
   EXPECT_EQ(link_properties_.icon_index, properties_read_1.icon_index);
-  if (GetVersion() >= VERSION_WIN7) {
-    EXPECT_EQ(link_properties_.app_id, properties_read_1.app_id);
-    EXPECT_EQ(link_properties_.dual_mode, properties_read_1.dual_mode);
-  }
+  EXPECT_EQ(link_properties_.app_id, properties_read_1.app_id);
+  EXPECT_EQ(link_properties_.dual_mode, properties_read_1.dual_mode);
 
   // Test simple shortcut with no special properties set.
   FilePath file_2(temp_dir_.GetPath().Append(L"Link2.lnk"));
@@ -126,10 +122,8 @@
   EXPECT_EQ(L"", properties_read_2.description);
   ValidatePathsAreEqual(FilePath(), properties_read_2.icon);
   EXPECT_EQ(0, properties_read_2.icon_index);
-  if (GetVersion() >= VERSION_WIN7) {
-    EXPECT_EQ(L"", properties_read_2.app_id);
-    EXPECT_FALSE(properties_read_2.dual_mode);
-  }
+  EXPECT_EQ(L"", properties_read_2.app_id);
+  EXPECT_FALSE(properties_read_2.dual_mode);
 }
 
 TEST_F(ShortcutTest, CreateAndResolveShortcut) {
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 1d01970..3f0cfaf 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -3892,27 +3892,24 @@
     Wi-Fi
   </message>
   <message name="IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR" desc="Label for a cellular network device.">
-    Mobile Data
+    Mobile data
   </message>
-  <message name="IDS_NETWORK_TYPE_ETHERNET" desc="The ethernet network type.">
+  <message name="IDS_NETWORK_TYPE_ETHERNET" desc="Label for Ethernet networks.">
     Ethernet
   </message>
-  <message name="IDS_NETWORK_TYPE_TETHER" desc="The Tether network type.">
-    Tether
-  </message>
-  <message name="IDS_NETWORK_TYPE_WIFI" desc="The wifi network type.">
+  <message name="IDS_NETWORK_TYPE_WIFI" desc="Label for WiFi networks.">
     Wi-Fi
   </message>
-  <message name="IDS_NETWORK_TYPE_WIMAX" desc="The wimax network type.">
+  <message name="IDS_NETWORK_TYPE_WIMAX" desc="Label for WiMAX networks.">
     WiMAX
   </message>
-  <message name="IDS_NETWORK_TYPE_BLUETOOTH" desc="The bluetooth network type.">
+  <message name="IDS_NETWORK_TYPE_BLUETOOTH" desc="Label for Bluetooth networks.">
     Bluetooth
   </message>
-  <message name="IDS_NETWORK_TYPE_CELLULAR" desc="The cellular network type.">
-    Mobile
+  <message name="IDS_NETWORK_TYPE_MOBILE_DATA" desc="Label for Cellular and Tether networks.">
+    Mobile data
   </message>
-  <message name="IDS_NETWORK_TYPE_VPN" desc="The vpn network type.">
+  <message name="IDS_NETWORK_TYPE_VPN" desc="Label for VPN networks.">
     VPN
   </message>
   <message name="IDS_NETWORK_TYPE_VPN_BUILTIN" desc="The built-in VPN types (Open VPN and L2TP/IPSec).">
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 4a089ca..e237d90 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -549,7 +549,7 @@
     <message name="IDS_SETTINGS_BLUETOOTH_NO_DEVICES_FOUND" desc="Message displayed when no Bluetooth devices are found after a scan.">
       No Bluetooth devices found
     </message>
-    <message name="IDS_SETTINGS_BLUETOOTH_TOGGLE_ACCESSIBILITY_LABEL" desc="Accessibility only label for Bluetooth enable/disable toggle .">
+    <message name="IDS_SETTINGS_BLUETOOTH_TOGGLE_ACCESSIBILITY_LABEL" desc="Accessibility only label for Bluetooth enable/disable toggle.">
       Bluetooth enable
     </message>
     <message name="IDS_SETTINGS_BLUETOOTH_EXPAND_ACCESSIBILITY_LABEL" desc="Label for the button that toggles showing available Bluetooth devices. Only visible by screen reader software.">
@@ -1372,8 +1372,11 @@
     <message name="IDS_SETTINGS_INTERNET_TETHER_CONNECTION_CONNECT_BUTTON" desc="Settings > Internet > Tether Connection Dialog > Button which, when tapped, starts a connection attempt to the device.">
       Connect
     </message>
-    <message name="IDS_SETTINGS_INTERNET_TOGGLE_TETHER_ACCESSIBILITY_LABEL" desc="Accessibility only label for tether enable/disable toggle .">
-      Tether enable
+    <message name="IDS_SETTINGS_INTERNET_TOGGLE_TETHER_LABEL" desc="Settings > Internet: Label for Tether enable/disable toggle .">
+      Get data connection
+    </message>
+    <message name="IDS_SETTINGS_INTERNET_TOGGLE_TETHER_SUBTEXT" desc="Settings > Internet: Description for Tether enable/disable toggle .">
+      Let this device find other devices with your Google Account that have a cellular data connection
     </message>
     <message name="IDS_SETTINGS_INTERNET_TOGGLE_MOBILE_ACCESSIBILITY_LABEL" desc="Accessibility only label for mobile data enable/disable toggle .">
       Mobile data enable
diff --git a/chrome/browser/chromeos/tether/tether_service.cc b/chrome/browser/chromeos/tether/tether_service.cc
index 797e978..9f1dc31 100644
--- a/chrome/browser/chromeos/tether/tether_service.cc
+++ b/chrome/browser/chromeos/tether/tether_service.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/net/tether_notification_presenter.h"
 #include "chrome/browser/chromeos/tether/tether_service_factory.h"
 #include "chrome/browser/cryptauth/chrome_cryptauth_service_factory.h"
@@ -69,9 +70,14 @@
                  base::Bind(&TetherService::OnPrefsChanged,
                             weak_ptr_factory_.GetWeakPtr()));
 
-  device::BluetoothAdapterFactory::GetAdapter(
-      base::Bind(&TetherService::OnBluetoothAdapterFetched,
-                 weak_ptr_factory_.GetWeakPtr()));
+  // GetAdapter may call OnBluetoothAdapterFetched immediately which can cause
+  // problems with the Fake implementation since the class is not fully
+  // constructed yet. Post the GetAdapter call to avoid this.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(device::BluetoothAdapterFactory::GetAdapter,
+                 base::Bind(&TetherService::OnBluetoothAdapterFetched,
+                            weak_ptr_factory_.GetWeakPtr())));
 }
 
 TetherService::~TetherService() {}
@@ -230,6 +236,8 @@
 
 void TetherService::OnBluetoothAdapterFetched(
     scoped_refptr<device::BluetoothAdapter> adapter) {
+  if (shut_down_)
+    return;
   adapter_ = adapter;
   adapter_->AddObserver(this);
   UpdateTetherTechnologyState();
diff --git a/chrome/browser/chromeos/tether/tether_service_unittest.cc b/chrome/browser/chromeos/tether/tether_service_unittest.cc
index 2c5c8e6..8fc262b 100644
--- a/chrome/browser/chromeos/tether/tether_service_unittest.cc
+++ b/chrome/browser/chromeos/tether/tether_service_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
@@ -146,6 +147,7 @@
         profile_.get(), fake_power_manager_client_.get(),
         fake_session_manager_client_.get(), fake_cryptauth_service_.get(),
         network_state_handler()));
+    base::RunLoop().RunUntilIdle();
   }
 
   void ShutdownTetherService() {
@@ -240,7 +242,8 @@
       chromeos::switches::kEnableTether);
 
   TetherService* tether_service = TetherService::Get(profile_.get());
-  EXPECT_TRUE(tether_service);
+  ASSERT_TRUE(tether_service);
+  base::RunLoop().RunUntilIdle();
   tether_service->Shutdown();
 }
 
@@ -307,18 +310,19 @@
 // state than the user preference.
 TEST_F(TetherServiceTest, TestEnabledMultipleChanges) {
   CreateTetherService();
-
-  EXPECT_EQ(0, tether_service_->updated_technology_state_count());
-
-  SetTetherTechnologyStateEnabled(false);
-  SetTetherTechnologyStateEnabled(false);
-  SetTetherTechnologyStateEnabled(false);
-
+  // CreateTetherService calls RunUntilIdle() so OnBluetoothAdapterFetched()
+  // will have been called which calls UpdateTetherTechnologyState().
   EXPECT_EQ(1, tether_service_->updated_technology_state_count());
 
+  SetTetherTechnologyStateEnabled(false);
+  SetTetherTechnologyStateEnabled(false);
+  SetTetherTechnologyStateEnabled(false);
+
+  EXPECT_EQ(2, tether_service_->updated_technology_state_count());
+
   SetTetherTechnologyStateEnabled(true);
   SetTetherTechnologyStateEnabled(true);
   SetTetherTechnologyStateEnabled(true);
 
-  EXPECT_EQ(2, tether_service_->updated_technology_state_count());
+  EXPECT_EQ(3, tether_service_->updated_technology_state_count());
 }
diff --git a/chrome/browser/download/download_status_updater_win.cc b/chrome/browser/download/download_status_updater_win.cc
index 93a36f00..6f6b3d7 100644
--- a/chrome/browser/download/download_status_updater_win.cc
+++ b/chrome/browser/download/download_status_updater_win.cc
@@ -10,7 +10,6 @@
 
 #include "base/logging.h"
 #include "base/win/scoped_comptr.h"
-#include "base/win/windows_version.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -21,10 +20,6 @@
 void UpdateTaskbarProgressBar(int download_count,
                               bool progress_known,
                               float progress) {
-  // Taskbar progress bar is only supported on Win7.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::win::ScopedComPtr<ITaskbarList3> taskbar;
   HRESULT result = ::CoCreateInstance(
       CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&taskbar));
diff --git a/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc b/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
index 894f45e..cf50555 100644
--- a/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
@@ -662,9 +662,9 @@
 void MAYBE_WebRtcAudioQualityBrowserTest::TestWithFakeDeviceGetUserMedia(
     const std::string& constraints,
     const std::string& perf_modifier) {
-  if (OnWin8()) {
+  if (OnWin8OrHigher()) {
     // http://crbug.com/379798.
-    LOG(ERROR) << "This test is not implemented for Windows XP/Win8.";
+    LOG(ERROR) << "This test is not implemented for Win8 or higher.";
     return;
   }
 
@@ -689,9 +689,9 @@
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
                        MANUAL_TestCallQualityWithAudioFromWebAudio) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  if (OnWin8()) {
+  if (OnWin8OrHigher()) {
     // http://crbug.com/379798.
-    LOG(ERROR) << "This test is not implemented for Windows XP/Win8.";
+    LOG(ERROR) << "This test is not implemented for Win8 or higher.";
     return;
   }
   ASSERT_TRUE(test::HasReferenceFilesInCheckout());
@@ -764,9 +764,9 @@
     const base::FilePath::StringType& reference_filename,
     const std::string& constraints,
     const std::string& perf_modifier) {
-  if (OnWin8()) {
+  if (OnWin8OrHigher()) {
     // http://crbug.com/379798.
-    LOG(ERROR) << "This test is not implemented for Windows XP/Win8.";
+    LOG(ERROR) << "This test is not implemented for Win8 or higher.";
     return;
   }
   base::FilePath reference_file =
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
index 562ca64..e258eb2 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
@@ -461,9 +461,9 @@
   return result.substr(3);
 }
 
-bool WebRtcTestBase::OnWin8() const {
+bool WebRtcTestBase::OnWin8OrHigher() const {
 #if defined(OS_WIN)
-  return base::win::GetVersion() > base::win::VERSION_WIN7;
+  return base::win::GetVersion() >= base::win::VERSION_WIN8;
 #else
   return false;
 #endif
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.h b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
index 4e1b150..5546ec8 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.h
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
@@ -158,8 +158,8 @@
   std::string GetStreamSize(content::WebContents* tab_contents,
                             const std::string& video_element) const;
 
-  // Returns true if we're on win 8.
-  bool OnWin8() const;
+  // Returns true if we're on Windows 8 or higher.
+  bool OnWin8OrHigher() const;
 
   void OpenDatabase(content::WebContents* tab) const;
   void CloseDatabase(content::WebContents* tab) const;
diff --git a/chrome/browser/notifications/platform_notification_service_unittest.cc b/chrome/browser/notifications/platform_notification_service_unittest.cc
index 7e34a6b0..c51c1e8 100644
--- a/chrome/browser/notifications/platform_notification_service_unittest.cc
+++ b/chrome/browser/notifications/platform_notification_service_unittest.cc
@@ -185,6 +185,10 @@
 
 // Native, non persistent notifications don't have delegates any more
 #if !defined(OS_MACOSX)
+#if defined(OS_ANDROID)
+// http://crbug.com/729247
+#define DisplayPageDisplayedEvent DISABLED_DisplayPageDisplayedEvent
+#endif
 TEST_F(PlatformNotificationServiceTest, DisplayPageDisplayedEvent) {
   auto* delegate = CreateSimplePageNotification();
 
diff --git a/chrome/browser/password_manager/password_manager_util_win.cc b/chrome/browser/password_manager/password_manager_util_win.cc
index 01dd5c2..c883e8f 100644
--- a/chrome/browser/password_manager/password_manager_util_win.cc
+++ b/chrome/browser/password_manager/password_manager_util_win.cc
@@ -25,7 +25,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/time/time.h"
-#include "base/win/windows_version.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/grit/chromium_strings.h"
 #include "components/password_manager/core/browser/password_manager.h"
@@ -178,10 +177,7 @@
     *status = PASSWORD_STATUS_WIN_DOMAIN;
   } else {
     username_length = CREDUI_MAX_USERNAME_LENGTH;
-    // CheckBlankPasswordWithPrefs() isn't safe to call on before Windows 7.
-    // http://crbug.com/345916
-    if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
-        GetUserName(username, &username_length)) {
+    if (GetUserName(username, &username_length)) {
       *status = CheckBlankPasswordWithPrefs(username, prefs) ?
           PASSWORD_STATUS_BLANK :
           PASSWORD_STATUS_NONBLANK;
diff --git a/chrome/browser/prefs/incognito_mode_prefs.cc b/chrome/browser/prefs/incognito_mode_prefs.cc
index b5324b3..d00d33a7 100644
--- a/chrome/browser/prefs/incognito_mode_prefs.cc
+++ b/chrome/browser/prefs/incognito_mode_prefs.cc
@@ -29,7 +29,6 @@
 #include "base/bind_helpers.h"
 #include "base/memory/singleton.h"
 #include "base/win/scoped_comptr.h"
-#include "base/win/windows_version.h"
 #endif  // OS_WIN
 
 #if defined(OS_ANDROID)
@@ -77,10 +76,6 @@
     // Since we can potentially block, make sure the thread is okay with this.
     base::ThreadRestrictions::AssertIOAllowed();
 
-    // Query this info on Windows 7 and above.
-    if (base::win::GetVersion() < base::win::VERSION_WIN7)
-      return false;
-
     ThreadType thread_type = ThreadType::BLOCKING;
     if (BrowserThread::IsThreadInitialized(BrowserThread::UI) &&
         content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js
index 2092704..eac0e4eb6 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -113,6 +113,7 @@
     CrOncStrings = {
       OncTypeCellular: loadTimeData.getString('OncTypeCellular'),
       OncTypeEthernet: loadTimeData.getString('OncTypeEthernet'),
+      OncTypeTether: loadTimeData.getString('OncTypeTether'),
       OncTypeVPN: loadTimeData.getString('OncTypeVPN'),
       OncTypeWiFi: loadTimeData.getString('OncTypeWiFi'),
       OncTypeWiMAX: loadTimeData.getString('OncTypeWiMAX'),
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.html b/chrome/browser/resources/settings/internet_page/internet_page.html
index 4771c26..82c766ca 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_page.html
@@ -113,7 +113,8 @@
             show-spinner="[[showSpinner_]]">
           <settings-internet-subpage 
               default-network="[[defaultNetwork]]"
-              device-state="[[get(subpageType_, deviceStates)]]"
+              device-state="[[getDeviceState_(subpageType_, deviceStates)]]"
+              tether-device-state="[[get('Tether', deviceStates)]]"
               global-policy="[[globalPolicy_]]"
               third-party-vpn-providers="[[thirdPartyVpnProviders_]]"
               networking-private="[[networkingPrivate]]"
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.js b/chrome/browser/resources/settings/internet_page/internet_page.js
index 45d9bee3..7a96a04 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_page.js
@@ -276,6 +276,22 @@
   },
 
   /**
+   * @param {string} subpageType
+   * @param {!Object<!CrOnc.DeviceStateProperties>|undefined} deviceStates
+   * @return {!CrOnc.DeviceStateProperties|undefined}
+   * @private
+   */
+  getDeviceState_: function(subpageType, deviceStates) {
+    // If both Tether and Cellular are enabled, use the Cellular device state
+    // when directly navigating to the Tether page.
+    if (subpageType == CrOnc.Type.TETHER &&
+        this.deviceStates[CrOnc.Type.CELLULAR]) {
+      subpageType = CrOnc.Type.CELLULAR;
+    }
+    return deviceStates[subpageType];
+  },
+
+  /**
    * @param {!{detail: {type: string}}} event
    * @private
    */
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.html b/chrome/browser/resources/settings/internet_page/internet_subpage.html
index e865ab9..9534330 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.html
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.html
@@ -60,10 +60,10 @@
             aria-label="$i18n{internetAddWiFi}"
             on-tap="onAddButtonTap_" tabindex$="[[tabindex]]">
         </paper-icon-button>
-        <paper-toggle-button  id="deviceEnabledButton"
+        <paper-toggle-button id="deviceEnabledButton"
             aria-label$="[[getToggleA11yString_(deviceState)]]"
             checked="[[deviceIsEnabled_(deviceState)]]"
-            enabled="[[enableToggleIsEnabled_(deviceState)]]"
+            disabled="[[!enableToggleIsEnabled_(deviceState)]]"
             on-tap="onDeviceEnabledTap_">
         </paper-toggle-button>
       </div>
@@ -124,6 +124,25 @@
         </template>
       </div>
 
+      <template is="dom-if"
+          if="[[tetherToggleIsVisible_(deviceState, tetherDeviceState)]]">
+        <div class="settings-box two-line" actionable
+            on-tap="onTetherEnabledTap_">
+          <div class="start">
+            $i18n{internetToggleTetherLabel}
+            <div id="tetherSecondary" class="secondary">
+              $i18n{internetToggleTetherSubtext}
+            </div>
+          </div>
+          <paper-toggle-button id="tetherEnabledButton"
+              aria-label="$i18n{internetToggleTetherLabel}"
+              aria-describedby="tetherSecondary"
+              checked="[[deviceIsEnabled_(tetherDeviceState)]]"
+              disabled="[[!tetherToggleIsEnabled_(deviceState,
+                  tetherDeviceState)]]">
+          </paper-toggle-button>
+        </div>
+      </template>
     </template>
 
   </template>
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.js b/chrome/browser/resources/settings/internet_page/internet_subpage.js
index 71ef109..7735898 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.js
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.js
@@ -25,11 +25,20 @@
     defaultNetwork: Object,
 
     /**
-     * Device state for the network type.
+     * Device state for the network type. Note: when both Cellular and Tether
+     * are available this will always be set to the Cellular device state and
+     * |tetherDeviceState| will be set to the Tether device state.
      * @type {!CrOnc.DeviceStateProperties|undefined}
      */
     deviceState: Object,
 
+    /**
+     * If both Cellular and Tether technologies exist, we combine the subpages
+     * and set this to the device state for Tether.
+     * @type {!CrOnc.DeviceStateProperties|undefined}
+     */
+    tetherDeviceState: Object,
+
     /** @type {!chrome.networkingPrivate.GlobalPolicy|undefined} */
     globalPolicy: Object,
 
@@ -171,15 +180,34 @@
       visible: true,
       configured: false
     };
-    this.networkingPrivate.getNetworks(filter, function(networkStates) {
-      if (!this.deviceState)
-        return;
-      if (this.deviceState.Type != CrOnc.Type.VPN) {
-        this.networkStateList_ = networkStates;
-        return;
-      }
-      // For VPNs, separate out third party VPNs.
-      var networkStateList = [];
+    this.networkingPrivate.getNetworks(filter, this.onGetNetworks_.bind(this));
+  },
+
+  /**
+   * @param {!Array<!CrOnc.NetworkStateProperties>} networkStates
+   * @private
+   */
+  onGetNetworks_: function(networkStates) {
+    if (!this.deviceState)
+      return;  // Edge case when device states change before this callback.
+
+    // For the Cellular/Mobile subpage, request Tether networks if available.
+    if (this.deviceState.Type == CrOnc.Type.CELLULAR &&
+        this.tetherDeviceState) {
+      var filter = {
+        networkType: CrOnc.Type.TETHER,
+        visible: true,
+        configured: false
+      };
+      this.networkingPrivate.getNetworks(filter, function(tetherNetworkStates) {
+        this.networkStateList_ = networkStates.concat(tetherNetworkStates);
+      }.bind(this));
+      return;
+    }
+
+    // For VPNs, separate out third party VPNs.
+    if (this.deviceState.Type == CrOnc.Type.VPN) {
+      var builtinNetworkStates = [];
       var thirdPartyVpns = {};
       for (var i = 0; i < networkStates.length; ++i) {
         var state = networkStates[i];
@@ -189,12 +217,14 @@
           thirdPartyVpns[providerType] = thirdPartyVpns[providerType] || [];
           thirdPartyVpns[providerType].push(state);
         } else {
-          networkStateList.push(state);
+          builtinNetworkStates.push(state);
         }
+        networkStates = builtinNetworkStates;
+        this.thirdPartyVpns_ = thirdPartyVpns;
       }
-      this.networkStateList_ = networkStateList;
-      this.thirdPartyVpns_ = thirdPartyVpns;
-    }.bind(this));
+    }
+
+    this.networkStateList_ = networkStates;
   },
 
   /**
@@ -246,7 +276,6 @@
       return '';
     switch (deviceState.Type) {
       case CrOnc.Type.TETHER:
-        return this.i18n('internetToggleTetherA11yLabel');
       case CrOnc.Type.CELLULAR:
         return this.i18n('internetToggleMobileA11yLabel');
       case CrOnc.Type.WI_FI:
@@ -405,6 +434,41 @@
   },
 
   /**
+   * @param {!CrOnc.DeviceStateProperties|undefined} deviceState
+   * @param {!CrOnc.DeviceStateProperties|undefined} tetherDeviceState
+   * @return {boolean}
+   * @private
+   */
+  tetherToggleIsVisible_: function(deviceState, tetherDeviceState) {
+    return !!deviceState && deviceState.Type == CrOnc.Type.CELLULAR &&
+        !!tetherDeviceState;
+  },
+
+  /**
+   * @param {!CrOnc.DeviceStateProperties|undefined} deviceState
+   * @param {!CrOnc.DeviceStateProperties|undefined} tetherDeviceState
+   * @return {boolean}
+   * @private
+   */
+  tetherToggleIsEnabled_: function(deviceState, tetherDeviceState) {
+    return this.tetherToggleIsVisible_(deviceState, tetherDeviceState) &&
+      this.enableToggleIsEnabled_(tetherDeviceState) &&
+      tetherDeviceState.State != CrOnc.DeviceState.UNINITIALIZED;
+  },
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
+  onTetherEnabledTap_: function(event) {
+    this.fire('device-enabled-toggled', {
+      enabled: !this.deviceIsEnabled_(this.tetherDeviceState),
+      type: CrOnc.Type.TETHER,
+    });
+    event.stopPropagation();
+  },
+
+  /**
    * @param {*} lhs
    * @param {*} rhs
    * @return {boolean}
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.html b/chrome/browser/resources/settings/internet_page/network_summary.html
index e46a5be1..315a1043 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary.html
@@ -12,7 +12,8 @@
             active-network-state="[[item]]"
             device-state="[[get(item.Type, deviceStates)]]"
             network-state-list="[[get(item.Type, networkStateLists_)]]"
-            networking-private="[[networkingPrivate]]">
+            networking-private="[[networkingPrivate]]"
+            tether-device-state="[[get('Tether', deviceStates)]]">
         </network-summary-item>
       </template>
     </div>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.js b/chrome/browser/resources/settings/internet_page/network_summary.js
index 3ef2ccb9a..b1e607f 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary.js
@@ -310,8 +310,21 @@
       var type = orderedDeviceTypes[i];
       var device = newDeviceStates[type];
       if (!device)
+        continue;  // The technology for this device type is unavailable.
+
+      // If both 'Tether' and 'Cellular' technoligies exist, merge the network
+      // lists and do not add an active network for 'Tether' so that there is
+      // only one 'Mobile data' section / subpage.
+      if (type == CrOnc.Type.TETHER && newDeviceStates[CrOnc.Type.CELLULAR]) {
+        newNetworkStateLists[CrOnc.Type.CELLULAR] =
+            newNetworkStateLists[CrOnc.Type.CELLULAR].concat(
+                newNetworkStateLists[CrOnc.Type.TETHER]);
         continue;
-      var state = activeNetworkStatesByType.get(type) || {GUID: '', Type: type};
+      }
+
+      // Note: The active state for 'Cellular' may be a Tether network if both
+      // types are enabled but no Cellular network exists (edge case).
+      var state = this.getActiveStateForType_(activeNetworkStatesByType, type);
       if (state.Source === undefined &&
           device.State == CrOnc.DeviceState.PROHIBITED) {
         // Prohibited technologies are enforced by the device policy.
@@ -326,4 +339,19 @@
     // Set activeNetworkStates last to rebuild the dom-repeat.
     this.activeNetworkStates_ = newActiveNetworkStates;
   },
+
+  /**
+   * Returns the active network state for |type| or a default network state.
+   * If there is no 'Cellular' network, return the active 'Tether' network if
+   * any since the two types are represented by the same section / subpage.
+   * @param {!Map<string, !CrOnc.NetworkStateProperties>} activeStatesByType
+   * @param {string} type
+   * @return {!CrOnc.NetworkStateProperties|undefined}
+   */
+  getActiveStateForType_: function(activeStatesByType, type) {
+    var activeState = activeStatesByType.get(type);
+    if (!activeState && type == CrOnc.Type.CELLULAR)
+      activeState = activeStatesByType.get(CrOnc.Type.TETHER);
+    return activeState || {GUID: '', Type: type};
+  },
 });
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html
index 6a0b7f3..b258d4ae 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -72,7 +72,7 @@
         <paper-toggle-button  id="deviceEnabledButton"
             aria-label$="[[getToggleA11yString_(deviceState)]]"
             checked="[[deviceIsEnabled_(deviceState)]]"
-            enabled="[[enableToggleIsEnabled_(deviceState)]]"
+            disabled="[[!enableToggleIsEnabled_(deviceState)]]"
             on-tap="onDeviceEnabledTap_">
         </paper-toggle-button>
       </template>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chrome/browser/resources/settings/internet_page/network_summary_item.js
index f688f05..2f59a79 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -4,7 +4,9 @@
 
 /**
  * @fileoverview Polymer element for displaying the network state for a specific
- * type and a list of networks for that type.
+ * type and a list of networks for that type. NOTE: It both Cellular and Tether
+ * technologies are available, they are combined into a single 'Mobile data'
+ * section. See crbug.com/726380.
  */
 
 Polymer({
@@ -21,6 +23,13 @@
     deviceState: Object,
 
     /**
+     * If both Cellular and Tether technologies exist, we combine the sections
+     * and set this to the device state for Tether.
+     * @type {!CrOnc.DeviceStateProperties|undefined}
+     */
+    tetherDeviceState: Object,
+
+    /**
      * Network state for the active network.
      * @type {!CrOnc.NetworkStateProperties|undefined}
      */
@@ -162,7 +171,9 @@
    */
   enableToggleIsVisible_: function(deviceState) {
     return !!deviceState && deviceState.Type != CrOnc.Type.ETHERNET &&
-        deviceState.Type != CrOnc.Type.VPN;
+        deviceState.Type != CrOnc.Type.VPN &&
+        (deviceState.Type == CrOnc.Type.TETHER ||
+         deviceState.State != CrOnc.DeviceState.UNINITIALIZED);
   },
 
   /**
@@ -171,7 +182,9 @@
    * @private
    */
   enableToggleIsEnabled_: function(deviceState) {
-    return !!deviceState && deviceState.State != CrOnc.DeviceState.PROHIBITED;
+    return this.enableToggleIsVisible_(deviceState) &&
+        deviceState.State != CrOnc.DeviceState.PROHIBITED &&
+        deviceState.State != CrOnc.DeviceState.UNINITIALIZED;
   },
 
   /**
@@ -184,7 +197,6 @@
       return '';
     switch (deviceState.Type) {
       case CrOnc.Type.TETHER:
-        return this.i18n('internetToggleTetherA11yLabel');
       case CrOnc.Type.CELLULAR:
         return this.i18n('internetToggleMobileA11yLabel');
       case CrOnc.Type.WI_FI:
@@ -219,9 +231,10 @@
     if (!deviceState)
       return false;
     var type = deviceState.Type;
-    var minlen = (deviceState.Type == CrOnc.Type.WI_FI ||
-                  deviceState.Type == CrOnc.Type.VPN ||
-                  deviceState.Type == CrOnc.Type.TETHER) ?
+    if (type == CrOnc.Type.CELLULAR && this.tetherDeviceState)
+      return true;
+    var minlen = (type == CrOnc.Type.WI_FI || type == CrOnc.Type.VPN ||
+                  type == CrOnc.Type.TETHER) ?
         1 :
         2;
     return networkStateList.length >= minlen;
@@ -233,9 +246,11 @@
    */
   onShowDetailsTap_: function(event) {
     if (!this.deviceIsEnabled_(this.deviceState)) {
-      this.fire(
-          'device-enabled-toggled',
-          {enabled: true, type: this.deviceState.Type});
+      if (this.enableToggleIsEnabled_(this.deviceState)) {
+        this.fire(
+            'device-enabled-toggled',
+            {enabled: true, type: this.deviceState.Type});
+      }
     } else if (this.shouldShowSubpage_(
                    this.deviceState, this.networkStateList)) {
       this.fire('show-networks', this.deviceState);
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
index 2b93e6e9..5288cc6 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
@@ -160,12 +160,12 @@
             <div class="expiration-column">
               <div id="creditCardExpiration"
                   class="expiration-date">[[expiration_(item)]]</div>
-              <template is="dom-if" if="[[item.metadata.isLocal]]">
+              <template is="dom-if" if="[[showDots_(item.metadata)]]">
                 <paper-icon-button id="creditCardMenu" icon="cr:more-vert"
                     on-tap="onCreditCardMenuTap_" title="$i18n{moreActions}">
                 </paper-icon-button>
               </template>
-              <template is="dom-if" if="[[!item.metadata.isLocal]]">
+              <template is="dom-if" if="[[!showDots_(item.metadata)]]">
                 <button is="paper-icon-button-light" class="icon-external"
                     on-tap="onRemoteEditCreditCardTap_" actionable></button>
               </template>
@@ -182,6 +182,7 @@
       <button id="menuEditCreditCard" class="dropdown-item"
           on-tap="onMenuEditCreditCardTap_">$i18n{edit}</button>
       <button id="menuRemoveCreditCard" class="dropdown-item"
+          hidden$="[[!activeCreditCard.metadata.isLocal]]"
           on-tap="onMenuRemoveCreditCardTap_">$i18n{removeCreditCard}</button>
       <button id="menuClearCreditCard" class="dropdown-item"
           on-tap="onMenuClearCreditCardTap_"
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
index eda4031..3cfa710 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
@@ -386,7 +386,12 @@
      */
     onMenuEditCreditCardTap_: function(e) {
       e.preventDefault();
-      this.showCreditCardDialog_ = true;
+
+      if (this.activeCreditCard.metadata.isLocal)
+        this.showCreditCardDialog_ = true;
+      else
+        this.onRemoteEditCreditCardTap_();
+
       this.$.creditCardSharedMenu.close();
     },
 
@@ -416,6 +421,16 @@
     },
 
     /**
+     * The 3-dot menu should not be shown if the card is entirely remote.
+     * @param {!chrome.autofillPrivate.AutofillMetadata} metadata
+     * @return {boolean}
+     * @private
+     */
+    showDots_: function(metadata) {
+      return !!(metadata.isLocal || metadata.isCached);
+    },
+
+    /**
      * Returns true if the list exists and has items.
      * @param {Array<Object>} list
      * @return {boolean}
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 707e8c82f..3b15d6d 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -108,8 +108,8 @@
 // <if expr="chromeos">
     CrOncStrings = {
       OncTypeCellular: loadTimeData.getString('OncTypeCellular'),
-      OncTypeTether: loadTimeData.getString('OncTypeTether'),
       OncTypeEthernet: loadTimeData.getString('OncTypeEthernet'),
+      OncTypeTether: loadTimeData.getString('OncTypeTether'),
       OncTypeVPN: loadTimeData.getString('OncTypeVPN'),
       OncTypeWiFi: loadTimeData.getString('OncTypeWiFi'),
       OncTypeWiMAX: loadTimeData.getString('OncTypeWiMAX'),
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index c8fc1ac..fb717d2 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -746,9 +746,6 @@
 }
 
 void MigrateTaskbarPins() {
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   // This needs to happen (e.g. so that the appid is fixed and the
   // run-time Chrome icon is merged with the taskbar shortcut), but it is not an
   // urgent task.
@@ -765,8 +762,6 @@
 
 int MigrateShortcutsInPathInternal(const base::FilePath& chrome_exe,
                                    const base::FilePath& path) {
-  DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN7);
-
   // Enumerate all pinned shortcuts in the given path directly.
   base::FileEnumerator shortcuts_enum(
       path, false,  // not recursive
diff --git a/chrome/browser/shell_integration_win_unittest.cc b/chrome/browser/shell_integration_win_unittest.cc
index 7276263..89596e7 100644
--- a/chrome/browser/shell_integration_win_unittest.cc
+++ b/chrome/browser/shell_integration_win_unittest.cc
@@ -17,7 +17,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_shortcut_win.h"
 #include "base/win/scoped_com_initializer.h"
-#include "base/win/windows_version.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths_internal.h"
@@ -257,9 +256,6 @@
 }  // namespace
 
 TEST_F(ShellIntegrationWinMigrateShortcutTest, ClearDualModeAndAdjustAppIds) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   // 9 shortcuts should have their app id updated below and shortcut 11 should
   // be migrated away from dual_mode for a total of 10 shortcuts migrated.
   EXPECT_EQ(10,
diff --git a/chrome/browser/ui/pdf/adobe_reader_info_win.cc b/chrome/browser/ui/pdf/adobe_reader_info_win.cc
index 16893f6..8b180af 100644
--- a/chrome/browser/ui/pdf/adobe_reader_info_win.cc
+++ b/chrome/browser/ui/pdf/adobe_reader_info_win.cc
@@ -18,7 +18,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/version.h"
 #include "base/win/registry.h"
-#include "base/win/windows_version.h"
 #include "chrome/browser/browser_process.h"
 
 namespace {
@@ -41,9 +40,8 @@
   base::FilePath filepath;
   base::win::RegKey hkcu_key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ);
   base::string16 path;
-  // As of Win7 AppPaths can also be registered in HKCU: http://goo.gl/UgFOf.
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
-      hkcu_key.ReadValue(kRegistryPath, &path) == ERROR_SUCCESS) {
+  // AppPaths can also be registered in HKCU: http://goo.gl/UgFOf.
+  if (hkcu_key.ReadValue(kRegistryPath, &path) == ERROR_SUCCESS) {
     filepath = base::FilePath(path);
   } else {
     base::win::RegKey hklm_key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ);
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc
index cafaf26..4d4fd0e7 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -58,10 +58,6 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #endif
 
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
 using content::WebContents;
 using content::WebPreferences;
 
@@ -166,8 +162,7 @@
     return false;
   UINT smooth_type = 0;
   SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smooth_type, 0);
-  return (base::win::GetVersion() >= base::win::VERSION_WIN7) &&
-         (smooth_type == FE_FONTSMOOTHINGCLEARTYPE);
+  return smooth_type == FE_FONTSMOOTHINGCLEARTYPE;
 }
 #endif
 
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index ae3f329..d089d9b 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -158,12 +158,8 @@
       return LM_SHORTCUT_NONAME;
     base::string16 shortcut(si.lpTitle);
     // The windows quick launch path is not localized.
-    if (shortcut.find(L"\\Quick Launch\\") != base::string16::npos) {
-      if (base::win::GetVersion() >= base::win::VERSION_WIN7)
-        return LM_SHORTCUT_TASKBAR;
-      else
-        return LM_SHORTCUT_QUICKLAUNCH;
-    }
+    if (shortcut.find(L"\\Quick Launch\\") != base::string16::npos)
+      return LM_SHORTCUT_TASKBAR;
     std::unique_ptr<base::Environment> env(base::Environment::Create());
     std::string appdata_path;
     env->GetVar("USERPROFILE", &appdata_path);
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
index bbd6e94..f70dabe1 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
@@ -325,7 +325,7 @@
   gfx::Point right_bottom = display::win::ScreenWin::DIPToClientPoint(
       hwnd, gfx::Point(thicknesses.right(), thicknesses.bottom()));
 
-  if (base::win::GetVersion() <= base::win::VERSION_WIN7) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8) {
     // The 2 px (not DIP) at the inner edges of the glass are a light and
     // dark line, so we must inset further to account for those.
     constexpr gfx::Vector2d kDWMEdgeThickness(2, 2);
diff --git a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
index ef906ff..79aa8d6 100644
--- a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
+++ b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
@@ -17,7 +17,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_propvariant.h"
-#include "base/win/windows_version.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/profiles/profile.h"
@@ -183,10 +182,6 @@
 // http://crbug.com/396344
 IN_PROC_BROWSER_TEST_F(BrowserTestWithProfileShortcutManager,
                        DISABLED_WindowProperties) {
-  // This test checks HWND properties that are only available on Win7+.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   // Single profile case. The profile name should not be shown.
   WaitAndValidateBrowserWindowProperties(base::Bind(
       &ValidateBrowserWindowProperties, browser(), base::string16()));
@@ -230,10 +225,6 @@
 
 // http://crbug.com/396344
 IN_PROC_BROWSER_TEST_F(BrowserWindowPropertyManagerTest, DISABLED_HostedApp) {
-  // This test checks HWND properties that are only available on Win7+.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   // Load an app.
   const extensions::Extension* extension =
       LoadExtension(test_data_dir_.AppendASCII("app/"));
diff --git a/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc b/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc
index 00fcecd0..3080979d 100644
--- a/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc
+++ b/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc
@@ -97,9 +97,6 @@
 BrowserWindowPropertyManager::CreateBrowserWindowPropertyManager(
     BrowserView* view,
     HWND hwnd) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return nullptr;
-
   std::unique_ptr<BrowserWindowPropertyManager> browser_window_property_manager(
       new BrowserWindowPropertyManager(view, hwnd));
   browser_window_property_manager->UpdateWindowProperties();
diff --git a/chrome/browser/ui/views/frame/taskbar_decorator_win.cc b/chrome/browser/ui/views/frame/taskbar_decorator_win.cc
index 5f99203..aab7e5a 100644
--- a/chrome/browser/ui/views/frame/taskbar_decorator_win.cc
+++ b/chrome/browser/ui/views/frame/taskbar_decorator_win.cc
@@ -12,7 +12,6 @@
 #include "base/task_scheduler/post_task.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_gdi_object.h"
-#include "base/win/windows_version.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
 #include "skia/ext/image_operations.h"
 #include "skia/ext/platform_canvas.h"
@@ -69,9 +68,6 @@
 }  // namespace
 
 void DrawTaskbarDecoration(gfx::NativeWindow window, const gfx::Image* image) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   HWND hwnd = views::HWNDForNativeWindow(window);
 
   // SetOverlayIcon() does nothing if the window is not visible so testing here
diff --git a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
index eebb74d4..b589e1f9 100644
--- a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
@@ -16,9 +16,9 @@
     const char* name;
     int id;
   } localized_strings[] = {
-      {"OncTypeCellular", IDS_NETWORK_TYPE_CELLULAR},
+      {"OncTypeCellular", IDS_NETWORK_TYPE_MOBILE_DATA},
       {"OncTypeEthernet", IDS_NETWORK_TYPE_ETHERNET},
-      {"OncTypeTether", IDS_NETWORK_TYPE_TETHER},
+      {"OncTypeTether", IDS_NETWORK_TYPE_MOBILE_DATA},
       {"OncTypeVPN", IDS_NETWORK_TYPE_VPN},
       {"OncTypeWiFi", IDS_NETWORK_TYPE_WIFI},
       {"OncTypeWiMAX", IDS_NETWORK_TYPE_WIMAX},
diff --git a/chrome/browser/ui/webui/help/help_utils_chromeos.cc b/chrome/browser/ui/webui/help/help_utils_chromeos.cc
index ea4884e..068f358 100644
--- a/chrome/browser/ui/webui/help/help_utils_chromeos.cc
+++ b/chrome/browser/ui/webui/help/help_utils_chromeos.cc
@@ -63,8 +63,10 @@
     return l10n_util::GetStringUTF16(IDS_NETWORK_TYPE_WIMAX);
   if (type == shill::kTypeBluetooth)
     return l10n_util::GetStringUTF16(IDS_NETWORK_TYPE_BLUETOOTH);
-  if (type == shill::kTypeCellular)
-    return l10n_util::GetStringUTF16(IDS_NETWORK_TYPE_CELLULAR);
+  if (type == shill::kTypeCellular ||
+      chromeos::NetworkTypePattern::Tether().MatchesType(type)) {
+    return l10n_util::GetStringUTF16(IDS_NETWORK_TYPE_MOBILE_DATA);
+  }
   if (type == shill::kTypeVPN)
     return l10n_util::GetStringUTF16(IDS_NETWORK_TYPE_VPN);
   NOTREACHED();
diff --git a/chrome/browser/ui/webui/md_bookmarks/OWNERS b/chrome/browser/ui/webui/md_bookmarks/OWNERS
index d0663e0..b02ce2c 100644
--- a/chrome/browser/ui/webui/md_bookmarks/OWNERS
+++ b/chrome/browser/ui/webui/md_bookmarks/OWNERS
@@ -1,5 +1,4 @@
 calamity@chromium.org
-dbeam@chromium.org
 tsergeant@chromium.org
 
 # COMPONENT: UI>Browser>Bookmarks
diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler_strings.cc b/chrome/browser/ui/webui/options/chromeos/internet_options_handler_strings.cc
index 6a89972c..accea76 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler_strings.cc
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler_strings.cc
@@ -74,8 +74,9 @@
     {"OncCellular-RoamingStateHome", IDS_CHROMEOS_NETWORK_ROAMING_STATE_HOME},
     {"OncCellular-RoamingStateRoaming",
      IDS_CHROMEOS_NETWORK_ROAMING_STATE_ROAMING},
-    {"OncTypeCellular", IDS_NETWORK_TYPE_CELLULAR},
+    {"OncTypeCellular", IDS_NETWORK_TYPE_MOBILE_DATA},
     {"OncTypeEthernet", IDS_NETWORK_TYPE_ETHERNET},
+    {"OncTypeTether", IDS_NETWORK_TYPE_MOBILE_DATA},
     {"OncTypeWiFi", IDS_NETWORK_TYPE_WIFI},
     {"OncTypeWimax", IDS_NETWORK_TYPE_WIMAX},
     {"OncVPN-TypeL2TP-IPsecCert",
diff --git a/chrome/browser/ui/webui/set_as_default_browser_ui_browsertest_win.cc b/chrome/browser/ui/webui/set_as_default_browser_ui_browsertest_win.cc
index eef463871..80e5953 100644
--- a/chrome/browser/ui/webui/set_as_default_browser_ui_browsertest_win.cc
+++ b/chrome/browser/ui/webui/set_as_default_browser_ui_browsertest_win.cc
@@ -40,8 +40,8 @@
 
 IN_PROC_BROWSER_TEST_F(SetAsDefaultBrowserUIBrowserTestWithFirstRun, Test) {
   // Windows 8 only test case.
-  if (base::win::GetVersion() <= base::win::VERSION_WIN7 ||
-      base::win::GetVersion() >= base::win::VERSION_WIN10) {
+  if (base::win::GetVersion() != base::win::VERSION_WIN8 &&
+      base::win::GetVersion() != base::win::VERSION_WIN8_1) {
     return;
   }
   ASSERT_FALSE(IsBrowserVisible(browser()));
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 87c4040..008760be 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -920,8 +920,9 @@
       {"internetPageTitle", IDS_SETTINGS_INTERNET},
       {"internetToggleMobileA11yLabel",
        IDS_SETTINGS_INTERNET_TOGGLE_MOBILE_ACCESSIBILITY_LABEL},
-      {"internetToggleTetherA11yLabel",
-       IDS_SETTINGS_INTERNET_TOGGLE_TETHER_ACCESSIBILITY_LABEL},
+      {"internetToggleTetherLabel", IDS_SETTINGS_INTERNET_TOGGLE_TETHER_LABEL},
+      {"internetToggleTetherSubtext",
+       IDS_SETTINGS_INTERNET_TOGGLE_TETHER_SUBTEXT},
       {"internetToggleWiFiA11yLabel",
        IDS_SETTINGS_INTERNET_TOGGLE_WIFI_ACCESSIBILITY_LABEL},
       {"internetToggleWiMAXA11yLabel",
diff --git a/chrome/browser/ui/zoom/OWNERS b/chrome/browser/ui/zoom/OWNERS
index 17b9bbe9..93899b2 100644
--- a/chrome/browser/ui/zoom/OWNERS
+++ b/chrome/browser/ui/zoom/OWNERS
@@ -1,4 +1,3 @@
-dbeam@chromium.org
 wjmaclean@chromium.org
 
 # COMPONENT: UI>Browser>Toolbar
diff --git a/chrome/browser/unload_browsertest.cc b/chrome/browser/unload_browsertest.cc
index 6b50fa4c..92a2c1b 100644
--- a/chrome/browser/unload_browsertest.cc
+++ b/chrome/browser/unload_browsertest.cc
@@ -32,11 +32,6 @@
 #include "net/test/url_request/url_request_mock_http_job.h"
 #include "net/url_request/url_request_test_util.h"
 
-#if defined(OS_WIN)
-// For version specific disabled tests below (http://crbug.com/267597).
-#include "base/win/windows_version.h"
-#endif
-
 using base::TimeDelta;
 using content::BrowserThread;
 
@@ -761,12 +756,8 @@
 }
 
 // Fails on Mac, Linux, Win7 (http://crbug.com/301173).
+// Flaky on Windows bots (http://crbug.com/267597).
 IN_PROC_BROWSER_TEST_F(FastUnloadTest, DISABLED_ClosingLastTabFinishesUnload) {
-#if defined(OS_WIN)
-  // Flaky on Win7+ bots (http://crbug.com/267597).
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7)
-    return;
-#endif
   // Check for cookie set in unload handler of PRE_ test.
   NavigateToPage("no_listeners");
   EXPECT_EQ("unloaded=ohyeah", GetCookies("no_listeners"));
diff --git a/chrome/browser/web_applications/update_shortcut_worker_win.cc b/chrome/browser/web_applications/update_shortcut_worker_win.cc
index cd24d08..9d3ae82 100644
--- a/chrome/browser/web_applications/update_shortcut_worker_win.cc
+++ b/chrome/browser/web_applications/update_shortcut_worker_win.cc
@@ -15,7 +15,6 @@
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/shortcut.h"
-#include "base/win/windows_version.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -159,9 +158,7 @@
     }, {
       // For Win7, create_in_quick_launch_bar means pinning to taskbar.
       base::DIR_APP_DATA,
-      (base::win::GetVersion() >= base::win::VERSION_WIN7) ?
-          L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar" :
-          L"Microsoft\\Internet Explorer\\Quick Launch"
+      L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar"
     }
   };
 
diff --git a/chrome/browser/web_applications/web_app_win.cc b/chrome/browser/web_applications/web_app_win.cc
index a71ee45..ef26f880 100644
--- a/chrome/browser/web_applications/web_app_win.cc
+++ b/chrome/browser/web_applications/web_app_win.cc
@@ -22,7 +22,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/win/shortcut.h"
-#include "base/win/windows_version.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/shell_integration_win.h"
 #include "chrome/browser/web_applications/update_shortcut_worker_win.h"
@@ -300,10 +299,8 @@
       web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS;
   std::vector<base::FilePath> all_paths = web_app::internals::GetShortcutPaths(
       all_shortcut_locations);
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
-      !web_app_path.empty()) {
+  if (!web_app_path.empty())
     all_paths.push_back(web_app_path);
-  }
 
   if (was_pinned_to_taskbar) {
     // Determine if there is a link to this app in the TaskBar pin directory.
diff --git a/chrome/test/data/webui/settings/fake_networking_private.js b/chrome/test/data/webui/settings/fake_networking_private.js
index d6421e7..f067574 100644
--- a/chrome/test/data/webui/settings/fake_networking_private.js
+++ b/chrome/test/data/webui/settings/fake_networking_private.js
@@ -29,6 +29,7 @@
         Ethernet: {Type: 'Ethernet', State: 'Enabled'},
         WiFi: {Type: 'WiFi', State: ''},
         Cellular: {Type: 'Cellular', State: ''},
+        Tether: {Type: 'Tether', State: ''},
         WiMAX: {Type: 'WiMAX', State: ''},
       };
 
@@ -56,7 +57,13 @@
     getProperties: assertNotReached,
 
     /** @override */
-    getManagedProperties: assertNotReached,
+    getManagedProperties: function(guid) {
+      var result = this.networkStates_.find(function(state) {
+        return state.GUID == guid;
+      });
+      // TODO(stevenjb): Convert state to ManagedProperties.
+      return result;
+    },
 
     /** @override */
     getState: assertNotReached,
diff --git a/chrome/test/data/webui/settings/internet_page_tests.js b/chrome/test/data/webui/settings/internet_page_tests.js
index 70edfae..f09ff68c5 100644
--- a/chrome/test/data/webui/settings/internet_page_tests.js
+++ b/chrome/test/data/webui/settings/internet_page_tests.js
@@ -28,6 +28,7 @@
     CrOncStrings = {
       OncTypeCellular: 'OncTypeCellular',
       OncTypeEthernet: 'OncTypeEthernet',
+      OncTypeTether: 'OncTypeTether',
       OncTypeVPN: 'OncTypeVPN',
       OncTypeWiFi: 'OncTypeWiFi',
       OncTypeWiMAX: 'OncTypeWiMAX',
@@ -96,7 +97,7 @@
       assertEquals('Disabled', api_.getDeviceStateForTest('WiFi').State);
       var toggle = wifi.$$('#deviceEnabledButton');
       assertTrue(!!toggle);
-      assertTrue(toggle.enabled);
+      assertFalse(toggle.disabled);
       assertFalse(toggle.checked);
 
       // Tap the enable toggle button and ensure the state becomes enabled.
@@ -107,6 +108,10 @@
     });
   });
 
+  function callAsync(resolve) {
+    Polymer.Base.async(resolve);
+  };
+
   suite('SubPage', function() {
     test('WiFi', function() {
       api_.addNetworksForTest([
@@ -119,12 +124,96 @@
       assertTrue(!!wifi);
       MockInteractions.tap(wifi.$$('button.subpage-arrow'));
       Polymer.dom.flush();
-      var subpage = internetPage.$$('settings-internet-subpage');
-      assertTrue(!!subpage);
-      assertEquals(2, subpage.networkStateList_.length);
-      var networkList = subpage.$$('#networkList');
-      assertTrue(!!networkList);
-      assertEquals(2, networkList.networks.length);
+      // Allow dom-if templates to resolve.
+      return new Promise(callAsync).then(function() {
+        var subpage = internetPage.$$('settings-internet-subpage');
+        assertTrue(!!subpage);
+        assertEquals(2, subpage.networkStateList_.length);
+        var toggle = wifi.$$('#deviceEnabledButton');
+        assertTrue(!!toggle);
+        assertFalse(toggle.disabled);
+        var networkList = subpage.$$('#networkList');
+        assertTrue(!!networkList);
+        assertEquals(2, networkList.networks.length);
+      });
+    });
+
+    test('Cellular', function() {
+      api_.addNetworksForTest([
+        {GUID: 'cellular1_guid', Name: 'cellular1', Type: 'Cellular'},
+      ]);
+      api_.enableNetworkType('Cellular');
+      Polymer.dom.flush();
+      // Allow dom-if templates to resolve.
+      return new Promise(callAsync).then(function() {
+        var mobile = networkSummary_.$$('#Cellular');
+        assertTrue(!!mobile);
+        MockInteractions.tap(mobile.$$('button.subpage-arrow'));
+        Polymer.dom.flush();
+        return new Promise(callAsync);
+      }).then(function() {
+        var detailPage = internetPage.$$('settings-internet-detail-page');
+        assertTrue(!!detailPage);
+      });
+    });
+
+    test('Tether', function() {
+      api_.addNetworksForTest([
+        {GUID: 'tether1_guid', Name: 'tether1', Type: 'Tether'},
+        {GUID: 'tether2_guid', Name: 'tether2', Type: 'Tether'},
+      ]);
+      api_.enableNetworkType('Tether');
+      Polymer.dom.flush();
+      // Allow dom-if templates to resolve.
+      return new Promise(callAsync).then(function() {
+        var mobile = networkSummary_.$$('#Tether');
+        assertTrue(!!mobile);
+        MockInteractions.tap(mobile.$$('button.subpage-arrow'));
+        Polymer.dom.flush();
+        var subpage = internetPage.$$('settings-internet-subpage');
+        assertTrue(!!subpage);
+        assertEquals(2, subpage.networkStateList_.length);
+        var toggle = mobile.$$('#deviceEnabledButton');
+        assertTrue(!!toggle);
+        assertFalse(toggle.disabled);
+        var networkList = subpage.$$('#networkList');
+        assertTrue(!!networkList);
+        assertEquals(2, networkList.networks.length);
+        var tetherToggle = mobile.$$('#tetherEnabledButton');
+        // No separate tether toggle when Celular is not available; the
+        // primary toggle enables or disables Tether in that case.
+        assertFalse(!!tetherToggle);
+      });
+    });
+
+    test('Tether plus Cellular', function() {
+      api_.addNetworksForTest([
+        {GUID: 'cellular1_guid', Name: 'cellular1', Type: 'Cellular'},
+        {GUID: 'tether1_guid', Name: 'tether1', Type: 'Tether'},
+        {GUID: 'tether2_guid', Name: 'tether2', Type: 'Tether'},
+      ]);
+      api_.enableNetworkType('Cellular');
+      api_.enableNetworkType('Tether');
+      Polymer.dom.flush();
+      // Allow dom-if templates to resolve.
+      return new Promise(callAsync).then(function() {
+        var mobile = networkSummary_.$$('#Cellular');
+        assertTrue(!!mobile);
+        MockInteractions.tap(mobile.$$('button.subpage-arrow'));
+        Polymer.dom.flush();
+        var subpage = internetPage.$$('settings-internet-subpage');
+        assertTrue(!!subpage);
+        assertEquals(3, subpage.networkStateList_.length);
+        var toggle = mobile.$$('#deviceEnabledButton');
+        assertTrue(!!toggle);
+        assertFalse(toggle.disabled);
+        var networkList = subpage.$$('#networkList');
+        assertTrue(!!networkList);
+        assertEquals(3, networkList.networks.length);
+        var tetherToggle = subpage.$$('#tetherEnabledButton');
+        assertTrue(!!tetherToggle);
+        assertFalse(tetherToggle.disabled);
+      });
     });
 
     test('VPN', function() {
@@ -161,18 +250,21 @@
       ]);
       api_.onNetworkListChanged.callListeners();
       Polymer.dom.flush();
-      var vpn = networkSummary_.$$('#VPN');
-      assertTrue(!!vpn);
-      MockInteractions.tap(vpn.$$('button.subpage-arrow'));
-      Polymer.dom.flush();
-      var subpage = internetPage.$$('settings-internet-subpage');
-      assertTrue(!!subpage);
-      assertEquals(2, subpage.networkStateList_.length);
-      var networkList = subpage.$$('#networkList');
-      assertTrue(!!networkList);
-      assertEquals(2, networkList.networks.length);
-      // TODO(stevenjb): Implement fake management API and test third
-      // party provider sections.
+      // Allow dom-if templates to resolve.
+      Polymer.Base.async(function() {
+        var vpn = networkSummary_.$$('#VPN');
+        assertTrue(!!vpn);
+        MockInteractions.tap(vpn.$$('button.subpage-arrow'));
+        Polymer.dom.flush();
+        var subpage = internetPage.$$('settings-internet-subpage');
+        assertTrue(!!subpage);
+        assertEquals(2, subpage.networkStateList_.length);
+        var networkList = subpage.$$('#networkList');
+        assertTrue(!!networkList);
+        assertEquals(2, networkList.networks.length);
+        // TODO(stevenjb): Implement fake management API and test third
+        // party provider sections.
+      });
     });
   });
 });
diff --git a/chrome/utility/importer/edge_database_reader_unittest_win.cc b/chrome/utility/importer/edge_database_reader_unittest_win.cc
index 630f439e..80e194c4 100644
--- a/chrome/utility/importer/edge_database_reader_unittest_win.cc
+++ b/chrome/utility/importer/edge_database_reader_unittest_win.cc
@@ -16,7 +16,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/win/windows_version.h"
 #include "chrome/common/chrome_paths.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/zlib/google/compression_utils.h"
@@ -72,10 +71,6 @@
 }  // namespace
 
 TEST_F(EdgeDatabaseReaderTest, OpenFileTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -83,19 +78,11 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, NoFileTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   EdgeDatabaseReader reader;
   EXPECT_FALSE(reader.OpenDatabase(L"ThisIsntARealFileName.edb"));
 }
 
 TEST_F(EdgeDatabaseReaderTest, RandomGarbageDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"random.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -103,10 +90,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, ZerosDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   std::string zeros(0x10000, '\0');
   ASSERT_TRUE(WriteFile(L"zeros.edb", zeros, &database_path));
@@ -115,10 +98,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, EmptyDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(WriteFile(L"empty.edb", "", &database_path));
   EdgeDatabaseReader reader;
@@ -126,10 +105,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, OpenTableDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -140,10 +115,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, InvalidTableDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -154,10 +125,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, NotOpenDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   EdgeDatabaseReader reader;
   std::unique_ptr<EdgeDatabaseTableEnumerator> table_enum =
       reader.OpenTableEnumerator(L"TestTable");
@@ -166,10 +133,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, AlreadyOpenDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -179,10 +142,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, OpenTableAndReadDataDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -242,10 +201,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, CheckEnumResetDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -266,10 +221,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, InvalidColumnDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -283,10 +234,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, NoColumnDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -300,10 +247,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, EmptyTableDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -327,9 +270,6 @@
       "\x48\x65\x6C\x6C\x6F",
       "\xEC\x95\x88\xEB\x85\x95\xED\x95\x98\xEC\x84\xB8\xEC\x9A\x94",
   };
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
 
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
@@ -352,10 +292,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, NonUnicodeStringsDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -369,10 +305,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, CheckNullColumnDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
@@ -420,10 +352,6 @@
 }
 
 TEST_F(EdgeDatabaseReaderTest, CheckInvalidColumnTypeDatabaseTest) {
-  // Only verified to work with ESE library on Windows 7 and above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::FilePath database_path;
   ASSERT_TRUE(CopyTestDatabase(L"testdata.edb", &database_path));
   EdgeDatabaseReader reader;
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index bed774e3..6bf3463 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -158,8 +158,8 @@
       if (tether_technology_state_ != TECHNOLOGY_ENABLED &&
           tether_technology_state_ != TECHNOLOGY_AVAILABLE) {
         NET_LOG(ERROR) << "SetTechnologyEnabled() called for the Tether "
-                       << "DeviceState, but the current state was not "
-                       << "TECHNOLOGY_ENABLED or TECHNOLOGY_AVAILABLE.";
+                       << "DeviceState, but the current state was: "
+                       << tether_technology_state_;
         network_handler::RunErrorCallback(
             error_callback, kTetherDevicePath,
             NetworkConnectionHandler::kErrorEnabledOrDisabledWhenNotAvailable,
diff --git a/cloud_print/virtual_driver/win/install/setup.cc b/cloud_print/virtual_driver/win/install/setup.cc
index 70ae0dd..fc353a1 100644
--- a/cloud_print/virtual_driver/win/install/setup.cc
+++ b/cloud_print/virtual_driver/win/install/setup.cc
@@ -257,8 +257,7 @@
 
 bool IsOSSupported() {
   // We don't support Vista or older.
-  base::win::Version version = base::win::GetVersion();
-  return (version >= base::win::VERSION_WIN7);
+  return base::win::GetVersion() >= base::win::VERSION_WIN7;
 }
 
 HRESULT RegisterVirtualDriver(const base::FilePath& install_path) {
diff --git a/components/cast_certificate/cast_cert_validator.cc b/components/cast_certificate/cast_cert_validator.cc
index afd7b64..8ea624b 100644
--- a/components/cast_certificate/cast_cert_validator.cc
+++ b/components/cast_certificate/cast_cert_validator.cc
@@ -176,6 +176,11 @@
     return false;
 
   // Check for an optional audio-only policy extension.
+  //
+  // TODO(eroman): Use |user_constrained_policy_set| that was output from
+  // verification instead. (Checking just the leaf certificate's policy
+  // assertion doesn't take into account policy restrictions on intermediates,
+  // policy constraints/inhibits, or policy re-mappings).
   *policy = CastDeviceCertPolicy::NONE;
   if (cert->has_policy_oids()) {
     const std::vector<net::der::Input>& policies = cert->policy_oids();
@@ -264,9 +269,11 @@
   if (!net::der::EncodeTimeAsGeneralizedTime(time, &verification_time))
     return false;
   net::CertPathBuilder::Result result;
-  net::CertPathBuilder path_builder(target_cert.get(), trust_store,
-                                    signature_policy.get(), verification_time,
-                                    net::KeyPurpose::CLIENT_AUTH, &result);
+  net::CertPathBuilder path_builder(
+      target_cert.get(), trust_store, signature_policy.get(), verification_time,
+      net::KeyPurpose::CLIENT_AUTH, net::InitialExplicitPolicy::kFalse,
+      {net::AnyPolicy()}, net::InitialPolicyMappingInhibit::kFalse,
+      net::InitialAnyPolicyInhibit::kFalse, &result);
   path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
   path_builder.Run();
   if (!result.HasValidPath()) {
diff --git a/components/cast_certificate/cast_crl.cc b/components/cast_certificate/cast_crl.cc
index e8e0595..4f57a905 100644
--- a/components/cast_certificate/cast_crl.cc
+++ b/components/cast_certificate/cast_crl.cc
@@ -142,9 +142,11 @@
     return false;
   }
   net::CertPathBuilder::Result result;
-  net::CertPathBuilder path_builder(parsed_cert.get(), trust_store,
-                                    signature_policy.get(), verification_time,
-                                    net::KeyPurpose::ANY_EKU, &result);
+  net::CertPathBuilder path_builder(
+      parsed_cert.get(), trust_store, signature_policy.get(), verification_time,
+      net::KeyPurpose::ANY_EKU, net::InitialExplicitPolicy::kFalse,
+      {net::AnyPolicy()}, net::InitialPolicyMappingInhibit::kFalse,
+      net::InitialAnyPolicyInhibit::kFalse, &result);
   path_builder.Run();
   if (!result.HasValidPath()) {
     VLOG(2) << "CRL - Issuer certificate verification failed.";
diff --git a/components/metrics/drive_metrics_provider_win.cc b/components/metrics/drive_metrics_provider_win.cc
index 360b80e..04647a9 100644
--- a/components/metrics/drive_metrics_provider_win.cc
+++ b/components/metrics/drive_metrics_provider_win.cc
@@ -11,18 +11,12 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/strings/stringprintf.h"
-#include "base/win/windows_version.h"
 
 namespace metrics {
 
 // static
 bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath& path,
                                           bool* has_seek_penalty) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN7) {
-    // TODO(dbeam): re-enable XP and Vista detection in a utility process.
-    return false;
-  }
-
   std::vector<base::FilePath::StringType> components;
   path.GetComponents(&components);
 
diff --git a/components/resources/OWNERS b/components/resources/OWNERS
index 1c722be6..eed6b23 100644
--- a/components/resources/OWNERS
+++ b/components/resources/OWNERS
@@ -22,9 +22,4 @@
 per-file security_interstitials_resources.grdp=file://components/security_interstitials/OWNERS
 per-file supervised_user_error_page_resources.grdp=file://components/supervised_user_error_page/OWNERS
 per-file sync_driver_resources.grdp=file://components/sync/OWNERS
-per-file version_ui*=achuith@chromium.org
-per-file version_ui*=bauerb@chromium.org
-per-file version_ui*=dbeam@chromium.org
-per-file version_ui*=estade@chromium.org
-per-file version_ui*=pam@chromium.org
-per-file version_ui*=xiyuan@chromium.org
+per-file version_ui*=file://ui/webui/PLATFORM_OWNERS
diff --git a/components/sync/engine_impl/model_type_worker_unittest.cc b/components/sync/engine_impl/model_type_worker_unittest.cc
index cc4fd1bd..201bd3c2 100644
--- a/components/sync/engine_impl/model_type_worker_unittest.cc
+++ b/components/sync/engine_impl/model_type_worker_unittest.cc
@@ -22,6 +22,12 @@
 #include "components/sync/test/engine/single_type_mock_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::Time;
+using base::TimeDelta;
+using sync_pb::EntitySpecifics;
+using sync_pb::ModelTypeState;
+using sync_pb::SyncEntity;
+
 namespace syncer {
 
 namespace {
@@ -45,9 +51,9 @@
 const std::string kHash2(GenerateTagHash(kTag2));
 const std::string kHash3(GenerateTagHash(kTag3));
 
-sync_pb::EntitySpecifics GenerateSpecifics(const std::string& tag,
-                                           const std::string& value) {
-  sync_pb::EntitySpecifics specifics;
+EntitySpecifics GenerateSpecifics(const std::string& tag,
+                                  const std::string& value) {
+  EntitySpecifics specifics;
   specifics.mutable_preference()->set_name(tag);
   specifics.mutable_preference()->set_value(value);
   return specifics;
@@ -78,12 +84,11 @@
 
 // Modifies the input/output parameter |specifics| by encrypting it with
 // a Nigori intialized with the specified KeyParams.
-void EncryptUpdate(const KeyParams& params,
-                   sync_pb::EntitySpecifics* specifics) {
+void EncryptUpdate(const KeyParams& params, EntitySpecifics* specifics) {
   Nigori nigori;
   nigori.InitByDerivation(params.hostname, params.username, params.password);
 
-  sync_pb::EntitySpecifics original_specifics = *specifics;
+  EntitySpecifics original_specifics = *specifics;
   std::string plaintext;
   original_specifics.SerializeToString(&plaintext);
 
@@ -144,7 +149,7 @@
   // significant server action until we receive an update response that
   // contains the type root node for this type.
   void FirstInitialize() {
-    sync_pb::ModelTypeState initial_state;
+    ModelTypeState initial_state;
     initial_state.mutable_progress_marker()->set_data_type_id(
         GetSpecificsFieldNumberFromModelType(kModelType));
 
@@ -160,7 +165,7 @@
   // Initialize with some saved pending updates from the model thread.
   void InitializeWithPendingUpdates(
       const UpdateResponseDataList& initial_pending_updates) {
-    sync_pb::ModelTypeState initial_state;
+    ModelTypeState initial_state;
     initial_state.mutable_progress_marker()->set_data_type_id(
         GetSpecificsFieldNumberFromModelType(kModelType));
     initial_state.mutable_progress_marker()->set_token(
@@ -175,7 +180,7 @@
 
   // Initialize with a custom initial ModelTypeState and pending updates.
   void InitializeWithState(
-      const sync_pb::ModelTypeState& state,
+      const ModelTypeState& state,
       const UpdateResponseDataList& initial_pending_updates) {
     DCHECK(!worker_);
 
@@ -283,7 +288,7 @@
   // Pretend to receive update messages from the server.
 
   void TriggerTypeRootUpdateFromServer() {
-    sync_pb::SyncEntity entity = mock_server_.TypeRootUpdate();
+    SyncEntity entity = mock_server_.TypeRootUpdate();
     worker_->ProcessGetUpdatesResponse(mock_server_.GetProgress(),
                                        mock_server_.GetContext(), {&entity},
                                        nullptr);
@@ -293,7 +298,7 @@
   void TriggerPartialUpdateFromServer(int64_t version_offset,
                                       const std::string& tag,
                                       const std::string& value) {
-    sync_pb::SyncEntity entity = mock_server_.UpdateFromServer(
+    SyncEntity entity = mock_server_.UpdateFromServer(
         version_offset, GenerateTagHash(tag), GenerateSpecifics(tag, value));
 
     if (update_encryption_filter_index_ != 0) {
@@ -315,7 +320,7 @@
 
   void TriggerTombstoneFromServer(int64_t version_offset,
                                   const std::string& tag) {
-    sync_pb::SyncEntity entity =
+    SyncEntity entity =
         mock_server_.TombstoneFromServer(version_offset, GenerateTagHash(tag));
 
     if (update_encryption_filter_index_ != 0) {
@@ -493,7 +498,7 @@
   ASSERT_EQ(1U, server()->GetNumCommitMessages());
   EXPECT_EQ(1, server()->GetNthCommitMessage(0).commit().entries_size());
   ASSERT_TRUE(server()->HasCommitEntity(kHash1));
-  const sync_pb::SyncEntity& entity = server()->GetLastCommittedEntity(kHash1);
+  const SyncEntity& entity = server()->GetLastCommittedEntity(kHash1);
   EXPECT_FALSE(entity.id_string().empty());
   EXPECT_EQ(0, entity.version());
   EXPECT_NE(0, entity.mtime());
@@ -559,7 +564,7 @@
   ASSERT_EQ(2U, server()->GetNumCommitMessages());
   EXPECT_EQ(1, server()->GetNthCommitMessage(1).commit().entries_size());
   ASSERT_TRUE(server()->HasCommitEntity(kHash1));
-  const sync_pb::SyncEntity& entity = server()->GetLastCommittedEntity(kHash1);
+  const SyncEntity& entity = server()->GetLastCommittedEntity(kHash1);
   EXPECT_FALSE(entity.id_string().empty());
   EXPECT_EQ(GenerateTagHash(kTag1), entity.client_defined_unique_tag());
   EXPECT_EQ(base_version, entity.version());
@@ -616,7 +621,7 @@
   // The update contains no entities.
   EXPECT_EQ(0U, processor()->GetNthUpdateResponse(0).size());
 
-  const sync_pb::ModelTypeState& state = processor()->GetNthUpdateState(0);
+  const ModelTypeState& state = processor()->GetNthUpdateState(0);
   EXPECT_FALSE(state.progress_marker().token().empty());
   EXPECT_TRUE(state.initial_sync_done());
   EXPECT_TRUE(worker()->IsInitialSyncEnded());
@@ -634,8 +639,7 @@
   ASSERT_EQ(1U, server()->GetNumCommitMessages());
   EXPECT_EQ(1, server()->GetNthCommitMessage(0).commit().entries_size());
   ASSERT_TRUE(server()->HasCommitEntity(kHash1));
-  const sync_pb::SyncEntity& tag1_entity =
-      server()->GetLastCommittedEntity(kHash1);
+  const SyncEntity& tag1_entity = server()->GetLastCommittedEntity(kHash1);
 
   // Commit the second of two entities.
   CommitRequest(kTag2, kValue2);
@@ -645,8 +649,7 @@
   ASSERT_EQ(2U, server()->GetNumCommitMessages());
   EXPECT_EQ(1, server()->GetNthCommitMessage(1).commit().entries_size());
   ASSERT_TRUE(server()->HasCommitEntity(kHash2));
-  const sync_pb::SyncEntity& tag2_entity =
-      server()->GetLastCommittedEntity(kHash2);
+  const SyncEntity& tag2_entity = server()->GetLastCommittedEntity(kHash2);
 
   EXPECT_FALSE(WillCommit());
 
@@ -758,8 +761,7 @@
   ASSERT_EQ(1U, server()->GetNumCommitMessages());
   EXPECT_EQ(1, server()->GetNthCommitMessage(0).commit().entries_size());
   ASSERT_TRUE(server()->HasCommitEntity(kHash1));
-  const sync_pb::SyncEntity& tag1_entity =
-      server()->GetLastCommittedEntity(kHash1);
+  const SyncEntity& tag1_entity = server()->GetLastCommittedEntity(kHash1);
 
   EXPECT_TRUE(tag1_entity.specifics().has_encrypted());
 
@@ -818,8 +820,7 @@
   ASSERT_EQ(1U, server()->GetNumCommitMessages());
   EXPECT_EQ(1, server()->GetNthCommitMessage(0).commit().entries_size());
   ASSERT_TRUE(server()->HasCommitEntity(kHash1));
-  const sync_pb::SyncEntity& tag1_entity =
-      server()->GetLastCommittedEntity(kHash1);
+  const SyncEntity& tag1_entity = server()->GetLastCommittedEntity(kHash1);
   EXPECT_TRUE(tag1_entity.specifics().has_encrypted());
   EXPECT_EQ(tag1_entity.name(), "encrypted");
   EXPECT_TRUE(tag1_entity.specifics().has_preference());
@@ -992,7 +993,7 @@
   EXPECT_TRUE(WillCommit());
   DoSuccessfulCommit();
   sync_pb::ClientToServerMessage message = server()->GetNthCommitMessage(1);
-  const google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>& entries =
+  const google::protobuf::RepeatedPtrField<SyncEntity>& entries =
       message.commit().entries();
   ASSERT_EQ(1, entries.size());
   EXPECT_EQ(entries.Get(0).version(), commit_version);
@@ -1004,10 +1005,8 @@
   EntityData entity;
   entity.client_tag_hash = GenerateTagHash(kTag1);
   entity.id = "SomeID";
-  entity.creation_time =
-      base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(10);
-  entity.modification_time =
-      base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(11);
+  entity.creation_time = Time::UnixEpoch() + TimeDelta::FromSeconds(10);
+  entity.modification_time = Time::UnixEpoch() + TimeDelta::FromSeconds(11);
   entity.non_unique_name = "encrypted";
   entity.specifics = GenerateSpecifics(kTag1, kValue1);
   EncryptUpdate(GetNthKeyParams(1), &(entity.specifics));
@@ -1045,10 +1044,8 @@
   EntityData entity;
   entity.client_tag_hash = GenerateTagHash(kTag1);
   entity.id = "SomeID";
-  entity.creation_time =
-      base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(10);
-  entity.modification_time =
-      base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(11);
+  entity.creation_time = Time::UnixEpoch() + TimeDelta::FromSeconds(10);
+  entity.modification_time = Time::UnixEpoch() + TimeDelta::FromSeconds(11);
   entity.non_unique_name = "encrypted";
 
   entity.specifics = GenerateSpecifics(kTag1, kValue1);
@@ -1107,7 +1104,7 @@
   DecryptPendingKey();
 
   // Manually create an update.
-  sync_pb::SyncEntity entity;
+  SyncEntity entity;
   entity.set_client_defined_unique_tag(GenerateTagHash(kTag1));
   entity.set_id_string("SomeID");
   entity.set_version(1);
@@ -1160,8 +1157,7 @@
 
   // Verify that entity got deleted from the server.
   {
-    const sync_pb::SyncEntity& entity =
-        server()->GetLastCommittedEntity(kHash1);
+    const SyncEntity& entity = server()->GetLastCommittedEntity(kHash1);
     EXPECT_TRUE(entity.deleted());
   }
 
@@ -1171,8 +1167,7 @@
   DoSuccessfulCommit();
   // Verify that there is a valid entity on the server.
   {
-    const sync_pb::SyncEntity& entity =
-        server()->GetLastCommittedEntity(kHash1);
+    const SyncEntity& entity = server()->GetLastCommittedEntity(kHash1);
     EXPECT_FALSE(entity.deleted());
   }
 }
diff --git a/components/sync/engine_impl/syncer_unittest.cc b/components/sync/engine_impl/syncer_unittest.cc
index 27702c2..7c230fe 100644
--- a/components/sync/engine_impl/syncer_unittest.cc
+++ b/components/sync/engine_impl/syncer_unittest.cc
@@ -13,6 +13,7 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -4141,7 +4142,7 @@
 TEST_F(SyncerTest, TestClientCommandDuringUpdate) {
   using sync_pb::ClientCommand;
 
-  ClientCommand* command = new ClientCommand();
+  auto command = base::MakeUnique<ClientCommand>();
   command->set_set_sync_poll_interval(8);
   command->set_set_sync_long_poll_interval(800);
   command->set_sessions_commit_delay_seconds(3141);
@@ -4153,7 +4154,7 @@
   command->set_client_invalidation_hint_buffer_size(11);
   mock_server_->AddUpdateDirectory(1, 0, "in_root", 1, 1, foreign_cache_guid(),
                                    "-1");
-  mock_server_->SetGUClientCommand(command);
+  mock_server_->SetGUClientCommand(std::move(command));
   EXPECT_TRUE(SyncShareNudge());
 
   EXPECT_EQ(TimeDelta::FromSeconds(8), last_short_poll_interval_received_);
@@ -4162,7 +4163,7 @@
   EXPECT_EQ(TimeDelta::FromMilliseconds(950), last_bookmarks_commit_delay_);
   EXPECT_EQ(11, last_client_invalidation_hint_buffer_size_);
 
-  command = new ClientCommand();
+  command = base::MakeUnique<ClientCommand>();
   command->set_set_sync_poll_interval(180);
   command->set_set_sync_long_poll_interval(190);
   command->set_sessions_commit_delay_seconds(2718);
@@ -4173,7 +4174,7 @@
   command->set_client_invalidation_hint_buffer_size(9);
   mock_server_->AddUpdateDirectory(1, 0, "in_root", 1, 1, foreign_cache_guid(),
                                    "-1");
-  mock_server_->SetGUClientCommand(command);
+  mock_server_->SetGUClientCommand(std::move(command));
   EXPECT_TRUE(SyncShareNudge());
 
   EXPECT_EQ(TimeDelta::FromSeconds(180), last_short_poll_interval_received_);
@@ -4186,7 +4187,7 @@
 TEST_F(SyncerTest, TestClientCommandDuringCommit) {
   using sync_pb::ClientCommand;
 
-  ClientCommand* command = new ClientCommand();
+  auto command = base::MakeUnique<ClientCommand>();
   command->set_set_sync_poll_interval(8);
   command->set_set_sync_long_poll_interval(800);
   command->set_sessions_commit_delay_seconds(3141);
@@ -4197,7 +4198,7 @@
   bookmark_delay->set_delay_ms(950);
   command->set_client_invalidation_hint_buffer_size(11);
   CreateUnsyncedDirectory("X", "id_X");
-  mock_server_->SetCommitClientCommand(command);
+  mock_server_->SetCommitClientCommand(std::move(command));
   EXPECT_TRUE(SyncShareNudge());
 
   EXPECT_EQ(TimeDelta::FromSeconds(8), last_short_poll_interval_received_);
@@ -4206,7 +4207,7 @@
   EXPECT_EQ(TimeDelta::FromMilliseconds(950), last_bookmarks_commit_delay_);
   EXPECT_EQ(11, last_client_invalidation_hint_buffer_size_);
 
-  command = new ClientCommand();
+  command = base::MakeUnique<ClientCommand>();
   command->set_set_sync_poll_interval(180);
   command->set_set_sync_long_poll_interval(190);
   command->set_sessions_commit_delay_seconds(2718);
@@ -4216,7 +4217,7 @@
   bookmark_delay->set_delay_ms(1050);
   command->set_client_invalidation_hint_buffer_size(9);
   CreateUnsyncedDirectory("Y", "id_Y");
-  mock_server_->SetCommitClientCommand(command);
+  mock_server_->SetCommitClientCommand(std::move(command));
   EXPECT_TRUE(SyncShareNudge());
 
   EXPECT_EQ(TimeDelta::FromSeconds(180), last_short_poll_interval_received_);
diff --git a/components/sync/model_impl/shared_model_type_processor_unittest.cc b/components/sync/model_impl/shared_model_type_processor_unittest.cc
index 091d78e9..c7341b58 100644
--- a/components/sync/model_impl/shared_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/shared_model_type_processor_unittest.cc
@@ -270,7 +270,7 @@
   EntitySpecifics WriteItemAndAck(const std::string& key,
                                   const std::string& value) {
     EntitySpecifics specifics = bridge()->WriteItem(key, value);
-    worker()->ExpectPendingCommits(
+    worker()->VerifyPendingCommits(
         {FakeModelTypeSyncBridge::TagHashFromKey(key)});
     worker()->AckOnePendingCommit();
     EXPECT_EQ(0U, worker()->GetNumPendingCommits());
@@ -389,7 +389,7 @@
   EXPECT_EQ(2U, ProcessorEntityCount());
   EXPECT_EQ(1, db().GetMetadata(kKey1).sequence_number());
   EXPECT_EQ(0, db().GetMetadata(kKey2).sequence_number());
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
 }
 
 // Test that an initial sync filters out tombstones in the processor.
@@ -490,7 +490,7 @@
   OnPendingCommitDataLoaded();
   OnSyncStarting();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics1);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics1);
 
   // Connect, data.
   EntitySpecifics specifics2 = ResetStateWriteItem(kKey1, kValue1);
@@ -499,7 +499,7 @@
   EXPECT_EQ(nullptr, worker());
   OnPendingCommitDataLoaded();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics2);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics2);
 
   // Data, connect, put.
   EntitySpecifics specifics3 = ResetStateWriteItem(kKey1, kValue1);
@@ -508,8 +508,8 @@
   OnSyncStarting();
   EntitySpecifics specifics4 = bridge()->WriteItem(kKey1, kValue2);
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics3);
-  worker()->ExpectNthPendingCommit(1, kHash1, specifics4);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics3);
+  worker()->VerifyNthPendingCommit(1, kHash1, specifics4);
 
   // Data, put, connect.
   ResetStateWriteItem(kKey1, kValue1);
@@ -518,7 +518,7 @@
   EntitySpecifics specifics5 = bridge()->WriteItem(kKey1, kValue2);
   OnSyncStarting();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics5);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics5);
 
   // Connect, data, put.
   EntitySpecifics specifics6 = ResetStateWriteItem(kKey1, kValue1);
@@ -527,8 +527,8 @@
   OnPendingCommitDataLoaded();
   EntitySpecifics specifics7 = bridge()->WriteItem(kKey1, kValue2);
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics6);
-  worker()->ExpectNthPendingCommit(1, kHash1, specifics7);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics6);
+  worker()->VerifyNthPendingCommit(1, kHash1, specifics7);
 
   // Connect, put, data.
   ResetStateWriteItem(kKey1, kValue1);
@@ -538,7 +538,7 @@
   EXPECT_EQ(nullptr, worker());
   OnPendingCommitDataLoaded();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics8);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics8);
 
   // Put, data, connect.
   ResetStateWriteItem(kKey1, kValue1);
@@ -547,7 +547,7 @@
   OnPendingCommitDataLoaded();
   OnSyncStarting();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics9);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics9);
 
   // Put, connect, data.
   ResetStateWriteItem(kKey1, kValue1);
@@ -557,7 +557,7 @@
   EXPECT_EQ(nullptr, worker());
   OnPendingCommitDataLoaded();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics10);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics10);
 
   // Data, connect, delete.
   EntitySpecifics specifics11 = ResetStateWriteItem(kKey1, kValue1);
@@ -566,8 +566,8 @@
   OnSyncStarting();
   bridge()->DeleteItem(kKey1);
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics11);
-  worker()->ExpectNthPendingCommit(1, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics11);
+  worker()->VerifyNthPendingCommit(1, kHash1, kEmptySpecifics);
 
   // Data, delete, connect.
   ResetStateWriteItem(kKey1, kValue1);
@@ -576,7 +576,7 @@
   bridge()->DeleteItem(kKey1);
   OnSyncStarting();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, kEmptySpecifics);
 
   // Connect, data, delete.
   EntitySpecifics specifics12 = ResetStateWriteItem(kKey1, kValue1);
@@ -585,8 +585,8 @@
   OnPendingCommitDataLoaded();
   bridge()->DeleteItem(kKey1);
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics12);
-  worker()->ExpectNthPendingCommit(1, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics12);
+  worker()->VerifyNthPendingCommit(1, kHash1, kEmptySpecifics);
 
   // Connect, delete, data.
   ResetStateWriteItem(kKey1, kValue1);
@@ -596,7 +596,7 @@
   EXPECT_EQ(nullptr, worker());
   OnPendingCommitDataLoaded();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, kEmptySpecifics);
 
   // Delete, data, connect.
   ResetStateWriteItem(kKey1, kValue1);
@@ -605,7 +605,7 @@
   OnPendingCommitDataLoaded();
   OnSyncStarting();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, kEmptySpecifics);
 
   // Delete, connect, data.
   ResetStateWriteItem(kKey1, kValue1);
@@ -615,7 +615,7 @@
   EXPECT_EQ(nullptr, worker());
   OnPendingCommitDataLoaded();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, kEmptySpecifics);
 }
 
 // Tests cases where pending data loads synchronously.
@@ -626,7 +626,7 @@
   InitializeToMetadataLoaded();
   OnSyncStarting();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics1);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics1);
 
   // Sync, model.
   EntitySpecifics specifics2 = ResetStateWriteItem(kKey1, kValue1);
@@ -634,7 +634,7 @@
   bridge()->ExpectSynchronousDataCallback();
   InitializeToMetadataLoaded();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics2);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics2);
 }
 
 // This test covers race conditions during loading a pending delete. All cases
@@ -653,7 +653,7 @@
   InitializeToMetadataLoaded();
   OnSyncStarting();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, kEmptySpecifics);
 
   // Connect, put.
   ResetStateDeleteItem(kKey1, kValue1);
@@ -662,8 +662,8 @@
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
   EntitySpecifics specifics1 = bridge()->WriteItem(kKey1, kValue2);
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
-  worker()->ExpectNthPendingCommit(1, kHash1, specifics1);
+  worker()->VerifyNthPendingCommit(0, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(1, kHash1, specifics1);
 
   // Put, connect.
   ResetStateDeleteItem(kKey1, kValue1);
@@ -671,7 +671,7 @@
   EntitySpecifics specifics2 = bridge()->WriteItem(kKey1, kValue2);
   OnSyncStarting();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics2);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics2);
 
   // Connect, delete.
   ResetStateDeleteItem(kKey1, kValue1);
@@ -680,8 +680,8 @@
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
   bridge()->DeleteItem(kKey1);
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
-  worker()->ExpectNthPendingCommit(1, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(1, kHash1, kEmptySpecifics);
 
   // Delete, connect.
   ResetStateDeleteItem(kKey1, kValue1);
@@ -689,7 +689,7 @@
   bridge()->DeleteItem(kKey1);
   OnSyncStarting();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, kEmptySpecifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, kEmptySpecifics);
 }
 
 // Test that loading a committed item does not queue another commit.
@@ -713,7 +713,7 @@
   bridge()->WriteItem(kKey1, kValue1);
 
   // Verify the commit request this operation has triggered.
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
   const CommitRequestData& tag1_request_data =
       worker()->GetLatestPendingCommitForHash(kHash1);
   const EntityData& tag1_data = tag1_request_data.entity.value();
@@ -826,7 +826,7 @@
 
   bridge()->WriteItem(kKey1, kValue1);
   EXPECT_EQ(1U, db().metadata_count());
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
 
   const CommitRequestData& request_data_v1 =
       worker()->GetLatestPendingCommitForHash(kHash1);
@@ -835,7 +835,7 @@
 
   bridge()->WriteItem(kKey1, kValue2);
   EXPECT_EQ(1U, db().metadata_count());
-  worker()->ExpectPendingCommits({kHash1, kHash1});
+  worker()->VerifyPendingCommits({kHash1, kHash1});
 
   const CommitRequestData& request_data_v2 =
       worker()->GetLatestPendingCommitForHash(kHash1);
@@ -878,10 +878,10 @@
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
   EXPECT_EQ(1U, db().metadata_count());
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
 
   bridge()->WriteItem(kKey1, kValue1);
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
 }
 
 // Thoroughly tests the data generated by a server item creation.
@@ -961,7 +961,7 @@
   // Metadata is not removed until the commit response comes back.
   EXPECT_EQ(1U, db().metadata_count());
   EXPECT_EQ(1U, ProcessorEntityCount());
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
 
   const EntityMetadata metadata_v2 = db().GetMetadata(kKey1);
   EXPECT_TRUE(metadata_v2.is_deleted());
@@ -988,7 +988,7 @@
 TEST_F(SharedModelTypeProcessorTest, LocalDeleteItemInterleaved) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
   const CommitRequestData& data_v1 =
       worker()->GetLatestPendingCommitForHash(kHash1);
 
@@ -1002,7 +1002,7 @@
   EXPECT_EQ(0U, db().data_count());
   EXPECT_EQ(1U, db().metadata_count());
   EXPECT_EQ(1U, ProcessorEntityCount());
-  worker()->ExpectPendingCommits({kHash1, kHash1});
+  worker()->VerifyPendingCommits({kHash1, kHash1});
 
   const CommitRequestData& data_v2 =
       worker()->GetLatestPendingCommitForHash(kHash1);
@@ -1093,7 +1093,7 @@
   const EntityMetadata metadata1 = db().GetMetadata(kKey1);
 
   // There should be one commit request for this item only.
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
 
   bridge()->WriteItem(kKey2, kValue2);
   EXPECT_EQ(2U, db().data_count());
@@ -1101,7 +1101,7 @@
   const EntityMetadata metadata2 = db().GetMetadata(kKey2);
 
   // The second write should trigger another single-item commit request.
-  worker()->ExpectPendingCommits({kHash1, kHash2});
+  worker()->VerifyPendingCommits({kHash1, kHash2});
 
   EXPECT_FALSE(metadata1.is_deleted());
   EXPECT_EQ(1, metadata1.sequence_number());
@@ -1121,8 +1121,8 @@
   EXPECT_EQ(kValue1, db().GetValue(kKey1));
   EXPECT_EQ(1U, db().metadata_change_count());
   EXPECT_EQ(kUncommittedVersion, db().GetMetadata(kKey1).server_version());
-  worker()->ExpectPendingCommits({kHash1});
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics);
+  worker()->VerifyPendingCommits({kHash1});
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics);
 
   // Changes match doesn't call ResolveConflict.
   worker()->UpdateFromServer(kHash1, specifics);
@@ -1130,7 +1130,7 @@
   // Updated metadata but not data; no new commit request.
   EXPECT_EQ(1U, db().data_change_count());
   EXPECT_EQ(1, db().GetMetadata(kKey1).server_version());
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
 }
 
 TEST_F(SharedModelTypeProcessorTest, ConflictResolutionUseLocal) {
@@ -1148,8 +1148,8 @@
   EXPECT_EQ(2U, db().data_change_count());
   EXPECT_EQ(4U, db().metadata_change_count());
   EXPECT_EQ(2, db().GetMetadata(kKey1).server_version());
-  worker()->ExpectPendingCommits({kHash1, kHash1});
-  worker()->ExpectNthPendingCommit(1, kHash1, specifics2);
+  worker()->VerifyPendingCommits({kHash1, kHash1});
+  worker()->VerifyNthPendingCommit(1, kHash1, specifics2);
 }
 
 TEST_F(SharedModelTypeProcessorTest, ConflictResolutionUseRemote) {
@@ -1163,7 +1163,7 @@
   EXPECT_EQ(kValue2, db().GetValue(kKey1));
   EXPECT_EQ(2U, db().metadata_change_count());
   EXPECT_EQ(1, db().GetMetadata(kKey1).server_version());
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
 }
 
 TEST_F(SharedModelTypeProcessorTest, ConflictResolutionUseNew) {
@@ -1177,8 +1177,8 @@
   EXPECT_EQ(kValue3, db().GetValue(kKey1));
   EXPECT_EQ(2U, db().metadata_change_count());
   EXPECT_EQ(1, db().GetMetadata(kKey1).server_version());
-  worker()->ExpectPendingCommits({kHash1, kHash1});
-  worker()->ExpectNthPendingCommit(1, kHash1,
+  worker()->VerifyPendingCommits({kHash1, kHash1});
+  worker()->VerifyNthPendingCommit(1, kHash1,
                                    GenerateSpecifics(kKey1, kValue3));
 }
 
@@ -1246,7 +1246,7 @@
   // themselves uncommitted and pending for commit.
   // The hashes need to be in alphabet order of their storage keys since
   // enabling sync trigered merge and it will reorder the commits.
-  worker()->ExpectPendingCommits({kHash2, kHash3, kHash1});
+  worker()->VerifyPendingCommits({kHash2, kHash3, kHash1});
 }
 
 // Test re-encrypt everything when desired encryption key changes.
@@ -1257,7 +1257,7 @@
   EntitySpecifics specifics1 = WriteItemAndAck(kKey1, kValue1);
   // Create another item and don't wait for its commit response.
   EntitySpecifics specifics2 = bridge()->WriteItem(kKey2, kValue2);
-  worker()->ExpectPendingCommits({kHash2});
+  worker()->VerifyPendingCommits({kHash2});
   EXPECT_EQ(1U, db().GetMetadata(kKey1).sequence_number());
   EXPECT_EQ(1U, db().GetMetadata(kKey2).sequence_number());
 
@@ -1265,7 +1265,7 @@
   worker()->UpdateWithEncryptionKey("k1");
   // Tag 2 is recommitted immediately because the data was in memory.
   ASSERT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(1, kHash2, specifics2);
+  worker()->VerifyNthPendingCommit(1, kHash2, specifics2);
   // Sequence numbers in the store are updated.
   EXPECT_EQ(2U, db().GetMetadata(kKey1).sequence_number());
   EXPECT_EQ(2U, db().GetMetadata(kKey2).sequence_number());
@@ -1273,7 +1273,7 @@
   // Tag 1 needs to go to the store to load its data before recommitting.
   OnPendingCommitDataLoaded();
   ASSERT_EQ(3U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(2, kHash1, specifics1);
+  worker()->VerifyNthPendingCommit(2, kHash1, specifics1);
 }
 
 // Test that an error loading pending commit data for re-encryption is
@@ -1305,22 +1305,22 @@
   worker()->UpdateWithEncryptionKey("k2", update);
 
   // kKey2 needed to be re-encrypted and had data so it was queued immediately.
-  worker()->ExpectPendingCommits({kHash2});
+  worker()->VerifyPendingCommits({kHash2});
   OnPendingCommitDataLoaded();
   // kKey1 needed data so once that's loaded, it is also queued.
-  worker()->ExpectPendingCommits({kHash2, kHash1});
+  worker()->VerifyPendingCommits({kHash2, kHash1});
 
   // Receive a separate update that was encrypted with key k1.
   worker()->UpdateFromServer(kHash4, GenerateSpecifics(kKey4, kValue1), 1,
                              "k1");
   // Receipt of updates encrypted with old key also forces a re-encrypt commit.
-  worker()->ExpectPendingCommits({kHash2, kHash1, kHash4});
+  worker()->VerifyPendingCommits({kHash2, kHash1, kHash4});
 
   // Receive an update that was encrypted with key k2.
   worker()->UpdateFromServer(kHash5, GenerateSpecifics(kKey5, kValue1), 1,
                              "k2");
   // That was the correct key, so no re-encryption is required.
-  worker()->ExpectPendingCommits({kHash2, kHash1, kHash4});
+  worker()->VerifyPendingCommits({kHash2, kHash1, kHash4});
 }
 
 // Test that re-encrypting enqueues the right data for USE_LOCAL conflicts.
@@ -1330,7 +1330,7 @@
   WriteItemAndAck(kKey1, kValue1);
   worker()->UpdateWithEncryptionKey("k1");
   EntitySpecifics specifics = bridge()->WriteItem(kKey1, kValue2);
-  worker()->ExpectPendingCommits({kHash1});
+  worker()->VerifyPendingCommits({kHash1});
 
   bridge()->SetConflictResolution(ConflictResolution::UseLocal());
   // Unencrypted update needs to be re-commited with key k1.
@@ -1338,7 +1338,7 @@
 
   // Ensure the re-commit has the correct value.
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(1, kHash1, specifics);
+  worker()->VerifyNthPendingCommit(1, kHash1, specifics);
   EXPECT_EQ(kValue2, db().GetValue(kKey1));
 
   // GetData was launched as a result of UpdateWithEncryptionKey(). Since the
@@ -1361,7 +1361,7 @@
 
   // Ensure the re-commit has the correct value.
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(1, kHash1, specifics);
+  worker()->VerifyNthPendingCommit(1, kHash1, specifics);
   EXPECT_EQ(kValue2, db().GetValue(kKey1));
 }
 
@@ -1378,7 +1378,7 @@
 
   // Ensure the re-commit has the correct value.
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(1, kHash1,
+  worker()->VerifyNthPendingCommit(1, kHash1,
                                    GenerateSpecifics(kKey1, kValue3));
   EXPECT_EQ(kValue3, db().GetValue(kKey1));
 }
@@ -1397,7 +1397,7 @@
 
   // Ensure the re-commit has the correct value.
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics);
   EXPECT_EQ(kValue2, db().GetValue(kKey1));
 
   // Data load completing shouldn't change anything.
@@ -1412,7 +1412,7 @@
   worker()->UpdateWithEncryptionKey("k1");
   OnPendingCommitDataLoaded();
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics);
 
   worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2));
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
@@ -1429,7 +1429,7 @@
   worker()->UpdateWithEncryptionKey("k1", update);
 
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(1, kHash1, specifics2);
+  worker()->VerifyNthPendingCommit(1, kHash1, specifics2);
 }
 
 // Same as above but with two commit requests before one ack.
@@ -1442,14 +1442,14 @@
   worker()->AckOnePendingCommit();
   // kValue2 is now the base value.
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(0, kHash1, specifics2);
+  worker()->VerifyNthPendingCommit(0, kHash1, specifics2);
 
   UpdateResponseDataList update;
   update.push_back(worker()->GenerateUpdateData(kHash1, specifics1, 1, "k1"));
   worker()->UpdateWithEncryptionKey("k1", update);
 
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->ExpectNthPendingCommit(1, kHash1, specifics2);
+  worker()->VerifyNthPendingCommit(1, kHash1, specifics2);
 }
 
 }  // namespace syncer
diff --git a/components/sync/protocol/proto_enum_conversions.cc b/components/sync/protocol/proto_enum_conversions.cc
index 8824edf..2ff77244 100644
--- a/components/sync/protocol/proto_enum_conversions.cc
+++ b/components/sync/protocol/proto_enum_conversions.cc
@@ -313,6 +313,8 @@
 
 const char* ProtoEnumToString(
     sync_pb::WalletMaskedCreditCard::WalletCardClass wallet_card_class) {
+  ASSERT_ENUM_BOUNDS(sync_pb::WalletMaskedCreditCard, WalletCardClass,
+                     UNKNOWN_CARD_CLASS, PREPAID);
   switch (wallet_card_class) {
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, UNKNOWN_CARD_CLASS);
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, CREDIT);
@@ -325,6 +327,8 @@
 
 const char* ProtoEnumToString(
     sync_pb::WalletMaskedCreditCard::WalletCardStatus wallet_card_status) {
+  ASSERT_ENUM_BOUNDS(sync_pb::WalletMaskedCreditCard, WalletCardStatus, VALID,
+                     EXPIRED);
   switch (wallet_card_status) {
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, VALID);
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, EXPIRED);
@@ -335,6 +339,8 @@
 
 const char* ProtoEnumToString(
     sync_pb::WalletMaskedCreditCard::WalletCardType wallet_card_type) {
+  ASSERT_ENUM_BOUNDS(sync_pb::WalletMaskedCreditCard, WalletCardType, UNKNOWN,
+                     UNIONPAY);
   switch (wallet_card_type) {
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, UNKNOWN);
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, AMEX);
@@ -344,8 +350,8 @@
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, MASTER_CARD);
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, SOLO);
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, SWITCH);
-    ENUM_CASE(sync_pb::WalletMaskedCreditCard, UNIONPAY);
     ENUM_CASE(sync_pb::WalletMaskedCreditCard, VISA);
+    ENUM_CASE(sync_pb::WalletMaskedCreditCard, UNIONPAY);
   }
   NOTREACHED();
   return "";
diff --git a/components/sync/test/engine/mock_connection_manager.cc b/components/sync/test/engine/mock_connection_manager.cc
index 79b5b3a..64952a54 100644
--- a/components/sync/test/engine/mock_connection_manager.cc
+++ b/components/sync/test/engine/mock_connection_manager.cc
@@ -5,6 +5,7 @@
 #include "components/sync/test/engine/mock_connection_manager.h"
 
 #include <map>
+#include <utility>
 
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
@@ -230,13 +231,13 @@
 }
 
 void MockConnectionManager::SetGUClientCommand(
-    sync_pb::ClientCommand* command) {
-  gu_client_command_.reset(command);
+    std::unique_ptr<sync_pb::ClientCommand> command) {
+  gu_client_command_ = std::move(command);
 }
 
 void MockConnectionManager::SetCommitClientCommand(
-    sync_pb::ClientCommand* command) {
-  commit_client_command_.reset(command);
+    std::unique_ptr<sync_pb::ClientCommand> command) {
+  commit_client_command_ = std::move(command);
 }
 
 void MockConnectionManager::SetTransientErrorId(syncable::Id id) {
diff --git a/components/sync/test/engine/mock_connection_manager.h b/components/sync/test/engine/mock_connection_manager.h
index 6af40a6..fba4317c 100644
--- a/components/sync/test/engine/mock_connection_manager.h
+++ b/components/sync/test/engine/mock_connection_manager.h
@@ -177,9 +177,8 @@
   // Simple inspectors.
   bool client_stuck() const { return client_stuck_; }
 
-  // warning: These take ownership of their input.
-  void SetGUClientCommand(sync_pb::ClientCommand* command);
-  void SetCommitClientCommand(sync_pb::ClientCommand* command);
+  void SetGUClientCommand(std::unique_ptr<sync_pb::ClientCommand> command);
+  void SetCommitClientCommand(std::unique_ptr<sync_pb::ClientCommand> command);
 
   void SetTransientErrorId(syncable::Id);
 
diff --git a/components/sync/test/engine/mock_model_type_worker.cc b/components/sync/test/engine/mock_model_type_worker.cc
index 2d87fc2..ac53569 100644
--- a/components/sync/test/engine/mock_model_type_worker.cc
+++ b/components/sync/test/engine/mock_model_type_worker.cc
@@ -70,7 +70,7 @@
   return CommitRequestData();
 }
 
-void MockModelTypeWorker::ExpectNthPendingCommit(
+void MockModelTypeWorker::VerifyNthPendingCommit(
     size_t n,
     const std::string& tag_hash,
     const sync_pb::EntitySpecifics& specifics) {
@@ -81,7 +81,7 @@
   EXPECT_EQ(specifics.SerializeAsString(), data.specifics.SerializeAsString());
 }
 
-void MockModelTypeWorker::ExpectPendingCommits(
+void MockModelTypeWorker::VerifyPendingCommits(
     const std::vector<std::string>& tag_hashes) {
   EXPECT_EQ(tag_hashes.size(), GetNumPendingCommits());
   for (size_t i = 0; i < tag_hashes.size(); i++) {
diff --git a/components/sync/test/engine/mock_model_type_worker.h b/components/sync/test/engine/mock_model_type_worker.h
index 28ad55a..0e3cac7 100644
--- a/components/sync/test/engine/mock_model_type_worker.h
+++ b/components/sync/test/engine/mock_model_type_worker.h
@@ -43,15 +43,15 @@
   CommitRequestData GetLatestPendingCommitForHash(
       const std::string& tag_hash) const;
 
-  // Expect that the |n|th commit request list has one commit request for |tag|
+  // Verify that the |n|th commit request list has one commit request for |tag|
   // with |value| set.
-  void ExpectNthPendingCommit(size_t n,
+  void VerifyNthPendingCommit(size_t n,
                               const std::string& tag_hash,
                               const sync_pb::EntitySpecifics& specifics);
 
-  // For each hash in |tag_hashes|, expect a corresponding request list of
-  // length one.
-  void ExpectPendingCommits(const std::vector<std::string>& tag_hashes);
+  // Verify the pending commits each contain a single CommitRequestData and they
+  // have the same hashes in the same order as |tag_hashes|.
+  void VerifyPendingCommits(const std::vector<std::string>& tag_hashes);
 
   // Trigger an update from the server. See GenerateUpdateData for parameter
   // descriptions. |version_offset| defaults to 1 and |ekn| defaults to the
diff --git a/components/web_resource/OWNERS b/components/web_resource/OWNERS
index ed07838..0173e25 100644
--- a/components/web_resource/OWNERS
+++ b/components/web_resource/OWNERS
@@ -1,5 +1,4 @@
 achuith@chromium.org
-dbeam@chromium.org
 rsesek@chromium.org
 
 # For ResourceRequestAllowedNotifier and EulaAcceptedNotifier:
diff --git a/components/zoom/OWNERS b/components/zoom/OWNERS
index 2cd925c..fd016d7 100644
--- a/components/zoom/OWNERS
+++ b/components/zoom/OWNERS
@@ -1,4 +1,3 @@
-dbeam@chromium.org
 wjmaclean@chromium.org
 
 # COMPONENT: UI>Browser>Zoom
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc
index b1fb4d6..770362c8 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -11,7 +11,6 @@
 
 #include "base/command_line.h"
 #include "base/win/win_util.h"
-#include "base/win/windows_version.h"
 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/accessibility/browser_accessibility_win.h"
@@ -123,8 +122,7 @@
 }
 
 bool LegacyRenderWidgetHostHWND::Init() {
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7)
-    RegisterTouchWindow(hwnd(), TWF_WANTPALM);
+  RegisterTouchWindow(hwnd(), TWF_WANTPALM);
 
   HRESULT hr = ::CreateStdAccessibleObject(hwnd(), OBJID_WINDOW,
                                            IID_PPV_ARGS(&window_accessible_));
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 4e79b0bf..0b66264 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1052,6 +1052,9 @@
                mouse_event.PositionInWidget().x, "y",
                mouse_event.PositionInWidget().y);
 
+  DCHECK_GE(mouse_event.GetType(), blink::WebInputEvent::kMouseTypeFirst);
+  DCHECK_LE(mouse_event.GetType(), blink::WebInputEvent::kMouseTypeLast);
+
   for (size_t i = 0; i < mouse_event_callbacks_.size(); ++i) {
     if (mouse_event_callbacks_[i].Run(mouse_event))
       return;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index e0ca6486..7e558ed 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -385,6 +385,7 @@
                            ForwardsBeginFrameAcks);
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
                            VirtualKeyboardFocusEnsureCaretInRect);
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, PopupMenuTest);
   FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest,
                            WebContentsViewReparent);
 
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 0812caa..cbbedc1 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -6475,9 +6475,20 @@
 
   filter->Wait();
 
-  RenderWidgetHostView* popup_view =
+  RenderWidgetHostViewAura* popup_view = static_cast<RenderWidgetHostViewAura*>(
       RenderWidgetHost::FromID(process_id, filter->last_routing_id())
-          ->GetView();
+          ->GetView());
+  // The IO thread posts to ViewMsg_ShowWidget handlers in both the message
+  // filter above and the WebContents, which initializes the popup's view.
+  // It is possible for this code to execute before the WebContents handler,
+  // in which case OnMouseEvent would be called on an uninitialized RWHVA.
+  // This loop ensures that the initialization completes before proceeding.
+  while (!popup_view->window()) {
+    base::RunLoop loop;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  loop.QuitClosure());
+    loop.Run();
+  }
 
   RenderWidgetHostMouseEventMonitor popup_monitor(
       popup_view->GetRenderWidgetHost());
@@ -6489,8 +6500,7 @@
                                 gfx::Point(10, 5), ui::EventTimeForNow(),
                                 ui::EF_LEFT_MOUSE_BUTTON,
                                 ui::EF_LEFT_MOUSE_BUTTON);
-  static_cast<RenderWidgetHostViewAura*>(popup_view)
-      ->OnMouseEvent(&mouse_up_event);
+  popup_view->OnMouseEvent(&mouse_up_event);
 
   // This verifies that the popup actually received the event, and it wasn't
   // diverted to a different RenderWidgetHostView due to mouse capture.
diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc
index 3d6f9b80..3963c6e 100644
--- a/content/common/sandbox_win.cc
+++ b/content/common/sandbox_win.cc
@@ -403,7 +403,7 @@
   sandbox::ResultCode result = sandbox::SBOX_ALL_OK;
 
   // Win8+ adds a device DeviceApi that we don't need.
-  if (base::win::GetVersion() > base::win::VERSION_WIN7)
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
     result = policy->AddKernelObjectToClose(L"File", L"\\Device\\DeviceApi");
   if (result != sandbox::SBOX_ALL_OK)
     return result;
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index ebd62ac..39c079d 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -58,7 +58,6 @@
 
 #if defined(OS_WIN)
 #include "base/win/win_util.h"
-#include "base/win/windows_version.h"
 #include "content/child/font_warmup_win.h"
 #include "sandbox/win/src/sandbox.h"
 #elif defined(OS_MACOSX)
@@ -75,10 +74,6 @@
 extern sandbox::TargetServices* g_target_services;
 
 // Used by EnumSystemLocales for warming up.
-static BOOL CALLBACK EnumLocalesProc(LPTSTR lpLocaleString) {
-  return TRUE;
-}
-
 static BOOL CALLBACK EnumLocalesProcEx(
     LPWSTR lpLocaleString,
     DWORD dwFlags,
@@ -91,21 +86,8 @@
   ::GetUserDefaultLangID();
   ::GetUserDefaultLCID();
 
-  if (permissions.HasPermission(ppapi::PERMISSION_FLASH)) {
-    if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
-      typedef BOOL (WINAPI *PfnEnumSystemLocalesEx)
-          (LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
-
-      HMODULE handle_kern32 = GetModuleHandleW(L"Kernel32.dll");
-      PfnEnumSystemLocalesEx enum_sys_locales_ex =
-          reinterpret_cast<PfnEnumSystemLocalesEx>
-              (GetProcAddress(handle_kern32, "EnumSystemLocalesEx"));
-
-      enum_sys_locales_ex(EnumLocalesProcEx, LOCALE_WINDOWS, 0, 0);
-    } else {
-      EnumSystemLocalesW(EnumLocalesProc, LCID_INSTALLED);
-    }
-  }
+  if (permissions.HasPermission(ppapi::PERMISSION_FLASH))
+    ::EnumSystemLocalesEx(EnumLocalesProcEx, LOCALE_WINDOWS, 0, 0);
 }
 
 #endif
@@ -415,28 +397,22 @@
   // can be loaded. TODO(cpu): consider changing to the loading style of
   // regular plugins.
   if (g_target_services) {
-    // Let Flash and Widevine CDM adapter load DXVA before lockdown on Vista+.
+    // Let Flash and Widevine CDM adapter load DXVA before lockdown.
     if (permissions.HasPermission(ppapi::PERMISSION_FLASH) ||
         path.BaseName().MaybeAsASCII() == kWidevineCdmAdapterFileName) {
-      if (base::win::OSInfo::GetInstance()->version() >=
-          base::win::VERSION_VISTA) {
-        LoadLibraryA("dxva2.dll");
-      }
+      LoadLibraryA("dxva2.dll");
     }
 
     if (permissions.HasPermission(ppapi::PERMISSION_FLASH)) {
-      if (base::win::OSInfo::GetInstance()->version() >=
-          base::win::VERSION_WIN7) {
-        base::CPU cpu;
-        if (cpu.vendor_name() == "AuthenticAMD") {
-          // The AMD crypto acceleration is only AMD Bulldozer and above.
+      base::CPU cpu;
+      if (cpu.vendor_name() == "AuthenticAMD") {
+        // The AMD crypto acceleration is only AMD Bulldozer and above.
 #if defined(_WIN64)
-          LoadLibraryA("amdhcp64.dll");
+        LoadLibraryA("amdhcp64.dll");
 #else
-          LoadLibraryA("amdhcp32.dll");
+        LoadLibraryA("amdhcp32.dll");
 #endif
         }
-      }
     }
 
     // Cause advapi32 to load before the sandbox is turned on.
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index fcf333ed..25b9c8c8 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -271,11 +271,7 @@
   IPC_STRUCT_TRAITS_MEMBER(menu_bar_visible)
   IPC_STRUCT_TRAITS_MEMBER(status_bar_visible)
   IPC_STRUCT_TRAITS_MEMBER(tool_bar_visible)
-  IPC_STRUCT_TRAITS_MEMBER(location_bar_visible)
   IPC_STRUCT_TRAITS_MEMBER(scrollbars_visible)
-  IPC_STRUCT_TRAITS_MEMBER(resizable)
-  IPC_STRUCT_TRAITS_MEMBER(fullscreen)
-  IPC_STRUCT_TRAITS_MEMBER(dialog)
 IPC_STRUCT_TRAITS_END()
 
 IPC_ENUM_TRAITS_MAX_VALUE(ui::AXEvent, ui::AX_EVENT_LAST)
diff --git a/content/public/renderer/window_features_converter.cc b/content/public/renderer/window_features_converter.cc
index 84f75f6..b8dc864 100644
--- a/content/public/renderer/window_features_converter.cc
+++ b/content/public/renderer/window_features_converter.cc
@@ -20,11 +20,7 @@
   result->menu_bar_visible = web_window_features.menu_bar_visible;
   result->status_bar_visible = web_window_features.status_bar_visible;
   result->tool_bar_visible = web_window_features.tool_bar_visible;
-  result->location_bar_visible = web_window_features.location_bar_visible;
   result->scrollbars_visible = web_window_features.scrollbars_visible;
-  result->resizable = web_window_features.resizable;
-  result->fullscreen = web_window_features.fullscreen;
-  result->dialog = web_window_features.dialog;
   return result;
 }
 
@@ -42,11 +38,7 @@
   result.menu_bar_visible = window_features.menu_bar_visible;
   result.status_bar_visible = window_features.status_bar_visible;
   result.tool_bar_visible = window_features.tool_bar_visible;
-  result.location_bar_visible = window_features.location_bar_visible;
   result.scrollbars_visible = window_features.scrollbars_visible;
-  result.resizable = window_features.resizable;
-  result.fullscreen = window_features.fullscreen;
-  result.dialog = window_features.dialog;
   return result;
 }
 
diff --git a/content/renderer/media/media_stream_constraints_util_video_content.cc b/content/renderer/media/media_stream_constraints_util_video_content.cc
index d71fe79..be48325 100644
--- a/content/renderer/media/media_stream_constraints_util_video_content.cc
+++ b/content/renderer/media/media_stream_constraints_util_video_content.cc
@@ -35,6 +35,7 @@
 static_assert(kDefaultScreenCastHeight <= kMaxScreenCastDimension,
               "Invalid kDefaultScreenCastHeight");
 
+const double kMinScreenCastFrameRate = 1.0 / 60.0;
 const double kMaxScreenCastFrameRate = 120.0;
 const double kDefaultScreenCastFrameRate =
     MediaStreamVideoSource::kDefaultFrameRate;
@@ -383,7 +384,7 @@
   VideoContentCaptureCandidates candidates;
   candidates.set_resolution_set(ScreenCastResolutionCapabilities());
   candidates.set_frame_rate_set(
-      DoubleRangeSet(0.0, kMaxScreenCastFrameRate));
+      DoubleRangeSet(kMinScreenCastFrameRate, kMaxScreenCastFrameRate));
   // candidates.device_id_set and candidates.noise_reduction_set are
   // automatically initialized with the universal set.
 
diff --git a/content/renderer/media/media_stream_constraints_util_video_content.h b/content/renderer/media/media_stream_constraints_util_video_content.h
index 8ef6ccf..26ea044 100644
--- a/content/renderer/media/media_stream_constraints_util_video_content.h
+++ b/content/renderer/media/media_stream_constraints_util_video_content.h
@@ -23,6 +23,7 @@
 CONTENT_EXPORT extern const int kDefaultScreenCastHeight;
 CONTENT_EXPORT extern const double kDefaultScreenCastAspectRatio;
 
+CONTENT_EXPORT extern const double kMinScreenCastFrameRate;
 CONTENT_EXPORT extern const double kMaxScreenCastFrameRate;
 CONTENT_EXPORT extern const double kDefaultScreenCastFrameRate;
 
diff --git a/content/renderer/media/media_stream_constraints_util_video_content_unittest.cc b/content/renderer/media/media_stream_constraints_util_video_content_unittest.cc
index c31bef3..ae8ac1e 100644
--- a/content/renderer/media/media_stream_constraints_util_video_content_unittest.cc
+++ b/content/renderer/media/media_stream_constraints_util_video_content_unittest.cc
@@ -21,7 +21,6 @@
   EXPECT_EQ(kDefaultScreenCastFrameRate, result.FrameRate());
   EXPECT_EQ(base::Optional<bool>(), result.noise_reduction());
   EXPECT_EQ(std::string(), result.device_id());
-  EXPECT_EQ(0.0, result.min_frame_rate());
 }
 
 void CheckNonFrameRateDefaults(const VideoCaptureSettings& result) {
@@ -167,7 +166,7 @@
             result.failed_constraint_name());
 
   constraint_factory_.Reset();
-  constraint_factory_.basic().frame_rate.SetMax(-0.1);
+  constraint_factory_.basic().frame_rate.SetMax(kMinScreenCastFrameRate - 0.1);
   result = SelectSettings();
   EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().frame_rate.GetName(),
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 35718fb..afd133a 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -528,29 +528,10 @@
   ui::LatencyInfo latency_info_;
 };
 
-const char kWindowFeatureBackground[] = "background";
-const char kWindowFeaturePersistent[] = "persistent";
-
 content::mojom::WindowContainerType WindowFeaturesToContainerType(
     const blink::WebWindowFeatures& window_features) {
-  bool background = false;
-  bool persistent = false;
-
-  for (size_t i = 0; i < window_features.additional_features.size(); ++i) {
-    blink::WebString feature = window_features.additional_features[i];
-    if (feature.ContainsOnlyASCII()) {
-      std::string featureASCII = feature.Ascii();
-      if (base::LowerCaseEqualsASCII(featureASCII, kWindowFeatureBackground)) {
-        background = true;
-      } else if (base::LowerCaseEqualsASCII(featureASCII,
-                                            kWindowFeaturePersistent)) {
-        persistent = true;
-      }
-    }
-  }
-
-  if (background) {
-    if (persistent)
+  if (window_features.background) {
+    if (window_features.persistent)
       return content::mojom::WindowContainerType::PERSISTENT;
     else
       return content::mojom::WindowContainerType::BACKGROUND;
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 3111fbd..a755fd51 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -102,6 +102,21 @@
         ['win10', ('nvidia', 0x1cb3), 'd3d11'], bug=680754)
     self.Fail('deqp/functional/gles3/transformfeedback/interpolation_flat.html',
         ['win10', ('nvidia', 0x1cb3), 'd3d11'], bug=680754)
+    self.Flaky('conformance2/textures/video/tex-3d-rgba32f-rgba-float.html',
+        ['win10', ('nvidia', 0x1cb3)], bug=728670)
+    self.Flaky('conformance2/textures/image_bitmap_from_video/' +
+        'tex-3d-rg16f-rg-half_float.html',
+        ['win10', ('nvidia', 0x1cb3)], bug=728670)
+    self.Flaky('conformance2/textures/image_bitmap_from_video/' +
+        'tex-3d-rgba8ui-rgba_integer-unsigned_byte.html',
+        ['win10', ('nvidia', 0x1cb3)], bug=728670)
+    self.Flaky('conformance2/textures/video/tex-3d-rgb9_e5-rgb-half_float.html',
+        ['win10', ('nvidia', 0x1cb3)], bug=728670)
+    self.Flaky('conformance2/textures/video/' +
+        'tex-3d-rg8ui-rg_integer-unsigned_byte.html',
+        ['win10', ('nvidia', 0x1cb3)], bug=728670)
+    self.Flaky('conformance/extensions/oes-texture-half-float-with-video.html',
+        ['win10', ('nvidia', 0x1cb3)], bug=728670)
 
     # Win / NVIDIA / OpenGL
     self.Fail('conformance2/rendering/framebuffer-texture-level1.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 5c8ce544..0212732e 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -235,6 +235,12 @@
         ['win10', ('nvidia', 0x1cb3)], bug=715001)
     self.Fail('conformance/ogles/GL/cos/cos_001_to_006.html',
         ['win10', ('nvidia', 0x1cb3), 'd3d9'], bug=680754)
+    self.Flaky('conformance/textures/image_bitmap_from_video/' +
+        'tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html',
+        ['win10', ('nvidia', 0x1cb3)], bug=728670)
+    self.Flaky('conformance/textures/image_bitmap_from_video/' +
+        'tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html',
+        ['win10', ('nvidia', 0x1cb3)], bug=728670)
 
     # Win7 / Intel failures
     self.Fail('conformance/textures/misc/' +
diff --git a/device/gamepad/gamepad_platform_data_fetcher_win.cc b/device/gamepad/gamepad_platform_data_fetcher_win.cc
index 42404e0..2f2f7ac 100644
--- a/device/gamepad/gamepad_platform_data_fetcher_win.cc
+++ b/device/gamepad/gamepad_platform_data_fetcher_win.cc
@@ -68,14 +68,10 @@
   // Xinput.h specifies it in build time. Approach here uses the same values
   // and it is resolving dll filename based on Windows version it is running on.
   if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
-    // For Windows 8 and 10, XINPUT_DLL is xinput1_4.dll.
+    // For Windows 8+, XINPUT_DLL is xinput1_4.dll.
     return FILE_PATH_LITERAL("xinput1_4.dll");
-  } else if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
-    return FILE_PATH_LITERAL("xinput9_1_0.dll");
-  } else {
-    NOTREACHED();
-    return nullptr;
   }
+  return FILE_PATH_LITERAL("xinput9_1_0.dll");
 }
 
 }  // namespace
diff --git a/device/power_save_blocker/power_save_blocker_win.cc b/device/power_save_blocker/power_save_blocker_win.cc
index 2d257224..83830a7 100644
--- a/device/power_save_blocker/power_save_blocker_win.cc
+++ b/device/power_save_blocker/power_save_blocker_win.cc
@@ -17,12 +17,10 @@
 namespace device {
 namespace {
 
-int g_blocker_count[2];
-
 HANDLE CreatePowerRequest(POWER_REQUEST_TYPE type,
                           const std::string& description) {
   if (type == PowerRequestExecutionRequired &&
-      base::win::GetVersion() < base::win::VERSION_WIN8) {
+      base::win::GetVersion() == base::win::VERSION_WIN7) {
     return INVALID_HANDLE_VALUE;
   }
 
@@ -51,7 +49,7 @@
     return;
 
   if (type == PowerRequestExecutionRequired &&
-      base::win::GetVersion() < base::win::VERSION_WIN8) {
+      base::win::GetVersion() == base::win::VERSION_WIN7) {
     return;
   }
 
@@ -59,30 +57,6 @@
   DCHECK(success);
 }
 
-void ApplySimpleBlock(PowerSaveBlocker::PowerSaveBlockerType type, int delta) {
-  g_blocker_count[type] += delta;
-  DCHECK_GE(g_blocker_count[type], 0);
-
-  if (g_blocker_count[type] > 1)
-    return;
-
-  DWORD this_flag = 0;
-  if (type == PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension)
-    this_flag |= ES_SYSTEM_REQUIRED;
-  else
-    this_flag |= ES_DISPLAY_REQUIRED;
-
-  DCHECK(this_flag);
-
-  static DWORD flags = ES_CONTINUOUS;
-  if (!g_blocker_count[type])
-    flags &= ~this_flag;
-  else
-    flags |= this_flag;
-
-  SetThreadExecutionState(flags);
-}
-
 }  // namespace
 
 class PowerSaveBlocker::Delegate
@@ -116,17 +90,11 @@
 
 void PowerSaveBlocker::Delegate::ApplyBlock() {
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return ApplySimpleBlock(type_, 1);
-
   handle_.Set(CreatePowerRequest(RequestType(), description_));
 }
 
 void PowerSaveBlocker::Delegate::RemoveBlock() {
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return ApplySimpleBlock(type_, -1);
-
   DeletePowerRequest(RequestType(), handle_.Take());
 }
 
@@ -134,7 +102,7 @@
   if (type_ == kPowerSaveBlockPreventDisplaySleep)
     return PowerRequestDisplayRequired;
 
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+  if (base::win::GetVersion() == base::win::VERSION_WIN7)
     return PowerRequestSystemRequired;
 
   return PowerRequestExecutionRequired;
diff --git a/device/sensors/data_fetcher_shared_memory_win.cc b/device/sensors/data_fetcher_shared_memory_win.cc
index 4ec59fa..e7345c2 100644
--- a/device/sensors/data_fetcher_shared_memory_win.cc
+++ b/device/sensors/data_fetcher_shared_memory_win.cc
@@ -14,7 +14,6 @@
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/win/iunknown_impl.h"
-#include "base/win/windows_version.h"
 
 namespace {
 
@@ -313,9 +312,6 @@
     REFSENSOR_TYPE_ID sensor_type,
     ISensor** sensor,
     scoped_refptr<SensorEventSink> event_sink) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return false;
-
   base::win::ScopedComPtr<ISensorManager> sensor_manager;
   HRESULT hr = ::CoCreateInstance(CLSID_SensorManager, nullptr, CLSCTX_ALL,
                                   IID_PPV_ARGS(&sensor_manager));
diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc
index edbf4e1..c346cba 100644
--- a/gpu/command_buffer/service/command_buffer_service.cc
+++ b/gpu/command_buffer/service/command_buffer_service.cc
@@ -148,7 +148,8 @@
 }
 
 void CommandBufferService::SetReleaseCount(uint64_t release_count) {
-  DCHECK(release_count >= state_.release_count);
+  DLOG_IF(ERROR, release_count < state_.release_count)
+      << "Non-monotonic SetReleaseCount";
   state_.release_count = release_count;
   UpdateState();
 }
diff --git a/ios/chrome/browser/tabs/DEPS b/ios/chrome/browser/tabs/DEPS
index da8e45d..8a3f4f299 100644
--- a/ios/chrome/browser/tabs/DEPS
+++ b/ios/chrome/browser/tabs/DEPS
@@ -1,14 +1,12 @@
 specific_include_rules = {
   # TODO(crbug.com/620465): Remove tab.mm and tab_unittest.mm exceptions.
   "^tab\.mm$": [
-    "+ios/web/navigation/crw_session_controller.h",
     "+ios/web/navigation/navigation_item_impl.h",
     "+ios/web/web_state/web_state_impl.h",
     "+ios/web/web_state/ui/crw_web_controller.h",
     "+ios/web/navigation/navigation_manager_impl.h",
   ],
   "^tab_unittest\.mm$": [
-    "+ios/web/navigation/crw_session_controller.h",
     "+ios/web/web_state/ui/crw_web_controller.h",
     "+ios/web/web_state/navigation_context_impl.h",
     "+ios/web/navigation/navigation_manager_impl.h",
@@ -17,13 +15,10 @@
 
   # TODO(crbug.com/620480): Remove tab.mm and tab_unittest.mm exceptions.
   "^tab_model\.mm$": [
-    "+ios/web/navigation/crw_session_certificate_policy_manager.h",
-    "+ios/web/navigation/crw_session_controller.h",
     "+ios/web/web_state/web_state_impl.h",
     "+ios/web/web_state/ui/crw_web_controller.h",
   ],
   "^tab_model_unittest\.mm$": [
-    "+ios/web/navigation/crw_session_controller.h",
     "+ios/web/web_state/ui/crw_web_controller.h",
     "+ios/web/web_state/web_state_impl.h",
     "+ios/web/navigation/navigation_manager_impl.h",
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index 02a6e52..504933b2 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -108,7 +108,6 @@
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_metadata.h"
 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_whitelist_manager.h"
-#import "ios/web/navigation/crw_session_controller.h"
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #include "ios/web/public/favicon_status.h"
@@ -1076,14 +1075,9 @@
 
 - (void)goToItem:(const web::NavigationItem*)item {
   DCHECK(item);
-
-  if (self.navigationManager) {
-    CRWSessionController* sessionController =
-        [self navigationManagerImpl]->GetSessionController();
-    NSInteger itemIndex = [sessionController indexOfItem:item];
-    DCHECK_NE(itemIndex, NSNotFound);
-    self.navigationManager->GoToIndex(itemIndex);
-  }
+  int index = self.navigationManager->GetIndexOfItem(item);
+  DCHECK_NE(index, -1);
+  self.navigationManager->GoToIndex(index);
 }
 
 - (BOOL)openExternalURL:(const GURL&)url
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm
index 9857518..e1131973 100644
--- a/ios/chrome/browser/tabs/tab_model_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -25,7 +25,6 @@
 #import "ios/chrome/browser/web/chrome_web_client.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h"
-#import "ios/web/navigation/crw_session_controller.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #import "ios/web/public/crw_session_storage.h"
 #import "ios/web/public/navigation_manager.h"
@@ -846,7 +845,7 @@
                                 inBackground:NO];
   // Force the history to update, as it is used to determine grouping.
   ASSERT_TRUE([parent navigationManagerImpl]);
-  [[parent navigationManagerImpl]->GetSessionController() commitPendingItem];
+  [parent navigationManagerImpl]->CommitPendingItem();
   [tab_model_ insertTabWithURL:GURL(kURL1)
                       referrer:web::Referrer()
                     transition:ui::PAGE_TRANSITION_TYPED
@@ -894,7 +893,7 @@
   parent_params.transition_type = ui::PAGE_TRANSITION_TYPED;
   [parent navigationManager]->LoadURLWithParams(parent_params);
   ASSERT_TRUE([parent navigationManagerImpl]);
-  [[parent navigationManagerImpl]->GetSessionController() commitPendingItem];
+  [parent navigationManagerImpl]->CommitPendingItem();
   EXPECT_EQ([tab_model_ indexOfTab:parent], 0U);
 
   // Add a new tab. It should be added behind the parent. It should not be added
@@ -947,7 +946,7 @@
                                 inBackground:NO];
   // Force the history to update, as it is used to determine grouping.
   ASSERT_TRUE([parent navigationManagerImpl]);
-  [[parent navigationManagerImpl]->GetSessionController() commitPendingItem];
+  [parent navigationManagerImpl]->CommitPendingItem();
   [tab_model_ insertTabWithURL:GURL(kURL1)
                       referrer:web::Referrer()
                     transition:ui::PAGE_TRANSITION_TYPED
diff --git a/ios/chrome/browser/tabs/tab_unittest.mm b/ios/chrome/browser/tabs/tab_unittest.mm
index 6b4f1c0..8ff8547 100644
--- a/ios/chrome/browser/tabs/tab_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_unittest.mm
@@ -39,7 +39,6 @@
 #import "ios/public/provider/chrome/browser/native_app_launcher/fake_native_app_whitelist_manager.h"
 #include "ios/public/provider/chrome/browser/test_chrome_browser_provider.h"
 #import "ios/testing/ocmock_complex_type_helper.h"
-#import "ios/web/navigation/crw_session_controller.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #include "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
@@ -251,7 +250,7 @@
             web_state_impl_.get(), redirectUrl,
             ui::PageTransition::PAGE_TRANSITION_TYPED);
     web_state_impl_->OnNavigationStarted(context2.get());
-    [[tab_ navigationManagerImpl]->GetSessionController() commitPendingItem];
+    [tab_ navigationManagerImpl]->CommitPendingItem();
     web_state_impl_->UpdateHttpResponseHeaders(redirectUrl);
     web_state_impl_->OnNavigationFinished(context2.get());
 
diff --git a/ios/chrome/browser/ui/DEPS b/ios/chrome/browser/ui/DEPS
index 72d416b..2f0e159 100644
--- a/ios/chrome/browser/ui/DEPS
+++ b/ios/chrome/browser/ui/DEPS
@@ -10,7 +10,6 @@
     "+ios/web/web_state/ui/crw_web_controller.h",
   ],
   "^browser_view_controller_unittest\.mm$": [
-    "+ios/web/navigation/crw_session_controller.h",
     "+ios/web/web_state/ui/crw_web_controller.h",
     "+ios/web/web_state/web_state_impl.h",
   ],
diff --git a/ios/chrome/browser/web_resource/OWNERS b/ios/chrome/browser/web_resource/OWNERS
index 58c6484..50c6bcd4 100644
--- a/ios/chrome/browser/web_resource/OWNERS
+++ b/ios/chrome/browser/web_resource/OWNERS
@@ -1,3 +1,2 @@
 achuith@chromium.org
-dbeam@chromium.org
 rsesek@chromium.org
diff --git a/ios/web/OWNERS b/ios/web/OWNERS
index 8d4fba23..2710e7a 100644
--- a/ios/web/OWNERS
+++ b/ios/web/OWNERS
@@ -1,2 +1,3 @@
 eugenebut@chromium.org
+kkhorimoto@chromium.org
 marq@chromium.org
diff --git a/ios/web/navigation/crw_session_controller.h b/ios/web/navigation/crw_session_controller.h
index 301f3e3..9f84afc 100644
--- a/ios/web/navigation/crw_session_controller.h
+++ b/ios/web/navigation/crw_session_controller.h
@@ -147,8 +147,8 @@
 - (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem
                                     andItem:(web::NavigationItem*)secondItem;
 
-// Returns the index of |item| in |items|.
-- (NSInteger)indexOfItem:(const web::NavigationItem*)item;
+// Returns the index of |item| in |items|, or -1 if it is not present.
+- (int)indexOfItem:(const web::NavigationItem*)item;
 
 // Returns the item at |index| in |items|.
 - (web::NavigationItemImpl*)itemAtIndex:(NSInteger)index;
diff --git a/ios/web/navigation/crw_session_controller.mm b/ios/web/navigation/crw_session_controller.mm
index 5b3e0c5..dfdd73b 100644
--- a/ios/web/navigation/crw_session_controller.mm
+++ b/ios/web/navigation/crw_session_controller.mm
@@ -599,14 +599,14 @@
                                     andItem:(web::NavigationItem*)secondItem {
   if (!firstItem || !secondItem || firstItem == secondItem)
     return NO;
-  NSUInteger firstIndex = [self indexOfItem:firstItem];
-  NSUInteger secondIndex = [self indexOfItem:secondItem];
-  if (firstIndex == NSNotFound || secondIndex == NSNotFound)
+  int firstIndex = [self indexOfItem:firstItem];
+  int secondIndex = [self indexOfItem:secondItem];
+  if (firstIndex == -1 || secondIndex == -1)
     return NO;
-  NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex;
-  NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex;
+  int startIndex = firstIndex < secondIndex ? firstIndex : secondIndex;
+  int endIndex = firstIndex < secondIndex ? secondIndex : firstIndex;
 
-  for (NSUInteger i = startIndex + 1; i <= endIndex; i++) {
+  for (int i = startIndex + 1; i <= endIndex; i++) {
     web::NavigationItemImpl* item = self.items[i].get();
     // Every item in the sequence has to be created from a hash change or
     // pushState() call.
@@ -621,13 +621,13 @@
   return YES;
 }
 
-- (NSInteger)indexOfItem:(const web::NavigationItem*)item {
+- (int)indexOfItem:(const web::NavigationItem*)item {
   DCHECK(item);
   for (size_t index = 0; index < self.items.size(); ++index) {
     if (self.items[index].get() == item)
       return index;
   }
-  return NSNotFound;
+  return -1;
 }
 
 - (web::NavigationItemImpl*)itemAtIndex:(NSInteger)index {
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index ffc8a15..d2226ee 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -121,6 +121,7 @@
       BrowserURLRewriter::URLRewriter rewriter) override;
   int GetItemCount() const override;
   NavigationItem* GetItemAtIndex(size_t index) const override;
+  int GetIndexOfItem(const NavigationItem* item) const override;
   int GetPendingItemIndex() const override;
   int GetLastCommittedItemIndex() const override;
   bool RemoveItemAtIndex(int index) override;
diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/navigation_manager_impl.mm
index f7c69ed0..a4e0732 100644
--- a/ios/web/navigation/navigation_manager_impl.mm
+++ b/ios/web/navigation/navigation_manager_impl.mm
@@ -267,6 +267,11 @@
   return [session_controller_ itemAtIndex:index];
 }
 
+int NavigationManagerImpl::GetIndexOfItem(
+    const web::NavigationItem* item) const {
+  return [session_controller_ indexOfItem:item];
+}
+
 int NavigationManagerImpl::GetPendingItemIndex() const {
   if (GetPendingItem()) {
     if ([session_controller_ pendingItemIndex] != -1) {
diff --git a/ios/web/navigation/navigation_manager_impl_unittest.mm b/ios/web/navigation/navigation_manager_impl_unittest.mm
index c3d3ecea..3f24089 100644
--- a/ios/web/navigation/navigation_manager_impl_unittest.mm
+++ b/ios/web/navigation/navigation_manager_impl_unittest.mm
@@ -1363,4 +1363,28 @@
   EXPECT_EQ(rewritten_url4, navigation_manager()->GetPendingItem()->GetURL());
 }
 
+// Tests that GetIndexOfItem() returns the correct values.
+TEST_F(NavigationManagerTest, GetIndexOfItem) {
+  // Create two items and add them to the NavigationManagerImpl.
+  navigation_manager()->AddPendingItem(
+      GURL("http://www.url.com/0"), Referrer(), ui::PAGE_TRANSITION_TYPED,
+      web::NavigationInitiationType::USER_INITIATED,
+      web::NavigationManager::UserAgentOverrideOption::INHERIT);
+  navigation_manager()->CommitPendingItem();
+  web::NavigationItem* item0 = navigation_manager()->GetLastCommittedItem();
+  navigation_manager()->AddPendingItem(
+      GURL("http://www.url.com/1"), Referrer(), ui::PAGE_TRANSITION_TYPED,
+      web::NavigationInitiationType::USER_INITIATED,
+      web::NavigationManager::UserAgentOverrideOption::INHERIT);
+  navigation_manager()->CommitPendingItem();
+  web::NavigationItem* item1 = navigation_manager()->GetLastCommittedItem();
+  // Create an item that does not exist in the NavigationManagerImpl.
+  std::unique_ptr<web::NavigationItem> item_not_found =
+      web::NavigationItem::Create();
+  // Verify GetIndexOfItem() results.
+  EXPECT_EQ(0, navigation_manager()->GetIndexOfItem(item0));
+  EXPECT_EQ(1, navigation_manager()->GetIndexOfItem(item1));
+  EXPECT_EQ(-1, navigation_manager()->GetIndexOfItem(item_not_found.get()));
+}
+
 }  // namespace web
diff --git a/ios/web/public/navigation_manager.h b/ios/web/public/navigation_manager.h
index 2950c3be..6816af6f 100644
--- a/ios/web/public/navigation_manager.h
+++ b/ios/web/public/navigation_manager.h
@@ -130,6 +130,9 @@
   // Returns the committed NavigationItem at |index|.
   virtual NavigationItem* GetItemAtIndex(size_t index) const = 0;
 
+  // Returns the index of |item| in the committed session history.
+  virtual int GetIndexOfItem(const NavigationItem* item) const = 0;
+
   // Returns the index of the last committed item or -1 if the last
   // committed item correspond to a new navigation.
   // TODO(crbug.com/533848): Update to return size_t.
diff --git a/ios/web/public/test/fakes/test_navigation_manager.h b/ios/web/public/test/fakes/test_navigation_manager.h
index 4d9e483..d68ddaef 100644
--- a/ios/web/public/test/fakes/test_navigation_manager.h
+++ b/ios/web/public/test/fakes/test_navigation_manager.h
@@ -30,6 +30,7 @@
       BrowserURLRewriter::URLRewriter rewriter) override;
   int GetItemCount() const override;
   NavigationItem* GetItemAtIndex(size_t index) const override;
+  int GetIndexOfItem(const NavigationItem* item) const override;
   int GetPendingItemIndex() const override;
   int GetLastCommittedItemIndex() const override;
   bool RemoveItemAtIndex(int index) override;
diff --git a/ios/web/public/test/fakes/test_navigation_manager.mm b/ios/web/public/test/fakes/test_navigation_manager.mm
index 972efdca..c1c0125 100644
--- a/ios/web/public/test/fakes/test_navigation_manager.mm
+++ b/ios/web/public/test/fakes/test_navigation_manager.mm
@@ -75,6 +75,15 @@
   return items_[index].get();
 }
 
+int TestNavigationManager::GetIndexOfItem(
+    const web::NavigationItem* item) const {
+  for (size_t index = 0; index < items_.size(); ++index) {
+    if (items_[index].get() == item)
+      return index;
+  }
+  return -1;
+}
+
 void TestNavigationManager::SetLastCommittedItemIndex(const int index) {
   DCHECK(index == -1 || index >= 0 && index < GetItemCount());
   items_index_ = index;
diff --git a/media/capture/video/win/video_capture_device_factory_win.cc b/media/capture/video/win/video_capture_device_factory_win.cc
index 9b071270..c044c52 100644
--- a/media/capture/video/win/video_capture_device_factory_win.cc
+++ b/media/capture/video/win/video_capture_device_factory_win.cc
@@ -17,7 +17,6 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/win/scoped_co_mem.h"
 #include "base/win/scoped_variant.h"
-#include "base/win/windows_version.h"
 #include "media/base/media_switches.h"
 #include "media/base/win/mf_initializer.h"
 #include "media/capture/video/win/video_capture_device_mf_win.h"
@@ -402,19 +401,12 @@
 // distributions such as Windows 7 N and Windows 7 KN.
 // static
 bool VideoCaptureDeviceFactoryWin::PlatformSupportsMediaFoundation() {
-  // Even though the DLLs might be available on Vista, we get crashes
-  // when running our tests on the build bots.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return false;
-
   static bool g_dlls_available = LoadMediaFoundationDlls();
   return g_dlls_available;
 }
 
 VideoCaptureDeviceFactoryWin::VideoCaptureDeviceFactoryWin()
-    : use_media_foundation_(base::win::GetVersion() >=
-                                base::win::VERSION_WIN7 &&
-                            base::CommandLine::ForCurrentProcess()->HasSwitch(
+    : use_media_foundation_(base::CommandLine::ForCurrentProcess()->HasSwitch(
                                 switches::kForceMediaFoundationVideoCapture)) {}
 
 std::unique_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::CreateDevice(
diff --git a/media/formats/webm/webm_cluster_parser.cc b/media/formats/webm/webm_cluster_parser.cc
index 9b367b4..9dad920 100644
--- a/media/formats/webm/webm_cluster_parser.cc
+++ b/media/formats/webm/webm_cluster_parser.cc
@@ -498,9 +498,8 @@
 
   scoped_refptr<StreamParserBuffer> buffer;
   if (buffer_type != DemuxerStream::TEXT) {
-    // Every encrypted Block has a signal byte and IV prepended to it. Current
-    // encrypted WebM request for comments specification is here
-    // http://wiki.webmproject.org/encryption/webm-encryption-rfc
+    // Every encrypted Block has a signal byte and IV prepended to it.
+    // See: http://www.webmproject.org/docs/webm-encryption/
     std::unique_ptr<DecryptConfig> decrypt_config;
     int data_offset = 0;
     if (!encryption_key_id.empty() &&
@@ -509,6 +508,7 @@
              reinterpret_cast<const uint8_t*>(encryption_key_id.data()),
              encryption_key_id.size(),
              &decrypt_config, &data_offset)) {
+      MEDIA_LOG(ERROR, media_log_) << "Failed to extract decrypt config.";
       return false;
     }
 
diff --git a/media/formats/webm/webm_cluster_parser_unittest.cc b/media/formats/webm/webm_cluster_parser_unittest.cc
index dce4f99..7b7e9f4 100644
--- a/media/formats/webm/webm_cluster_parser_unittest.cc
+++ b/media/formats/webm/webm_cluster_parser_unittest.cc
@@ -745,6 +745,8 @@
 
   parser_.reset(CreateParserWithKeyIdsAndAudioCodec(
       std::string(), "video_key_id", kUnknownAudioCodec));
+
+  EXPECT_MEDIA_LOG(HasSubstr("Failed to extract decrypt config"));
   int result = parser_->Parse(cluster->data(), cluster->size());
   EXPECT_EQ(-1, result);
 }
diff --git a/media/formats/webm/webm_crypto_helpers.cc b/media/formats/webm/webm_crypto_helpers.cc
index 9251065..1f8447ab 100644
--- a/media/formats/webm/webm_crypto_helpers.cc
+++ b/media/formats/webm/webm_crypto_helpers.cc
@@ -129,10 +129,6 @@
       }
 
       const size_t num_partitions = data[frame_offset];
-      if (num_partitions == 0) {
-        DVLOG(1) << "Got a partitioned encrypted block with 0 partitions.";
-        return false;
-      }
       frame_offset += kWebMEncryptedFrameNumPartitionsSize;
       const uint8_t* partition_data_start = data + frame_offset;
       frame_offset += kWebMEncryptedFramePartitionOffsetSize * num_partitions;
diff --git a/media/formats/webm/webm_crypto_helpers_unittest.cc b/media/formats/webm/webm_crypto_helpers_unittest.cc
index 4a984b0e..e6e184fa 100644
--- a/media/formats/webm/webm_crypto_helpers_unittest.cc
+++ b/media/formats/webm/webm_crypto_helpers_unittest.cc
@@ -233,4 +233,34 @@
   EXPECT_EQ(14, data_offset);
 }
 
+TEST(WebMCryptoHelpersTest, EncryptedPartitionedZeroNumberOfPartitions) {
+  const uint8_t kData[] = {
+      // Encrypted and Partitioned
+      0x03,
+      // IV
+      0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a,
+      // Num partitions = 0
+      0x00,
+      // Some random data.
+      0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+  };
+  // Extracted from kData and zero extended to 16 bytes.
+  const uint8_t kExpectedIv[] = {
+      0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  };
+  std::unique_ptr<DecryptConfig> decrypt_config;
+  int data_offset;
+  ASSERT_TRUE(WebMCreateDecryptConfig(kData, sizeof(kData), kKeyId,
+                                      sizeof(kKeyId), &decrypt_config,
+                                      &data_offset));
+  EXPECT_TRUE(decrypt_config->is_encrypted());
+  EXPECT_EQ(std::string(kKeyId, kKeyId + sizeof(kKeyId)),
+            decrypt_config->key_id());
+  EXPECT_EQ(std::string(kExpectedIv, kExpectedIv + sizeof(kExpectedIv)),
+            decrypt_config->iv());
+  EXPECT_THAT(decrypt_config->subsamples(), ElementsAre(SubsampleEntry(6, 0)));
+  EXPECT_EQ(10, data_offset);
+}
+
 }  // namespace media
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 121979a2..1b58a14 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -217,6 +217,8 @@
     if (enable_media_codec_video_decoder) {
       assert(mojo_media_host == "gpu", "MCVD requires the CDM")
       sources += [
+        "android/codec_image.cc",
+        "android/codec_image.h",
         "android/codec_wrapper.cc",
         "android/codec_wrapper.h",
         "android/media_codec_video_decoder.cc",
@@ -465,6 +467,7 @@
     ]
     if (enable_media_codec_video_decoder) {
       sources += [
+        "android/codec_image_unittest.cc",
         "android/codec_wrapper_unittest.cc",
         "android/media_codec_video_decoder_unittest.cc",
       ]
diff --git a/media/gpu/android/codec_image.cc b/media/gpu/android/codec_image.cc
new file mode 100644
index 0000000..02b6dbbf
--- /dev/null
+++ b/media/gpu/android/codec_image.cc
@@ -0,0 +1,199 @@
+// 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 "media/gpu/android/codec_image.h"
+
+#include <string.h>
+
+#include <memory>
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "media/gpu/surface_texture_gl_owner.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/scoped_make_current.h"
+
+namespace media {
+namespace {
+
+// Makes |surface_texture|'s context current if it isn't already.
+std::unique_ptr<ui::ScopedMakeCurrent> MakeCurrentIfNeeded(
+    SurfaceTextureGLOwner* surface_texture) {
+  // Note: this works for virtual contexts too, because IsCurrent() returns true
+  // if their shared platform context is current, regardless of which virtual
+  // context is current.
+  return std::unique_ptr<ui::ScopedMakeCurrent>(
+      surface_texture->GetContext()->IsCurrent(nullptr)
+          ? nullptr
+          : new ui::ScopedMakeCurrent(surface_texture->GetContext(),
+                                      surface_texture->GetSurface()));
+}
+
+}  // namespace
+
+CodecImage::CodecImage(std::unique_ptr<CodecOutputBuffer> output_buffer,
+                       scoped_refptr<SurfaceTextureGLOwner> surface_texture,
+                       DestructionCb destruction_cb)
+    : phase_(Phase::kInCodec),
+      output_buffer_(std::move(output_buffer)),
+      surface_texture_(std::move(surface_texture)),
+      destruction_cb_(std::move(destruction_cb)) {}
+
+CodecImage::~CodecImage() {
+  destruction_cb_.Run(this);
+}
+
+gfx::Size CodecImage::GetSize() {
+  return output_buffer_->size();
+}
+
+unsigned CodecImage::GetInternalFormat() {
+  return GL_RGBA;
+}
+
+bool CodecImage::BindTexImage(unsigned target) {
+  return false;
+}
+
+void CodecImage::ReleaseTexImage(unsigned target) {}
+
+bool CodecImage::CopyTexImage(unsigned target) {
+  if (!surface_texture_ || target != GL_TEXTURE_EXTERNAL_OES)
+    return false;
+
+  GLint bound_service_id = 0;
+  glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id);
+  // The currently bound texture should be the surface texture's texture.
+  if (bound_service_id != static_cast<GLint>(surface_texture_->GetTextureId()))
+    return false;
+
+  return RenderToSurfaceTextureFrontBuffer(BindingsMode::kDontRestore);
+}
+
+bool CodecImage::CopyTexSubImage(unsigned target,
+                                 const gfx::Point& offset,
+                                 const gfx::Rect& rect) {
+  return false;
+}
+
+bool CodecImage::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+                                      int z_order,
+                                      gfx::OverlayTransform transform,
+                                      const gfx::Rect& bounds_rect,
+                                      const gfx::RectF& crop_rect) {
+  if (surface_texture_) {
+    DVLOG(1) << "Invalid call to ScheduleOverlayPlane; this image is "
+                "SurfaceTexture backed.";
+    return false;
+  }
+
+  // Move the overlay if needed.
+  if (most_recent_bounds_ != bounds_rect) {
+    most_recent_bounds_ = bounds_rect;
+    // TODO(watk): Implement overlay layout scheduling. Either post the call
+    // or create a threadsafe wrapper.
+  }
+
+  RenderToOverlay();
+  return true;
+}
+
+void CodecImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
+                              uint64_t process_tracing_id,
+                              const std::string& dump_name) {}
+
+void CodecImage::GetTextureMatrix(float matrix[16]) {
+  // Default to identity.
+  static constexpr float kYInvertedIdentity[16]{
+      1, 0,  0, 0,  //
+      0, -1, 0, 0,  //
+      0, 0,  1, 0,  //
+      0, 1,  0, 1   //
+  };
+  memcpy(matrix, kYInvertedIdentity, sizeof(kYInvertedIdentity));
+  if (!surface_texture_)
+    return;
+
+  // The matrix is available after we render to the front buffer. If that fails
+  // we'll return the matrix from the previous frame, which is more likely to be
+  // correct than the identity matrix anyway.
+  RenderToSurfaceTextureFrontBuffer(BindingsMode::kDontRestore);
+  surface_texture_->GetTransformMatrix(matrix);
+  YInvertMatrix(matrix);
+}
+
+bool CodecImage::RenderToFrontBuffer() {
+  return surface_texture_
+             ? RenderToSurfaceTextureFrontBuffer(BindingsMode::kRestore)
+             : RenderToOverlay();
+}
+
+bool CodecImage::RenderToSurfaceTextureBackBuffer() {
+  DCHECK(surface_texture_);
+  DCHECK_NE(phase_, Phase::kInFrontBuffer);
+  if (phase_ == Phase::kInBackBuffer)
+    return true;
+  if (phase_ == Phase::kInvalidated)
+    return false;
+
+  // Wait for a previous frame available so we don't confuse it with the one
+  // we're about to release.
+  if (surface_texture_->IsExpectingFrameAvailable())
+    surface_texture_->WaitForFrameAvailable();
+  if (!output_buffer_->ReleaseToSurface()) {
+    phase_ = Phase::kInvalidated;
+    return false;
+  }
+  phase_ = Phase::kInBackBuffer;
+  surface_texture_->SetReleaseTimeToNow();
+  return true;
+}
+
+bool CodecImage::RenderToSurfaceTextureFrontBuffer(BindingsMode bindings_mode) {
+  DCHECK(surface_texture_);
+  if (phase_ == Phase::kInFrontBuffer)
+    return true;
+  if (phase_ == Phase::kInvalidated)
+    return false;
+
+  // Render it to the back buffer if it's not already there.
+  if (!RenderToSurfaceTextureBackBuffer())
+    return false;
+
+  // The image is now in the back buffer, so promote it to the front buffer.
+  phase_ = Phase::kInFrontBuffer;
+  if (surface_texture_->IsExpectingFrameAvailable())
+    surface_texture_->WaitForFrameAvailable();
+
+  std::unique_ptr<ui::ScopedMakeCurrent> scoped_make_current =
+      MakeCurrentIfNeeded(surface_texture_.get());
+  // If we have to switch contexts, then we always want to restore the
+  // bindings.
+  bool should_restore_bindings =
+      bindings_mode == BindingsMode::kRestore || !!scoped_make_current;
+
+  GLint bound_service_id = 0;
+  if (should_restore_bindings)
+    glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id);
+  surface_texture_->UpdateTexImage();
+  if (should_restore_bindings)
+    glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id);
+  return true;
+}
+
+bool CodecImage::RenderToOverlay() {
+  if (phase_ == Phase::kInFrontBuffer)
+    return true;
+  if (phase_ == Phase::kInvalidated)
+    return false;
+
+  if (!output_buffer_->ReleaseToSurface()) {
+    phase_ = Phase::kInvalidated;
+    return false;
+  }
+  phase_ = Phase::kInFrontBuffer;
+  return true;
+}
+
+}  // namespace media
diff --git a/media/gpu/android/codec_image.h b/media/gpu/android/codec_image.h
new file mode 100644
index 0000000..bc569a9
--- /dev/null
+++ b/media/gpu/android/codec_image.h
@@ -0,0 +1,115 @@
+// 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 MEDIA_GPU_ANDROID_CODEC_IMAGE_H_
+#define MEDIA_GPU_ANDROID_CODEC_IMAGE_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "gpu/command_buffer/service/gl_stream_texture_image.h"
+#include "media/gpu/android/codec_wrapper.h"
+#include "media/gpu/media_gpu_export.h"
+#include "media/gpu/surface_texture_gl_owner.h"
+
+namespace media {
+
+// A GLImage that renders MediaCodec buffers to a SurfaceTexture or overlay
+// as needed in order to draw them.
+class MEDIA_GPU_EXPORT CodecImage : public gpu::gles2::GLStreamTextureImage {
+ public:
+  // A callback for observing CodecImage destruction.
+  using DestructionCb = base::Callback<void(CodecImage*)>;
+
+  CodecImage(std::unique_ptr<CodecOutputBuffer> output_buffer,
+             scoped_refptr<SurfaceTextureGLOwner> surface_texture,
+             DestructionCb destruction_cb);
+
+  // gl::GLImage implementation
+  gfx::Size GetSize() override;
+  unsigned GetInternalFormat() override;
+  bool BindTexImage(unsigned target) override;
+  void ReleaseTexImage(unsigned target) override;
+  bool CopyTexImage(unsigned target) override;
+  bool CopyTexSubImage(unsigned target,
+                       const gfx::Point& offset,
+                       const gfx::Rect& rect) override;
+  bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+                            int z_order,
+                            gfx::OverlayTransform transform,
+                            const gfx::Rect& bounds_rect,
+                            const gfx::RectF& crop_rect) override;
+  void Flush() override {}
+  void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
+                    uint64_t process_tracing_id,
+                    const std::string& dump_name) override;
+  // gpu::gles2::GLStreamTextureMatrix implementation
+  void GetTextureMatrix(float xform[16]) override;
+
+  // Whether the codec buffer has been rendered to the front buffer.
+  bool was_rendered_to_front_buffer() const {
+    return phase_ == Phase::kInFrontBuffer;
+  }
+
+  // Whether this image is be backed by a surface texture.
+  bool is_surface_texture_backed() const { return !!surface_texture_; }
+
+  // Renders this image to the front buffer of its backing surface.
+  // Returns true if the buffer is in the front buffer. Returns false if the
+  // buffer was invalidated. After an image is invalidated it's no longer
+  // possible to render it.
+  bool RenderToFrontBuffer();
+
+  // Renders this image to the back buffer of its surface texture. Only valid if
+  // is_surface_texture_backed(). Returns true if the buffer is in the back
+  // buffer. Returns false if the buffer was invalidated.
+  bool RenderToSurfaceTextureBackBuffer();
+
+ private:
+  // The lifecycle phases of an image.
+  // The only possible transitions are from left to right. Both
+  // kInFrontBuffer and kInvalidated are terminal.
+  enum class Phase { kInCodec, kInBackBuffer, kInFrontBuffer, kInvalidated };
+
+  ~CodecImage() override;
+
+  // Renders this image to the surface texture front buffer by first rendering
+  // it to the back buffer if it's not already there, and then waiting for the
+  // frame available event before calling UpdateTexImage(). Passing
+  // BindingsMode::kDontRestore skips the work of restoring the current texture
+  // bindings if the surface texture's context is already current. Otherwise,
+  // this switches contexts and preserves the texture bindings.
+  // Returns true if the buffer is in the front buffer. Returns false if the
+  // buffer was invalidated.
+  enum class BindingsMode { kRestore, kDontRestore };
+  bool RenderToSurfaceTextureFrontBuffer(BindingsMode bindings_mode);
+
+  // Renders this image to the overlay. Returns true if the buffer is in the
+  // overlay front buffer. Returns false if the buffer was invalidated.
+  bool RenderToOverlay();
+
+  // The phase of the image buffer's lifecycle.
+  Phase phase_;
+
+  // The buffer backing this image.
+  std::unique_ptr<CodecOutputBuffer> output_buffer_;
+
+  // The SurfaceTexture that |output_buffer_| will be rendered to. Or null, if
+  // this image is backed by an overlay.
+  scoped_refptr<SurfaceTextureGLOwner> surface_texture_;
+
+  // The bounds last sent to the overlay.
+  gfx::Rect most_recent_bounds_;
+
+  DestructionCb destruction_cb_;
+
+  DISALLOW_COPY_AND_ASSIGN(CodecImage);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_ANDROID_CODEC_IMAGE_H_
diff --git a/media/gpu/android/codec_image_unittest.cc b/media/gpu/android/codec_image_unittest.cc
new file mode 100644
index 0000000..dac3b78
--- /dev/null
+++ b/media/gpu/android/codec_image_unittest.cc
@@ -0,0 +1,255 @@
+// 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 "media/gpu/android/codec_image.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/mock_callback.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "media/base/android/media_codec_bridge.h"
+#include "media/base/android/mock_media_codec_bridge.h"
+#include "media/gpu/mock_surface_texture_gl_owner.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_egl.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_share_group.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/init/gl_factory.h"
+
+using testing::_;
+using testing::InSequence;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::Return;
+
+namespace media {
+
+const auto kNoop = base::Bind([](CodecImage*) {});
+
+class CodecImageTest : public testing::Test {
+ public:
+  CodecImageTest() = default;
+
+  void SetUp() override {
+    auto codec = base::MakeUnique<NiceMock<MockMediaCodecBridge>>();
+    codec_ = codec.get();
+    wrapper_ = base::MakeUnique<CodecWrapper>(std::move(codec));
+    ON_CALL(*codec_, DequeueOutputBuffer(_, _, _, _, _, _, _))
+        .WillByDefault(Return(MEDIA_CODEC_OK));
+
+    gl::init::InitializeGLOneOffImplementation(gl::kGLImplementationEGLGLES2,
+                                               false, false, false);
+    surface_ = new gl::PbufferGLSurfaceEGL(gfx::Size(320, 240));
+    surface_->Initialize();
+    share_group_ = new gl::GLShareGroup();
+    context_ = new gl::GLContextEGL(share_group_.get());
+    context_->Initialize(surface_.get(), gl::GLContextAttribs());
+    ASSERT_TRUE(context_->MakeCurrent(surface_.get()));
+
+    GLuint texture_id = 0;
+    glGenTextures(1, &texture_id);
+    // The tests rely on this texture being bound.
+    glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
+    surface_texture_ = new NiceMock<MockSurfaceTextureGLOwner>(
+        texture_id, context_.get(), surface_.get());
+  }
+
+  void TearDown() override {
+    context_ = nullptr;
+    share_group_ = nullptr;
+    surface_ = nullptr;
+    gl::init::ShutdownGL();
+    wrapper_->TakeCodec();
+  }
+
+  enum ImageKind { kOverlay, kSurfaceTexture };
+  scoped_refptr<CodecImage> NewImage(
+      ImageKind kind,
+      CodecImage::DestructionCb destruction_cb = kNoop) {
+    std::unique_ptr<CodecOutputBuffer> buffer;
+    wrapper_->DequeueOutputBuffer(base::TimeDelta(), nullptr, nullptr, &buffer);
+    return new CodecImage(std::move(buffer),
+                          kind == kSurfaceTexture ? surface_texture_ : nullptr,
+                          std::move(destruction_cb));
+  }
+
+  NiceMock<MockMediaCodecBridge>* codec_;
+  std::unique_ptr<CodecWrapper> wrapper_;
+  scoped_refptr<NiceMock<MockSurfaceTextureGLOwner>> surface_texture_;
+  scoped_refptr<gl::GLContext> context_;
+  scoped_refptr<gl::GLShareGroup> share_group_;
+  scoped_refptr<gl::GLSurface> surface_;
+};
+
+TEST_F(CodecImageTest, DestructionCbRuns) {
+  base::MockCallback<CodecImage::DestructionCb> cb;
+  auto i = NewImage(kOverlay, cb.Get());
+  EXPECT_CALL(cb, Run(i.get()));
+  i = nullptr;
+}
+
+TEST_F(CodecImageTest, ImageStartsUnrendered) {
+  auto i = NewImage(kSurfaceTexture);
+  ASSERT_FALSE(i->was_rendered_to_front_buffer());
+}
+
+TEST_F(CodecImageTest, CopyTexImageIsInvalidForOverlayImages) {
+  auto i = NewImage(kOverlay);
+  ASSERT_FALSE(i->CopyTexImage(GL_TEXTURE_EXTERNAL_OES));
+}
+
+TEST_F(CodecImageTest, ScheduleOverlayPlaneIsInvalidForSurfaceTextureImages) {
+  auto i = NewImage(kSurfaceTexture);
+  ASSERT_FALSE(i->ScheduleOverlayPlane(gfx::AcceleratedWidget(), 0,
+                                       gfx::OverlayTransform(), gfx::Rect(),
+                                       gfx::RectF()));
+}
+
+TEST_F(CodecImageTest, CopyTexImageFailsIfTargetIsNotOES) {
+  auto i = NewImage(kSurfaceTexture);
+  ASSERT_FALSE(i->CopyTexImage(GL_TEXTURE_2D));
+}
+
+TEST_F(CodecImageTest, CopyTexImageFailsIfTheWrongTextureIsBound) {
+  auto i = NewImage(kSurfaceTexture);
+  GLuint wrong_texture_id;
+  glGenTextures(1, &wrong_texture_id);
+  glBindTexture(GL_TEXTURE_EXTERNAL_OES, wrong_texture_id);
+  ASSERT_FALSE(i->CopyTexImage(GL_TEXTURE_EXTERNAL_OES));
+}
+
+TEST_F(CodecImageTest, CopyTexImageCanBeCalledRepeatedly) {
+  auto i = NewImage(kSurfaceTexture);
+  ASSERT_TRUE(i->CopyTexImage(GL_TEXTURE_EXTERNAL_OES));
+  ASSERT_TRUE(i->CopyTexImage(GL_TEXTURE_EXTERNAL_OES));
+}
+
+TEST_F(CodecImageTest, CopyTexImageTriggersFrontBufferRendering) {
+  auto i = NewImage(kSurfaceTexture);
+  // Verify that the release comes before the wait.
+  InSequence s;
+  EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true));
+  EXPECT_CALL(*surface_texture_, WaitForFrameAvailable());
+  EXPECT_CALL(*surface_texture_, UpdateTexImage());
+  i->CopyTexImage(GL_TEXTURE_EXTERNAL_OES);
+  ASSERT_TRUE(i->was_rendered_to_front_buffer());
+}
+
+TEST_F(CodecImageTest, GetTextureMatrixTriggersFrontBufferRendering) {
+  auto i = NewImage(kSurfaceTexture);
+  InSequence s;
+  EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true));
+  EXPECT_CALL(*surface_texture_, WaitForFrameAvailable());
+  EXPECT_CALL(*surface_texture_, UpdateTexImage());
+  EXPECT_CALL(*surface_texture_, GetTransformMatrix(_));
+  float matrix[16];
+  i->GetTextureMatrix(matrix);
+  ASSERT_TRUE(i->was_rendered_to_front_buffer());
+}
+
+TEST_F(CodecImageTest, GetTextureMatrixReturnsIdentityForOverlayImages) {
+  auto i = NewImage(kOverlay);
+  float matrix[16]{0};
+  i->GetTextureMatrix(matrix);
+  // See GetTextureMatrix() for the expected result.
+  ASSERT_EQ(matrix[0], 1);
+  ASSERT_EQ(matrix[5], -1);
+}
+
+TEST_F(CodecImageTest, ScheduleOverlayPlaneTriggersFrontBufferRendering) {
+  auto i = NewImage(kOverlay);
+  EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true));
+  i->ScheduleOverlayPlane(gfx::AcceleratedWidget(), 0, gfx::OverlayTransform(),
+                          gfx::Rect(), gfx::RectF());
+  ASSERT_TRUE(i->was_rendered_to_front_buffer());
+}
+
+TEST_F(CodecImageTest, CanRenderSurfaceTextureImageToBackBuffer) {
+  auto i = NewImage(kSurfaceTexture);
+  ASSERT_TRUE(i->RenderToSurfaceTextureBackBuffer());
+  ASSERT_FALSE(i->was_rendered_to_front_buffer());
+}
+
+TEST_F(CodecImageTest, CodecBufferInvalidationResultsInRenderingFailure) {
+  auto i = NewImage(kSurfaceTexture);
+  // Invalidate the backing codec buffer.
+  wrapper_->TakeCodec();
+  ASSERT_FALSE(i->RenderToSurfaceTextureBackBuffer());
+}
+
+TEST_F(CodecImageTest, RenderToBackBufferDoesntWait) {
+  auto i = NewImage(kSurfaceTexture);
+  InSequence s;
+  EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true));
+  EXPECT_CALL(*surface_texture_, SetReleaseTimeToNow());
+  EXPECT_CALL(*surface_texture_, WaitForFrameAvailable()).Times(0);
+  ASSERT_TRUE(i->RenderToSurfaceTextureBackBuffer());
+}
+
+TEST_F(CodecImageTest, PromotingTheBackBufferWaits) {
+  auto i = NewImage(kSurfaceTexture);
+  EXPECT_CALL(*surface_texture_, SetReleaseTimeToNow()).Times(1);
+  i->RenderToSurfaceTextureBackBuffer();
+  EXPECT_CALL(*surface_texture_, WaitForFrameAvailable());
+  ASSERT_TRUE(i->RenderToFrontBuffer());
+}
+
+TEST_F(CodecImageTest, PromotingTheBackBufferAlwaysSucceeds) {
+  auto i = NewImage(kSurfaceTexture);
+  i->RenderToSurfaceTextureBackBuffer();
+  // Invalidating the codec buffer doesn't matter after it's rendered to the
+  // back buffer.
+  wrapper_->TakeCodec();
+  ASSERT_TRUE(i->RenderToFrontBuffer());
+}
+
+TEST_F(CodecImageTest, FrontBufferRenderingFailsIfBackBufferRenderingFailed) {
+  auto i = NewImage(kSurfaceTexture);
+  wrapper_->TakeCodec();
+  i->RenderToSurfaceTextureBackBuffer();
+  ASSERT_FALSE(i->RenderToFrontBuffer());
+}
+
+TEST_F(CodecImageTest, RenderToFrontBufferRestoresTextureBindings) {
+  GLuint pre_bound_texture = 0;
+  glGenTextures(1, &pre_bound_texture);
+  glBindTexture(GL_TEXTURE_EXTERNAL_OES, pre_bound_texture);
+  auto i = NewImage(kSurfaceTexture);
+  EXPECT_CALL(*surface_texture_, UpdateTexImage());
+  i->RenderToFrontBuffer();
+  GLint post_bound_texture = 0;
+  glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &post_bound_texture);
+  ASSERT_EQ(pre_bound_texture, static_cast<GLuint>(post_bound_texture));
+}
+
+TEST_F(CodecImageTest, RenderToFrontBufferRestoresGLContext) {
+  // Make a new context current.
+  scoped_refptr<gl::GLSurface> surface(
+      new gl::PbufferGLSurfaceEGL(gfx::Size(320, 240)));
+  surface->Initialize();
+  scoped_refptr<gl::GLShareGroup> share_group(new gl::GLShareGroup());
+  scoped_refptr<gl::GLContext> context(new gl::GLContextEGL(share_group.get()));
+  context->Initialize(surface.get(), gl::GLContextAttribs());
+  ASSERT_TRUE(context->MakeCurrent(surface.get()));
+
+  auto i = NewImage(kSurfaceTexture);
+  // Our context should not be current when UpdateTexImage() is called.
+  EXPECT_CALL(*surface_texture_, UpdateTexImage()).WillOnce(Invoke([&]() {
+    ASSERT_FALSE(context->IsCurrent(surface.get()));
+  }));
+  i->RenderToFrontBuffer();
+  // Our context should have been restored.
+  ASSERT_TRUE(context->IsCurrent(surface.get()));
+
+  context = nullptr;
+  share_group = nullptr;
+  surface = nullptr;
+}
+
+}  // namespace media
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc
index 5b863cc..c1f525db 100644
--- a/media/gpu/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -1254,7 +1254,7 @@
     ::LoadLibrary(mfdll);
   ::LoadLibrary(L"dxva2.dll");
 
-  if (base::win::GetVersion() > base::win::VERSION_WIN7) {
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
     LoadLibrary(L"msvproc.dll");
   } else {
 #if defined(ENABLE_DX11_FOR_WIN7)
diff --git a/media/gpu/gpu_video_decode_accelerator_factory.cc b/media/gpu/gpu_video_decode_accelerator_factory.cc
index 6b809fd..e926ad640f 100644
--- a/media/gpu/gpu_video_decode_accelerator_factory.cc
+++ b/media/gpu/gpu_video_decode_accelerator_factory.cc
@@ -182,12 +182,10 @@
     const gpu::GpuDriverBugWorkarounds& workarounds,
     const gpu::GpuPreferences& gpu_preferences) const {
   std::unique_ptr<VideoDecodeAccelerator> decoder;
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
-    DVLOG(0) << "Initializing DXVA HW decoder for windows.";
-    decoder.reset(new DXVAVideoDecodeAccelerator(
-        get_gl_context_cb_, make_context_current_cb_, bind_image_cb_,
-        workarounds, gpu_preferences));
-  }
+  DVLOG(0) << "Initializing DXVA HW decoder for windows.";
+  decoder.reset(new DXVAVideoDecodeAccelerator(
+      get_gl_context_cb_, make_context_current_cb_, bind_image_cb_,
+      workarounds, gpu_preferences));
   return decoder;
 }
 #endif
diff --git a/media/gpu/mock_surface_texture_gl_owner.cc b/media/gpu/mock_surface_texture_gl_owner.cc
index e55e6b4b..9e52690b 100644
--- a/media/gpu/mock_surface_texture_gl_owner.cc
+++ b/media/gpu/mock_surface_texture_gl_owner.cc
@@ -3,9 +3,37 @@
 // found in the LICENSE file.
 
 #include "media/gpu/mock_surface_texture_gl_owner.h"
+
 namespace media {
 
-MockSurfaceTextureGLOwner::MockSurfaceTextureGLOwner() = default;
+using testing::Invoke;
+using testing::Return;
+
+MockSurfaceTextureGLOwner::MockSurfaceTextureGLOwner(
+    GLuint fake_texture_id,
+    gl::GLContext* fake_context,
+    gl::GLSurface* fake_surface)
+    : fake_texture_id(fake_texture_id),
+      fake_context(fake_context),
+      fake_surface(fake_surface),
+      expecting_frame_available(false) {
+  ON_CALL(*this, GetTextureId()).WillByDefault(Return(fake_texture_id));
+  ON_CALL(*this, GetContext()).WillByDefault(Return(fake_context));
+  ON_CALL(*this, GetSurface()).WillByDefault(Return(fake_surface));
+  ON_CALL(*this, SetReleaseTimeToNow())
+      .WillByDefault(
+          Invoke(this, &MockSurfaceTextureGLOwner::FakeSetReleaseTimeToNow));
+  ON_CALL(*this, IgnorePendingRelease())
+      .WillByDefault(
+          Invoke(this, &MockSurfaceTextureGLOwner::FakeIgnorePendingRelease));
+  ON_CALL(*this, IsExpectingFrameAvailable())
+      .WillByDefault(Invoke(
+          this, &MockSurfaceTextureGLOwner::FakeIsExpectingFrameAvailable));
+  ON_CALL(*this, WaitForFrameAvailable())
+      .WillByDefault(
+          Invoke(this, &MockSurfaceTextureGLOwner::FakeWaitForFrameAvailable));
+}
+
 MockSurfaceTextureGLOwner::~MockSurfaceTextureGLOwner() = default;
 
 }  // namespace media
diff --git a/media/gpu/mock_surface_texture_gl_owner.h b/media/gpu/mock_surface_texture_gl_owner.h
index aa2a286..78ce708 100644
--- a/media/gpu/mock_surface_texture_gl_owner.h
+++ b/media/gpu/mock_surface_texture_gl_owner.h
@@ -8,12 +8,19 @@
 #include "media/gpu/surface_texture_gl_owner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface.h"
 
 namespace media {
 
+// This is a mock with a small amount of fake functionality too.
 class MockSurfaceTextureGLOwner : public SurfaceTextureGLOwner {
  public:
-  MockSurfaceTextureGLOwner();
+  MockSurfaceTextureGLOwner(GLuint fake_texture_id,
+                            gl::GLContext* fake_context,
+                            gl::GLSurface* fake_surface);
+
   MOCK_CONST_METHOD0(GetTextureId, GLuint());
   MOCK_CONST_METHOD0(GetContext, gl::GLContext*());
   MOCK_CONST_METHOD0(GetSurface, gl::GLSurface*());
@@ -26,6 +33,17 @@
   MOCK_METHOD0(IsExpectingFrameAvailable, bool());
   MOCK_METHOD0(WaitForFrameAvailable, void());
 
+  // Fake implementations that the mocks will call by default.
+  void FakeSetReleaseTimeToNow() { expecting_frame_available = true; }
+  void FakeIgnorePendingRelease() { expecting_frame_available = false; }
+  bool FakeIsExpectingFrameAvailable() { return expecting_frame_available; }
+  void FakeWaitForFrameAvailable() { expecting_frame_available = false; }
+
+  GLuint fake_texture_id;
+  gl::GLContext* fake_context;
+  gl::GLSurface* fake_surface;
+  bool expecting_frame_available;
+
  protected:
   ~MockSurfaceTextureGLOwner();
 };
diff --git a/net/cert/cert_verify_proc_builtin.cc b/net/cert/cert_verify_proc_builtin.cc
index efba79b..2ed89b6 100644
--- a/net/cert/cert_verify_proc_builtin.cc
+++ b/net/cert/cert_verify_proc_builtin.cc
@@ -221,9 +221,12 @@
 
   // Initialize the path builder.
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target, ssl_trust_store->GetTrustStore(),
-                               &signature_policy, verification_time,
-                               KeyPurpose::SERVER_AUTH, &result);
+  CertPathBuilder path_builder(
+      target, ssl_trust_store->GetTrustStore(), &signature_policy,
+      verification_time, KeyPurpose::SERVER_AUTH, InitialExplicitPolicy::kFalse,
+      {AnyPolicy()} /* user_initial_policy_set*/,
+      InitialPolicyMappingInhibit::kFalse, InitialAnyPolicyInhibit::kFalse,
+      &result);
 
   // Allow the path builder to discover the explicitly provided intermediates in
   // |input_cert|.
diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc
index 05b66d6..cc25543 100644
--- a/net/cert/internal/path_builder.cc
+++ b/net/cert/internal/path_builder.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "net/base/net_errors.h"
 #include "net/cert/internal/cert_issuer_source.h"
+#include "net/cert/internal/certificate_policies.h"
 #include "net/cert/internal/parse_certificate.h"
 #include "net/cert/internal/parse_name.h"  // For CertDebugString.
 #include "net/cert/internal/signature_policy.h"
@@ -544,16 +545,25 @@
   best_result_index = 0;
 }
 
-CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert,
-                                 TrustStore* trust_store,
-                                 const SignaturePolicy* signature_policy,
-                                 const der::GeneralizedTime& time,
-                                 KeyPurpose key_purpose,
-                                 Result* result)
+CertPathBuilder::CertPathBuilder(
+    scoped_refptr<ParsedCertificate> cert,
+    TrustStore* trust_store,
+    const SignaturePolicy* signature_policy,
+    const der::GeneralizedTime& time,
+    KeyPurpose key_purpose,
+    InitialExplicitPolicy initial_explicit_policy,
+    const std::set<der::Input>& user_initial_policy_set,
+    InitialPolicyMappingInhibit initial_policy_mapping_inhibit,
+    InitialAnyPolicyInhibit initial_any_policy_inhibit,
+    Result* result)
     : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)),
       signature_policy_(signature_policy),
       time_(time),
       key_purpose_(key_purpose),
+      initial_explicit_policy_(initial_explicit_policy),
+      user_initial_policy_set_(user_initial_policy_set),
+      initial_policy_mapping_inhibit_(initial_policy_mapping_inhibit),
+      initial_any_policy_inhibit_(initial_any_policy_inhibit),
       next_state_(STATE_NONE),
       out_result_(result) {
   result->Clear();
@@ -604,12 +614,11 @@
 
   // Verify the entire certificate chain.
   auto result_path = base::MakeUnique<ResultPath>();
-  // TODO(eroman): don't pass placeholder for policy.
   VerifyCertificateChain(
       next_path_.certs, next_path_.last_cert_trust, signature_policy_, time_,
-      key_purpose_, InitialExplicitPolicy::kFalse, {AnyPolicy()},
-      InitialPolicyMappingInhibit::kFalse, InitialAnyPolicyInhibit::kFalse,
-      nullptr /*user_constrained_policy_set*/, &result_path->errors);
+      key_purpose_, initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_,
+      &result_path->user_constrained_policy_set, &result_path->errors);
   bool verify_result = !result_path->errors.ContainsHighSeverityErrors();
 
   DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = "
diff --git a/net/cert/internal/path_builder.h b/net/cert/internal/path_builder.h
index 5860ed76..2dcaa6836 100644
--- a/net/cert/internal/path_builder.h
+++ b/net/cert/internal/path_builder.h
@@ -78,6 +78,10 @@
     // |path.trust_anchor| may be null, and the path may be incomplete.
     CertPath path;
 
+    // The set of policies that the certificate is valid for (of the
+    // subset of policies user requested during verification).
+    std::set<der::Input> user_constrained_policy_set;
+
     // The errors/warnings from this path. Use |IsValid()| to determine if the
     // path is valid.
     CertPathErrors errors;
@@ -120,11 +124,18 @@
   //
   // The caller must keep |trust_store|, |signature_policy|, and |*result| valid
   // for the lifetime of the CertPathBuilder.
+  //
+  // See VerifyCertificateChain() for a more detailed explanation of the
+  // same-named parameters.
   CertPathBuilder(scoped_refptr<ParsedCertificate> cert,
                   TrustStore* trust_store,
                   const SignaturePolicy* signature_policy,
                   const der::GeneralizedTime& time,
                   KeyPurpose key_purpose,
+                  InitialExplicitPolicy initial_explicit_policy,
+                  const std::set<der::Input>& user_initial_policy_set,
+                  InitialPolicyMappingInhibit initial_policy_mapping_inhibit,
+                  InitialAnyPolicyInhibit initial_any_policy_inhibit,
                   Result* result);
   ~CertPathBuilder();
 
@@ -160,6 +171,10 @@
   const SignaturePolicy* signature_policy_;
   const der::GeneralizedTime time_;
   const KeyPurpose key_purpose_;
+  const InitialExplicitPolicy initial_explicit_policy_;
+  const std::set<der::Input> user_initial_policy_set_;
+  const InitialPolicyMappingInhibit initial_policy_mapping_inhibit_;
+  const InitialAnyPolicyInhibit initial_any_policy_inhibit_;
 
   // Stores the next complete path to attempt verification on. This is filled in
   // by |cert_path_iter_| during the STATE_GET_NEXT_PATH step, and thus should
diff --git a/net/cert/internal/path_builder_pkits_unittest.cc b/net/cert/internal/path_builder_pkits_unittest.cc
index 5b14575..18a6445 100644
--- a/net/cert/internal/path_builder_pkits_unittest.cc
+++ b/net/cert/internal/path_builder_pkits_unittest.cc
@@ -81,14 +81,21 @@
     SimpleSignaturePolicy signature_policy(1024);
 
     CertPathBuilder::Result result;
-    CertPathBuilder path_builder(std::move(target_cert), &trust_store,
-                                 &signature_policy, info.time,
-                                 KeyPurpose::ANY_EKU, &result);
+    CertPathBuilder path_builder(
+        std::move(target_cert), &trust_store, &signature_policy, info.time,
+        KeyPurpose::ANY_EKU, info.initial_explicit_policy,
+        info.initial_policy_set, info.initial_policy_mapping_inhibit,
+        info.initial_inhibit_any_policy, &result);
     path_builder.AddCertIssuerSource(&cert_issuer_source);
 
     path_builder.Run();
 
     ASSERT_EQ(info.should_validate, result.HasValidPath());
+
+    if (result.HasValidPath()) {
+      EXPECT_EQ(info.user_constrained_policy_set,
+                result.GetBestValidPath()->user_constrained_policy_set);
+    }
   }
 };
 
@@ -233,6 +240,21 @@
                               PkitsTest07KeyUsage,
                               PathBuilderPkitsTestDelegate);
 INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest08CertificatePolicies,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest09RequireExplicitPolicy,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest10PolicyMappings,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest11InhibitPolicyMapping,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest12InhibitAnyPolicy,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
                               PkitsTest13NameConstraints,
                               PathBuilderPkitsTestDelegate);
 INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
@@ -243,8 +265,4 @@
 // PkitsTest05VerifyingPathswithSelfIssuedCertificates,
 // PkitsTest14DistributionPoints, PkitsTest15DeltaCRLs
 
-// TODO(mattm): Certificate Policies support: PkitsTest08CertificatePolicies,
-// PkitsTest09RequireExplicitPolicy PkitsTest10PolicyMappings,
-// PkitsTest11InhibitPolicyMapping, PkitsTest12InhibitAnyPolicy
-
 }  // namespace net
diff --git a/net/cert/internal/path_builder_unittest.cc b/net/cert/internal/path_builder_unittest.cc
index a69c629..c09504d 100644
--- a/net/cert/internal/path_builder_unittest.cc
+++ b/net/cert/internal/path_builder_unittest.cc
@@ -135,6 +135,14 @@
 
   SimpleSignaturePolicy signature_policy_;
   der::GeneralizedTime time_ = {2017, 3, 1, 0, 0, 0};
+
+  const InitialExplicitPolicy initial_explicit_policy_ =
+      InitialExplicitPolicy::kFalse;
+  const std::set<der::Input> user_initial_policy_set_ = {AnyPolicy()};
+  const InitialPolicyMappingInhibit initial_policy_mapping_inhibit_ =
+      InitialPolicyMappingInhibit::kFalse;
+  const InitialAnyPolicyInhibit initial_any_policy_inhibit_ =
+      InitialAnyPolicyInhibit::kFalse;
 };
 
 // Tests when the target cert has the same name and key as a trust anchor,
@@ -150,8 +158,10 @@
   trust_store.AddTrustAnchor(b_by_f_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      a_by_b_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
 
   path_builder.Run();
 
@@ -175,8 +185,10 @@
   trust_store.AddTrustAnchor(a_by_b_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      a_by_b_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
 
   path_builder.Run();
 
@@ -204,8 +216,10 @@
   der::GeneralizedTime expired_time = {2016, 1, 1, 0, 0, 0};
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(b_by_c_, &trust_store, &signature_policy_,
-                               expired_time, KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      b_by_c_, &trust_store, &signature_policy_, expired_time,
+      KeyPurpose::ANY_EKU, initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs);
 
   path_builder.Run();
@@ -229,8 +243,10 @@
   trust_store.AddTrustAnchor(f_by_e_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(e_by_e_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      e_by_e_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
 
   path_builder.Run();
 
@@ -253,8 +269,10 @@
   trust_store.AddTrustAnchor(b_by_f_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      a_by_b_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
 
   path_builder.Run();
 
@@ -280,8 +298,10 @@
   async_certs.AddCert(c_by_e_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      a_by_b_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&async_certs);
   path_builder.AddCertIssuerSource(&sync_certs);
 
@@ -308,8 +328,10 @@
   async_certs2.AddCert(f_by_e_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      a_by_b_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&async_certs1);
   path_builder.AddCertIssuerSource(&async_certs2);
   path_builder.AddCertIssuerSource(&sync_certs);
@@ -335,8 +357,10 @@
   sync_certs.AddCert(c_by_d_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      a_by_b_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs);
 
   path_builder.Run();
@@ -368,8 +392,10 @@
   async_certs.AddCert(c_by_d_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      a_by_b_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs);
   path_builder.AddCertIssuerSource(&async_certs);
 
@@ -407,8 +433,10 @@
     }
 
     CertPathBuilder::Result result;
-    CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_,
-                                 time_, KeyPurpose::ANY_EKU, &result);
+    CertPathBuilder path_builder(
+        a_by_b_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+        initial_explicit_policy_, user_initial_policy_set_,
+        initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
     path_builder.AddCertIssuerSource(&sync_certs);
 
     path_builder.Run();
@@ -480,6 +508,14 @@
 
   SimpleSignaturePolicy signature_policy_;
   der::GeneralizedTime time_;
+
+  const InitialExplicitPolicy initial_explicit_policy_ =
+      InitialExplicitPolicy::kFalse;
+  const std::set<der::Input> user_initial_policy_set_ = {AnyPolicy()};
+  const InitialPolicyMappingInhibit initial_policy_mapping_inhibit_ =
+      InitialPolicyMappingInhibit::kFalse;
+  const InitialAnyPolicyInhibit initial_any_policy_inhibit_ =
+      InitialAnyPolicyInhibit::kFalse;
 };
 
 // Tests that if only the old root cert is trusted, the path builder can build a
@@ -496,8 +532,10 @@
   sync_certs.AddCert(newrootrollover_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      target_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs);
 
   path_builder.Run();
@@ -544,8 +582,10 @@
   sync_certs.AddCert(newrootrollover_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      target_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs);
 
   path_builder.Run();
@@ -579,8 +619,10 @@
   trust_store.AddTrustAnchor(newroot_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      target_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
 
   path_builder.Run();
 
@@ -610,9 +652,10 @@
   sync_certs.AddCert(oldintermediate_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target_, &trust_store_collection,
-                               &signature_policy_, time_, KeyPurpose::ANY_EKU,
-                               &result);
+  CertPathBuilder path_builder(
+      target_, &trust_store_collection, &signature_policy_, time_,
+      KeyPurpose::ANY_EKU, initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs);
 
   path_builder.Run();
@@ -661,8 +704,10 @@
   async_certs.AddCert(newrootrollover_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      target_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs);
   path_builder.AddCertIssuerSource(&async_certs);
 
@@ -718,9 +763,10 @@
 
   CertPathBuilder::Result result;
   // Newintermediate is also the target cert.
-  CertPathBuilder path_builder(newintermediate_, &trust_store,
-                               &signature_policy_, time_, KeyPurpose::ANY_EKU,
-                               &result);
+  CertPathBuilder path_builder(
+      newintermediate_, &trust_store, &signature_policy_, time_,
+      KeyPurpose::ANY_EKU, initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
 
   path_builder.Run();
 
@@ -743,8 +789,10 @@
 
   CertPathBuilder::Result result;
   // Newroot is the target cert.
-  CertPathBuilder path_builder(newroot_, &trust_store, &signature_policy_,
-                               time_, KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      newroot_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs);
 
   path_builder.Run();
@@ -764,8 +812,10 @@
 
   CertPathBuilder::Result result;
   // Newroot is the target cert.
-  CertPathBuilder path_builder(newroot_, &trust_store, &signature_policy_,
-                               time_, KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      newroot_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
 
   path_builder.Run();
 
@@ -812,8 +862,10 @@
   async_certs.AddCert(newintermediate_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      target_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs1);
   path_builder.AddCertIssuerSource(&sync_certs2);
   path_builder.AddCertIssuerSource(&async_certs);
@@ -866,8 +918,10 @@
   sync_certs.AddCert(newroot_dupe);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      target_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&sync_certs);
 
   path_builder.Run();
@@ -940,8 +994,10 @@
   trust_store.AddTrustAnchor(newroot_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      target_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&cert_issuer_source);
 
   // Create the mock CertIssuerSource::Request...
@@ -1019,8 +1075,10 @@
   trust_store.AddTrustAnchor(newroot_);
 
   CertPathBuilder::Result result;
-  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
-                               KeyPurpose::ANY_EKU, &result);
+  CertPathBuilder path_builder(
+      target_, &trust_store, &signature_policy_, time_, KeyPurpose::ANY_EKU,
+      initial_explicit_policy_, user_initial_policy_set_,
+      initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result);
   path_builder.AddCertIssuerSource(&cert_issuer_source);
 
   // Create the mock CertIssuerSource::Request...
@@ -1134,9 +1192,18 @@
 
     SimpleSignaturePolicy signature_policy(1024);
 
-    CertPathBuilder path_builder(test_.chain.front(), &trust_store,
-                                 &signature_policy, test_.time,
-                                 KeyPurpose::ANY_EKU, result);
+    const InitialExplicitPolicy initial_explicit_policy =
+        InitialExplicitPolicy::kFalse;
+    const std::set<der::Input> user_initial_policy_set = {AnyPolicy()};
+    const InitialPolicyMappingInhibit initial_policy_mapping_inhibit =
+        InitialPolicyMappingInhibit::kFalse;
+    const InitialAnyPolicyInhibit initial_any_policy_inhibit =
+        InitialAnyPolicyInhibit::kFalse;
+
+    CertPathBuilder path_builder(
+        test_.chain.front(), &trust_store, &signature_policy, test_.time,
+        KeyPurpose::ANY_EKU, initial_explicit_policy, user_initial_policy_set,
+        initial_policy_mapping_inhibit, initial_any_policy_inhibit, result);
     path_builder.AddCertIssuerSource(&intermediates);
     path_builder.Run();
   }
diff --git a/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc b/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc
index ca3d81b..3de3cc81a 100644
--- a/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc
+++ b/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc
@@ -43,9 +43,11 @@
 
     CertPathBuilder::Result result;
     // First cert in the |chain| is the target.
-    CertPathBuilder path_builder(test.chain.front(), &trust_store,
-                                 &signature_policy, test.time, test.key_purpose,
-                                 &result);
+    CertPathBuilder path_builder(
+        test.chain.front(), &trust_store, &signature_policy, test.time,
+        test.key_purpose, test.initial_explicit_policy,
+        test.user_initial_policy_set, test.initial_policy_mapping_inhibit,
+        test.initial_any_policy_inhibit, &result);
     path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
 
     path_builder.Run();
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.cc b/net/quic/chromium/bidirectional_stream_quic_impl.cc
index 28f49d9..c10720d5 100644
--- a/net/quic/chromium/bidirectional_stream_quic_impl.cc
+++ b/net/quic/chromium/bidirectional_stream_quic_impl.cc
@@ -102,21 +102,16 @@
 
 void BidirectionalStreamQuicImpl::SendRequestHeaders() {
   ScopedBoolSaver saver(&may_invoke_callbacks_, false);
-  // If this fails, a task will have been posted to notify the delegate
-  // asynchronously.
-  WriteHeaders();
-}
-
-bool BidirectionalStreamQuicImpl::WriteHeaders() {
-  DCHECK(!has_sent_headers_);
-  if (!stream_) {
-    LOG(ERROR)
-        << "Trying to send request headers after stream has been destroyed.";
+  int rv = WriteHeaders();
+  if (rv < 0) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
-                              weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
-    return false;
+                              weak_factory_.GetWeakPtr(), rv));
   }
+}
+
+int BidirectionalStreamQuicImpl::WriteHeaders() {
+  DCHECK(!has_sent_headers_);
 
   SpdyHeaderBlock headers;
   HttpRequestInfo http_request_info;
@@ -126,17 +121,13 @@
 
   CreateSpdyHeadersFromHttpRequest(
       http_request_info, http_request_info.extra_headers, true, &headers);
-  // Sending the request might result in the stream being closed via OnClose
-  // which will post a task to notify the delegate asynchronously.
-  // TODO(rch): Clean up this interface when OnClose and OnError are removed.
-  size_t headers_bytes_sent = stream_->WriteHeaders(
-      std::move(headers), request_info_->end_stream_on_headers, nullptr);
-  if (!stream_)
-    return false;
-
-  headers_bytes_sent_ += headers_bytes_sent;
-  has_sent_headers_ = true;
-  return true;
+  int rv = stream_->WriteHeaders(std::move(headers),
+                                 request_info_->end_stream_on_headers, nullptr);
+  if (rv >= 0) {
+    headers_bytes_sent_ += rv;
+    has_sent_headers_ = true;
+  }
+  return rv;
 }
 
 int BidirectionalStreamQuicImpl::ReadData(IOBuffer* buffer, int buffer_len) {
@@ -144,10 +135,6 @@
   DCHECK(buffer);
   DCHECK(buffer_len);
 
-  if (!stream_) {
-    // If the stream is already closed, there is no body to read.
-    return response_status_;
-  }
   int rv = stream_->ReadBody(
       buffer, buffer_len,
       base::Bind(&BidirectionalStreamQuicImpl::OnReadDataComplete,
@@ -161,11 +148,11 @@
   if (rv < 0)
     return rv;
 
-  if (stream_->IsDoneReading()) {
-    // If the write side is closed, OnFinRead() will call
-    // BidirectionalStreamQuicImpl::OnClose().
+  // If the write side is closed, OnFinRead() will call
+  // BidirectionalStreamQuicImpl::OnClose().
+  if (stream_->IsDoneReading())
     stream_->OnFinRead();
-  }
+
   return rv;
 }
 
@@ -176,8 +163,8 @@
   ScopedBoolSaver saver(&may_invoke_callbacks_, false);
   DCHECK_EQ(buffers.size(), lengths.size());
 
-  if (!stream_) {
-    LOG(ERROR) << "Trying to send data after stream has been destroyed.";
+  if (!stream_->IsOpen()) {
+    LOG(ERROR) << "Trying to send data after stream has been closed.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
                               weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
@@ -188,9 +175,13 @@
       session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING));
   if (!has_sent_headers_) {
     DCHECK(!send_request_headers_automatically_);
-    // Sending the request might result in the stream being closed.
-    if (!WriteHeaders())
+    int rv = WriteHeaders();
+    if (rv < 0) {
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
+                                weak_factory_.GetWeakPtr(), rv));
       return;
+    }
   }
 
   int rv = stream_->WritevStreamData(
@@ -198,11 +189,10 @@
       base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
                  weak_factory_.GetWeakPtr()));
 
-  DCHECK(rv == OK || rv == ERR_IO_PENDING);
-  if (rv == OK) {
+  if (rv != ERR_IO_PENDING) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
-                              weak_factory_.GetWeakPtr(), OK));
+                              weak_factory_.GetWeakPtr(), rv));
   }
 }
 
@@ -236,42 +226,15 @@
   return true;
 }
 
-void BidirectionalStreamQuicImpl::OnClose() {
-  DCHECK(stream_);
-
-  if (stream_->connection_error() != QUIC_NO_ERROR ||
-      stream_->stream_error() != QUIC_STREAM_NO_ERROR) {
-    OnError(session_->IsCryptoHandshakeConfirmed() ? ERR_QUIC_PROTOCOL_ERROR
-                                                   : ERR_QUIC_HANDSHAKE_FAILED);
-    return;
-  }
-
-  if (!stream_->fin_sent() || !stream_->fin_received()) {
-    // The connection must have been closed by the peer with QUIC_NO_ERROR,
-    // which is improper.
-    OnError(ERR_UNEXPECTED);
-    return;
-  }
-
-  // The connection was closed normally so there is no need to notify
-  // the delegate.
-  ResetStream();
-}
-
-void BidirectionalStreamQuicImpl::OnError(int error) {
-  // Avoid reentrancy by notifying the delegate asynchronously.
-  NotifyErrorImpl(error, /*notify_delegate_later*/ true);
-}
-
 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
   DCHECK_NE(ERR_IO_PENDING, rv);
-  DCHECK(rv == OK || !stream_);
+  DCHECK(!stream_);
   if (rv != OK) {
     NotifyError(rv);
     return;
   }
 
-  stream_ = session_->ReleaseStream(this);
+  stream_ = session_->ReleaseStream();
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::ReadInitialHeaders,
@@ -282,8 +245,8 @@
 
 void BidirectionalStreamQuicImpl::OnSendDataComplete(int rv) {
   CHECK(may_invoke_callbacks_);
-  DCHECK(rv == OK || !stream_);
-  if (rv != 0) {
+  DCHECK_NE(ERR_IO_PENDING, rv);
+  if (rv < 0) {
     NotifyError(rv);
     return;
   }
@@ -346,17 +309,21 @@
 
 void BidirectionalStreamQuicImpl::OnReadDataComplete(int rv) {
   CHECK(may_invoke_callbacks_);
-  DCHECK_GE(rv, 0);
+
   read_buffer_ = nullptr;
   read_buffer_len_ = 0;
 
-  if (stream_->IsDoneReading()) {
-    // If the write side is closed, OnFinRead() will call
-    // BidirectionalStreamQuicImpl::OnClose().
+  // If the write side is closed, OnFinRead() will call
+  // BidirectionalStreamQuicImpl::OnClose().
+  if (stream_->IsDoneReading())
     stream_->OnFinRead();
-  }
 
-  if (delegate_)
+  if (!delegate_)
+    return;
+
+  if (rv < 0)
+    NotifyError(rv);
+  else
     delegate_->OnDataRead(rv);
 }
 
@@ -397,9 +364,15 @@
 
 void BidirectionalStreamQuicImpl::NotifyStreamReady() {
   CHECK(may_invoke_callbacks_);
-  // Sending the request might result in the stream being closed.
-  if (send_request_headers_automatically_ && !WriteHeaders())
-    return;
+  if (send_request_headers_automatically_) {
+    int rv = WriteHeaders();
+    if (rv < 0) {
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
+                                weak_factory_.GetWeakPtr(), rv));
+      return;
+    }
+  }
 
   if (delegate_)
     delegate_->OnStreamReady(has_sent_headers_);
@@ -411,8 +384,6 @@
   closed_stream_received_bytes_ = stream_->stream_bytes_read();
   closed_stream_sent_bytes_ = stream_->stream_bytes_written();
   closed_is_first_stream_ = stream_->IsFirstStream();
-  stream_->ClearDelegate();
-  stream_ = nullptr;
 }
 
 }  // namespace net
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.h b/net/quic/chromium/bidirectional_stream_quic_impl.h
index 1b386466..8ec93aee 100644
--- a/net/quic/chromium/bidirectional_stream_quic_impl.h
+++ b/net/quic/chromium/bidirectional_stream_quic_impl.h
@@ -29,8 +29,7 @@
 class IOBuffer;
 
 class NET_EXPORT_PRIVATE BidirectionalStreamQuicImpl
-    : public BidirectionalStreamImpl,
-      public QuicChromiumClientStream::Delegate {
+    : public BidirectionalStreamImpl {
  public:
   explicit BidirectionalStreamQuicImpl(
       std::unique_ptr<QuicChromiumClientSession::Handle> session);
@@ -54,14 +53,7 @@
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
 
  private:
-  // QuicChromiumClientStream::Delegate implementation:
-  void OnClose() override;
-  void OnError(int error) override;
-
-  // Write headers to the stream and returns true on success. Posts a task to
-  // notify the delegate asynchronously and returns false on failure
-  bool WriteHeaders();
-
+  int WriteHeaders();
   void OnStreamReady(int rv);
   void OnSendDataComplete(int rv);
   void ReadInitialHeaders();
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
index 2ea276e2..ea69e90 100644
--- a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
+++ b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
@@ -1716,10 +1716,10 @@
   // Try to send data after OnFailed(), should not get called back.
   scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
   delegate->SendData(buf, buf->size(), false);
-  base::RunLoop().RunUntilIdle();
 
-  EXPECT_THAT(delegate->ReadData(cb.callback()), IsError(ERR_UNEXPECTED));
-  EXPECT_THAT(delegate->error(), IsError(ERR_UNEXPECTED));
+  EXPECT_THAT(delegate->ReadData(cb.callback()),
+              IsError(ERR_QUIC_PROTOCOL_ERROR));
+  EXPECT_THAT(delegate->error(), IsError(ERR_QUIC_PROTOCOL_ERROR));
   EXPECT_EQ(0, delegate->on_data_read_count());
   EXPECT_EQ(0, delegate->on_data_sent_count());
   EXPECT_EQ(kProtoQUIC, delegate->GetProtocol());
diff --git a/net/quic/chromium/quic_chromium_client_session.cc b/net/quic/chromium/quic_chromium_client_session.cc
index a2c88c8..3e47b88 100644
--- a/net/quic/chromium/quic_chromium_client_session.cc
+++ b/net/quic/chromium/quic_chromium_client_session.cc
@@ -305,11 +305,10 @@
 }
 
 std::unique_ptr<QuicChromiumClientStream::Handle>
-QuicChromiumClientSession::Handle::ReleaseStream(
-    QuicChromiumClientStream::Delegate* delegate) {
+QuicChromiumClientSession::Handle::ReleaseStream() {
   DCHECK(stream_request_);
 
-  auto handle = stream_request_->ReleaseStream(delegate);
+  auto handle = stream_request_->ReleaseStream();
   stream_request_.reset();
   return handle;
 }
@@ -381,12 +380,11 @@
 }
 
 std::unique_ptr<QuicChromiumClientStream::Handle>
-QuicChromiumClientSession::StreamRequest::ReleaseStream(
-    QuicChromiumClientStream::Delegate* delegate) {
+QuicChromiumClientSession::StreamRequest::ReleaseStream() {
   DCHECK(stream_);
   QuicChromiumClientStream* stream = stream_;
   stream_ = nullptr;
-  return stream->CreateHandle(delegate);
+  return stream->CreateHandle();
 }
 
 void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess(
diff --git a/net/quic/chromium/quic_chromium_client_session.h b/net/quic/chromium/quic_chromium_client_session.h
index 306224b7..2740521 100644
--- a/net/quic/chromium/quic_chromium_client_session.h
+++ b/net/quic/chromium/quic_chromium_client_session.h
@@ -90,9 +90,8 @@
     int RequestStream(bool requires_confirmation,
                       const CompletionCallback& callback);
 
-    // Releases |stream_| to the caller and sets |delegate| on the handle.
-    std::unique_ptr<QuicChromiumClientStream::Handle> ReleaseStream(
-        QuicChromiumClientStream::Delegate* delegate);
+    // Releases |stream_| to the caller.
+    std::unique_ptr<QuicChromiumClientStream::Handle> ReleaseStream();
 
     // Sends Rst for the stream, and makes sure that future calls to
     // IsClosedStream(id) return true, which ensures that any subsequent
@@ -193,9 +192,8 @@
     // complete |callback| will be called.
     int StartRequest(const CompletionCallback& callback);
 
-    // Releases |stream_| to the caller and sets |delegate| on it.
-    std::unique_ptr<QuicChromiumClientStream::Handle> ReleaseStream(
-        QuicChromiumClientStream::Delegate* delegate);
+    // Releases |stream_| to the caller.
+    std::unique_ptr<QuicChromiumClientStream::Handle> ReleaseStream();
 
    private:
     friend class QuicChromiumClientSession;
diff --git a/net/quic/chromium/quic_chromium_client_session_test.cc b/net/quic/chromium/quic_chromium_client_session_test.cc
index 1420732b..4fd2b39e4 100644
--- a/net/quic/chromium/quic_chromium_client_session_test.cc
+++ b/net/quic/chromium/quic_chromium_client_session_test.cc
@@ -58,25 +58,6 @@
 const uint16_t kServerPort = 443;
 const size_t kMaxReadersPerQuicSession = 5;
 
-class MockStreamDelegate : public QuicChromiumClientStream::Delegate {
- public:
-  MockStreamDelegate() {}
-
-  MOCK_METHOD0(OnSendData, int());
-  MOCK_METHOD2(OnSendDataComplete, int(int, bool*));
-  MOCK_METHOD2(OnInitialHeadersAvailable,
-               void(const SpdyHeaderBlock& headers, size_t frame_len));
-  MOCK_METHOD2(OnTrailingHeadersAvailable,
-               void(const SpdyHeaderBlock& headers, size_t frame_len));
-  MOCK_METHOD2(OnDataReceived, int(const char*, int));
-  MOCK_METHOD0(OnDataAvailable, void());
-  MOCK_METHOD0(OnClose, void());
-  MOCK_METHOD1(OnError, void(int));
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockStreamDelegate);
-};
-
 class QuicChromiumClientSessionTest
     : public ::testing::TestWithParam<QuicVersion> {
  protected:
@@ -178,7 +159,6 @@
   MockCryptoClientStreamFactory crypto_client_stream_factory_;
   QuicClientPushPromiseIndex push_promise_index_;
   QuicServerId server_id_;
-  MockStreamDelegate delegate_;
   std::unique_ptr<QuicChromiumClientSession> session_;
   TestServerPushDelegate test_push_delegate_;
   QuicConnectionVisitorInterface* visitor_;
@@ -240,7 +220,7 @@
   TestCompletionCallback callback;
   ASSERT_EQ(OK, handle->RequestStream(/*requires_confirmation=*/false,
                                       callback.callback()));
-  EXPECT_TRUE(handle->ReleaseStream(&delegate_) != nullptr);
+  EXPECT_TRUE(handle->ReleaseStream() != nullptr);
 
   quic_data.Resume();
   EXPECT_TRUE(quic_data.AllReadDataConsumed());
@@ -302,7 +282,7 @@
   TestCompletionCallback callback;
   ASSERT_EQ(OK, handle->RequestStream(/*requires_confirmation=*/false,
                                       callback.callback()));
-  EXPECT_TRUE(handle->ReleaseStream(&delegate_) != nullptr);
+  EXPECT_TRUE(handle->ReleaseStream() != nullptr);
 
   quic_data.Resume();
   EXPECT_TRUE(quic_data.AllReadDataConsumed());
@@ -325,7 +305,7 @@
   TestCompletionCallback callback;
   ASSERT_EQ(OK, handle->RequestStream(/*requires_confirmation=*/true,
                                       callback.callback()));
-  EXPECT_TRUE(handle->ReleaseStream(&delegate_) != nullptr);
+  EXPECT_TRUE(handle->ReleaseStream() != nullptr);
 
   quic_data.Resume();
   EXPECT_TRUE(quic_data.AllReadDataConsumed());
@@ -353,7 +333,7 @@
 
   EXPECT_THAT(callback.WaitForResult(), IsOk());
 
-  EXPECT_TRUE(handle->ReleaseStream(&delegate_) != nullptr);
+  EXPECT_TRUE(handle->ReleaseStream() != nullptr);
 
   quic_data.Resume();
   EXPECT_TRUE(quic_data.AllReadDataConsumed());
@@ -419,7 +399,7 @@
   session_->OnRstStream(rst);
   ASSERT_TRUE(callback.have_result());
   EXPECT_THAT(callback.WaitForResult(), IsOk());
-  EXPECT_TRUE(handle->ReleaseStream(&delegate_) != nullptr);
+  EXPECT_TRUE(handle->ReleaseStream() != nullptr);
 
   quic_data.Resume();
   EXPECT_TRUE(quic_data.AllReadDataConsumed());
@@ -924,7 +904,7 @@
   session_->OnRstStream(rst1);
   ASSERT_TRUE(callback.have_result());
   EXPECT_THAT(callback.WaitForResult(), IsOk());
-  EXPECT_TRUE(handle->ReleaseStream(&delegate_) != nullptr);
+  EXPECT_TRUE(handle->ReleaseStream() != nullptr);
 }
 
 TEST_P(QuicChromiumClientSessionTest, GoAwayReceived) {
diff --git a/net/quic/chromium/quic_chromium_client_stream.cc b/net/quic/chromium/quic_chromium_client_stream.cc
index 0014b40..029cd4d8 100644
--- a/net/quic/chromium/quic_chromium_client_stream.cc
+++ b/net/quic/chromium/quic_chromium_client_stream.cc
@@ -20,13 +20,30 @@
 #include "net/quic/core/spdy_utils.h"
 
 namespace net {
+namespace {
+// Sets a boolean to a value, and restores it to the previous value once
+// the saver goes out of scope.
+class ScopedBoolSaver {
+ public:
+  ScopedBoolSaver(bool* var, bool new_val) : var_(var), old_val_(*var) {
+    *var_ = new_val;
+  }
 
-QuicChromiumClientStream::Handle::Handle(QuicChromiumClientStream* stream,
-                                         Delegate* delegate)
+  ~ScopedBoolSaver() { *var_ = old_val_; }
+
+ private:
+  bool* var_;
+  bool old_val_;
+};
+}  // namespace
+
+QuicChromiumClientStream::Handle::Handle(QuicChromiumClientStream* stream)
     : stream_(stream),
-      delegate_(delegate),
+      may_invoke_callbacks_(true),
       read_headers_buffer_(nullptr),
-      read_body_buffer_len_(0) {
+      read_body_buffer_len_(0),
+      net_error_(ERR_UNEXPECTED),
+      weak_factory_(this) {
   SaveState();
 }
 
@@ -39,10 +56,6 @@
   }
 }
 
-void QuicChromiumClientStream::Handle::ClearDelegate() {
-  delegate_ = nullptr;
-}
-
 void QuicChromiumClientStream::Handle::OnInitialHeadersAvailable() {
   if (!read_headers_callback_)
     return;  // Wait for ReadInitialHeaders to be called.
@@ -51,7 +64,7 @@
   if (!stream_->DeliverInitialHeaders(read_headers_buffer_, &rv))
     rv = ERR_QUIC_PROTOCOL_ERROR;
 
-  ResetAndReturn(&read_headers_callback_).Run(rv);
+  ResetAndRun(&read_headers_callback_, rv);
 }
 
 void QuicChromiumClientStream::Handle::OnTrailingHeadersAvailable() {
@@ -62,7 +75,7 @@
   if (!stream_->DeliverTrailingHeaders(read_headers_buffer_, &rv))
     rv = ERR_QUIC_PROTOCOL_ERROR;
 
-  ResetAndReturn(&read_headers_callback_).Run(rv);
+  ResetAndRun(&read_headers_callback_, rv);
 }
 
 void QuicChromiumClientStream::Handle::OnDataAvailable() {
@@ -75,50 +88,70 @@
 
   read_body_buffer_ = nullptr;
   read_body_buffer_len_ = 0;
-  ResetAndReturn(&read_body_callback_).Run(rv);
+  ResetAndRun(&read_body_callback_, rv);
 }
 
 void QuicChromiumClientStream::Handle::OnCanWrite() {
   if (!write_callback_)
     return;
 
-  base::ResetAndReturn(&write_callback_).Run(OK);
+  ResetAndRun(&write_callback_, OK);
 }
 
 void QuicChromiumClientStream::Handle::OnClose() {
-  if (stream_)
-    SaveState();
-  stream_ = nullptr;
-  if (delegate_) {
-    auto* delegate = delegate_;
-    delegate_ = nullptr;
-    delegate->OnClose();
+  if (net_error_ == ERR_UNEXPECTED) {
+    if (stream_error() == QUIC_STREAM_NO_ERROR &&
+        connection_error() == QUIC_NO_ERROR && fin_sent() && fin_received()) {
+      net_error_ = ERR_CONNECTION_CLOSED;
+    } else {
+      net_error_ = ERR_QUIC_PROTOCOL_ERROR;
+    }
   }
+  OnError(net_error_);
 }
 
 void QuicChromiumClientStream::Handle::OnError(int error) {
+  net_error_ = error;
   if (stream_)
     SaveState();
   stream_ = nullptr;
-  if (delegate_) {
-    auto* delegate = delegate_;
-    delegate_ = nullptr;
-    delegate->OnError(error);
+
+  // Post a task to invoke the callbacks to ensure that there is no reentrancy.
+  // A ScopedPacketBundler might cause an error which closes the stream under
+  // the call stack of the owner of the handle.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&QuicChromiumClientStream::Handle::InvokeCallbacksOnClose,
+                 weak_factory_.GetWeakPtr(), error));
+}
+
+void QuicChromiumClientStream::Handle::InvokeCallbacksOnClose(int error) {
+  // Invoking a callback may cause |this| to be deleted. If this happens, no
+  // more callbacks should be invoked. Guard against this by holding a WeakPtr
+  // to |this| and ensuring it's still valid.
+  auto guard(weak_factory_.GetWeakPtr());
+  for (auto* callback :
+       {&read_headers_callback_, &read_body_callback_, &write_callback_}) {
+    if (*callback)
+      ResetAndRun(callback, error);
+    if (!guard.get())
+      return;
   }
 }
 
 int QuicChromiumClientStream::Handle::ReadInitialHeaders(
     SpdyHeaderBlock* header_block,
     const CompletionCallback& callback) {
+  ScopedBoolSaver saver(&may_invoke_callbacks_, false);
   if (!stream_)
-    return ERR_CONNECTION_CLOSED;
+    return net_error_;
 
   int frame_len = 0;
   if (stream_->DeliverInitialHeaders(header_block, &frame_len))
     return frame_len;
 
   read_headers_buffer_ = header_block;
-  read_headers_callback_ = callback;
+  SetCallback(callback, &read_headers_callback_);
   return ERR_IO_PENDING;
 }
 
@@ -126,14 +159,18 @@
     IOBuffer* buffer,
     int buffer_len,
     const CompletionCallback& callback) {
+  ScopedBoolSaver saver(&may_invoke_callbacks_, false);
+  if (IsDoneReading())
+    return OK;
+
   if (!stream_)
-    return ERR_CONNECTION_CLOSED;
+    return net_error_;
 
   int rv = stream_->Read(buffer, buffer_len);
   if (rv != ERR_IO_PENDING)
     return rv;
 
-  read_body_callback_ = callback;
+  SetCallback(callback, &read_body_callback_);
   read_body_buffer_ = buffer;
   read_body_buffer_len_ = buffer_len;
   return ERR_IO_PENDING;
@@ -142,40 +179,42 @@
 int QuicChromiumClientStream::Handle::ReadTrailingHeaders(
     SpdyHeaderBlock* header_block,
     const CompletionCallback& callback) {
+  ScopedBoolSaver saver(&may_invoke_callbacks_, false);
   if (!stream_)
-    return ERR_CONNECTION_CLOSED;
+    return net_error_;
 
   int frame_len = 0;
   if (stream_->DeliverTrailingHeaders(header_block, &frame_len))
     return frame_len;
 
   read_headers_buffer_ = header_block;
-  read_headers_callback_ = callback;
+  SetCallback(callback, &read_headers_callback_);
   return ERR_IO_PENDING;
 }
 
-size_t QuicChromiumClientStream::Handle::WriteHeaders(
+int QuicChromiumClientStream::Handle::WriteHeaders(
     SpdyHeaderBlock header_block,
     bool fin,
     QuicReferenceCountedPointer<QuicAckListenerInterface>
         ack_notifier_delegate) {
   if (!stream_)
     return 0;
-  return stream_->WriteHeaders(std::move(header_block), fin,
-                               ack_notifier_delegate);
+  return HandleIOComplete(stream_->WriteHeaders(std::move(header_block), fin,
+                                                ack_notifier_delegate));
 }
 
 int QuicChromiumClientStream::Handle::WriteStreamData(
     base::StringPiece data,
     bool fin,
     const CompletionCallback& callback) {
+  ScopedBoolSaver saver(&may_invoke_callbacks_, false);
   if (!stream_)
-    return ERR_CONNECTION_CLOSED;
+    return net_error_;
 
   if (stream_->WriteStreamData(data, fin))
-    return OK;
+    return HandleIOComplete(OK);
 
-  write_callback_ = callback;
+  SetCallback(callback, &write_callback_);
   return ERR_IO_PENDING;
 }
 
@@ -184,23 +223,25 @@
     const std::vector<int>& lengths,
     bool fin,
     const CompletionCallback& callback) {
+  ScopedBoolSaver saver(&may_invoke_callbacks_, false);
   if (!stream_)
-    return ERR_CONNECTION_CLOSED;
+    return net_error_;
 
   if (stream_->WritevStreamData(buffers, lengths, fin))
-    return OK;
+    return HandleIOComplete(OK);
 
-  write_callback_ = callback;
+  SetCallback(callback, &write_callback_);
   return ERR_IO_PENDING;
 }
 
 int QuicChromiumClientStream::Handle::Read(IOBuffer* buf, int buf_len) {
   if (!stream_)
-    return ERR_CONNECTION_CLOSED;
+    return net_error_;
   return stream_->Read(buf, buf_len);
 }
 
 void QuicChromiumClientStream::Handle::OnFinRead() {
+  read_headers_callback_.Reset();
   if (stream_)
     stream_->OnFinRead();
 }
@@ -300,11 +341,6 @@
   return stream_->can_migrate();
 }
 
-QuicChromiumClientStream::Delegate*
-QuicChromiumClientStream::Handle::GetDelegate() {
-  return delegate_;
-}
-
 void QuicChromiumClientStream::Handle::SaveState() {
   DCHECK(stream_);
   fin_sent_ = stream_->fin_sent();
@@ -320,6 +356,37 @@
   priority_ = stream_->priority();
 }
 
+void QuicChromiumClientStream::Handle::SetCallback(
+    const CompletionCallback& new_callback,
+    CompletionCallback* callback) {
+  // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
+  // bug free.
+  CHECK(!may_invoke_callbacks_);
+  *callback = new_callback;
+}
+
+void QuicChromiumClientStream::Handle::ResetAndRun(CompletionCallback* callback,
+                                                   int rv) {
+  // TODO(rch): Convert this to a DCHECK once we ensure the API is stable and
+  // bug free.
+  CHECK(may_invoke_callbacks_);
+  ResetAndReturn(callback).Run(rv);
+}
+
+int QuicChromiumClientStream::Handle::HandleIOComplete(int rv) {
+  // If |stream_| is still valid the stream has not been closed. If the stream
+  // has not been closed, then just return |rv|.
+  if (rv < 0 || stream_)
+    return rv;
+
+  if (stream_error_ == QUIC_STREAM_NO_ERROR &&
+      connection_error_ == QUIC_NO_ERROR && fin_sent_ && fin_received_) {
+    return rv;
+  }
+
+  return net_error_;
+}
+
 QuicChromiumClientStream::QuicChromiumClientStream(
     QuicStreamId id,
     QuicClientSessionBase* session,
@@ -479,11 +546,10 @@
 }
 
 std::unique_ptr<QuicChromiumClientStream::Handle>
-QuicChromiumClientStream::CreateHandle(
-    QuicChromiumClientStream::Delegate* delegate) {
+QuicChromiumClientStream::CreateHandle() {
   DCHECK(!handle_);
   auto handle = std::unique_ptr<QuicChromiumClientStream::Handle>(
-      new QuicChromiumClientStream::Handle(this, delegate));
+      new QuicChromiumClientStream::Handle(this));
   handle_ = handle.get();
 
   // Should this perhaps be via PostTask to make reasoning simpler?
@@ -552,7 +618,7 @@
     return;
 
   DCHECK(headers_delivered_);
-  // Post an async task to notify delegate of the FIN flag.
+  // Post an async task to notify handle of the FIN flag.
   NotifyHandleOfDataAvailableLater();
   handle_->OnTrailingHeadersAvailable();
 }
diff --git a/net/quic/chromium/quic_chromium_client_stream.h b/net/quic/chromium/quic_chromium_client_stream.h
index e95d4784..80a84b17 100644
--- a/net/quic/chromium/quic_chromium_client_stream.h
+++ b/net/quic/chromium/quic_chromium_client_stream.h
@@ -32,26 +32,6 @@
 // are owned by the QuicClientSession which created them.
 class NET_EXPORT_PRIVATE QuicChromiumClientStream : public QuicSpdyStream {
  public:
-  // TODO(rch): Remove this class completely in favor of async methods
-  // on the Handle.
-  // Delegate handles protocol specific behavior of a quic stream.
-  class NET_EXPORT_PRIVATE Delegate {
-   public:
-    Delegate() {}
-
-    // Called when the stream is closed by the peer.
-    virtual void OnClose() = 0;
-
-    // Called when the stream is closed because of an error.
-    virtual void OnError(int error) = 0;
-
-   protected:
-    virtual ~Delegate() {}
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Delegate);
-  };
-
   // Wrapper for interacting with the session in a restricted fashion.
   class NET_EXPORT_PRIVATE Handle {
    public:
@@ -89,11 +69,13 @@
 
     // Writes |header_block| to the peer. Closes the write side if |fin| is
     // true. If non-null, |ack_notifier_delegate| will be notified when the
-    // headers are ACK'd by the peer.
-    size_t WriteHeaders(SpdyHeaderBlock header_block,
-                        bool fin,
-                        QuicReferenceCountedPointer<QuicAckListenerInterface>
-                            ack_notifier_delegate);
+    // headers are ACK'd by the peer. Returns a net error code if there is
+    // an error writing the headers, or the number of bytes written on
+    // success. Will not return ERR_IO_PENDING.
+    int WriteHeaders(SpdyHeaderBlock header_block,
+                     bool fin,
+                     QuicReferenceCountedPointer<QuicAckListenerInterface>
+                         ack_notifier_delegate);
 
     // Writes |data| to the peer. Closes the write side if |fin| is true.
     // If the data could not be written immediately, returns ERR_IO_PENDING
@@ -126,10 +108,6 @@
     // Sends a RST_STREAM frame to the peer and closes the streams.
     void Reset(QuicRstStreamErrorCode error_code);
 
-    // Clears |delegate_| from this Handle, but does not disconnect the Handle
-    // from |stream_|.
-    void ClearDelegate();
-
     QuicStreamId id() const;
     QuicErrorCode connection_error() const;
     QuicRstStreamErrorCode stream_error() const;
@@ -148,14 +126,11 @@
     SpdyPriority priority() const;
     bool can_migrate();
 
-    Delegate* GetDelegate();
-
    private:
     friend class QuicChromiumClientStream;
 
-    // Constucts a new Handle for |stream| with |delegate| set to receive
-    // up calls on various events.
-    Handle(QuicChromiumClientStream* stream, Delegate* delegate);
+    // Constucts a new Handle for |stream|.
+    explicit Handle(QuicChromiumClientStream* stream);
 
     // Methods invoked by the stream.
     void OnInitialHeadersAvailable();
@@ -165,11 +140,22 @@
     void OnClose();
     void OnError(int error);
 
+    // Invokes async IO callbacks because of |error|.
+    void InvokeCallbacksOnClose(int error);
+
     // Saves various fields from the stream before the stream goes away.
     void SaveState();
 
+    void SetCallback(const CompletionCallback& new_callback,
+                     CompletionCallback* callback);
+
+    void ResetAndRun(CompletionCallback* callback, int rv);
+
+    int HandleIOComplete(int rv);
+
     QuicChromiumClientStream* stream_;  // Unowned.
-    Delegate* delegate_;                // Owns this.
+
+    bool may_invoke_callbacks_;  // True when callbacks may be invoked.
 
     // Callback to be invoked when ReadHeaders completes asynchronously.
     CompletionCallback read_headers_callback_;
@@ -196,6 +182,10 @@
     size_t num_bytes_consumed_;
     SpdyPriority priority_;
 
+    int net_error_;
+
+    base::WeakPtrFactory<Handle> weak_factory_;
+
     DISALLOW_COPY_AND_ASSIGN(Handle);
   };
 
@@ -238,10 +228,8 @@
                         const std::vector<int>& lengths,
                         bool fin);
 
-  // Creates a new Handle for this stream and sets |delegate| on the handle.
-  // Must only be called once.
-  std::unique_ptr<QuicChromiumClientStream::Handle> CreateHandle(
-      QuicChromiumClientStream::Delegate* delegate);
+  // Creates a new Handle for this stream. Must only be called once.
+  std::unique_ptr<QuicChromiumClientStream::Handle> CreateHandle();
 
   // Clears |handle_| from this stream.
   void ClearHandle();
@@ -290,7 +278,7 @@
   // Set to false if this stream to not be migrated during connection migration.
   bool can_migrate_;
 
-  // Stores the initial header if they arrive before the delegate.
+  // Stores the initial header if they arrive before the handle.
   SpdyHeaderBlock initial_headers_;
   // Length of the HEADERS frame containing initial headers.
   size_t initial_headers_frame_len_;
diff --git a/net/quic/chromium/quic_chromium_client_stream_test.cc b/net/quic/chromium/quic_chromium_client_stream_test.cc
index bb20cb3..9ac3ee4 100644
--- a/net/quic/chromium/quic_chromium_client_stream_test.cc
+++ b/net/quic/chromium/quic_chromium_client_stream_test.cc
@@ -38,23 +38,6 @@
 
 const QuicStreamId kTestStreamId = 5u;
 
-class MockDelegate : public QuicChromiumClientStream::Delegate {
- public:
-  MockDelegate() {}
-
-  MOCK_METHOD0(OnSendData, int());
-  MOCK_METHOD2(OnSendDataComplete, int(int, bool*));
-  MOCK_METHOD0(OnClose, void());
-  MOCK_METHOD1(OnError, void(int));
-  MOCK_METHOD0(HasSendHeadersComplete, bool());
-
-  SpdyHeaderBlock headers_;
-  SpdyHeaderBlock trailers_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockDelegate);
-};
-
 class MockQuicClientSessionBase : public QuicClientSessionBase {
  public:
   explicit MockQuicClientSessionBase(QuicConnection* connection,
@@ -183,7 +166,7 @@
     stream_ = new QuicChromiumClientStream(kTestStreamId, &session_,
                                            NetLogWithSource());
     session_.ActivateStream(base::WrapUnique(stream_));
-    handle_ = stream_->CreateHandle(&delegate_);
+    handle_ = stream_->CreateHandle();
   }
 
   void InitializeHeaders() {
@@ -239,10 +222,9 @@
   QuicHeaderList ProcessHeadersFull(const SpdyHeaderBlock& headers) {
     QuicHeaderList h = ProcessHeaders(headers);
     TestCompletionCallback callback;
-    EXPECT_EQ(
-        static_cast<int>(h.uncompressed_header_bytes()),
-        handle_->ReadInitialHeaders(&delegate_.headers_, callback.callback()));
-    EXPECT_EQ(headers, delegate_.headers_);
+    EXPECT_EQ(static_cast<int>(h.uncompressed_header_bytes()),
+              handle_->ReadInitialHeaders(&headers_, callback.callback()));
+    EXPECT_EQ(headers, headers_);
     EXPECT_TRUE(stream_->header_list().empty());
     return h;
   }
@@ -261,14 +243,13 @@
 
   QuicCryptoClientConfig crypto_config_;
   std::unique_ptr<QuicChromiumClientStream::Handle> handle_;
-  testing::StrictMock<MockDelegate> delegate_;
   std::unique_ptr<QuicChromiumClientStream::Handle> handle2_;
-  testing::StrictMock<MockDelegate> delegate2_;
   MockQuicConnectionHelper helper_;
   MockAlarmFactory alarm_factory_;
   MockQuicClientSessionBase session_;
   QuicChromiumClientStream* stream_;
   SpdyHeaderBlock headers_;
+  SpdyHeaderBlock trailers_;
   QuicClientPushPromiseIndex push_promise_index_;
 };
 
@@ -293,7 +274,6 @@
   QuicStreamOffset offset = 0;
   ProcessHeadersFull(headers_);
   QuicStreamFrame frame2(kTestStreamId, true, offset, QuicStringPiece());
-  EXPECT_CALL(delegate_, OnClose());
   stream_->OnStreamFrame(frame2);
   EXPECT_TRUE(handle_->fin_received());
   handle_->OnFinRead();
@@ -332,12 +312,10 @@
       handle_->WritevStreamData(buffers, lengths, true, callback.callback()));
 
   SpdyHeaderBlock headers;
-  EXPECT_EQ(0u, handle_->WriteHeaders(std::move(headers), true, nullptr));
+  EXPECT_EQ(0, handle_->WriteHeaders(std::move(headers), true, nullptr));
 }
 
 TEST_P(QuicChromiumClientStreamTest, HandleAfterConnectionClose) {
-  // Verify that the delegate's OnClose is called after closing the connection.
-  EXPECT_CALL(delegate_, OnClose());
   EXPECT_CALL(session_,
               SendRstStream(kTestStreamId, QUIC_RST_ACKNOWLEDGEMENT, 0));
   stream_->OnConnectionClosed(QUIC_INVALID_FRAME_DATA,
@@ -348,24 +326,7 @@
 }
 
 TEST_P(QuicChromiumClientStreamTest, HandleAfterStreamReset) {
-  // Verify that the delegate's OnClose is called after the stream is reset,
-  // but that the Handle still behaves correctly.
-  EXPECT_CALL(delegate_, OnClose());
-  QuicRstStreamFrame rst(kTestStreamId, QUIC_STREAM_CANCELLED, 0);
-  EXPECT_CALL(session_,
-              SendRstStream(kTestStreamId, QUIC_RST_ACKNOWLEDGEMENT, 0));
-  stream_->OnStreamReset(rst);
-
-  EXPECT_FALSE(handle_->IsOpen());
-  EXPECT_EQ(QUIC_STREAM_CANCELLED, handle_->stream_error());
-}
-
-TEST_P(QuicChromiumClientStreamTest, HandleAfterClearDelegate) {
-  EXPECT_TRUE(handle_->IsOpen());
-  handle_->ClearDelegate();
-
-  // Verify that the delegate's OnClose is not called after ClearDelegate.
-  EXPECT_CALL(delegate_, OnClose()).Times(0);
+  // Verify that the Handle still behaves correctly after the stream is reset.
   QuicRstStreamFrame rst(kTestStreamId, QUIC_STREAM_CANCELLED, 0);
   EXPECT_CALL(session_,
               SendRstStream(kTestStreamId, QUIC_RST_ACKNOWLEDGEMENT, 0));
@@ -380,7 +341,6 @@
   QuicStreamOffset offset = 0;
   ProcessHeadersFull(headers_);
   QuicStreamFrame frame2(kTestStreamId, true, offset, QuicStringPiece());
-  EXPECT_CALL(delegate_, OnClose());
   stream_->OnStreamFrame(frame2);
 }
 
@@ -399,8 +359,6 @@
   EXPECT_EQ(data_len,
             handle_->ReadBody(buffer.get(), 2 * data_len, callback.callback()));
   EXPECT_EQ(QuicStringPiece(data), QuicStringPiece(buffer->data(), data_len));
-
-  EXPECT_CALL(delegate_, OnClose());
 }
 
 TEST_P(QuicChromiumClientStreamTest, OnDataAvailableAfterReadBody) {
@@ -422,8 +380,6 @@
   EXPECT_EQ(data_len, callback.WaitForResult());
   EXPECT_EQ(QuicStringPiece(data), QuicStringPiece(buffer->data(), data_len));
   base::RunLoop().RunUntilIdle();
-
-  EXPECT_CALL(delegate_, OnClose());
 }
 
 TEST_P(QuicChromiumClientStreamTest, ProcessHeadersWithError) {
@@ -437,8 +393,6 @@
                               headers);
 
   base::RunLoop().RunUntilIdle();
-
-  EXPECT_CALL(delegate_, OnClose());
 }
 
 TEST_P(QuicChromiumClientStreamTest, OnDataAvailableWithError) {
@@ -464,12 +418,10 @@
                                          /*offset=*/0, data));
 
   base::RunLoop().RunUntilIdle();
-
-  EXPECT_CALL(delegate_, OnClose());
 }
 
 TEST_P(QuicChromiumClientStreamTest, OnError) {
-  EXPECT_CALL(delegate_, OnError(ERR_INTERNET_DISCONNECTED)).Times(1);
+  //  EXPECT_CALL(delegate_, OnError(ERR_INTERNET_DISCONNECTED)).Times(1);
 
   stream_->OnError(ERR_INTERNET_DISCONNECTED);
   stream_->OnError(ERR_INTERNET_DISCONNECTED);
@@ -498,9 +450,9 @@
   auto t = ProcessTrailers(trailers);
 
   TestCompletionCallback trailers_callback;
-  EXPECT_EQ(static_cast<int>(t.uncompressed_header_bytes()),
-            handle_->ReadTrailingHeaders(&delegate_.trailers_,
-                                         trailers_callback.callback()));
+  EXPECT_EQ(
+      static_cast<int>(t.uncompressed_header_bytes()),
+      handle_->ReadTrailingHeaders(&trailers_, trailers_callback.callback()));
 
   // Read the body and verify that it arrives correctly.
   EXPECT_EQ(0,
@@ -508,9 +460,8 @@
 
   // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers.
   trailers.erase(kFinalOffsetHeaderKey);
-  EXPECT_EQ(trailers, delegate_.trailers_);
+  EXPECT_EQ(trailers, trailers_);
   base::RunLoop().RunUntilIdle();
-  EXPECT_CALL(delegate_, OnClose());
 }
 
 // Tests that trailers are marked as consumed only before delegate is to be
@@ -542,9 +493,8 @@
   QuicHeaderList t = ProcessTrailers(trailers);
   EXPECT_FALSE(stream_->IsDoneReading());
 
-  EXPECT_EQ(
-      static_cast<int>(t.uncompressed_header_bytes()),
-      handle_->ReadTrailingHeaders(&delegate_.trailers_, callback.callback()));
+  EXPECT_EQ(static_cast<int>(t.uncompressed_header_bytes()),
+            handle_->ReadTrailingHeaders(&trailers_, callback.callback()));
 
   // Read the body and verify that it arrives correctly.
   EXPECT_EQ(0, callback.WaitForResult());
@@ -554,10 +504,9 @@
   EXPECT_TRUE(stream_->IsDoneReading());
   // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers.
   trailers.erase(kFinalOffsetHeaderKey);
-  EXPECT_EQ(trailers, delegate_.trailers_);
+  EXPECT_EQ(trailers, trailers_);
 
   base::RunLoop().RunUntilIdle();
-  EXPECT_CALL(delegate_, OnClose());
 }
 
 // Test that if Read() is called after response body is read and after trailers
@@ -596,9 +545,8 @@
   EXPECT_FALSE(stream_->IsDoneReading());
 
   TestCompletionCallback callback2;
-  EXPECT_EQ(
-      static_cast<int>(t.uncompressed_header_bytes()),
-      handle_->ReadTrailingHeaders(&delegate_.trailers_, callback2.callback()));
+  EXPECT_EQ(static_cast<int>(t.uncompressed_header_bytes()),
+            handle_->ReadTrailingHeaders(&trailers_, callback2.callback()));
 
   // Read the body and verify that it arrives correctly.
   // OnDataAvailable() should follow right after and Read() will return 0.
@@ -610,15 +558,12 @@
 
   // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers.
   trailers.erase(kFinalOffsetHeaderKey);
-  EXPECT_EQ(trailers, delegate_.trailers_);
+  EXPECT_EQ(trailers, trailers_);
 
   base::RunLoop().RunUntilIdle();
-  EXPECT_CALL(delegate_, OnClose());
 }
 
 TEST_P(QuicChromiumClientStreamTest, WriteStreamData) {
-  EXPECT_CALL(delegate_, OnClose());
-
   const char kData1[] = "hello world";
   const size_t kDataLen = arraysize(kData1);
 
@@ -631,9 +576,6 @@
 }
 
 TEST_P(QuicChromiumClientStreamTest, WriteStreamDataAsync) {
-  EXPECT_CALL(delegate_, HasSendHeadersComplete()).Times(AnyNumber());
-  EXPECT_CALL(delegate_, OnClose());
-
   const char kData1[] = "hello world";
   const size_t kDataLen = arraysize(kData1);
 
@@ -655,8 +597,6 @@
 }
 
 TEST_P(QuicChromiumClientStreamTest, WritevStreamData) {
-  EXPECT_CALL(delegate_, OnClose());
-
   scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer("hello world!"));
   scoped_refptr<StringIOBuffer> buf2(
       new StringIOBuffer("Just a small payload"));
@@ -672,9 +612,6 @@
 }
 
 TEST_P(QuicChromiumClientStreamTest, WritevStreamDataAsync) {
-  EXPECT_CALL(delegate_, HasSendHeadersComplete()).Times(AnyNumber());
-  EXPECT_CALL(delegate_, OnClose());
-
   scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer("hello world!"));
   scoped_refptr<StringIOBuffer> buf2(
       new StringIOBuffer("Just a small payload"));
@@ -700,7 +637,7 @@
   EXPECT_THAT(callback.WaitForResult(), IsOk());
 }
 
-TEST_P(QuicChromiumClientStreamTest, HeadersBeforeDelegate) {
+TEST_P(QuicChromiumClientStreamTest, HeadersBeforeHandle) {
   // We don't use stream_ because we want an incoming server push
   // stream.
   QuicStreamId stream_id = GetNthServerInitiatedStreamId(0);
@@ -714,22 +651,16 @@
   QuicHeaderList header_list = AsHeaderList(headers_);
   stream2->OnStreamHeaderList(true, header_list.uncompressed_header_bytes(),
                               header_list);
-  EXPECT_TRUE(delegate2_.headers_.empty());
 
   // Now set the delegate and verify that the headers are delivered.
-  handle2_ = stream2->CreateHandle(&delegate2_);
+  handle2_ = stream2->CreateHandle();
   TestCompletionCallback callback;
-  EXPECT_EQ(
-      static_cast<int>(header_list.uncompressed_header_bytes()),
-      handle2_->ReadInitialHeaders(&delegate2_.headers_, callback.callback()));
-  EXPECT_EQ(headers_, delegate2_.headers_);
-
-  // Both delegates should be notified that theirs streams are closed.
-  EXPECT_CALL(delegate2_, OnClose());
-  EXPECT_CALL(delegate_, OnClose());
+  EXPECT_EQ(static_cast<int>(header_list.uncompressed_header_bytes()),
+            handle2_->ReadInitialHeaders(&headers_, callback.callback()));
+  EXPECT_EQ(headers_, headers_);
 }
 
-TEST_P(QuicChromiumClientStreamTest, HeadersAndDataBeforeDelegate) {
+TEST_P(QuicChromiumClientStreamTest, HeadersAndDataBeforeHandle) {
   // We don't use stream_ because we want an incoming server push
   // stream.
   QuicStreamId stream_id = GetNthServerInitiatedStreamId(0);
@@ -743,19 +674,17 @@
   QuicHeaderList header_list = AsHeaderList(headers_);
   stream2->OnStreamHeaderList(false, header_list.uncompressed_header_bytes(),
                               header_list);
-  EXPECT_TRUE(delegate2_.headers_.empty());
   const char data[] = "hello world!";
   stream2->OnStreamFrame(QuicStreamFrame(stream_id, /*fin=*/false,
                                          /*offset=*/0, data));
 
   // Now set the delegate and verify that the headers are delivered, but
   // not the data, which needs to be read explicitly.
-  handle2_ = stream2->CreateHandle(&delegate2_);
+  handle2_ = stream2->CreateHandle();
   TestCompletionCallback callback;
-  EXPECT_EQ(
-      static_cast<int>(header_list.uncompressed_header_bytes()),
-      handle2_->ReadInitialHeaders(&delegate2_.headers_, callback.callback()));
-  EXPECT_EQ(headers_, delegate2_.headers_);
+  EXPECT_EQ(static_cast<int>(header_list.uncompressed_header_bytes()),
+            handle2_->ReadInitialHeaders(&headers_, callback.callback()));
+  EXPECT_EQ(headers_, headers_);
   base::RunLoop().RunUntilIdle();
 
   // Now explicitly read the data.
@@ -763,10 +692,6 @@
   scoped_refptr<IOBuffer> buffer(new IOBuffer(data_len + 1));
   ASSERT_EQ(data_len, stream2->Read(buffer.get(), data_len + 1));
   EXPECT_EQ(QuicStringPiece(data), QuicStringPiece(buffer->data(), data_len));
-
-  // Both delegates should be notified that theirs streams are closed.
-  EXPECT_CALL(delegate2_, OnClose());
-  EXPECT_CALL(delegate_, OnClose());
 }
 
 }  // namespace
diff --git a/net/quic/chromium/quic_http_stream.cc b/net/quic/chromium/quic_http_stream.cc
index c2caf5c..140dbc0a 100644
--- a/net/quic/chromium/quic_http_stream.cc
+++ b/net/quic/chromium/quic_http_stream.cc
@@ -64,8 +64,6 @@
       closed_is_first_stream_(false),
       user_buffer_len_(0),
       session_error_(ERR_UNEXPECTED),
-      quic_connection_error_(QUIC_NO_ERROR),
-      quic_stream_error_(QUIC_STREAM_NO_ERROR),
       found_promise_(false),
       push_handle_(nullptr),
       in_loop_(false),
@@ -107,8 +105,7 @@
 void QuicHttpStream::OnRendezvousResult(QuicSpdyStream* stream) {
   push_handle_ = nullptr;
   if (stream) {
-    stream_ =
-        static_cast<QuicChromiumClientStream*>(stream)->CreateHandle(this);
+    stream_ = static_cast<QuicChromiumClientStream*>(stream)->CreateHandle();
   }
 
   // callback_ should only be non-null in the case of asynchronous
@@ -193,7 +190,7 @@
   if (rv == ERR_IO_PENDING)
     callback_ = callback;
 
-  return rv;
+  return MapStreamError(rv);
 }
 
 int QuicHttpStream::DoHandlePromise() {
@@ -305,16 +302,13 @@
   if (rv == ERR_IO_PENDING)
     callback_ = callback;
 
-  return rv > 0 ? OK : rv;
+  return rv > 0 ? OK : MapStreamError(rv);
 }
 
 int QuicHttpStream::ReadResponseHeaders(const CompletionCallback& callback) {
   CHECK(callback_.is_null());
   CHECK(!callback.is_null());
 
-  if (stream_ == nullptr)
-    return GetResponseStatus();
-
   int rv = stream_->ReadInitialHeaders(
       &response_header_block_,
       base::Bind(&QuicHttpStream::OnReadResponseHeadersComplete,
@@ -328,7 +322,7 @@
   }
 
   if (rv < 0)
-    return rv;
+    return MapStreamError(rv);
 
   // Check if we already have the response headers. If so, return synchronously.
   if (response_headers_received_)
@@ -355,7 +349,7 @@
   request_info_ = nullptr;
 
   // If the stream is already closed, there is no body to read.
-  if (!stream_)
+  if (stream_->IsDoneReading())
     return GetResponseStatus();
 
   int rv = stream_->ReadBody(buf, buf_len,
@@ -369,7 +363,7 @@
   }
 
   if (rv < 0)
-    return rv;
+    return MapStreamError(rv);
 
   return HandleReadComplete(rv);
 }
@@ -378,15 +372,13 @@
   session_error_ = ERR_ABORTED;
   SaveResponseStatus();
   // Note: the not_reusable flag has no meaning for QUIC streams.
-  if (stream_) {
-    stream_->ClearDelegate();
+  if (stream_)
     stream_->Reset(QUIC_STREAM_CANCELLED);
-  }
   ResetStream();
 }
 
 bool QuicHttpStream::IsResponseBodyComplete() const {
-  return next_state_ == STATE_OPEN && !stream_;
+  return next_state_ == STATE_OPEN && stream_->IsDoneReading();
 }
 
 bool QuicHttpStream::IsConnectionReused() const {
@@ -445,8 +437,8 @@
   details->connection_info =
       ConnectionInfoFromQuicVersion(quic_session()->GetQuicVersion());
   quic_session()->PopulateNetErrorDetails(details);
-  if (quic_session()->IsCryptoHandshakeConfirmed())
-    details->quic_connection_error = quic_connection_error_;
+  if (quic_session()->IsCryptoHandshakeConfirmed() && stream_)
+    details->quic_connection_error = stream_->connection_error();
 }
 
 void QuicHttpStream::SetPriority(RequestPriority priority) {
@@ -466,9 +458,6 @@
 }
 
 void QuicHttpStream::ReadTrailingHeaders() {
-  if (!stream_)
-    return;
-
   int rv = stream_->ReadTrailingHeaders(
       &trailing_header_block_,
       base::Bind(&QuicHttpStream::OnReadTrailingHeadersComplete,
@@ -492,33 +481,6 @@
   }
 }
 
-void QuicHttpStream::OnClose() {
-  quic_connection_error_ = stream_->connection_error();
-  quic_stream_error_ = stream_->stream_error();
-  SaveResponseStatus();
-
-  ResetStream();
-  // If already in DoLoop(), |callback_| will be handled when DoLoop() exits.
-  if (in_loop_)
-    return;
-
-  if (!callback_.is_null()) {
-    DoCallback(GetResponseStatus());
-  }
-}
-
-void QuicHttpStream::OnError(int error) {
-  ResetStream();
-  session_error_ = error;
-  SaveResponseStatus();
-  if (in_loop_) {
-    // If already in DoLoop(), |callback_| will be handled when DoLoop() exits.
-    return;
-  }
-  if (!callback_.is_null())
-    DoCallback(GetResponseStatus());
-}
-
 void QuicHttpStream::OnIOComplete(int rv) {
   rv = DoLoop(rv);
 
@@ -534,7 +496,7 @@
 
   // The client callback can do anything, including destroying this class,
   // so any pending callback must be issued after everything else is done.
-  base::ResetAndReturn(&callback_).Run(rv);
+  base::ResetAndReturn(&callback_).Run(MapStreamError(rv));
 }
 
 int QuicHttpStream::DoLoop(int rv) {
@@ -611,7 +573,7 @@
     return GetResponseStatus();
   }
 
-  stream_ = quic_session()->ReleaseStream(this);
+  stream_ = quic_session()->ReleaseStream();
   if (request_info_->load_flags & LOAD_DISABLE_CONNECTION_MIGRATION) {
     stream_->DisableConnectionMigration();
   }
@@ -638,9 +600,6 @@
 }
 
 int QuicHttpStream::DoSendHeaders() {
-  if (!stream_)
-    return GetResponseStatus();
-
   // Log the actual request with the URL Request's net log.
   stream_net_log_.AddEvent(
       NetLogEventType::HTTP_TRANSACTION_QUIC_SEND_REQUEST_HEADERS,
@@ -661,10 +620,6 @@
   if (rv < 0)
     return rv;
 
-  // If the stream is already closed, don't read the request body.
-  if (!stream_)
-    return GetResponseStatus();
-
   next_state_ = request_body_stream_ ? STATE_READ_REQUEST_BODY : STATE_OPEN;
 
   return OK;
@@ -678,14 +633,9 @@
 }
 
 int QuicHttpStream::DoReadRequestBodyComplete(int rv) {
-  // If the stream is already closed, don't continue.
-  if (!stream_)
-    return GetResponseStatus();
-
   // |rv| is the result of read from the request body from the last call to
   // DoSendBody().
   if (rv < 0) {
-    stream_->ClearDelegate();
     stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
     ResetStream();
     return rv;
@@ -701,9 +651,6 @@
 }
 
 int QuicHttpStream::DoSendBody() {
-  if (!stream_)
-    return GetResponseStatus();
-
   CHECK(request_body_stream_);
   CHECK(request_body_buf_.get());
   const bool eof = request_body_stream_->IsEOF();
@@ -724,10 +671,6 @@
   if (rv < 0)
     return rv;
 
-  // If the stream is already closed, don't continue.
-  if (!stream_)
-    return GetResponseStatus();
-
   request_body_buf_->DidConsume(request_body_buf_->BytesRemaining());
 
   if (!request_body_stream_->IsEOF()) {
@@ -770,6 +713,12 @@
       FROM_HERE, base::Bind(&QuicHttpStream::ReadTrailingHeaders,
                             weak_factory_.GetWeakPtr()));
 
+  if (stream_->IsDoneReading()) {
+    session_error_ = OK;
+    SaveResponseStatus();
+    stream_->OnFinRead();
+  }
+
   return OK;
 }
 
@@ -783,7 +732,6 @@
 
 int QuicHttpStream::HandleReadComplete(int rv) {
   if (stream_->IsDoneReading()) {
-    stream_->ClearDelegate();
     stream_->OnFinRead();
     SetResponseStatus(OK);
     ResetStream();
@@ -804,13 +752,20 @@
 
   if (!stream_)
     return;
+
   DCHECK_LE(stream_->NumBytesConsumed(), stream_->stream_bytes_read());
   // Only count the uniquely received bytes.
   closed_stream_received_bytes_ = stream_->NumBytesConsumed();
   closed_stream_sent_bytes_ = stream_->stream_bytes_written();
   closed_is_first_stream_ = stream_->IsFirstStream();
-  stream_->ClearDelegate();
-  stream_ = nullptr;
+}
+
+int QuicHttpStream::MapStreamError(int rv) {
+  if (rv == ERR_QUIC_PROTOCOL_ERROR &&
+      !quic_session()->IsCryptoHandshakeConfirmed()) {
+    return ERR_QUIC_HANDSHAKE_FAILED;
+  }
+  return rv;
 }
 
 int QuicHttpStream::GetResponseStatus() {
@@ -847,13 +802,11 @@
     return ERR_CONNECTION_CLOSED;
 
   // Explicit stream error are always fatal.
-  if (quic_stream_error_ != QUIC_STREAM_NO_ERROR &&
-      quic_stream_error_ != QUIC_STREAM_CONNECTION_ERROR) {
+  if (stream_->stream_error() != QUIC_STREAM_NO_ERROR &&
+      stream_->stream_error() != QUIC_STREAM_CONNECTION_ERROR) {
     return ERR_QUIC_PROTOCOL_ERROR;
   }
 
-  DCHECK_NE(QUIC_HANDSHAKE_TIMEOUT, quic_connection_error_);
-
   return ERR_QUIC_PROTOCOL_ERROR;
 }
 
diff --git a/net/quic/chromium/quic_http_stream.h b/net/quic/chromium/quic_http_stream.h
index 562a076..f9f887aa 100644
--- a/net/quic/chromium/quic_http_stream.h
+++ b/net/quic/chromium/quic_http_stream.h
@@ -36,8 +36,7 @@
 // non-owning pointer to a QuicChromiumClientStream which it uses to
 // send and receive data.
 class NET_EXPORT_PRIVATE QuicHttpStream
-    : public QuicChromiumClientStream::Delegate,
-      public QuicClientPushPromiseIndex::Delegate,
+    : public QuicClientPushPromiseIndex::Delegate,
       public MultiplexedHttpStream {
  public:
   explicit QuicHttpStream(
@@ -68,10 +67,6 @@
   void PopulateNetErrorDetails(NetErrorDetails* details) override;
   void SetPriority(RequestPriority priority) override;
 
-  // QuicChromiumClientStream::Delegate implementation
-  void OnClose() override;
-  void OnError(int error) override;
-
   // QuicClientPushPromiseIndex::Delegate implementation
   bool CheckVary(const SpdyHeaderBlock& client_request,
                  const SpdyHeaderBlock& promise_request,
@@ -131,6 +126,10 @@
 
   void ResetStream();
 
+  // Returns ERR_QUIC_HANDSHAKE_FAILED, if |rv| is ERR_QUIC_PROTOCOL_ERROR and
+  // the handshake was never confirmed. Otherwise, returns |rv|.
+  int MapStreamError(int rv);
+
   // If |has_response_status_| is false, sets |response_status| to the result
   // of ComputeResponseStatus(). Returns |response_status_|.
   int GetResponseStatus();
@@ -216,8 +215,6 @@
   NetLogWithSource stream_net_log_;
 
   int session_error_;  // Error code from the connection shutdown.
-  QuicErrorCode quic_connection_error_;       // Cached connection error code.
-  QuicRstStreamErrorCode quic_stream_error_;  // Cached stream error code.
 
   bool found_promise_;
   // |QuicClientPromisedInfo| owns this. It will be set when |Try()|
diff --git a/net/quic/chromium/quic_http_stream_test.cc b/net/quic/chromium/quic_http_stream_test.cc
index 8a9ba22..d22ea64 100644
--- a/net/quic/chromium/quic_http_stream_test.cc
+++ b/net/quic/chromium/quic_http_stream_test.cc
@@ -1403,7 +1403,7 @@
   SetResponse("404 OK", "hello world!");
   // In the course of processing this packet, the QuicHttpStream close itself.
   size_t response_size = 0;
-  ProcessPacket(ConstructResponseHeadersPacket(2, kFin, &response_size));
+  ProcessPacket(ConstructResponseHeadersPacket(2, !kFin, &response_size));
 
   base::RunLoop().RunUntilIdle();
 
@@ -1469,38 +1469,6 @@
             stream_->GetTotalReceivedBytes());
 }
 
-// Regression test for http://crbug.com/294870
-TEST_P(QuicHttpStreamTest, CheckPriorityWithNoDelegate) {
-  SetRequest("GET", "/", MEDIUM);
-  QuicStreamOffset header_stream_offset = 0;
-  AddWrite(ConstructInitialSettingsPacket(&header_stream_offset));
-  AddWrite(ConstructClientRstStreamPacket(2));
-
-  Initialize();
-
-  request_.method = "GET";
-  request_.url = GURL("https://www.example.org/");
-
-  EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, net_log_.bound(),
-                                          callback_.callback()));
-
-  // Check that priority is highest.
-  QuicChromiumClientStream::Handle* reliable_stream =
-      QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get());
-  DCHECK(reliable_stream);
-  QuicChromiumClientStream::Delegate* delegate = reliable_stream->GetDelegate();
-  DCHECK(delegate);
-  DCHECK_EQ(kV3HighestPriority, reliable_stream->priority());
-
-  // Set Delegate to nullptr and make sure Priority returns highest
-  // priority.
-  reliable_stream->ClearDelegate();
-  DCHECK_EQ(kV3HighestPriority, reliable_stream->priority());
-
-  EXPECT_EQ(0, stream_->GetTotalSentBytes());
-  EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
-}
-
 TEST_P(QuicHttpStreamTest, SessionClosedDuringDoLoop) {
   SetRequest("POST", "/", DEFAULT_PRIORITY);
   size_t spdy_request_headers_frame_length;
diff --git a/net/quic/chromium/quic_network_transaction_unittest.cc b/net/quic/chromium/quic_network_transaction_unittest.cc
index 1762682..0d56c1d4 100644
--- a/net/quic/chromium/quic_network_transaction_unittest.cc
+++ b/net/quic/chromium/quic_network_transaction_unittest.cc
@@ -1206,8 +1206,6 @@
   mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
       1, GetNthClientInitiatedStreamId(0), false, true,
       GetResponseHeaders("421"), nullptr));
-  mock_quic_data.AddWrite(ConstructClientAckAndRstPacket(
-      3, GetNthClientInitiatedStreamId(0), QUIC_STREAM_CANCELLED, 1, 1, 1));
   mock_quic_data.AddRead(ASYNC, OK);
   mock_quic_data.AddSocketDataToFactory(&socket_factory_);
 
diff --git a/net/quic/core/congestion_control/send_algorithm_test.cc b/net/quic/core/congestion_control/send_algorithm_test.cc
index c2d6632..166cad36 100644
--- a/net/quic/core/congestion_control/send_algorithm_test.cc
+++ b/net/quic/core/congestion_control/send_algorithm_test.cc
@@ -166,40 +166,14 @@
   std::vector<TestParams> params;
   for (const CongestionControlType congestion_control_type :
        {kBBR, kCubic, kCubicBytes, kReno, kRenoBytes, kPCC}) {
+    params.push_back(
+        TestParams(congestion_control_type, false, false, false, false));
     if (congestion_control_type != kCubic &&
         congestion_control_type != kCubicBytes) {
-      params.push_back(
-          TestParams(congestion_control_type, false, false, false, false));
       continue;
     }
-    for (bool fix_convex_mode : {true, false}) {
-      for (bool fix_cubic_quantization : {true, false}) {
-        for (bool fix_beta_last_max : {true, false}) {
-          for (bool allow_per_ack_updates : {true, false}) {
-            if (!FLAGS_quic_reloadable_flag_quic_fix_cubic_convex_mode &&
-                fix_convex_mode) {
-              continue;
-            }
-            if (!FLAGS_quic_reloadable_flag_quic_fix_cubic_bytes_quantization &&
-                fix_cubic_quantization) {
-              continue;
-            }
-            if (!FLAGS_quic_reloadable_flag_quic_fix_beta_last_max &&
-                fix_beta_last_max) {
-              continue;
-            }
-            if (!FLAGS_quic_reloadable_flag_quic_enable_cubic_per_ack_updates &&
-                allow_per_ack_updates) {
-              continue;
-            }
-            TestParams param(congestion_control_type, fix_convex_mode,
-                             fix_cubic_quantization, fix_beta_last_max,
-                             allow_per_ack_updates);
-            params.push_back(param);
-          }
-        }
-      }
-    }
+    params.push_back(
+        TestParams(congestion_control_type, true, true, true, true));
   }
   return params;
 }
@@ -220,6 +194,10 @@
                   "QUIC sender",
                   Perspective::IS_SERVER,
                   net::test::GetPeerInMemoryConnectionId(42)) {
+    FLAGS_quic_reloadable_flag_quic_fix_cubic_convex_mode = true;
+    FLAGS_quic_reloadable_flag_quic_fix_cubic_bytes_quantization = true;
+    FLAGS_quic_reloadable_flag_quic_fix_beta_last_max = true;
+    FLAGS_quic_reloadable_flag_quic_enable_cubic_per_ack_updates = true;
     rtt_stats_ = quic_sender_.connection()->sent_packet_manager().GetRttStats();
     sender_ = SendAlgorithmInterface::Create(
         simulator_.GetClock(), rtt_stats_,
diff --git a/net/tools/cert_verify_tool/verify_using_path_builder.cc b/net/tools/cert_verify_tool/verify_using_path_builder.cc
index 2426f61..7a85816 100644
--- a/net/tools/cert_verify_tool/verify_using_path_builder.cc
+++ b/net/tools/cert_verify_tool/verify_using_path_builder.cc
@@ -210,7 +210,9 @@
   net::CertPathBuilder::Result result;
   net::CertPathBuilder path_builder(
       target_cert, ssl_trust_store->GetTrustStore(), &signature_policy, time,
-      net::KeyPurpose::SERVER_AUTH, &result);
+      net::KeyPurpose::SERVER_AUTH, net::InitialExplicitPolicy::kFalse,
+      {net::AnyPolicy()}, net::InitialPolicyMappingInhibit::kFalse,
+      net::InitialAnyPolicyInhibit::kFalse, &result);
   path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
 
   // Create a network thread to be used for AIA fetches, and wait for a
diff --git a/remoting/base/auto_thread_unittest.cc b/remoting/base/auto_thread_unittest.cc
index a825753..224b505 100644
--- a/remoting/base/auto_thread_unittest.cc
+++ b/remoting/base/auto_thread_unittest.cc
@@ -15,7 +15,6 @@
 
 #if defined(OS_WIN)
 #include <objbase.h>
-#include "base/win/windows_version.h"
 #endif
 
 namespace {
@@ -37,12 +36,6 @@
   typedef HRESULT (WINAPI * CoGetApartmentTypeFunc)
       (APTTYPE*, APTTYPEQUALIFIER*);
 
-  // CoGetApartmentType requires Windows 7 or above.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7) {
-    *hresult = E_NOTIMPL;
-    return;
-  }
-
   // Dynamic link to the API so the same test binary can run on older systems.
   base::ScopedNativeLibrary com_library(base::FilePath(L"ole32.dll"));
   ASSERT_TRUE(com_library.is_valid());
@@ -165,13 +158,8 @@
   task_runner = NULL;
   RunMessageLoop();
 
-  // CoGetApartmentType requires Windows 7 or above.
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
-    EXPECT_EQ(S_OK, hresult);
-    EXPECT_EQ(APTTYPE_MTA, apt_type);
-  } else {
-    EXPECT_EQ(E_NOTIMPL, hresult);
-  }
+  EXPECT_EQ(S_OK, hresult);
+  EXPECT_EQ(APTTYPE_MTA, apt_type);
 }
 
 TEST_F(AutoThreadTest, ThreadWithComSta) {
@@ -191,15 +179,10 @@
   task_runner = NULL;
   RunMessageLoop();
 
-  // CoGetApartmentType requires Windows 7 or above.
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
-    EXPECT_EQ(S_OK, hresult);
-    // Whether the thread is the "main" STA apartment depends upon previous
-    // COM activity in this test process, so allow both types here.
-    EXPECT_TRUE(apt_type == APTTYPE_MAINSTA || apt_type == APTTYPE_STA);
-  } else {
-    EXPECT_EQ(E_NOTIMPL, hresult);
-  }
+  EXPECT_EQ(S_OK, hresult);
+  // Whether the thread is the "main" STA apartment depends upon previous
+  // COM activity in this test process, so allow both types here.
+  EXPECT_TRUE(apt_type == APTTYPE_MAINSTA || apt_type == APTTYPE_STA);
 }
 #endif // defined(OS_WIN)
 
diff --git a/remoting/ios/app/client_connection_view_controller.mm b/remoting/ios/app/client_connection_view_controller.mm
index 108419a..395f3c60 100644
--- a/remoting/ios/app/client_connection_view_controller.mm
+++ b/remoting/ios/app/client_connection_view_controller.mm
@@ -51,11 +51,17 @@
 - (id)init {
   self = [super init];
   if (self) {
-    self.navigationItem.rightBarButtonItem =
-        [[UIBarButtonItem alloc] initWithTitle:@"CANCEL"
-                                         style:UIBarButtonItemStylePlain
-                                        target:self
-                                        action:@selector(didTapCancel:)];
+    // TODO(yuweih): This logic may be reused by other views.
+    UIButton* cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
+    [cancelButton setTitle:@"CANCEL" forState:UIControlStateNormal];
+    [cancelButton setImage:[[UIImage imageNamed:@"Back"]
+                               imageFlippedForRightToLeftLayoutDirection]
+                  forState:UIControlStateNormal];
+    [cancelButton addTarget:self
+                     action:@selector(didTapCancel:)
+           forControlEvents:UIControlEventTouchUpInside];
+    self.navigationItem.leftBarButtonItem =
+        [[UIBarButtonItem alloc] initWithCustomView:cancelButton];
 
     _navBar = [[MDCNavigationBar alloc] initWithFrame:CGRectZero];
     [_navBar observeNavigationItem:self.navigationItem];
@@ -66,6 +72,17 @@
     [mutator mutate:_navBar];
     [self.view addSubview:_navBar];
     _navBar.translatesAutoresizingMaskIntoConstraints = NO;
+
+    // Attach navBar to the top of the view.
+    [NSLayoutConstraint activateConstraints:@[
+      [[_navBar topAnchor] constraintEqualToAnchor:[self.view topAnchor]],
+      [[_navBar leadingAnchor]
+          constraintEqualToAnchor:[self.view leadingAnchor]],
+      [[_navBar trailingAnchor]
+          constraintEqualToAnchor:[self.view trailingAnchor]],
+      [[_navBar heightAnchor] constraintEqualToConstant:kBarHeight],
+    ]];
+
     _remoteHostName = @"";
   }
   return self;
@@ -118,9 +135,6 @@
 - (void)viewWillLayoutSubviews {
   [super viewWillLayoutSubviews];
 
-  _navBar.frame = CGRectMake(0.f, 0.f, self.view.frame.size.width, kBarHeight);
-  [_navBar setNeedsLayout];
-
   _iconView.frame = CGRectMake(0, 0, kIconRadius * 2, kIconRadius * 2.f);
   _iconView.center =
       CGPointMake(self.view.center.x, self.view.center.y + kCenterShift);
diff --git a/remoting/ios/session/remoting_client.mm b/remoting/ios/session/remoting_client.mm
index f753f22..3dfccc8 100644
--- a/remoting/ios/session/remoting_client.mm
+++ b/remoting/ios/session/remoting_client.mm
@@ -67,6 +67,10 @@
   return self;
 }
 
+- (void)dealloc {
+  [self disconnectFromHost];
+}
+
 - (void)connectToHost:(HostInfo*)hostInfo
              username:(NSString*)username
           accessToken:(NSString*)accessToken {
diff --git a/rlz/test/rlz_test_helpers.cc b/rlz/test/rlz_test_helpers.cc
index 2d4b6dd..c8d5000a 100644
--- a/rlz/test/rlz_test_helpers.cc
+++ b/rlz/test/rlz_test_helpers.cc
@@ -20,7 +20,6 @@
 #if defined(OS_WIN)
 #include <shlwapi.h>
 #include "base/win/registry.h"
-#include "base/win/windows_version.h"
 #elif defined(OS_POSIX)
 #include "base/files/file_path.h"
 #include "rlz/lib/rlz_value_store.h"
@@ -100,31 +99,26 @@
 void InitializeRegistryOverridesForTesting(
     registry_util::RegistryOverrideManager* override_manager) {
   // For the moment, the HKCU hive requires no initialization.
-  const bool do_copy = (base::win::GetVersion() >= base::win::VERSION_WIN7);
   RegistryKeyData data;
 
-  if (do_copy) {
-    // Copy the following HKLM subtrees to the temporary location so that the
-    // win32 APIs used by the tests continue to work:
-    //
-    //    HKLM\System\CurrentControlSet\Control\Lsa\AccessProviders
-    //
-    // This seems to be required since Win7.
-    ReadRegistryTree(base::win::RegKey(HKEY_LOCAL_MACHINE,
-                                       kHKLMAccessProviders,
-                                       KEY_READ), &data);
-  }
+  // Copy the following HKLM subtrees to the temporary location so that the
+  // win32 APIs used by the tests continue to work:
+  //
+  //    HKLM\System\CurrentControlSet\Control\Lsa\AccessProviders
+  //
+  // This seems to be required since Win7.
+  ReadRegistryTree(base::win::RegKey(HKEY_LOCAL_MACHINE,
+                                     kHKLMAccessProviders,
+                                     KEY_READ), &data);
 
   ASSERT_NO_FATAL_FAILURE(
       override_manager->OverrideRegistry(HKEY_LOCAL_MACHINE));
   ASSERT_NO_FATAL_FAILURE(
       override_manager->OverrideRegistry(HKEY_CURRENT_USER));
 
-  if (do_copy) {
-    base::win::RegKey key(
-        HKEY_LOCAL_MACHINE, kHKLMAccessProviders, KEY_ALL_ACCESS);
-    WriteRegistryTree(data, &key);
-  }
+  base::win::RegKey key(
+      HKEY_LOCAL_MACHINE, kHKLMAccessProviders, KEY_ALL_ACCESS);
+  WriteRegistryTree(data, &key);
 }
 
 }  // namespace
diff --git a/sandbox/win/src/process_mitigations_test.cc b/sandbox/win/src/process_mitigations_test.cc
index 53b0442..1e6b3420 100644
--- a/sandbox/win/src/process_mitigations_test.cc
+++ b/sandbox/win/src/process_mitigations_test.cc
@@ -948,7 +948,7 @@
 
 #if !defined(_WIN64)  // DEP is always enabled on 64-bit.
 TEST(ProcessMitigationsTest, CheckDep) {
-  if (base::win::GetVersion() > base::win::VERSION_WIN7)
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
     return;
 
   TestRunner runner;
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations
index f11e01a..f8043c5e 100644
--- a/third_party/WebKit/LayoutTests/W3CImportExpectations
+++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -159,6 +159,8 @@
 external/wpt/css/css-multicol-1 [ Skip ]
 external/wpt/css/css-namespaces-3 [ Skip ]
 external/wpt/css/css-page-3 [ Skip ]
+## Owners: smcgruer@chromium.org
+# external/wpt/css/css-position-3 [ Pass ]
 external/wpt/css/css-pseudo-4 [ Skip ]
 external/wpt/css/css-regions-1 [ Skip ]
 ## Owners: kojii@chromium.org
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-metadata-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-metadata-expected.txt
index cfc6678..163040a1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-metadata-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-metadata-expected.txt
@@ -31,196 +31,68 @@
 PASS link.href: 38 tests
 PASS link.crossOrigin: 52 tests
 PASS link.rel: 32 tests
+PASS link.as: 22 tests
+FAIL link.as: setAttribute() to "document" assert_equals: IDL get expected "document" but got ""
 PASS link.as: 3 tests
-FAIL link.as: setAttribute() to " \0\x01\x02\x03\x04\x05\x06\x07 \b\t\n\v\f\r\x0e\x0f \x10\x11\x12\x13\x14\x15\x16\x17 \x18\x19\x1a\x1b\x1c\x1d\x1e\x1f  foo " assert_equals: IDL get expected "" but got " \0\x01\x02\x03\x04\x05\x06\x07 \b\t\n\v\f\r\x0e\x0f \x10\x11\x12\x13\x14\x15\x16\x17 \x18\x19\x1a\x1b\x1c\x1d\x1e\x1f  foo "
-FAIL link.as: setAttribute() to undefined assert_equals: IDL get expected "" but got "undefined"
-FAIL link.as: setAttribute() to 7 assert_equals: IDL get expected "" but got "7"
-FAIL link.as: setAttribute() to 1.5 assert_equals: IDL get expected "" but got "1.5"
-FAIL link.as: setAttribute() to true assert_equals: IDL get expected "" but got "true"
-FAIL link.as: setAttribute() to false assert_equals: IDL get expected "" but got "false"
-FAIL link.as: setAttribute() to object "[object Object]" assert_equals: IDL get expected "" but got "[object Object]"
-FAIL link.as: setAttribute() to NaN assert_equals: IDL get expected "" but got "NaN"
-FAIL link.as: setAttribute() to Infinity assert_equals: IDL get expected "" but got "Infinity"
-FAIL link.as: setAttribute() to -Infinity assert_equals: IDL get expected "" but got "-Infinity"
-FAIL link.as: setAttribute() to "\0" assert_equals: IDL get expected "" but got "\0"
-FAIL link.as: setAttribute() to null assert_equals: IDL get expected "" but got "null"
-FAIL link.as: setAttribute() to object "test-toString" assert_equals: IDL get expected "" but got "test-toString"
-FAIL link.as: setAttribute() to object "test-valueOf" assert_equals: IDL get expected "" but got "test-valueOf"
-PASS link.as: setAttribute() to "audio" 
-FAIL link.as: setAttribute() to "xaudio" assert_equals: IDL get expected "" but got "xaudio"
-FAIL link.as: setAttribute() to "audio\0" assert_equals: IDL get expected "" but got "audio\0"
-FAIL link.as: setAttribute() to "udio" assert_equals: IDL get expected "" but got "udio"
-FAIL link.as: setAttribute() to "AUDIO" assert_equals: IDL get expected "audio" but got "AUDIO"
-PASS link.as: setAttribute() to "document" 
-FAIL link.as: setAttribute() to "xdocument" assert_equals: IDL get expected "" but got "xdocument"
-FAIL link.as: setAttribute() to "document\0" assert_equals: IDL get expected "" but got "document\0"
-FAIL link.as: setAttribute() to "ocument" assert_equals: IDL get expected "" but got "ocument"
-FAIL link.as: setAttribute() to "DOCUMENT" assert_equals: IDL get expected "document" but got "DOCUMENT"
-PASS link.as: setAttribute() to "embed" 
-FAIL link.as: setAttribute() to "xembed" assert_equals: IDL get expected "" but got "xembed"
-FAIL link.as: setAttribute() to "embed\0" assert_equals: IDL get expected "" but got "embed\0"
-FAIL link.as: setAttribute() to "mbed" assert_equals: IDL get expected "" but got "mbed"
-FAIL link.as: setAttribute() to "EMBED" assert_equals: IDL get expected "embed" but got "EMBED"
-PASS link.as: setAttribute() to "font" 
-FAIL link.as: setAttribute() to "xfont" assert_equals: IDL get expected "" but got "xfont"
-FAIL link.as: setAttribute() to "font\0" assert_equals: IDL get expected "" but got "font\0"
-FAIL link.as: setAttribute() to "ont" assert_equals: IDL get expected "" but got "ont"
-FAIL link.as: setAttribute() to "FONT" assert_equals: IDL get expected "font" but got "FONT"
-PASS link.as: setAttribute() to "image" 
-FAIL link.as: setAttribute() to "ximage" assert_equals: IDL get expected "" but got "ximage"
-FAIL link.as: setAttribute() to "image\0" assert_equals: IDL get expected "" but got "image\0"
-FAIL link.as: setAttribute() to "mage" assert_equals: IDL get expected "" but got "mage"
-FAIL link.as: setAttribute() to "IMAGE" assert_equals: IDL get expected "image" but got "IMAGE"
-PASS link.as: setAttribute() to "manifest" 
-FAIL link.as: setAttribute() to "xmanifest" assert_equals: IDL get expected "" but got "xmanifest"
-FAIL link.as: setAttribute() to "manifest\0" assert_equals: IDL get expected "" but got "manifest\0"
-FAIL link.as: setAttribute() to "anifest" assert_equals: IDL get expected "" but got "anifest"
-FAIL link.as: setAttribute() to "MANIFEST" assert_equals: IDL get expected "manifest" but got "MANIFEST"
-PASS link.as: setAttribute() to "object" 
-FAIL link.as: setAttribute() to "xobject" assert_equals: IDL get expected "" but got "xobject"
-FAIL link.as: setAttribute() to "object\0" assert_equals: IDL get expected "" but got "object\0"
-FAIL link.as: setAttribute() to "bject" assert_equals: IDL get expected "" but got "bject"
-FAIL link.as: setAttribute() to "OBJECT" assert_equals: IDL get expected "object" but got "OBJECT"
-PASS link.as: setAttribute() to "report" 
-FAIL link.as: setAttribute() to "xreport" assert_equals: IDL get expected "" but got "xreport"
-FAIL link.as: setAttribute() to "report\0" assert_equals: IDL get expected "" but got "report\0"
-FAIL link.as: setAttribute() to "eport" assert_equals: IDL get expected "" but got "eport"
-FAIL link.as: setAttribute() to "REPORT" assert_equals: IDL get expected "report" but got "REPORT"
-PASS link.as: setAttribute() to "script" 
-FAIL link.as: setAttribute() to "xscript" assert_equals: IDL get expected "" but got "xscript"
-FAIL link.as: setAttribute() to "script\0" assert_equals: IDL get expected "" but got "script\0"
-FAIL link.as: setAttribute() to "cript" assert_equals: IDL get expected "" but got "cript"
-FAIL link.as: setAttribute() to "SCRIPT" assert_equals: IDL get expected "script" but got "SCRIPT"
-PASS link.as: setAttribute() to "serviceworker" 
-FAIL link.as: setAttribute() to "xserviceworker" assert_equals: IDL get expected "" but got "xserviceworker"
-FAIL link.as: setAttribute() to "serviceworker\0" assert_equals: IDL get expected "" but got "serviceworker\0"
-FAIL link.as: setAttribute() to "erviceworker" assert_equals: IDL get expected "" but got "erviceworker"
-FAIL link.as: setAttribute() to "SERVICEWORKER" assert_equals: IDL get expected "serviceworker" but got "SERVICEWORKER"
-PASS link.as: setAttribute() to "sharedworker" 
-FAIL link.as: setAttribute() to "xsharedworker" assert_equals: IDL get expected "" but got "xsharedworker"
-FAIL link.as: setAttribute() to "sharedworker\0" assert_equals: IDL get expected "" but got "sharedworker\0"
-FAIL link.as: setAttribute() to "haredworker" assert_equals: IDL get expected "" but got "haredworker"
-FAIL link.as: setAttribute() to "SHAREDWORKER" assert_equals: IDL get expected "sharedworker" but got "SHAREDWORKER"
-PASS link.as: setAttribute() to "style" 
-FAIL link.as: setAttribute() to "xstyle" assert_equals: IDL get expected "" but got "xstyle"
-FAIL link.as: setAttribute() to "style\0" assert_equals: IDL get expected "" but got "style\0"
-FAIL link.as: setAttribute() to "tyle" assert_equals: IDL get expected "" but got "tyle"
-FAIL link.as: setAttribute() to "STYLE" assert_equals: IDL get expected "style" but got "STYLE"
-PASS link.as: setAttribute() to "track" 
-FAIL link.as: setAttribute() to "xtrack" assert_equals: IDL get expected "" but got "xtrack"
-FAIL link.as: setAttribute() to "track\0" assert_equals: IDL get expected "" but got "track\0"
-FAIL link.as: setAttribute() to "rack" assert_equals: IDL get expected "" but got "rack"
-FAIL link.as: setAttribute() to "TRACK" assert_equals: IDL get expected "track" but got "TRACK"
-PASS link.as: setAttribute() to "video" 
-FAIL link.as: setAttribute() to "xvideo" assert_equals: IDL get expected "" but got "xvideo"
-FAIL link.as: setAttribute() to "video\0" assert_equals: IDL get expected "" but got "video\0"
-FAIL link.as: setAttribute() to "ideo" assert_equals: IDL get expected "" but got "ideo"
-FAIL link.as: setAttribute() to "VIDEO" assert_equals: IDL get expected "video" but got "VIDEO"
-PASS link.as: setAttribute() to "worker" 
-FAIL link.as: setAttribute() to "xworker" assert_equals: IDL get expected "" but got "xworker"
-FAIL link.as: setAttribute() to "worker\0" assert_equals: IDL get expected "" but got "worker\0"
-FAIL link.as: setAttribute() to "orker" assert_equals: IDL get expected "" but got "orker"
-FAIL link.as: setAttribute() to "WORKER" assert_equals: IDL get expected "worker" but got "WORKER"
-PASS link.as: setAttribute() to "xslt" 
-FAIL link.as: setAttribute() to "xxslt" assert_equals: IDL get expected "" but got "xxslt"
-FAIL link.as: setAttribute() to "xslt\0" assert_equals: IDL get expected "" but got "xslt\0"
-FAIL link.as: setAttribute() to "slt" assert_equals: IDL get expected "" but got "slt"
-FAIL link.as: setAttribute() to "XSLT" assert_equals: IDL get expected "xslt" but got "XSLT"
-PASS link.as: IDL set to "" 
-FAIL link.as: IDL set to " \0\x01\x02\x03\x04\x05\x06\x07 \b\t\n\v\f\r\x0e\x0f \x10\x11\x12\x13\x14\x15\x16\x17 \x18\x19\x1a\x1b\x1c\x1d\x1e\x1f  foo " assert_equals: IDL get expected "" but got " \0\x01\x02\x03\x04\x05\x06\x07 \b\t\n\v\f\r\x0e\x0f \x10\x11\x12\x13\x14\x15\x16\x17 \x18\x19\x1a\x1b\x1c\x1d\x1e\x1f  foo "
-FAIL link.as: IDL set to undefined assert_equals: IDL get expected "" but got "undefined"
-FAIL link.as: IDL set to 7 assert_equals: IDL get expected "" but got "7"
-FAIL link.as: IDL set to 1.5 assert_equals: IDL get expected "" but got "1.5"
-FAIL link.as: IDL set to true assert_equals: IDL get expected "" but got "true"
-FAIL link.as: IDL set to false assert_equals: IDL get expected "" but got "false"
-FAIL link.as: IDL set to object "[object Object]" assert_equals: IDL get expected "" but got "[object Object]"
-FAIL link.as: IDL set to NaN assert_equals: IDL get expected "" but got "NaN"
-FAIL link.as: IDL set to Infinity assert_equals: IDL get expected "" but got "Infinity"
-FAIL link.as: IDL set to -Infinity assert_equals: IDL get expected "" but got "-Infinity"
-FAIL link.as: IDL set to "\0" assert_equals: IDL get expected "" but got "\0"
-FAIL link.as: IDL set to null assert_equals: IDL get expected "" but got "null"
-FAIL link.as: IDL set to object "test-toString" assert_equals: IDL get expected "" but got "test-toString"
-FAIL link.as: IDL set to object "test-valueOf" assert_equals: IDL get expected "" but got "test-valueOf"
-PASS link.as: IDL set to "audio" 
-FAIL link.as: IDL set to "xaudio" assert_equals: IDL get expected "" but got "xaudio"
-FAIL link.as: IDL set to "audio\0" assert_equals: IDL get expected "" but got "audio\0"
-FAIL link.as: IDL set to "udio" assert_equals: IDL get expected "" but got "udio"
-FAIL link.as: IDL set to "AUDIO" assert_equals: IDL get expected "audio" but got "AUDIO"
-PASS link.as: IDL set to "document" 
-FAIL link.as: IDL set to "xdocument" assert_equals: IDL get expected "" but got "xdocument"
-FAIL link.as: IDL set to "document\0" assert_equals: IDL get expected "" but got "document\0"
-FAIL link.as: IDL set to "ocument" assert_equals: IDL get expected "" but got "ocument"
-FAIL link.as: IDL set to "DOCUMENT" assert_equals: IDL get expected "document" but got "DOCUMENT"
-PASS link.as: IDL set to "embed" 
-FAIL link.as: IDL set to "xembed" assert_equals: IDL get expected "" but got "xembed"
-FAIL link.as: IDL set to "embed\0" assert_equals: IDL get expected "" but got "embed\0"
-FAIL link.as: IDL set to "mbed" assert_equals: IDL get expected "" but got "mbed"
-FAIL link.as: IDL set to "EMBED" assert_equals: IDL get expected "embed" but got "EMBED"
-PASS link.as: IDL set to "font" 
-FAIL link.as: IDL set to "xfont" assert_equals: IDL get expected "" but got "xfont"
-FAIL link.as: IDL set to "font\0" assert_equals: IDL get expected "" but got "font\0"
-FAIL link.as: IDL set to "ont" assert_equals: IDL get expected "" but got "ont"
-FAIL link.as: IDL set to "FONT" assert_equals: IDL get expected "font" but got "FONT"
-PASS link.as: IDL set to "image" 
-FAIL link.as: IDL set to "ximage" assert_equals: IDL get expected "" but got "ximage"
-FAIL link.as: IDL set to "image\0" assert_equals: IDL get expected "" but got "image\0"
-FAIL link.as: IDL set to "mage" assert_equals: IDL get expected "" but got "mage"
-FAIL link.as: IDL set to "IMAGE" assert_equals: IDL get expected "image" but got "IMAGE"
-PASS link.as: IDL set to "manifest" 
-FAIL link.as: IDL set to "xmanifest" assert_equals: IDL get expected "" but got "xmanifest"
-FAIL link.as: IDL set to "manifest\0" assert_equals: IDL get expected "" but got "manifest\0"
-FAIL link.as: IDL set to "anifest" assert_equals: IDL get expected "" but got "anifest"
-FAIL link.as: IDL set to "MANIFEST" assert_equals: IDL get expected "manifest" but got "MANIFEST"
-PASS link.as: IDL set to "object" 
-FAIL link.as: IDL set to "xobject" assert_equals: IDL get expected "" but got "xobject"
-FAIL link.as: IDL set to "object\0" assert_equals: IDL get expected "" but got "object\0"
-FAIL link.as: IDL set to "bject" assert_equals: IDL get expected "" but got "bject"
-FAIL link.as: IDL set to "OBJECT" assert_equals: IDL get expected "object" but got "OBJECT"
-PASS link.as: IDL set to "report" 
-FAIL link.as: IDL set to "xreport" assert_equals: IDL get expected "" but got "xreport"
-FAIL link.as: IDL set to "report\0" assert_equals: IDL get expected "" but got "report\0"
-FAIL link.as: IDL set to "eport" assert_equals: IDL get expected "" but got "eport"
-FAIL link.as: IDL set to "REPORT" assert_equals: IDL get expected "report" but got "REPORT"
-PASS link.as: IDL set to "script" 
-FAIL link.as: IDL set to "xscript" assert_equals: IDL get expected "" but got "xscript"
-FAIL link.as: IDL set to "script\0" assert_equals: IDL get expected "" but got "script\0"
-FAIL link.as: IDL set to "cript" assert_equals: IDL get expected "" but got "cript"
-FAIL link.as: IDL set to "SCRIPT" assert_equals: IDL get expected "script" but got "SCRIPT"
-PASS link.as: IDL set to "serviceworker" 
-FAIL link.as: IDL set to "xserviceworker" assert_equals: IDL get expected "" but got "xserviceworker"
-FAIL link.as: IDL set to "serviceworker\0" assert_equals: IDL get expected "" but got "serviceworker\0"
-FAIL link.as: IDL set to "erviceworker" assert_equals: IDL get expected "" but got "erviceworker"
-FAIL link.as: IDL set to "SERVICEWORKER" assert_equals: IDL get expected "serviceworker" but got "SERVICEWORKER"
-PASS link.as: IDL set to "sharedworker" 
-FAIL link.as: IDL set to "xsharedworker" assert_equals: IDL get expected "" but got "xsharedworker"
-FAIL link.as: IDL set to "sharedworker\0" assert_equals: IDL get expected "" but got "sharedworker\0"
-FAIL link.as: IDL set to "haredworker" assert_equals: IDL get expected "" but got "haredworker"
-FAIL link.as: IDL set to "SHAREDWORKER" assert_equals: IDL get expected "sharedworker" but got "SHAREDWORKER"
-PASS link.as: IDL set to "style" 
-FAIL link.as: IDL set to "xstyle" assert_equals: IDL get expected "" but got "xstyle"
-FAIL link.as: IDL set to "style\0" assert_equals: IDL get expected "" but got "style\0"
-FAIL link.as: IDL set to "tyle" assert_equals: IDL get expected "" but got "tyle"
-FAIL link.as: IDL set to "STYLE" assert_equals: IDL get expected "style" but got "STYLE"
-PASS link.as: IDL set to "track" 
-FAIL link.as: IDL set to "xtrack" assert_equals: IDL get expected "" but got "xtrack"
-FAIL link.as: IDL set to "track\0" assert_equals: IDL get expected "" but got "track\0"
-FAIL link.as: IDL set to "rack" assert_equals: IDL get expected "" but got "rack"
-FAIL link.as: IDL set to "TRACK" assert_equals: IDL get expected "track" but got "TRACK"
-PASS link.as: IDL set to "video" 
-FAIL link.as: IDL set to "xvideo" assert_equals: IDL get expected "" but got "xvideo"
-FAIL link.as: IDL set to "video\0" assert_equals: IDL get expected "" but got "video\0"
-FAIL link.as: IDL set to "ideo" assert_equals: IDL get expected "" but got "ideo"
-FAIL link.as: IDL set to "VIDEO" assert_equals: IDL get expected "video" but got "VIDEO"
-PASS link.as: IDL set to "worker" 
-FAIL link.as: IDL set to "xworker" assert_equals: IDL get expected "" but got "xworker"
-FAIL link.as: IDL set to "worker\0" assert_equals: IDL get expected "" but got "worker\0"
-FAIL link.as: IDL set to "orker" assert_equals: IDL get expected "" but got "orker"
-FAIL link.as: IDL set to "WORKER" assert_equals: IDL get expected "worker" but got "WORKER"
-PASS link.as: IDL set to "xslt" 
-FAIL link.as: IDL set to "xxslt" assert_equals: IDL get expected "" but got "xxslt"
-FAIL link.as: IDL set to "xslt\0" assert_equals: IDL get expected "" but got "xslt\0"
-FAIL link.as: IDL set to "slt" assert_equals: IDL get expected "" but got "slt"
-FAIL link.as: IDL set to "XSLT" assert_equals: IDL get expected "xslt" but got "XSLT"
+FAIL link.as: setAttribute() to "DOCUMENT" assert_equals: IDL get expected "document" but got ""
+FAIL link.as: setAttribute() to "embed" assert_equals: IDL get expected "embed" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "EMBED" assert_equals: IDL get expected "embed" but got ""
+PASS link.as: 10 tests
+FAIL link.as: setAttribute() to "manifest" assert_equals: IDL get expected "manifest" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "MANIFEST" assert_equals: IDL get expected "manifest" but got ""
+FAIL link.as: setAttribute() to "object" assert_equals: IDL get expected "object" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "OBJECT" assert_equals: IDL get expected "object" but got ""
+FAIL link.as: setAttribute() to "report" assert_equals: IDL get expected "report" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "REPORT" assert_equals: IDL get expected "report" but got ""
+PASS link.as: 5 tests
+FAIL link.as: setAttribute() to "serviceworker" assert_equals: IDL get expected "serviceworker" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "SERVICEWORKER" assert_equals: IDL get expected "serviceworker" but got ""
+FAIL link.as: setAttribute() to "sharedworker" assert_equals: IDL get expected "sharedworker" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "SHAREDWORKER" assert_equals: IDL get expected "sharedworker" but got ""
+PASS link.as: 15 tests
+FAIL link.as: setAttribute() to "worker" assert_equals: IDL get expected "worker" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "WORKER" assert_equals: IDL get expected "worker" but got ""
+FAIL link.as: setAttribute() to "xslt" assert_equals: IDL get expected "xslt" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "XSLT" assert_equals: IDL get expected "xslt" but got ""
+PASS link.as: 20 tests
+FAIL link.as: IDL set to "document" assert_equals: IDL get expected "document" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "DOCUMENT" assert_equals: IDL get expected "document" but got ""
+FAIL link.as: IDL set to "embed" assert_equals: IDL get expected "embed" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "EMBED" assert_equals: IDL get expected "embed" but got ""
+PASS link.as: 10 tests
+FAIL link.as: IDL set to "manifest" assert_equals: IDL get expected "manifest" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "MANIFEST" assert_equals: IDL get expected "manifest" but got ""
+FAIL link.as: IDL set to "object" assert_equals: IDL get expected "object" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "OBJECT" assert_equals: IDL get expected "object" but got ""
+FAIL link.as: IDL set to "report" assert_equals: IDL get expected "report" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "REPORT" assert_equals: IDL get expected "report" but got ""
+PASS link.as: 5 tests
+FAIL link.as: IDL set to "serviceworker" assert_equals: IDL get expected "serviceworker" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "SERVICEWORKER" assert_equals: IDL get expected "serviceworker" but got ""
+FAIL link.as: IDL set to "sharedworker" assert_equals: IDL get expected "sharedworker" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "SHAREDWORKER" assert_equals: IDL get expected "sharedworker" but got ""
+PASS link.as: 15 tests
+FAIL link.as: IDL set to "worker" assert_equals: IDL get expected "worker" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "WORKER" assert_equals: IDL get expected "worker" but got ""
+FAIL link.as: IDL set to "xslt" assert_equals: IDL get expected "xslt" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "XSLT" assert_equals: IDL get expected "xslt" but got ""
 PASS link.media: 32 tests
 PASS link.nonce: 17 tests
 FAIL link.nonce: IDL set to "" assert_equals: getAttribute() expected "" but got "test-valueOf"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/idlharness.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/idlharness.https-expected.txt
new file mode 100644
index 0000000..cea6321
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/idlharness.https-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL Navigator interface: operation requestKeyboardLock(sequence) assert_throws: calling operation with this = null didn't throw TypeError function "function () {
+            fn.apply(obj, args);
+        }" did not throw
+PASS Navigator interface: operation cancelKeyboardLock() 
+PASS Navigator must be primary interface of navigator 
+PASS Stringification of navigator 
+PASS Navigator interface: navigator must inherit property "requestKeyboardLock" with the proper type (0) 
+PASS Navigator interface: calling requestKeyboardLock(sequence) on navigator with too few arguments must throw TypeError 
+PASS Navigator interface: navigator must inherit property "cancelKeyboardLock" with the proper type (1) 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/idlharness.https.html
new file mode 100644
index 0000000..6fabb411
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/idlharness.https.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<html>
+<head>
+<title>Keyboard Lock IDL tests</title>
+<link rel="help" href="https://github.com/w3c/keyboard-lock"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+</head>
+<body>
+<pre id="untested_idl" style="display: none">
+interface Navigator {
+};
+</pre>
+<!--
+  The reason of the failure of requestKeyboardLock test looks like a code defect in
+  idlharness.js. media-capabilities/idlharness.html is also impacted by this
+  issue. See https://codereview.chromium.org/2805763004/#ps620001, which
+  includes a potential fix.
+  TODO(zijiehe): Submit the fix.
+-->
+<pre id="idl" style="display: none">
+partial interface Navigator {
+  [SecureContext] Promise<void> requestKeyboardLock(optional sequence<DOMString> keyCodes = []);
+  [SecureContext] void cancelKeyboardLock();
+};
+</pre>
+<script>
+var idl_array = new IdlArray();
+idl_array.add_untested_idls(
+    document.getElementById("untested_idl").textContent);
+idl_array.add_idls(document.getElementById("idl").textContent);
+idl_array.add_objects({
+  Navigator: ["navigator"]
+});
+idl_array.test();
+</script>
+<div id="log"></div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-cancelKeyboardLock.https.html b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-cancelKeyboardLock.https.html
new file mode 100644
index 0000000..10fd50d3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-cancelKeyboardLock.https.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+test(() => {
+  assert_equals(navigator.cancelKeyboardLock(),
+                undefined);
+}, 'Keyboard Lock cancelKeyboardLock');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https-expected.txt
new file mode 100644
index 0000000..d74fd153
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Keyboard Lock requestKeyboardLock twice in parallel Test bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html
new file mode 100644
index 0000000..8e84d14
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock-two-parallel-requests.https.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+promise_test((t) => {
+  const p1 = navigator.requestKeyboardLock(['a', 'b']);
+  const p2 = navigator.requestKeyboardLock(['c', 'd']);
+  return promise_rejects(t, null, p2,
+      'requestKeyboardLock() should only be ' +
+      'executed if another request has finished.');
+}, 'Keyboard Lock requestKeyboardLock twice in parallel');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html
new file mode 100644
index 0000000..30f4905
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock-two-sequential-requests.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+promise_test(() => {
+  return navigator.requestKeyboardLock(['a', 'b'])
+      .then(() => {
+        return navigator.requestKeyboardLock(['c', 'd']);
+      });
+}, 'Keyboard Lock requestKeyboardLock twice sequentially');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock.https.html b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock.https.html
new file mode 100644
index 0000000..e6e0121
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/keyboard-lock/navigator-requestKeyboardLock.https.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+promise_test(() => {
+  const p = navigator.requestKeyboardLock(['a', 'b']);
+  assert_true(p instanceof Promise);
+  return p;
+}, 'Keyboard Lock requestKeyboardLock');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/download-resources.html b/third_party/WebKit/LayoutTests/external/wpt/preload/download-resources.html
index d4165e1c..7b51e78 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/download-resources.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/download-resources.html
@@ -13,7 +13,8 @@
 <link rel=preload href="/media/sound_5.oga" as=audio>
 <link rel=preload href="/media/foo.vtt" as=track>
 <link rel=preload href="resources/dummy.xml?foo=bar" as=foobarxmlthing>
-<link rel=preload href="resources/dummy.xml">
+<link rel=preload href="resources/dummy.xml?novalue">
+<link rel=preload href="resources/dummy.xml" as="fetch">
 <body>
 <script src="resources/dummy.js?pipe=trickle(d5)"></script>
 <script>
@@ -26,6 +27,7 @@
         verifyNumberOfDownloads("/media/sound_5.oga", 1);
         verifyNumberOfDownloads("/media/foo.vtt", 1);
         verifyNumberOfDownloads("resources/dummy.xml?foo=bar", 0);
+        verifyNumberOfDownloads("resources/dummy.xml?novalue", 0);
         verifyNumberOfDownloads("resources/dummy.xml", 1);
         t.done();
     }));
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/onerror-event.html b/third_party/WebKit/LayoutTests/external/wpt/preload/onerror-event.html
index f503d41..e396628 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/onerror-event.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/onerror-event.html
@@ -15,7 +15,8 @@
     var audioFailed = false;
     var trackFailed = false;
     var gibberishFailed = false;
-    var noTypeFailed = false;
+    var fetchFailed = false;
+    var emptyFailed = false;
 </script>
 <link rel=preload href="non-existent/dummy.js" as=script onerror="scriptFailed = true;">
 <link rel=preload href="non-existent/dummy.css" as=style onerror="styleFailed = true;">
@@ -24,8 +25,9 @@
 <link rel=preload href="non-existent/test.mp4" as=video onerror="videoFailed = true;">
 <link rel=preload href="non-existent/test.oga" as=audio onerror="audioFailed = true;">
 <link rel=preload href="non-existent/security/captions.vtt" as=track onerror="trackFailed = true;">
-<link rel=preload href="non-existent/dummy.xml" as=foobarxmlthing onerror="gibberishFailed = true;">
-<link rel=preload href="non-existent/dummy.xml" onerror="noTypeFailed = true;">
+<link rel=preload href="non-existent/dummy.xml?foo" as=foobarxmlthing onerror="gibberishFailed = true;">
+<link rel=preload href="non-existent/dummy.xml?fetch" as=fetch onerror="fetchFailed = true;">
+<link rel=preload href="non-existent/dummy.xml?empty" onerror="emptyFailed = true;">
 <script src="resources/dummy.js?pipe=trickle(d5)"></script>
 <script>
     window.onload = t.step_func(function() {
@@ -37,8 +39,9 @@
         assert_true(videoFailed, "video triggered error event");
         assert_true(audioFailed, "audio triggered error event");
         assert_true(trackFailed, "track triggered error event");
-        assert_true(gibberishFailed, "gibberish as value triggered error event");
-        assert_true(noTypeFailed, "empty as triggered error event");
+        assert_false(gibberishFailed, "gibberish as value did not trigger error event");
+        assert_true(fetchFailed, "fetch as triggered error event");
+        assert_false(emptyFailed, "empty as triggered error event");
         t.done();
     });
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event.html b/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event.html
index 684f84f9..86a9852 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event.html
@@ -14,6 +14,7 @@
     var gibberishLoaded = false;
     var gibberishErrored = false;
     var noTypeLoaded = false;
+    var fetchLoaded = false;
 </script>
 <link rel=preload href="resources/dummy.js" as=script onload="scriptLoaded = true;">
 <link rel=preload href="resources/dummy.css" as=style onload="styleLoaded = true;">
@@ -23,6 +24,7 @@
 <link rel=preload href="/media/sound_5.oga" as=audio onload="audioLoaded = true;">
 <link rel=preload href="/media/foo.vtt" as=track onload="trackLoaded = true;">
 <link rel=preload href="resources/dummy.xml?foo=bar" as=foobarxmlthing onload="gibberishLoaded = true;" onerror="gibberishErrored = true;">
+<link rel=preload href="resources/dummy.xml?fetch" as=fetch onload="fetchLoaded = true;">
 <link rel=preload href="resources/dummy.xml" onload="noTypeLoaded = true;">
 <body>
 <script src="resources/dummy.js?pipe=trickle(d5)"></script>
@@ -37,8 +39,9 @@
         assert_true(audioLoaded, "audio triggered load event");
         assert_true(trackLoaded, "track triggered load event");
         assert_false(gibberishLoaded, "gibberish as value triggered load event");
-        assert_true(gibberishErrored, "gibberish as value triggered error event");
-        assert_true(noTypeLoaded, "empty as triggered load event");
+        assert_false(gibberishErrored, "gibberish as value triggered error event");
+        assert_true(fetchLoaded, "fetch as value triggered load event");
+        assert_false(noTypeLoaded, "empty as triggered load event");
         t.done();
     });
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/reflected-as-value.html b/third_party/WebKit/LayoutTests/external/wpt/preload/reflected-as-value.html
new file mode 100644
index 0000000..4ab8159
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/reflected-as-value.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  var link = document.createElement("link");
+  var values = {
+    "Image": "image",
+    "images": "",
+    "scripT": "script",
+    "style": "style",
+    "": "",
+    "foNt": "font",
+    "foobar": "",
+    "video": "video",
+    "audio": "audio",
+    "track": "track",
+  };
+  var keys = Object.keys(values);
+  for (var i = 0; i < keys.length; ++i) {
+    link.as = keys[i];
+    assert_true(link.as == values[keys[i]]);
+  }
+}, "Make sure that the `as` value reflects only known values");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/opaque-response-preloaded-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/opaque-response-preloaded-iframe.html
index 9c0eed1d..d4d3024e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/opaque-response-preloaded-iframe.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/opaque-response-preloaded-iframe.html
@@ -8,6 +8,7 @@
   // response.
   l.setAttribute('rel', 'preload');
   l.setAttribute('href', 'opaque-response');
+  l.setAttribute('as', 'fetch');
   l.onload = function() {
     xhr = new XMLHttpRequest;
     xhr.withCredentials = true;
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/link-preload-validity.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/link-preload-validity.html
index 5dadab37..904b168 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/link-preload-validity.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/link-preload-validity.html
@@ -7,7 +7,7 @@
     if (window.internals)
         internals.settings.setLogPreload(true);
 </script>
-<link rel="preload" href="http://prefetch.wut.com.test/1.gif">
+<link rel="preload" as="fetch" href="http://prefetch.wut.com.test/1.gif">
 <link rel="preload" as="image" href="gopher:???://prefetch.wut.com.test/2.gif">
 <link rel="preload" as="image" href="">
 <link rel="preload" as="image">
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/link_header_preload_on_commit.php b/third_party/WebKit/LayoutTests/http/tests/preload/link_header_preload_on_commit.php
index b9895d3..9f12dfe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/preload/link_header_preload_on_commit.php
+++ b/third_party/WebKit/LayoutTests/http/tests/preload/link_header_preload_on_commit.php
@@ -1,5 +1,5 @@
 <?php
-    header("Link: </resources/dummy.css>;rel=preload", false);
+    header("Link: </resources/dummy.css>;rel=preload;as=style", false);
     header("Link: </resources/square.png>;rel=preload;as=image;media=(min-width: 1px)", false);
 ?>
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/memcache_eviction.html b/third_party/WebKit/LayoutTests/http/tests/preload/memcache_eviction.html
index ace8c78..2306483 100644
--- a/third_party/WebKit/LayoutTests/http/tests/preload/memcache_eviction.html
+++ b/third_party/WebKit/LayoutTests/http/tests/preload/memcache_eviction.html
@@ -19,6 +19,7 @@
     var l = document.createElement('link');
     l.setAttribute('rel', 'preload');
     l.setAttribute('href', "resources/timestamp.php");
+    l.setAttribute('as', 'fetch');
     l.onload = loadTimestampWithXHR;
     document.body.appendChild(l);
 });
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/memcache_reuse_of_non_cacheable_preload.html b/third_party/WebKit/LayoutTests/http/tests/preload/memcache_reuse_of_non_cacheable_preload.html
index a075d8f..fa59865 100644
--- a/third_party/WebKit/LayoutTests/http/tests/preload/memcache_reuse_of_non_cacheable_preload.html
+++ b/third_party/WebKit/LayoutTests/http/tests/preload/memcache_reuse_of_non_cacheable_preload.html
@@ -31,6 +31,7 @@
     var l = document.createElement('link');
     l.setAttribute('rel', 'preload');
     l.setAttribute('href', "resources/timestamp.php");
+    l.setAttribute('as', 'fetch');
     l.onload = loadTimestampWithXHR;
     document.body.appendChild(l);
 });
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/onerror_event.html b/third_party/WebKit/LayoutTests/http/tests/preload/onerror_event.html
deleted file mode 100644
index 802e2d6a..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/preload/onerror_event.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head></head>
-<body>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-    var t = async_test('Makes sure that preloaded resources trigger the onerror event');
-    var scriptFailed = false;
-    var styleFailed = false;
-    var imageFailed = false;
-    var fontFailed = false;
-    var videoFailed = false;
-    var audioFailed = false;
-    var trackFailed = false;
-    var gibrishFailed = false;
-    var noTypeFailed = false;
-</script>
-<link rel=preload href="../non-existent/dummy.js" as=script onerror="scriptFailed = true;">
-<link rel=preload href="../non-existent/dummy.css" as=style onerror="styleFailed = true;">
-<link rel=preload href="../non-existent/square.png" as=image onerror="imageFailed = true;">
-<link rel=preload href="../non-existent/Ahem.ttf" as=font crossorigin onerror="fontFailed = true;">
-<link rel=preload href="../non-existent/test.mp4" as=video onerror="videoFailed = true;">
-<link rel=preload href="../non-existent/test.oga" as=audio onerror="audioFailed = true;">
-<link rel=preload href="../non-existent/security/captions.vtt" as=track onerror="trackFailed = true;">
-<link rel=preload href="../non-existent/dummy.xml" as=foobarxmlthing onerror="gibrishFailed = true;">
-<link rel=preload href="../non-existent/dummy.xml" onerror="noTypeFailed = true;">
-<script src="../resources/slow-script.pl?delay=500"></script>
-<script>
-    window.onload = t.step(function(){
-        assert_true(styleFailed, "style triggered error event");
-        assert_true(scriptFailed, "script triggered error event");
-        assert_true(imageFailed, "image triggered error event");
-        assert_true(fontFailed, "font triggered error event");
-        assert_true(videoFailed, "video triggered error event");
-        assert_true(audioFailed, "audio triggered error event");
-        assert_true(trackFailed, "track triggered error event");
-        assert_true(gibrishFailed, "gibrish as value triggered error event");
-        assert_true(noTypeFailed, "empty as triggered error event");
-        t.done();
-    });
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-anonymous.html b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-anonymous.html
index 8cd4785..7452937 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-anonymous.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-anonymous.html
@@ -12,12 +12,13 @@
     var anonymousDynamicLoad = false;
     var credentialsDynamicLoad = false;
 </script>
-<link crossorigin="anonymous" rel="preload" href="http://localhost:8080/security/resources/abe-allow-star.php" onload="anonymousMarkupLoad = true;">
-<link crossorigin="anonymous" rel="preload" href="http://localhost:8080/security/resources/abe-allow-credentials.php" onload="credentialsMarkupLoad = true;">
+<link crossorigin="anonymous" rel="preload" as="fetch" href="http://localhost:8080/security/resources/abe-allow-star.php" onload="anonymousMarkupLoad = true;">
+<link crossorigin="anonymous" rel="preload" as="fetch" href="http://localhost:8080/security/resources/abe-allow-credentials.php" onload="credentialsMarkupLoad = true;">
 <script>
     // Test that dynamically inserted <link> elements are handled the same way.
     var link = document.createElement("link");
     link.rel = "preload";
+    link.as = "fetch";
     link.crossOrigin = "anonymous";
     link.addEventListener("load", function() { anonymousDynamicLoad = true; });
     link.href = "http://localhost:8080/security/resources/abe-allow-star.php?1";
@@ -25,6 +26,7 @@
 
     link = document.createElement("link");
     link.rel = "preload";
+    link.as = "fetch";
     link.crossOrigin = "anonymous";
     link.addEventListener("load", function() { credentialsDynamicLoad = true; });
     link.href = "http://localhost:8080/security/resources/abe-allow-credentials.php?1";
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-no-cors.html b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-no-cors.html
index b6e9a2c7..6b150f9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-no-cors.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-no-cors.html
@@ -12,13 +12,14 @@
     var anonymousDynamicError = false;
     var credentialsDynamicError = false;
 </script>
-<link crossorigin="anonymous" rel="preload" href="http://localhost:8000/security/resources/abe.png?1" onerror="anonymousMarkupError = true;">
-<link crossorigin="use-credentials" rel="preload" href="http://localhost:8000/security/resources/abe.png?2" onerror="credentialsMarkupError = true;">
+<link crossorigin="anonymous" rel="preload" as="fetch" href="http://localhost:8000/security/resources/abe.png?1" onerror="anonymousMarkupError = true;">
+<link crossorigin="use-credentials" rel="preload" as="fetch" href="http://localhost:8000/security/resources/abe.png?2" onerror="credentialsMarkupError = true;">
 <script>
     // Test that dynamically inserted <link> elements are handled the same way.
     var link = document.createElement("link");
     link.crossOrigin = "anonymous";
     link.rel = "preload";
+    link.as = "fetch";
     link.addEventListener("error", function() { anonymousDynamicError = true; });
     link.href = "http://localhost:8000/security/resources/abe.png?3";
     document.body.appendChild(link);
@@ -26,6 +27,7 @@
     link = document.createElement("link");
     link.crossOrigin = "use-credentials";
     link.rel = "preload";
+    link.as = "fetch";
     link.addEventListener("error", function() { credentialsDynamicError = true; });
     link.href = "http://localhost:8000/security/resources/abe.png?4";
     document.body.appendChild(link);
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-use-credentials.html b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-use-credentials.html
index b0589cd..373f248 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-use-credentials.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-preload-use-credentials.html
@@ -12,11 +12,12 @@
     var credentialSpecificDynamicLoad = false;
     var credentialStarDynamicError = false;
 </script>
-<link crossorigin="use-credentials" rel="preload" href="http://localhost:8080/security/resources/abe-allow-credentials.php" onload="credentialSpecificMarkupLoad = true;">
-<link crossorigin="use-credentials" rel="preload" href="http://localhost:8080/security/resources/abe-allow-star.php" onerror="credentialStarMarkupError = true;">
+<link crossorigin="use-credentials" rel="preload" as="fetch" href="http://localhost:8080/security/resources/abe-allow-credentials.php" onload="credentialSpecificMarkupLoad = true;">
+<link crossorigin="use-credentials" rel="preload" as="fetch" href="http://localhost:8080/security/resources/abe-allow-star.php" onerror="credentialStarMarkupError = true;">
 <script>
     var link = document.createElement("link");
     link.rel = "preload";
+    link.as = "fetch";
     link.crossOrigin = "anonymous";
     link.addEventListener("load", function() { credentialSpecificDynamicLoad = true; });
     link.href = "http://localhost:8080/security/resources/abe-allow-credentials.php?1";
@@ -24,6 +25,7 @@
 
     link = document.createElement("link");
     link.rel = "preload";
+    link.as = "fetch";
     link.crossOrigin = "use-credentials";
     link.addEventListener("error", function() { credentialStarDynamicError = true; });
     link.href = "http://localhost:8080/security/resources/abe-allow-star.php?1";
diff --git a/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt b/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
index 72e6a1bd..fe80529 100644
--- a/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
@@ -65,6 +65,7 @@
 CONSOLE MESSAGE: line 147:     method entries
 CONSOLE MESSAGE: line 147:     method forEach
 CONSOLE MESSAGE: line 147:     method keys
+CONSOLE MESSAGE: line 147:     method toMatrix
 CONSOLE MESSAGE: line 147:     method values
 CONSOLE MESSAGE: line 147: interface CSSTranslation : CSSTransformComponent
 CONSOLE MESSAGE: line 147:     getter x
diff --git a/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray.html b/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray.html
new file mode 100644
index 0000000..b02ba40
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html>
+<body>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script type="text/javascript">
+test(function () {
+  assert_greater_than_equal(navigator.plugins.length, 1, "At least one plugin must be available.");
+  assert_greater_than_equal(navigator.mimeTypes.length, 1, "At least one mime type must be available.");
+  for (var i = 0; i < navigator.plugins.length; i++) {
+    var plugin = navigator.plugins[i];
+    var name = plugin.name;
+    assert_equals(plugin, navigator.plugins[i]);
+    assert_equals(plugin, navigator.plugins[name]);
+  }
+  for (var i = 0; i < navigator.mimeTypes.length; i++) {
+    var mime_type = navigator.mimeTypes[i];
+    var type = mime_type.type;
+    assert_equals(mime_type, navigator.mimeTypes[i]);
+    assert_equals(mime_type, navigator.mimeTypes[type]);
+    assert_equals(mime_type.enabledPlugin, navigator.plugins[mime_type.enabledPlugin.name]);
+  }
+}, "Tests that navigator.plugins returns the same object when queried multiple times.");
+
+test(function () {
+  assert_greater_than_equal(navigator.plugins.length, 1, "At least one plugin must be available.");
+  assert_greater_than_equal(navigator.mimeTypes.length, 1, "At least one mime type must be available.");
+  var iframe = document.createElement("iframe");
+  iframe.src = "about:blank";
+  document.body.appendChild(iframe);
+  assert_equals(navigator.plugins.length, iframe.contentWindow.navigator.plugins.length);
+  assert_equals(navigator.mimeTypes.length, iframe.contentWindow.navigator.mimeTypes.length);
+  for (var i = 0; i < navigator.plugins.length; i++) {
+    var plugin = navigator.plugins[i];
+    var name = plugin.name;
+    assert_not_equals(plugin, iframe.contentWindow.navigator.plugins[i]);
+    assert_not_equals(plugin, iframe.contentWindow.navigator.plugins[name]);
+  }
+  for (var i = 0; i < navigator.mimeTypes.length; i++) {
+    var mime_type = navigator.mimeTypes[i];
+    var type = mime_type.type;
+    assert_not_equals(mime_type, iframe.contentWindow.navigator.mimeTypes[i]);
+    assert_not_equals(mime_type, iframe.contentWindow.navigator.mimeTypes[type]);
+    assert_not_equals(mime_type.enabledPlugin, iframe.contentWindow.navigator.plugins[mime_type.enabledPlugin.name]);
+  }
+  iframe.remove();
+}, "Tests that navigator.plugins does not return the same object on different frames.");
+
+test(function () {
+  assert_greater_than_equal(navigator.plugins.length, 2, "At least two plugins must be available.");
+  assert_greater_than_equal(navigator.mimeTypes.length, 2, "At least two mime types must be available.");
+  for (var i = 1; i < navigator.plugins.length; i++) {
+    assert_less_than_equal(navigator.plugins[i-1].name.localeCompare(navigator.plugins[i].name), 0);
+  }
+  for (var i = 1; i < navigator.mimeTypes.length; i++) {
+    assert_less_than_equal(navigator.mimeTypes[i-1].type.localeCompare(navigator.mimeTypes[i].type), 0);
+  }
+}, "Tests that navigator.plugins returns plugins sorted in alphabetical order by plugin name.");
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssTransformValue.html b/third_party/WebKit/LayoutTests/typedcssom/cssTransformValue.html
index 15e5224..69119fb 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/cssTransformValue.html
+++ b/third_party/WebKit/LayoutTests/typedcssom/cssTransformValue.html
@@ -3,6 +3,7 @@
 <script src="../resources/testharnessreport.js"></script>
 
 <script>
+var EPSILON = 1e-6; // float epsilon
 
 test(function() {
   var transformValueObject = new CSSTransformValue();
@@ -44,4 +45,37 @@
   assert_equals(newTransformArray[2].constructor.name, CSSScale.name);
 }, "CSSTransformValue can iterate through all its all its transformComponent members");
 
+test(function() {
+  var transformArray = [new CSSScale(2,2)];
+  var transformValue = new CSSTransformValue(transformArray);
+
+  var expectedMatrix = new DOMMatrix();
+  expectedMatrix.scaleSelf(2, 2);
+
+  assert_matrix_approx_equals(transformValue.toMatrix(), expectedMatrix);
+}, "toMatrix() returns DOMMatrix Object - single CSSTransformComponent");
+
+test(function() {
+  var transformMatrix = new DOMMatrixReadOnly([1,1,1,1,1,1]);
+  var transformArray = [new CSSScale(2,2) , new CSSMatrixComponent(transformMatrix), new CSSScale(5,6)];
+  var transformValue = new CSSTransformValue(transformArray);
+
+  var expectedMatrix = new DOMMatrix();
+  expectedMatrix.scaleSelf(2, 2);
+  expectedMatrix.multiplySelf(transformMatrix);
+  expectedMatrix.scaleSelf(5, 6);
+
+  assert_matrix_approx_equals(transformValue.toMatrix(), expectedMatrix);
+},  "toMatrix() returns DOMMatrix Object - multiple CSSTransformComponent");
+
+function assert_array_approx_equals(actual, expected) {
+  for (var i = 0; i < actual.length; i++) {
+    assert_approx_equals(actual[i], expected[i], EPSILON);
+  }
+}
+
+function assert_matrix_approx_equals(actual, expected) {
+  assert_array_approx_equals(actual.toFloat64Array(), expected.toFloat64Array());
+}
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
index e1cd15e4f..aa614a4 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -767,6 +767,7 @@
     method entries
     method forEach
     method keys
+    method toMatrix
     method values
 interface CSSTranslation : CSSTransformComponent
     attribute @@toStringTag
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 72f8097..bd725eb 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -767,6 +767,7 @@
     method entries
     method forEach
     method keys
+    method toMatrix
     method values
 interface CSSTranslation : CSSTransformComponent
     attribute @@toStringTag
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index b9c997eed..363b23f 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1379,6 +1379,7 @@
     "loader/resource/MultipartImageResourceParserTest.cpp",
     "origin_trials/OriginTrialContextTest.cpp",
     "page/ChromeClientTest.cpp",
+    "page/EffectiveNavigationPolicyTest.cpp",
     "page/FocusControllerTest.cpp",
     "page/PagePopupClientTest.cpp",
     "page/PrintContextTest.cpp",
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.cpp b/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.cpp
index 8fa84ef..4c9c44a9 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.cpp
@@ -5,7 +5,9 @@
 #include "core/css/cssom/CSSTransformValue.h"
 
 #include "core/css/CSSValueList.h"
+#include "core/css/cssom/CSSMatrixComponent.h"
 #include "core/css/cssom/CSSTransformComponent.h"
+#include "core/geometry/DOMMatrix.h"
 
 namespace blink {
 
@@ -34,6 +36,17 @@
   return true;
 }
 
+DOMMatrix* CSSTransformValue::toMatrix() const {
+  DOMMatrix* matrix = DOMMatrix::Create();
+  for (size_t i = 0; i < transform_components_.size(); i++) {
+    CSSMatrixComponent* matrixComponent = transform_components_[i]->asMatrix();
+    if (matrixComponent) {
+      matrix->multiplySelf(matrixComponent->matrix());
+    }
+  }
+  return matrix;
+}
+
 const CSSValue* CSSTransformValue::ToCSSValue() const {
   CSSValueList* transform_css_value = CSSValueList::CreateSpaceSeparated();
   for (size_t i = 0; i < transform_components_.size(); i++) {
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.h b/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.h
index e03b904a..876601e 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.h
+++ b/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.h
@@ -13,6 +13,8 @@
 
 namespace blink {
 
+class DOMMatrix;
+
 class CORE_EXPORT CSSTransformValue final : public CSSStyleValue {
   WTF_MAKE_NONCOPYABLE(CSSTransformValue);
   DEFINE_WRAPPERTYPEINFO();
@@ -29,6 +31,8 @@
 
   bool is2D() const;
 
+  DOMMatrix* toMatrix() const;
+
   const CSSValue* ToCSSValue() const override;
 
   StyleValueType GetType() const override { return kTransformType; }
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.idl b/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.idl
index 6fabef5..c024b23 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.idl
+++ b/third_party/WebKit/Source/core/css/cssom/CSSTransformValue.idl
@@ -11,8 +11,8 @@
     // https://github.com/w3c/css-houdini-drafts/issues/358
     readonly attribute unsigned long length;
     [ImplementedAs=componentAtIndex] getter CSSTransformComponent (unsigned long index);
-
     iterable<CSSTransformComponent>;
 
     readonly attribute boolean is2D;
+    [RuntimeEnabled=GeometryInterfaces] DOMMatrix toMatrix();
 };
diff --git a/third_party/WebKit/Source/core/exported/WebViewBase.h b/third_party/WebKit/Source/core/exported/WebViewBase.h
index a80e23f9..0a32ec05 100644
--- a/third_party/WebKit/Source/core/exported/WebViewBase.h
+++ b/third_party/WebKit/Source/core/exported/WebViewBase.h
@@ -225,7 +225,6 @@
   virtual LinkHighlightImpl* GetLinkHighlight(int) = 0;
   virtual unsigned NumLinkHighlights() = 0;
   virtual void EnableTapHighlights(HeapVector<Member<Node>>&) = 0;
-  virtual void SetCurrentInputEventForTest(const WebInputEvent*) = 0;
 };
 }
 
diff --git a/third_party/WebKit/Source/core/frame/BarProp.cpp b/third_party/WebKit/Source/core/frame/BarProp.cpp
index 49dd576..70e3977 100644
--- a/third_party/WebKit/Source/core/frame/BarProp.cpp
+++ b/third_party/WebKit/Source/core/frame/BarProp.cpp
@@ -29,8 +29,8 @@
 #include "core/frame/BarProp.h"
 
 #include "core/frame/LocalFrame.h"
-#include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
+#include "public/web/WebWindowFeatures.h"
 
 namespace blink {
 
@@ -46,17 +46,19 @@
     return false;
   DCHECK(GetFrame()->GetPage());
 
+  const WebWindowFeatures& features =
+      GetFrame()->GetPage()->GetWindowFeatures();
   switch (type_) {
     case kLocationbar:
     case kPersonalbar:
     case kToolbar:
-      return GetFrame()->GetPage()->GetChromeClient().ToolbarsVisible();
+      return features.tool_bar_visible;
     case kMenubar:
-      return GetFrame()->GetPage()->GetChromeClient().MenubarVisible();
+      return features.menu_bar_visible;
     case kScrollbars:
-      return GetFrame()->GetPage()->GetChromeClient().ScrollbarsVisible();
+      return features.scrollbars_visible;
     case kStatusbar:
-      return GetFrame()->GetPage()->GetChromeClient().StatusbarVisible();
+      return features.status_bar_visible;
   }
 
   NOTREACHED();
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index 2e8f1551..5b5effb 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -75,7 +75,6 @@
 #include "core/page/ChromeClient.h"
 #include "core/page/CreateWindow.h"
 #include "core/page/Page.h"
-#include "core/page/WindowFeatures.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/probe/CoreProbes.h"
 #include "core/timing/DOMWindowPerformance.h"
@@ -1638,11 +1637,10 @@
     return target_frame->DomWindow();
   }
 
-  WindowFeatures features(window_features_string);
   DOMWindow* new_window =
-      CreateWindow(url_string, frame_name, features, *calling_window,
-                   *first_frame, *GetFrame(), exception_state);
-  return features.noopener ? nullptr : new_window;
+      CreateWindow(url_string, frame_name, window_features_string,
+                   *calling_window, *first_frame, *GetFrame(), exception_state);
+  return new_window;
 }
 
 DEFINE_TRACE(LocalDOMWindow) {
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp b/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp
index 3522b8e..90c26cd 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp
@@ -6,6 +6,10 @@
 
 namespace blink {
 
+DOMMatrix* DOMMatrix::Create() {
+  return new DOMMatrix(TransformationMatrix());
+}
+
 DOMMatrix* DOMMatrix::Create(ExecutionContext* execution_context,
                              ExceptionState& exception_state) {
   return new DOMMatrix(TransformationMatrix());
@@ -139,6 +143,10 @@
     DCHECK(exception_state.HadException());
     return nullptr;
   }
+  return multiplySelf(other_matrix);
+}
+
+DOMMatrix* DOMMatrix::multiplySelf(DOMMatrix* other_matrix) {
   if (!other_matrix->is2D())
     is2d_ = false;
 
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrix.h b/third_party/WebKit/Source/core/geometry/DOMMatrix.h
index 4254e94..fdc2432b 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrix.h
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrix.h
@@ -17,6 +17,7 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
+  static DOMMatrix* Create();
   static DOMMatrix* Create(ExecutionContext*, ExceptionState&);
   static DOMMatrix* Create(ExecutionContext*,
                            StringOrUnrestrictedDoubleSequence&,
@@ -87,6 +88,7 @@
   }
 
   DOMMatrix* multiplySelf(DOMMatrixInit&, ExceptionState&);
+  DOMMatrix* multiplySelf(DOMMatrix* other_matrix);
   DOMMatrix* preMultiplySelf(DOMMatrixInit&, ExceptionState&);
   DOMMatrix* translateSelf(double tx = 0, double ty = 0, double tz = 0);
   DOMMatrix* scaleSelf(double sx = 1);
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.idl b/third_party/WebKit/Source/core/html/HTMLLinkElement.idl
index e66a9382..51323cd 100644
--- a/third_party/WebKit/Source/core/html/HTMLLinkElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.idl
@@ -32,7 +32,7 @@
     [CEReactions, Reflect] attribute DOMString media;
     [CEReactions, Reflect] attribute DOMString hreflang;
     [CEReactions, Reflect] attribute DOMString type;
-    [Reflect] attribute DOMString as;
+    [Reflect, ReflectOnly=("script","style","image","video", "audio", "track", "font", "fetch")] attribute DOMString as;
     [CEReactions, Reflect, ReflectOnly=("","no-referrer","origin","no-referrer-when-downgrade","origin-when-cross-origin","unsafe-url"), ReflectMissing="", ReflectInvalid=""] attribute DOMString referrerPolicy;
     [CEReactions, PutForwards=value] readonly attribute DOMTokenList sizes;
 
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
index f4824ff6..b0f7222 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
@@ -797,7 +797,7 @@
 
 TEST_F(HTMLPreloadScannerTest, testLinkRelPreload) {
   TestCase test_cases[] = {
-      {"http://example.test", "<link rel=preload href=bla>", "bla",
+      {"http://example.test", "<link rel=preload as=fetch href=bla>", "bla",
        "http://example.test/", Resource::kRaw, 0},
       {"http://example.test", "<link rel=preload href=bla as=script>", "bla",
        "http://example.test/", Resource::kScript, 0},
@@ -838,6 +838,8 @@
       {"http://example.test",
        "<link rel=preload href=bla as=image media=\"(max-width: 400px)\">",
        nullptr, "http://example.test/", Resource::kImage, 0},
+      {"http://example.test", "<link rel=preload href=bla>", nullptr,
+       "http://example.test/", Resource::kRaw, 0},
   };
 
   for (const auto& test_case : test_cases)
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index da74d8cd..e23bbf49d 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -95,7 +95,7 @@
   void FocusedNodeChanged(Node*, Node*) override {}
   Page* CreateWindow(LocalFrame*,
                      const FrameLoadRequest&,
-                     const WindowFeatures&,
+                     const WebWindowFeatures&,
                      NavigationPolicy) override {
     return nullptr;
   }
@@ -117,20 +117,6 @@
                      const WebPoint& drag_image_offset) {}
   bool AcceptsLoadDrops() const override { return true; }
 
-  void SetToolbarsVisible(bool) override {}
-  bool ToolbarsVisible() override { return false; }
-
-  void SetStatusbarVisible(bool) override {}
-  bool StatusbarVisible() override { return false; }
-
-  void SetScrollbarsVisible(bool) override {}
-  bool ScrollbarsVisible() override { return false; }
-
-  void SetMenubarVisible(bool) override {}
-  bool MenubarVisible() override { return false; }
-
-  void SetResizable(bool) override {}
-
   bool ShouldReportDetailedMessageForSource(LocalFrame&,
                                             const String&) override {
     return false;
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index fcf4fe1..23b058d 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -75,7 +75,6 @@
 #include "core/page/CreateWindow.h"
 #include "core/page/FrameTree.h"
 #include "core/page/Page.h"
-#include "core/page/WindowFeatures.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/probe/CoreProbes.h"
 #include "core/svg/graphics/SVGImage.h"
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.cpp b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
index 3a97846..51e005b 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
@@ -226,7 +226,7 @@
     return Resource::kTextTrack;
   } else if (as == "font") {
     return Resource::kFont;
-  } else if (as.IsEmpty()) {
+  } else if (as == "fetch") {
     return Resource::kRaw;
   }
   return WTF::nullopt;
@@ -302,7 +302,6 @@
                                  const String& media,
                                  CrossOriginAttributeValue cross_origin,
                                  LinkCaller caller,
-                                 bool& error_occurred,
                                  ViewportDescription* viewport_description,
                                  ReferrerPolicy referrer_policy) {
   if (!document.Loader() || !rel_attribute.IsLinkPreload())
@@ -339,7 +338,6 @@
     document.AddConsoleMessage(ConsoleMessage::Create(
         kOtherMessageSource, kWarningMessageLevel,
         String("<link rel=preload> must have a valid `as` value")));
-    error_occurred = true;
     return nullptr;
   }
 
@@ -438,7 +436,6 @@
     }
     if (can_load_resources != kDoNotLoadResources) {
       DCHECK(document);
-      bool error_occurred = false;
       ViewportDescription* viewport_description =
           (viewport_description_wrapper && viewport_description_wrapper->set)
               ? &(viewport_description_wrapper->description)
@@ -448,8 +445,8 @@
           GetCrossOriginAttributeValue(header.CrossOrigin());
       PreloadIfNeeded(rel_attribute, url, *document, header.As(),
                       header.MimeType(), header.Media(), cross_origin,
-                      kLinkCalledFromHeader, error_occurred,
-                      viewport_description, kReferrerPolicyDefault);
+                      kLinkCalledFromHeader, viewport_description,
+                      kReferrerPolicyDefault);
       PrefetchIfNeeded(*document, url, rel_attribute, cross_origin,
                        kReferrerPolicyDefault);
     }
@@ -480,12 +477,9 @@
                      cross_origin, network_hints_interface,
                      kLinkCalledFromMarkup);
 
-  bool error_occurred = false;
   CreateLinkPreloadResourceClient(PreloadIfNeeded(
       rel_attribute, href, document, as, type, media, cross_origin,
-      kLinkCalledFromMarkup, error_occurred, nullptr, referrer_policy));
-  if (error_occurred)
-    link_loading_error_timer_.StartOneShot(0, BLINK_FROM_HERE);
+      kLinkCalledFromMarkup, nullptr, referrer_policy));
 
   if (href.IsEmpty() || !href.IsValid())
     Released();
diff --git a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
index 23463af..6d9aaa319 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
@@ -166,12 +166,15 @@
      kReferrerPolicyDefault},
     // TODO(yoav): subresource should be *very* low priority (rather than
     // low).
-    {"http://example.test/cat.empty", "", "", "", kReferrerPolicyDefault,
+    {"http://example.test/cat.empty", "fetch", "", "", kReferrerPolicyDefault,
      kResourceLoadPriorityHigh, WebURLRequest::kRequestContextSubresource, true,
      true, kReferrerPolicyDefault},
     {"http://example.test/cat.blob", "blabla", "", "", kReferrerPolicyDefault,
      kResourceLoadPriorityLow, WebURLRequest::kRequestContextSubresource, false,
      false, kReferrerPolicyDefault},
+    {"http://example.test/cat.blob", "", "", "", kReferrerPolicyDefault,
+     kResourceLoadPriorityLow, WebURLRequest::kRequestContextSubresource, false,
+     false, kReferrerPolicyDefault},
     {"bla://example.test/cat.gif", "image", "", "", kReferrerPolicyDefault,
      kResourceLoadPriorityUnresolved, WebURLRequest::kRequestContextImage,
      false, false, kReferrerPolicyDefault},
@@ -222,13 +225,17 @@
     {"http://example.test/cat.woff", "font", "font/woff84", "",
      kReferrerPolicyDefault, kResourceLoadPriorityUnresolved,
      WebURLRequest::kRequestContextFont, false, false, kReferrerPolicyDefault},
-    {"http://example.test/cat.empty", "", "foo/bar", "", kReferrerPolicyDefault,
-     kResourceLoadPriorityHigh, WebURLRequest::kRequestContextSubresource, true,
-     true, kReferrerPolicyDefault},
+    {"http://example.test/cat.empty", "fetch", "foo/bar", "",
+     kReferrerPolicyDefault, kResourceLoadPriorityHigh,
+     WebURLRequest::kRequestContextSubresource, true, true,
+     kReferrerPolicyDefault},
     {"http://example.test/cat.blob", "blabla", "foo/bar", "",
      kReferrerPolicyDefault, kResourceLoadPriorityLow,
      WebURLRequest::kRequestContextSubresource, false, false,
      kReferrerPolicyDefault},
+    {"http://example.test/cat.blob", "", "foo/bar", "", kReferrerPolicyDefault,
+     kResourceLoadPriorityLow, WebURLRequest::kRequestContextSubresource, false,
+     false, kReferrerPolicyDefault},
     // Media tests
     {"http://example.test/cat.gif", "image", "image/gif", "(max-width: 600px)",
      kReferrerPolicyDefault, kResourceLoadPriorityLow,
diff --git a/third_party/WebKit/Source/core/page/BUILD.gn b/third_party/WebKit/Source/core/page/BUILD.gn
index 7286a84..1cd9cb3a 100644
--- a/third_party/WebKit/Source/core/page/BUILD.gn
+++ b/third_party/WebKit/Source/core/page/BUILD.gn
@@ -65,8 +65,6 @@
     "ValidationMessageClient.h",
     "ValidationMessageClientImpl.cpp",
     "ValidationMessageClientImpl.h",
-    "WindowFeatures.cpp",
-    "WindowFeatures.h",
     "scrolling/OverscrollController.cpp",
     "scrolling/OverscrollController.h",
     "scrolling/RootScrollerController.cpp",
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.cpp b/third_party/WebKit/Source/core/page/ChromeClient.cpp
index a4760020f..4b08bd7 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.cpp
+++ b/third_party/WebKit/Source/core/page/ChromeClient.cpp
@@ -31,7 +31,6 @@
 #include "core/page/FrameTree.h"
 #include "core/page/Page.h"
 #include "core/page/ScopedPageSuspender.h"
-#include "core/page/WindowFeatures.h"
 #include "core/probe/CoreProbes.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/network/NetworkHints.h"
@@ -86,15 +85,6 @@
   return true;
 }
 
-void ChromeClient::SetWindowFeatures(const WindowFeatures& features) {
-  SetToolbarsVisible(features.tool_bar_visible ||
-                     features.location_bar_visible);
-  SetStatusbarVisible(features.status_bar_visible);
-  SetScrollbarsVisible(features.scrollbars_visible);
-  SetMenubarVisible(features.menu_bar_visible);
-  SetResizable(features.resizable);
-}
-
 template <typename Delegate>
 static bool OpenJavaScriptDialog(LocalFrame* frame,
                                  const String& message,
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index 21a903d..120c6478 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -91,7 +91,7 @@
 struct WebCursorInfo;
 struct WebPoint;
 struct WebScreenInfo;
-struct WindowFeatures;
+struct WebWindowFeatures;
 
 class CORE_EXPORT ChromeClient : public PlatformChromeClient {
  public:
@@ -131,11 +131,9 @@
   // request could be fulfilled. The ChromeClient should not load the request.
   virtual Page* CreateWindow(LocalFrame*,
                              const FrameLoadRequest&,
-                             const WindowFeatures&,
+                             const WebWindowFeatures&,
                              NavigationPolicy) = 0;
-  virtual void Show(NavigationPolicy = kNavigationPolicyIgnore) = 0;
-
-  void SetWindowFeatures(const WindowFeatures&);
+  virtual void Show(NavigationPolicy) = 0;
 
   // All the parameters should be in viewport space. That is, if an event
   // scrolls by 10 px, but due to a 2X page scale we apply a 5px scroll to the
@@ -146,20 +144,6 @@
                              const FloatPoint& position_in_viewport,
                              const FloatSize& velocity_in_viewport) = 0;
 
-  virtual void SetToolbarsVisible(bool) = 0;
-  virtual bool ToolbarsVisible() = 0;
-
-  virtual void SetStatusbarVisible(bool) = 0;
-  virtual bool StatusbarVisible() = 0;
-
-  virtual void SetScrollbarsVisible(bool) = 0;
-  virtual bool ScrollbarsVisible() = 0;
-
-  virtual void SetMenubarVisible(bool) = 0;
-  virtual bool MenubarVisible() = 0;
-
-  virtual void SetResizable(bool) = 0;
-
   virtual bool ShouldReportDetailedMessageForSource(LocalFrame&,
                                                     const String& source) = 0;
   virtual void AddMessageToConsole(LocalFrame*,
@@ -280,6 +264,7 @@
       WebEventListenerClass) const = 0;
   virtual void UpdateEventRectsForSubframeIfNecessary(LocalFrame*) = 0;
   virtual void SetHasScrollEventHandlers(LocalFrame*, bool) = 0;
+  virtual const WebInputEvent* GetCurrentInputEvent() const { return nullptr; }
 
   virtual void SetTouchAction(LocalFrame*, TouchAction) = 0;
 
diff --git a/third_party/WebKit/Source/core/page/CreateWindow.cpp b/third_party/WebKit/Source/core/page/CreateWindow.cpp
index d3a42e6f..88aa2ad 100644
--- a/third_party/WebKit/Source/core/page/CreateWindow.cpp
+++ b/third_party/WebKit/Source/core/page/CreateWindow.cpp
@@ -29,6 +29,7 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/Document.h"
 #include "core/dom/UserGestureIndicator.h"
+#include "core/events/UIEventWithKeyState.h"
 #include "core/frame/FrameClient.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/Settings.h"
@@ -37,16 +38,225 @@
 #include "core/page/ChromeClient.h"
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
-#include "core/page/WindowFeatures.h"
 #include "core/probe/CoreProbes.h"
+#include "platform/KeyboardCodes.h"
 #include "platform/loader/fetch/ResourceRequest.h"
 #include "platform/weborigin/KURL.h"
 #include "platform/weborigin/SecurityOrigin.h"
 #include "platform/weborigin/SecurityPolicy.h"
+#include "public/platform/WebInputEvent.h"
+#include "public/platform/WebKeyboardEvent.h"
+#include "public/platform/WebMouseEvent.h"
 #include "public/platform/WebURLRequest.h"
+#include "public/web/WebWindowFeatures.h"
 
 namespace blink {
 
+namespace {
+
+void UpdatePolicyForEvent(const WebInputEvent* input_event,
+                          NavigationPolicy* policy) {
+  if (!input_event)
+    return;
+
+  unsigned short button_number = 0;
+  if (input_event->GetType() == WebInputEvent::kMouseUp) {
+    const WebMouseEvent* mouse_event =
+        static_cast<const WebMouseEvent*>(input_event);
+
+    switch (mouse_event->button) {
+      case WebMouseEvent::Button::kLeft:
+        button_number = 0;
+        break;
+      case WebMouseEvent::Button::kMiddle:
+        button_number = 1;
+        break;
+      case WebMouseEvent::Button::kRight:
+        button_number = 2;
+        break;
+      default:
+        return;
+    }
+  } else if ((WebInputEvent::IsKeyboardEventType(input_event->GetType()) &&
+              static_cast<const WebKeyboardEvent*>(input_event)
+                      ->windows_key_code == VKEY_RETURN) ||
+             WebInputEvent::IsGestureEventType(input_event->GetType())) {
+    // Keyboard and gesture events can simulate mouse events.
+    button_number = 0;
+  } else {
+    return;
+  }
+
+  bool ctrl = input_event->GetModifiers() & WebInputEvent::kControlKey;
+  bool shift = input_event->GetModifiers() & WebInputEvent::kShiftKey;
+  bool alt = input_event->GetModifiers() & WebInputEvent::kAltKey;
+  bool meta = input_event->GetModifiers() & WebInputEvent::kMetaKey;
+
+  NavigationPolicy user_policy = *policy;
+  NavigationPolicyFromMouseEvent(button_number, ctrl, shift, alt, meta,
+                                 &user_policy);
+
+  // When the input event suggests a download, but the navigation was initiated
+  // by script, we should not override it.
+  if (user_policy == kNavigationPolicyDownload &&
+      *policy != kNavigationPolicyIgnore)
+    return;
+
+  // User and app agree that we want a new window; let the app override the
+  // decorations.
+  if (user_policy == kNavigationPolicyNewWindow &&
+      *policy == kNavigationPolicyNewPopup)
+    return;
+  *policy = user_policy;
+}
+
+NavigationPolicy GetNavigationPolicy(const WebInputEvent* current_event,
+                                     bool toolbar_visible) {
+  // If the window features didn't enable the toolbar, or this window wasn't
+  // created by a user gesture, show as a popup instead of a new tab.
+  //
+  // Note: this previously also checked that menubar, resizable, scrollbar, and
+  // statusbar are enabled too. When no feature string is specified, these
+  // features default to enabled (and the window opens as a new tab). However,
+  // when a feature string is specified, any *unspecified* features default to
+  // disabled, often causing the window to open as a popup instead.
+  //
+  // As specifying menubar, resizable, scrollbar, and statusbar have no effect
+  // on the UI, just ignore them and only consider whether or not the toolbar is
+  // enabled, which matches Firefox's behavior.
+  NavigationPolicy policy = toolbar_visible ? kNavigationPolicyNewForegroundTab
+                                            : kNavigationPolicyNewPopup;
+  UpdatePolicyForEvent(current_event, &policy);
+  return policy;
+}
+
+}  // anonymous namespace
+
+NavigationPolicy EffectiveNavigationPolicy(NavigationPolicy policy,
+                                           const WebInputEvent* current_event,
+                                           bool toolbar_visible) {
+  if (policy == kNavigationPolicyIgnore)
+    return GetNavigationPolicy(current_event, toolbar_visible);
+  if (policy == kNavigationPolicyNewBackgroundTab &&
+      GetNavigationPolicy(current_event, toolbar_visible) !=
+          kNavigationPolicyNewBackgroundTab &&
+      !UIEventWithKeyState::NewTabModifierSetFromIsolatedWorld()) {
+    return kNavigationPolicyNewForegroundTab;
+  }
+  return policy;
+}
+
+// Though isspace() considers \t and \v to be whitespace, Win IE doesn't when
+// parsing window features.
+static bool IsWindowFeaturesSeparator(UChar c) {
+  return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' ||
+         c == ',' || c == '\0';
+}
+
+WebWindowFeatures GetWindowFeaturesFromString(const String& feature_string) {
+  WebWindowFeatures window_features;
+
+  // The IE rule is: all features except for channelmode default
+  // to YES, but if the user specifies a feature string, all features default to
+  // NO. (There is no public standard that applies to this method.)
+  // <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
+  if (feature_string.IsEmpty())
+    return window_features;
+
+  window_features.menu_bar_visible = false;
+  window_features.status_bar_visible = false;
+  window_features.tool_bar_visible = false;
+  window_features.scrollbars_visible = false;
+
+  // Tread lightly in this code -- it was specifically designed to mimic Win
+  // IE's parsing behavior.
+  unsigned key_begin, key_end;
+  unsigned value_begin, value_end;
+
+  String buffer = feature_string.DeprecatedLower();
+  unsigned length = buffer.length();
+  for (unsigned i = 0; i < length;) {
+    // skip to first non-separator, but don't skip past the end of the string
+    while (i < length && IsWindowFeaturesSeparator(buffer[i]))
+      i++;
+    key_begin = i;
+
+    // skip to first separator
+    while (i < length && !IsWindowFeaturesSeparator(buffer[i]))
+      i++;
+    key_end = i;
+
+    SECURITY_DCHECK(i <= length);
+
+    // skip to first '=', but don't skip past a ',' or the end of the string
+    while (i < length && buffer[i] != '=') {
+      if (buffer[i] == ',')
+        break;
+      i++;
+    }
+
+    SECURITY_DCHECK(i <= length);
+
+    // Skip to first non-separator, but don't skip past a ',' or the end of the
+    // string.
+    while (i < length && IsWindowFeaturesSeparator(buffer[i])) {
+      if (buffer[i] == ',')
+        break;
+      i++;
+    }
+    value_begin = i;
+
+    SECURITY_DCHECK(i <= length);
+
+    // skip to first separator
+    while (i < length && !IsWindowFeaturesSeparator(buffer[i]))
+      i++;
+    value_end = i;
+
+    SECURITY_DCHECK(i <= length);
+
+    String key_string(buffer.Substring(key_begin, key_end - key_begin));
+    String value_string(buffer.Substring(value_begin, value_end - value_begin));
+
+    // Listing a key with no value is shorthand for key=yes
+    int value;
+    if (value_string.IsEmpty() || value_string == "yes")
+      value = 1;
+    else
+      value = value_string.ToInt();
+
+    if (key_string == "left" || key_string == "screenx") {
+      window_features.x_set = true;
+      window_features.x = value;
+    } else if (key_string == "top" || key_string == "screeny") {
+      window_features.y_set = true;
+      window_features.y = value;
+    } else if (key_string == "width" || key_string == "innerwidth") {
+      window_features.width_set = true;
+      window_features.width = value;
+    } else if (key_string == "height" || key_string == "innerheight") {
+      window_features.height_set = true;
+      window_features.height = value;
+    } else if (key_string == "menubar") {
+      window_features.menu_bar_visible = value;
+    } else if (key_string == "toolbar" || key_string == "location") {
+      window_features.tool_bar_visible |= static_cast<bool>(value);
+    } else if (key_string == "status") {
+      window_features.status_bar_visible = value;
+    } else if (key_string == "scrollbars") {
+      window_features.scrollbars_visible = value;
+    } else if (key_string == "noopener") {
+      window_features.noopener = true;
+    } else if (key_string == "background") {
+      window_features.background = true;
+    } else if (key_string == "persistent") {
+      window_features.persistent = true;
+    }
+  }
+
+  return window_features;
+}
+
 static Frame* ReuseExistingWindow(LocalFrame& active_frame,
                                   LocalFrame& lookup_frame,
                                   const AtomicString& frame_name,
@@ -71,13 +281,17 @@
 
 static Frame* CreateNewWindow(LocalFrame& opener_frame,
                               const FrameLoadRequest& request,
-                              const WindowFeatures& features,
+                              const WebWindowFeatures& features,
                               NavigationPolicy policy,
                               bool& created) {
   Page* old_page = opener_frame.GetPage();
   if (!old_page)
     return nullptr;
 
+  policy = EffectiveNavigationPolicy(
+      policy, old_page->GetChromeClient().GetCurrentInputEvent(),
+      features.tool_bar_visible);
+
   Page* page = old_page->GetChromeClient().CreateWindow(&opener_frame, request,
                                                         features, policy);
   if (!page)
@@ -92,7 +306,9 @@
   if (!EqualIgnoringASCIICase(request.FrameName(), "_blank"))
     frame.Tree().SetName(request.FrameName());
 
-  page->GetChromeClient().SetWindowFeatures(features);
+  page->SetWindowFeatures(features);
+
+  frame.View()->SetCanHaveScrollbars(features.scrollbars_visible);
 
   // 'x' and 'y' specify the location of the window, while 'width' and 'height'
   // specify the size of the viewport. We can only resize the window, so adjust
@@ -130,10 +346,9 @@
                                  LocalFrame& active_frame,
                                  LocalFrame& lookup_frame,
                                  const FrameLoadRequest& request,
-                                 const WindowFeatures& features,
+                                 const WebWindowFeatures& features,
                                  NavigationPolicy policy,
                                  bool& created) {
-  DCHECK(!features.dialog || request.FrameName().IsEmpty());
   DCHECK(request.GetResourceRequest().RequestorOrigin() ||
          opener_frame.GetDocument()->Url().IsEmpty());
   DCHECK_EQ(request.GetResourceRequest().GetFrameType(),
@@ -176,7 +391,7 @@
 
 DOMWindow* CreateWindow(const String& url_string,
                         const AtomicString& frame_name,
-                        const WindowFeatures& window_features,
+                        const String& window_features_string,
                         LocalDOMWindow& calling_window,
                         LocalFrame& first_frame,
                         LocalFrame& opener_frame,
@@ -195,6 +410,9 @@
     return nullptr;
   }
 
+  WebWindowFeatures window_features =
+      GetWindowFeaturesFromString(window_features_string);
+
   FrameLoadRequest frame_request(calling_window.document(),
                                  ResourceRequest(completed_url), frame_name);
   frame_request.SetShouldSetOpener(window_features.noopener ? kNeverSetOpener
@@ -231,7 +449,7 @@
     return nullptr;
   if (new_frame->DomWindow()->IsInsecureScriptAccess(calling_window,
                                                      completed_url))
-    return new_frame->DomWindow();
+    return window_features.noopener ? nullptr : new_frame->DomWindow();
 
   // TODO(dcheng): Special case for window.open("about:blank") to ensure it
   // loads synchronously into a new window. This is our historical behavior, and
@@ -252,7 +470,7 @@
                         has_user_gesture ? UserGestureStatus::kActive
                                          : UserGestureStatus::kNone);
   }
-  return new_frame->DomWindow();
+  return window_features.noopener ? nullptr : new_frame->DomWindow();
 }
 
 void CreateWindowForRequest(const FrameLoadRequest& request,
@@ -273,7 +491,7 @@
   if (policy == kNavigationPolicyCurrentTab)
     policy = kNavigationPolicyNewForegroundTab;
 
-  WindowFeatures features;
+  WebWindowFeatures features;
   features.noopener = request.GetShouldSetOpener() == kNeverSetOpener;
   bool created;
   Frame* new_frame =
diff --git a/third_party/WebKit/Source/core/page/CreateWindow.h b/third_party/WebKit/Source/core/page/CreateWindow.h
index ee4d3cc..557f25b 100644
--- a/third_party/WebKit/Source/core/page/CreateWindow.h
+++ b/third_party/WebKit/Source/core/page/CreateWindow.h
@@ -39,11 +39,11 @@
 class ExceptionState;
 class LocalFrame;
 struct FrameLoadRequest;
-struct WindowFeatures;
+struct WebWindowFeatures;
 
 DOMWindow* CreateWindow(const String& url_string,
                         const AtomicString& frame_name,
-                        const WindowFeatures&,
+                        const String& window_features_string,
                         LocalDOMWindow& calling_window,
                         LocalFrame& first_frame,
                         LocalFrame& opener_frame,
@@ -53,6 +53,15 @@
                             LocalFrame& opener_frame,
                             NavigationPolicy);
 
+// Exposed for testing
+CORE_EXPORT NavigationPolicy
+EffectiveNavigationPolicy(NavigationPolicy,
+                          const WebInputEvent* current_event,
+                          bool toolbar_visible);
+
+// Exposed for testing
+CORE_EXPORT WebWindowFeatures GetWindowFeaturesFromString(const String&);
+
 }  // namespace blink
 
 #endif  // CreateWindow_h
diff --git a/third_party/WebKit/Source/core/page/EffectiveNavigationPolicyTest.cpp b/third_party/WebKit/Source/core/page/EffectiveNavigationPolicyTest.cpp
new file mode 100644
index 0000000..7752ccb
--- /dev/null
+++ b/third_party/WebKit/Source/core/page/EffectiveNavigationPolicyTest.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/page/CreateWindow.h"
+#include "public/platform/WebInputEvent.h"
+#include "public/platform/WebMouseEvent.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+class EffectiveNavigationPolicyTest : public testing::Test {
+ protected:
+  NavigationPolicy GetNavigationPolicyWithMouseEvent(
+      int modifiers,
+      WebMouseEvent::Button button,
+      bool as_popup) {
+    WebMouseEvent event(WebInputEvent::kMouseUp, modifiers,
+                        WebInputEvent::kTimeStampForTesting);
+    event.button = button;
+    return EffectiveNavigationPolicy(kNavigationPolicyIgnore, &event,
+                                     !as_popup);
+  }
+};
+
+TEST_F(EffectiveNavigationPolicyTest, LeftClick) {
+  int modifiers = 0;
+  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
+  bool as_popup = false;
+  EXPECT_EQ(kNavigationPolicyNewForegroundTab,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, LeftClickPopup) {
+  int modifiers = 0;
+  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
+  bool as_popup = true;
+  EXPECT_EQ(kNavigationPolicyNewPopup,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, ShiftLeftClick) {
+  int modifiers = WebInputEvent::kShiftKey;
+  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
+  bool as_popup = false;
+  EXPECT_EQ(kNavigationPolicyNewWindow,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, ShiftLeftClickPopup) {
+  int modifiers = WebInputEvent::kShiftKey;
+  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
+  bool as_popup = true;
+  EXPECT_EQ(kNavigationPolicyNewPopup,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, ControlOrMetaLeftClick) {
+#if OS(MACOSX)
+  int modifiers = WebInputEvent::kMetaKey;
+#else
+  int modifiers = WebInputEvent::kControlKey;
+#endif
+  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
+  bool as_popup = false;
+  EXPECT_EQ(kNavigationPolicyNewBackgroundTab,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, ControlOrMetaLeftClickPopup) {
+#if OS(MACOSX)
+  int modifiers = WebInputEvent::kMetaKey;
+#else
+  int modifiers = WebInputEvent::kControlKey;
+#endif
+  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
+  bool as_popup = true;
+  EXPECT_EQ(kNavigationPolicyNewBackgroundTab,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, ControlOrMetaAndShiftLeftClick) {
+#if OS(MACOSX)
+  int modifiers = WebInputEvent::kMetaKey;
+#else
+  int modifiers = WebInputEvent::kControlKey;
+#endif
+  modifiers |= WebInputEvent::kShiftKey;
+  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
+  bool as_popup = false;
+  EXPECT_EQ(kNavigationPolicyNewForegroundTab,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, ControlOrMetaAndShiftLeftClickPopup) {
+#if OS(MACOSX)
+  int modifiers = WebInputEvent::kMetaKey;
+#else
+  int modifiers = WebInputEvent::kControlKey;
+#endif
+  modifiers |= WebInputEvent::kShiftKey;
+  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
+  bool as_popup = true;
+  EXPECT_EQ(kNavigationPolicyNewForegroundTab,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, MiddleClick) {
+  int modifiers = 0;
+  bool as_popup = false;
+  WebMouseEvent::Button button = WebMouseEvent::Button::kMiddle;
+  EXPECT_EQ(kNavigationPolicyNewBackgroundTab,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, MiddleClickPopup) {
+  int modifiers = 0;
+  bool as_popup = true;
+  WebMouseEvent::Button button = WebMouseEvent::Button::kMiddle;
+  EXPECT_EQ(kNavigationPolicyNewBackgroundTab,
+            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, NoToolbarsForcesPopup) {
+  EXPECT_EQ(kNavigationPolicyNewPopup,
+            EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, false));
+  EXPECT_EQ(kNavigationPolicyNewForegroundTab,
+            EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, true));
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index 25b883e..e878d1f 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -287,12 +287,6 @@
 
 void Page::RefreshPlugins() {
   PluginData::RefreshBrowserSidePluginCache();
-
-  for (const Page* page : AllPages()) {
-    // Clear out the page's plugin data.
-    if (page->plugin_data_)
-      page->plugin_data_->ResetPluginData();
-  }
 }
 
 PluginData* Page::GetPluginData(SecurityOrigin* main_frame_origin) {
diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h
index f1ef9635..6258d19 100644
--- a/third_party/WebKit/Source/core/page/Page.h
+++ b/third_party/WebKit/Source/core/page/Page.h
@@ -43,6 +43,7 @@
 #include "platform/wtf/HashSet.h"
 #include "platform/wtf/Noncopyable.h"
 #include "platform/wtf/text/WTFString.h"
+#include "public/web/WebWindowFeatures.h"
 
 namespace blink {
 
@@ -185,6 +186,13 @@
   Deprecation& GetDeprecation() { return deprecation_; }
   HostsUsingFeatures& GetHostsUsingFeatures() { return hosts_using_features_; }
 
+  void SetWindowFeatures(const WebWindowFeatures& features) {
+    window_features_ = features;
+  }
+  const WebWindowFeatures& GetWindowFeatures() const {
+    return window_features_;
+  }
+
   PageScaleConstraintsSet& GetPageScaleConstraintsSet();
   const PageScaleConstraintsSet& GetPageScaleConstraintsSet() const;
 
@@ -333,6 +341,7 @@
   UseCounter use_counter_;
   Deprecation deprecation_;
   HostsUsingFeatures hosts_using_features_;
+  WebWindowFeatures window_features_;
 
   bool opened_by_dom_;
   // Set to true when window.close() has been called and the Page will be
diff --git a/third_party/WebKit/Source/core/page/WindowFeatures.cpp b/third_party/WebKit/Source/core/page/WindowFeatures.cpp
deleted file mode 100644
index 6b2133d..0000000
--- a/third_party/WebKit/Source/core/page/WindowFeatures.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- *  Copyright (C) 2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights
- * reseved.
- *  Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
- *  USA
- */
-
-#include "core/page/WindowFeatures.h"
-
-#include "platform/geometry/IntRect.h"
-#include "platform/wtf/Assertions.h"
-#include "platform/wtf/MathExtras.h"
-#include "platform/wtf/text/StringHash.h"
-
-namespace blink {
-
-// Though isspace() considers \t and \v to be whitespace, Win IE doesn't when
-// parsing window features.
-static bool IsWindowFeaturesSeparator(UChar c) {
-  return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' ||
-         c == ',' || c == '\0';
-}
-
-WindowFeatures::WindowFeatures(const String& features)
-    : x(0),
-      x_set(false),
-      y(0),
-      y_set(false),
-      width(0),
-      width_set(false),
-      height(0),
-      height_set(false),
-      resizable(true),
-      fullscreen(false),
-      dialog(false),
-      noopener(false) {
-  /*
-     The IE rule is: all features except for channelmode and fullscreen default
-     to YES, but if the user specifies a feature string, all features default to
-     NO. (There is no public standard that applies to this method.)
-
-     <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
-     We always allow a window to be resized, which is consistent with Firefox.
-     */
-
-  if (features.IsEmpty()) {
-    menu_bar_visible = true;
-    status_bar_visible = true;
-    tool_bar_visible = true;
-    location_bar_visible = true;
-    scrollbars_visible = true;
-    return;
-  }
-
-  menu_bar_visible = false;
-  status_bar_visible = false;
-  tool_bar_visible = false;
-  location_bar_visible = false;
-  scrollbars_visible = false;
-
-  // Tread lightly in this code -- it was specifically designed to mimic Win
-  // IE's parsing behavior.
-  unsigned key_begin, key_end;
-  unsigned value_begin, value_end;
-
-  String buffer = features.DeprecatedLower();
-  unsigned length = buffer.length();
-  for (unsigned i = 0; i < length;) {
-    // skip to first non-separator, but don't skip past the end of the string
-    while (i < length && IsWindowFeaturesSeparator(buffer[i]))
-      i++;
-    key_begin = i;
-
-    // skip to first separator
-    while (i < length && !IsWindowFeaturesSeparator(buffer[i]))
-      i++;
-    key_end = i;
-
-    SECURITY_DCHECK(i <= length);
-
-    // skip to first '=', but don't skip past a ',' or the end of the string
-    while (i < length && buffer[i] != '=') {
-      if (buffer[i] == ',')
-        break;
-      i++;
-    }
-
-    SECURITY_DCHECK(i <= length);
-
-    // Skip to first non-separator, but don't skip past a ',' or the end of the
-    // string.
-    while (i < length && IsWindowFeaturesSeparator(buffer[i])) {
-      if (buffer[i] == ',')
-        break;
-      i++;
-    }
-    value_begin = i;
-
-    SECURITY_DCHECK(i <= length);
-
-    // skip to first separator
-    while (i < length && !IsWindowFeaturesSeparator(buffer[i]))
-      i++;
-    value_end = i;
-
-    SECURITY_DCHECK(i <= length);
-
-    String key_string(buffer.Substring(key_begin, key_end - key_begin));
-    String value_string(buffer.Substring(value_begin, value_end - value_begin));
-
-    SetWindowFeature(key_string, value_string);
-  }
-}
-
-void WindowFeatures::SetWindowFeature(const String& key_string,
-                                      const String& value_string) {
-  int value;
-
-  // Listing a key with no value is shorthand for key=yes
-  if (value_string.IsEmpty() || value_string == "yes")
-    value = 1;
-  else
-    value = value_string.ToInt();
-
-  // We treat keyString of "resizable" here as an additional feature rather than
-  // setting resizeable to true.  This is consistent with Firefox, but could
-  // also be handled at another level.
-
-  if (key_string == "left" || key_string == "screenx") {
-    x_set = true;
-    x = value;
-  } else if (key_string == "top" || key_string == "screeny") {
-    y_set = true;
-    y = value;
-  } else if (key_string == "width" || key_string == "innerwidth") {
-    width_set = true;
-    width = value;
-  } else if (key_string == "height" || key_string == "innerheight") {
-    height_set = true;
-    height = value;
-  } else if (key_string == "menubar") {
-    menu_bar_visible = value;
-  } else if (key_string == "toolbar") {
-    tool_bar_visible = value;
-  } else if (key_string == "location") {
-    location_bar_visible = value;
-  } else if (key_string == "status") {
-    status_bar_visible = value;
-  } else if (key_string == "fullscreen") {
-    fullscreen = value;
-  } else if (key_string == "scrollbars") {
-    scrollbars_visible = value;
-  } else if (key_string == "noopener") {
-    noopener = true;
-  } else if (value == 1) {
-    additional_features.push_back(key_string);
-  }
-}
-
-WindowFeatures::WindowFeatures(const String& dialog_features_string,
-                               const IntRect& screen_available_rect)
-    : width_set(true),
-      height_set(true),
-      menu_bar_visible(false),
-      tool_bar_visible(false),
-      location_bar_visible(false),
-      fullscreen(false),
-      dialog(true),
-      noopener(false) {
-  DialogFeaturesMap features;
-  ParseDialogFeatures(dialog_features_string, features);
-
-  const bool kTrusted = false;
-
-  // The following features from Microsoft's documentation are not implemented:
-  // - default font settings
-  // - width, height, left, and top specified in units other than "px"
-  // - edge (sunken or raised, default is raised)
-  // - dialogHide: trusted && boolFeature(features, "dialoghide"), makes dialog
-  //               hide when you print
-  // - help: boolFeature(features, "help", true), makes help icon appear in
-  //         dialog (what does it do on Windows?)
-  // - unadorned: trusted && boolFeature(features, "unadorned");
-
-  // default here came from frame size of dialog in MacIE
-  width = IntFeature(features, "dialogwidth", 100,
-                     screen_available_rect.Width(), 620);
-  // default here came from frame size of dialog in MacIE
-  height = IntFeature(features, "dialogheight", 100,
-                      screen_available_rect.Height(), 450);
-
-  x = IntFeature(features, "dialogleft", screen_available_rect.X(),
-                 screen_available_rect.MaxX() - width, -1);
-  x_set = x > 0;
-  y = IntFeature(features, "dialogtop", screen_available_rect.Y(),
-                 screen_available_rect.MaxY() - height, -1);
-  y_set = y > 0;
-
-  if (BoolFeature(features, "center", true)) {
-    if (!x_set) {
-      x = screen_available_rect.X() +
-          (screen_available_rect.Width() - width) / 2;
-      x_set = true;
-    }
-    if (!y_set) {
-      y = screen_available_rect.Y() +
-          (screen_available_rect.Height() - height) / 2;
-      y_set = true;
-    }
-  }
-
-  resizable = BoolFeature(features, "resizable");
-  scrollbars_visible = BoolFeature(features, "scroll", true);
-  status_bar_visible = BoolFeature(features, "status", !kTrusted);
-}
-
-bool WindowFeatures::BoolFeature(const DialogFeaturesMap& features,
-                                 const char* key,
-                                 bool default_value) {
-  DialogFeaturesMap::const_iterator it = features.find(key);
-  if (it == features.end())
-    return default_value;
-  const String& value = it->value;
-  return value.IsNull() || value == "1" || value == "yes" || value == "on";
-}
-
-int WindowFeatures::IntFeature(const DialogFeaturesMap& features,
-                               const char* key,
-                               int min,
-                               int max,
-                               int default_value) {
-  DialogFeaturesMap::const_iterator it = features.find(key);
-  if (it == features.end())
-    return default_value;
-  bool ok;
-  int parsed_number = it->value.ToInt(&ok);
-  if (!ok)
-    return default_value;
-  if (parsed_number < min || max <= min)
-    return min;
-  if (parsed_number > max)
-    return max;
-  return parsed_number;
-}
-
-void WindowFeatures::ParseDialogFeatures(const String& string,
-                                         DialogFeaturesMap& map) {
-  Vector<String> vector;
-  string.Split(';', vector);
-  size_t size = vector.size();
-  for (size_t i = 0; i < size; ++i) {
-    const String& feature_string = vector[i];
-
-    size_t separator_position = feature_string.find('=');
-    size_t colon_position = feature_string.find(':');
-    if (separator_position != kNotFound && colon_position != kNotFound)
-      continue;  // ignore strings that have both = and :
-    if (separator_position == kNotFound)
-      separator_position = colon_position;
-
-    String key = feature_string.Left(separator_position)
-                     .StripWhiteSpace()
-                     .DeprecatedLower();
-
-    // Null string for value indicates key without value.
-    String value;
-    if (separator_position != kNotFound) {
-      value = feature_string.Substring(separator_position + 1)
-                  .StripWhiteSpace()
-                  .DeprecatedLower();
-      value = value.Left(value.find(' '));
-    }
-
-    map.Set(key, value);
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/page/WindowFeatures.h b/third_party/WebKit/Source/core/page/WindowFeatures.h
deleted file mode 100644
index 7432c94..0000000
--- a/third_party/WebKit/Source/core/page/WindowFeatures.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2003, 2007, 2010 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WindowFeatures_h
-#define WindowFeatures_h
-
-#include "core/CoreExport.h"
-#include "platform/wtf/Allocator.h"
-#include "platform/wtf/HashMap.h"
-#include "platform/wtf/text/WTFString.h"
-
-namespace blink {
-
-class IntRect;
-
-struct CORE_EXPORT WindowFeatures {
-  DISALLOW_NEW();
-  WindowFeatures()
-      : x(0),
-        x_set(false),
-        y(0),
-        y_set(false),
-        width(0),
-        width_set(false),
-        height(0),
-        height_set(false),
-        menu_bar_visible(true),
-        status_bar_visible(true),
-        tool_bar_visible(true),
-        location_bar_visible(true),
-        scrollbars_visible(true),
-        resizable(true),
-        fullscreen(false),
-        dialog(false),
-        noopener(false) {}
-  explicit WindowFeatures(const String& window_features_string);
-  WindowFeatures(const String& dialog_features_string,
-                 const IntRect& screen_available_rect);
-
-  int x;
-  bool x_set;
-  int y;
-  bool y_set;
-  int width;
-  bool width_set;
-  int height;
-  bool height_set;
-
-  bool menu_bar_visible;
-  bool status_bar_visible;
-  bool tool_bar_visible;
-  bool location_bar_visible;
-  bool scrollbars_visible;
-  bool resizable;
-
-  bool fullscreen;
-  bool dialog;
-
-  bool noopener;
-
-  Vector<String> additional_features;
-
- private:
-  using DialogFeaturesMap = HashMap<String, String>;
-  static void ParseDialogFeatures(const String&, HashMap<String, String>&);
-  static bool BoolFeature(const DialogFeaturesMap&,
-                          const char* key,
-                          bool default_value = false);
-  static int IntFeature(const DialogFeaturesMap&,
-                        const char* key,
-                        int min,
-                        int max,
-                        int default_value);
-  void SetWindowFeature(const String& key_string, const String& value_string);
-};
-
-}  // namespace blink
-
-#endif  // WindowFeatures_h
diff --git a/third_party/WebKit/Source/core/page/WindowFeaturesTest.cpp b/third_party/WebKit/Source/core/page/WindowFeaturesTest.cpp
index 40798fd0..47633aa 100644
--- a/third_party/WebKit/Source/core/page/WindowFeaturesTest.cpp
+++ b/third_party/WebKit/Source/core/page/WindowFeaturesTest.cpp
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-#include "core/page/WindowFeatures.h"
+#include "core/page/CreateWindow.h"
 
 #include <gtest/gtest.h>
 #include "platform/wtf/text/WTFString.h"
+#include "public/web/WebWindowFeatures.h"
 
 namespace blink {
 
@@ -27,8 +28,8 @@
   };
 
   for (const auto& test : kCases) {
-    WindowFeatures features(test.feature_string);
-    EXPECT_EQ(test.noopener, features.noopener)
+    EXPECT_EQ(test.noopener,
+              GetWindowFeaturesFromString(test.feature_string).noopener)
         << "Testing '" << test.feature_string << "'";
   }
 }
diff --git a/third_party/WebKit/Source/modules/plugins/DOMMimeType.cpp b/third_party/WebKit/Source/modules/plugins/DOMMimeType.cpp
index 0d75a51..eed77485 100644
--- a/third_party/WebKit/Source/modules/plugins/DOMMimeType.cpp
+++ b/third_party/WebKit/Source/modules/plugins/DOMMimeType.cpp
@@ -19,10 +19,14 @@
 
 #include "modules/plugins/DOMMimeType.h"
 
+#include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/Navigator.h"
 #include "core/loader/FrameLoader.h"
 #include "core/page/Page.h"
 #include "modules/plugins/DOMPlugin.h"
+#include "modules/plugins/DOMPluginArray.h"
+#include "modules/plugins/NavigatorPlugins.h"
 #include "platform/wtf/text/StringBuilder.h"
 
 namespace blink {
@@ -66,7 +70,8 @@
       !GetFrame()->Loader().AllowPlugins(kNotAboutToInstantiatePlugin))
     return nullptr;
 
-  return DOMPlugin::Create(GetFrame(), *mime_class_info_->Plugin());
+  return NavigatorPlugins::plugins(*GetFrame()->DomWindow()->navigator())
+      ->namedItem(AtomicString(mime_class_info_->Plugin()->Name()));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp
index 8f32b91..66d6a66cf 100644
--- a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp
+++ b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp
@@ -28,36 +28,40 @@
 
 namespace blink {
 
-DOMMimeTypeArray::DOMMimeTypeArray(LocalFrame* frame) : ContextClient(frame) {}
+DOMMimeTypeArray::DOMMimeTypeArray(LocalFrame* frame) : ContextClient(frame) {
+  UpdatePluginData();
+}
 
 DEFINE_TRACE(DOMMimeTypeArray) {
   ContextClient::Trace(visitor);
+  visitor->Trace(dom_mime_types_);
 }
 
 unsigned DOMMimeTypeArray::length() const {
-  PluginData* data = GetPluginData();
-  if (!data)
-    return 0;
-  return data->Mimes().size();
+  return dom_mime_types_.size();
 }
 
 DOMMimeType* DOMMimeTypeArray::item(unsigned index) {
-  PluginData* data = GetPluginData();
-  if (!data)
+  if (index >= dom_mime_types_.size())
     return nullptr;
-  const HeapVector<Member<MimeClassInfo>>& mimes = data->Mimes();
-  if (index >= mimes.size())
-    return nullptr;
-  return DOMMimeType::Create(GetFrame(), *mimes[index]);
+  if (!dom_mime_types_[index]) {
+    dom_mime_types_[index] =
+        DOMMimeType::Create(GetFrame(), *GetPluginData()->Mimes()[index]);
+  }
+
+  return dom_mime_types_[index];
 }
 
 DOMMimeType* DOMMimeTypeArray::namedItem(const AtomicString& property_name) {
   PluginData* data = GetPluginData();
   if (!data)
     return nullptr;
-  for (const MimeClassInfo* mime : data->Mimes()) {
-    if (mime->Type() == property_name)
-      return DOMMimeType::Create(GetFrame(), *mime);
+
+  for (const Member<MimeClassInfo>& mime : data->Mimes()) {
+    if (mime->Type() == property_name) {
+      size_t index = &mime - &data->Mimes()[0];
+      return item(index);
+    }
   }
   return nullptr;
 }
@@ -68,4 +72,28 @@
   return GetFrame()->GetPluginData();
 }
 
+void DOMMimeTypeArray::UpdatePluginData() {
+  PluginData* data = GetPluginData();
+  if (!data) {
+    dom_mime_types_.clear();
+    return;
+  }
+
+  HeapVector<Member<DOMMimeType>> old_dom_mime_types(
+      std::move(dom_mime_types_));
+  dom_mime_types_.clear();
+  dom_mime_types_.resize(data->Mimes().size());
+
+  for (Member<DOMMimeType>& mime : old_dom_mime_types) {
+    if (mime) {
+      for (const Member<MimeClassInfo>& mime_info : data->Mimes()) {
+        if (mime->type() == mime_info->Type()) {
+          size_t index = &mime_info - &data->Mimes()[0];
+          dom_mime_types_[index] = mime;
+        }
+      }
+    }
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.h b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.h
index 893c225..62a63a1 100644
--- a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.h
+++ b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.h
@@ -42,6 +42,7 @@
   static DOMMimeTypeArray* Create(LocalFrame* frame) {
     return new DOMMimeTypeArray(frame);
   }
+  void UpdatePluginData();
 
   unsigned length() const;
   DOMMimeType* item(unsigned index);
@@ -52,6 +53,8 @@
  private:
   explicit DOMMimeTypeArray(LocalFrame*);
   PluginData* GetPluginData() const;
+
+  HeapVector<Member<DOMMimeType>> dom_mime_types_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp
index b312406..3d5bcd29 100644
--- a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp
+++ b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp
@@ -20,8 +20,12 @@
 
 #include "modules/plugins/DOMPluginArray.h"
 
+#include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/Navigator.h"
 #include "core/page/Page.h"
+#include "modules/plugins/DOMMimeTypeArray.h"
+#include "modules/plugins/NavigatorPlugins.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/plugins/PluginData.h"
 #include "platform/wtf/Vector.h"
@@ -29,36 +33,40 @@
 
 namespace blink {
 
-DOMPluginArray::DOMPluginArray(LocalFrame* frame) : ContextClient(frame) {}
+DOMPluginArray::DOMPluginArray(LocalFrame* frame) : ContextClient(frame) {
+  UpdatePluginData();
+}
 
 DEFINE_TRACE(DOMPluginArray) {
   ContextClient::Trace(visitor);
+  visitor->Trace(dom_plugins_);
 }
 
 unsigned DOMPluginArray::length() const {
-  PluginData* data = GetPluginData();
-  if (!data)
-    return 0;
-  return data->Plugins().size();
+  return dom_plugins_.size();
 }
 
 DOMPlugin* DOMPluginArray::item(unsigned index) {
-  PluginData* data = GetPluginData();
-  if (!data)
+  if (index >= dom_plugins_.size())
     return nullptr;
-  const HeapVector<Member<PluginInfo>>& plugins = data->Plugins();
-  if (index >= plugins.size())
-    return nullptr;
-  return DOMPlugin::Create(GetFrame(), *plugins[index]);
+  if (!dom_plugins_[index]) {
+    dom_plugins_[index] =
+        DOMPlugin::Create(GetFrame(), *GetPluginData()->Plugins()[index]);
+  }
+
+  return dom_plugins_[index];
 }
 
 DOMPlugin* DOMPluginArray::namedItem(const AtomicString& property_name) {
   PluginData* data = GetPluginData();
   if (!data)
     return nullptr;
-  for (const PluginInfo* plugin : data->Plugins()) {
-    if (plugin->Name() == property_name)
-      return DOMPlugin::Create(GetFrame(), *plugin);
+
+  for (const Member<PluginInfo>& plugin_info : data->Plugins()) {
+    if (plugin_info->Name() == property_name) {
+      size_t index = &plugin_info - &data->Plugins()[0];
+      return item(index);
+    }
   }
   return nullptr;
 }
@@ -66,7 +74,20 @@
 void DOMPluginArray::refresh(bool reload) {
   if (!GetFrame())
     return;
+
   Page::RefreshPlugins();
+  if (PluginData* data = GetPluginData())
+    data->ResetPluginData();
+
+  for (Frame* frame = GetFrame()->GetPage()->MainFrame(); frame;
+       frame = frame->Tree().TraverseNext()) {
+    if (!frame->IsLocalFrame())
+      continue;
+    Navigator& navigator = *ToLocalFrame(frame)->DomWindow()->navigator();
+    NavigatorPlugins::plugins(navigator)->UpdatePluginData();
+    NavigatorPlugins::mimeTypes(navigator)->UpdatePluginData();
+  }
+
   if (reload) {
     GetFrame()->Reload(kFrameLoadTypeReload,
                        ClientRedirectPolicy::kClientRedirect);
@@ -79,4 +100,27 @@
   return GetFrame()->GetPluginData();
 }
 
+void DOMPluginArray::UpdatePluginData() {
+  PluginData* data = GetPluginData();
+  if (!data) {
+    dom_plugins_.clear();
+    return;
+  }
+
+  HeapVector<Member<DOMPlugin>> old_dom_plugins(std::move(dom_plugins_));
+  dom_plugins_.clear();
+  dom_plugins_.resize(data->Plugins().size());
+
+  for (Member<DOMPlugin>& plugin : old_dom_plugins) {
+    if (plugin) {
+      for (const Member<PluginInfo>& plugin_info : data->Plugins()) {
+        if (plugin->name() == plugin_info->Name()) {
+          size_t index = &plugin_info - &data->Plugins()[0];
+          dom_plugins_[index] = plugin;
+        }
+      }
+    }
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.h b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.h
index 8f8c345..6200a7c4 100644
--- a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.h
+++ b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.h
@@ -42,6 +42,7 @@
   static DOMPluginArray* Create(LocalFrame* frame) {
     return new DOMPluginArray(frame);
   }
+  void UpdatePluginData();
 
   unsigned length() const;
   DOMPlugin* item(unsigned index);
@@ -54,6 +55,8 @@
  private:
   explicit DOMPluginArray(LocalFrame*);
   PluginData* GetPluginData() const;
+
+  HeapVector<Member<DOMPlugin>> dom_plugins_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/WebMouseEvent.cpp b/third_party/WebKit/Source/platform/WebMouseEvent.cpp
index 2823b7a7..2eeb7ec 100644
--- a/third_party/WebKit/Source/platform/WebMouseEvent.cpp
+++ b/third_party/WebKit/Source/platform/WebMouseEvent.cpp
@@ -20,6 +20,8 @@
                            WebPointerProperties::PointerType::kMouse,
                            button_param),
       click_count(click_count_param) {
+  DCHECK_GE(type, kMouseTypeFirst);
+  DCHECK_LE(type, kMouseTypeLast);
   SetPositionInWidget(gesture_event.x, gesture_event.y);
   SetPositionInScreen(gesture_event.global_x, gesture_event.global_y);
   SetFrameScale(gesture_event.FrameScale());
diff --git a/third_party/WebKit/Source/platform/plugins/PluginData.cpp b/third_party/WebKit/Source/platform/plugins/PluginData.cpp
index 2511cddc..c4fb8d7 100644
--- a/third_party/WebKit/Source/platform/plugins/PluginData.cpp
+++ b/third_party/WebKit/Source/platform/plugins/PluginData.cpp
@@ -84,6 +84,7 @@
 }
 
 void PluginData::UpdatePluginList(SecurityOrigin* main_frame_origin) {
+  ResetPluginData();
   main_frame_origin_ = main_frame_origin;
   PluginListBuilder builder(&plugins_);
   Platform::Current()->GetPluginList(
@@ -93,6 +94,17 @@
     for (MimeClassInfo* mime_class_info : plugin_info->mimes_)
       mimes_.push_back(mime_class_info);
   }
+
+  std::sort(
+      plugins_.begin(), plugins_.end(),
+      [](const Member<PluginInfo>& lhs, const Member<PluginInfo>& rhs) -> bool {
+        return WTF::CodePointCompareLessThan(lhs->Name(), rhs->Name());
+      });
+  std::sort(mimes_.begin(), mimes_.end(),
+            [](const Member<MimeClassInfo>& lhs,
+               const Member<MimeClassInfo>& rhs) -> bool {
+              return WTF::CodePointCompareLessThan(lhs->Type(), rhs->Type());
+            });
 }
 
 void PluginData::ResetPluginData() {
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
index 4d45d43..37afb31 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -38,7 +38,6 @@
 #include "core/dom/Document.h"
 #include "core/dom/Fullscreen.h"
 #include "core/dom/Node.h"
-#include "core/events/UIEventWithKeyState.h"
 #include "core/events/WebInputEventConversion.h"
 #include "core/exported/WebFileChooserCompletionImpl.h"
 #include "core/exported/WebPluginContainerBase.h"
@@ -75,7 +74,6 @@
 #include "platform/Cursor.h"
 #include "platform/FileChooser.h"
 #include "platform/Histogram.h"
-#include "platform/KeyboardCodes.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/WebFrameScheduler.h"
 #include "platform/animation/CompositorAnimationHost.h"
@@ -93,7 +91,6 @@
 #include "platform/wtf/text/StringConcatenate.h"
 #include "public/platform/WebCursorInfo.h"
 #include "public/platform/WebFloatRect.h"
-#include "public/platform/WebInputEvent.h"
 #include "public/platform/WebRect.h"
 #include "public/platform/WebURLRequest.h"
 #include "public/web/WebAXObject.h"
@@ -276,116 +273,15 @@
   return !web_view_->Client() || web_view_->Client()->AcceptsLoadDrops();
 }
 
-namespace {
-
-void UpdatePolicyForEvent(const WebInputEvent* input_event,
-                          NavigationPolicy* policy) {
-  if (!input_event)
-    return;
-
-  unsigned short button_number = 0;
-  if (input_event->GetType() == WebInputEvent::kMouseUp) {
-    const WebMouseEvent* mouse_event =
-        static_cast<const WebMouseEvent*>(input_event);
-
-    switch (mouse_event->button) {
-      case WebMouseEvent::Button::kLeft:
-        button_number = 0;
-        break;
-      case WebMouseEvent::Button::kMiddle:
-        button_number = 1;
-        break;
-      case WebMouseEvent::Button::kRight:
-        button_number = 2;
-        break;
-      default:
-        return;
-    }
-  } else if ((WebInputEvent::IsKeyboardEventType(input_event->GetType()) &&
-              static_cast<const WebKeyboardEvent*>(input_event)
-                      ->windows_key_code == VKEY_RETURN) ||
-             WebInputEvent::IsGestureEventType(input_event->GetType())) {
-    // Keyboard and gesture events can simulate mouse events.
-    button_number = 0;
-  } else {
-    return;
-  }
-
-  bool ctrl = input_event->GetModifiers() & WebInputEvent::kControlKey;
-  bool shift = input_event->GetModifiers() & WebInputEvent::kShiftKey;
-  bool alt = input_event->GetModifiers() & WebInputEvent::kAltKey;
-  bool meta = input_event->GetModifiers() & WebInputEvent::kMetaKey;
-
-  NavigationPolicy user_policy = *policy;
-  NavigationPolicyFromMouseEvent(button_number, ctrl, shift, alt, meta,
-                                 &user_policy);
-
-  // When the input event suggests a download, but the navigation was initiated
-  // by script, we should not override it.
-  if (user_policy == kNavigationPolicyDownload &&
-      *policy != kNavigationPolicyIgnore)
-    return;
-
-  // User and app agree that we want a new window; let the app override the
-  // decorations.
-  if (user_policy == kNavigationPolicyNewWindow &&
-      *policy == kNavigationPolicyNewPopup)
-    return;
-  *policy = user_policy;
-}
-
-WebNavigationPolicy GetNavigationPolicy(const WindowFeatures& features) {
-  // If the window features didn't enable the toolbar, or this window wasn't
-  // created by a user gesture, show as a popup instead of a new tab.
-  //
-  // Note: this previously also checked that menubar, resizable, scrollbar, and
-  // statusbar are enabled too. When no feature string is specified, these
-  // features default to enabled (and the window opens as a new tab). However,
-  // when a feature string is specified, any *unspecified* features default to
-  // disabled, often causing the window to open as a popup instead.
-  //
-  // As specifying menubar, resizable, scrollbar, and statusbar have no effect
-  // on the UI, just ignore them and only consider whether or not the toolbar is
-  // enabled, which matches Firefox's behavior.
-  bool as_popup = !features.tool_bar_visible;
-
-  NavigationPolicy policy = kNavigationPolicyNewForegroundTab;
-  if (as_popup)
-    policy = kNavigationPolicyNewPopup;
-  UpdatePolicyForEvent(WebViewBase::CurrentInputEvent(), &policy);
-
-  return static_cast<WebNavigationPolicy>(policy);
-}
-
-WebNavigationPolicy EffectiveNavigationPolicy(
-    NavigationPolicy navigation_policy,
-    const WindowFeatures& features) {
-  WebNavigationPolicy policy =
-      static_cast<WebNavigationPolicy>(navigation_policy);
-  if (policy == kWebNavigationPolicyIgnore)
-    return GetNavigationPolicy(features);
-  if (policy == kWebNavigationPolicyNewBackgroundTab &&
-      GetNavigationPolicy(features) != kWebNavigationPolicyNewBackgroundTab &&
-      !UIEventWithKeyState::NewTabModifierSetFromIsolatedWorld())
-    return kWebNavigationPolicyNewForegroundTab;
-
-  return policy;
-}
-
-}  // namespace
-
 Page* ChromeClientImpl::CreateWindow(LocalFrame* frame,
                                      const FrameLoadRequest& r,
-                                     const WindowFeatures& features,
+                                     const WebWindowFeatures& features,
                                      NavigationPolicy navigation_policy) {
   if (!web_view_->Client())
     return nullptr;
 
   if (!frame->GetPage() || frame->GetPage()->Suspended())
     return nullptr;
-
-  WebNavigationPolicy policy =
-      EffectiveNavigationPolicy(navigation_policy, features);
   DCHECK(frame->GetDocument());
   Fullscreen::FullyExitFullscreen(*frame->GetDocument());
 
@@ -393,8 +289,8 @@
       static_cast<WebViewBase*>(web_view_->Client()->CreateView(
           WebLocalFrameImpl::FromFrame(frame),
           WrappedResourceRequest(r.GetResourceRequest()), features,
-          r.FrameName(), policy,
-          r.GetShouldSetOpener() == kNeverSetOpener || features.noopener));
+          r.FrameName(), static_cast<WebNavigationPolicy>(navigation_policy),
+          r.GetShouldSetOpener() == kNeverSetOpener));
   if (!new_view)
     return nullptr;
   return new_view->GetPage();
@@ -413,48 +309,10 @@
 }
 
 void ChromeClientImpl::Show(NavigationPolicy navigation_policy) {
-  if (web_view_->Client())
+  if (web_view_->Client()) {
     web_view_->Client()->Show(
-        EffectiveNavigationPolicy(navigation_policy, window_features_));
-}
-
-void ChromeClientImpl::SetToolbarsVisible(bool value) {
-  window_features_.tool_bar_visible = value;
-}
-
-bool ChromeClientImpl::ToolbarsVisible() {
-  return window_features_.tool_bar_visible;
-}
-
-void ChromeClientImpl::SetStatusbarVisible(bool value) {
-  window_features_.status_bar_visible = value;
-}
-
-bool ChromeClientImpl::StatusbarVisible() {
-  return window_features_.status_bar_visible;
-}
-
-void ChromeClientImpl::SetScrollbarsVisible(bool value) {
-  window_features_.scrollbars_visible = value;
-  if (WebLocalFrameImpl* web_frame =
-          ToWebLocalFrameImpl(web_view_->MainFrame()))
-    web_frame->SetCanHaveScrollbars(value);
-}
-
-bool ChromeClientImpl::ScrollbarsVisible() {
-  return window_features_.scrollbars_visible;
-}
-
-void ChromeClientImpl::SetMenubarVisible(bool value) {
-  window_features_.menu_bar_visible = value;
-}
-
-bool ChromeClientImpl::MenubarVisible() {
-  return window_features_.menu_bar_visible;
-}
-
-void ChromeClientImpl::SetResizable(bool value) {
-  window_features_.resizable = value;
+        static_cast<WebNavigationPolicy>(navigation_policy));
+  }
 }
 
 bool ChromeClientImpl::ShouldReportDetailedMessageForSource(
@@ -1091,6 +949,10 @@
     client->SetTouchAction(static_cast<TouchAction>(touch_action));
 }
 
+const WebInputEvent* ChromeClientImpl::GetCurrentInputEvent() const {
+  return WebViewBase::CurrentInputEvent();
+}
+
 bool ChromeClientImpl::RequestPointerLock(LocalFrame* frame) {
   LocalFrame& local_root = frame->LocalFrameRoot();
   return WebLocalFrameImpl::FromFrame(&local_root)
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h
index c6d9fc2..bb665831 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.h
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -34,9 +34,9 @@
 
 #include <memory>
 #include "core/page/ChromeClient.h"
-#include "core/page/WindowFeatures.h"
 #include "platform/graphics/TouchAction.h"
 #include "public/web/WebNavigationPolicy.h"
+#include "public/web/WebWindowFeatures.h"
 #include "web/WebExport.h"
 
 namespace blink {
@@ -73,22 +73,13 @@
   bool AcceptsLoadDrops() const override;
   Page* CreateWindow(LocalFrame*,
                      const FrameLoadRequest&,
-                     const WindowFeatures&,
+                     const WebWindowFeatures&,
                      NavigationPolicy) override;
   void Show(NavigationPolicy) override;
   void DidOverscroll(const FloatSize& overscroll_delta,
                      const FloatSize& accumulated_overscroll,
                      const FloatPoint& position_in_viewport,
                      const FloatSize& velocity_in_viewport) override;
-  void SetToolbarsVisible(bool) override;
-  bool ToolbarsVisible() override;
-  void SetStatusbarVisible(bool) override;
-  bool StatusbarVisible() override;
-  void SetScrollbarsVisible(bool) override;
-  bool ScrollbarsVisible() override;
-  void SetMenubarVisible(bool) override;
-  bool MenubarVisible() override;
-  void SetResizable(bool) override;
   bool ShouldReportDetailedMessageForSource(LocalFrame&,
                                             const String&) override;
   void AddMessageToConsole(LocalFrame*,
@@ -154,6 +145,7 @@
   // appropriate scroll optimizations can be chosen.
   void SetHasScrollEventHandlers(LocalFrame*, bool has_event_handlers) override;
   void SetTouchAction(LocalFrame*, TouchAction) override;
+  const WebInputEvent* GetCurrentInputEvent() const override;
 
   void AttachRootGraphicsLayer(GraphicsLayer*, LocalFrame* local_root) override;
 
@@ -253,7 +245,6 @@
   void SetCursor(const WebCursorInfo&, LocalFrame*);
 
   WebViewBase* web_view_;  // Weak pointer.
-  WindowFeatures window_features_;
   Vector<PopupOpeningObserver*> popup_opening_observers_;
   Cursor last_set_mouse_cursor_for_testing_;
   bool cursor_overridden_;
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
index 7c07259c..18f9519 100644
--- a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
+++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
@@ -59,7 +59,6 @@
 #include "core/loader/HistoryItem.h"
 #include "core/origin_trials/OriginTrials.h"
 #include "core/page/Page.h"
-#include "core/page/WindowFeatures.h"
 #include "modules/audio_output_devices/HTMLMediaElementAudioOutputDevice.h"
 #include "modules/device_orientation/DeviceMotionController.h"
 #include "modules/device_orientation/DeviceOrientationAbsoluteController.h"
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 5b5b2ada..c219bba 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -3584,7 +3584,7 @@
 }
 
 void WebViewImpl::SetWindowFeatures(const WebWindowFeatures& features) {
-  page_->GetChromeClient().SetWindowFeatures(features);
+  page_->SetWindowFeatures(features);
 }
 
 void WebViewImpl::SetOpenedByDOM() {
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h
index 8aa59e5..0d065bb6 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.h
+++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -376,9 +376,6 @@
   static const WebInputEvent* CurrentInputEvent() {
     return current_input_event_;
   }
-  void SetCurrentInputEventForTest(const WebInputEvent* event) override {
-    current_input_event_ = event;
-  }
 
   GraphicsLayer* RootGraphicsLayer() override;
   void RegisterViewportLayersWithCompositor() override;
diff --git a/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp b/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp
index 2b9b3a5..5e7e060 100644
--- a/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp
+++ b/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp
@@ -64,177 +64,6 @@
 
 }  // anonymous namespace
 
-class GetNavigationPolicyTest : public testing::Test {
- public:
-  GetNavigationPolicyTest()
-      : result_(kWebNavigationPolicyIgnore), web_view_client_(&result_) {}
-
- protected:
-  void SetUp() override {
-    web_view_ = static_cast<WebViewBase*>(
-        WebViewBase::Create(&web_view_client_, kWebPageVisibilityStateVisible));
-    web_view_->SetMainFrame(WebLocalFrame::Create(
-        WebTreeScopeType::kDocument, &web_frame_client_, nullptr, nullptr));
-    chrome_client_impl_ =
-        ToChromeClientImpl(&web_view_->GetPage()->GetChromeClient());
-    result_ = kWebNavigationPolicyIgnore;
-  }
-
-  void TearDown() override { web_view_->Close(); }
-
-  WebNavigationPolicy GetNavigationPolicyWithMouseEvent(
-      int modifiers,
-      WebMouseEvent::Button button,
-      bool as_popup) {
-    WebMouseEvent event(WebInputEvent::kMouseUp, modifiers,
-                        WebInputEvent::kTimeStampForTesting);
-    event.button = button;
-    web_view_->SetCurrentInputEventForTest(&event);
-    chrome_client_impl_->SetToolbarsVisible(!as_popup);
-    chrome_client_impl_->Show(kNavigationPolicyIgnore);
-    web_view_->SetCurrentInputEventForTest(0);
-    return result_;
-  }
-
-  bool IsNavigationPolicyPopup() {
-    chrome_client_impl_->Show(kNavigationPolicyIgnore);
-    return result_ == kWebNavigationPolicyNewPopup;
-  }
-
- protected:
-  WebNavigationPolicy result_;
-  TestWebViewClient web_view_client_;
-  WebViewBase* web_view_;
-  FrameTestHelpers::TestWebFrameClient web_frame_client_;
-  Persistent<ChromeClientImpl> chrome_client_impl_;
-};
-
-TEST_F(GetNavigationPolicyTest, LeftClick) {
-  int modifiers = 0;
-  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
-  bool as_popup = false;
-  EXPECT_EQ(kWebNavigationPolicyNewForegroundTab,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, LeftClickPopup) {
-  int modifiers = 0;
-  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
-  bool as_popup = true;
-  EXPECT_EQ(kWebNavigationPolicyNewPopup,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, ShiftLeftClick) {
-  int modifiers = WebInputEvent::kShiftKey;
-  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
-  bool as_popup = false;
-  EXPECT_EQ(kWebNavigationPolicyNewWindow,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, ShiftLeftClickPopup) {
-  int modifiers = WebInputEvent::kShiftKey;
-  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
-  bool as_popup = true;
-  EXPECT_EQ(kWebNavigationPolicyNewPopup,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, ControlOrMetaLeftClick) {
-#if OS(MACOSX)
-  int modifiers = WebInputEvent::kMetaKey;
-#else
-  int modifiers = WebInputEvent::kControlKey;
-#endif
-  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
-  bool as_popup = false;
-  EXPECT_EQ(kWebNavigationPolicyNewBackgroundTab,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, ControlOrMetaLeftClickPopup) {
-#if OS(MACOSX)
-  int modifiers = WebInputEvent::kMetaKey;
-#else
-  int modifiers = WebInputEvent::kControlKey;
-#endif
-  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
-  bool as_popup = true;
-  EXPECT_EQ(kWebNavigationPolicyNewBackgroundTab,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, ControlOrMetaAndShiftLeftClick) {
-#if OS(MACOSX)
-  int modifiers = WebInputEvent::kMetaKey;
-#else
-  int modifiers = WebInputEvent::kControlKey;
-#endif
-  modifiers |= WebInputEvent::kShiftKey;
-  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
-  bool as_popup = false;
-  EXPECT_EQ(kWebNavigationPolicyNewForegroundTab,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, ControlOrMetaAndShiftLeftClickPopup) {
-#if OS(MACOSX)
-  int modifiers = WebInputEvent::kMetaKey;
-#else
-  int modifiers = WebInputEvent::kControlKey;
-#endif
-  modifiers |= WebInputEvent::kShiftKey;
-  WebMouseEvent::Button button = WebMouseEvent::Button::kLeft;
-  bool as_popup = true;
-  EXPECT_EQ(kWebNavigationPolicyNewForegroundTab,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, MiddleClick) {
-  int modifiers = 0;
-  bool as_popup = false;
-  WebMouseEvent::Button button = WebMouseEvent::Button::kMiddle;
-  EXPECT_EQ(kWebNavigationPolicyNewBackgroundTab,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, MiddleClickPopup) {
-  int modifiers = 0;
-  bool as_popup = true;
-  WebMouseEvent::Button button = WebMouseEvent::Button::kMiddle;
-  EXPECT_EQ(kWebNavigationPolicyNewBackgroundTab,
-            GetNavigationPolicyWithMouseEvent(modifiers, button, as_popup));
-}
-
-TEST_F(GetNavigationPolicyTest, NoToolbarsForcesPopup) {
-  chrome_client_impl_->SetToolbarsVisible(false);
-  EXPECT_TRUE(IsNavigationPolicyPopup());
-  chrome_client_impl_->SetToolbarsVisible(true);
-  EXPECT_FALSE(IsNavigationPolicyPopup());
-}
-
-TEST_F(GetNavigationPolicyTest, NoStatusbarIsNotPopup) {
-  chrome_client_impl_->SetStatusbarVisible(false);
-  EXPECT_FALSE(IsNavigationPolicyPopup());
-  chrome_client_impl_->SetStatusbarVisible(true);
-  EXPECT_FALSE(IsNavigationPolicyPopup());
-}
-
-TEST_F(GetNavigationPolicyTest, NoMenubarIsNotPopup) {
-  chrome_client_impl_->SetMenubarVisible(false);
-  EXPECT_FALSE(IsNavigationPolicyPopup());
-  chrome_client_impl_->SetMenubarVisible(true);
-  EXPECT_FALSE(IsNavigationPolicyPopup());
-}
-
-TEST_F(GetNavigationPolicyTest, NotResizableIsNotPopup) {
-  chrome_client_impl_->SetResizable(false);
-  EXPECT_FALSE(IsNavigationPolicyPopup());
-  chrome_client_impl_->SetResizable(true);
-  EXPECT_FALSE(IsNavigationPolicyPopup());
-}
-
 class ViewCreatingClient : public FrameTestHelpers::TestWebViewClient {
  public:
   WebView* CreateView(WebLocalFrame* opener,
@@ -275,7 +104,7 @@
   ScopedPageSuspender suspender;
   LocalFrame* frame = ToWebLocalFrameBase(main_frame_)->GetFrame();
   FrameLoadRequest request(frame->GetDocument());
-  WindowFeatures features;
+  WebWindowFeatures features;
   EXPECT_EQ(nullptr,
             chrome_client_impl_->CreateWindow(
                 frame, request, features, kNavigationPolicyNewForegroundTab));
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
index 3febe1d6..e94f755 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
@@ -51,7 +51,7 @@
             return 1
 
         jobs = self.latest_try_jobs()
-        self._log_scheduled_jobs(jobs)
+        self._log_jobs(jobs)
         builders_with_no_jobs = self.builders_with_no_jobs(jobs)
 
         if options.trigger_jobs and builders_with_no_jobs:
@@ -63,8 +63,7 @@
         builders_without_results = set(self._try_bots()) - builders_with_results
         if builders_without_results:
             _log.info('There are some builders with no results:')
-            for builder in sorted(builders_without_results):
-                _log.info('  %s', builder)
+            self._log_builder_list(builders_without_results)
 
         if not options.fill_missing and builders_without_results:
             options.fill_missing = self._tool.user.confirm(
@@ -139,24 +138,25 @@
         """Returns the set of builders that don't have triggered builds."""
         return set(self._try_bots()) - {b.builder_name for b in builds}
 
-    def _log_scheduled_jobs(self, builds):
-        builders = self._builders_with_scheduled_jobs(builds)
-        if not builders:
-            return
-        _log.info('There are scheduled (but not yet started) builds for:')
+    def _log_jobs(self, jobs):
+        scheduled = {b.builder_name for b, s in jobs.items() if s.status == 'SCHEDULED'}
+        if scheduled:
+            _log.info('Builders with scheduled builds:')
+            self._log_builder_list(scheduled)
+        started = {b.builder_name for b, s in jobs.items() if s.status == 'STARTED'}
+        if started:
+            _log.info('Builders with started builds:')
+            self._log_builder_list(started)
+
+    def _log_builder_list(self, builders):
         for builder in sorted(builders):
             _log.info('  %s', builder)
 
-    def _builders_with_scheduled_jobs(self, builds):
-        """Returns the set of builders that have scheduled builds
-        that have not yet started."""
-        return {b.builder_name for b in builds if b.build_number is None}
-
     def _try_bots(self):
         """Returns a collection of try bot builders to fetch results for."""
         return self._tool.builders.all_try_builder_names()
 
-    def _fetch_results(self, builds):
+    def _fetch_results(self, jobs):
         """Fetches results for all of the given builds.
 
         There should be a one-to-one correspondence between Builds, supported
@@ -166,7 +166,7 @@
         that's missing results.
 
         Args:
-            builds: A list of Build objects.
+            jobs: A dict mapping Build objects to TryJobStatus objects.
 
         Returns:
             A dict mapping Build to LayoutTestResults, or None if any results
@@ -174,7 +174,7 @@
         """
         buildbot = self._tool.buildbot
         results = {}
-        for build in builds:
+        for build, _ in jobs.iteritems():
             results_url = buildbot.results_url(build.builder_name, build.build_number)
             layout_test_results = buildbot.fetch_results(build)
             if layout_test_results is None:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
index b2a4b67..c0f12395 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
@@ -7,6 +7,7 @@
 
 from webkitpy.common.net.buildbot import Build
 from webkitpy.common.net.git_cl import GitCL
+from webkitpy.common.net.git_cl import TryJobStatus
 from webkitpy.common.checkout.git_mock import MockGit
 from webkitpy.common.net.layout_test_results import LayoutTestResults
 from webkitpy.common.system.log_testing import LoggingTestCase
@@ -23,11 +24,11 @@
         BaseTestCase.setUp(self)
         LoggingTestCase.setUp(self)
 
-        builds = [
-            Build('MOCK Try Win', 5000),
-            Build('MOCK Try Mac', 4000),
-            Build('MOCK Try Linux', 6000),
-        ]
+        builds = {
+            Build('MOCK Try Win', 5000): TryJobStatus('COMPLETED', 'FAILURE'),
+            Build('MOCK Try Mac', 4000): TryJobStatus('COMPLETED', 'FAILURE'),
+            Build('MOCK Try Linux', 6000): TryJobStatus('COMPLETED', 'FAILURE'),
+        }
 
         git_cl = GitCL(self.tool)
         git_cl.get_issue_number = lambda: '11112222'
@@ -148,11 +149,11 @@
     def test_execute_with_flaky_test_that_fails_on_retry(self):
         # In this example, one test failed both with and without the patch
         # in the try job, so it is not rebaselined.
-        builds = [
-            Build('MOCK Try Win', 5000),
-            Build('MOCK Try Mac', 4000),
-            Build('MOCK Try Linux', 6000),
-        ]
+        builds = {
+            Build('MOCK Try Win', 5000): TryJobStatus('COMPLETED', 'FAILURE'),
+            Build('MOCK Try Mac', 4000): TryJobStatus('COMPLETED', 'FAILURE'),
+            Build('MOCK Try Linux', 6000): TryJobStatus('COMPLETED', 'FAILURE'),
+        }
         for build in builds:
             self.tool.buildbot.set_retry_sumary_json(build, json.dumps({
                 'failures': ['one/text-fail.html'],
@@ -183,10 +184,10 @@
         ])
 
     def test_execute_with_trigger_jobs_option(self):
-        builds = [
-            Build('MOCK Try Win', 5000),
-            Build('MOCK Try Mac', 4000),
-        ]
+        builds = {
+            Build('MOCK Try Win', 5000): TryJobStatus('COMPLETED', 'FAILURE'),
+            Build('MOCK Try Mac', 4000): TryJobStatus('COMPLETED', 'FAILURE'),
+        }
         git_cl = GitCL(self.tool)
         git_cl.get_issue_number = lambda: '11112222'
         git_cl.latest_try_jobs = lambda _: builds
@@ -201,10 +202,10 @@
         ])
 
     def test_execute_with_no_trigger_jobs_option(self):
-        builds = [
-            Build('MOCK Try Win', 5000),
-            Build('MOCK Try Mac', 4000),
-        ]
+        builds = {
+            Build('MOCK Try Win', 5000): TryJobStatus('COMPLETED', 'FAILURE'),
+            Build('MOCK Try Mac', 4000): TryJobStatus('COMPLETED', 'FAILURE'),
+        }
         git_cl = GitCL(self.tool)
         git_cl.get_issue_number = lambda: '11112222'
         git_cl.latest_try_jobs = lambda _: builds
@@ -273,19 +274,15 @@
             'webkit-patch rebaseline-cl to fetch new baselines.\n',
         ])
 
-    def test_builders_with_scheduled_jobs(self):
-        # Test for protected method - pylint: disable=protected-access
-        builds = [Build('MOCK Try Linux', None), Build('MOCK Try Win', 123)]
-        self.assertEqual(
-            self.command._builders_with_scheduled_jobs(builds),
-            {'MOCK Try Linux'})
-
     def test_builders_with_no_jobs(self):
-        # In this example, Linux has a scheduled but not started build, Win has
-        # a started or finished build, and Mac has no triggered build.
-        # MOCK Try Mac is listed because it's listed in the BuilderList in setUp.
+        # In this example, Linux has a scheduled but not started build,
+        # and Mac has no triggered build.
         # Test for protected method - pylint: disable=protected-access
-        builds = [Build('MOCK Try Linux', None), Build('MOCK Try Win', 123)]
+        builds = {
+            Build('MOCK Try Linux', None): TryJobStatus('SCHEDULED'),
+            Build('MOCK Try Win', 123): TryJobStatus('STARTED'),
+        }
+        # MOCK Try Mac is here because it's listed in the BuilderList in setUp.
         self.assertEqual(self.command.builders_with_no_jobs(builds), {'MOCK Try Mac'})
 
     def test_bails_when_one_build_is_missing_results(self):
diff --git a/third_party/WebKit/public/platform/WebMouseEvent.h b/third_party/WebKit/public/platform/WebMouseEvent.h
index c2a0095..35fd516 100644
--- a/third_party/WebKit/public/platform/WebMouseEvent.h
+++ b/third_party/WebKit/public/platform/WebMouseEvent.h
@@ -41,7 +41,10 @@
                              PointerType::kUnknown,
                              Button::kNoButton,
                              WebFloatPoint(x_param, y_param),
-                             WebFloatPoint(global_x_param, global_y_param)) {}
+                             WebFloatPoint(global_x_param, global_y_param)) {
+    DCHECK_GE(type_param, kMouseTypeFirst);
+    DCHECK_LE(type_param, kMouseTypeLast);
+  }
 
   WebMouseEvent(Type type_param,
                 WebFloatPoint position,
@@ -61,7 +64,10 @@
             button_param,
             WebFloatPoint(floor(position.x), floor(position.y)),
             WebFloatPoint(floor(global_position.x), floor(global_position.y))),
-        click_count(click_count_param) {}
+        click_count(click_count_param) {
+    DCHECK_GE(type_param, kMouseTypeFirst);
+    DCHECK_LE(type_param, kMouseTypeLast);
+  }
 
   WebMouseEvent(Type type_param,
                 int modifiers_param,
diff --git a/third_party/WebKit/public/web/WebWindowFeatures.h b/third_party/WebKit/public/web/WebWindowFeatures.h
index f4ede78..fdb6b0d 100644
--- a/third_party/WebKit/public/web/WebWindowFeatures.h
+++ b/third_party/WebKit/public/web/WebWindowFeatures.h
@@ -31,98 +31,28 @@
 #ifndef WebWindowFeatures_h
 #define WebWindowFeatures_h
 
-#include "public/platform/WebCommon.h"
-#include "public/platform/WebString.h"
-#include "public/platform/WebVector.h"
-
-#if BLINK_IMPLEMENTATION
-#include "core/page/WindowFeatures.h"
-#endif
-
 namespace blink {
 
 struct WebWindowFeatures {
-  float x;
-  bool x_set;
-  float y;
-  bool y_set;
-  float width;
-  bool width_set;
-  float height;
-  bool height_set;
+  float x = 0;
+  bool x_set = false;
+  float y = 0;
+  bool y_set = false;
+  float width = 0;
+  bool width_set = false;
+  float height = 0;
+  bool height_set = false;
 
-  bool menu_bar_visible;
-  bool status_bar_visible;
-  bool tool_bar_visible;
-  bool location_bar_visible;
-  bool scrollbars_visible;
-  bool resizable;
+  bool menu_bar_visible = true;
+  bool status_bar_visible = true;
+  // This can be set based on "locationbar" or "toolbar" in a window features
+  // string, we don't distinguish between the two.
+  bool tool_bar_visible = true;
+  bool scrollbars_visible = true;
 
-  bool fullscreen;
-  bool dialog;
-  WebVector<WebString> additional_features;
-
-  WebWindowFeatures()
-      : x(0),
-        x_set(false),
-        y(0),
-        y_set(false),
-        width(0),
-        width_set(false),
-        height(0),
-        height_set(false),
-        menu_bar_visible(true),
-        status_bar_visible(true),
-        tool_bar_visible(true),
-        location_bar_visible(true),
-        scrollbars_visible(true),
-        resizable(true),
-        fullscreen(false),
-        dialog(false) {}
-
-#if BLINK_IMPLEMENTATION
-  WebWindowFeatures(const WindowFeatures& f)
-      : x(f.x),
-        x_set(f.x_set),
-        y(f.y),
-        y_set(f.y_set),
-        width(f.width),
-        width_set(f.width_set),
-        height(f.height),
-        height_set(f.height_set),
-        menu_bar_visible(f.menu_bar_visible),
-        status_bar_visible(f.status_bar_visible),
-        tool_bar_visible(f.tool_bar_visible),
-        location_bar_visible(f.location_bar_visible),
-        scrollbars_visible(f.scrollbars_visible),
-        resizable(f.resizable),
-        fullscreen(f.fullscreen),
-        dialog(f.dialog),
-        additional_features(f.additional_features) {}
-
-  operator WindowFeatures() const {
-    WindowFeatures result;
-    result.x = x;
-    result.x_set = x_set;
-    result.y = y;
-    result.y_set = y_set;
-    result.width = width;
-    result.width_set = width_set;
-    result.height = height;
-    result.height_set = height_set;
-    result.menu_bar_visible = menu_bar_visible;
-    result.status_bar_visible = status_bar_visible;
-    result.tool_bar_visible = tool_bar_visible;
-    result.location_bar_visible = location_bar_visible;
-    result.scrollbars_visible = scrollbars_visible;
-    result.resizable = resizable;
-    result.fullscreen = fullscreen;
-    result.dialog = dialog;
-    for (size_t i = 0; i < additional_features.size(); ++i)
-      result.additional_features.push_back(additional_features[i]);
-    return result;
-  }
-#endif
+  bool noopener = false;
+  bool background = false;
+  bool persistent = false;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/web/window_features.mojom b/third_party/WebKit/public/web/window_features.mojom
index a26b8a3b4..dac13c38 100644
--- a/third_party/WebKit/public/web/window_features.mojom
+++ b/third_party/WebKit/public/web/window_features.mojom
@@ -20,14 +20,5 @@
     bool menu_bar_visible = true;
     bool status_bar_visible = true;
     bool tool_bar_visible = true;
-    bool location_bar_visible = true;
     bool scrollbars_visible = true;
-    bool resizable = true;
-
-    bool fullscreen = false;
-    bool dialog = false;
-
-    // NOTE: WebWindowFeatures::additionalFeatures is not mirrored by this
-    // mojom struct as it's never used by the browser and therefore doesn't need
-    // to be sent.
 };
diff --git a/third_party/closure_compiler/OWNERS b/third_party/closure_compiler/OWNERS
index 7eae7d6c..6f005f1 100644
--- a/third_party/closure_compiler/OWNERS
+++ b/third_party/closure_compiler/OWNERS
@@ -1,3 +1,4 @@
 dbeam@chromium.org
+dpapad@chromium.org
 fukino@chromium.org
 tbreisacher@chromium.org
diff --git a/third_party/jstemplate/OWNERS b/third_party/jstemplate/OWNERS
deleted file mode 100644
index cba869d..0000000
--- a/third_party/jstemplate/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-dbeam@chromium.org
diff --git a/ui/base/win/shell.cc b/ui/base/win/shell.cc
index 0cace9b..dd8459e 100644
--- a/ui/base/win/shell.cc
+++ b/ui/base/win/shell.cc
@@ -19,7 +19,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/win_util.h"
-#include "base/win/windows_version.h"
 #include "ui/base/ui_base_switches.h"
 
 namespace ui {
@@ -99,10 +98,6 @@
 bool PreventWindowFromPinning(HWND hwnd) {
   DCHECK(hwnd);
 
-  // This functionality is only available on Win7+.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return false;
-
   base::win::ScopedComPtr<IPropertyStore> pps;
   if (FAILED(
           SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(pps.GetAddressOf()))))
@@ -122,10 +117,6 @@
                             HWND hwnd) {
   DCHECK(hwnd);
 
-  // This functionality is only available on Win7+.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::win::ScopedComPtr<IPropertyStore> pps;
   if (FAILED(
           SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(pps.GetAddressOf()))))
@@ -176,10 +167,6 @@
 void ClearWindowPropertyStore(HWND hwnd) {
   DCHECK(hwnd);
 
-  // This functionality is only available on Win7+.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   base::win::ScopedComPtr<IPropertyStore> pps;
   if (FAILED(
           SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(pps.GetAddressOf()))))
@@ -208,10 +195,6 @@
           switches::kDisableDwmComposition))
     return false;
 
-  // Technically Aero glass works in Vista but we want to put XP and Vista
-  // at the same feature level. See bug 426573.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return false;
   // If composition is not enabled, we behave like on XP.
   BOOL enabled = FALSE;
   return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled;
diff --git a/ui/events/blink/web_input_event_builders_win_unittest.cc b/ui/events/blink/web_input_event_builders_win_unittest.cc
index f0a69e6..61837d0 100644
--- a/ui/events/blink/web_input_event_builders_win_unittest.cc
+++ b/ui/events/blink/web_input_event_builders_win_unittest.cc
@@ -20,9 +20,6 @@
 // This test validates that Pixel to DIP conversion occurs as needed in the
 // WebMouseEventBuilder::Build function.
 TEST(WebInputEventBuilderTest, TestMouseEventScale) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN7)
-    return;
-
   display::Display::ResetForceDeviceScaleFactorForTesting();
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/ui/gl/vsync_provider_win.cc b/ui/gl/vsync_provider_win.cc
index 7a400e2..8025ca9 100644
--- a/ui/gl/vsync_provider_win.cc
+++ b/ui/gl/vsync_provider_win.cc
@@ -8,15 +8,10 @@
 
 #include "base/logging.h"
 #include "base/trace_event/trace_event.h"
-#include "base/win/windows_version.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace gl {
 
-namespace {
-bool g_use_dwm_vsync;
-}  // namespace
-
 VSyncProviderWin::VSyncProviderWin(gfx::AcceleratedWidget window)
     : window_(window) {
 }
@@ -29,12 +24,9 @@
   if (initialized)
     return;
   initialized = true;
-  g_use_dwm_vsync = (base::win::GetVersion() >= base::win::VERSION_WIN7);
 
-  if (g_use_dwm_vsync) {
-    // Prewarm sandbox
-    ::LoadLibrary(L"dwmapi.dll");
-  }
+  // Prewarm sandbox
+  ::LoadLibrary(L"dwmapi.dll");
 }
 
 void VSyncProviderWin::GetVSyncParameters(const UpdateVSyncCallback& callback) {
@@ -42,61 +34,54 @@
 
   base::TimeTicks timebase;
   base::TimeDelta interval;
-  bool dwm_active = false;
 
   // Query the DWM timing info first if available. This will provide the most
   // precise values.
-  if (g_use_dwm_vsync) {
-    DWM_TIMING_INFO timing_info;
-    timing_info.cbSize = sizeof(timing_info);
-    HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
-    if (result == S_OK) {
-      dwm_active = true;
+  DWM_TIMING_INFO timing_info;
+  timing_info.cbSize = sizeof(timing_info);
+  HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
+  if (result == S_OK) {
+    // Calculate an interval value using the rateRefresh numerator and
+    // denominator.
+    base::TimeDelta rate_interval;
+    if (timing_info.rateRefresh.uiDenominator > 0 &&
+        timing_info.rateRefresh.uiNumerator > 0) {
+      // Swap the numerator/denominator to convert frequency to period.
+      rate_interval = base::TimeDelta::FromMicroseconds(
+          timing_info.rateRefresh.uiDenominator *
+          base::Time::kMicrosecondsPerSecond /
+          timing_info.rateRefresh.uiNumerator);
+    }
 
-      // Calculate an interval value using the rateRefresh numerator and
-      // denominator.
-      base::TimeDelta rate_interval;
-      if (timing_info.rateRefresh.uiDenominator > 0 &&
-          timing_info.rateRefresh.uiNumerator > 0) {
-        // Swap the numerator/denominator to convert frequency to period.
-        rate_interval = base::TimeDelta::FromMicroseconds(
-            timing_info.rateRefresh.uiDenominator *
-            base::Time::kMicrosecondsPerSecond /
-            timing_info.rateRefresh.uiNumerator);
-      }
-
-      if (base::TimeTicks::IsHighResolution()) {
-        // qpcRefreshPeriod is very accurate but noisy, and must be used with
-        // a high resolution timebase to avoid frequently missing Vsync.
-        timebase = base::TimeTicks::FromQPCValue(
-            static_cast<LONGLONG>(timing_info.qpcVBlank));
-        interval = base::TimeDelta::FromQPCValue(
-            static_cast<LONGLONG>(timing_info.qpcRefreshPeriod));
-        // Check for interval values that are impossibly low. A 29 microsecond
-        // interval was seen (from a qpcRefreshPeriod of 60).
-        if (interval < base::TimeDelta::FromMilliseconds(1)) {
-          interval = rate_interval;
-        }
-        // Check for the qpcRefreshPeriod interval being improbably small
-        // compared to the rateRefresh calculated interval, as another
-        // attempt at detecting driver bugs.
-        if (!rate_interval.is_zero() && interval < rate_interval / 2) {
-          interval = rate_interval;
-        }
-      } else {
-        // If FrameTime is not high resolution, we do not want to translate
-        // the QPC value provided by DWM into the low-resolution timebase,
-        // which would be error prone and jittery. As a fallback, we assume
-        // the timebase is zero and use rateRefresh, which may be rounded but
-        // isn't noisy like qpcRefreshPeriod, instead. The fact that we don't
-        // have a timebase here may lead to brief periods of jank when our
-        // scheduling becomes offset from the hardware vsync.
+    if (base::TimeTicks::IsHighResolution()) {
+      // qpcRefreshPeriod is very accurate but noisy, and must be used with
+      // a high resolution timebase to avoid frequently missing Vsync.
+      timebase = base::TimeTicks::FromQPCValue(
+          static_cast<LONGLONG>(timing_info.qpcVBlank));
+      interval = base::TimeDelta::FromQPCValue(
+          static_cast<LONGLONG>(timing_info.qpcRefreshPeriod));
+      // Check for interval values that are impossibly low. A 29 microsecond
+      // interval was seen (from a qpcRefreshPeriod of 60).
+      if (interval < base::TimeDelta::FromMilliseconds(1)) {
         interval = rate_interval;
       }
+      // Check for the qpcRefreshPeriod interval being improbably small
+      // compared to the rateRefresh calculated interval, as another
+      // attempt at detecting driver bugs.
+      if (!rate_interval.is_zero() && interval < rate_interval / 2) {
+        interval = rate_interval;
+      }
+    } else {
+      // If FrameTime is not high resolution, we do not want to translate
+      // the QPC value provided by DWM into the low-resolution timebase,
+      // which would be error prone and jittery. As a fallback, we assume
+      // the timebase is zero and use rateRefresh, which may be rounded but
+      // isn't noisy like qpcRefreshPeriod, instead. The fact that we don't
+      // have a timebase here may lead to brief periods of jank when our
+      // scheduling becomes offset from the hardware vsync.
+      interval = rate_interval;
     }
-  }
-
-  if (!dwm_active) {
+  } else {
     // When DWM compositing is active all displays are normalized to the
     // refresh rate of the primary display, and won't composite any faster.
     // If DWM compositing is disabled, though, we can use the refresh rates
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index b1f2574c..09c44ee 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -364,11 +364,18 @@
       if (!view_for_activation) {
         view_for_activation = GetWidget()->GetRootView();
       } else if (view_for_activation == focus_manager->GetStoredFocusView()) {
-        focus_manager->RestoreFocusedView();
-        // Set to false if desktop native widget has activated activation
-        // change, so that aura window activation change focus restore operation
-        // can be ignored.
-        restore_focus_on_activate_ = false;
+        // When desktop native widget has modal transient child, we don't
+        // restore focused view here, as the modal transient child window will
+        // get activated and focused. Thus, we are not left with multiple
+        // focuses. For aura child widgets, since their views are managed by
+        // |focus_manager|, we then allow restoring focused view.
+        if (!wm::GetModalTransient(GetWidget()->GetNativeView())) {
+          focus_manager->RestoreFocusedView();
+          // Set to false if desktop native widget has activated activation
+          // change, so that aura window activation change focus restore
+          // operation can be ignored.
+          restore_focus_on_activate_ = false;
+        }
       }
       activation_client->ActivateWindow(
           view_for_activation->GetWidget()->GetNativeView());
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc
index a1e82b4..0e20f33 100644
--- a/ui/views/widget/widget_interactive_uitest.cc
+++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -1271,6 +1271,52 @@
   widget->CloseNow();
 }
 
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+// Tests that when a desktop native widget has modal transient child, it should
+// avoid restore focused view itself as the modal transient child window will do
+// that, thus avoids having multiple focused view visually (crbug.com/727641).
+TEST_F(WidgetTestInteractive, DesktopNativeWidgetWithModalTransientChild) {
+  // Create a top level desktop native widget.
+  Widget* top_level = CreateWidget();
+
+  Textfield* textfield = new Textfield;
+  textfield->SetBounds(0, 0, 200, 20);
+  top_level->GetRootView()->AddChildView(textfield);
+  ShowSync(top_level);
+  textfield->RequestFocus();
+  EXPECT_TRUE(textfield->HasFocus());
+
+  // Create a modal dialog.
+  // This instance will be destroyed when the dialog is destroyed.
+  ModalDialogDelegate* dialog_delegate =
+      new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW);
+  Widget* modal_dialog_widget = DialogDelegate::CreateDialogWidget(
+      dialog_delegate, nullptr, top_level->GetNativeView());
+  modal_dialog_widget->SetBounds(gfx::Rect(0, 0, 100, 10));
+  Textfield* dialog_textfield = new Textfield;
+  dialog_textfield->SetBounds(0, 0, 50, 5);
+  modal_dialog_widget->GetRootView()->AddChildView(dialog_textfield);
+  // Dialog widget doesn't need a ShowSync as it gains active status
+  // synchronously.
+  modal_dialog_widget->Show();
+  dialog_textfield->RequestFocus();
+  EXPECT_TRUE(dialog_textfield->HasFocus());
+  EXPECT_FALSE(textfield->HasFocus());
+
+  DeactivateSync(top_level);
+  EXPECT_FALSE(dialog_textfield->HasFocus());
+  EXPECT_FALSE(textfield->HasFocus());
+
+  // After deactivation and activation of top level widget, only modal dialog
+  // should restore focused view.
+  ActivateSync(top_level);
+  EXPECT_TRUE(dialog_textfield->HasFocus());
+  EXPECT_FALSE(textfield->HasFocus());
+
+  top_level->CloseNow();
+}
+#endif  // defined(USE_AURA) && !defined(OS_CHROMEOS)
+
 namespace {
 
 // Helper class for CaptureLostTrackingWidget to store whether
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 3c67457..4f9ad05 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -1658,8 +1658,8 @@
 LRESULT HWNDMessageHandler::OnPointerEvent(UINT message,
                                            WPARAM w_param,
                                            LPARAM l_param) {
-  // WM_POINTER is not supported on Windows 7 or lower.
-  if (base::win::GetVersion() <= base::win::VERSION_WIN7) {
+  // WM_POINTER is not supported on Windows 7.
+  if (base::win::GetVersion() == base::win::VERSION_WIN7) {
     SetMsgHandled(FALSE);
     return -1;
   }