diff --git a/AUTHORS b/AUTHORS
index 751d0a4..f0fbef00 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -21,6 +21,7 @@
 Adam Kallai <kadam@inf.u-szeged.hu>
 Adam Roben <adam@github.com>
 Adam Treat <adam.treat@samsung.com>
+Adam Yi <i@adamyi.com>
 Addanki Gandhi Kishor <kishor.ag@samsung.com>
 Adenilson Cavalcanti <a.cavalcanti@samsung.com>
 Aditya Bhargava <heuristicist@gmail.com>
diff --git a/DEPS b/DEPS
index d8fc42e..18ded5f8 100644
--- a/DEPS
+++ b/DEPS
@@ -116,11 +116,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd029c0e837343238f7dde2e64cbe42fab4b9ffbb',
+  'skia_revision': '7e4081554d066e07a18121aabdb2ab345ed1a280',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '041083534e527dca939286b06d6b2e82ffbb954a',
+  'v8_revision': '35240cdb67759342f73809bc1400943addb331fb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -128,7 +128,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '6ba22ee1376836e2bae478448770882b72be4b06',
+  'angle_revision': '37297a4f14406f49031b6855d2d8fa7ad881fd1b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -176,7 +176,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '468ff3e5a03038c57a1a300e373f88e47dea2692',
+  'catapult_revision': '8c035b35abf8db181ae20d6e3a1f0e4c30c9f489',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -680,7 +680,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'fec80c41355c59f356229dc223808d5c22c87a47',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '7e0b0c498a5c85c2ba2aaf524ac71cc28627e1bb',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1009,7 +1009,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '5af3a96bfa9fd7fa77b2209115b3ec4e600e121e',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'c7000ce0e554e3a9387dbb1e359cebb433e9c42f',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1161,7 +1161,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '0d55c887e92b645f6effe753528323ab2ffd94c2',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '0367d1a1fb0a74ddb0e256625c48107648675885',
+    Var('webrtc_git') + '/src.git' + '@' + '671341ac666920287b63008dc15ffceb7febb5da',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1192,7 +1192,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@48a5c18d49cebc9d1690149df5d11ce7c98446c2',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f900879ca7b23a68e3698312f946a9c0ff9b699e',
     'condition': 'checkout_src_internal',
   },
 
@@ -2450,19 +2450,6 @@
                 '-d', 'src/components/zucchini',
     ],
   },
-
-  {
-    # We used to use src as a CIPD root. We moved it to a different directory
-    # in crrev.com/c/930178 but left the clobber here to ensure that that CL
-    # could be reverted safely. This can be safely removed once crbug.com/794764
-    # is resolved.
-    'name': 'Android Clobber Deprecated CIPD Root',
-    'pattern': '.',
-    'condition': 'checkout_android',
-    'action': ['src/build/cipd/clobber_cipd_root.py',
-               '--root', 'src',
-    ],
-  },
   {
     'name': 'Fetch Android AFDO profile',
     'pattern': '.',
diff --git a/android_webview/browser/aw_feature_list.cc b/android_webview/browser/aw_feature_list.cc
index 23e1c04..b49f524 100644
--- a/android_webview/browser/aw_feature_list.cc
+++ b/android_webview/browser/aw_feature_list.cc
@@ -47,6 +47,10 @@
 const base::Feature kWebViewConnectionlessSafeBrowsing{
     "WebViewConnectionlessSafeBrowsing", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Whether the application package name is logged in UMA.
+const base::Feature kWebViewUmaLogAppPackageName{
+    "WebViewUmaLogAppPackageName", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 
 static jboolean JNI_AwFeatureList_IsEnabled(
diff --git a/android_webview/browser/aw_feature_list.h b/android_webview/browser/aw_feature_list.h
index def7cff..aaa60eb 100644
--- a/android_webview/browser/aw_feature_list.h
+++ b/android_webview/browser/aw_feature_list.h
@@ -15,6 +15,7 @@
 
 // Alphabetical:
 extern const base::Feature kWebViewConnectionlessSafeBrowsing;
+extern const base::Feature kWebViewUmaLogAppPackageName;
 
 }  // namespace features
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc
index b501570..70d1371 100644
--- a/android_webview/browser/aw_metrics_service_client.cc
+++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 #include <vector>
 
+#include "android_webview/browser/aw_feature_list.h"
 #include "android_webview/browser/aw_metrics_log_uploader.h"
 #include "android_webview/common/aw_switches.h"
 #include "android_webview/jni/AwMetricsServiceClient_jni.h"
@@ -268,6 +269,16 @@
   return base::TimeDelta::FromMinutes(kUploadIntervalMinutes);
 }
 
+std::string AwMetricsServiceClient::GetAppPackageName() {
+  if (!base::FeatureList::IsEnabled(features::kWebViewUmaLogAppPackageName))
+    return std::string();
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jstring> j_app_name =
+      Java_AwMetricsServiceClient_getAppPackageName(env);
+  return ConvertJavaStringToUTF8(env, j_app_name);
+}
+
 AwMetricsServiceClient::AwMetricsServiceClient()
     : pref_service_(nullptr),
       consent_(false),
diff --git a/android_webview/browser/aw_metrics_service_client.h b/android_webview/browser/aw_metrics_service_client.h
index d9dfeef..f9a33b4f9 100644
--- a/android_webview/browser/aw_metrics_service_client.h
+++ b/android_webview/browser/aw_metrics_service_client.h
@@ -78,6 +78,7 @@
       const metrics::MetricsLogUploader::UploadCallback& on_upload_complete)
       override;
   base::TimeDelta GetStandardUploadInterval() override;
+  std::string GetAppPackageName() override;
 
  private:
   AwMetricsServiceClient();
diff --git a/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java b/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java
index 9dc76aa..4ee4cbf 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java
@@ -8,6 +8,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
@@ -84,5 +85,10 @@
         }
     }
 
+    @CalledByNative
+    private static String getAppPackageName() {
+        return ContextUtils.getApplicationContext().getPackageName();
+    }
+
     public static native void nativeSetHaveMetricsConsent(boolean enabled);
 }
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn
index 260da88..f19efa84 100644
--- a/ash/app_list/BUILD.gn
+++ b/ash/app_list/BUILD.gn
@@ -110,6 +110,7 @@
     "//components/keyed_service/core",
     "//components/sync",
     "//mojo/public/cpp/bindings",
+    "//services/content/public/cpp",
     "//services/ws/public/cpp",
     "//services/ws/public/mojom",
     "//services/ws/remote_view_host",
@@ -137,11 +138,14 @@
   public_deps = [
     "//ash/app_list/model:app_list_model",
     "//ash/app_list/model:search_model",
-    "//ash/public/cpp:cpp",
+    "//ash/public/cpp",
+    "//services/content/public/mojom",
   ]
 }
 
 static_library("test_support") {
+  testonly = true
+
   sources = [
     "test/app_list_test_model.cc",
     "test/app_list_test_model.h",
@@ -156,6 +160,7 @@
   deps = [
     ":app_list",
     "//base",
+    "//services/content/public/cpp/test:test_support",
     "//ui/base:base",
     "//ui/events",
     "//ui/gfx",
@@ -215,6 +220,10 @@
     "//base",
     "//base/test:test_support",
     "//mojo/core/embedder",
+    "//mojo/public/cpp/bindings",
+    "//services/content/public/cpp",
+    "//services/content/public/cpp/test:test_support",
+    "//services/content/public/mojom",
     "//skia",
     "//testing/gtest",
     "//ui/accessibility",
diff --git a/ash/app_list/DEPS b/ash/app_list/DEPS
index 5bb4d79d..f6dc209 100644
--- a/ash/app_list/DEPS
+++ b/ash/app_list/DEPS
@@ -3,6 +3,7 @@
   "+components/keyed_service/core",
   "+components/sync",
   "+mojo/public/cpp",
+  "+net/http/http_response_headers.h",
   "+services/ws/public",
   "+skia",
   "+third_party/google_toolbox_for_mac/src",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 68f10ea..f55ce09 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -40,15 +40,18 @@
 
 namespace ash {
 
-AppListControllerImpl::AppListControllerImpl(ws::WindowService* window_service)
-    : window_service_(window_service),
-      presenter_(std::make_unique<AppListPresenterDelegateImpl>(this)),
+AppListControllerImpl::AppListControllerImpl()
+    : presenter_(std::make_unique<AppListPresenterDelegateImpl>(this)),
       is_home_launcher_enabled_(app_list_features::IsHomeLauncherEnabled()),
       voice_interaction_binding_(this) {
   model_.AddObserver(this);
 
   // Create only for non-mash. Mash uses window tree embed API to get a
   // token to map answer card contents.
+  //
+  // TODO(https://crbug.com/894987): This is now only used (as a singleton) by
+  // assistant UI code to display its answer card contents. It can be removed
+  // once that code is ported to use Content Service.
   if (!::features::IsUsingWindowService()) {
     answer_card_contents_registry_ =
         std::make_unique<app_list::AnswerCardContentsRegistry>();
@@ -831,8 +834,10 @@
          HomeLauncherGestureHandler::Mode::kSlideUpToShow;
 }
 
-ws::WindowService* AppListControllerImpl::GetWindowService() {
-  return window_service_;
+void AppListControllerImpl::GetNavigableContentsFactory(
+    content::mojom::NavigableContentsFactoryRequest request) {
+  if (client_)
+    client_->GetNavigableContentsFactory(std::move(request));
 }
 
 void AppListControllerImpl::OnVisibilityChanged(bool visible) {
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 366ca00..732e5441 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -37,10 +37,6 @@
 class MouseWheelEvent;
 }  // namespace ui
 
-namespace ws {
-class WindowService;
-}  // namespace ws
-
 namespace ash {
 
 class HomeLauncherGestureHandler;
@@ -61,7 +57,7 @@
  public:
   using AppListItemMetadataPtr = mojom::AppListItemMetadataPtr;
   using SearchResultMetadataPtr = mojom::SearchResultMetadataPtr;
-  explicit AppListControllerImpl(ws::WindowService* window_service);
+  AppListControllerImpl();
   ~AppListControllerImpl() override;
 
   // Binds the mojom::AppListController interface request to this object.
@@ -185,7 +181,8 @@
   bool ProcessHomeLauncherGesture(ui::GestureEvent* event,
                                   const gfx::Point& screen_location) override;
   bool CanProcessEventsOnApplistViews() override;
-  ws::WindowService* GetWindowService() override;
+  void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) override;
 
   void OnVisibilityChanged(bool visible);
   void OnTargetVisibilityChanged(bool visible);
@@ -248,8 +245,6 @@
 
   int64_t GetDisplayIdToShowAppListOn();
 
-  ws::WindowService* window_service_;
-
   base::string16 last_raw_query_;
 
   mojom::AppListClientPtr client_;
@@ -264,7 +259,9 @@
   // Bindings for the AppListController interface.
   mojo::BindingSet<mojom::AppListController> bindings_;
 
-  // Token to view map for classic/mus ash (i.e. non-mash).
+  // TODO(https://crbug.com/894987): Remove this once assistant UI is converted
+  // to use Content Service, as there will then be no more consumers of
+  // AnswerCardContentsRegistry.
   std::unique_ptr<app_list::AnswerCardContentsRegistry>
       answer_card_contents_registry_;
 
diff --git a/ash/app_list/app_list_view_delegate.h b/ash/app_list/app_list_view_delegate.h
index 6b851538..18a94b2 100644
--- a/ash/app_list/app_list_view_delegate.h
+++ b/ash/app_list/app_list_view_delegate.h
@@ -12,6 +12,7 @@
 #include "ash/public/interfaces/menu.mojom.h"
 #include "base/callback_forward.h"
 #include "base/strings/string16.h"
+#include "services/content/public/mojom/navigable_contents_factory.mojom.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/events/event_constants.h"
@@ -21,10 +22,6 @@
 class GestureEvent;
 }  // namespace ui
 
-namespace ws {
-class WindowService;
-}  // namespace ws
-
 namespace app_list {
 
 class AppListModel;
@@ -127,7 +124,11 @@
   // its descendants.
   virtual bool CanProcessEventsOnApplistViews() = 0;
 
-  virtual ws::WindowService* GetWindowService() = 0;
+  // Acquires a factory interface from the client which can be used to acquire
+  // initialize new NavigableContents objects for embedding web contents into
+  // the app list UI.
+  virtual void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) = 0;
 };
 
 }  // namespace app_list
diff --git a/ash/app_list/model/search/search_model.cc b/ash/app_list/model/search/search_model.cc
index e790813..14bcbb0 100644
--- a/ash/app_list/model/search/search_model.cc
+++ b/ash/app_list/model/search/search_model.cc
@@ -62,12 +62,10 @@
   // Add items back to |results_| in the order of |new_results|.
   for (auto&& new_result : new_results) {
     auto ui_result_it = results_map.find(new_result->id());
-    if (ui_result_it != results_map.end() &&
-        new_result->answer_card_contents_token() ==
-            ui_result_it->second->answer_card_contents_token()) {
+    if (ui_result_it != results_map.end()) {
       // Update and use the old result if it exists.
       std::unique_ptr<SearchResult> ui_result = std::move(ui_result_it->second);
-      ui_result->SetMetadata(new_result->CloneMetadata());
+      ui_result->SetMetadata(new_result->TakeMetadata());
       results_->Add(std::move(ui_result));
 
       // Remove the item from the map so that it ends up only with unused
diff --git a/ash/app_list/model/search/search_result.h b/ash/app_list/model/search/search_result.h
index 621a2ac7d..3a496c7 100644
--- a/ash/app_list/model/search/search_result.h
+++ b/ash/app_list/model/search/search_result.h
@@ -80,18 +80,8 @@
   }
   void SetFormattedPrice(const base::string16& formatted_price);
 
-  const base::Optional<base::UnguessableToken>& answer_card_contents_token()
-      const {
-    return metadata_->answer_card_contents_token;
-  }
-  void set_answer_card_contents_token(
-      const base::Optional<base::UnguessableToken>& token) {
-    metadata_->answer_card_contents_token = token;
-  }
-
-  gfx::Size answer_card_size() const {
-    return metadata_->answer_card_size.value_or(gfx::Size());
-  }
+  const base::Optional<GURL>& query_url() const { return metadata_->query_url; }
+  void set_query_url(const GURL& url) { metadata_->query_url = url; }
 
   const std::string& id() const { return metadata_->id; }
 
@@ -138,8 +128,8 @@
   virtual void InvokeAction(int action_index, int event_flags);
 
   void SetMetadata(ash::mojom::SearchResultMetadataPtr metadata);
-  ash::mojom::SearchResultMetadataPtr CloneMetadata() const {
-    return metadata_.Clone();
+  ash::mojom::SearchResultMetadataPtr TakeMetadata() {
+    return std::move(metadata_);
   }
 
  protected:
diff --git a/ash/app_list/test/app_list_test_view_delegate.cc b/ash/app_list/test/app_list_test_view_delegate.cc
index ec9b38e..06949e0 100644
--- a/ash/app_list/test/app_list_test_view_delegate.cc
+++ b/ash/app_list/test/app_list_test_view_delegate.cc
@@ -98,8 +98,9 @@
   return true;
 }
 
-ws::WindowService* AppListTestViewDelegate::GetWindowService() {
-  return nullptr;
+void AppListTestViewDelegate::GetNavigableContentsFactory(
+    content::mojom::NavigableContentsFactoryRequest request) {
+  fake_navigable_contents_factory_.BindRequest(std::move(request));
 }
 
 void AppListTestViewDelegate::GetSearchResultContextMenuModel(
diff --git a/ash/app_list/test/app_list_test_view_delegate.h b/ash/app_list/test/app_list_test_view_delegate.h
index 88333b55..7144f60 100644
--- a/ash/app_list/test/app_list_test_view_delegate.h
+++ b/ash/app_list/test/app_list_test_view_delegate.h
@@ -18,6 +18,7 @@
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "services/content/public/cpp/test/fake_navigable_contents_factory.h"
 #include "ui/base/models/simple_menu_model.h"
 
 namespace app_list {
@@ -45,6 +46,10 @@
   // SetProfileByPath() is called.
   void set_next_profile_app_count(int apps) { next_profile_app_count_ = apps; }
 
+  content::FakeNavigableContentsFactory& fake_navigable_contents_factory() {
+    return fake_navigable_contents_factory_;
+  }
+
   // Sets whether the search engine is Google or not.
   void SetSearchEngineIsGoogle(bool is_google);
 
@@ -80,7 +85,8 @@
   bool ProcessHomeLauncherGesture(ui::GestureEvent* event,
                                   const gfx::Point& screen_location) override;
   bool CanProcessEventsOnApplistViews() override;
-  ws::WindowService* GetWindowService() override;
+  void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) override;
 
   // Do a bulk replacement of the items in the model.
   void ReplaceTestModel(int item_count);
@@ -103,6 +109,7 @@
   std::unique_ptr<SearchModel> search_model_;
   std::vector<SkColor> wallpaper_prominent_colors_;
   ui::SimpleMenuModel search_result_context_menu_model_;
+  content::FakeNavigableContentsFactory fake_navigable_contents_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListTestViewDelegate);
 };
diff --git a/ash/app_list/test/test_app_list_client.h b/ash/app_list/test/test_app_list_client.h
index 8727252..10a24a0 100644
--- a/ash/app_list/test/test_app_list_client.h
+++ b/ash/app_list/test/test_app_list_client.h
@@ -45,14 +45,16 @@
                                int event_flags) override {}
   void OnAppListTargetVisibilityChanged(bool visible) override {}
   void OnAppListVisibilityChanged(bool visible) override {}
-  void StartVoiceInteractionSession() override;
-  void ToggleVoiceInteractionSession() override;
   void OnFolderCreated(mojom::AppListItemMetadataPtr item) override {}
   void OnFolderDeleted(mojom::AppListItemMetadataPtr item) override {}
   void OnItemUpdated(mojom::AppListItemMetadataPtr item) override {}
   void OnPageBreakItemAdded(const std::string& id,
                             const syncer::StringOrdinal& position) override {}
   void OnPageBreakItemDeleted(const std::string& id) override {}
+  void StartVoiceInteractionSession() override;
+  void ToggleVoiceInteractionSession() override;
+  void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) override {}
 
   size_t voice_session_count() const { return voice_session_count_; }
 
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc
index 59c5dfa3..c790602 100644
--- a/ash/app_list/views/app_list_view_unittest.cc
+++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -37,7 +37,6 @@
 #include "ash/app_list/views/suggestion_chip_view.h"
 #include "ash/app_list/views/suggestions_container_view.h"
 #include "ash/app_list/views/test/apps_grid_view_test_api.h"
-#include "ash/public/cpp/app_list/answer_card_contents_registry.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
@@ -47,6 +46,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/icu_test_util.h"
 #include "base/test/scoped_feature_list.h"
+#include "services/content/public/cpp/test/fake_navigable_contents.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/chromeos/search_box/search_box_constants.h"
@@ -278,14 +278,11 @@
     }
 
     views::ViewsTestBase::SetUp();
-    answer_card_contents_registry_ =
-        std::make_unique<AnswerCardContentsRegistry>();
-    fake_answer_card_view_ = std::make_unique<views::View>();
-    fake_answer_card_view_->set_owned_by_client();
-    fake_answer_card_token_ = answer_card_contents_registry_->Register(
-        fake_answer_card_view_.get(), /*contents_native_view=*/nullptr);
 
     // Initialize app list view.
+    fake_card_contents_.set_default_response_headers(
+        SearchResultAnswerCardView::CreateAnswerCardResponseHeadersForTest(
+            "weather", "Unimportant Title"));
     delegate_ = std::make_unique<AppListTestViewDelegate>();
     view_ = new AppListView(delegate_.get());
     AppListView::InitParams params;
@@ -325,6 +322,10 @@
     // Disable animation timer.
     view_->GetWidget()->GetLayer()->GetAnimator()->set_disable_timer_for_test(
         true);
+
+    // The Update above will elicit a navigation. Wait for it.
+    delegate_->fake_navigable_contents_factory()
+        .WaitForAndBindNextContentsRequest(&fake_card_contents_);
   }
 
   void TearDown() override {
@@ -379,8 +380,10 @@
             std::make_unique<TestSearchResult>();
         result->set_display_type(data.first);
         result->set_display_score(display_score);
-        if (data.first == ash::SearchResultDisplayType::kCard)
-          result->set_answer_card_contents_token(fake_answer_card_token_);
+        if (data.first == ash::SearchResultDisplayType::kCard) {
+          const GURL kFakeCardUrl = GURL("https://www.google.com/coac?q=fake");
+          result->set_query_url(kFakeCardUrl);
+        }
         results->Add(std::move(result));
       }
     }
@@ -592,13 +595,12 @@
   // Restores the locale to default when destructor is called.
   base::test::ScopedRestoreICUDefaultLocale restore_locale_;
 
-  std::unique_ptr<AnswerCardContentsRegistry> answer_card_contents_registry_;
-  std::unique_ptr<views::View> fake_answer_card_view_;
-  base::UnguessableToken fake_answer_card_token_;
-
   // Used by AppListFolderView::UpdatePreferredBounds.
   keyboard::KeyboardController keyboard_controller_;
 
+  // A fake NavigableContents implementation to back card navigation requests.
+  content::FakeNavigableContents fake_card_contents_;
+
   DISALLOW_COPY_AND_ASSIGN(AppListViewFocusTest);
 };
 
diff --git a/ash/app_list/views/search_result_answer_card_view.cc b/ash/app_list/views/search_result_answer_card_view.cc
index 98ca4da4..5ab6cc0 100644
--- a/ash/app_list/views/search_result_answer_card_view.cc
+++ b/ash/app_list/views/search_result_answer_card_view.cc
@@ -12,16 +12,23 @@
 #include "ash/app_list/app_list_view_delegate.h"
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/app_list/views/search_result_base_view.h"
-#include "ash/public/cpp/app_list/answer_card_contents_registry.h"
 #include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/bind.h"
-#include "base/feature_list.h"
-#include "services/ws/public/mojom/window_tree.mojom.h"
-#include "services/ws/remote_view_host/server_remote_view_host.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
+#include "base/optional.h"
+#include "base/strings/strcat.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "services/content/public/cpp/navigable_contents.h"
+#include "services/content/public/cpp/navigable_contents_view.h"
+#include "services/content/public/mojom/navigable_contents_factory.mojom.h"
 #include "ui/accessibility/ax_node.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/aura/window.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/background.h"
 #include "ui/views/layout/box_layout.h"
@@ -31,45 +38,9 @@
 
 namespace {
 
-// Holds answer card data. |view| is the view to be added to app list view
-// hierarchy. |native_view| is the root of the card contents view. For classic
-// ash, it is the NativeView of the answer card WebContents. For mash, it is
-// the embedding root for answer card contents.
-struct CardData {
-  views::View* view = nullptr;
-  gfx::NativeView native_view = nullptr;
-};
-
-// Get answer card data by token.
-CardData GetCardDataByToken(
-    ws::WindowService* window_service,
-    const base::Optional<base::UnguessableToken>& token) {
-  // Bail for invalid token.
-  if (!token.has_value() || token->is_empty())
-    return {};
-
-  // Use AnswerCardContentsRegistry for an in-process token-to-view map. See
-  // answer_card_contents_registry.h. Null check because it could be missing in
-  // Mash and for tests.
-  auto* card_registry = AnswerCardContentsRegistry::Get();
-  if (card_registry) {
-    return {card_registry->GetView(token.value()),
-            card_registry->GetNativeView(token.value())};
-  }
-
-  // Use ServerRemoteViewHost to embed the answer card contents provided in the
-  // browser process in Mash.
-  if (features::IsUsingWindowService()) {
-    ws::ServerRemoteViewHost* view =
-        new ws::ServerRemoteViewHost(window_service);
-    view->EmbedUsingToken(token.value(),
-                          ws::mojom::kEmbedFlagEmbedderControlsVisibility,
-                          base::DoNothing());
-    return {view, view->embedding_root()};
-  }
-
-  return {};
-}
+constexpr char kSearchAnswerHasResult[] = "SearchAnswer-HasResult";
+constexpr char kSearchAnswerIssuedQuery[] = "SearchAnswer-IssuedQuery";
+constexpr char kSearchAnswerTitle[] = "SearchAnswer-Title";
 
 // Exclude the card native view from event handling.
 void ExcludeCardFromEventHandling(gfx::NativeView card_native_view) {
@@ -78,7 +49,7 @@
     return;
 
   if (!card_native_view->parent()) {
-    LOG(ERROR) << "Card is not attached to the app list view.";
+    DLOG(ERROR) << "Card is not attached to the app list view.";
     return;
   }
 
@@ -97,14 +68,43 @@
   AppListView::ExcludeWindowFromEventHandling(window);
 }
 
+bool ParseResponseHeaders(const net::HttpResponseHeaders* headers,
+                          std::string* title,
+                          std::string* issued_query) {
+  if (!headers || headers->response_code() != net::HTTP_OK)
+    return false;
+
+  if (!headers->HasHeaderValue(kSearchAnswerHasResult, "true")) {
+    DLOG(WARNING) << "Response not an answer card. Expected a value of \"true\""
+                  << " for " << kSearchAnswerHasResult << " header.";
+    return false;
+  }
+  if (!headers->GetNormalizedHeader(kSearchAnswerTitle, title) ||
+      title->empty()) {
+    DLOG(WARNING) << "Ignoring answer card response with no valid "
+                  << kSearchAnswerTitle << " header present.";
+    return false;
+  }
+  if (!headers->GetNormalizedHeader(kSearchAnswerIssuedQuery, issued_query) ||
+      issued_query->empty()) {
+    DLOG(WARNING) << "Ignoring answer card response with no valid "
+                  << kSearchAnswerIssuedQuery << " header present.";
+    return false;
+  }
+
+  return true;
+}
+
 }  // namespace
 
 // Container of the search answer view.
 class SearchResultAnswerCardView::SearchAnswerContainerView
-    : public SearchResultBaseView {
+    : public SearchResultBaseView,
+      public content::NavigableContentsObserver {
  public:
-  explicit SearchAnswerContainerView(AppListViewDelegate* view_delegate)
-      : view_delegate_(view_delegate) {
+  SearchAnswerContainerView(SearchResultContainerView* container,
+                            AppListViewDelegate* view_delegate)
+      : container_(container), view_delegate_(view_delegate) {
     SetFocusBehavior(FocusBehavior::ALWAYS);
     // Center the card horizontally in the container. Padding is set on the
     // server.
@@ -113,52 +113,80 @@
     answer_container_layout->set_main_axis_alignment(
         views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
     SetLayoutManager(std::move(answer_container_layout));
+
+    view_delegate_->GetNavigableContentsFactory(
+        mojo::MakeRequest(&contents_factory_));
+
+    auto params = content::mojom::NavigableContentsParams::New();
+    params->enable_view_auto_resize = true;
+    params->suppress_navigations = true;
+    contents_ = std::make_unique<content::NavigableContents>(
+        contents_factory_.get(), std::move(params));
+    contents_->AddObserver(this);
   }
 
   ~SearchAnswerContainerView() override {
+    contents_->RemoveObserver(this);
     if (search_result_)
       search_result_->RemoveObserver(this);
   }
 
-  bool SetSearchResult(SearchResult* search_result) {
-    const base::Optional<base::UnguessableToken> old_token =
-        search_result_ ? search_result_->answer_card_contents_token()
-                       : base::nullopt;
-    const base::Optional<base::UnguessableToken> new_token =
-        search_result ? search_result->answer_card_contents_token()
-                      : base::nullopt;
+  bool has_valid_answer_card() const {
+    return is_current_navigation_valid_answer_card_;
+  }
 
-    views::View* result_view = child_count() ? child_at(0) : nullptr;
-    if (old_token != new_token) {
-      RemoveAllChildViews(true /* delete_children */);
+  void HideCard() {
+    OnVisibilityChanged(false /* is_visible */);
+    RemoveAllChildViews(false /* delete_children */);
+    SetPreferredSize(gfx::Size{0, 0});
 
-      const CardData card_data =
-          GetCardDataByToken(view_delegate_->GetWindowService(), new_token);
+    // Force any future result changes to initiate another navigation.
+    is_current_navigation_valid_answer_card_ = false;
+  }
 
-      result_view = card_data.view;
-      if (result_view) {
-        AddChildView(result_view);
-        ExcludeCardFromEventHandling(card_data.native_view);
-      }
-    }
-
-    base::string16 old_title;
-    base::string16 new_title;
+  void SetSearchResult(SearchResult* search_result) {
+    // Remove the card contents from the UI temporarily while we attempt to
+    // navigate it to the new query URL.
+    base::Optional<GURL> previous_url;
     if (search_result_) {
+      previous_url = search_result_->query_url();
       search_result_->RemoveObserver(this);
-      old_title = search_result_->title();
+      search_result_ = nullptr;
     }
+
+    if (!search_result || !search_result->query_url()) {
+      HideCard();
+      return;
+    }
+
     search_result_ = search_result;
-    if (search_result_) {
-      search_result_->AddObserver(this);
-      if (result_view)
-        result_view->SetPreferredSize(search_result_->answer_card_size());
+    search_result_->AddObserver(this);
 
-      new_title = search_result_->title();
-      SetAccessibleName(new_title);
+    if (search_result_->query_url() == previous_url &&
+        is_current_navigation_valid_answer_card_) {
+      // The new search result is for a query URL identical to the previous one,
+      // so we don't bother hiding or navigating the existing card contents.
+      return;
     }
 
-    return old_title != new_title;
+    // We hide the view while navigating its contents. Once navigation is
+    // finished and we (possibly) have a valid answer card response, the
+    // contents view will be re-parented to this container.
+    HideCard();
+
+    base::RecordAction(base::UserMetricsAction("SearchAnswer_UserInteraction"));
+
+    contents_->Navigate(*search_result_->query_url());
+  }
+
+  void OnVisibilityChanged(bool is_visible) {
+    if (is_visible && !last_shown_time_) {
+      last_shown_time_ = base::Time::Now();
+    } else if (last_shown_time_) {
+      UMA_HISTOGRAM_MEDIUM_TIMES("SearchAnswer.AnswerVisibleTime",
+                                 base::Time::Now() - *last_shown_time_);
+      last_shown_time_.reset();
+    }
   }
 
   // views::Button overrides:
@@ -207,13 +235,83 @@
 
   // SearchResultObserver overrides:
   void OnResultDestroying() override {
-    RemoveAllChildViews(true /* delete_children */);
+    HideCard();
     search_result_ = nullptr;
   }
 
  private:
-  AppListViewDelegate* const view_delegate_;  // Not owned.
-  SearchResult* search_result_ = nullptr;     // Not owned.
+  // content::NavigableContentsObserver overrides:
+  void DidFinishNavigation(
+      const GURL& url,
+      bool is_main_frame,
+      bool is_error_page,
+      const net::HttpResponseHeaders* response_headers) override {
+    if (!is_main_frame)
+      return;
+
+    is_current_navigation_valid_answer_card_ = false;
+    if (is_error_page)
+      return;
+
+    std::string title;
+    if (!ParseResponseHeaders(response_headers, &title, &answer_card_query_))
+      return;
+
+    SetAccessibleName(base::UTF8ToUTF16(title));
+
+    // TODO(https://crbug.com/894893): Consider where, how to record some
+    // SearchAnswer metrics regarding navigation results and timing.
+
+    is_current_navigation_valid_answer_card_ = true;
+    answer_card_url_ = url;
+  }
+
+  void DidStopLoading() override {
+    if (!is_current_navigation_valid_answer_card_)
+      return;
+
+    OnVisibilityChanged(true /* is_visible */);
+    views::View* content_view = contents_->GetView()->view();
+    if (!has_children()) {
+      AddChildView(content_view);
+      ExcludeCardFromEventHandling(contents_->GetView()->native_view());
+    }
+    SetPreferredSize(content_view->GetPreferredSize());
+    container_->Update();
+  }
+
+  void DidAutoResizeView(const gfx::Size& new_size) override {
+    SetPreferredSize(new_size);
+    contents_->GetView()->view()->SetPreferredSize(new_size);
+    container_->Update();
+  }
+
+  void DidSuppressNavigation(const GURL& url,
+                             WindowOpenDisposition disposition,
+                             bool from_user_gesture) override {
+    if (!from_user_gesture)
+      return;
+
+    // NOTE: We shouldn't ever hit this path since all user gestures targeting
+    // the content area should be intercepted by the Button which overlaps its
+    // display region, and answer cards are generally not expected to elicit
+    // scripted navigations. This action is recorded here to verify these
+    // expectations.
+    base::RecordAction(base::UserMetricsAction("SearchAnswer_OpenedUrl"));
+  }
+
+  SearchResultContainerView* const container_;  // Not owned.
+  AppListViewDelegate* const view_delegate_;    // Not owned.
+  SearchResult* search_result_ = nullptr;       // Not owned.
+  content::mojom::NavigableContentsFactoryPtr contents_factory_;
+  std::unique_ptr<content::NavigableContents> contents_;
+
+  bool is_current_navigation_valid_answer_card_ = false;
+  GURL answer_card_url_;
+  std::string answer_card_query_;
+
+  // Tracks the last time this view was made visible, if still visible.
+  base::Optional<base::Time> last_shown_time_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchAnswerContainerView);
 };
@@ -221,7 +319,7 @@
 SearchResultAnswerCardView::SearchResultAnswerCardView(
     AppListViewDelegate* view_delegate)
     : search_answer_container_view_(
-          new SearchAnswerContainerView(view_delegate)) {
+          new SearchAnswerContainerView(this, view_delegate)) {
   AddChildView(search_answer_container_view_);
   SetLayoutManager(std::make_unique<views::FillLayout>());
 }
@@ -240,19 +338,16 @@
   std::vector<SearchResult*> display_results =
       SearchModel::FilterSearchResultsByDisplayType(
           results(), ash::SearchResultDisplayType::kCard, /*excludes=*/{}, 1);
+  SearchResult* top_result =
+      display_results.empty() ? nullptr : display_results.front();
 
-  const bool have_result = !display_results.empty();
-
-  const bool title_changed = search_answer_container_view_->SetSearchResult(
-      have_result ? display_results[0] : nullptr);
+  const bool have_result =
+      search_answer_container_view_->has_valid_answer_card();
+  search_answer_container_view_->SetSearchResult(top_result);
   parent()->SetVisible(have_result);
 
-  set_container_score(have_result ? display_results.front()->display_score()
-                                  : 0);
-  if (title_changed && search_answer_container_view_->HasFocus()) {
-    search_answer_container_view_->NotifyAccessibilityEvent(
-        ax::mojom::Event::kSelection, true);
-  }
+  set_container_score(top_result ? top_result->display_score() : 0);
+
   return have_result ? 1 : 0;
 }
 
@@ -272,4 +367,18 @@
   return search_answer_container_view_;
 }
 
+// static
+scoped_refptr<net::HttpResponseHeaders>
+SearchResultAnswerCardView::CreateAnswerCardResponseHeadersForTest(
+    const std::string& query,
+    const std::string& title) {
+  auto headers =
+      base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
+  headers->AddHeader(base::StrCat({kSearchAnswerHasResult, ": true"}));
+  headers->AddHeader(base::StrCat({kSearchAnswerTitle, ": ", title.c_str()}));
+  headers->AddHeader(
+      base::StrCat({kSearchAnswerIssuedQuery, ": ", query.c_str()}));
+  return headers;
+}
+
 }  // namespace app_list
diff --git a/ash/app_list/views/search_result_answer_card_view.h b/ash/app_list/views/search_result_answer_card_view.h
index 1a3dee4..a208d06 100644
--- a/ash/app_list/views/search_result_answer_card_view.h
+++ b/ash/app_list/views/search_result_answer_card_view.h
@@ -6,6 +6,9 @@
 #define ASH_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_
 
 #include "ash/app_list/views/search_result_container_view.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
+#include "net/http/http_response_headers.h"
 
 namespace app_list {
 
@@ -30,6 +33,10 @@
 
   views::View* GetSearchAnswerContainerViewForTest() const;
 
+  static scoped_refptr<net::HttpResponseHeaders>
+  CreateAnswerCardResponseHeadersForTest(const std::string& query,
+                                         const std::string& title);
+
  private:
   class SearchAnswerContainerView;
 
@@ -37,6 +44,10 @@
   // It's visible iff we have a search answer result.
   SearchAnswerContainerView* const search_answer_container_view_;
 
+  // Tracks the last known card title so we can update the accessibility
+  // framework if the title changes while the card has focus.
+  base::string16 last_known_card_title_;
+
   DISALLOW_COPY_AND_ASSIGN(SearchResultAnswerCardView);
 };
 
diff --git a/ash/app_list/views/search_result_answer_card_view_unittest.cc b/ash/app_list/views/search_result_answer_card_view_unittest.cc
index 876f54e3..053199dc 100644
--- a/ash/app_list/views/search_result_answer_card_view_unittest.cc
+++ b/ash/app_list/views/search_result_answer_card_view_unittest.cc
@@ -10,11 +10,12 @@
 #include "ash/app_list/test/app_list_test_view_delegate.h"
 #include "ash/app_list/test/test_search_result.h"
 #include "ash/app_list/views/search_result_view.h"
-#include "ash/public/cpp/app_list/answer_card_contents_registry.h"
 #include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/unguessable_token.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/content/public/cpp/test/fake_navigable_contents.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/views/background.h"
 #include "ui/views/test/views_test_base.h"
@@ -37,31 +38,33 @@
 
     search_card_view_ = std::make_unique<views::View>();
 
+    fake_card_contents_.set_default_response_headers(
+        SearchResultAnswerCardView::CreateAnswerCardResponseHeadersForTest(
+            "weather", kResultTitle));
+
     result_container_view_ = new SearchResultAnswerCardView(&view_delegate_);
     search_card_view_->AddChildView(result_container_view_);
     result_container_view_->SetResults(
         view_delegate_.GetSearchModel()->results());
 
-    result_view_ = std::make_unique<views::View>();
-    result_view_->set_owned_by_client();
-    token_ = contents_registry_.Register(result_view_.get(),
-                                         /*contents_native_view=*/nullptr);
-
     SetUpSearchResult();
   }
 
  protected:
   void SetUpSearchResult() {
+    const GURL kFakeQueryUrl = GURL("https://www.google.com/coac?q=fake");
     SearchModel::SearchResults* results = GetResults();
     std::unique_ptr<TestSearchResult> result =
         std::make_unique<TestSearchResult>();
     result->set_display_type(ash::SearchResultDisplayType::kCard);
     result->set_title(base::UTF8ToUTF16(kResultTitle));
-    result->set_answer_card_contents_token(token_);
     result->set_display_score(kDisplayScore);
+    result->set_query_url(kFakeQueryUrl);
     results->Add(std::move(result));
 
     // Adding results will schedule Update().
+    view_delegate_.fake_navigable_contents_factory()
+        .WaitForAndBindNextContentsRequest(&fake_card_contents_);
     RunPendingMessages();
   }
 
@@ -100,8 +103,6 @@
     result_container_view_->child_at(0)->GetAccessibleNodeData(node_data);
   }
 
-  views::View* result_view() const { return result_view_.get(); }
-
  private:
   AppListTestViewDelegate view_delegate_;
 
@@ -111,25 +112,17 @@
   // Result container that we are testing. It's a child of search_card_view_.
   // Owned by the view hierarchy.
   SearchResultAnswerCardView* result_container_view_;
-  // View sent within the search result. May be shown within
-  // result_container_view_. Has set_owned_by_client() called.
-  std::unique_ptr<views::View> result_view_;
 
-  AnswerCardContentsRegistry contents_registry_;
-  base::UnguessableToken token_;
+  // Fake NavigableContents implementation to back answer card navigations.
+  content::FakeNavigableContents fake_card_contents_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchResultAnswerCardViewTest);
 };
 
 TEST_F(SearchResultAnswerCardViewTest, Basic) {
   EXPECT_EQ(kDisplayScore, GetContainerScore());
-
   EXPECT_EQ(1, GetResultCountFromView());
-
-  // Result view should be added to the hierarchy.
-  EXPECT_EQ(search_card_view(), result_view()->parent()->parent()->parent());
   ASSERT_TRUE(search_card_view()->visible());
-
   EXPECT_EQ(1, GetYSize());
 }
 
@@ -149,7 +142,6 @@
 TEST_F(SearchResultAnswerCardViewTest, DeleteResult) {
   DeleteResult();
   EXPECT_EQ(0UL, GetResults()->item_count());
-  EXPECT_EQ(nullptr, result_view()->parent());
   EXPECT_EQ(0, GetYSize());
   ASSERT_FALSE(search_card_view()->visible());
   EXPECT_EQ(0, GetContainerScore());
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 107cfb3..776dcb7 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -160,6 +160,7 @@
 # this after Deserialize(Serialize()) API works with handles.
 mojom("test_interfaces") {
   visibility = [ ":unit_tests" ]
+  disable_variants = true
 
   sources = [
     "shelf_struct_traits_test_service.mojom",
diff --git a/ash/public/cpp/immersive/immersive_fullscreen_controller.cc b/ash/public/cpp/immersive/immersive_fullscreen_controller.cc
index 76acdbc7..13d73662 100644
--- a/ash/public/cpp/immersive/immersive_fullscreen_controller.cc
+++ b/ash/public/cpp/immersive/immersive_fullscreen_controller.cc
@@ -297,7 +297,9 @@
 // static
 void ImmersiveFullscreenController::EnableForWidget(views::Widget* widget,
                                                     bool enabled) {
-  widget->GetNativeWindow()->SetProperty(kImmersiveIsActive, enabled);
+  auto* window = widget->GetNativeWindow();
+  if (window->GetProperty(kImmersiveIsActive) != enabled)
+    widget->GetNativeWindow()->SetProperty(kImmersiveIsActive, enabled);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn
index 3a2b26ca..e86d917 100644
--- a/ash/public/interfaces/BUILD.gn
+++ b/ash/public/interfaces/BUILD.gn
@@ -10,6 +10,7 @@
 # enums and constants).
 mojom("interfaces_internal") {
   visibility = [ "//ash/public/cpp:*" ]
+  disable_variants = true
 
   sources = [
     "accelerator_controller.mojom",
@@ -72,6 +73,7 @@
     "//components/arc/common:notifications",
     "//components/sync/mojo:interfaces",
     "//mojo/public/mojom/base",
+    "//services/content/public/mojom",
     "//services/preferences/public/mojom",
     "//skia/public/interfaces",
     "//ui/accessibility:ax_enums_mojo",
@@ -95,6 +97,7 @@
 
 mojom("test_interfaces") {
   testonly = true
+  disable_variants = true
   sources = [
     "shelf_test_api.mojom",
     "shell_test_api.mojom",
diff --git a/ash/public/interfaces/app_list.mojom b/ash/public/interfaces/app_list.mojom
index 55e70bf..2838360 100644
--- a/ash/public/interfaces/app_list.mojom
+++ b/ash/public/interfaces/app_list.mojom
@@ -8,9 +8,11 @@
 import "components/sync/mojo/syncer.mojom";
 import "mojo/public/mojom/base/string16.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
+import "services/content/public/mojom/navigable_contents_factory.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/image/mojo/image.mojom";
 import "ui/gfx/range/mojo/range.mojom";
+import "url/mojom/url.mojom";
 
 // A structure holding the common information which is sent between ash and,
 // chrome representing an app list item.
@@ -59,17 +61,12 @@
   double display_score;       // A score to determine the result display order.
   bool is_omnibox_search;     // Whether this result is searched from Omnibox.
   bool is_installing;         // Whether this result is installing.
-  mojo_base.mojom.UnguessableToken? answer_card_contents_token;
-                              // A token used to render answer card, which is
-                              // empty before initialized. It's illegal to pass
-                              // an empty UnguessableToken across processes. So
-                              // we use a null value when it's empty here.
-  gfx.mojom.Size? answer_card_size;  // Preferred size of answer card. It is
-                                     // unset for non-answer-card results. For
-                                     // answer card results, it is set when
-                                     // the answer card WebContents finishes
-                                     // loading and its renderer notifies it
-                                     // about a new contents size.
+
+  url.mojom.Url? query_url;  // A query URL associated with this result. The
+                             // meaning and treatment of the URL
+                             // (e.g. displaying inline web contents) is
+                             // dependent on the result type.
+
   gfx.mojom.ImageSkia? icon;  // The icon of this result.
   gfx.mojom.ImageSkia? chip_icon;  // The icon of this result in a smaller
                                    // dimension to be rendered in suggestion
@@ -372,4 +369,9 @@
   StartVoiceInteractionSession();
   // Starts or stops voice interaction session based on current state.
   ToggleVoiceInteractionSession();
+
+  // Acquires a NavigableContentsFactory (indirectly) from the Content Service
+  // to allow the app list to display embedded web contents. Currently used only
+  // for answer card search results.
+  GetNavigableContentsFactory(content.mojom.NavigableContentsFactory& request);
 };
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index e7317ae..09b5a1b 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -487,12 +487,13 @@
   MaybeUpdateShelfBackground(AnimationChangeType::IMMEDIATE);
 }
 
-void ShelfLayoutManager::OnOverviewModeStarting() {
+void ShelfLayoutManager::OnOverviewModeStartingAnimationComplete(
+    bool canceled) {
   UpdateVisibilityState();
   MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE);
 }
 
-void ShelfLayoutManager::OnOverviewModeEnded() {
+void ShelfLayoutManager::OnOverviewModeEndingAnimationComplete(bool canceled) {
   UpdateVisibilityState();
   MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE);
 }
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 327d873..3fdb91c 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -164,8 +164,8 @@
   void OnPinnedStateChanged(aura::Window* pinned_window) override;
   void OnAppListVisibilityChanged(bool shown,
                                   aura::Window* root_window) override;
-  void OnOverviewModeStarting() override;
-  void OnOverviewModeEnded() override;
+  void OnOverviewModeStartingAnimationComplete(bool canceled) override;
+  void OnOverviewModeEndingAnimationComplete(bool canceled) override;
   void OnSplitViewModeStarted() override;
   void OnSplitViewModeEnded() override;
 
diff --git a/ash/shell.cc b/ash/shell.cc
index db313f3..d4a2131 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -1097,8 +1097,7 @@
 
   // |app_list_controller_| is put after |tablet_mode_controller_| as the former
   // uses the latter in constructor.
-  app_list_controller_ = std::make_unique<AppListControllerImpl>(
-      window_service_owner_->window_service());
+  app_list_controller_ = std::make_unique<AppListControllerImpl>();
   shelf_controller_ = std::make_unique<ShelfController>();
 
   magnifier_key_scroll_handler_ = MagnifierKeyScroller::CreateHandler();
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index 29d40cc..831adfb9 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -329,9 +329,9 @@
     return true;
   }
 
-  ws::WindowService* GetWindowService() override {
+  void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) override {
     NOTIMPLEMENTED();
-    return nullptr;
   }
 
   std::unique_ptr<app_list::AppListModel> model_;
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc
index 98c24877..24ada41 100644
--- a/ash/wm/overview/overview_utils.cc
+++ b/ash/wm/overview/overview_utils.cc
@@ -13,6 +13,7 @@
 #include "ash/shell.h"
 #include "ash/wm/overview/cleanup_animation_observer.h"
 #include "ash/wm/overview/scoped_overview_animation_settings.h"
+#include "ash/wm/overview/start_animation_observer.h"
 #include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/window_state.h"
@@ -139,8 +140,14 @@
   ScopedOverviewAnimationSettings scoped_overview_animation_settings(
       animation_type, window);
   window->layer()->SetOpacity(1.0f);
-  if (slide)
+  if (slide) {
     window->SetTransform(original_transform);
+
+    auto start_observer = std::make_unique<StartAnimationObserver>();
+    scoped_overview_animation_settings.AddObserver(start_observer.get());
+    Shell::Get()->window_selector_controller()->AddStartAnimationObserver(
+        std::move(start_observer));
+  }
 }
 
 void FadeOutWidgetAndMaybeSlideOnExit(std::unique_ptr<views::Widget> widget,
diff --git a/ash/wm/overview/window_grid.cc b/ash/wm/overview/window_grid.cc
index 981e284..69808369 100644
--- a/ash/wm/overview/window_grid.cc
+++ b/ash/wm/overview/window_grid.cc
@@ -509,6 +509,9 @@
     window_observer_.Remove(selector_item->GetWindow());
     window_state_observer_.Remove(
         wm::GetWindowState(selector_item->GetWindow()));
+    // Erase from the list first because deleting WindowSelectorItem can
+    // lead to iterating through the |window_list_|.
+    std::unique_ptr<WindowSelectorItem> tmp = std::move(*iter);
     window_list_.erase(iter);
   }
 
@@ -734,7 +737,11 @@
   const bool needs_repositioning = !((*iter)->animating_to_close());
 
   size_t removed_index = iter - window_list_.begin();
+  // Erase from the list first because deleting WindowSelectorItem can
+  // lead to iterating through the |window_list_|.
+  std::unique_ptr<WindowSelectorItem> tmp = std::move(*iter);
   window_list_.erase(iter);
+  tmp.reset();
 
   if (empty()) {
     selection_widget_.reset();
@@ -1101,7 +1108,6 @@
   aura::Window* parent_window = widget_window->parent();
   const gfx::Rect bounds = ash::screen_util::SnapBoundsToDisplayEdge(
       parent_window->bounds(), parent_window);
-  parent_window->SetBounds(bounds);
   widget_window->SetBounds(bounds);
   widget_window->SetName("OverviewModeShield");
 
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index d372b73..01b9d25 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -50,6 +50,7 @@
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/widget/widget_delegate.h"
 #include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/core/window_util.h"
 #include "ui/wm/public/activation_client.h"
@@ -104,6 +105,27 @@
   const aura::Window* root_window;
 };
 
+// A WidgetDelegate to specify the initialy focused view.
+class TextFilterWidgetDelegate : public views::WidgetDelegate {
+ public:
+  TextFilterWidgetDelegate(views::Widget* widget, views::View* initial_focus)
+      : widget_(widget), initial_focus_(initial_focus) {}
+  ~TextFilterWidgetDelegate() override = default;
+
+  // WidgetDelegate:
+  void DeleteDelegate() override { delete this; }
+  views::Widget* GetWidget() override { return widget_; }
+  const views::Widget* GetWidget() const override { return widget_; }
+  bool ShouldAdvanceFocusToTopLevelWidget() const override { return true; }
+  views::View* GetInitiallyFocusedView() override { return initial_focus_; }
+
+ private:
+  views::Widget* widget_;
+  views::View* initial_focus_;
+
+  DISALLOW_COPY_AND_ASSIGN(TextFilterWidgetDelegate);
+};
+
 // Triggers a shelf visibility update on all root window controllers.
 void UpdateShelfVisibility() {
   for (aura::Window* root : Shell::GetAllRootWindows())
@@ -196,6 +218,9 @@
   params.name = "OverviewModeTextFilter";
   *text_filter_bottom = params.bounds.bottom() + kTextFieldBottomMargin;
   params.parent = root_window->GetChildById(kShellWindowId_StatusContainer);
+
+  views::Textfield* textfield = new views::Textfield();
+  params.delegate = new TextFilterWidgetDelegate(widget, textfield);
   widget->Init(params);
 
   // Use |container| to specify the padding surrounding the text and to give
@@ -215,7 +240,6 @@
                   vertical_padding, kTextFilterCornerRadius),
       kTextFilterHorizontalPadding));
 
-  views::Textfield* textfield = new views::Textfield();
   textfield->set_controller(controller);
   textfield->SetBorder(views::NullBorder());
   textfield->SetBackgroundColor(kTextFilterBackgroundColor);
@@ -239,8 +263,6 @@
   aura::Window* text_filter_widget_window = widget->GetNativeWindow();
   text_filter_widget_window->layer()->SetOpacity(0);
   text_filter_widget_window->SetTransform(transform);
-  widget->Show();
-  textfield->RequestFocus();
 
   return widget;
 }
@@ -722,6 +744,14 @@
   }
 }
 
+void WindowSelector::OnStartingAnimationComplete(bool canceled) {
+  if (!canceled) {
+    UpdateMaskAndShadow(!canceled);
+    if (text_filter_widget_)
+      text_filter_widget_->Show();
+  }
+}
+
 void WindowSelector::OnDisplayRemoved(const display::Display& display) {
   // TODO(flackr): Keep window selection active on remaining displays.
   CancelSelection();
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index 30807b6..a29253ac 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -217,6 +217,9 @@
   // Shows or hides all the window selector items' mask and shadow.
   void UpdateMaskAndShadow(bool show);
 
+  // Called when the overview mode starting animation completes.
+  void OnStartingAnimationComplete(bool canceled);
+
   WindowSelectorDelegate* delegate() { return delegate_; }
 
   SplitViewDragIndicators* split_view_drag_indicators() {
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
index 8125ca6..963b07e 100644
--- a/ash/wm/overview/window_selector_controller.cc
+++ b/ash/wm/overview/window_selector_controller.cc
@@ -42,6 +42,15 @@
 
 constexpr int kBlurSlideDurationMs = 250;
 
+// It can take up to two frames until the frame created in the UI thread that
+// triggered animation observer is drawn. Wait 50ms in attemp to
+// let its draw and swap finish.
+constexpr int kOcclusionPauseDurationForStartMs = 50;
+
+// Wait longer when exiting overview mode in case when a user
+// may re-enter overview mode immediately, contents are ready.
+constexpr int kOcclusionPauseDurationForEndMs = 5000;
+
 // Returns true if |window| should be hidden when entering overview.
 bool ShouldHideWindowInOverview(const aura::Window* window) {
   return window->GetProperty(ash::kHideInOverviewKey);
@@ -110,28 +119,21 @@
 // prior to entering overview mode (covered by a window), otherwise animates
 // the blur.
 class WindowSelectorController::OverviewBlurController
-    : public gfx::AnimationDelegate,
+    : public ui::CompositorAnimationObserver,
       public aura::WindowObserver {
  public:
-  OverviewBlurController() : animation_(this) {
-    animation_.SetSlideDuration(kBlurSlideDurationMs);
-  }
+  OverviewBlurController() = default;
 
   ~OverviewBlurController() override {
-    animation_.Stop();
+    if (compositor_)
+      compositor_->RemoveAnimationObserver(this);
     for (aura::Window* root : roots_to_animate_)
       root->RemoveObserver(this);
   }
 
-  void Blur() {
-    state_ = WallpaperAnimationState::kAddingBlur;
-    OnBlurChange();
-  }
+  void Blur() { OnBlurChange(WallpaperAnimationState::kAddingBlur); }
 
-  void Unblur() {
-    state_ = WallpaperAnimationState::kRemovingBlur;
-    OnBlurChange();
-  }
+  void Unblur() { OnBlurChange(WallpaperAnimationState::kRemovingBlur); }
 
  private:
   enum class WallpaperAnimationState {
@@ -140,30 +142,47 @@
     kNormal,
   };
 
-  // gfx::AnimationDelegate:
-  void AnimationEnded(const gfx::Animation* animation) override {
-    if (state_ == WallpaperAnimationState::kNormal)
+  void OnAnimationStep(base::TimeTicks timestamp) override {
+    if (start_time_ == base::TimeTicks()) {
+      start_time_ = timestamp;
       return;
+    }
+    const float progress = (timestamp - start_time_).InMilliseconds() /
+                           static_cast<float>(kBlurSlideDurationMs);
+    const bool adding = state_ == WallpaperAnimationState::kAddingBlur;
+    if (progress > 1.0f) {
+      AnimationProgressed(adding ? 1.0f : 0.f);
+      Stop();
+    } else {
+      AnimationProgressed(adding ? progress : 1.f - progress);
+    }
+  }
 
-    float value = state_ == WallpaperAnimationState::kAddingBlur
-                      ? kWallpaperBlurSigma
-                      : kWallpaperClearBlurSigma;
-    for (aura::Window* root : roots_to_animate_)
-      ApplyBlur(root, value);
+  void OnCompositingShuttingDown(ui::Compositor* compositor) override {
+    if (compositor_ == compositor)
+      Stop();
+  }
+
+  void Stop() {
+    if (compositor_) {
+      compositor_->RemoveAnimationObserver(this);
+      compositor_ = nullptr;
+    }
     state_ = WallpaperAnimationState::kNormal;
   }
 
-  void AnimationProgressed(const gfx::Animation* animation) override {
-    float value = animation_.CurrentValueBetween(kWallpaperClearBlurSigma,
-                                                 kWallpaperBlurSigma);
-    for (aura::Window* root : roots_to_animate_)
-      ApplyBlur(root, value);
+  void Start() {
+    DCHECK(!compositor_);
+    compositor_ = Shell::GetPrimaryRootWindow()->GetHost()->compositor();
+    compositor_->AddAnimationObserver(this);
+    start_time_ = base::TimeTicks();
   }
 
-  void AnimationCanceled(const gfx::Animation* animation) override {
+  void AnimationProgressed(float value) {
+    // Animate only to even numbers to reduce the load.
+    int ivalue = static_cast<int>(value * kWallpaperBlurSigma) / 2 * 2;
     for (aura::Window* root : roots_to_animate_)
-      ApplyBlur(root, kWallpaperClearBlurSigma);
-    state_ = WallpaperAnimationState::kNormal;
+      ApplyBlur(root, ivalue);
   }
 
   // aura::WindowObserver:
@@ -185,14 +204,17 @@
   // windows should have their wallpaper blurs animated and fills
   // |roots_to_animate_| accordingly. Applys blur or unblur immediately if
   // the wallpaper does not need blur animation.
-  void OnBlurChange() {
-    const bool should_blur = state_ == WallpaperAnimationState::kAddingBlur;
-    const float value =
-        should_blur ? kWallpaperBlurSigma : kWallpaperClearBlurSigma;
+  void OnBlurChange(WallpaperAnimationState state) {
+    Stop();
     for (aura::Window* root : roots_to_animate_)
       root->RemoveObserver(this);
     roots_to_animate_.clear();
 
+    state_ = state;
+    const bool should_blur = state_ == WallpaperAnimationState::kAddingBlur;
+    const float value =
+        should_blur ? kWallpaperBlurSigma : kWallpaperClearBlurSigma;
+
     WindowSelector* window_selector =
         Shell::Get()->window_selector_controller()->window_selector();
     for (aura::Window* root : Shell::Get()->GetAllRootWindows()) {
@@ -206,23 +228,20 @@
           continue;
         }
       }
-
-      animation_.Reset(should_blur ? 1.0 : 0.0);
       ApplyBlur(root, value);
     }
 
     // Run the animation if one of the roots needs to be animated.
-    if (roots_to_animate_.empty()) {
+    if (roots_to_animate_.empty())
       state_ = WallpaperAnimationState::kNormal;
-    } else if (should_blur) {
-      animation_.Show();
-    } else {
-      animation_.Hide();
-    }
+    else
+      Start();
   }
 
+  ui::Compositor* compositor_ = nullptr;
+  base::TimeTicks start_time_;
+
   WallpaperAnimationState state_ = WallpaperAnimationState::kNormal;
-  gfx::SlideAnimation animation_;
   // Vector which contains the root windows, if any, whose wallpaper should have
   // blur animated after Blur or Unblur is called.
   std::vector<aura::Window*> roots_to_animate_;
@@ -231,7 +250,8 @@
 };
 
 WindowSelectorController::WindowSelectorController()
-    : overview_blur_controller_(std::make_unique<OverviewBlurController>()) {}
+    : overview_blur_controller_(std::make_unique<OverviewBlurController>()),
+      weak_ptr_factory_(this) {}
 
 WindowSelectorController::~WindowSelectorController() {
   overview_blur_controller_.reset();
@@ -298,6 +318,12 @@
       return true;
     }
 
+    // Suspend occlusion tracker until the enter animation is complete.
+    reset_pauser_task_.Cancel();
+    occlusion_tracker_pauser_ =
+        std::make_unique<aura::WindowOcclusionTracker::ScopedPause>(
+            Shell::Get()->aura_env());
+
     window_selector_->set_enter_exit_overview_type(new_type);
     if (type == WindowSelector::EnterExitOverviewType::kWindowsMinimized ||
         type == WindowSelector::EnterExitOverviewType::kSwipeFromShelf) {
@@ -325,23 +351,53 @@
     // Clear any animations that may be running from last overview end.
     for (const auto& animation : delayed_animations_)
       animation->Shutdown();
-    if (!delayed_animations_.empty()) {
-      Shell::Get()->NotifyOverviewModeStartingAnimationComplete(
-          /*canceled=*/true);
-    }
+    if (!delayed_animations_.empty())
+      OnStartingAnimationComplete(/*canceled=*/true);
     delayed_animations_.clear();
 
+    // Suspend occlusion tracker until the exit animation is complete.
+    reset_pauser_task_.Cancel();
+    occlusion_tracker_pauser_ =
+        std::make_unique<aura::WindowOcclusionTracker::ScopedPause>(
+            Shell::Get()->aura_env());
+
     window_selector_ = std::make_unique<WindowSelector>(this);
     window_selector_->set_enter_exit_overview_type(new_type);
     Shell::Get()->NotifyOverviewModeStarting();
     window_selector_->Init(windows, hide_windows);
     if (IsBlurAllowed())
       overview_blur_controller_->Blur();
+    if (start_animations_.empty())
+      OnStartingAnimationComplete(/*canceled=*/false);
     OnSelectionStarted();
   }
   return true;
 }
 
+void WindowSelectorController::OnStartingAnimationComplete(bool canceled) {
+  Shell::Get()->NotifyOverviewModeStartingAnimationComplete(canceled);
+  if (window_selector_)
+    window_selector_->OnStartingAnimationComplete(canceled);
+  reset_pauser_task_.Reset(base::BindOnce(
+      &WindowSelectorController::ResetPauser, weak_ptr_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, reset_pauser_task_.callback(),
+      base::TimeDelta::FromMilliseconds(kOcclusionPauseDurationForStartMs));
+}
+
+void WindowSelectorController::OnEndingAnimationComplete(bool canceled) {
+  Shell::Get()->NotifyOverviewModeEndingAnimationComplete(canceled);
+  reset_pauser_task_.Reset(base::BindOnce(
+      &WindowSelectorController::ResetPauser, weak_ptr_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, reset_pauser_task_.callback(),
+      base::TimeDelta::FromMilliseconds(kOcclusionPauseDurationForEndMs));
+}
+
+void WindowSelectorController::ResetPauser() {
+  occlusion_tracker_pauser_.reset();
+}
+
 bool WindowSelectorController::IsSelecting() const {
   return window_selector_ != nullptr;
 }
@@ -480,15 +536,14 @@
   if (is_shutting_down_)
     return;
 
-  if (!start_animations_.empty()) {
-    Shell::Get()->NotifyOverviewModeEndingAnimationComplete(
-        /*canceled=*/true);
-  }
+  if (!start_animations_.empty())
+    OnEndingAnimationComplete(/*canceled=*/true);
   start_animations_.clear();
+
+  window_selector_->UpdateMaskAndShadow(/*show=*/false);
   is_shutting_down_ = true;
   Shell::Get()->NotifyOverviewModeEnding();
   auto* window_selector = window_selector_.release();
-  window_selector->UpdateMaskAndShadow(/*show=*/false);
   window_selector->Shutdown();
   // There may be no delayed animations in tests, so unblur right away.
   if (delayed_animations_.empty() && IsBlurAllowed())
@@ -519,7 +574,8 @@
   if (!window_selector_ && !previous_empty && delayed_animations_.empty()) {
     if (IsBlurAllowed())
       overview_blur_controller_->Unblur();
-    Shell::Get()->NotifyOverviewModeEndingAnimationComplete(/*canceled=*/false);
+
+    OnEndingAnimationComplete(/*canceled=*/false);
   }
 }
 
@@ -534,11 +590,8 @@
   const bool previous_empty = start_animations_.empty();
   base::EraseIf(start_animations_, base::MatchesUniquePtr(animation_observer));
 
-  if (!previous_empty && start_animations_.empty()) {
-    Shell::Get()->NotifyOverviewModeStartingAnimationComplete(
-        /*canceled=*/false);
-    window_selector_->UpdateMaskAndShadow(/*show=*/true);
-  }
+  if (!previous_empty && start_animations_.empty())
+    OnStartingAnimationComplete(/*canceled=*/false);
 }
 
 // static
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/window_selector_controller.h
index 72491bd..e3a96636 100644
--- a/ash/wm/overview/window_selector_controller.h
+++ b/ash/wm/overview/window_selector_controller.h
@@ -12,7 +12,9 @@
 #include "ash/wm/overview/window_selector.h"
 #include "ash/wm/overview/window_selector_delegate.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "ui/aura/window_occlusion_tracker.h"
 
 namespace ash {
 class WindowSelector;
@@ -97,6 +99,10 @@
   // Dispatched when window selection begins.
   void OnSelectionStarted();
 
+  void OnStartingAnimationComplete(bool canceled);
+  void OnEndingAnimationComplete(bool canceled);
+  void ResetPauser();
+
   // Collection of DelayedAnimationObserver objects that own widgets that may be
   // still animating after overview mode ends. If shell needs to shut down while
   // those animations are in progress, the animations are shut down and the
@@ -106,6 +112,9 @@
   // notify shell that the starting animations have been completed.
   std::vector<std::unique_ptr<DelayedAnimationObserver>> start_animations_;
 
+  std::unique_ptr<aura::WindowOcclusionTracker::ScopedPause>
+      occlusion_tracker_pauser_;
+
   std::unique_ptr<WindowSelector> window_selector_;
   base::Time last_selection_time_;
 
@@ -116,6 +125,10 @@
   // Animates the blurring if necessary.
   std::unique_ptr<OverviewBlurController> overview_blur_controller_;
 
+  base::CancelableOnceClosure reset_pauser_task_;
+
+  base::WeakPtrFactory<WindowSelectorController> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(WindowSelectorController);
 };
 
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index e2f9ae00..fe4e5be 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -586,7 +586,6 @@
   // called if we see the home launcher on enter (all windows are minimized).
   DCHECK(item_widget_);
   DCHECK(transform_window_.minimized_widget());
-
   FadeInWidgetAndMaybeSlideOnEnter(item_widget_.get(),
                                    OVERVIEW_ANIMATION_ENTER_FROM_HOME_LAUNCHER,
                                    /*slide=*/true);
@@ -1177,7 +1176,6 @@
   caption_container_view_ = new CaptionContainerView(
       this, image_view, label_view_, cannot_snap_label_view_, close_button_);
   UpdateCannotSnapWarningVisibility();
-
   item_widget_->SetContentsView(caption_container_view_);
   item_widget_->Show();
   item_widget_->SetOpacity(0);
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc
index a4b4166..3835b58 100644
--- a/ash/wm/workspace/backdrop_controller.cc
+++ b/ash/wm/workspace/backdrop_controller.cc
@@ -15,9 +15,11 @@
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
+#include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/wallpaper/wallpaper_controller.h"
 #include "ash/wm/overview/window_selector_controller.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/workspace/backdrop_delegate.h"
 #include "base/auto_reset.h"
@@ -68,7 +70,7 @@
 }  // namespace
 
 BackdropController::BackdropController(aura::Window* container)
-    : container_(container), in_restacking_(false) {
+    : container_(container) {
   DCHECK(container_);
   Shell::Get()->AddShellObserver(this);
   Shell::Get()->accessibility_controller()->AddObserver(this);
@@ -101,6 +103,10 @@
   UpdateBackdrop();
 }
 
+void BackdropController::OnDisplayMetricsChanged() {
+  UpdateBackdrop();
+}
+
 void BackdropController::OnPostWindowStateTypeChange(
     wm::WindowState* window_state,
     mojom::WindowStateType old_type) {
@@ -117,8 +123,8 @@
   // No need to continue update for recursive calls or in overview mode.
   WindowSelectorController* window_selector_controller =
       Shell::Get()->window_selector_controller();
-  if (in_restacking_ || (window_selector_controller &&
-                         window_selector_controller->IsSelecting())) {
+  if (pause_update_ || (window_selector_controller &&
+                        window_selector_controller->IsSelecting())) {
     return;
   }
 
@@ -129,12 +135,14 @@
     return;
   }
   // We are changing the order of windows which will cause recursion.
-  base::AutoReset<bool> lock(&in_restacking_, true);
+  base::AutoReset<bool> lock(&pause_update_, true);
   EnsureBackdropWidget();
   UpdateAccessibilityMode();
 
-  if (window == backdrop_window_ && backdrop_->IsVisible())
+  if (window == backdrop_window_ && backdrop_->IsVisible()) {
+    Layout();
     return;
+  }
   if (window->GetRootWindow() != backdrop_window_->GetRootWindow())
     return;
 
@@ -148,11 +156,20 @@
 }
 
 void BackdropController::OnOverviewModeStarting() {
+  if (backdrop_window_)
+    backdrop_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
   Hide();
 }
 
-void BackdropController::OnOverviewModeEnded() {
+void BackdropController::OnOverviewModeEnding() {
+  pause_update_ = true;
+}
+
+void BackdropController::OnOverviewModeEndingAnimationComplete(bool canceled) {
+  pause_update_ = false;
   UpdateBackdrop();
+  if (backdrop_window_)
+    backdrop_window_->ClearProperty(aura::client::kAnimationsDisabledKey);
 }
 
 void BackdropController::OnAppListVisibilityChanged(bool shown,
@@ -209,6 +226,8 @@
   ::wm::SetWindowVisibilityAnimationType(
       backdrop_window_, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
   backdrop_window_->layer()->SetColor(SK_ColorBLACK);
+
+  wm::GetWindowState(backdrop_window_)->set_allow_set_bounds_direct(true);
 }
 
 void BackdropController::UpdateAccessibilityMode() {
@@ -265,11 +284,7 @@
 }
 
 void BackdropController::Show() {
-  // Makes sure that the backdrop has the correct bounds if it should not be
-  // fullscreen size.
-  backdrop_->SetFullscreen(BackdropShouldFullscreen());
-  if (!BackdropShouldFullscreen())
-    backdrop_->SetBounds(GetBackdropBounds());
+  Layout();
   backdrop_->Show();
 }
 
@@ -315,4 +330,21 @@
       snapped_window, snap_position);
 }
 
+void BackdropController::Layout() {
+  // Makes sure that the backdrop has the correct bounds if it should not be
+  // fullscreen size.
+  backdrop_->SetFullscreen(BackdropShouldFullscreen());
+  if (backdrop_->IsFullscreen()) {
+    // TODO(oshima): The size of solid color layer can be smaller than texture's
+    // layer with fractional scale (crbug.com/9000220). Use adjusted bounds so
+    // that it can cover texture layer. Fix the bug and remove this.
+    auto* window = backdrop_window_;
+    gfx::Rect bounds = screen_util::GetDisplayBoundsInParent(window);
+    backdrop_window_->SetBounds(
+        screen_util::SnapBoundsToDisplayEdge(bounds, window));
+  } else {
+    backdrop_->SetBounds(GetBackdropBounds());
+  }
+}
+
 }  // namespace ash
diff --git a/ash/wm/workspace/backdrop_controller.h b/ash/wm/workspace/backdrop_controller.h
index e7562c3..150f709 100644
--- a/ash/wm/workspace/backdrop_controller.h
+++ b/ash/wm/workspace/backdrop_controller.h
@@ -57,6 +57,7 @@
   void OnWindowStackingChanged(aura::Window* window);
   void OnPostWindowStateTypeChange(wm::WindowState* window_state,
                                    mojom::WindowStateType old_type);
+  void OnDisplayMetricsChanged();
 
   void SetBackdropDelegate(std::unique_ptr<BackdropDelegate> delegate);
 
@@ -68,7 +69,8 @@
 
   // ShellObserver:
   void OnOverviewModeStarting() override;
-  void OnOverviewModeEnded() override;
+  void OnOverviewModeEnding() override;
+  void OnOverviewModeEndingAnimationComplete(bool canceled) override;
   void OnAppListVisibilityChanged(bool shown,
                                   aura::Window* root_window) override;
   void OnSplitViewModeStarting() override;
@@ -92,6 +94,8 @@
 
   void UpdateAccessibilityMode();
 
+  void Layout();
+
   // Returns the current visible top level window in the container.
   aura::Window* GetTopmostWindowWithBackdrop();
 
@@ -130,8 +134,10 @@
   std::unique_ptr<ui::EventHandler> backdrop_event_handler_;
   ui::EventHandler* original_event_handler_ = nullptr;
 
-  // If true, the |RestackOrHideWindow| might recurse.
-  bool in_restacking_ = false;
+  // If true, skip updating background. Used to avoid recursive update
+  // when updating the window stack, or delay hiding the backdrop
+  // in overview mode.
+  bool pause_update_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(BackdropController);
 };
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index e5e0739..744d2da 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -387,6 +387,7 @@
     const wm::WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED);
     AdjustAllWindowsBoundsForWorkAreaChange(&event);
   }
+  backdrop_controller_->OnDisplayMetricsChanged();
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/base/task/task_scheduler/scheduler_parallel_task_runner.cc b/base/task/task_scheduler/scheduler_parallel_task_runner.cc
index c5c1ace1..daec344 100644
--- a/base/task/task_scheduler/scheduler_parallel_task_runner.cc
+++ b/base/task/task_scheduler/scheduler_parallel_task_runner.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/task/task_scheduler/scheduler_parallel_task_runner.h"
+#include "base/task/task_scheduler/scheduler_task_runner_delegate.h"
 
 #include "base/task/task_scheduler/sequence.h"
 
@@ -24,14 +25,27 @@
     return false;
 
   // Post the task as part of a one-off single-task Sequence.
+  scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(traits_, this);
+
+  {
+    AutoSchedulerLock auto_lock(lock_);
+    sequences_.insert(sequence.get());
+  }
+
   return scheduler_task_runner_delegate_->PostTaskWithSequence(
-      Task(from_here, std::move(closure), delay),
-      MakeRefCounted<Sequence>(traits_));
+      Task(from_here, std::move(closure), delay), std::move(sequence));
 }
 
 bool SchedulerParallelTaskRunner::RunsTasksInCurrentSequence() const {
   return scheduler_task_runner_delegate_->IsRunningPoolWithTraits(traits_);
 }
 
+void SchedulerParallelTaskRunner::UnregisterSequence(Sequence* sequence) {
+  DCHECK(sequence);
+
+  AutoSchedulerLock auto_lock(lock_);
+  sequences_.erase(sequence);
+}
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/task/task_scheduler/scheduler_parallel_task_runner.h b/base/task/task_scheduler/scheduler_parallel_task_runner.h
index ead08af..5107be35 100644
--- a/base/task/task_scheduler/scheduler_parallel_task_runner.h
+++ b/base/task/task_scheduler/scheduler_parallel_task_runner.h
@@ -7,8 +7,9 @@
 
 #include "base/base_export.h"
 #include "base/callback_forward.h"
+#include "base/containers/flat_set.h"
 #include "base/location.h"
-#include "base/task/task_scheduler/scheduler_task_runner_delegate.h"
+#include "base/task/task_scheduler/scheduler_lock.h"
 #include "base/task/task_traits.h"
 #include "base/task_runner.h"
 #include "base/time/time.h"
@@ -16,6 +17,9 @@
 namespace base {
 namespace internal {
 
+class Sequence;
+class SchedulerTaskRunnerDelegate;
+
 // A task runner that runs tasks in parallel.
 class BASE_EXPORT SchedulerParallelTaskRunner : public TaskRunner {
  public:
@@ -31,12 +35,23 @@
 
   bool RunsTasksInCurrentSequence() const override;
 
+  // Removes |sequence| from |sequences_|.
+  void UnregisterSequence(Sequence* sequence);
+
  private:
   ~SchedulerParallelTaskRunner() override;
 
   const TaskTraits traits_;
   SchedulerTaskRunnerDelegate* const scheduler_task_runner_delegate_;
 
+  // Synchronizes access to |sequences_|.
+  SchedulerLock lock_;
+
+  // List of alive Sequences instantiated by this SchedulerParallelTaskRunner.
+  // Sequences are added when they are instantiated, and removed when they are
+  // destroyed.
+  base::flat_set<Sequence*> sequences_;
+
   DISALLOW_COPY_AND_ASSIGN(SchedulerParallelTaskRunner);
 };
 
diff --git a/base/task/task_scheduler/sequence.cc b/base/task/task_scheduler/sequence.cc
index 885bd92a..225b00bb 100644
--- a/base/task/task_scheduler/sequence.cc
+++ b/base/task/task_scheduler/sequence.cc
@@ -13,7 +13,11 @@
 namespace base {
 namespace internal {
 
-Sequence::Sequence(const TaskTraits& traits) : traits_(traits) {}
+Sequence::Sequence(
+    const TaskTraits& traits,
+    scoped_refptr<SchedulerParallelTaskRunner> scheduler_parallel_task_runner)
+    : traits_(traits),
+      scheduler_parallel_task_runner_(scheduler_parallel_task_runner) {}
 
 bool Sequence::PushTask(Task task) {
   // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
@@ -64,7 +68,11 @@
   return SequenceSortKey(traits_.priority(), next_task_sequenced_time);
 }
 
-Sequence::~Sequence() = default;
+Sequence::~Sequence() {
+  if (scheduler_parallel_task_runner_) {
+    scheduler_parallel_task_runner_->UnregisterSequence(this);
+  }
+}
 
 }  // namespace internal
 }  // namespace base
diff --git a/base/task/task_scheduler/sequence.h b/base/task/task_scheduler/sequence.h
index 6aab70c5..9ea5500 100644
--- a/base/task/task_scheduler/sequence.h
+++ b/base/task/task_scheduler/sequence.h
@@ -14,6 +14,7 @@
 #include "base/optional.h"
 #include "base/sequence_token.h"
 #include "base/task/task_scheduler/scheduler_lock.h"
+#include "base/task/task_scheduler/scheduler_parallel_task_runner.h"
 #include "base/task/task_scheduler/sequence_sort_key.h"
 #include "base/task/task_scheduler/task.h"
 #include "base/task/task_traits.h"
@@ -43,7 +44,11 @@
 class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> {
  public:
   // |traits| is metadata that applies to all Tasks in the Sequence.
-  explicit Sequence(const TaskTraits& traits);
+  // |scheduler_parallel_task_runner| is a reference to the
+  // SchedulerParallelTaskRunner that created this Sequence, if any.
+  Sequence(const TaskTraits& traits,
+           scoped_refptr<SchedulerParallelTaskRunner>
+               scheduler_parallel_task_runner = nullptr);
 
   // Adds |task| in a new slot at the end of the Sequence. Returns true if the
   // Sequence was empty before this operation.
@@ -97,6 +102,12 @@
   // The TaskTraits of all Tasks in the Sequence.
   const TaskTraits traits_;
 
+  // A reference to the SchedulerParallelTaskRunner that created this Sequence,
+  // if any. Used to remove Sequence from the TaskRunner's list of Sequence
+  // references when Sequence is deleted.
+  const scoped_refptr<SchedulerParallelTaskRunner>
+      scheduler_parallel_task_runner_;
+
   DISALLOW_COPY_AND_ASSIGN(Sequence);
 };
 
diff --git a/base/task/task_scheduler/task_tracker_posix_unittest.cc b/base/task/task_scheduler/task_tracker_posix_unittest.cc
index 4109a99..51c79e21 100644
--- a/base/task/task_scheduler/task_tracker_posix_unittest.cc
+++ b/base/task/task_scheduler/task_tracker_posix_unittest.cc
@@ -56,7 +56,7 @@
   Task task(FROM_HERE,
             Bind([](bool* did_run) { *did_run = true; }, Unretained(&did_run)),
             TimeDelta());
-  TaskTraits default_traits = {};
+  constexpr TaskTraits default_traits = {};
 
   EXPECT_TRUE(tracker_.WillPostTask(&task, default_traits.shutdown_behavior()));
 
@@ -78,7 +78,7 @@
             Bind(IgnoreResult(&FileDescriptorWatcher::WatchReadable), fds[0],
                  DoNothing()),
             TimeDelta());
-  TaskTraits default_traits = {};
+  constexpr TaskTraits default_traits = {};
   // FileDescriptorWatcher::WatchReadable needs a SequencedTaskRunnerHandle.
   task.sequenced_task_runner_ref = MakeRefCounted<NullTaskRunner>();
 
diff --git a/base/trace_event/cfi_backtrace_android.cc b/base/trace_event/cfi_backtrace_android.cc
index 623dcf7..567b2de2 100644
--- a/base/trace_event/cfi_backtrace_android.cc
+++ b/base/trace_event/cfi_backtrace_android.cc
@@ -8,6 +8,7 @@
 #include <sys/types.h>
 
 #include "base/android/apk_assets.h"
+#include "base/android/library_loader/anchor_functions.h"
 
 #if !defined(ARCH_CPU_ARMEL)
 #error This file should not be built for this architecture.
@@ -63,10 +64,6 @@
 // of the instruction in binary from PC.
 extern char __executable_start;
 
-// The address |_etext| gives the end of the .text section in the binary. This
-// value is more accurate than parsing the memory map since the mapped
-// regions are usualy larger than the .text section.
-extern char _etext;
 }
 
 namespace base {
@@ -128,13 +125,18 @@
 }
 
 // static
+bool CFIBacktraceAndroid::is_chrome_address(uintptr_t pc) {
+  return pc >= base::android::kStartOfText && pc < executable_end_addr();
+}
+
+// static
 uintptr_t CFIBacktraceAndroid::executable_start_addr() {
   return reinterpret_cast<uintptr_t>(&__executable_start);
 }
 
 // static
 uintptr_t CFIBacktraceAndroid::executable_end_addr() {
-  return reinterpret_cast<uintptr_t>(&_etext);
+  return base::android::kEndOfText;
 }
 
 CFIBacktraceAndroid::CFIBacktraceAndroid()
diff --git a/base/trace_event/cfi_backtrace_android.h b/base/trace_event/cfi_backtrace_android.h
index 48eabb5e..6790812 100644
--- a/base/trace_event/cfi_backtrace_android.h
+++ b/base/trace_event/cfi_backtrace_android.h
@@ -36,9 +36,7 @@
   static CFIBacktraceAndroid* GetInitializedInstance();
 
   // Returns true if the given program counter |pc| is mapped in chrome library.
-  static bool is_chrome_address(uintptr_t pc) {
-    return pc >= executable_start_addr() && pc < executable_end_addr();
-  }
+  static bool is_chrome_address(uintptr_t pc);
 
   // Returns the start and end address of the current library.
   static uintptr_t executable_start_addr();
diff --git a/build/config/allocator.gni b/build/config/allocator.gni
index 6a144e1b..53a62fd 100644
--- a/build/config/allocator.gni
+++ b/build/config/allocator.gni
@@ -34,7 +34,7 @@
   use_partition_alloc = !is_ios
 
   # Use the new tcmalloc. It's relevant only when use_allocator == "tcmalloc".
-  use_new_tcmalloc = false
+  use_new_tcmalloc = is_linux && !is_chromeos
 }
 
 if (is_nacl) {
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 5e7636ae..6186f451 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1418,7 +1418,7 @@
     _enable_bytecode_rewriter =
         _enable_assert || _enable_custom_resources || _enable_thread_annotations
     _is_prebuilt = defined(invoker.is_prebuilt) && invoker.is_prebuilt
-    _enable_bytecode_checks = !defined(invoker.enable_bytecode_checks) ||
+    _enable_bytecode_checks = defined(invoker.enable_bytecode_checks) &&
                               invoker.enable_bytecode_checks
 
     # Release builds don't have asserts enabled, so they often will not run the
diff --git a/chrome/VERSION b/chrome/VERSION
index 45d9e05e1..8f184429 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=72
 MINOR=0
-BUILD=3600
+BUILD=3601
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java
index 1ae69ee..eaa1ede3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java
@@ -11,7 +11,6 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.PluralsRes;
 import android.text.TextUtils;
-import android.text.format.Formatter;
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
@@ -583,8 +582,8 @@
                             R.plurals.download_infobar_downloading_files, inProgressDownloadCount,
                             inProgressDownloadCount);
                 } else {
-                    String bytesString =
-                            Formatter.formatFileSize(getContext(), totalDownloadingSizeBytes);
+                    String bytesString = DownloadUtils.getStringForBytes(
+                            getContext(), totalDownloadingSizeBytes);
                     info.message = inProgressDownloadCount == 1
                             ? getContext().getString(
                                       R.string.downloading_file_with_bytes, bytesString)
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index f4d0116e..8e57b3d 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-72.0.3599.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-72.0.3600.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 5be16a3..5082a05 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1412,6 +1412,10 @@
      flag_descriptions::kWebrtcNewEncodeCpuLoadEstimatorName,
      flag_descriptions::kWebrtcNewEncodeCpuLoadEstimatorDescription, kOsAll,
      FEATURE_VALUE_TYPE(media::kNewEncodeCpuLoadEstimator)},
+    {"enable-webrtc-hide-local-ips-with-mdns",
+     flag_descriptions::kWebrtcHideLocalIpsWithMdnsName,
+     flag_descriptions::kWebrtcHideLocalIpsWithMdnsDecription, kOsDesktop,
+     FEATURE_VALUE_TYPE(features::kWebRtcHideLocalIpsWithMdns)},
     {"webrtc-unified-plan-by-default",
      flag_descriptions::kWebrtcUnifiedPlanByDefaultName,
      flag_descriptions::kWebrtcUnifiedPlanByDefaultDescription, kOsAll,
@@ -3072,6 +3076,14 @@
      kOsAll,
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillUpstreamEditableCardholderName)},
+    {"enable-autofill-credit-card-upload-editable-expiration-date",
+     flag_descriptions::
+         kEnableAutofillCreditCardUploadEditableExpirationDateName,
+     flag_descriptions::
+         kEnableAutofillCreditCardUploadEditableExpirationDateDescription,
+     kOsAll,
+     FEATURE_VALUE_TYPE(
+         autofill::features::kAutofillUpstreamEditableExpirationDate)},
     {"enable-autofill-credit-card-upload-google-pay-on-android-branding",
      flag_descriptions::
          kEnableAutofillCreditCardUploadGooglePayOnAndroidBrandingName,
@@ -4343,7 +4355,7 @@
 #endif  // OS_WIN
 
 #if !defined(OS_ANDROID)
-    {"happiness-tarcking-surveys-for-desktop",
+    {"happiness-tracking-surveys-for-desktop",
      flag_descriptions::kHappinessTrackingSurveysForDesktopName,
      flag_descriptions::kHappinessTrackingSurveysForDesktopDescription,
      kOsDesktop,
diff --git a/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.cc b/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.cc
index cd952d2..0824c4a3 100644
--- a/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.cc
@@ -30,11 +30,42 @@
 
 }  // namespace
 
+// Observes the note taking app widget so bounds changes can update the toast
+// position.
+class FirstAppRunToastManager::AppWidgetObserver
+    : public views::WidgetObserver {
+ public:
+  AppWidgetObserver(FirstAppRunToastManager* manager, views::Widget* widget)
+      : manager_(manager), widget_(widget) {
+    widget_->AddObserver(this);
+  }
+
+  ~AppWidgetObserver() override {
+    // This is a no-op of the observer was previously removed.
+    widget_->RemoveObserver(this);
+  }
+
+  // views::WidgetObserver:
+  void OnWidgetBoundsChanged(views::Widget* widget,
+                             const gfx::Rect& new_bounds) override {
+    manager_->AdjustToastWidgetBounds();
+  }
+
+  void OnWidgetDestroying(views::Widget* widget) override {
+    widget_->RemoveObserver(this);
+  }
+
+ private:
+  FirstAppRunToastManager* manager_;
+  views::Widget* widget_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppWidgetObserver);
+};
+
 FirstAppRunToastManager::FirstAppRunToastManager(Profile* profile)
     : profile_(profile),
       toast_widget_observer_(this),
       app_window_observer_(this),
-      native_app_window_observer_(this),
       weak_ptr_factory_(this) {}
 
 FirstAppRunToastManager::~FirstAppRunToastManager() {
@@ -59,7 +90,10 @@
   }
 
   app_window_ = app_window;
-  native_app_window_observer_.Add(app_window_->GetNativeWindow());
+  views::Widget* app_widget =
+      views::Widget::GetWidgetForNativeWindow(app_window_->GetNativeWindow());
+  DCHECK(app_widget);
+  app_widget_observer_ = std::make_unique<AppWidgetObserver>(this, app_widget);
 
   if (app_window_->GetNativeWindow()->HasFocus()) {
     CreateAndShowToastDialog();
@@ -70,7 +104,7 @@
 }
 
 void FirstAppRunToastManager::Reset() {
-  native_app_window_observer_.RemoveAll();
+  app_widget_observer_.reset();
   app_window_observer_.RemoveAll();
   toast_widget_observer_.RemoveAll();
 
@@ -101,15 +135,6 @@
   }
 }
 
-void FirstAppRunToastManager::OnWindowBoundsChanged(
-    aura::Window* window,
-    const gfx::Rect& old_bounds,
-    const gfx::Rect& new_bounds,
-    ui::PropertyChangeReason reason) {
-  if (toast_widget_ && window == app_window_->GetNativeWindow())
-    AdjustToastWidgetBounds();
-}
-
 void FirstAppRunToastManager::CreateAndShowToastDialog() {
   auto* toast_dialog = new ToastDialogView(
       base::UTF8ToUTF16(app_window_->GetExtension()->short_name()),
@@ -132,7 +157,9 @@
 }
 
 void FirstAppRunToastManager::AdjustToastWidgetBounds() {
-  DCHECK(toast_widget_);
+  if (!toast_widget_)
+    return;
+
   DCHECK(app_window_);
 
   const gfx::Rect app_window_bounds =
diff --git a/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.h b/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.h
index 065f094..f09aefc 100644
--- a/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.h
+++ b/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.h
@@ -28,7 +28,6 @@
 // dialog informing the user about the app that's been launched from the lock
 // screen.
 class FirstAppRunToastManager : public extensions::AppWindowRegistry::Observer,
-                                public aura::WindowObserver,
                                 public views::WidgetObserver {
  public:
   explicit FirstAppRunToastManager(Profile* profile);
@@ -48,12 +47,6 @@
   // views::WidgetObserver:
   void OnWidgetDestroyed(views::Widget* widget) override;
 
-  // aura::WindowObserver:
-  void OnWindowBoundsChanged(aura::Window* window,
-                             const gfx::Rect& old_bounds,
-                             const gfx::Rect& new_bounds,
-                             ui::PropertyChangeReason reason) override;
-
   // extensions::AppWindowRegistry::Observer:
   void OnAppWindowActivated(extensions::AppWindow* app_window) override;
 
@@ -88,8 +81,9 @@
   ScopedObserver<extensions::AppWindowRegistry,
                  extensions::AppWindowRegistry::Observer>
       app_window_observer_;
-  ScopedObserver<aura::Window, aura::WindowObserver>
-      native_app_window_observer_;
+
+  class AppWidgetObserver;
+  std::unique_ptr<AppWidgetObserver> app_widget_observer_;
 
   base::WeakPtrFactory<FirstAppRunToastManager> weak_ptr_factory_;
 
diff --git a/chrome/browser/chromeos/lock_screen_apps/note_taking_browsertest.cc b/chrome/browser/chromeos/lock_screen_apps/note_taking_browsertest.cc
index 5062e812..7806b50 100644
--- a/chrome/browser/chromeos/lock_screen_apps/note_taking_browsertest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/note_taking_browsertest.cc
@@ -17,10 +17,13 @@
 #include "chromeos/chromeos_switches.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
+#include "extensions/browser/app_window/app_window.h"
+#include "extensions/browser/app_window/native_app_window.h"
 #include "extensions/common/api/app_runtime.h"
 #include "extensions/common/switches.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/result_catcher.h"
+#include "ui/aura/test/mus/change_completion_waiter.h"
 
 namespace {
 
@@ -146,6 +149,20 @@
       return false;
     }
 
+    // By this point the app window is created on the lock screen. Ensure the
+    // asynchronous window maximize from ash completes.
+    aura::test::WaitForAllChangesToComplete();
+    extensions::AppWindow* app_window =
+        lock_screen_apps::StateController::Get()->note_app_window_for_test();
+    if (!app_window) {
+      *error = "No app window";
+      return false;
+    }
+    if (!app_window->GetBaseWindow()->IsMaximized()) {
+      *error = "App window not maximized";
+      return false;
+    }
+
     // Close the app window created by the API test.
     ready_to_close.Reply("close");
 
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.h b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
index bb0ba20..b7f584d 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.h
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
@@ -108,6 +108,7 @@
   // |SetPrimaryProfile|
   void SetLockScreenLockScreenProfileCreatorForTesting(
       std::unique_ptr<LockScreenProfileCreator> profile_creator);
+  extensions::AppWindow* note_app_window_for_test() { return note_app_window_; }
 
   // Initializes mojo bindings for the StateController - it creates binding to
   // ash's tray action interface and sets this object as the interface's client.
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 3044cea..992b02e 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -403,6 +403,13 @@
     "offer-to-save dialog, which is prefilled with the name from the signed-in "
     "Google Account.";
 
+const char kEnableAutofillCreditCardUploadEditableExpirationDateName[] =
+    "Make expiration date editable in dialog during credit card upload";
+const char kEnableAutofillCreditCardUploadEditableExpirationDateDescription[] =
+    "If enabled, if a credit card's expiration date was not detected when "
+    "offering card upload to Google Payments, the offer-to-save dialog "
+    "displays an expiration date selector.";
+
 const char kEnableAutofillCreditCardUploadGooglePayOnAndroidBrandingName[] =
     "Enable Google Pay branding when offering credit card upload on Android";
 const char
@@ -2068,6 +2075,11 @@
 const char kWebrtcEchoCanceller3Description[] =
     "Experimental WebRTC echo canceller (AEC3).";
 
+const char kWebrtcHideLocalIpsWithMdnsName[] =
+    "Anonymize local IPs exposed by WebRTC.";
+const char kWebrtcHideLocalIpsWithMdnsDecription[] =
+    "Conceal local IP addresses with mDNS hostnames.";
+
 const char kWebrtcHybridAgcName[] = "WebRTC hybrid Agc2/Agc1.";
 const char kWebrtcHybridAgcDescription[] =
     "WebRTC Agc2 digital adaptation with Agc1 analog adaptation.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 5f9594e..ff171832 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -271,6 +271,10 @@
 extern const char
     kEnableAutofillCreditCardUploadEditableCardholderNameDescription[];
 
+extern const char kEnableAutofillCreditCardUploadEditableExpirationDateName[];
+extern const char
+    kEnableAutofillCreditCardUploadEditableExpirationDateDescription[];
+
 extern const char
     kEnableAutofillCreditCardUploadGooglePayOnAndroidBrandingName[];
 extern const char
@@ -1244,6 +1248,9 @@
 extern const char kWebrtcEchoCanceller3Name[];
 extern const char kWebrtcEchoCanceller3Description[];
 
+extern const char kWebrtcHideLocalIpsWithMdnsName[];
+extern const char kWebrtcHideLocalIpsWithMdnsDecription[];
+
 extern const char kWebrtcHybridAgcName[];
 extern const char kWebrtcHybridAgcDescription[];
 
diff --git a/chrome/browser/notifications/win/mock_notification_image_retainer.h b/chrome/browser/notifications/win/mock_notification_image_retainer.h
index 154e5fa..776ff61 100644
--- a/chrome/browser/notifications/win/mock_notification_image_retainer.h
+++ b/chrome/browser/notifications/win/mock_notification_image_retainer.h
@@ -10,7 +10,7 @@
 
 namespace gfx {
 class Image;
-}
+}  // namespace gfx
 
 // A mock NotificationImageRetainer class for use with unit tests. Returns
 // predictable paths to callers wanting to register temporary files.
diff --git a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
index 72f6e44..bc357f0 100644
--- a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
+++ b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
@@ -60,6 +60,7 @@
           WebFeature::kDocumentDomainEnabledCrossOriginAccess,
           WebFeature::kSuppressHistoryEntryWithoutUserGesture,
           WebFeature::kCursorImageGT32x32, WebFeature::kCursorImageLE32x32,
+          WebFeature::kHistoryPushState, WebFeature::kHistoryReplaceState,
       }));
   return opt_in_features->count(feature);
 }
diff --git a/chrome/browser/resources/md_extensions/BUILD.gn b/chrome/browser/resources/md_extensions/BUILD.gn
index c1c8982..416dfc3 100644
--- a/chrome/browser/resources/md_extensions/BUILD.gn
+++ b/chrome/browser/resources/md_extensions/BUILD.gn
@@ -56,6 +56,7 @@
     ":drag_and_drop_handler",
     ":drop_overlay",
     ":error_page",
+    ":host_permissions_toggle_list",
     ":install_warnings_dialog",
     ":item",
     ":item_behavior",
@@ -145,6 +146,13 @@
   ]
 }
 
+js_library("host_permissions_toggle_list") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [ "$externs_path/developer_private.js" ]
+}
+
 js_library("install_warnings_dialog") {
   deps = [
     "//ui/webui/resources/js:cr",
diff --git a/chrome/browser/resources/md_extensions/detail_view.html b/chrome/browser/resources/md_extensions/detail_view.html
index 98315e4b..137ce6d 100644
--- a/chrome/browser/resources/md_extensions/detail_view.html
+++ b/chrome/browser/resources/md_extensions/detail_view.html
@@ -20,6 +20,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
 <link rel="import" href="item_behavior.html">
 <link rel="import" href="item_util.html">
+<link rel="import" href="host_permissions_toggle_list.html">
 <link rel="import" href="navigation_helper.html">
 <link rel="import" href="runtime_host_permissions.html">
 <link rel="import" href="strings.html">
@@ -166,6 +167,13 @@
         border-top: var(--cr-separator-line);
       }
 
+      extensions-toggle-row {
+        @apply --cr-section;
+        padding-inline-end: 0;
+        padding-inline-start: 0;
+        --toggle-row-label-padding: var(--cr-section-padding);
+      }
+
       #load-path {
         word-break: break-all;
       }
@@ -329,13 +337,22 @@
                 </li>
               </template>
             </ul>
-            <template is="dom-if" if="[[hasRuntimeHostPermissions_(data.*)]]">
+            <template is="dom-if"
+                if="[[showFreeformRuntimeHostPermissions_(data.*)]]">
               <extensions-runtime-host-permissions
                   permissions="[[data.permissions.runtimeHostPermissions]]"
                   delegate="[[delegate]]"
                   item-id="[[data.id]]">
               </extensions-runtime-host-permissions>
             </template>
+            <template is="dom-if"
+                if="[[showHostPermissionsToggleList_(data.*)]]">
+              <extensions-host-permissions-toggle-list
+                  permissions="[[data.permissions.runtimeHostPermissions]]"
+                  delegate="[[delegate]]"
+                  item-id="[[data.id]]">
+              </extensions-host-permissions-toggle-list>
+            </template>
           </div>
         </div>
         <template is="dom-if"
diff --git a/chrome/browser/resources/md_extensions/detail_view.js b/chrome/browser/resources/md_extensions/detail_view.js
index 327a7c4..77ee5467 100644
--- a/chrome/browser/resources/md_extensions/detail_view.js
+++ b/chrome/browser/resources/md_extensions/detail_view.js
@@ -302,6 +302,24 @@
     hasRuntimeHostPermissions_: function() {
       return !!this.data.permissions.runtimeHostPermissions;
     },
+
+    /**
+     * @return {boolean}
+     * @private
+     */
+    showFreeformRuntimeHostPermissions_: function() {
+      return this.hasRuntimeHostPermissions_() &&
+          this.data.permissions.runtimeHostPermissions.hasAllHosts;
+    },
+
+    /**
+     * @return {boolean}
+     * @private
+     */
+    showHostPermissionsToggleList_: function() {
+      return this.hasRuntimeHostPermissions_() &&
+          !this.data.permissions.runtimeHostPermissions.hasAllHosts;
+    },
   });
 
   return {DetailView: DetailView};
diff --git a/chrome/browser/resources/md_extensions/extensions_resources.grd b/chrome/browser/resources/md_extensions/extensions_resources.grd
index f150f3a..df243d2d 100644
--- a/chrome/browser/resources/md_extensions/extensions_resources.grd
+++ b/chrome/browser/resources/md_extensions/extensions_resources.grd
@@ -123,6 +123,12 @@
       <structure name="IDR_MD_EXTENSIONS_LOAD_ERROR_JS"
                  file="load_error.js"
                  type="chrome_html" />
+      <structure name="IDR_MD_EXTENSIONS_HOST_PERMISSIONS_TOGGLE_LIST_HMTL"
+                 file="host_permissions_toggle_list.html"
+                 type="chrome_html" />
+      <structure name="IDR_MD_EXTENSIONS_HOST_PERMISSIONS_TOGGLE_LIST_JS"
+                 file="host_permissions_toggle_list.js"
+                 type="chrome_html" />
       <structure name="IDR_MD_EXTENSIONS_NAVIGATION_HELPER_HTML"
                  file="navigation_helper.html"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html b/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html
new file mode 100644
index 0000000..7255fab
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html
@@ -0,0 +1,60 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="toggle_row.html">
+<link rel="import" href="strings.html">
+
+<dom-module id="extensions-host-permissions-toggle-list">
+  <template>
+    <style include="cr-shared-style">
+      #section-heading {
+        color: var(--cr-primary-text-color);
+        margin-top: 12px;
+      }
+
+      a[href] {
+        color: var(--google-blue-700);
+        text-decoration: none;
+      }
+
+      extensions-toggle-row {
+        color: black;
+      }
+
+      .toggle-section {
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        min-height: var(--cr-section-min-height);
+      }
+
+      .site-toggle {
+        border-top: var(--cr-separator-line);
+        margin-inline-start: var(--cr-section-indent-width);
+      }
+    </style>
+    <div id="section-heading">$i18n{hostPermissionsHeading}</div>
+    <div class="toggle-section">
+      <extensions-toggle-row checked="[[allowedOnAllHosts_(permissions.*)]]"
+          id="allHostsToggle"
+          on-change="onAllHostsToggleChanged_">
+        <span>$i18n{itemAllowOnAllSites}</span>
+      </extensions-toggle-row>
+    </div>
+    <template is="dom-repeat" items="[[getSortedHosts_(permissions.*)]]">
+      <div class="toggle-section site-toggle">
+        <extensions-toggle-row checked="[[item.granted]]"
+            class="host-toggle no-end-padding"
+            disabled="[[allowedOnAllHosts_(permissions.*)]]"
+            host="[[item.host]]"
+            on-change="onHostAccessChanged_">
+          <span>[[item.host]]</span>
+        </extensions-toggle-row>
+      </div>
+    </template>
+    <div>$i18nRaw{hostPermissionsLearnMoreLink}</div>
+  </template>
+  <script src="host_permissions_toggle_list.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/md_extensions/host_permissions_toggle_list.js b/chrome/browser/resources/md_extensions/host_permissions_toggle_list.js
new file mode 100644
index 0000000..cab51dc
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/host_permissions_toggle_list.js
@@ -0,0 +1,80 @@
+// Copyright 2018 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.
+
+cr.define('extensions', function() {
+  'use strict';
+
+  const HostPermissionsToggleList = Polymer({
+    is: 'extensions-host-permissions-toggle-list',
+
+    properties: {
+      /**
+       * The underlying permissions data.
+       * @type {chrome.developerPrivate.RuntimeHostPermissions}
+       */
+      permissions: Object,
+
+      /** @private */
+      itemId: String,
+
+      /** @type {!extensions.ItemDelegate} */
+      delegate: Object,
+    },
+
+    /**
+     * @return {boolean} Whether the item is allowed to execute on all of its
+     *     requested sites.
+     * @private
+     */
+    allowedOnAllHosts_: function() {
+      return this.permissions.hostAccess ==
+          chrome.developerPrivate.HostAccess.ON_ALL_SITES;
+    },
+
+    /**
+     * Returns a lexicographically-sorted list of the hosts associated with this
+     * item.
+     * @return {!Array<!chrome.developerPrivate.SiteControl>}
+     * @private
+     */
+    getSortedHosts_: function() {
+      return this.permissions.hosts.sort((a, b) => {
+        if (a.host < b.host)
+          return -1;
+        if (a.host > b.host)
+          return 1;
+        return 0;
+      });
+    },
+
+    /** @private */
+    onAllHostsToggleChanged_: function() {
+      // TODO(devlin): In the case of going from all sites to specific sites,
+      // we'll withhold all sites (i.e., all specific site toggles will move to
+      // unchecked, and the user can check them individually). This is slightly
+      // different than the sync page, where disabling the "sync everything"
+      // switch leaves everything synced, and user can uncheck them
+      // individually. It could be nice to align on behavior, but probably not
+      // super high priority.
+      this.delegate.setItemHostAccess(
+          this.itemId,
+          this.$.allHostsToggle.checked ?
+              chrome.developerPrivate.HostAccess.ON_ALL_SITES :
+              chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES);
+    },
+
+    /** @private */
+    onHostAccessChanged_: function(e) {
+      const host = e.target.host;
+      const checked = e.target.checked;
+
+      if (checked)
+        this.delegate.addRuntimeHostPermission(this.itemId, host);
+      else
+        this.delegate.removeRuntimeHostPermission(this.itemId, host);
+    },
+  });
+
+  return {HostPermissionsToggleList: HostPermissionsToggleList};
+});
diff --git a/chrome/browser/resources/md_extensions/toggle_row.html b/chrome/browser/resources/md_extensions/toggle_row.html
index c847dbf..6f963b43 100644
--- a/chrome/browser/resources/md_extensions/toggle_row.html
+++ b/chrome/browser/resources/md_extensions/toggle_row.html
@@ -7,10 +7,7 @@
   <template>
     <style>
       :host {
-        @apply --cr-section;
         flex-direction: column;
-        padding-left: 0;
-        padding-right: 0;
         touch-action: none;
       }
 
@@ -24,7 +21,7 @@
         cursor: pointer;
         display: flex;
         flex: 1;
-        padding: 0 var(--cr-section-padding);
+        padding: 0 var(--toggle-row-label-padding, 0);
         width: 100%;
       }
 
@@ -39,10 +36,11 @@
     </style>
     <label id="label">
       <input id="native" type="checkbox" checked="[[checked]]"
-          on-change="onNativeChange_" on-click="onNativeClick_">
+          on-change="onNativeChange_" on-click="onNativeClick_"
+          disabled="[[disabled]]">
       <slot></slot>
       <cr-toggle id="crToggle" checked="{{checked}}" aria-labelledby="label"
-          on-change="onCrToggleChange_"></cr-toggle>
+          on-change="onCrToggleChange_" disabled="[[disabled]]"></cr-toggle>
     </label>
   </template>
   <script src="toggle_row.js"></script>
diff --git a/chrome/browser/resources/md_extensions/toggle_row.js b/chrome/browser/resources/md_extensions/toggle_row.js
index 1b5de89..d1786a77 100644
--- a/chrome/browser/resources/md_extensions/toggle_row.js
+++ b/chrome/browser/resources/md_extensions/toggle_row.js
@@ -15,6 +15,8 @@
 
     properties: {
       checked: Boolean,
+
+      disabled: Boolean,
     },
 
     /**
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 81c2bc90..6d70ed0 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3085,14 +3085,10 @@
       "app_list/extension_uninstaller.h",
       "app_list/md_icon_normalizer.cc",
       "app_list/md_icon_normalizer.h",
-      "app_list/search/answer_card/answer_card_contents.cc",
-      "app_list/search/answer_card/answer_card_contents.h",
       "app_list/search/answer_card/answer_card_result.cc",
       "app_list/search/answer_card/answer_card_result.h",
       "app_list/search/answer_card/answer_card_search_provider.cc",
       "app_list/search/answer_card/answer_card_search_provider.h",
-      "app_list/search/answer_card/answer_card_web_contents.cc",
-      "app_list/search/answer_card/answer_card_web_contents.h",
       "app_list/search/app_result.cc",
       "app_list/search/app_result.h",
       "app_list/search/app_search_provider.cc",
diff --git a/chrome/browser/ui/DEPS b/chrome/browser/ui/DEPS
index 799b5c347..e17e0d6 100644
--- a/chrome/browser/ui/DEPS
+++ b/chrome/browser/ui/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "-chrome/browser/ui/views",
   "+mash/public/mojom",
+  "+services/content/public",
   "+services/device/public/mojom",
 ]
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.cc b/chrome/browser/ui/app_list/app_list_client_impl.cc
index c381248..90580f08 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl.cc
@@ -36,6 +36,7 @@
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "content/public/common/service_manager_connection.h"
 #include "extensions/common/extension.h"
+#include "services/content/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/base/models/menu_model.h"
 #include "ui/display/display.h"
@@ -201,22 +202,6 @@
   app_list_visible_ = visible;
 }
 
-void AppListClientImpl::StartVoiceInteractionSession() {
-  auto* service =
-      arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(
-          ChromeLauncherController::instance()->profile());
-  if (service)
-    service->StartSessionFromUserInteraction(gfx::Rect());
-}
-
-void AppListClientImpl::ToggleVoiceInteractionSession() {
-  auto* service =
-      arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(
-          ChromeLauncherController::instance()->profile());
-  if (service)
-    service->ToggleSessionFromUserInteraction();
-}
-
 void AppListClientImpl::OnFolderCreated(
     ash::mojom::AppListItemMetadataPtr item) {
   if (!model_updater_)
@@ -253,6 +238,30 @@
   model_updater_->OnPageBreakItemDeleted(id);
 }
 
+void AppListClientImpl::StartVoiceInteractionSession() {
+  auto* service =
+      arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(
+          ChromeLauncherController::instance()->profile());
+  if (service)
+    service->StartSessionFromUserInteraction(gfx::Rect());
+}
+
+void AppListClientImpl::ToggleVoiceInteractionSession() {
+  auto* service =
+      arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(
+          ChromeLauncherController::instance()->profile());
+  if (service)
+    service->ToggleSessionFromUserInteraction();
+}
+
+void AppListClientImpl::GetNavigableContentsFactory(
+    content::mojom::NavigableContentsFactoryRequest request) {
+  if (profile_) {
+    content::BrowserContext::GetConnectorFor(profile_)->BindInterface(
+        content::mojom::kServiceName, std::move(request));
+  }
+}
+
 void AppListClientImpl::ActiveUserChanged(
     const user_manager::User* active_user) {
   if (!active_user->is_profile_created())
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.h b/chrome/browser/ui/app_list/app_list_client_impl.h
index c9745de..952ce63 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.h
+++ b/chrome/browser/ui/app_list/app_list_client_impl.h
@@ -65,18 +65,18 @@
   void ContextMenuItemSelected(const std::string& id,
                                int command_id,
                                int event_flags) override;
-
   void OnAppListTargetVisibilityChanged(bool visible) override;
   void OnAppListVisibilityChanged(bool visible) override;
-  void StartVoiceInteractionSession() override;
-  void ToggleVoiceInteractionSession() override;
-
   void OnFolderCreated(ash::mojom::AppListItemMetadataPtr item) override;
   void OnFolderDeleted(ash::mojom::AppListItemMetadataPtr item) override;
   void OnItemUpdated(ash::mojom::AppListItemMetadataPtr item) override;
   void OnPageBreakItemAdded(const std::string& id,
                             const syncer::StringOrdinal& position) override;
   void OnPageBreakItemDeleted(const std::string& id) override;
+  void StartVoiceInteractionSession() override;
+  void ToggleVoiceInteractionSession() override;
+  void GetNavigableContentsFactory(
+      content::mojom::NavigableContentsFactoryRequest request) override;
 
   // user_manager::UserManager::UserSessionStateObserver:
   void ActiveUserChanged(const user_manager::User* active_user) override;
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_contents.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_contents.cc
deleted file mode 100644
index c7b9fef..0000000
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_contents.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h"
-
-#include "chrome/browser/ui/app_list/search/answer_card/answer_card_result.h"
-
-namespace app_list {
-
-AnswerCardContents::AnswerCardContents() {}
-
-AnswerCardContents::~AnswerCardContents() {
-  for (auto& result : results_)
-    result.OnContentsDestroying();
-}
-
-void AnswerCardContents::SetDelegate(Delegate* delegate) {
-  DCHECK(delegate);
-  DCHECK(!delegate_);
-  delegate_ = delegate;
-}
-
-void AnswerCardContents::RegisterResult(AnswerCardResult* result) {
-  results_.AddObserver(result);
-}
-
-void AnswerCardContents::UnregisterResult(AnswerCardResult* result) {
-  results_.RemoveObserver(result);
-}
-
-}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h b/chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h
deleted file mode 100644
index 9a8c67d..0000000
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_ANSWER_CARD_ANSWER_CARD_CONTENTS_H_
-#define CHROME_BROWSER_UI_APP_LIST_SEARCH_ANSWER_CARD_ANSWER_CARD_CONTENTS_H_
-
-#include <string>
-
-#include "base/observer_list.h"
-#include "base/unguessable_token.h"
-
-namespace gfx {
-class Size;
-}  // namespace gfx
-
-class GURL;
-
-namespace app_list {
-
-class AnswerCardResult;
-
-// Abstract source of contents for AnswerCardSearchProvider.
-class AnswerCardContents {
- public:
-  // Delegate handling contents-related events.
-  class Delegate {
-   public:
-    Delegate() {}
-
-    // Events that the delegate processes. They have same meaning as same-named
-    // events in WebContentsDelegate and WebContentsObserver, however,
-    // unnecessary parameters are omitted.
-    virtual void UpdatePreferredSize(const AnswerCardContents* source) = 0;
-    virtual void DidFinishNavigation(const AnswerCardContents* source,
-                                     const GURL& url,
-                                     bool has_error,
-                                     bool has_answer_card,
-                                     const std::string& result_title,
-                                     const std::string& issued_query) = 0;
-
-    // Invoked when |source| is ready to be shown.
-    virtual void OnContentsReady(const AnswerCardContents* source) = 0;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Delegate);
-  };
-
-  AnswerCardContents();
-  virtual ~AnswerCardContents();
-
-  // Loads contents from |url|.
-  virtual void LoadURL(const GURL& url) = 0;
-
-  // Returns the token associated with the contents.
-  virtual const base::UnguessableToken& GetToken() const = 0;
-
-  // Returns the preferred contents size.
-  virtual gfx::Size GetPreferredSize() const = 0;
-
-  // Sets the delegate to process contents-related events.
-  void SetDelegate(Delegate* delegate);
-
-  // Registers a result that will be notified of input events for the view.
-  void RegisterResult(AnswerCardResult* result);
-
-  // Unregisters a result.
-  void UnregisterResult(AnswerCardResult* result);
-
- protected:
-  Delegate* delegate() const { return delegate_; }
-
- private:
-  // Results receiving input events.
-  base::ObserverList<AnswerCardResult>::Unchecked results_;
-  // Unowned delegate that handles content-related events.
-  Delegate* delegate_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(AnswerCardContents);
-};
-
-}  // namespace app_list
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_ANSWER_CARD_ANSWER_CARD_CONTENTS_H_
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_result.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_result.cc
index 8335043..4892837 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_result.cc
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_result.cc
@@ -4,45 +4,27 @@
 
 #include "chrome/browser/ui/app_list/search/answer_card/answer_card_result.h"
 
-#include "base/unguessable_token.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
-#include "chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h"
 #include "chrome/browser/ui/app_list/search/search_util.h"
 
 namespace app_list {
 
 AnswerCardResult::AnswerCardResult(Profile* profile,
                                    AppListControllerDelegate* list_controller,
-                                   const std::string& result_url,
-                                   const std::string& stripped_result_url,
-                                   const base::string16& result_title,
-                                   AnswerCardContents* contents)
-    : profile_(profile),
-      list_controller_(list_controller),
-      contents_(contents) {
-  DCHECK(!stripped_result_url.empty());
+                                   const GURL& potential_card_url,
+                                   const GURL& search_result_url,
+                                   const GURL& stripped_search_result_url)
+    : profile_(profile), list_controller_(list_controller) {
+  DCHECK(!stripped_search_result_url.is_empty());
   SetDisplayType(ash::SearchResultDisplayType::kCard);
   SetResultType(ash::SearchResultType::kAnswerCard);
-  set_id(result_url);
-  set_comparable_id(stripped_result_url);
+  SetQueryUrl(potential_card_url);
+  set_id(search_result_url.spec());
+  set_comparable_id(stripped_search_result_url.spec());
   set_relevance(1);
-  SetAnswerCardContentsToken(contents ? contents->GetToken()
-                                      : base::UnguessableToken());
-  SetAnswerCardSize(contents ? contents->GetPreferredSize() : gfx::Size());
-  SetTitle(result_title);
-
-  if (contents)
-    contents->RegisterResult(this);
 }
 
-AnswerCardResult::~AnswerCardResult() {
-  if (contents_)
-    contents_->UnregisterResult(this);
-}
-
-void AnswerCardResult::OnContentsDestroying() {
-  contents_ = nullptr;
-}
+AnswerCardResult::~AnswerCardResult() = default;
 
 void AnswerCardResult::Open(int event_flags) {
   list_controller_->OpenURL(profile_, GURL(id()), ui::PAGE_TRANSITION_GENERATED,
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_result.h b/chrome/browser/ui/app_list/search/answer_card/answer_card_result.h
index 033fc6c..9891c06c 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_result.h
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_result.h
@@ -9,34 +9,29 @@
 #include <string>
 
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
+#include "url/gurl.h"
 
 class AppListControllerDelegate;
 class Profile;
 
 namespace app_list {
 
-class AnswerCardContents;
-
 // Result of AnswerCardSearchProvider.
 class AnswerCardResult : public ChromeSearchResult {
  public:
   AnswerCardResult(Profile* profile,
                    AppListControllerDelegate* list_controller,
-                   const std::string& result_url,
-                   const std::string& stripped_result_url,
-                   const base::string16& result_title,
-                   AnswerCardContents* contents);
+                   const GURL& potential_card_url,
+                   const GURL& search_result_url,
+                   const GURL& stripped_search_result_url);
 
   ~AnswerCardResult() override;
 
-  void OnContentsDestroying();
-
   void Open(int event_flags) override;
 
  private:
   Profile* const profile_;                            // Unowned
   AppListControllerDelegate* const list_controller_;  // Unowned
-  AnswerCardContents* contents_;                      // Unowned
 
   DISALLOW_COPY_AND_ASSIGN(AnswerCardResult);
 };
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_result_unittest.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_result_unittest.cc
index 8c2d1a7..49ae4d8 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_result_unittest.cc
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_result_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/app_list/app_list_test_util.h"
-#include "chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h"
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
 #include "chrome/test/base/testing_profile.h"
 #include "ui/views/view.h"
@@ -19,62 +18,40 @@
 
 namespace {
 
-constexpr char kResultUrl[] =
+constexpr char kSearchResultUrl[] =
     "http://www.google.com/search?q=weather&strippable_part=something";
-constexpr char kResultUrlStripped[] = "http://google.com/search?q=weather";
-constexpr char kResultTitle[] = "The weather is fine";
-
-class AnswerCardTestContents : public AnswerCardContents {
- public:
-  AnswerCardTestContents() {}
-
-  // AnswerCardContents overrides:
-  void LoadURL(const GURL& url) override { NOTREACHED(); }
-  const base::UnguessableToken& GetToken() const override { return token_; }
-  gfx::Size GetPreferredSize() const override { return gfx::Size(); }
-
- private:
-  base::UnguessableToken token_;
-
-  DISALLOW_COPY_AND_ASSIGN(AnswerCardTestContents);
-};
+constexpr char kStrippedSearchResultUrl[] =
+    "http://google.com/search?q=weather";
+constexpr char kCardUrl[] = "http://google.com/coac?q=weather";
 
 }  // namespace
 
 class AnswerCardResultTest : public AppListTestBase {
  public:
-  AnswerCardResultTest() {}
-
-  void DeleteContents() { contents_.reset(nullptr); }
+  AnswerCardResultTest() = default;
 
   std::unique_ptr<AnswerCardResult> CreateResult(
-      const std::string& result_url,
-      const std::string& stripped_result_url,
-      const base::string16& result_title) const {
+      const GURL& potential_card_url,
+      const GURL& search_result_url,
+      const GURL& stripped_search_result_url) const {
     return std::make_unique<AnswerCardResult>(
-        profile_.get(), app_list_controller_delegate_.get(), result_url,
-        stripped_result_url, result_title, contents_.get());
+        profile_.get(), app_list_controller_delegate_.get(), potential_card_url,
+        search_result_url, stripped_search_result_url);
   }
 
   const GURL& GetLastOpenedUrl() const {
     return app_list_controller_delegate_->last_opened_url();
   }
 
-  const base::UnguessableToken& GetToken() const {
-    return contents_->GetToken();
-  }
-
   // AppListTestBase overrides:
   void SetUp() override {
     AppListTestBase::SetUp();
 
-    contents_ = std::make_unique<AnswerCardTestContents>();
     app_list_controller_delegate_ =
         std::make_unique<::test::TestAppListControllerDelegate>();
   }
 
  private:
-  std::unique_ptr<AnswerCardTestContents> contents_;
   std::unique_ptr<::test::TestAppListControllerDelegate>
       app_list_controller_delegate_;
 
@@ -83,32 +60,16 @@
 
 TEST_F(AnswerCardResultTest, Basic) {
   std::unique_ptr<AnswerCardResult> result = CreateResult(
-      kResultUrl, kResultUrlStripped, base::ASCIIToUTF16(kResultTitle));
+      GURL(kCardUrl), GURL(kSearchResultUrl), GURL(kStrippedSearchResultUrl));
 
-  EXPECT_EQ(kResultUrl, result->id());
-  EXPECT_EQ(base::ASCIIToUTF16(kResultTitle), result->title());
+  EXPECT_EQ(kSearchResultUrl, result->id());
+  EXPECT_EQ(kStrippedSearchResultUrl, result->comparable_id());
+  EXPECT_EQ(kCardUrl, result->query_url()->spec());
   EXPECT_EQ(ash::SearchResultDisplayType::kCard, result->display_type());
   EXPECT_EQ(1, result->relevance());
-  EXPECT_EQ(GetToken(), result->answer_card_contents_token());
 
   result->Open(ui::EF_NONE);
-  EXPECT_EQ(kResultUrl, GetLastOpenedUrl().spec());
-}
-
-TEST_F(AnswerCardResultTest, NullContents) {
-  DeleteContents();
-
-  // Shouldn't crash with null contents.
-  std::unique_ptr<AnswerCardResult> result = CreateResult(
-      kResultUrl, kResultUrlStripped, base::ASCIIToUTF16(kResultTitle));
-}
-
-TEST_F(AnswerCardResultTest, EarlyDeleteContents) {
-  // Shouldn't crash with contents gets deleted while search result exists.
-  std::unique_ptr<AnswerCardResult> result = CreateResult(
-      kResultUrl, kResultUrlStripped, base::ASCIIToUTF16(kResultTitle));
-
-  DeleteContents();
+  EXPECT_EQ(kSearchResultUrl, GetLastOpenedUrl().spec());
 }
 
 }  // namespace test
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc
index 69698043..b561f665 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc
@@ -22,214 +22,60 @@
 
 namespace app_list {
 
-namespace {
-
-enum class SearchAnswerRequestResult {
-  REQUEST_RESULT_ANOTHER_REQUEST_STARTED = 0,
-  REQUEST_RESULT_REQUEST_FAILED = 1,
-  REQUEST_RESULT_NO_ANSWER = 2,
-  REQUEST_RESULT_RECEIVED_ANSWER = 3,
-  REQUEST_RESULT_RECEIVED_ANSWER_TOO_LARGE = 4,
-  REQUEST_RESULT_MAX = 5
-};
-
-void RecordRequestResult(SearchAnswerRequestResult request_result) {
-  UMA_HISTOGRAM_ENUMERATION("SearchAnswer.RequestResult", request_result,
-                            SearchAnswerRequestResult::REQUEST_RESULT_MAX);
-}
-
-}  // namespace
-
-AnswerCardSearchProvider::NavigationContext::NavigationContext() {}
-
-AnswerCardSearchProvider::NavigationContext::~NavigationContext() {}
-
-void AnswerCardSearchProvider::NavigationContext::StartServerRequest(
-    const GURL& url) {
-  contents->LoadURL(url);
-  state = RequestState::NO_RESULT;
-}
-
-void AnswerCardSearchProvider::NavigationContext::Clear() {
-  result_url.clear();
-  result_title.clear();
-  state = RequestState::NO_RESULT;
-  // We are not clearing |preferred_size| since the |contents| remains
-  // unchanged, and |preferred_size| always corresponds to the contents's size.
-}
-
 AnswerCardSearchProvider::AnswerCardSearchProvider(
     Profile* profile,
     AppListModelUpdater* model_updater,
-    AppListControllerDelegate* list_controller,
-    std::unique_ptr<AnswerCardContents> contents0,
-    std::unique_ptr<AnswerCardContents> contents1)
+    AppListControllerDelegate* list_controller)
     : profile_(profile),
       model_updater_(model_updater),
       list_controller_(list_controller),
       answer_server_url_(app_list_features::AnswerServerUrl()),
       template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)) {
-  navigation_contexts_[0].contents = std::move(contents0);
-  navigation_contexts_[1].contents = std::move(contents1);
-  navigation_contexts_[0].contents->SetDelegate(this);
-  navigation_contexts_[1].contents->SetDelegate(this);
 }
 
-AnswerCardSearchProvider::~AnswerCardSearchProvider() {
-}
+AnswerCardSearchProvider::~AnswerCardSearchProvider() = default;
 
 void AnswerCardSearchProvider::Start(const base::string16& query) {
-  // Reset the state.
-  current_request_url_ = GURL();
-  server_request_start_time_ = answer_loaded_time_ = base::TimeTicks();
-
-  if (query.empty() || !model_updater_->SearchEngineIsGoogle()) {
-    DeleteCurrentResult();
+  if (!model_updater_->SearchEngineIsGoogle()) {
+    UpdateQuery(base::string16());
     return;
   }
 
-  // Start a request to the answer server.
+  UpdateQuery(query);
+}
 
-  // Lifetime of |prefixed_query| should be longer than the one of
-  // |replacements|.
+void AnswerCardSearchProvider::UpdateQuery(const base::string16& query) {
+  if (query.empty()) {
+    ClearResults();
+    current_potential_answer_card_url_ = GURL();
+    return;
+  }
+
   const std::string prefixed_query(
       "q=" + net::EscapeQueryParamValue(base::UTF16ToUTF8(query), true) +
       app_list_features::AnswerServerQuerySuffix());
   GURL::Replacements replacements;
   replacements.SetQueryStr(prefixed_query);
-  current_request_url_ = answer_server_url_.ReplaceComponents(replacements);
-  GetNavigationContextForLoading().StartServerRequest(current_request_url_);
-
-  server_request_start_time_ = base::TimeTicks::Now();
-}
-
-void AnswerCardSearchProvider::UpdatePreferredSize(
-    const AnswerCardContents* source) {
-  if (source != GetCurrentNavigationContext().contents.get())
+  GURL potential_answer_card_url =
+      answer_server_url_.ReplaceComponents(replacements);
+  if (potential_answer_card_url == current_potential_answer_card_url_)
     return;
 
-  // Contents' size changed for the current card. Updating the result to cause
-  // relayout.
-  UpdateResult();
+  current_potential_answer_card_url_ = potential_answer_card_url;
+  GURL search_result_url =
+      GURL(template_url_service_->GetDefaultSearchProvider()
+               ->url_ref()
+               .ReplaceSearchTerms(TemplateURLRef::SearchTermsArgs(query),
+                                   template_url_service_->search_terms_data()));
+  const GURL stripped_search_result_url = AutocompleteMatch::GURLToStrippedGURL(
+      GURL(search_result_url), AutocompleteInput(), template_url_service_,
+      base::string16() /* keyword */);
 
-  if (!answer_loaded_time_.is_null()) {
-    UMA_HISTOGRAM_TIMES("SearchAnswer.ResizeAfterLoadTime",
-                        base::TimeTicks::Now() - answer_loaded_time_);
-  }
-}
-
-void AnswerCardSearchProvider::DidFinishNavigation(
-    const AnswerCardContents* source,
-    const GURL& url,
-    bool has_error,
-    bool has_answer_card,
-    const std::string& result_title,
-    const std::string& issued_query) {
-  NavigationContext& context_for_loading = GetNavigationContextForLoading();
-  DCHECK_EQ(source, context_for_loading.contents.get());
-
-  if (url != current_request_url_) {
-    RecordRequestResult(
-        SearchAnswerRequestResult::REQUEST_RESULT_ANOTHER_REQUEST_STARTED);
-    return;
-  }
-
-  if (has_error) {
-    RecordRequestResult(
-        SearchAnswerRequestResult::REQUEST_RESULT_REQUEST_FAILED);
-    // Loading new card has failed. This invalidates the currently shown result.
-    DeleteCurrentResult();
-    return;
-  }
-
-  if (!has_answer_card) {
-    RecordRequestResult(SearchAnswerRequestResult::REQUEST_RESULT_NO_ANSWER);
-    // No answer card in the server response. This invalidates the currently
-    // shown result.
-    DeleteCurrentResult();
-    return;
-  }
-  DCHECK(!result_title.empty());
-  DCHECK(!issued_query.empty());
-  context_for_loading.result_title = result_title;
-  context_for_loading.result_url =
-      GetResultUrl(base::UTF8ToUTF16(issued_query));
-  RecordRequestResult(
-      SearchAnswerRequestResult::REQUEST_RESULT_RECEIVED_ANSWER);
-
-  context_for_loading.state = RequestState::HAVE_RESULT_LOADING;
-  UMA_HISTOGRAM_TIMES("SearchAnswer.NavigationTime",
-                      base::TimeTicks::Now() - server_request_start_time_);
-}
-
-void AnswerCardSearchProvider::OnContentsReady(
-    const AnswerCardContents* source) {
-  NavigationContext& context_for_loading = GetNavigationContextForLoading();
-  DCHECK_EQ(source, context_for_loading.contents.get());
-
-  if (context_for_loading.state != RequestState::HAVE_RESULT_LOADING) {
-    // This stop-loading event is either for a navigation that was intercepted
-    // by another navigation, or for a failed navigation. In both cases, there
-    // is nothing we need to do about it.
-    return;
-  }
-
-  context_for_loading.state = RequestState::HAVE_RESULT_LOADED;
-
-  // Prepare for loading card into the other contents. Loading will start when
-  // the user modifies the query string.
-  GetCurrentNavigationContext().Clear();
-  current_navigation_context_ = 1 - current_navigation_context_;
-
-  // Show the result.
-  UpdateResult();
-
-  answer_loaded_time_ = base::TimeTicks::Now();
-  UMA_HISTOGRAM_TIMES("SearchAnswer.LoadingTime",
-                      answer_loaded_time_ - server_request_start_time_);
-}
-
-void AnswerCardSearchProvider::UpdateResult() {
   SearchProvider::Results results;
-
-  const NavigationContext& current_context = GetCurrentNavigationContext();
-  if (current_context.state == RequestState::HAVE_RESULT_LOADED) {
-    results.reserve(1);
-
-    const GURL stripped_result_url = AutocompleteMatch::GURLToStrippedGURL(
-        GURL(current_context.result_url), AutocompleteInput(),
-        template_url_service_, base::string16() /* keyword */);
-
-    results.emplace_back(std::make_unique<AnswerCardResult>(
-        profile_, list_controller_, current_context.result_url,
-        stripped_result_url.spec(),
-        base::UTF8ToUTF16(current_context.result_title),
-        current_context.contents.get()));
-  }
+  results.emplace_back(std::make_unique<AnswerCardResult>(
+      profile_, list_controller_, potential_answer_card_url, search_result_url,
+      stripped_search_result_url));
   SwapResults(&results);
 }
 
-std::string AnswerCardSearchProvider::GetResultUrl(
-    const base::string16& query) const {
-  return template_url_service_->GetDefaultSearchProvider()
-      ->url_ref()
-      .ReplaceSearchTerms(TemplateURLRef::SearchTermsArgs(query),
-                          template_url_service_->search_terms_data());
-}
-
-void AnswerCardSearchProvider::DeleteCurrentResult() {
-  GetCurrentNavigationContext().Clear();
-  UpdateResult();
-}
-
-AnswerCardSearchProvider::NavigationContext&
-AnswerCardSearchProvider::GetCurrentNavigationContext() {
-  return navigation_contexts_[current_navigation_context_];
-}
-
-AnswerCardSearchProvider::NavigationContext&
-AnswerCardSearchProvider::GetNavigationContextForLoading() {
-  return navigation_contexts_[1 - current_navigation_context_];
-}
-
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h
index 70b1993..f3b47fbe 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h
@@ -8,8 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/time/time.h"
-#include "chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
 #include "url/gurl.h"
 
@@ -21,69 +19,19 @@
 namespace app_list {
 
 // Search provider for the answer card.
-class AnswerCardSearchProvider : public SearchProvider,
-                                 public AnswerCardContents::Delegate {
+class AnswerCardSearchProvider : public SearchProvider {
  public:
   AnswerCardSearchProvider(Profile* profile,
                            AppListModelUpdater* model_updater,
-                           AppListControllerDelegate* list_controller,
-                           std::unique_ptr<AnswerCardContents> contents0,
-                           std::unique_ptr<AnswerCardContents> contents1);
+                           AppListControllerDelegate* list_controller);
 
   ~AnswerCardSearchProvider() override;
 
   // SearchProvider overrides:
   void Start(const base::string16& query) override;
 
-  // AnswerCardContents::Delegate overrides:
-  void UpdatePreferredSize(const AnswerCardContents* source) override;
-  void DidFinishNavigation(const AnswerCardContents* source,
-                           const GURL& url,
-                           bool has_error,
-                           bool has_answer_card,
-                           const std::string& result_title,
-                           const std::string& issued_query) override;
-  void OnContentsReady(const AnswerCardContents* source) override;
-
  private:
-  enum class RequestState {
-    NO_RESULT,
-    HAVE_RESULT_LOADING,
-    HAVE_RESULT_LOADED
-  };
-
-  // State of navigation for a single AnswerCardContents. There are 2 instances
-  // of AnswerCardContents: one is used to show the current answer, and the
-  // other for loading an answer for the next query. Once the answer has been
-  // loaded, the roles of contents instances get swapped.
-  struct NavigationContext {
-    NavigationContext();
-    ~NavigationContext();
-
-    void StartServerRequest(const GURL& url);
-    void Clear();
-
-    // The source of answer card contents.
-    std::unique_ptr<AnswerCardContents> contents;
-
-    // State of a server request.
-    RequestState state = RequestState::NO_RESULT;
-
-    // Url to open when the user clicks at the result.
-    std::string result_url;
-
-    // Title of the result.
-    std::string result_title;
-
-    DISALLOW_COPY_AND_ASSIGN(NavigationContext);
-  };
-
-  void UpdateResult();
-  // Returns Url to open when the user clicks at the result for |query|.
-  std::string GetResultUrl(const base::string16& query) const;
-  void DeleteCurrentResult();
-  NavigationContext& GetCurrentNavigationContext();
-  NavigationContext& GetNavigationContextForLoading();
+  void UpdateQuery(const base::string16& query);
 
   // Unowned pointer to the associated profile.
   Profile* const profile_;
@@ -94,27 +42,11 @@
   // Unowned pointer to app list controller.
   AppListControllerDelegate* const list_controller_;
 
-  // Index of the navigation contents corresponding to the current result. 1 -
-  // |current_navigation_context_| will be used for loading the next card, or is
-  // already used loading a new card. This pointer switches to the other
-  // contents after the card gets successfully loaded.
-  int current_navigation_context_ = 0;
-
-  // States of card navigation. one is used to show the current answer, and
-  // another for loading an answer for the next query.
-  NavigationContext navigation_contexts_[2];
-
   // If valid, URL of the answer server. Otherwise, search answers are disabled.
-  GURL answer_server_url_;
+  const GURL answer_server_url_;
 
-  // URL of the current answer server request.
-  GURL current_request_url_;
-
-  // Time when the current server request started.
-  base::TimeTicks server_request_start_time_;
-
-  // Time when the current server response loaded.
-  base::TimeTicks answer_loaded_time_;
+  // URL of the current answer server query.
+  GURL current_potential_answer_card_url_;
 
   // Unowned pointer to template URL service.
   TemplateURLService* const template_url_service_;
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc
index a0b1846c..552b68f 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
-#include "base/unguessable_token.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_test_util.h"
 #include "chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h"
@@ -25,13 +24,8 @@
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/search_engines/template_url_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using ::testing::_;
-using ::testing::Return;
-using ::testing::ReturnRef;
-
 namespace app_list {
 namespace test {
 
@@ -39,37 +33,18 @@
 
 constexpr char kQueryBase[] = "http://beasts.org/search";
 constexpr char kSomeParam[] = "&some_param=some_value";
-constexpr char kCatQuery[] = "cat";
 constexpr char kDogQuery[] = "dog";
 constexpr char kSharkQuery[] = "shark";
-constexpr char kCatCardId[] =
-    "https://www.google.com/search?q=cat&sourceid=chrome&ie=UTF-8";
 constexpr char kDogCardId[] =
     "https://www.google.com/search?q=dog&sourceid=chrome&ie=UTF-8";
 constexpr char kSharkCardId[] =
     "https://www.google.com/search?q=shark&sourceid=chrome&ie=UTF-8";
-constexpr char kCatCardTitle[] = "Cat is a furry beast.";
-constexpr char kDogCardTitle[] = "Dog is a friendly beast.";
-constexpr char kSharkCardTitle[] = "Shark is a scary beast.";
 
-GURL GetSearchUrl(const std::string& query) {
+GURL GetAnswerCardUrl(const std::string& query) {
   return GURL(
       base::StringPrintf("%s?q=%s%s", kQueryBase, query.c_str(), kSomeParam));
 }
 
-class MockAnswerCardContents : public AnswerCardContents {
- public:
-  MockAnswerCardContents() {}
-
-  // AnswerCardContents overrides:
-  MOCK_METHOD1(LoadURL, void(const GURL& url));
-  MOCK_CONST_METHOD0(GetToken, const base::UnguessableToken&());
-  MOCK_CONST_METHOD0(GetPreferredSize, gfx::Size());
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockAnswerCardContents);
-};
-
 std::unique_ptr<KeyedService> CreateTemplateURLService(
     content::BrowserContext* context) {
   return std::make_unique<TemplateURLService>(nullptr, 0);
@@ -81,57 +56,14 @@
  public:
   AnswerCardSearchProviderTest() : field_trial_list_(nullptr) {}
 
-  void TestDidFinishNavigation(int contents_number,
-                               bool has_error,
-                               bool has_answer_card,
-                               const std::string& title,
-                               const std::string& issued_query,
-                               std::size_t expected_result_count) {
-    MockAnswerCardContents* const contents =
-        contents_number == 0 ? contents0_ : contents1_;
-    EXPECT_CALL(*contents, LoadURL(GetSearchUrl(kCatQuery)));
-    provider()->Start(base::UTF8ToUTF16(kCatQuery));
-
-    provider()->DidFinishNavigation(contents, GetSearchUrl(kCatQuery),
-                                    has_error, has_answer_card, title,
-                                    issued_query);
-
-    provider()->OnContentsReady(contents);
-
-    EXPECT_EQ(expected_result_count, results().size());
-
-    testing::Mock::VerifyAndClearExpectations(contents);
-  }
-
-  void VerifyResult(const std::string& message,
-                    const std::string& id,
-                    const base::UnguessableToken& token,
-                    const std::string& title) {
-    SCOPED_TRACE(message);
-
-    EXPECT_EQ(1UL, results().size());
-    ChromeSearchResult* result = results()[0].get();
-    EXPECT_EQ(ash::SearchResultDisplayType::kCard, result->display_type());
-    EXPECT_EQ(id, result->id());
-    EXPECT_EQ(1, result->relevance());
-    EXPECT_EQ(token, result->answer_card_contents_token());
-    EXPECT_EQ(base::UTF8ToUTF16(title), result->title());
-  }
-
   FakeAppListModelUpdater* GetModelUpdater() const {
     return model_updater_.get();
   }
 
   const SearchProvider::Results& results() { return provider()->results(); }
 
-  MockAnswerCardContents* contents0() const { return contents0_; }
-  MockAnswerCardContents* contents1() const { return contents1_; }
-
   AnswerCardSearchProvider* provider() const { return provider_.get(); }
 
-  const base::UnguessableToken& token0() const { return token0_; }
-  const base::UnguessableToken& token1() const { return token1_; }
-
   // AppListTestBase overrides:
   void SetUp() override {
     AppListTestBase::SetUp();
@@ -155,281 +87,49 @@
         base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
     scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
 
-    contents0_ = new MockAnswerCardContents;
-    contents1_ = new MockAnswerCardContents;
-    std::unique_ptr<AnswerCardContents> contents0(contents0_);
-    std::unique_ptr<AnswerCardContents> contents1(contents1_);
     TemplateURLServiceFactory::GetInstance()->SetTestingFactory(
         profile_.get(), base::BindRepeating(&CreateTemplateURLService));
-    // Provider will own the MockAnswerCardContents instance.
     provider_ = std::make_unique<AnswerCardSearchProvider>(
-        profile_.get(), model_updater_.get(), nullptr, std::move(contents0),
-        std::move(contents1));
-
-    token0_ = base::UnguessableToken::Create();
-    token1_ = base::UnguessableToken::Create();
-
-    ON_CALL(*contents0_, GetToken()).WillByDefault(ReturnRef(token0()));
-    ON_CALL(*contents1_, GetToken()).WillByDefault(ReturnRef(token1()));
+        profile_.get(), model_updater_.get(), nullptr);
   }
 
  private:
   std::unique_ptr<FakeAppListModelUpdater> model_updater_;
   std::unique_ptr<AnswerCardSearchProvider> provider_;
   std::unique_ptr<::test::TestAppListControllerDelegate> controller_;
-  MockAnswerCardContents* contents0_ = nullptr;  // Unowned.
-  MockAnswerCardContents* contents1_ = nullptr;  // Unowned.
   base::FieldTrialList field_trial_list_;
   base::test::ScopedFeatureList scoped_feature_list_;
-  base::UnguessableToken token0_;
-  base::UnguessableToken token1_;
 
   DISALLOW_COPY_AND_ASSIGN(AnswerCardSearchProviderTest);
 };
 
-// Basic event sequence.
-TEST_F(AnswerCardSearchProviderTest, Basic) {
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(base::UTF8ToUTF16(kCatQuery));
-  provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
-                                  true, kCatCardTitle, kCatQuery);
-  provider()->OnContentsReady(contents1());
+// Basic usage. |Start()| immediately populates an appropriate search result to
+// be used by the client. A subsequent |Start()| call replaces the previous
+// result.
+TEST_F(AnswerCardSearchProviderTest, Start) {
+  provider()->Start(base::UTF8ToUTF16(kDogQuery));
+  ASSERT_EQ(1u, results().size());
+  EXPECT_EQ(kDogCardId, results()[0]->id());
+  EXPECT_EQ(GetAnswerCardUrl(kDogQuery), results()[0]->query_url()->spec());
 
-  VerifyResult("Basic Result", kCatCardId, token1(), kCatCardTitle);
-
-  // Now an empty query.
-  EXPECT_CALL(*contents0(), LoadURL(_)).Times(0);
-  provider()->Start(base::UTF8ToUTF16(""));
-  EXPECT_EQ(0UL, results().size());
+  provider()->Start(base::UTF8ToUTF16(kSharkQuery));
+  ASSERT_EQ(1u, results().size());
+  EXPECT_EQ(kSharkCardId, results()[0]->id());
+  EXPECT_EQ(GetAnswerCardUrl(kSharkQuery), results()[0]->query_url()->spec());
 }
 
 // Queries to non-Google search engines are ignored.
 TEST_F(AnswerCardSearchProviderTest, NotGoogle) {
   GetModelUpdater()->SetSearchEngineIsGoogle(false);
-  EXPECT_CALL(*contents1(), LoadURL(_)).Times(0);
-  provider()->Start(base::UTF8ToUTF16(kCatQuery));
-}
-
-// Three queries in a row.
-TEST_F(AnswerCardSearchProviderTest, ThreeQueries) {
-  // 1. Fetch for cat.
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(base::UTF8ToUTF16(kCatQuery));
-  provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
-                                  true, kCatCardTitle, kCatQuery);
-  provider()->OnContentsReady(contents1());
-
-  VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
-
-  // 2. Fetch for dog.
-  // Starting another (dog) search doesn't dismiss the cat card.
-  EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
   provider()->Start(base::UTF8ToUTF16(kDogQuery));
-
-  VerifyResult("Cat Result 2", kCatCardId, token1(), kCatCardTitle);
-
-  provider()->DidFinishNavigation(contents0(), GetSearchUrl(kDogQuery), false,
-                                  true, kDogCardTitle, kDogQuery);
-
-  // The cat still stays.
-  VerifyResult("Cat Result 3", kCatCardId, token1(), kCatCardTitle);
-
-  provider()->OnContentsReady(contents0());
-
-  // Once the dog finishes loading, it replaces the cat.
-  VerifyResult("Dog Result 1", kDogCardId, token0(), kDogCardTitle);
-
-  // 3. Fetch for shark.
-  // The third query will use contents1/token1 again.
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kSharkQuery)));
-  provider()->Start(base::UTF8ToUTF16(kSharkQuery));
-
-  VerifyResult("Dog Result 2", kDogCardId, token0(), kDogCardTitle);
-
-  provider()->DidFinishNavigation(contents1(), GetSearchUrl(kSharkQuery), false,
-                                  true, kSharkCardTitle, kSharkQuery);
-
-  VerifyResult("Dog Result 3", kDogCardId, token0(), kDogCardTitle);
-
-  provider()->OnContentsReady(contents1());
-
-  VerifyResult("Shark Result", kSharkCardId, token1(), kSharkCardTitle);
+  EXPECT_EQ(0u, results().size());
 }
 
-// Three queries in a row, second one fails due to an error.
-TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondErrors) {
-  // 1. Fetch for cat.
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(base::UTF8ToUTF16(kCatQuery));
-  provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
-                                  true, kCatCardTitle, kCatQuery);
-  provider()->OnContentsReady(contents1());
-
-  VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
-
-  // 2. Fetch for dog. This will fail with an error.
-  EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
-  provider()->Start(base::UTF8ToUTF16(kDogQuery));
-
-  VerifyResult("Cat Result 2", kCatCardId, token1(), kCatCardTitle);
-
-  provider()->DidFinishNavigation(contents0(), GetSearchUrl(kDogQuery), true,
-                                  false, "", "");
-
-  EXPECT_EQ(0UL, results().size());
-
-  provider()->OnContentsReady(contents0());
-
-  EXPECT_EQ(0UL, results().size());
-
-  // 3. Fetch for shark.
-  EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kSharkQuery)));
-  provider()->Start(base::UTF8ToUTF16(kSharkQuery));
-
-  EXPECT_EQ(0UL, results().size());
-
-  provider()->DidFinishNavigation(contents0(), GetSearchUrl(kSharkQuery), false,
-                                  true, kSharkCardTitle, kSharkQuery);
-
-  EXPECT_EQ(0UL, results().size());
-
-  provider()->OnContentsReady(contents0());
-
-  VerifyResult("Shark Result", kSharkCardId, token0(), kSharkCardTitle);
-}
-
-// Three queries in a row, second one fails because the server responds with no
-// card.
-TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondNoCard) {
-  // 1. Fetch for cat.
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(base::UTF8ToUTF16(kCatQuery));
-  provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
-                                  true, kCatCardTitle, kCatQuery);
-  provider()->OnContentsReady(contents1());
-
-  VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
-
-  // 2. Fetch for dog. This will fail with an error.
-  EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
-  provider()->Start(base::UTF8ToUTF16(kDogQuery));
-
-  VerifyResult("Cat Result 2", kCatCardId, token1(), kCatCardTitle);
-
-  provider()->DidFinishNavigation(contents0(), GetSearchUrl(kDogQuery), false,
-                                  false, "", "");
-
-  EXPECT_EQ(0UL, results().size());
-
-  provider()->OnContentsReady(contents0());
-
-  EXPECT_EQ(0UL, results().size());
-
-  // 3. Fetch for shark.
-  EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kSharkQuery)));
-  provider()->Start(base::UTF8ToUTF16(kSharkQuery));
-
-  EXPECT_EQ(0UL, results().size());
-
-  provider()->DidFinishNavigation(contents0(), GetSearchUrl(kSharkQuery), false,
-                                  true, kSharkCardTitle, kSharkQuery);
-
-  EXPECT_EQ(0UL, results().size());
-
-  provider()->OnContentsReady(contents0());
-
-  VerifyResult("Shark Result", kSharkCardId, token0(), kSharkCardTitle);
-}
-
-// User enters a query character by character, so that each next query generates
-// a web request while the previous one is still in progress. Only the last
-// query should produce a result.
-TEST_F(AnswerCardSearchProviderTest, InterruptedRequest) {
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl("c")));
-  provider()->Start(base::UTF8ToUTF16("c"));
-  EXPECT_EQ(0UL, results().size());
-
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl("ca")));
-  provider()->Start(base::UTF8ToUTF16("ca"));
-  EXPECT_EQ(0UL, results().size());
-
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(base::UTF8ToUTF16(kCatQuery));
-  EXPECT_EQ(0UL, results().size());
-
-  provider()->DidFinishNavigation(contents1(), GetSearchUrl("c"), false, true,
-                                  "Title c", "c");
-  provider()->OnContentsReady(contents1());
-  EXPECT_EQ(0UL, results().size());
-
-  provider()->DidFinishNavigation(contents1(), GetSearchUrl("ca"), false, true,
-                                  "Title ca", "ca");
-  provider()->OnContentsReady(contents1());
-  EXPECT_EQ(0UL, results().size());
-
-  provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
-                                  true, kCatCardTitle, kCatQuery);
-  provider()->OnContentsReady(contents1());
-
-  VerifyResult("Cat Result", kCatCardId, token1(), kCatCardTitle);
-}
-
-// After seeing a result, the user enters a query character by character. The
-// result will stay until we get an uninterrupted answer.
-TEST_F(AnswerCardSearchProviderTest, InterruptedRequestAfterResult) {
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(base::UTF8ToUTF16(kCatQuery));
-  provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
-                                  true, kCatCardTitle, kCatQuery);
-  provider()->OnContentsReady(contents1());
-
-  VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
-
-  EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl("d")));
-  provider()->Start(base::UTF8ToUTF16("d"));
-
-  VerifyResult("Cat Result 2", kCatCardId, token1(), kCatCardTitle);
-
-  EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl("do")));
-  provider()->Start(base::UTF8ToUTF16("do"));
-
-  VerifyResult("Cat Result 3", kCatCardId, token1(), kCatCardTitle);
-
-  EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
-  provider()->Start(base::UTF8ToUTF16(kDogQuery));
-
-  VerifyResult("Cat Result 4", kCatCardId, token1(), kCatCardTitle);
-
-  provider()->DidFinishNavigation(contents0(), GetSearchUrl("d"), false, true,
-                                  "Title d", "d");
-  provider()->OnContentsReady(contents0());
-
-  VerifyResult("Cat Result 5", kCatCardId, token1(), kCatCardTitle);
-
-  provider()->DidFinishNavigation(contents0(), GetSearchUrl("do"), false, true,
-                                  "Title do", "do");
-  provider()->OnContentsReady(contents0());
-
-  VerifyResult("Cat Result 5", kCatCardId, token1(), kCatCardTitle);
-
-  provider()->DidFinishNavigation(contents0(), GetSearchUrl(kDogQuery), false,
-                                  true, kDogCardTitle, kDogQuery);
-  provider()->OnContentsReady(contents0());
-
-  VerifyResult("Dog Result", kDogCardId, token0(), kDogCardTitle);
-}
-
-// Various values for DidFinishNavigation params.
-TEST_F(AnswerCardSearchProviderTest, DidFinishNavigation) {
-  TestDidFinishNavigation(1, false, true, kCatCardTitle, kCatQuery, 1UL);
-  TestDidFinishNavigation(0, true, true, kCatCardTitle, kCatQuery, 0UL);
-  TestDidFinishNavigation(0, false, false, kCatCardTitle, "", 0UL);
-}
-
-// Escaping a query with a special character.
+// Escaping a query with a special character produces a well-formed query URL.
 TEST_F(AnswerCardSearchProviderTest, QueryEscaping) {
-  EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl("cat%26dog")));
   provider()->Start(base::UTF8ToUTF16("cat&dog"));
+  ASSERT_EQ(1u, results().size());
+  EXPECT_EQ(GetAnswerCardUrl("cat%26dog"), results()[0]->query_url()->spec());
 }
 
 }  // namespace test
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.cc
deleted file mode 100644
index b30f2c2..0000000
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.cc
+++ /dev/null
@@ -1,332 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.h"
-
-#include <string>
-
-#include "ash/public/cpp/app_list/answer_card_contents_registry.h"
-#include "base/bind.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/browser/ui/browser_navigator_params.h"
-#include "content/public/browser/host_zoom_map.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/page_navigator.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/renderer_preferences.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_status_code.h"
-#include "ui/aura/window.h"
-#include "ui/base/ui_base_features.h"
-#include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/controls/webview/web_contents_set_background_color.h"
-#include "ui/views/controls/webview/webview.h"
-#include "ui/views/mus/remote_view/remote_view_provider.h"
-#include "ui/views/widget/widget.h"
-
-namespace app_list {
-
-namespace {
-
-constexpr char kSearchAnswerHasResult[] = "SearchAnswer-HasResult";
-constexpr char kSearchAnswerIssuedQuery[] = "SearchAnswer-IssuedQuery";
-constexpr char kSearchAnswerTitle[] = "SearchAnswer-Title";
-
-// SearchAnswerWebView is only created in non-mash mode, see comment below.
-class SearchAnswerWebView : public views::WebView {
- public:
-  explicit SearchAnswerWebView(content::BrowserContext* browser_context)
-      : WebView(browser_context) {
-    DCHECK(!::features::IsUsingWindowService());
-    holder()->set_can_process_events_within_subtree(false);
-  }
-
-  void OnVisibilityEvent(bool is_removing) {
-    // Need to check for |is_removing| because inside RemovedFromWidget()
-    // callback, GetWidget() still returns a non-null value.
-    if (!is_removing && GetWidget() && GetWidget()->IsActive() &&
-        GetWidget()->IsVisible() && IsDrawn()) {
-      if (shown_time_.is_null())
-        shown_time_ = base::TimeTicks::Now();
-    } else {
-      if (!shown_time_.is_null()) {
-        UMA_HISTOGRAM_MEDIUM_TIMES("SearchAnswer.AnswerVisibleTime",
-                                   base::TimeTicks::Now() - shown_time_);
-        shown_time_ = base::TimeTicks();
-      }
-    }
-  }
-
-  // views::WebView overrides:
-  void AddedToWidget() override {
-    WebView::AddedToWidget();
-
-    OnVisibilityEvent(false);
-    // Focus Behavior is originally set in WebView::SetWebContents, but
-    // overriden here because we do not want the webview to get focus.
-    SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
-  }
-
-  void RemovedFromWidget() override {
-    OnVisibilityEvent(true);
-
-    WebView::RemovedFromWidget();
-  }
-
-  void VisibilityChanged(View* starting_from, bool is_visible) override {
-    WebView::VisibilityChanged(starting_from, is_visible);
-
-    OnVisibilityEvent(false);
-  }
-
-  const char* GetClassName() const override { return "SearchAnswerWebView"; }
-
- private:
-  // Time when the answer became visible to the user.
-  base::TimeTicks shown_time_;
-
-  DISALLOW_COPY_AND_ASSIGN(SearchAnswerWebView);
-};
-
-void ParseResponseHeaders(const net::HttpResponseHeaders* headers,
-                          bool* has_answer_card,
-                          std::string* result_title,
-                          std::string* issued_query) {
-  if (!headers) {
-    LOG(ERROR) << "Failed to parse response headers: no headers";
-    return;
-  }
-  if (headers->response_code() != net::HTTP_OK) {
-    LOG(ERROR) << "Failed to parse response headers: response code="
-               << headers->response_code();
-    return;
-  }
-  if (!headers->HasHeaderValue(kSearchAnswerHasResult, "true")) {
-    LOG(ERROR) << "Failed to parse response headers: " << kSearchAnswerHasResult
-               << " header != true";
-    return;
-  }
-  if (!headers->GetNormalizedHeader(kSearchAnswerTitle, result_title) ||
-      result_title->empty()) {
-    LOG(ERROR) << "Failed to parse response headers: " << kSearchAnswerTitle
-               << " header is not present";
-    return;
-  }
-  if (!headers->GetNormalizedHeader(kSearchAnswerIssuedQuery, issued_query) ||
-      issued_query->empty()) {
-    LOG(ERROR) << "Failed to parse response headers: "
-               << kSearchAnswerIssuedQuery << " header is not present";
-    return;
-  }
-  *has_answer_card = true;
-}
-
-}  // namespace
-
-AnswerCardWebContents::AnswerCardWebContents(Profile* profile)
-    : web_contents_(
-          content::WebContents::Create(content::WebContents::CreateParams(
-              profile,
-              content::SiteInstance::Create(profile)))),
-      profile_(profile),
-      weak_ptr_factory_(this) {
-  content::RendererPreferences* renderer_prefs =
-      web_contents_->GetMutableRendererPrefs();
-  renderer_prefs->can_accept_load_drops = false;
-  // We need the OpenURLFromTab() to get called.
-  renderer_prefs->browser_handles_all_top_level_requests = true;
-  web_contents_->GetRenderViewHost()->SyncRendererPrefs();
-
-  Observe(web_contents_.get());
-  web_contents_->SetDelegate(this);
-
-  // Make the webview transparent since it's going to be shown on top of a
-  // highlightable button.
-  views::WebContentsSetBackgroundColor::CreateForWebContentsWithColor(
-      web_contents_.get(), SK_ColorTRANSPARENT);
-
-  content::RenderViewHost* const rvh = web_contents_->GetRenderViewHost();
-  if (rvh)
-    AttachToHost(rvh->GetWidget());
-
-  // AnswerCardContentsRegistry::Get() returns null in mash. See
-  // answer_card_contents_registry.h for details.
-  if (AnswerCardContentsRegistry::Get()) {
-    web_view_ = std::make_unique<SearchAnswerWebView>(profile);
-    web_view_->set_owned_by_client();
-    web_view_->SetWebContents(web_contents_.get());
-    web_view_->SetResizeBackgroundColor(SK_ColorTRANSPARENT);
-
-    token_ = AnswerCardContentsRegistry::Get()->Register(
-        web_view_.get(), web_contents_->GetNativeView());
-  }
-}
-
-AnswerCardWebContents::~AnswerCardWebContents() {
-  if (AnswerCardContentsRegistry::Get() && !token_.is_empty())
-    AnswerCardContentsRegistry::Get()->Unregister(token_);
-
-  DetachFromHost();
-  web_contents_->SetDelegate(nullptr);
-  Observe(nullptr);
-}
-
-void AnswerCardWebContents::LoadURL(const GURL& url) {
-  content::NavigationController::LoadURLParams load_params(url);
-  load_params.transition_type = ui::PAGE_TRANSITION_AUTO_TOPLEVEL;
-  load_params.should_clear_history_list = true;
-  web_contents_->GetController().LoadURLWithParams(load_params);
-
-  web_contents_->GetRenderWidgetHostView()->EnableAutoResize(
-      gfx::Size(1, 1), gfx::Size(INT_MAX, INT_MAX));
-}
-
-const base::UnguessableToken& AnswerCardWebContents::GetToken() const {
-  return token_;
-}
-
-gfx::Size AnswerCardWebContents::GetPreferredSize() const {
-  return preferred_size_;
-}
-
-void AnswerCardWebContents::ResizeDueToAutoResize(
-    content::WebContents* web_contents,
-    const gfx::Size& new_size) {
-  if (preferred_size_ == new_size)
-    return;
-
-  preferred_size_ = new_size;
-  delegate()->UpdatePreferredSize(this);
-}
-
-content::WebContents* AnswerCardWebContents::OpenURLFromTab(
-    content::WebContents* source,
-    const content::OpenURLParams& params) {
-  if (!params.user_gesture)
-    return WebContentsDelegate::OpenURLFromTab(source, params);
-
-  // Open the user-clicked link in the browser taking into account the requested
-  // disposition.
-  NavigateParams new_tab_params(profile_, params.url, params.transition);
-
-  new_tab_params.disposition = params.disposition;
-
-  if (params.disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB) {
-    // When the user asks to open a link as a background tab, we show an
-    // activated window with the new activated tab after the user closes the
-    // launcher. So it's "background" relative to the launcher itself.
-    new_tab_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
-    new_tab_params.window_action = NavigateParams::SHOW_WINDOW_INACTIVE;
-  }
-
-  Navigate(&new_tab_params);
-
-  base::RecordAction(base::UserMetricsAction("SearchAnswer_OpenedUrl"));
-
-  return new_tab_params.navigated_or_inserted_contents;
-}
-
-bool AnswerCardWebContents::HandleContextMenu(
-    const content::ContextMenuParams& params) {
-  // Disable showing the menu.
-  return true;
-}
-
-void AnswerCardWebContents::DidStartNavigation(
-    content::NavigationHandle* navigation_handle) {
-  if (!navigation_handle->IsRendererInitiated())
-    base::RecordAction(base::UserMetricsAction("SearchAnswer_UserInteraction"));
-}
-
-void AnswerCardWebContents::DidFinishNavigation(
-    content::NavigationHandle* navigation_handle) {
-  bool has_answer_card = false;
-  std::string result_title;
-  std::string issued_query;
-
-  const bool has_error = !navigation_handle->HasCommitted() ||
-                         navigation_handle->IsErrorPage() ||
-                         !navigation_handle->IsInMainFrame();
-  if (has_error) {
-    LOG(ERROR) << "Failed to navigate: HasCommitted="
-               << navigation_handle->HasCommitted()
-               << ", IsErrorPage=" << navigation_handle->IsErrorPage()
-               << ", IsInMainFrame=" << navigation_handle->IsInMainFrame();
-  } else {
-    ParseResponseHeaders(navigation_handle->GetResponseHeaders(),
-                         &has_answer_card, &result_title, &issued_query);
-  }
-
-  delegate()->DidFinishNavigation(this, navigation_handle->GetURL(), has_error,
-                                  has_answer_card, result_title, issued_query);
-}
-
-void AnswerCardWebContents::DidStopLoading() {
-  if (web_view_) {
-    delegate()->OnContentsReady(this);
-    return;
-  }
-
-  remote_view_provider_ = std::make_unique<views::RemoteViewProvider>(
-      web_contents_->GetNativeView());
-  remote_view_provider_->GetEmbedToken(
-      base::BindOnce(&AnswerCardWebContents::OnGotEmbedTokenAndNotify,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void AnswerCardWebContents::DidGetUserInteraction(
-    const blink::WebInputEvent::Type type) {
-  base::RecordAction(base::UserMetricsAction("SearchAnswer_UserInteraction"));
-}
-
-void AnswerCardWebContents::RenderViewCreated(content::RenderViewHost* host) {
-  if (!host_)
-    AttachToHost(host->GetWidget());
-
-  // Do not zoom for answer card web contents.
-  content::HostZoomMap* zoom_map =
-      content::HostZoomMap::GetForWebContents(web_contents());
-  DCHECK(zoom_map);
-  zoom_map->SetZoomLevelForHost(web_contents()->GetURL().host(), 0);
-}
-
-void AnswerCardWebContents::RenderViewDeleted(content::RenderViewHost* host) {
-  if (host->GetWidget() == host_)
-    DetachFromHost();
-}
-
-void AnswerCardWebContents::RenderViewHostChanged(
-    content::RenderViewHost* old_host,
-    content::RenderViewHost* new_host) {
-  if ((old_host && old_host->GetWidget() == host_) || (!old_host && !host_)) {
-    DetachFromHost();
-    AttachToHost(new_host->GetWidget());
-  }
-}
-
-void AnswerCardWebContents::AttachToHost(content::RenderWidgetHost* host) {
-  host_ = host;
-}
-
-void AnswerCardWebContents::DetachFromHost() {
-  if (!host_)
-    return;
-
-  host_ = nullptr;
-}
-
-void AnswerCardWebContents::OnGotEmbedTokenAndNotify(
-    const base::UnguessableToken& token) {
-  token_ = token;
-  web_contents_->GetNativeView()->Show();
-  delegate()->OnContentsReady(this);
-}
-
-}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.h b/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.h
deleted file mode 100644
index 6072ae8..0000000
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_ANSWER_CARD_ANSWER_CARD_WEB_CONTENTS_H_
-#define CHROME_BROWSER_UI_APP_LIST_SEARCH_ANSWER_CARD_ANSWER_CARD_WEB_CONTENTS_H_
-
-#include <memory>
-
-#include "base/memory/weak_ptr.h"
-#include "base/unguessable_token.h"
-#include "chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/browser/web_contents_observer.h"
-
-class Profile;
-
-namespace views {
-class RemoteViewProvider;
-class WebView;
-}
-
-namespace app_list {
-
-// Web source of contents for AnswerCardSearchProvider.
-class AnswerCardWebContents : public AnswerCardContents,
-                              public content::WebContentsDelegate,
-                              public content::WebContentsObserver {
- public:
-  explicit AnswerCardWebContents(Profile* profile);
-  ~AnswerCardWebContents() override;
-
-  // AnswerCardContents overrides:
-  void LoadURL(const GURL& url) override;
-  const base::UnguessableToken& GetToken() const override;
-  gfx::Size GetPreferredSize() const override;
-
-  // content::WebContentsDelegate overrides:
-  void ResizeDueToAutoResize(content::WebContents* web_contents,
-                             const gfx::Size& new_size) override;
-  content::WebContents* OpenURLFromTab(
-      content::WebContents* source,
-      const content::OpenURLParams& params) override;
-  bool HandleContextMenu(const content::ContextMenuParams& params) override;
-
-  // content::WebContentsObserver overrides:
-  void DidStartNavigation(
-      content::NavigationHandle* navigation_handle) override;
-  void DidFinishNavigation(
-      content::NavigationHandle* navigation_handle) override;
-  void DidStopLoading() override;
-  void DidGetUserInteraction(const blink::WebInputEvent::Type type) override;
-  void RenderViewCreated(content::RenderViewHost* host) override;
-  void RenderViewDeleted(content::RenderViewHost* host) override;
-  void RenderViewHostChanged(content::RenderViewHost* old_host,
-                             content::RenderViewHost* new_host) override;
-
- private:
-  void AttachToHost(content::RenderWidgetHost* host);
-  void DetachFromHost();
-
-  void OnGotEmbedTokenAndNotify(const base::UnguessableToken& token);
-
-  // Web contents managed by this class.
-  const std::unique_ptr<content::WebContents> web_contents_;
-
-  // Web view for the web contents managed by this class.
-  // Note this is only used for classic ash.
-  std::unique_ptr<views::WebView> web_view_;
-
-  // Current widget host.
-  content::RenderWidgetHost* host_ = nullptr;
-
-  Profile* const profile_;  // Unowned
-
-  // Token to embed the web contents. On classic ash, it is a token registered
-  // with AnswerCardContentsRegistry. On mash, it is the embedding token for
-  // the native window of |web_contents_|.
-  base::UnguessableToken token_;
-
-  // Preferred size of web contents.
-  gfx::Size preferred_size_;
-
-  // Helper to prepare the native view of |web_contents_| to be embedded under
-  // mash.
-  std::unique_ptr<views::RemoteViewProvider> remote_view_provider_;
-
-  base::WeakPtrFactory<AnswerCardWebContents> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(AnswerCardWebContents);
-};
-
-}  // namespace app_list
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_ANSWER_CARD_ANSWER_CARD_WEB_CONTENTS_H_
diff --git a/chrome/browser/ui/app_list/search/chrome_search_result.cc b/chrome/browser/ui/app_list/search/chrome_search_result.cc
index c9fa34b..4ef3e51 100644
--- a/chrome/browser/ui/app_list/search/chrome_search_result.cc
+++ b/chrome/browser/ui/app_list/search/chrome_search_result.cc
@@ -108,27 +108,19 @@
     updater->SetSearchResultMetadata(id(), CloneMetadata());
 }
 
-void ChromeSearchResult::SetAnswerCardContentsToken(
-    const base::UnguessableToken& token) {
-  metadata_->answer_card_contents_token = token;
-  AppListModelUpdater* updater = model_updater();
-  if (updater)
-    updater->SetSearchResultMetadata(id(), CloneMetadata());
-}
-
-void ChromeSearchResult::SetAnswerCardSize(const gfx::Size& size) {
-  metadata_->answer_card_size = size;
-  AppListModelUpdater* updater = model_updater();
-  if (updater)
-    updater->SetSearchResultMetadata(id(), CloneMetadata());
-}
-
 void ChromeSearchResult::SetPercentDownloaded(int percent_downloaded) {
   AppListModelUpdater* updater = model_updater();
   if (updater)
     updater->SetSearchResultPercentDownloaded(id(), percent_downloaded);
 }
 
+void ChromeSearchResult::SetQueryUrl(const GURL& url) {
+  metadata_->query_url = url;
+  auto* updater = model_updater();
+  if (updater)
+    updater->SetSearchResultMetadata(id(), CloneMetadata());
+}
+
 void ChromeSearchResult::SetIcon(const gfx::ImageSkia& icon) {
   icon.EnsureRepsForSupportedScales();
   metadata_->icon = icon;
diff --git a/chrome/browser/ui/app_list/search/chrome_search_result.h b/chrome/browser/ui/app_list/search/chrome_search_result.h
index dfc575d..1feab91 100644
--- a/chrome/browser/ui/app_list/search/chrome_search_result.h
+++ b/chrome/browser/ui/app_list/search/chrome_search_result.h
@@ -12,7 +12,6 @@
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/public/interfaces/app_list.mojom.h"
 #include "base/macros.h"
-#include "base/unguessable_token.h"
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
 
 namespace app_list {
@@ -50,9 +49,7 @@
   const Actions& actions() const { return metadata_->actions; }
   double display_score() const { return metadata_->display_score; }
   bool is_installing() const { return metadata_->is_installing; }
-  const base::UnguessableToken& answer_card_contents_token() const {
-    return metadata_->answer_card_contents_token.value();
-  }
+  const base::Optional<GURL>& query_url() const { return metadata_->query_url; }
   const gfx::ImageSkia& icon() const { return metadata_->icon; }
   const gfx::ImageSkia& chip_icon() const { return metadata_->chip_icon; }
   const gfx::ImageSkia& badge_icon() const { return metadata_->badge_icon; }
@@ -73,9 +70,8 @@
   void SetDisplayScore(double display_score);
   void SetActions(const Actions& actions);
   void SetIsOmniboxSearch(bool is_omnibox_search);
-  void SetAnswerCardContentsToken(const base::UnguessableToken& token);
-  void SetAnswerCardSize(const gfx::Size& size);
   void SetIsInstalling(bool is_installing);
+  void SetQueryUrl(const GURL& url);
   void SetIcon(const gfx::ImageSkia& icon);
   void SetChipIcon(const gfx::ImageSkia& icon);
   void SetBadgeIcon(const gfx::ImageSkia& badge_icon);
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index 87fc590..29ffee3 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h"
-#include "chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.h"
 #include "chrome/browser/ui/app_list/search/app_search_provider.h"
 #include "chrome/browser/ui/app_list/search/arc/arc_app_data_search_provider.h"
 #include "chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.h"
@@ -87,12 +86,9 @@
   controller->AddProvider(omnibox_group_id, std::make_unique<OmniboxProvider>(
                                                 profile, list_controller));
   if (app_list_features::IsAnswerCardEnabled()) {
-    controller->AddProvider(
-        answer_card_group_id,
-        std::make_unique<AnswerCardSearchProvider>(
-            profile, model_updater, list_controller,
-            std::make_unique<AnswerCardWebContents>(profile),
-            std::make_unique<AnswerCardWebContents>(profile)));
+    controller->AddProvider(answer_card_group_id,
+                            std::make_unique<AnswerCardSearchProvider>(
+                                profile, model_updater, list_controller));
   }
 
   // LauncherSearchProvider is added only when flag is enabled, not in guest
diff --git a/chrome/browser/usb/usb_tab_helper.cc b/chrome/browser/usb/usb_tab_helper.cc
index 29b8a19..d1e3302 100644
--- a/chrome/browser/usb/usb_tab_helper.cc
+++ b/chrome/browser/usb/usb_tab_helper.cc
@@ -98,19 +98,26 @@
     : content::WebContentsObserver(web_contents) {}
 
 void UsbTabHelper::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
-  frame_usb_services_.erase(render_frame_host);
-  NotifyTabStateChanged();
+  // This method handles the simple case of a frame closing.
+  DeleteFrameServices(render_frame_host);
+}
+
+void UsbTabHelper::RenderFrameHostChanged(RenderFrameHost* old_host,
+                                          RenderFrameHost* new_host) {
+  // This method handles the case where a frame swaps its RenderFrameHost for a
+  // new one on navigation.
+  DeleteFrameServices(old_host);
 }
 
 void UsbTabHelper::DidFinishNavigation(content::NavigationHandle* handle) {
-  if (handle->HasCommitted() && !handle->IsSameDocument()) {
-    frame_usb_services_.erase(handle->GetRenderFrameHost());
-    NotifyTabStateChanged();
-  }
+  // This method handles the case where a frame navigates without swapping its
+  // RenderFrameHost for a new one.
+  if (handle->HasCommitted() && !handle->IsSameDocument())
+    DeleteFrameServices(handle->GetRenderFrameHost());
 }
 
 FrameUsbServices* UsbTabHelper::GetFrameUsbService(
-    content::RenderFrameHost* render_frame_host) {
+    RenderFrameHost* render_frame_host) {
   FrameUsbServicesMap::const_iterator it =
       frame_usb_services_.find(render_frame_host);
   if (it == frame_usb_services_.end()) {
@@ -123,8 +130,13 @@
   return it->second.get();
 }
 
+void UsbTabHelper::DeleteFrameServices(RenderFrameHost* render_frame_host) {
+  frame_usb_services_.erase(render_frame_host);
+  NotifyTabStateChanged();
+}
+
 base::WeakPtr<WebUsbChooser> UsbTabHelper::GetUsbChooser(
-    content::RenderFrameHost* render_frame_host) {
+    RenderFrameHost* render_frame_host) {
   FrameUsbServices* frame_usb_services = GetFrameUsbService(render_frame_host);
   if (!frame_usb_services->usb_chooser) {
     frame_usb_services->usb_chooser.reset(
diff --git a/chrome/browser/usb/usb_tab_helper.h b/chrome/browser/usb/usb_tab_helper.h
index e89442d..c89c7d59 100644
--- a/chrome/browser/usb/usb_tab_helper.h
+++ b/chrome/browser/usb/usb_tab_helper.h
@@ -49,10 +49,13 @@
 
   // content::WebContentsObserver overrides:
   void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+  void RenderFrameHostChanged(content::RenderFrameHost* old_host,
+                              content::RenderFrameHost* new_host) override;
   void DidFinishNavigation(content::NavigationHandle* handle) override;
 
   FrameUsbServices* GetFrameUsbService(
       content::RenderFrameHost* render_frame_host);
+  void DeleteFrameServices(content::RenderFrameHost* render_frame_host);
 
   base::WeakPtr<WebUsbChooser> GetUsbChooser(
       content::RenderFrameHost* render_frame_host);
diff --git a/chrome/installer/mac/keystone_install.sh b/chrome/installer/mac/keystone_install.sh
index 350873ef..379d16d 100755
--- a/chrome/installer/mac/keystone_install.sh
+++ b/chrome/installer/mac/keystone_install.sh
@@ -341,45 +341,6 @@
   return 0
 }
 
-# Prints the OS version, as reported by sw_vers -productVersion, to stdout.
-# This function operates with "static" variables: it will only check the OS
-# version once per script run.
-g_checked_os_version=
-g_os_version=
-os_version() {
-  if [[ -z "${g_checked_os_version}" ]]; then
-    g_checked_os_version="y"
-    g_os_version="$(sw_vers -productVersion)"
-    note "g_os_version = ${g_os_version}"
-  fi
-  echo "${g_os_version}"
-  return 0
-}
-
-# Compares the running OS version against a supplied version number,
-# |check_version|, and returns 0 (true) if the running OS version is greater
-# than or equal to |check_version| according to a piece-wise comparison.
-# Returns 1 (false) if the running OS version number cannot be determined or
-# if |check_version| is greater than the running OS version. |check_version|
-# should be a string of the form "major.minor" or "major.minor.micro".
-is_os_version_ge() {
-  local check_version="${1}"
-
-  local os_version="$(os_version)"
-  is_version_ge "${os_version}" "${check_version}"
-
-  # The return value of is_version_ge is used as this function's return value.
-}
-
-# Returns 0 (true) if xattr supports -r for recursive operation.
-os_xattr_supports_r() {
-  # xattr -r is supported in Mac OS X 10.6.
-  is_os_version_ge 10.6
-
-  # The return value of is_os_version_ge is used as this function's return
-  # value.
-}
-
 # Prints the version of ksadmin, as reported by ksadmin --ksadmin-version, to
 # stdout.  This function operates with "static" variables: it will only check
 # the ksadmin version once per script run.  If ksadmin is old enough to not
@@ -1484,14 +1445,7 @@
   # the application.
   note "lifting quarantine"
 
-  if os_xattr_supports_r; then
-    # On 10.6, xattr supports -r for recursive operation.
-    xattr -d -r "${QUARANTINE_ATTR}" "${installed_app}" 2> /dev/null
-  else
-    # On earlier systems, xattr doesn't support -r, so run xattr via find.
-    find "${installed_app}" -exec xattr -d "${QUARANTINE_ATTR}" {} + \
-        2> /dev/null
-  fi
+  xattr -d -r "${QUARANTINE_ATTR}" "${installed_app}" 2> /dev/null
 
   # Do Keychain reauthorization. This involves running a stub executable on
   # the dmg that loads the newly-updated framework and jumps to it to perform
diff --git a/chrome/test/data/extensions/lock_screen_apps/app_launch/test.js b/chrome/test/data/extensions/lock_screen_apps/app_launch/test.js
index e19ec28..2a0f2b2 100644
--- a/chrome/test/data/extensions/lock_screen_apps/app_launch/test.js
+++ b/chrome/test/data/extensions/lock_screen_apps/app_launch/test.js
@@ -11,7 +11,6 @@
   function hasAccessToCurrentWindow() {
     chrome.test.assertTrue(!!chrome.app.window.current);
     chrome.test.assertTrue(!!chrome.app.window.current());
-    chrome.test.assertTrue(chrome.app.window.current().isMaximized());
     chrome.test.succeed();
   },
 
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index 1aae6fc..344d1e5 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -872,3 +872,24 @@
 TEST_F('CrExtensionsRuntimeHostPermissionsTest', 'All', () => {
   mocha.run();
 });
+
+////////////////////////////////////////////////////////////////////////////////
+// HostPermissionsToggleList tests
+
+CrExtensionsHostPermissionsToggleListTest =
+    class extends CrExtensionsBrowserTest {
+  /** @override */
+  get browserPreload() {
+    return 'chrome://extensions/host_permissions_toggle_list.html';
+  }
+
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'host_permissions_toggle_list_test.js',
+    ]);
+  }
+};
+
+TEST_F('CrExtensionsHostPermissionsToggleListTest', 'All', () => {
+  mocha.run();
+});
diff --git a/chrome/test/data/webui/extensions/detail_view_test.js b/chrome/test/data/webui/extensions/detail_view_test.js
index f38d22a..d06f33ae 100644
--- a/chrome/test/data/webui/extensions/detail_view_test.js
+++ b/chrome/test/data/webui/extensions/detail_view_test.js
@@ -165,6 +165,11 @@
       Polymer.dom.flush();
       expectTrue(testIsVisible('.warning-icon'));
 
+      // Ensure that without runtimeHostPermissions data, the sections are
+      // hidden.
+      expectFalse(testIsVisible('extensions-runtime-host-permissions'));
+      expectFalse(testIsVisible('extensions-host-permissions-toggle-list'));
+
       // Adding any runtime host permissions should result in the runtime host
       // controls becoming visible.
       const allSitesPermissions = {
@@ -178,6 +183,23 @@
       item.set('data.permissions', allSitesPermissions);
       Polymer.dom.flush();
       expectTrue(testIsVisible('extensions-runtime-host-permissions'));
+      expectFalse(testIsVisible('extensions-host-permissions-toggle-list'));
+
+      const someSitesPermissions = {
+        simplePermissions: [],
+        runtimeHostPermissions: {
+          hosts: [
+            {granted: true, host: 'https://chromium.org/*'},
+            {granted: false, host: 'https://example.com/*'}
+          ],
+          hasAllHosts: false,
+          hostAccess: chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES,
+        },
+      };
+      item.set('data.permissions', someSitesPermissions);
+      Polymer.dom.flush();
+      expectFalse(testIsVisible('extensions-runtime-host-permissions'));
+      expectTrue(testIsVisible('extensions-host-permissions-toggle-list'));
     });
 
     test(assert(TestNames.LayoutSource), function() {
diff --git a/chrome/test/data/webui/extensions/host_permissions_toggle_list_test.js b/chrome/test/data/webui/extensions/host_permissions_toggle_list_test.js
new file mode 100644
index 0000000..13f3212
--- /dev/null
+++ b/chrome/test/data/webui/extensions/host_permissions_toggle_list_test.js
@@ -0,0 +1,203 @@
+// Copyright 2018 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.
+
+suite('HostPermissionsToggleList', function() {
+  /** @type {extensions.HostPermissionsToggleListElement} */ let element;
+  /** @type {extensions.TestService} */ let delegate;
+
+  const HostAccess = chrome.developerPrivate.HostAccess;
+  const ITEM_ID = 'a'.repeat(32);
+  const EXAMPLE_COM = 'https://example.com/*';
+  const GOOGLE_COM = 'https://google.com/*';
+  const CHROMIUM_ORG = 'https://chromium.org/*';
+
+  setup(function() {
+    PolymerTest.clearBody();
+    element = document.createElement('extensions-host-permissions-toggle-list');
+    delegate = new extensions.TestService();
+    element.delegate = delegate;
+    element.itemId = ITEM_ID;
+
+    document.body.appendChild(element);
+  });
+
+  teardown(function() {
+    element.remove();
+  });
+
+  // Tests the display of the list when only specific sites are granted.
+  test('permissions display for specific sites', function() {
+    const permissions = {
+      hostAccess: HostAccess.ON_SPECIFIC_SITES,
+      hasAllHosts: false,
+      hosts: [
+        {host: EXAMPLE_COM, granted: true},
+        {host: GOOGLE_COM, granted: false},
+        {host: CHROMIUM_ORG, granted: true},
+      ],
+    };
+
+    element.permissions = permissions;
+    Polymer.dom.flush();
+
+    assertTrue(!!element.$);
+    const allSites = element.$.allHostsToggle;
+    expectFalse(allSites.checked);
+
+    const hostToggles = element.shadowRoot.querySelectorAll('.host-toggle');
+    assertEquals(3, hostToggles.length);
+
+    // There should be three toggles, all enabled, and checked corresponding to
+    // whether the host is granted.
+    expectEquals(CHROMIUM_ORG, hostToggles[0].innerText.trim());
+    expectFalse(hostToggles[0].disabled);
+    expectTrue(hostToggles[0].checked);
+
+    expectEquals(EXAMPLE_COM, hostToggles[1].innerText.trim());
+    expectFalse(hostToggles[1].disabled);
+    expectTrue(hostToggles[1].checked);
+
+    expectEquals(GOOGLE_COM, hostToggles[2].innerText.trim());
+    expectFalse(hostToggles[2].disabled);
+    expectFalse(hostToggles[2].checked);
+  });
+
+  // Tests the display when the user has chosen to allow on all the requested
+  // sites.
+  test('permissions display for all requested sites', function() {
+    const permissions = {
+      hostAccess: HostAccess.ON_ALL_SITES,
+      hasAllHosts: false,
+      hosts: [
+        {host: EXAMPLE_COM, granted: true},
+        {host: GOOGLE_COM, granted: true},
+        {host: CHROMIUM_ORG, granted: true},
+      ],
+    };
+
+    element.permissions = permissions;
+    Polymer.dom.flush();
+
+    assertTrue(!!element.$);
+    const allSites = element.$.allHostsToggle;
+    expectTrue(allSites.checked);
+
+    const hostToggles = element.shadowRoot.querySelectorAll('.host-toggle');
+    assertEquals(3, hostToggles.length);
+
+    // There should be three toggles, and they should all be disabled and
+    // checked, since the user selected to allow the extension to run on all
+    // (requested) sites.
+    expectEquals(CHROMIUM_ORG, hostToggles[0].innerText.trim());
+    expectTrue(hostToggles[0].disabled);
+    expectTrue(hostToggles[0].checked);
+
+    expectEquals(EXAMPLE_COM, hostToggles[1].innerText.trim());
+    expectTrue(hostToggles[1].disabled);
+    expectTrue(hostToggles[1].checked);
+
+    expectEquals(GOOGLE_COM, hostToggles[2].innerText.trim());
+    expectTrue(hostToggles[2].disabled);
+    expectTrue(hostToggles[2].checked);
+  });
+
+  // Tests the permissions display when a user has chosen to only run an
+  // extension on-click.
+  test('permissions display for on click', function() {
+    const permissions = {
+      hostAccess: HostAccess.ON_CLICK,
+      hasAllHosts: false,
+      hosts: [
+        {host: EXAMPLE_COM, granted: false},
+        {host: GOOGLE_COM, granted: false},
+        {host: CHROMIUM_ORG, granted: false},
+      ],
+    };
+
+    element.permissions = permissions;
+    Polymer.dom.flush();
+
+    assertTrue(!!element.$);
+    const allSites = element.$.allHostsToggle;
+    expectFalse(allSites.checked);
+
+    const hostToggles = element.shadowRoot.querySelectorAll('.host-toggle');
+    assertEquals(3, hostToggles.length);
+
+    // There should be three toggles, all enabled, and all unchecked, since no
+    // host has been granted.
+    expectEquals(CHROMIUM_ORG, hostToggles[0].innerText.trim());
+    expectFalse(hostToggles[0].disabled);
+    expectFalse(hostToggles[0].checked);
+
+    expectEquals(EXAMPLE_COM, hostToggles[1].innerText.trim());
+    expectFalse(hostToggles[1].disabled);
+    expectFalse(hostToggles[1].checked);
+
+    expectEquals(GOOGLE_COM, hostToggles[2].innerText.trim());
+    expectFalse(hostToggles[2].disabled);
+    expectFalse(hostToggles[2].checked);
+  });
+
+  // Tests that clicking the "allow on all sites" toggle changes the item
+  // host access properly.
+  test('clicking all hosts toggle', function() {
+    const permissions = {
+      hostAccess: HostAccess.ON_CLICK,
+      hasAllHosts: false,
+      hosts: [
+        {host: EXAMPLE_COM, granted: false},
+        {host: GOOGLE_COM, granted: false},
+        {host: CHROMIUM_ORG, granted: false},
+      ],
+    };
+    element.permissions = permissions;
+    Polymer.dom.flush();
+
+    assertTrue(!!element.$);
+    const allSites = element.$.allHostsToggle;
+    allSites.getLabel().click();
+    return delegate.whenCalled('setItemHostAccess').then((args) => {
+      expectEquals(ITEM_ID, args[0] /* id */);
+      expectEquals(HostAccess.ON_ALL_SITES, args[1] /* access */);
+    });
+  });
+
+  // Tests that toggling a site's enabled state toggles the extension's access
+  // to that site properly.
+  test('clicking to toggle a specific site', function() {
+    const permissions = {
+      hostAccess: HostAccess.ON_SPECIFIC_SITES,
+      hasAllHosts: false,
+      hosts: [
+        {host: EXAMPLE_COM, granted: true},
+        {host: GOOGLE_COM, granted: false},
+        {host: CHROMIUM_ORG, granted: true},
+      ],
+    };
+
+    element.permissions = permissions;
+    Polymer.dom.flush();
+
+    const hostToggles = element.shadowRoot.querySelectorAll('.host-toggle');
+    assertEquals(3, hostToggles.length);
+
+    expectEquals(CHROMIUM_ORG, hostToggles[0].innerText.trim());
+    expectEquals(GOOGLE_COM, hostToggles[2].innerText.trim());
+
+    hostToggles[0].getLabel().click();
+    return delegate.whenCalled('removeRuntimeHostPermission')
+        .then((args) => {
+          expectEquals(ITEM_ID, args[0] /* id */);
+          expectEquals(CHROMIUM_ORG, args[1] /* site */);
+
+          hostToggles[2].getLabel().click();
+          return delegate.whenCalled('addRuntimeHostPermission');
+        })
+        .then((args) => {
+          expectEquals(ITEM_ID, args[0] /* id */);
+          expectEquals(GOOGLE_COM, args[1] /* site */);
+        });
+  });
+});
diff --git a/chromecast/media/cma/base/demuxer_stream_for_test.cc b/chromecast/media/cma/base/demuxer_stream_for_test.cc
index a25119d3..983fe22 100644
--- a/chromecast/media/cma/base/demuxer_stream_for_test.cc
+++ b/chromecast/media/cma/base/demuxer_stream_for_test.cc
@@ -57,7 +57,7 @@
   gfx::Size natural_size(640, 480);
   return ::media::VideoDecoderConfig(
       ::media::kCodecH264, ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
-      ::media::PIXEL_FORMAT_YV12, ::media::COLOR_SPACE_UNSPECIFIED,
+      ::media::PIXEL_FORMAT_YV12, ::media::VideoColorSpace(),
       ::media::VIDEO_ROTATION_0, coded_size, visible_rect, natural_size,
       ::media::EmptyExtraData(), ::media::Unencrypted());
 }
diff --git a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
index 83e6d2b0..72ea574 100644
--- a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
+++ b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
@@ -153,7 +153,7 @@
       std::vector<::media::VideoDecoderConfig> video_configs;
       video_configs.push_back(::media::VideoDecoderConfig(
           ::media::kCodecH264, ::media::H264PROFILE_MAIN,
-          ::media::PIXEL_FORMAT_I420, ::media::COLOR_SPACE_UNSPECIFIED,
+          ::media::PIXEL_FORMAT_I420, ::media::VideoColorSpace(),
           ::media::VIDEO_ROTATION_0, gfx::Size(640, 480),
           gfx::Rect(0, 0, 640, 480), gfx::Size(640, 480),
           ::media::EmptyExtraData(), ::media::EncryptionScheme()));
diff --git a/chromecast/media/cma/test/mock_frame_provider.cc b/chromecast/media/cma/test/mock_frame_provider.cc
index ff27cc63..83f3593b 100644
--- a/chromecast/media/cma/test/mock_frame_provider.cc
+++ b/chromecast/media/cma/test/mock_frame_provider.cc
@@ -81,7 +81,7 @@
     gfx::Size natural_size(640, 480);
     video_config = ::media::VideoDecoderConfig(
         ::media::kCodecH264, ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
-        ::media::PIXEL_FORMAT_YV12, ::media::COLOR_SPACE_UNSPECIFIED,
+        ::media::PIXEL_FORMAT_YV12, ::media::VideoColorSpace(),
         ::media::VIDEO_ROTATION_0, coded_size, visible_rect, natural_size,
         ::media::EmptyExtraData(), ::media::Unencrypted());
 
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 1dd611a4..18f5da8 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-11220.0.0
\ No newline at end of file
+11224.0.0
\ No newline at end of file
diff --git a/chromeos/components/proximity_auth/logging/logging.cc b/chromeos/components/proximity_auth/logging/logging.cc
index 8303ac9..f755be7 100644
--- a/chromeos/components/proximity_auth/logging/logging.cc
+++ b/chromeos/components/proximity_auth/logging/logging.cc
@@ -34,6 +34,13 @@
   LogBuffer::GetInstance()->AddLogMessage(LogBuffer::LogMessage(
       string_from_stream, base::Time::Now(), file_, line_, severity_));
 
+  // Don't emit VERBOSE-level logging to the standard logging system unless
+  // verbose logging is enabled for the source file.
+  if (severity_ <= logging::LOG_VERBOSE &&
+      logging::GetVlogLevelHelper(file_, strlen(file_) + 1) <= 0) {
+    return;
+  }
+
   // The destructor of |log_message| also creates a log for the standard logging
   // system.
   logging::LogMessage log_message(file_, line_, severity_);
diff --git a/chromeos/components/proximity_auth/logging/logging_unittest.cc b/chromeos/components/proximity_auth/logging/logging_unittest.cc
index 3314b5c..6a4f705 100644
--- a/chromeos/components/proximity_auth/logging/logging_unittest.cc
+++ b/chromeos/components/proximity_auth/logging/logging_unittest.cc
@@ -19,6 +19,7 @@
 const char kLog1[] = "Mahogony destined to make a sturdy table";
 const char kLog2[] = "Construction grade cedar";
 const char kLog3[] = "Pine infested by hungry beetles";
+const char kLog4[] = "Unremarkable maple";
 
 // Called for every log message added to the standard logging system. The new
 // log is saved in |g_standard_logs| and consumed so it does not flood stdout.
@@ -58,9 +59,10 @@
   PA_LOG(INFO) << kLog1;
   PA_LOG(WARNING) << kLog2;
   PA_LOG(ERROR) << kLog3;
+  PA_LOG(VERBOSE) << kLog3;
 
   auto* logs = LogBuffer::GetInstance()->logs();
-  ASSERT_EQ(3u, logs->size());
+  ASSERT_EQ(4u, logs->size());
 
   auto iterator = logs->begin();
   const LogBuffer::LogMessage& log_message1 = *iterator;
@@ -82,6 +84,13 @@
   EXPECT_EQ(__FILE__, log_message3.file);
   EXPECT_EQ(base_line_number + 3, log_message3.line);
   EXPECT_EQ(logging::LOG_ERROR, log_message3.severity);
+
+  ++iterator;
+  const LogBuffer::LogMessage& log_message4 = *iterator;
+  EXPECT_EQ(kLog3, log_message4.text);
+  EXPECT_EQ(__FILE__, log_message4.file);
+  EXPECT_EQ(base_line_number + 4, log_message4.line);
+  EXPECT_EQ(logging::LOG_VERBOSE, log_message4.severity);
 }
 
 TEST_F(ProximityAuthLoggingTest, LogWhenBufferIsFull) {
@@ -109,6 +118,7 @@
   PA_LOG(INFO) << kLog1;
   PA_LOG(WARNING) << kLog2;
   PA_LOG(ERROR) << kLog3;
+  PA_LOG(VERBOSE) << kLog4;
 
   ASSERT_EQ(3u, g_standard_logs.Get().size());
   EXPECT_NE(std::string::npos, g_standard_logs.Get()[0].find(kLog1));
diff --git a/chromeos/services/device_sync/device_sync_impl.cc b/chromeos/services/device_sync/device_sync_impl.cc
index 7e203da..5e4f5b6 100644
--- a/chromeos/services/device_sync/device_sync_impl.cc
+++ b/chromeos/services/device_sync/device_sync_impl.cc
@@ -61,6 +61,16 @@
   kMaxValue = kUnknown
 };
 
+// This enum is tied directly to a UMA enum defined in
+// //tools/metrics/histograms/enums.xml, and should always reflect it (do not
+// change one without changing the other). Entries should be never modified
+// or deleted. Only additions possible.
+enum class ForceCryptAuthOperationResult {
+  kSuccess = 0,
+  kServiceNotReady = 1,
+  kMaxValue = kServiceNotReady
+};
+
 DeviceSyncRequestFailureReason GetDeviceSyncRequestFailureReason(
     mojom::NetworkRequestResult failure_reason) {
   switch (failure_reason) {
@@ -115,6 +125,16 @@
       failure_reason);
 }
 
+void RecordForceEnrollmentNowResult(ForceCryptAuthOperationResult result) {
+  UMA_HISTOGRAM_ENUMERATION(
+      "MultiDevice.DeviceSyncService.ForceEnrollmentNow.Result", result);
+}
+
+void RecordForceSyncNowResult(ForceCryptAuthOperationResult result) {
+  UMA_HISTOGRAM_ENUMERATION("MultiDevice.DeviceSyncService.ForceSyncNow.Result",
+                            result);
+}
+
 }  // namespace
 
 // static
@@ -253,12 +273,16 @@
     PA_LOG(WARNING) << "DeviceSyncImpl::ForceEnrollmentNow() invoked before "
                     << "initialization was complete. Cannot force enrollment.";
     std::move(callback).Run(false /* success */);
+    RecordForceEnrollmentNowResult(
+        ForceCryptAuthOperationResult::kServiceNotReady /* result */);
     return;
   }
 
   cryptauth_enrollment_manager_->ForceEnrollmentNow(
       cryptauth::INVOCATION_REASON_MANUAL);
   std::move(callback).Run(true /* success */);
+  RecordForceEnrollmentNowResult(
+      ForceCryptAuthOperationResult::kSuccess /* result */);
 }
 
 void DeviceSyncImpl::ForceSyncNow(ForceSyncNowCallback callback) {
@@ -266,11 +290,15 @@
     PA_LOG(WARNING) << "DeviceSyncImpl::ForceSyncNow() invoked before "
                     << "initialization was complete. Cannot force sync.";
     std::move(callback).Run(false /* success */);
+    RecordForceSyncNowResult(
+        ForceCryptAuthOperationResult::kServiceNotReady /* result */);
     return;
   }
 
   cryptauth_device_manager_->ForceSyncNow(cryptauth::INVOCATION_REASON_MANUAL);
   std::move(callback).Run(true /* success */);
+  RecordForceSyncNowResult(
+      ForceCryptAuthOperationResult::kSuccess /* result */);
 }
 
 void DeviceSyncImpl::GetLocalDeviceMetadata(
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index ec045366..aa254d9 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -553,11 +553,12 @@
   // the UI is not cluttered with duplicate cards.
   if (this->IsVerified() && !imported_card.IsVerified()) {
     // If the original card is expired and the imported card is not, and the
-    // name on the cards are identical, update the expiration date.
+    // name on the cards are identical, and the imported card's expiration date
+    // is not empty, update the expiration date.
     if (this->IsExpired(AutofillClock::Now()) &&
         !imported_card.IsExpired(AutofillClock::Now()) &&
-        (name_on_card_ == imported_card.name_on_card_)) {
-      DCHECK(imported_card.expiration_month_ && imported_card.expiration_year_);
+        (name_on_card_ == imported_card.name_on_card_) &&
+        (imported_card.expiration_month_ && imported_card.expiration_year_)) {
       expiration_month_ = imported_card.expiration_month_;
       expiration_year_ = imported_card.expiration_year_;
     }
@@ -572,10 +573,12 @@
   if (!imported_card.name_on_card_.empty())
     name_on_card_ = imported_card.name_on_card_;
 
-  // The expiration date for |imported_card| should always be set.
-  DCHECK(imported_card.expiration_month_ && imported_card.expiration_year_);
-  expiration_month_ = imported_card.expiration_month_;
-  expiration_year_ = imported_card.expiration_year_;
+  // If |imported_card| has an expiration date, overwrite |this|'s expiration
+  // date with its value.
+  if (imported_card.expiration_month_ && imported_card.expiration_year_) {
+    expiration_month_ = imported_card.expiration_month_;
+    expiration_year_ = imported_card.expiration_year_;
+  }
 
   return true;
 }
@@ -877,6 +880,10 @@
          !name_on_card_.empty();
 }
 
+bool CreditCard::HasNameOnCard() const {
+  return !name_on_card_.empty();
+}
+
 base::string16 CreditCard::Expiration2DigitYearAsString() const {
   if (expiration_year_ == 0)
     return base::string16();
diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h
index 570be5e..5c73b863 100644
--- a/components/autofill/core/browser/credit_card.h
+++ b/components/autofill/core/browser/credit_card.h
@@ -278,6 +278,9 @@
   // name fields.
   bool HasFirstAndLastName() const;
 
+  // Returns whether the card has a cardholder name.
+  bool HasNameOnCard() const;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(CreditCardTest, SetExpirationDateFromString);
   FRIEND_TEST_ALL_PREFIXES(CreditCardTest, SetExpirationYearFromString);
diff --git a/components/autofill/core/browser/credit_card_save_manager.cc b/components/autofill/core/browser/credit_card_save_manager.cc
index f586a2f..5c7370c 100644
--- a/components/autofill/core/browser/credit_card_save_manager.cc
+++ b/components/autofill/core/browser/credit_card_save_manager.cc
@@ -180,6 +180,27 @@
     should_request_name_from_user_ = true;
   }
 
+  // If the user must provide expiration month or expration year, log it and set
+  // |should_request_expiration_date_from_user_| so the offer-to-save dialog
+  // knows to ask for it.
+  should_request_expiration_date_from_user_ = false;
+  if (upload_request_.detected_values &
+      DetectedValue::USER_PROVIDED_EXPIRATION_DATE) {
+    // TODO(crbug.com/899057): Update |upload_decision_metrics_| with
+    //                         USER_REQUESTED_TO_PROVIDE_EXPIRATION_DATE.
+    should_request_expiration_date_from_user_ = true;
+  }
+
+  // The cardholder name and expiration date fix flows cannot both be
+  // active at the same time.  If they are, abort offering upload.
+  if (should_request_name_from_user_ &&
+      should_request_expiration_date_from_user_) {
+    DCHECK(base::FeatureList::IsEnabled(
+        features::kAutofillUpstreamEditableExpirationDate));
+    LogCardUploadDecisions(upload_decision_metrics_);
+    pending_upload_request_origin_ = url::Origin();
+    return;
+  }
   // If the relevant feature is enabled, only send the country of the
   // recently-used addresses. We make a copy here to avoid modifying
   // |upload_request_.profiles|, which should always have full addresses even
@@ -650,6 +671,33 @@
     detected_values |= DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT;
   }
 
+  // If we are missing expiration date month or expiration year, signal that
+  // expiration date will be explicitly requested in the offer-to-save bubble.
+  if (base::FeatureList::IsEnabled(
+          features::kAutofillUpstreamEditableExpirationDate)) {
+    if (!upload_request_.card
+             .GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale_)
+             .empty()) {
+      detected_values |= DetectedValue::CARD_EXPIRATION_MONTH;
+    }
+    // Set |USER_PROVIDED_EXPIRATION_DATE| if any of
+    // |CREDIT_CARD_EXP_4_DIGIT_YEAR| or |CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR| is
+    // set.
+    if (!(upload_request_.card
+              .GetInfo(AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale_)
+              .empty()) ||
+        !(upload_request_.card
+              .GetInfo(AutofillType(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR),
+                       app_locale_)
+              .empty())) {
+      detected_values |= DetectedValue::CARD_EXPIRATION_YEAR;
+    }
+    if (!(detected_values & DetectedValue::CARD_EXPIRATION_MONTH) ||
+        !(detected_values & DetectedValue::CARD_EXPIRATION_YEAR)) {
+      detected_values |= DetectedValue::USER_PROVIDED_EXPIRATION_DATE;
+    }
+  }
+
   // If one of the following is true, signal that cardholder name will be
   // explicitly requested in the offer-to-save bubble:
   //  1) Name is conflicting/missing, and the user does NOT have a Google
diff --git a/components/autofill/core/browser/credit_card_save_manager.h b/components/autofill/core/browser/credit_card_save_manager.h
index 6b83ed6..2aea741af 100644
--- a/components/autofill/core/browser/credit_card_save_manager.h
+++ b/components/autofill/core/browser/credit_card_save_manager.h
@@ -56,9 +56,9 @@
     COUNTRY_CODE = 1 << 7,
     // Set if the user is already syncing data from a Google Payments account.
     HAS_GOOGLE_PAYMENTS_ACCOUNT = 1 << 8,
-    // Card expiration month (not currently used).
+    // Card expiration month.
     CARD_EXPIRATION_MONTH = 1 << 9,
-    // Card expiration year (not currently used).
+    // Card expiration year.
     CARD_EXPIRATION_YEAR = 1 << 10,
     // Phone number was found on any address (not currently used).
     PHONE_NUMBER = 1 << 11,
@@ -66,6 +66,10 @@
     // dialog.  In general, this should happen when name is conflicting/missing
     // and the user does not have a Google Payments account.
     USER_PROVIDED_NAME = 1 << 12,
+    // Set if expiration date was explicitly requested in the offer-to-save
+    // dialog. In general, this should happen when expiration date month or year
+    // is missing.
+    USER_PROVIDED_EXPIRATION_DATE = 1 << 13,
   };
 
   // An observer class used by browsertests that gets notified whenever
@@ -238,6 +242,10 @@
   // |true| if the user has opted to upload save their credit card to Google.
   bool user_did_accept_upload_prompt_ = false;
 
+  // |should_request_expiration_date_from_user_| is |true| if the upload save
+  // dialog should request expiration date from the user.
+  bool should_request_expiration_date_from_user_ = false;
+
   // |should_request_name_from_user_| is |true| if the upload save dialog should
   // request cardholder name from the user (prefilled with Google Account name).
   bool should_request_name_from_user_ = false;
@@ -267,6 +275,9 @@
   FRIEND_TEST_ALL_PREFIXES(
       CreditCardSaveManagerTest,
       UploadCreditCard_ShouldRequestCardholderName_ResetBetweenConsecutiveSaves);
+  FRIEND_TEST_ALL_PREFIXES(
+      CreditCardSaveManagerTest,
+      UploadCreditCard_ShouldRequestExpirationDate_ResetBetweenConsecutiveSaves);
 
   DISALLOW_COPY_AND_ASSIGN(CreditCardSaveManager);
 };
diff --git a/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
index 06b1e7c..2291b6f0 100644
--- a/components/autofill/core/browser/credit_card_save_manager_unittest.cc
+++ b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -2287,6 +2287,188 @@
   EXPECT_FALSE(credit_card_save_manager_->should_request_name_from_user_);
 }
 
+// This test ensures |should_request_expiration_date_from_user_|
+// is reset between offers to save.
+TEST_F(
+    CreditCardSaveManagerTest,
+    UploadCreditCard_ShouldRequestExpirationDate_ResetBetweenConsecutiveSaves) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillUpstreamEditableExpirationDate);
+
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, but don't include a expiration date, and submit.
+  credit_card_form.fields[0].value = ASCIIToUTF16("Jane Doe");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("");
+  credit_card_form.fields[3].value = ASCIIToUTF16("");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+  // With the offer-to-save decision deferred to Google Payments, Payments can
+  // still decide to allow saving despite the missing expiration date.
+  FormSubmitted(credit_card_form);
+  EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
+  EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
+
+  // Verify the |credit_card_save_manager_| is requesting expiration date.
+  EXPECT_TRUE(
+      credit_card_save_manager_->should_request_expiration_date_from_user_);
+
+  // Edit the data, include a expiration date, and submit this time.
+  credit_card_form.fields[0].value = ASCIIToUTF16("Jane Doe");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth());
+  credit_card_form.fields[3].value = ASCIIToUTF16(NextYear());
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+  FormSubmitted(credit_card_form);
+
+  // Verify the |credit_card_save_manager_| is NOT requesting expiration date.
+  EXPECT_FALSE(
+      credit_card_save_manager_->should_request_expiration_date_from_user_);
+}
+
+TEST_F(
+    CreditCardSaveManagerTest,
+    UploadCreditCard_DoNotRequestExpirationDateIfMissingNameAndExpirationDate) {
+  scoped_feature_list_.InitWithFeatures(
+      {features::kAutofillUpstreamEditableExpirationDate,
+       features::kAutofillUpstreamEditableCardholderName},
+      {});
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  // But omit the name:
+  ManuallyFillAddressForm("", "", "77401", "US", &address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, and submit.
+  credit_card_form.fields[0].value = ASCIIToUTF16("");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("");
+  credit_card_form.fields[3].value = ASCIIToUTF16("");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+  base::HistogramTester histogram_tester;
+
+  FormSubmitted(credit_card_form);
+  EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
+  EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded());
+}
+
+TEST_F(CreditCardSaveManagerTest,
+       UploadCreditCard_RequestExpirationDateIfTestingExperimentOn) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillUpstreamEditableExpirationDate);
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm("John", "Smith", "77401", "US", &address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, and submit.
+  credit_card_form.fields[0].value = ASCIIToUTF16("John Smith");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("");
+  credit_card_form.fields[3].value = ASCIIToUTF16("");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+  FormSubmitted(credit_card_form);
+  EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
+  EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
+  EXPECT_TRUE(
+      payments_client_->detected_values_in_upload_details() &
+      CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
+}
+
+TEST_F(CreditCardSaveManagerTest,
+       UploadCreditCard_RequestExpirationDateIfOnlyMonthMissing) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillUpstreamEditableExpirationDate);
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm("John", "Smith", "77401", "US", &address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, and submit.
+  credit_card_form.fields[0].value = ASCIIToUTF16("John Smith");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("");
+  credit_card_form.fields[3].value = ASCIIToUTF16(NextYear());
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+  FormSubmitted(credit_card_form);
+  EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
+  EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
+  EXPECT_TRUE(
+      payments_client_->detected_values_in_upload_details() &
+      CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
+}
+
+TEST_F(CreditCardSaveManagerTest,
+       UploadCreditCard_RequestExpirationDateIfOnlyYearMissing) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillUpstreamEditableExpirationDate);
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm("John", "Smith", "77401", "US", &address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, and submit.
+  credit_card_form.fields[0].value = ASCIIToUTF16("John Smith");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth());
+  credit_card_form.fields[3].value = ASCIIToUTF16("");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+  FormSubmitted(credit_card_form);
+  EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
+  EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
+  EXPECT_TRUE(
+      payments_client_->detected_values_in_upload_details() &
+      CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
+}
+
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_RequestCardholderNameIfTestingExperimentOn) {
   scoped_feature_list_.InitAndEnableFeature(
diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc
index 88a452f..0093b82 100644
--- a/components/autofill/core/browser/credit_card_unittest.cc
+++ b/components/autofill/core/browser/credit_card_unittest.cc
@@ -607,17 +607,15 @@
             CreditCard::IconResourceId(kVisaCard));
 }
 
-TEST(CreditCardTest, UpdateFromImportedCard) {
+TEST(CreditCardTest, UpdateFromImportedCard_UpdatedWithNameAndExpirationDate) {
   CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
                           "09", "2017", "1");
-
   CreditCard a = original_card;
 
-  // The new card has a different name, expiration date, and origin.
+  // The new card has a different name, expiration date.
   CreditCard b = a;
   b.set_guid(base::GenerateGUID());
-  b.set_origin(test::kEmptyOrigin);
   b.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
   b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
   b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
@@ -628,12 +626,73 @@
   EXPECT_EQ(ASCIIToUTF16("J. Dillinger"), a.GetRawInfo(CREDIT_CARD_NAME_FULL));
   EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
   EXPECT_EQ(ASCIIToUTF16("2019"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
 
-  // Try again, but with no name set for |b|.
+TEST(CreditCardTest,
+     UpdateFromImportedCard_UpdatedWithNameAndInvalidExpirationDateMonth) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+  CreditCard a = original_card;
+
+  // The new card has a different name and empty origin and invalid expiration
+  // date month
+  // |a| should be updated with |b|'s name and keep its original expiration
+  // date.
+  CreditCard b = a;
+  b.set_guid(base::GenerateGUID());
+  b.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("0"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
+
+  EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
+  EXPECT_EQ(test::kEmptyOrigin, a.origin());
+  EXPECT_EQ(ASCIIToUTF16("J. Dillinger"), a.GetRawInfo(CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ(ASCIIToUTF16("09"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
+  EXPECT_EQ(ASCIIToUTF16("2017"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
+
+TEST(CreditCardTest,
+     UpdateFromImportedCard_UpdatedWithNameAndInvalidExpirationDateYear) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+
+  CreditCard a = original_card;
+
+  // The new card has a different name and empty origin and invalid expiration
+  // date year
+  // |a| should be updated with |b|'s name and keep its original expiration
+  // date.
+  CreditCard b = a;
+  b.set_guid(base::GenerateGUID());
+  b.set_origin(test::kEmptyOrigin);
+  b.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("09"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16(""));
+
+  EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
+  EXPECT_EQ(test::kEmptyOrigin, a.origin());
+  EXPECT_EQ(ASCIIToUTF16("J. Dillinger"), a.GetRawInfo(CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ(ASCIIToUTF16("09"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
+  EXPECT_EQ(ASCIIToUTF16("2017"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
+
+TEST(CreditCardTest,
+     UpdateFromImportedCard_UpdatedWithEmptyNameAndValidExpirationDate) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+  CreditCard a = original_card;
+
+  // A valid new expiration date and no name set for |b|.
   // |a| should be updated with |b|'s expiration date and keep its original
   // name.
-  a = original_card;
+  CreditCard b = a;
+  b.set_guid(base::GenerateGUID());
   b.SetRawInfo(CREDIT_CARD_NAME_FULL, base::string16());
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
 
   EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
   EXPECT_EQ(test::kEmptyOrigin, a.origin());
@@ -641,12 +700,76 @@
             a.GetRawInfo(CREDIT_CARD_NAME_FULL));
   EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
   EXPECT_EQ(ASCIIToUTF16("2019"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
 
-  // Try again, but with only the original card having a verified origin.
+TEST(
+    CreditCardTest,
+    UpdateFromImportedCard_VerifiedCardNotUpdatedWithEmptyExpirationDateMonth) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+
+  CreditCard a = original_card;
+
+  // Empty expiration date month set for |b| and original card verified.
   // |a| should be unchanged.
-  a = original_card;
-  a.set_origin(kSettingsOrigin);
+  CreditCard b = a;
+  b.set_guid(base::GenerateGUID());
+  a.set_origin("Chrome settings");
+  b.set_origin(test::kEmptyOrigin);
   b.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("0"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
+
+  EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
+  EXPECT_EQ("Chrome settings", a.origin());
+  EXPECT_EQ(ASCIIToUTF16("John Dillinger"),
+            a.GetRawInfo(CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ(ASCIIToUTF16("09"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
+  EXPECT_EQ(ASCIIToUTF16("2017"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
+
+TEST(CreditCardTest,
+     UpdateFromImportedCard_VerifiedCardNotUpdatedWithEmptyExpirationDateYear) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+  CreditCard a = original_card;
+
+  // Empty expiration date year set for |b| and original card verified.
+  // |a| should be unchanged.
+  CreditCard b = a;
+  b.set_guid(base::GenerateGUID());
+  a.set_origin("Chrome settings");
+  b.set_origin(test::kEmptyOrigin);
+  b.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("09"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("0"));
+
+  EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
+  EXPECT_EQ("Chrome settings", a.origin());
+  EXPECT_EQ(ASCIIToUTF16("John Dillinger"),
+            a.GetRawInfo(CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ(ASCIIToUTF16("09"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
+  EXPECT_EQ(ASCIIToUTF16("2017"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
+
+TEST(CreditCardTest,
+     UpdateFromImportedCard_VerifiedCardNotUpdatedWithDifferentName) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+  CreditCard a = original_card;
+
+  // New card is from empty origin and has an different name.
+  // |a| should be unchanged.
+  CreditCard b = a;
+  b.set_guid(base::GenerateGUID());
+  a.set_origin(kSettingsOrigin);
+  b.set_origin(test::kEmptyOrigin);
+  b.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2017"));
 
   EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
   EXPECT_EQ(kSettingsOrigin, a.origin());
@@ -654,12 +777,26 @@
             a.GetRawInfo(CREDIT_CARD_NAME_FULL));
   EXPECT_EQ(ASCIIToUTF16("09"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
   EXPECT_EQ(ASCIIToUTF16("2017"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
 
-  // Try again, but with using an expired verified original card.
-  // |a| should not be updated because the name on the cards are not identical.
-  a = original_card;
+TEST(CreditCardTest,
+     UpdateFromImportedCard_ExpiredVerifiedCardNotUpdatedWithDifferentName) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+  CreditCard a = original_card;
+
+  // New card is from empty origin and has a different name.
+  // |a| is an expired verified original card and should not be updated because
+  // the name on the cards are not identical with |b|.
+  CreditCard b = a;
   a.set_origin("Chrome settings");
   a.SetExpirationYear(2010);
+  b.set_guid(base::GenerateGUID());
+  b.set_origin(test::kEmptyOrigin);
+  b.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
 
   EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
   EXPECT_EQ("Chrome settings", a.origin());
@@ -667,67 +804,109 @@
             a.GetRawInfo(CREDIT_CARD_NAME_FULL));
   EXPECT_EQ(ASCIIToUTF16("09"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
   EXPECT_EQ(ASCIIToUTF16("2010"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
 
-  // Try again, but with using identical name on the cards.
+TEST(CreditCardTest,
+     UpdateFromImportedCard_ExpiredVerifiedCardUpdatedWithSameName) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+  CreditCard a = original_card;
+
+  // New card is from empty origin and has a same name.
+  // |a| is an expired verified original card.
   // |a|'s expiration date should be updated.
-  a = original_card;
+  CreditCard b = a;
   a.set_origin("Chrome settings");
   a.SetExpirationYear(2010);
-  a.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
+  b.set_guid(base::GenerateGUID());
+  b.set_origin(test::kEmptyOrigin);
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
 
   EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
   EXPECT_EQ("Chrome settings", a.origin());
-  EXPECT_EQ(ASCIIToUTF16("J. Dillinger"), a.GetRawInfo(CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ(ASCIIToUTF16("John Dillinger"),
+            a.GetRawInfo(CREDIT_CARD_NAME_FULL));
   EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
   EXPECT_EQ(ASCIIToUTF16("2019"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
 
-  // Try again, but with |b| being expired.
+TEST(CreditCardTest,
+     UpdateFromImportedCard_ExpiredOriginalCardVerifiedUpdatedWithExpiredCard) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+  CreditCard a = original_card;
+
+  // New card is expired and from empty origin.
+  // |a| is an expired verified original card.
   // |a|'s expiration date should not be updated.
-  a = original_card;
+  CreditCard b = a;
   a.set_origin("Chrome settings");
   a.SetExpirationYear(2010);
-  a.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
-  b.SetExpirationYear(2009);
+  b.set_guid(base::GenerateGUID());
+  b.set_origin(test::kEmptyOrigin);
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2009"));
 
   EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
   EXPECT_EQ("Chrome settings", a.origin());
-  EXPECT_EQ(ASCIIToUTF16("J. Dillinger"), a.GetRawInfo(CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ(ASCIIToUTF16("John Dillinger"),
+            a.GetRawInfo(CREDIT_CARD_NAME_FULL));
   EXPECT_EQ(ASCIIToUTF16("09"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
   EXPECT_EQ(ASCIIToUTF16("2010"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
 
-  // Put back |b|'s initial expiration date.
-  b.SetExpirationYear(2019);
+TEST(CreditCardTest,
+     UpdateFromImportedCard_VerifiedCardUpdatedWithVerifiedCard) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+  CreditCard a = original_card;
 
-  // Try again, but with only the new card having a verified origin.
-  // |a| should be updated.
-  a = original_card;
+  // New card is verified.
+  // |a| is an expired verified original card.
+  // |a|'s expiration date should be updated.
+  CreditCard b = a;
+  a.set_origin("Chrome settings");
+  b.set_guid(base::GenerateGUID());
   b.set_origin(kSettingsOrigin);
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
 
   EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
-  EXPECT_EQ(kSettingsOrigin, a.origin());
-  EXPECT_EQ(ASCIIToUTF16("J. Dillinger"), a.GetRawInfo(CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ("Chrome settings", a.origin());
+  EXPECT_EQ(ASCIIToUTF16("John Dillinger"),
+            a.GetRawInfo(CREDIT_CARD_NAME_FULL));
   EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
   EXPECT_EQ(ASCIIToUTF16("2019"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+}
 
-  // Try again, with both cards having a verified origin.
-  // |a| should be updated.
-  a = original_card;
-  a.set_origin("Chrome Autofill dialog");
+TEST(CreditCardTest,
+     UpdateFromImportedCard_VerifiedCardNotUpdatedWithDifferentCard) {
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
+                          "09", "2017", "1");
+  CreditCard a = original_card;
+
+  // New card has diffenrent card number.
+  // |a| is an expired verified original card.
+  // |a|'s expiration date should be updated.
+  CreditCard b = a;
+  a.set_origin("Chrome settings");
+  b.set_guid(base::GenerateGUID());
   b.set_origin(kSettingsOrigin);
-
-  EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
-  EXPECT_EQ(kSettingsOrigin, a.origin());
-  EXPECT_EQ(ASCIIToUTF16("J. Dillinger"), a.GetRawInfo(CREDIT_CARD_NAME_FULL));
-  EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
-  EXPECT_EQ(ASCIIToUTF16("2019"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
-
-  // Try again, but with |b| having a different card number.
-  // |a| should be unchanged.
-  a = original_card;
   b.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("4111111111111111"));
+  b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
+  b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
 
   EXPECT_FALSE(a.UpdateFromImportedCard(b, "en-US"));
-  EXPECT_EQ(original_card, a);
+  EXPECT_EQ("Chrome settings", a.origin());
+  EXPECT_EQ(ASCIIToUTF16("John Dillinger"),
+            a.GetRawInfo(CREDIT_CARD_NAME_FULL));
+  EXPECT_EQ(ASCIIToUTF16("09"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
+  EXPECT_EQ(ASCIIToUTF16("2017"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
 }
 
 TEST(CreditCardTest, IsValidCardNumberAndExpiryDate) {
diff --git a/components/autofill/core/browser/form_data_importer.cc b/components/autofill/core/browser/form_data_importer.cc
index 48c54bc..df485ac8 100644
--- a/components/autofill/core/browser/form_data_importer.cc
+++ b/components/autofill/core/browser/form_data_importer.cc
@@ -29,6 +29,7 @@
 #include "components/autofill/core/browser/phone_number.h"
 #include "components/autofill/core/browser/phone_number_i18n.h"
 #include "components/autofill/core/browser/validation.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_util.h"
 
 namespace autofill {
@@ -379,7 +380,10 @@
   if (has_duplicate_field_type)
     return false;
 
-  if (!candidate_credit_card.IsValid()) {
+  if (candidate_credit_card.IsValid()) {
+    AutofillMetrics::LogSubmittedCardStateMetric(
+        AutofillMetrics::HAS_CARD_NUMBER_AND_EXPIRATION_DATE);
+  } else {
     if (candidate_credit_card.HasValidCardNumber()) {
       AutofillMetrics::LogSubmittedCardStateMetric(
           AutofillMetrics::HAS_CARD_NUMBER_ONLY);
@@ -388,11 +392,20 @@
       AutofillMetrics::LogSubmittedCardStateMetric(
           AutofillMetrics::HAS_EXPIRATION_DATE_ONLY);
     }
+  }
 
+  // If editable expiration date experiment is enabled, the card with invalid
+  // expiration date can be uploaded. However, the card with invalid card number
+  // must be ignored.
+  if (!candidate_credit_card.HasValidCardNumber()) {
     return false;
   }
-  AutofillMetrics::LogSubmittedCardStateMetric(
-      AutofillMetrics::HAS_CARD_NUMBER_AND_EXPIRATION_DATE);
+  if (!candidate_credit_card.HasValidExpirationDate() &&
+      !base::FeatureList::IsEnabled(
+          features::kAutofillUpstreamEditableExpirationDate)) {
+    return false;
+  }
+
   // Can import one valid card per form. Start by treating it as NEW_CARD, but
   // overwrite this type if we discover it is already a local or server card.
   imported_credit_card_record_type_ = ImportedCreditCardRecordType::NEW_CARD;
@@ -430,6 +443,11 @@
   for (const CreditCard* card :
        personal_data_manager_->GetServerCreditCards()) {
     if (candidate_credit_card.HasSameNumberAs(*card)) {
+      // Don't update card if the expiration date is missing
+      if (candidate_credit_card.expiration_month() == 0 ||
+          candidate_credit_card.expiration_year() == 0) {
+        return false;
+      }
       // Mark that the imported credit card is a server card.
       imported_credit_card_record_type_ =
           ImportedCreditCardRecordType::SERVER_CARD;
diff --git a/components/autofill/core/browser/form_data_importer.h b/components/autofill/core/browser/form_data_importer.h
index e7bc5b6..7af4149 100644
--- a/components/autofill/core/browser/form_data_importer.h
+++ b/components/autofill/core/browser/form_data_importer.h
@@ -196,7 +196,12 @@
   FRIEND_TEST_ALL_PREFIXES(
       FormDataImporterTest,
       Metrics_SubmittedServerCardExpirationStatus_MaskedServerCardMismatch);
-
+  FRIEND_TEST_ALL_PREFIXES(
+      FormDataImporterTest,
+      Metrics_SubmittedServerCardExpirationStatus_EmptyExpirationMonth);
+  FRIEND_TEST_ALL_PREFIXES(
+      FormDataImporterTest,
+      Metrics_SubmittedServerCardExpirationStatus_EmptyExpirationYear);
   DISALLOW_COPY_AND_ASSIGN(FormDataImporter);
 };
 
diff --git a/components/autofill/core/browser/form_data_importer_unittest.cc b/components/autofill/core/browser/form_data_importer_unittest.cc
index b241ed5..f4b13ae 100644
--- a/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -38,6 +38,7 @@
 #include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_prefs.h"
 #include "components/autofill/core/common/autofill_switches.h"
 #include "components/autofill/core/common/autofill_util.h"
@@ -228,6 +229,7 @@
   std::unique_ptr<TestAutofillClient> autofill_client_;
   std::unique_ptr<PersonalDataManager> personal_data_manager_;
   std::unique_ptr<FormDataImporter> form_data_importer_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 class FormDataImporterTest : public FormDataImporterTestBase,
@@ -1493,6 +1495,27 @@
   ASSERT_EQ(0U, personal_data_manager_->GetCreditCards().size());
 }
 
+// Tests that an empty credit card expiration is extracted when editable
+// expiration date experiment on.
+TEST_F(FormDataImporterTest,
+       ImportCreditCard_InvalidExpiryDate_EditableExpirationExpOn) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillUpstreamEditableExpirationDate);
+  FormData form;
+  form.origin = GURL("https://wwww.foo.com");
+
+  AddFullCreditCardForm(&form, "Smalls Biggie", "4111-1111-1111-1111", "", "");
+
+  FormStructure form_structure(form);
+  form_structure.DetermineHeuristicTypes();
+  std::unique_ptr<CreditCard> imported_credit_card;
+  base::HistogramTester histogram_tester;
+  EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
+  ASSERT_TRUE(imported_credit_card);
+  histogram_tester.ExpectUniqueSample("Autofill.SubmittedCardState",
+                                      AutofillMetrics::HAS_CARD_NUMBER_ONLY, 1);
+}
+
 // Tests that a valid credit card is extracted when the option text for month
 // select can't be parsed but its value can.
 TEST_F(FormDataImporterTest, ImportCreditCard_MonthSelectInvalidText) {
@@ -2873,6 +2896,102 @@
       AutofillMetrics::FULL_SERVER_CARD_EXPIRATION_DATE_MATCHED, 1);
 }
 
+// Ensure that we don't offer to save if we already have same card stored as a
+// server card and user submitted an invalid expiration date month.
+TEST_F(FormDataImporterTest,
+       Metrics_SubmittedServerCardExpirationStatus_EmptyExpirationMonth) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillUpstreamEditableExpirationDate);
+  EnableWalletCardImport();
+
+  std::vector<CreditCard> server_cards;
+  server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
+  test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
+                          "4444333322221111" /* Visa */, "04", "2111", "1");
+
+  test::SetServerCreditCards(autofill_table_, server_cards);
+
+  // Make sure everything is set up correctly.
+  personal_data_manager_->Refresh();
+  WaitForOnPersonalDataChanged();
+  EXPECT_EQ(1U, personal_data_manager_->GetCreditCards().size());
+
+  // A user fills/enters the card's information on a checkout form with an empty
+  // expiration date.
+  FormData form;
+  form.origin = GURL("https://wwww.foo.com");
+
+  FormFieldData field;
+  test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow",
+                            "text", &field);
+  form.fields.push_back(field);
+  test::CreateTestFormField("Card Number:", "card_number", "4444333322221111",
+                            "text", &field);
+  form.fields.push_back(field);
+  test::CreateTestFormField("Exp Month:", "exp_month", "", "text", &field);
+  form.fields.push_back(field);
+  test::CreateTestFormField("Exp Year:", "exp_year", "2111", "text", &field);
+  form.fields.push_back(field);
+
+  FormStructure form_structure(form);
+  form_structure.DetermineHeuristicTypes();
+  std::unique_ptr<CreditCard> imported_credit_card;
+  EXPECT_FALSE(form_data_importer_->ImportFormData(
+      form_structure,
+      /*profile_autofill_enabled=*/true,
+      /*credit_card_autofill_enabled=*/true,
+      /*should_return_local_card=*/false, &imported_credit_card));
+  EXPECT_FALSE(imported_credit_card);
+}
+
+// Ensure that we don't offer to save if we already have same card stored as a
+// server card and user submitted an invalid expiration date year.
+TEST_F(FormDataImporterTest,
+       Metrics_SubmittedServerCardExpirationStatus_EmptyExpirationYear) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillUpstreamEditableExpirationDate);
+  EnableWalletCardImport();
+
+  std::vector<CreditCard> server_cards;
+  server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
+  test::SetCreditCardInfo(&server_cards.back(), "Clyde Barrow",
+                          "4444333322221111" /* Visa */, "04", "2111", "1");
+
+  test::SetServerCreditCards(autofill_table_, server_cards);
+
+  // Make sure everything is set up correctly.
+  personal_data_manager_->Refresh();
+  WaitForOnPersonalDataChanged();
+  EXPECT_EQ(1U, personal_data_manager_->GetCreditCards().size());
+
+  // A user fills/enters the card's information on a checkout form with an empty
+  // expiration date.
+  FormData form;
+  form.origin = GURL("https://wwww.foo.com");
+
+  FormFieldData field;
+  test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow",
+                            "text", &field);
+  form.fields.push_back(field);
+  test::CreateTestFormField("Card Number:", "card_number", "4444333322221111",
+                            "text", &field);
+  form.fields.push_back(field);
+  test::CreateTestFormField("Exp Month:", "exp_month", "08", "text", &field);
+  form.fields.push_back(field);
+  test::CreateTestFormField("Exp Year:", "exp_year", "", "text", &field);
+  form.fields.push_back(field);
+
+  FormStructure form_structure(form);
+  form_structure.DetermineHeuristicTypes();
+  std::unique_ptr<CreditCard> imported_credit_card;
+  EXPECT_FALSE(form_data_importer_->ImportFormData(
+      form_structure,
+      /*profile_autofill_enabled=*/true,
+      /*credit_card_autofill_enabled=*/true,
+      /*should_return_local_card=*/false, &imported_credit_card));
+  EXPECT_FALSE(imported_credit_card);
+}
+
 TEST_F(FormDataImporterTest,
        Metrics_SubmittedServerCardExpirationStatus_FullServerCardMismatch) {
   EnableWalletCardImport();
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index cf61cce..ed99220 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -258,6 +258,10 @@
     "AutofillUpstreamEditableCardholderName",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kAutofillUpstreamEditableExpirationDate{
+    "AutofillUpstreamEditableExpirationDate",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether the credit card upload bubble shows the Google Pay logo and
 // a shorter "Save card?" header message on mobile.
 const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile{
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 98996fd..1e4c472 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -73,6 +73,7 @@
 extern const base::Feature kAutofillUpstreamDisallowElo;
 extern const base::Feature kAutofillUpstreamDisallowJcb;
 extern const base::Feature kAutofillUpstreamEditableCardholderName;
+extern const base::Feature kAutofillUpstreamEditableExpirationDate;
 extern const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile;
 extern const base::Feature kAutofillUsePaymentsCustomerData;
 extern const base::Feature kAutomaticPasswordGeneration;
diff --git a/components/cryptauth/cryptauth_device_manager_impl.cc b/components/cryptauth/cryptauth_device_manager_impl.cc
index b42f294..8d2541b 100644
--- a/components/cryptauth/cryptauth_device_manager_impl.cc
+++ b/components/cryptauth/cryptauth_device_manager_impl.cc
@@ -113,6 +113,10 @@
   }
 }
 
+void RecordDeviceSyncResult(bool success) {
+  UMA_HISTOGRAM_BOOLEAN("CryptAuth.DeviceSync.Result", success);
+}
+
 // Converts supported and enabled SoftwareFeature protos to a single dictionary
 // value that can be stored in user prefs.
 std::unique_ptr<base::DictionaryValue>
@@ -646,8 +650,12 @@
   // Update the synced devices stored in the user's prefs.
   std::unique_ptr<base::ListValue> devices_as_list(new base::ListValue());
 
-  if (!response.devices().empty())
+  if (!response.devices().empty()) {
     PA_LOG(VERBOSE) << "Devices were successfully synced.";
+    RecordDeviceSyncResult(true /* success */);
+  } else {
+    RecordDeviceSyncResult(false /* success */);
+  }
 
   for (const auto& device : response.devices()) {
     std::unique_ptr<base::DictionaryValue> device_dictionary =
@@ -695,6 +703,7 @@
   cryptauth_client_.reset();
   sync_request_.reset();
   NotifySyncFinished(SyncResult::FAILURE, DeviceChangeResult::UNCHANGED);
+  RecordDeviceSyncResult(false /* success */);
 }
 
 void CryptAuthDeviceManagerImpl::OnResyncMessage() {
diff --git a/components/data_reduction_proxy/core/common/BUILD.gn b/components/data_reduction_proxy/core/common/BUILD.gn
index 6d9547fd..bd23bdd 100644
--- a/components/data_reduction_proxy/core/common/BUILD.gn
+++ b/components/data_reduction_proxy/core/common/BUILD.gn
@@ -127,7 +127,6 @@
   ]
 
   deps = [
-    "//mojo/public/mojom/base",
     "//services/network/public/mojom",
   ]
 }
diff --git a/components/metrics/metrics_service_client.h b/components/metrics/metrics_service_client.h
index c1bc8285..4fc66e45 100644
--- a/components/metrics/metrics_service_client.h
+++ b/components/metrics/metrics_service_client.h
@@ -130,8 +130,8 @@
   // Returns whether UKM notification listeners were attached to all profiles.
   virtual bool AreNotificationListenersEnabledOnAllProfiles();
 
-  // Gets the Chrome package name for Android. Returns empty string for other
-  // platforms.
+  // Gets Chrome's package name in Android Chrome, or the host app's package
+  // name in Android WebView, or an empty string on other platforms.
   virtual std::string GetAppPackageName();
 
   // Sets the callback to run MetricsServiceManager::UpdateRunningServices.
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 70128acf..9d54034 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -1273,6 +1273,12 @@
 }
 
 TEST_P(PasswordProtectionServiceTest, VerifyContentTypeIsPopulated) {
+  LoginReputationClientResponse response =
+      CreateVerdictProto(LoginReputationClientResponse::SAFE, 10 * kMinute,
+                         GURL(kTargetUrl).host());
+  test_url_loader_factory_.AddResponse(url_.spec(),
+                                       response.SerializeAsString());
+
   content::WebContents* web_contents = GetWebContents();
 
   content::WebContentsTester::For(web_contents)
diff --git a/components/tracing/common/stack_unwinder_android.cc b/components/tracing/common/stack_unwinder_android.cc
index a1cdd9ca2..e5279b49 100644
--- a/components/tracing/common/stack_unwinder_android.cc
+++ b/components/tracing/common/stack_unwinder_android.cc
@@ -82,9 +82,6 @@
   AsyncSafeWaitableEvent* event_;
 };
 
-using JniMarker = jni_generator::JniJavaCallContextUnchecked;
-using JniMarkers = std::vector<const JniMarker*>;
-
 // Unwinds from given |cursor| readable by libunwind, and returns
 // the number of frames added to the output. This function can unwind through
 // android framework and then chrome functions. It cannot handle the cases when
@@ -92,15 +89,18 @@
 // create the right context for libunwind from chrome functions.
 // TODO(ssid): This function should support unwinding from chrome to android
 // libraries also.
-size_t TraceStackWithContext(unw_cursor_t* cursor,
-                             CFIBacktraceAndroid* cfi_unwinder,
-                             const tracing::StackUnwinderAndroid* unwinder,
-                             const uintptr_t stack_segment_base,
-                             const JniMarkers& jni_markers,
-                             const void** out_trace,
-                             const size_t max_depth) {
+size_t TraceStackWithContext(
+    unw_cursor_t* cursor,
+    CFIBacktraceAndroid* cfi_unwinder,
+    const tracing::StackUnwinderAndroid* unwinder,
+    const uintptr_t stack_segment_base,
+    const std::vector<const tracing::StackUnwinderAndroid::JniMarker*>&
+        jni_markers,
+    const void** out_trace,
+    const size_t max_depth) {
   size_t depth = 0;
   unw_word_t ip = 0, sp = 0;
+  bool try_stack_search = true;
   unw_get_reg(cursor, UNW_REG_SP, &sp);
   const uintptr_t initial_sp = sp;
   uintptr_t previous_sp = 0;
@@ -139,6 +139,7 @@
     unw_get_reg(cursor, UNW_ARM_LR, &lr);
     depth +=
         cfi_unwinder->Unwind(ip, sp, lr, out_trace + depth, max_depth - depth);
+    try_stack_search = false;
   }
   if (depth >= max_depth)
     return depth;
@@ -152,22 +153,112 @@
       continue;
     depth += cfi_unwinder->Unwind(marker->pc, marker->sp, /*lr=*/0,
                                   out_trace + depth, max_depth - depth);
+    try_stack_search = false;
     if (depth >= max_depth)
       break;
   }
 
+  // We tried all possible ways to unwind and failed. So, scan the stack to find
+  // all chrome address and add them to stack trace. This would give us a lot of
+  // false frames on the trace. The idea is to try to sanitize the trace on
+  // server side or try unwinding after each search. The current version just
+  // sends back all PCs untill we figure out what is the best way to sanitize
+  // the stack trace.
+  if (try_stack_search) {
+    uintptr_t* stack = reinterpret_cast<uintptr_t*>(sp);
+    // Add a nullptr to differentiate addresses found by unwinding and scanning.
+    out_trace[depth++] = nullptr;
+    while (depth < max_depth &&
+           reinterpret_cast<uintptr_t>(stack) < stack_segment_base) {
+      if (CFIBacktraceAndroid::is_chrome_address(
+              reinterpret_cast<uintptr_t>(*stack))) {
+        out_trace[depth++] = reinterpret_cast<void*>(*stack);
+      }
+      ++stack;
+    }
+  }
+
   if (depth == 0)
     RecordUnwindResult(SamplingProfilerUnwindResult::kFirstFrameUnmapped);
   return depth;
 }
 
-// Returns the offset of stack pointer for the given program counter in chrome
-// library.
-bool GetCFIForPC(CFIBacktraceAndroid* cfi_unwinder,
-                 uintptr_t pc,
-                 CFIBacktraceAndroid::CFIRow* cfi) {
-  return cfi_unwinder->FindCFIRowForPC(
-      pc - CFIBacktraceAndroid::executable_start_addr(), cfi);
+uintptr_t RewritePointerIfInOriginalStack(uintptr_t addr,
+                                          uintptr_t sp,
+                                          uintptr_t stack_size,
+                                          uintptr_t new_stack_top) {
+  if (addr >= sp && addr < sp + stack_size)
+    return addr - sp + new_stack_top;
+  return addr;
+}
+
+// Creates unwind cursor for the copied stack, which points to the function
+// frame in which the sampled thread was stopped. We get information about this
+// frame from signal context. Replaces registers in the context and cursor to
+// point to the new stack's top function frame.
+bool GetUnwindCursorForStack(uintptr_t sp,
+                             size_t stack_size,
+                             uintptr_t new_stack_top,
+                             const ucontext_t& signal_context,
+                             unw_context_t* context,
+                             unw_cursor_t* cursor) {
+  // Initialize an unwind cursor on copied stack.
+  if (unw_init_local(cursor, context) != 0)
+    return false;
+
+  uintptr_t return_sp = signal_context.uc_mcontext.arm_sp - sp + new_stack_top;
+
+  // Reset the unwind cursor to previous function and continue with libunwind.
+  unw_set_reg(cursor, UNW_REG_SP, return_sp);  // 13
+  unw_set_reg(cursor, UNW_ARM_R0,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r0,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R1,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r1,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R3,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r2,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R3,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r3,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R4,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r4,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R5,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r5,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R6,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r6,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R7,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r7,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R8,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r8,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R9,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r9,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(
+      cursor, UNW_ARM_R10,
+      RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_r10, sp,
+                                      stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R11,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_fp,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_R12,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_ip,
+                                              sp, stack_size, new_stack_top));
+  unw_set_reg(cursor, UNW_ARM_LR,
+              RewritePointerIfInOriginalStack(signal_context.uc_mcontext.arm_lr,
+                                              sp, stack_size, new_stack_top));
+
+  // Setting the IP register might cause adjustments in SP register. So, this
+  // must be set after setting SP to the right value.
+  unw_set_reg(cursor, UNW_REG_IP, signal_context.uc_mcontext.arm_pc);  // 15
+
+  return true;
 }
 
 // Struct to store the arguments to the signal handler.
@@ -183,6 +274,8 @@
   unw_context_t* context;
   // The value of Stack pointer of the thread.
   uintptr_t* sp;
+  // The context of the return function from signal context.
+  ucontext_t* ucontext;
   // Buffer to copy the stack segment.
   base::NativeStackSampler::StackBuffer* stack_buffer;
   size_t* stack_size;
@@ -214,6 +307,8 @@
   asm volatile("mov %0, sp" : "=r"(sp));
   *params->sp = sp;
 
+  memcpy(params->ucontext, sigcontext, sizeof(ucontext_t));
+
   uintptr_t stack_base_addr = params->unwinder->GetEndAddressOfRegion(sp);
   *params->stack_size = stack_base_addr - sp;
   if (stack_base_addr == 0 ||
@@ -298,7 +393,8 @@
     return 0;
   return TraceStackWithContext(
       &cursor, CFIBacktraceAndroid::GetInitializedInstance(), this,
-      /* stack_segment_base=*/0, JniMarkers(), out_trace, max_depth);
+      /* stack_segment_base=*/0, std::vector<const JniMarker*>(), out_trace,
+      max_depth);
 }
 
 size_t StackUnwinderAndroid::TraceStack(
@@ -310,13 +406,74 @@
   // copies the stack of the thread and returns. This function tries to unwind
   // stack frames from the copied stack.
   DCHECK(is_initialized_);
-  AsyncSafeWaitableEvent wait_event;
   size_t stack_size;
-  bool copied = false;
   unw_context_t context;
   uintptr_t sp = 0;
-  HandlerParams params = {this, &wait_event,  &copied,    &context,
-                          &sp,  stack_buffer, &stack_size};
+  ucontext_t signal_context = {};
+  if (!SuspendThreadAndRecordStack(tid, stack_buffer, &sp, &stack_size,
+                                   &context, &signal_context)) {
+    RecordUnwindResult(SamplingProfilerUnwindResult::kStackCopyFailed);
+    return 0;
+  }
+
+  const uintptr_t new_stack_top =
+      reinterpret_cast<uintptr_t>(stack_buffer->buffer());
+  uintptr_t ip = signal_context.uc_mcontext.arm_pc;
+  uintptr_t return_sp = signal_context.uc_mcontext.arm_sp - sp + new_stack_top;
+
+  auto* cfi_unwinder = CFIBacktraceAndroid::GetInitializedInstance();
+  // Do not use libunwind if we stopped at chrome frame.
+  if (CFIBacktraceAndroid::is_chrome_address(ip)) {
+    return cfi_unwinder->Unwind(
+        ip, return_sp, signal_context.uc_mcontext.arm_lr, out_trace, max_depth);
+  }
+
+  std::vector<const JniMarker*> jni_markers =
+      RewritePointersAndGetMarkers(stack_buffer, sp, stack_size);
+
+  unw_cursor_t cursor;
+  if (!GetUnwindCursorForStack(sp, stack_size, new_stack_top, signal_context,
+                               &context, &cursor)) {
+    RecordUnwindResult(SamplingProfilerUnwindResult::kUnwindInitFailed);
+    return 0;
+  }
+
+  return TraceStackWithContext(
+      &cursor, cfi_unwinder, this,
+      reinterpret_cast<uintptr_t>(stack_buffer->buffer()) + stack_size,
+      jni_markers, out_trace, max_depth);
+}
+
+uintptr_t StackUnwinderAndroid::GetEndAddressOfRegion(uintptr_t addr) const {
+  auto it =
+      std::lower_bound(regions_.begin(), regions_.end(), addr,
+                       [](const MappedMemoryRegion& region, uintptr_t addr) {
+                         return region.start < addr;
+                       });
+  if (it == regions_.begin())
+    return 0;
+  --it;
+  if (it->start <= addr && it->end > addr)
+    return it->end;
+  return 0;
+}
+
+bool StackUnwinderAndroid::IsAddressMapped(uintptr_t pc) const {
+  // TODO(ssid): We only need to check regions which are file mapped.
+  return GetEndAddressOfRegion(pc) != 0;
+}
+
+bool StackUnwinderAndroid::SuspendThreadAndRecordStack(
+    base::PlatformThreadId tid,
+    base::NativeStackSampler::StackBuffer* stack_buffer,
+    uintptr_t* sp,
+    size_t* stack_size,
+    unw_context_t* context,
+    ucontext_t* signal_context) const {
+  AsyncSafeWaitableEvent wait_event;
+  bool copied = false;
+  HandlerParams params = {this, &wait_event,    &copied,      context,
+                          sp,   signal_context, stack_buffer, stack_size};
   base::subtle::Release_Store(&g_handler_params,
                               reinterpret_cast<uintptr_t>(&params));
 
@@ -343,37 +500,27 @@
     }
   }
   base::subtle::Release_Store(&g_handler_params, 0);
-  if (!copied) {
-    RecordUnwindResult(SamplingProfilerUnwindResult::kStackCopyFailed);
-    return 0;
-  }
+  return copied;
+}
 
-  // Context contains list of saved registers. Replace the SP and any register
-  // that points to address on the previous stack to point to the copied stack.
-  const uintptr_t relocation_offset =
-      reinterpret_cast<uintptr_t>(stack_buffer->buffer()) - sp;
-  bool replaced_sp = false;
-  uintptr_t* register_context = reinterpret_cast<uintptr_t*>(&context);
-  for (size_t i = 0; i < 16; ++i) {
-    if (register_context[i] >= sp && register_context[i] < sp + stack_size) {
-      replaced_sp = replaced_sp || register_context[i] == sp;
-      register_context[i] += relocation_offset;
-    }
-  }
-  DCHECK(replaced_sp);
-
+std::vector<const StackUnwinderAndroid::JniMarker*>
+StackUnwinderAndroid::RewritePointersAndGetMarkers(
+    base::NativeStackSampler::StackBuffer* stack_buffer,
+    uintptr_t sp,
+    size_t stack_size) const {
+  std::vector<const JniMarker*> jni_markers;
   uintptr_t* new_stack = reinterpret_cast<uintptr_t*>(stack_buffer->buffer());
   constexpr uintptr_t marker_l =
                           jni_generator::kJniStackMarkerValue & 0xFFFFFFFF,
                       marker_r = jni_generator::kJniStackMarkerValue >> 32;
-  JniMarkers jni_markers;
+  const uintptr_t new_stack_top =
+      reinterpret_cast<uintptr_t>(stack_buffer->buffer());
   for (size_t i = 0; i < stack_size / sizeof(uintptr_t); ++i) {
     if (new_stack[i] == marker_r && i > 0 && new_stack[i - 1] == marker_l) {
       // Note: JniJavaCallContext::sp will be replaced with offset below.
       const JniMarker* marker =
           reinterpret_cast<const JniMarker*>(new_stack + i - 1);
-      DCHECK_EQ(jni_generator::kJniStackMarkerValue,
-                jni_markers.back()->marker);
+      DCHECK_EQ(jni_generator::kJniStackMarkerValue, marker->marker);
       if (marker->sp >= sp && marker->sp < sp + stack_size &&
           CFIBacktraceAndroid::is_chrome_address(marker->pc)) {
         jni_markers.push_back(marker);
@@ -385,67 +532,9 @@
     // Unwind can use address on the stack. So, replace them as well. See EHABI
     // #7.5.4 table 3.
     if (new_stack[i] >= sp && new_stack[i] < sp + stack_size)
-      new_stack[i] += relocation_offset;
+      new_stack[i] = new_stack[i] - sp + new_stack_top;
   }
-
-  // Initialize an unwind cursor on copied stack.
-  unw_cursor_t cursor;
-  if (unw_init_local(&cursor, &context) != 0) {
-    RecordUnwindResult(SamplingProfilerUnwindResult::kUnwindInitFailed);
-    return 0;
-  }
-  uintptr_t ip = 0;
-  unw_get_reg(&cursor, UNW_REG_SP, &sp);
-  DCHECK_EQ(sp, reinterpret_cast<uintptr_t>(stack_buffer->buffer()));
-  unw_get_reg(&cursor, UNW_REG_IP, &ip);
-
-  // Unwind handler function (ThreadSignalHandler()) since libunwind cannot
-  // handle chrome functions. Then call either libunwind or use chrome's
-  // unwinder based on the next function in the stack.
-  auto* cfi_unwinder = CFIBacktraceAndroid::GetInitializedInstance();
-  static CFIBacktraceAndroid::CFIRow cfi;
-  static bool found = GetCFIForPC(cfi_unwinder, ip, &cfi);
-  if (!found) {
-    RecordUnwindResult(SamplingProfilerUnwindResult::kHandlerUnwindFailed);
-    return 0;
-  }
-  sp = sp + cfi.cfa_offset;
-  memcpy(&ip, reinterpret_cast<uintptr_t*>(sp - cfi.ra_offset),
-         sizeof(uintptr_t));
-
-  // Do not use libunwind if we stopped at chrome frame.
-  if (CFIBacktraceAndroid::is_chrome_address(ip))
-    return cfi_unwinder->Unwind(ip, sp, 0, out_trace, max_depth);
-
-  // Reset the unwind cursor to previous function and continue with libunwind.
-  // TODO(ssid): Dynamic allocation functions might require registers to be
-  // restored.
-  unw_set_reg(&cursor, UNW_REG_SP, sp);
-  unw_set_reg(&cursor, UNW_REG_IP, ip);
-
-  return TraceStackWithContext(
-      &cursor, cfi_unwinder, this,
-      reinterpret_cast<uintptr_t>(stack_buffer->buffer()) + stack_size,
-      jni_markers, out_trace, max_depth);
-}
-
-uintptr_t StackUnwinderAndroid::GetEndAddressOfRegion(uintptr_t addr) const {
-  auto it =
-      std::lower_bound(regions_.begin(), regions_.end(), addr,
-                       [](const MappedMemoryRegion& region, uintptr_t addr) {
-                         return region.start < addr;
-                       });
-  if (it == regions_.begin())
-    return 0;
-  --it;
-  if (it->start <= addr && it->end > addr)
-    return it->end;
-  return 0;
-}
-
-bool StackUnwinderAndroid::IsAddressMapped(uintptr_t pc) const {
-  // TODO(ssid): We only need to check regions which are file mapped.
-  return GetEndAddressOfRegion(pc) != 0;
+  return jni_markers;
 }
 
 }  // namespace tracing
diff --git a/components/tracing/common/stack_unwinder_android.h b/components/tracing/common/stack_unwinder_android.h
index b211eef..539ea1b 100644
--- a/components/tracing/common/stack_unwinder_android.h
+++ b/components/tracing/common/stack_unwinder_android.h
@@ -5,13 +5,21 @@
 #ifndef COMPONENTS_TRACING_COMMON_STACK_UNWINDER_ANDROID_H_
 #define COMPONENTS_TRACING_COMMON_STACK_UNWINDER_ANDROID_H_
 
+#include <ucontext.h>
+
 #include <map>
+#include <vector>
 
 #include "base/debug/proc_maps_linux.h"
 #include "base/profiler/native_stack_sampler.h"
 #include "base/threading/platform_thread.h"
 #include "components/tracing/tracing_export.h"
 
+namespace jni_generator {
+struct JniJavaCallContextUnchecked;
+}
+struct unw_context_t;
+
 namespace tracing {
 
 // Utility to unwind stacks for current thread on ARM devices. Contains ability
@@ -24,6 +32,8 @@
 // instances of this class.
 class TRACING_EXPORT StackUnwinderAndroid {
  public:
+  using JniMarker = jni_generator::JniJavaCallContextUnchecked;
+
   StackUnwinderAndroid();
   ~StackUnwinderAndroid();
 
@@ -53,6 +63,24 @@
   bool is_initialized() const { return is_initialized_; }
 
  private:
+  // Sends a SIGURG signal to the thread with id |tid| and copies the stack
+  // segment of the thread, along with register context. Returns true on
+  // success.
+  bool SuspendThreadAndRecordStack(
+      base::PlatformThreadId tid,
+      base::NativeStackSampler::StackBuffer* stack_buffer,
+      uintptr_t* sp,
+      size_t* stack_size,
+      unw_context_t* context,
+      ucontext_t* signal_context) const;
+
+  // Replaces any pointers to the old stack to point to the new stack segment.
+  // Returns the jni markers found on stack while scanning stack for pointers.
+  std::vector<const JniMarker*> RewritePointersAndGetMarkers(
+      base::NativeStackSampler::StackBuffer* stack_buffer,
+      uintptr_t sp,
+      size_t stack_size) const;
+
   bool is_initialized_ = false;
 
   // Stores all the memory mapped regions in the current process, including all
diff --git a/components/tracing/common/stack_unwinder_android_unittest.cc b/components/tracing/common/stack_unwinder_android_unittest.cc
index 6864ba6d..d044c01 100644
--- a/components/tracing/common/stack_unwinder_android_unittest.cc
+++ b/components/tracing/common/stack_unwinder_android_unittest.cc
@@ -71,10 +71,14 @@
     size_t result =
         unwinder->TraceStack(tid, stack_buffer.get(), frames, kMaxStackFrames);
     EXPECT_GT(result, 0u);
+    bool current_function_found = false;
     for (size_t i = 0; i < result; ++i) {
       uintptr_t addr = reinterpret_cast<uintptr_t>(frames[i]);
       EXPECT_TRUE(unwinder->IsAddressMapped(addr));
+      if (addr >= test_pc && addr < test_pc + 100)
+        current_function_found = true;
     }
+    EXPECT_TRUE(current_function_found);
 
     unwind_finished_event->Signal();
   };
@@ -88,8 +92,6 @@
   // While the background thread is trying to unwind make some slow framework
   // calls (malloc) so that the current thread can be stopped in framework
   // library functions on stack.
-  // TODO(ssid): Test for reliable unwinding through non-chrome and chrome
-  // frames.
   while (true) {
     std::vector<int> temp;
     temp.reserve(kMaxStackFrames);
diff --git a/components/tracing/common/tracing_sampler_profiler.cc b/components/tracing/common/tracing_sampler_profiler.cc
index 60535dc..ee91c95 100644
--- a/components/tracing/common/tracing_sampler_profiler.cc
+++ b/components/tracing/common/tracing_sampler_profiler.cc
@@ -72,8 +72,10 @@
       // For chrome address we do not have symbols on the binary. So, just write
       // the offset address. For addresses on framework libraries, symbolize
       // and write the function name.
-      if (base::trace_event::CFIBacktraceAndroid::is_chrome_address(
-              frame.instruction_pointer)) {
+      if (frame.instruction_pointer == 0) {
+        frame_name = "Scanned";
+      } else if (base::trace_event::CFIBacktraceAndroid::is_chrome_address(
+                     frame.instruction_pointer)) {
         frame_name = GetFrameNameFromOffsetAddr(
             frame.instruction_pointer -
             base::trace_event::CFIBacktraceAndroid::executable_start_addr());
diff --git a/components/update_client/protocol_serializer_xml.cc b/components/update_client/protocol_serializer_xml.cc
index a904f51e..af0bbc6 100644
--- a/components/update_client/protocol_serializer_xml.cc
+++ b/components/update_client/protocol_serializer_xml.cc
@@ -96,6 +96,7 @@
 #endif
 
   for (const auto& app : request.apps) {
+    // Begin <app> attributes.
     base::StringAppendF(&msg, "<app appid=\"%s\"", app.app_id.c_str());
     base::StringAppendF(&msg, " version=\"%s\"", app.version.c_str());
     if (!app.brand_code.empty())
@@ -118,16 +119,16 @@
       base::StringAppendF(&msg, " cohortname=\"%s\"", app.cohort_name.c_str());
     if (!app.cohort_hint.empty())
       base::StringAppendF(&msg, " cohorthint=\"%s\"", app.cohort_hint.c_str());
-
     if (app.enabled)
       base::StringAppendF(&msg, " enabled=\"%d\"", *app.enabled ? 1 : 0);
+    base::StringAppendF(&msg, ">");
+    // End <app> attributes.
+
     if (app.disabled_reasons) {
       for (const int disabled_reason : *app.disabled_reasons)
         base::StringAppendF(&msg, "<disabled reason=\"%d\"/>", disabled_reason);
     }
 
-    base::StringAppendF(&msg, ">");
-
     if (app.update_check) {
       base::StringAppendF(&msg, "<updatecheck");
       if (app.update_check->is_update_disabled)
@@ -186,6 +187,7 @@
         base::StringAppendF(&msg, "/>");
       }
     }
+
     base::StringAppendF(&msg, "</app>");
   }
 
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index 1e4c9979..4d4c7cd 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -39,6 +39,28 @@
   ]
 }
 
+if (enable_vulkan) {
+  viz_component("vulkan_context_provider") {
+    output_name = "viz_vulkan_context_provider"
+
+    defines = [ "VIZ_VULKAN_CONTEXT_PROVIDER_IMPLEMENTATION" ]
+
+    sources = [
+      "gpu/vulkan_context_provider.h",
+      "gpu/vulkan_in_process_context_provider.cc",
+      "gpu/vulkan_in_process_context_provider.h",
+      "viz_vulkan_context_provider_export.h",
+    ]
+    configs = [ "//third_party/vulkan:vulkan_config" ]
+    deps = [
+      "//base",
+      "//gpu/vulkan",
+      "//gpu/vulkan:buildflags",
+      "//skia",
+    ]
+  }
+}
+
 viz_component("common") {
   output_name = "viz_common"
 
@@ -184,16 +206,6 @@
     "//ui/latency",
   ]
 
-  if (enable_vulkan) {
-    sources += [
-      "gpu/vulkan_context_provider.h",
-      "gpu/vulkan_in_process_context_provider.cc",
-      "gpu/vulkan_in_process_context_provider.h",
-    ]
-    configs = [ "//third_party/vulkan:vulkan_config" ]
-    deps += [ "//gpu/vulkan" ]
-  }
-
   if (is_win) {
     sources += [
       "display/use_layered_window.cc",
@@ -210,6 +222,9 @@
     "//mojo/public/cpp/bindings",
     "//skia",
   ]
+  if (enable_vulkan) {
+    public_deps += [ ":vulkan_context_provider" ]
+  }
 }
 
 viz_source_set("unit_tests") {
diff --git a/components/viz/common/gpu/vulkan_context_provider.h b/components/viz/common/gpu/vulkan_context_provider.h
index a4c11f8aa..713635fb9a 100644
--- a/components/viz/common/gpu/vulkan_context_provider.h
+++ b/components/viz/common/gpu/vulkan_context_provider.h
@@ -6,7 +6,7 @@
 #define COMPONENTS_VIZ_COMMON_GPU_VULKAN_CONTEXT_PROVIDER_H_
 
 #include "base/memory/ref_counted.h"
-#include "components/viz/common/viz_common_export.h"
+#include "components/viz/common/viz_vulkan_context_provider_export.h"
 
 class GrContext;
 
@@ -18,7 +18,7 @@
 namespace viz {
 
 // The VulkanContextProvider groups sharing of vulkan objects synchronously.
-class VIZ_COMMON_EXPORT VulkanContextProvider
+class VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT VulkanContextProvider
     : public base::RefCountedThreadSafe<VulkanContextProvider> {
  public:
   virtual gpu::VulkanImplementation* GetVulkanImplementation() = 0;
diff --git a/components/viz/common/gpu/vulkan_in_process_context_provider.h b/components/viz/common/gpu/vulkan_in_process_context_provider.h
index 426950f..5a41204 100644
--- a/components/viz/common/gpu/vulkan_in_process_context_provider.h
+++ b/components/viz/common/gpu/vulkan_in_process_context_provider.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "components/viz/common/gpu/vulkan_context_provider.h"
-#include "components/viz/common/viz_common_export.h"
+#include "components/viz/common/viz_vulkan_context_provider_export.h"
 #include "gpu/vulkan/buildflags.h"
 #if BUILDFLAG(ENABLE_VULKAN)
 #include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
@@ -21,7 +21,7 @@
 
 namespace viz {
 
-class VIZ_COMMON_EXPORT VulkanInProcessContextProvider
+class VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT VulkanInProcessContextProvider
     : public VulkanContextProvider {
  public:
   static scoped_refptr<VulkanInProcessContextProvider> Create(
diff --git a/components/viz/common/viz_vulkan_context_provider_export.h b/components/viz/common/viz_vulkan_context_provider_export.h
new file mode 100644
index 0000000..51d940f
--- /dev/null
+++ b/components/viz/common/viz_vulkan_context_provider_export.h
@@ -0,0 +1,30 @@
+// Copyright 2018 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 COMPONENTS_VIZ_COMMON_VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT_H_
+#define COMPONENTS_VIZ_COMMON_VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(VIZ_VULKAN_CONTEXT_PROVIDER_IMPLEMENTATION)
+#define VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT __declspec(dllexport)
+#else
+#define VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT __declspec(dllimport)
+#endif  // defined(VIZ_VULKAN_CONTEXT_PROVIDER_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(VIZ_VULKAN_CONTEXT_PROVIDER_IMPLEMENTATION)
+#define VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT \
+  __attribute__((visibility("default")))
+#else
+#define VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT
+#endif
+
+#endif  // COMPONENTS_VIZ_COMMON_VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT_H_
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc
index 6fa3d5a..4da3159 100644
--- a/components/viz/service/gl/gpu_service_impl.cc
+++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -257,8 +257,6 @@
   skia_output_surface_sequence_id_ =
       scheduler_->CreateSequence(gpu::SchedulingPriority::kHigh);
 
-  GrContext* vulkan_gr_context =
-      is_using_vulkan() ? vulkan_context_provider()->GetGrContext() : nullptr;
   // Defer creation of the render thread. This is to prevent it from handling
   // IPC messages before the sandbox has been enabled and all other necessary
   // initialization has succeeded.
@@ -266,7 +264,7 @@
       gpu_preferences_, this, watchdog_thread_.get(), main_runner_, io_runner_,
       scheduler_.get(), sync_point_manager_, gpu_memory_buffer_factory_.get(),
       gpu_feature_info_, std::move(activity_flags),
-      std::move(default_offscreen_surface), vulkan_gr_context);
+      std::move(default_offscreen_surface), vulkan_context_provider());
 
   media_gpu_channel_manager_.reset(
       new media::MediaGpuChannelManager(gpu_channel_manager_.get()));
diff --git a/content/browser/android/synchronous_compositor_sync_call_bridge.cc b/content/browser/android/synchronous_compositor_sync_call_bridge.cc
index 8410eaa..7b94dbe5 100644
--- a/content/browser/android/synchronous_compositor_sync_call_bridge.cc
+++ b/content/browser/android/synchronous_compositor_sync_call_bridge.cc
@@ -93,8 +93,9 @@
     return true;
   }
   window_android_in_vsync_ = window_android;
-  window_android_in_vsync_->AddVSyncCompleteCallback(base::BindOnce(
-      &SynchronousCompositorSyncCallBridge::VSyncCompleteOnUIThread, this));
+  window_android_in_vsync_->AddBeginFrameCompletionCallback(base::BindOnce(
+      &SynchronousCompositorSyncCallBridge::BeginFrameCompleteOnUIThread,
+      this));
   return true;
 }
 
@@ -128,7 +129,7 @@
   return remote_state_ == RemoteState::READY;
 }
 
-void SynchronousCompositorSyncCallBridge::VSyncCompleteOnUIThread() {
+void SynchronousCompositorSyncCallBridge::BeginFrameCompleteOnUIThread() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(window_android_in_vsync_);
   window_android_in_vsync_ = nullptr;
diff --git a/content/browser/android/synchronous_compositor_sync_call_bridge.h b/content/browser/android/synchronous_compositor_sync_call_bridge.h
index 1b833f9..5cf9236 100644
--- a/content/browser/android/synchronous_compositor_sync_call_bridge.h
+++ b/content/browser/android/synchronous_compositor_sync_call_bridge.h
@@ -107,8 +107,9 @@
   friend class base::RefCountedThreadSafe<SynchronousCompositorSyncCallBridge>;
   ~SynchronousCompositorSyncCallBridge();
 
-  // Callback passed to WindowAndroid, runs when the current vsync is completed.
-  void VSyncCompleteOnUIThread();
+  // Callback passed to WindowAndroid, runs when the current begin frame is
+  // completed.
+  void BeginFrameCompleteOnUIThread();
 
   // Process metadata.
   void ProcessFrameMetadataOnUIThread(uint32_t metadata_version,
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index f0762bb..b24c8fe 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -14,11 +14,13 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
@@ -30,6 +32,7 @@
 #include "content/browser/appcache/appcache_quota_client.h"
 #include "content/browser/appcache/appcache_response.h"
 #include "content/browser/appcache/appcache_service_impl.h"
+#include "content/public/common/content_switches.h"
 #include "net/base/cache_type.h"
 #include "net/base/net_errors.h"
 #include "sql/database.h"
@@ -43,11 +46,13 @@
 
 namespace {
 
-// Hard coded default when not using quota management.
-constexpr const int kDefaultQuota = 5 * 1024 * 1024;
+constexpr const int kMB = 1024 * 1024;
 
-constexpr const int kMaxAppCacheDiskCacheSize = 250 * 1024 * 1024;
-constexpr const int kMaxAppCacheMemDiskCacheSize = 10 * 1024 * 1024;
+// Hard coded default when not using quota management.
+constexpr const int kDefaultQuota = 5 * kMB;
+
+constexpr const int kMaxAppCacheDiskCacheSize = 250 * kMB;
+constexpr const int kMaxAppCacheMemDiskCacheSize = 10 * kMB;
 
 constexpr base::FilePath::CharType kDiskCacheDirectoryName[] =
     FILE_PATH_LITERAL("Cache");
@@ -615,14 +620,24 @@
   bool would_exceed_quota_;
   int64_t space_available_;
   int64_t new_origin_usage_;
+  int64_t max_appcache_origin_cache_size_;
   std::vector<int64_t> newly_deletable_response_ids_;
 };
 
 AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask(
-    AppCacheStorageImpl* storage, AppCacheGroup* group, AppCache* newest_cache)
-    : StoreOrLoadTask(storage), group_(group), cache_(newest_cache),
-      success_(false), would_exceed_quota_(false),
-      space_available_(-1), new_origin_usage_(-1) {
+    AppCacheStorageImpl* storage,
+    AppCacheGroup* group,
+    AppCache* newest_cache)
+    : StoreOrLoadTask(storage),
+      group_(group),
+      cache_(newest_cache),
+      success_(false),
+      would_exceed_quota_(false),
+      space_available_(-1),
+      new_origin_usage_(-1),
+      // TODO(crbug.com/895825): Remove max_appcache_origin_cache_size_ in Feb
+      // 2019.
+      max_appcache_origin_cache_size_(kDefaultQuota) {
   group_record_.group_id = group->group_id();
   group_record_.manifest_url = group->manifest_url();
   group_record_.origin = url::Origin::Create(group_record_.manifest_url);
@@ -636,6 +651,15 @@
       &intercept_namespace_records_,
       &fallback_namespace_records_,
       &online_whitelist_records_);
+
+  base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
+  if (command_line.HasSwitch(switches::kMaxAppCacheOriginCacheSizeMb)) {
+    if (base::StringToInt64(command_line.GetSwitchValueASCII(
+                                switches::kMaxAppCacheOriginCacheSizeMb),
+                            &max_appcache_origin_cache_size_)) {
+      max_appcache_origin_cache_size_ *= kMB;
+    }
+  }
 }
 
 void AppCacheStorageImpl::StoreGroupAndCacheTask::GetQuotaThenSchedule() {
@@ -757,9 +781,10 @@
     return;
   }
 
-  // Use a simple hard-coded value when not using quota management.
+  // Use the value in --max-appcache-disk-cache-size-mb (or a hard-coded
+  // default) when no QuotaManager is wired in.
   if (space_available_ == -1) {
-    if (new_origin_usage_ > kDefaultQuota) {
+    if (new_origin_usage_ > max_appcache_origin_cache_size_) {
       would_exceed_quota_ = true;
       success_ = false;
       return;
@@ -1874,9 +1899,21 @@
                          base::Unretained(this)));
     } else {
       expecting_cleanup_complete_on_disable_ = true;
+
+      const base::CommandLine& command_line =
+          *base::CommandLine::ForCurrentProcess();
+      int64_t max_appcache_disk_cache_size = kMaxAppCacheDiskCacheSize;
+      if (command_line.HasSwitch(switches::kMaxAppCacheDiskCacheSizeMb)) {
+        if (base::StringToInt64(command_line.GetSwitchValueASCII(
+                                    switches::kMaxAppCacheDiskCacheSizeMb),
+                                &max_appcache_disk_cache_size)) {
+          max_appcache_disk_cache_size *= kMB;
+        }
+      }
+
       rv = disk_cache_->InitWithDiskBackend(
           cache_directory_.Append(kDiskCacheDirectoryName),
-          kMaxAppCacheDiskCacheSize, false,
+          max_appcache_disk_cache_size, false,
           base::BindOnce(&AppCacheStorageImpl::OnDiskCacheCleanupComplete,
                          weak_factory_.GetWeakPtr()),
           base::BindOnce(&AppCacheStorageImpl::OnDiskCacheInitialized,
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index 389fd19..337b557 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -615,7 +615,11 @@
       total_bytes_to_send -= write_size;
     }
 
-    if (!net::GetMimeTypeFromFile(path, &head.mime_type)) {
+    if (path.MatchesExtension(FILE_PATH_LITERAL(".svgz"))) {
+      head.mime_type = "image/svg+xml";
+      // Don't know what the uncompressed content length will be.
+      head.content_length = -1;
+    } else if (!net::GetMimeTypeFromFile(path, &head.mime_type)) {
       net::SniffMimeType(
           initial_read_buffer, initial_read_result, request.url, head.mime_type,
           GetContentClient()->browser()->ForceSniffingFileUrlsForHtml()
@@ -624,7 +628,7 @@
           &head.mime_type);
       head.did_mime_sniff = true;
     }
-    if (head.headers) {
+    if (head.headers && !head.mime_type.empty()) {
       head.headers->AddHeader(
           base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType,
                              head.mime_type.c_str()));
diff --git a/content/browser/frame_host/frame_tree_browsertest.cc b/content/browser/frame_host/frame_tree_browsertest.cc
index 7159859c..a05c6c7 100644
--- a/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/content/browser/frame_host/frame_tree_browsertest.cc
@@ -849,11 +849,15 @@
   IsolateIcelandFrameTreeBrowserTest() {}
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
-    // blink suppresses navigations to blob URLs of origins different from the
+    // Blink suppresses navigations to blob URLs of origins different from the
     // frame initiating the navigation. We disable those checks for this test,
     // to test what happens in a compromise scenario.
     command_line->AppendSwitch(switches::kDisableWebSecurity);
-    command_line->AppendSwitchASCII(switches::kIsolateSitesForTesting, "*.is");
+
+    // ProcessSwitchForIsolatedBlob test below requires that one of URLs used in
+    // the test (blob:http://b.is:2932/) belongs to an isolated origin.
+    command_line->AppendSwitchASCII(switches::kIsolateOrigins,
+                                    "http://b.is:2932/");
   }
 
   void SetUpOnMainThread() override {
@@ -879,7 +883,7 @@
 
   // The navigation targets an invalid blob url; that's intentional to trigger
   // an error response. The response should commit in a process dedicated to
-  // http://b.is.
+  // http://b.is:2932.
   EXPECT_EQ(
       "done",
       EvalJs(
@@ -896,7 +900,7 @@
       " Site A ------------ proxies for B\n"
       "   +--Site B ------- proxies for A\n"
       "Where A = http://a.com/\n"
-      "      B = http://b.is/",
+      "      B = http://b.is:2932/",
       FrameTreeVisualizer().DepictFrameTree(root));
 }
 
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 51f89f6..1bb2b8665e 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -4797,25 +4797,9 @@
   EXPECT_EQ(frame_entry->redirect_chain()[1], frame_final_url);
 }
 
-// Support a set of tests that isolate only a subset of sites with
-// out-of-process iframes (OOPIFs).
-class NavigationControllerOopifBrowserTest
-    : public NavigationControllerBrowserTest {
- public:
-  NavigationControllerOopifBrowserTest() {}
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    // Enable the OOPIF framework but only isolate sites from a single TLD.
-    command_line->AppendSwitchASCII(switches::kIsolateSitesForTesting, "*.is");
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NavigationControllerOopifBrowserTest);
-};
-
 // Verify that restoring a NavigationEntry with cross-site subframes does not
 // create out-of-process iframes unless the current SiteIsolationPolicy says to.
-IN_PROC_BROWSER_TEST_F(NavigationControllerOopifBrowserTest,
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
                        RestoreWithoutExtraOopifs) {
   // 1. Start on a page with a data URL iframe.
   GURL main_url_a(embedded_test_server()->GetURL(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 9022352..d9c28e8 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2139,6 +2139,7 @@
 
   if (web_ui())
     web_ui()->RenderFrameHostSwappingOut();
+  web_bluetooth_services_.clear();
 
   // TODO(nasko): If the frame is not live, the RFH should just be deleted by
   // simulating the receipt of swap out ack.
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.h b/content/browser/renderer_host/browser_compositor_view_mac.h
index 731c8c4..f7d024b7 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.h
+++ b/content/browser/renderer_host/browser_compositor_view_mac.h
@@ -105,11 +105,6 @@
   // initiate copies occur before the ui::Compositor be detached.
   void SetRenderWidgetHostIsHidden(bool hidden);
 
-  // This is used to ensure that the ui::Compositor be attached to this
-  // NSView while its contents may be visible on-screen, even if the RWHImpl is
-  // hidden (e.g, because it is occluded by another window).
-  void SetNSViewAttachedToWindow(bool attached);
-
   // Specify if the ui::Layer should be visible or not.
   void SetViewVisible(bool visible);
 
@@ -151,8 +146,6 @@
 
   void DidNavigate();
 
-  bool ShouldContinueToPauseForFrame() const;
-
   bool ForceNewSurfaceForTesting();
 
   ui::Compositor* GetCompositor() const;
@@ -197,7 +190,6 @@
   // |root_layer_| to be under |parent_ui_layer_|, if needed.
   ui::Layer* parent_ui_layer_ = nullptr;
   bool render_widget_host_is_hidden_ = true;
-  bool ns_view_attached_to_window_ = false;
 
   BrowserCompositorMacClient* client_ = nullptr;
   ui::AcceleratedWidgetMacNSView* accelerated_widget_mac_ns_view_ = nullptr;
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm
index 59128ca..97b8894 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.mm
+++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -63,7 +63,6 @@
       frame_sink_id, this, true /* should_register_frame_sink_id */));
 
   SetRenderWidgetHostIsHidden(render_widget_host_is_hidden);
-  SetNSViewAttachedToWindow(false);
 }
 
 BrowserCompositorMac::~BrowserCompositorMac() {
@@ -218,11 +217,6 @@
   UpdateState();
 }
 
-void BrowserCompositorMac::SetNSViewAttachedToWindow(bool attached) {
-  ns_view_attached_to_window_ = attached;
-  UpdateState();
-}
-
 void BrowserCompositorMac::SetViewVisible(bool visible) {
   root_layer_->SetVisible(visible);
 }
@@ -387,21 +381,6 @@
   is_first_navigation_ = false;
 }
 
-bool BrowserCompositorMac::ShouldContinueToPauseForFrame() const {
-  if (state_ == UseParentLayerCompositor)
-    return false;
-
-  // The renderer won't produce a frame if its frame sink hasn't been created
-  // yet.
-  if (!renderer_compositor_frame_sink_)
-    return false;
-
-  if (!recyclable_compositor_)
-    return false;
-
-  return !recyclable_compositor_->widget()->HasFrameOfSize(dfh_size_dip_);
-}
-
 void BrowserCompositorMac::SetParentUiLayer(ui::Layer* new_parent_ui_layer) {
   if (new_parent_ui_layer)
     DCHECK(new_parent_ui_layer->GetCompositor());
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index b306bac1..32ea5ffa0 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -25,7 +25,6 @@
 #include "ipc/ipc_sender.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
-#include "ui/accelerated_widget_mac/ca_transaction_observer.h"
 #include "ui/accelerated_widget_mac/display_link_mac.h"
 #include "ui/base/cocoa/remote_layer_api.h"
 #include "ui/events/gesture_detection/filtered_gesture_provider.h"
@@ -71,7 +70,6 @@
       public mojom::RenderWidgetHostNSViewClient,
       public BrowserCompositorMacClient,
       public TextInputManager::Observer,
-      public ui::CATransactionCoordinator::PreCommitObserver,
       public ui::GestureProviderClient,
       public ui::AcceleratedWidgetMacNSView,
       public IPC::Sender {
@@ -226,10 +224,6 @@
   void OnTextSelectionChanged(TextInputManager* text_input_manager,
                               RenderWidgetHostViewBase* updated_view) override;
 
-  // ui::CATransactionCoordinator::PreCommitObserver implementation
-  bool ShouldWaitInPreCommit() override;
-  base::TimeDelta PreCommitTimeout() override;
-
   // ui::GestureProviderClient implementation.
   void OnGestureEvent(const ui::GestureEventData& gesture) override;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 00dfa7f8..b1461077 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -62,10 +62,6 @@
 using blink::WebGestureEvent;
 using blink::WebTouchEvent;
 
-namespace {
-constexpr auto kContentPaintTimeout = base::TimeDelta::FromMilliseconds(167);
-}  // namespace
-
 namespace content {
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -628,14 +624,6 @@
                                     selection->range());
 }
 
-bool RenderWidgetHostViewMac::ShouldWaitInPreCommit() {
-  return browser_compositor_->ShouldContinueToPauseForFrame();
-}
-
-base::TimeDelta RenderWidgetHostViewMac::PreCommitTimeout() {
-  return kContentPaintTimeout;
-}
-
 void RenderWidgetHostViewMac::OnGestureEvent(
     const ui::GestureEventData& gesture) {
   blink::WebGestureEvent web_gesture =
@@ -1461,8 +1449,6 @@
   bool view_size_changed =
       view_bounds_in_window_dip_.size() != view_bounds_in_window_dip.size();
 
-  browser_compositor_->SetNSViewAttachedToWindow(attached_to_window);
-
   if (attached_to_window) {
     view_bounds_in_window_dip_ = view_bounds_in_window_dip;
   } else {
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc
index dd85cd1f..37f09df 100644
--- a/content/browser/webauth/webauth_browsertest.cc
+++ b/content/browser/webauth/webauth_browsertest.cc
@@ -229,10 +229,6 @@
   // Set when |IsFocused| is called.
   bool focus_checked = false;
 
-  // If true, request a new render process for each site (i.e. site isolation).
-  // Otherwise have the default behaviour for |ContentBrowserClient|.
-  bool force_new_render_processes = false;
-
   // This is incremented when an |AuthenticatorRequestClientDelegate| is
   // created.
   int delegate_create_count = 0;
@@ -277,24 +273,6 @@
     return std::make_unique<WebAuthBrowserTestClientDelegate>(test_state_);
   }
 
-  bool ShouldUseProcessPerSite(BrowserContext* browser_context,
-                               const GURL& effective_url) override {
-    if (test_state_->force_new_render_processes) {
-      return true;
-    }
-    return ContentBrowserClient::ShouldUseProcessPerSite(browser_context,
-                                                         effective_url);
-  }
-
-  bool DoesSiteRequireDedicatedProcess(BrowserContext* browser_context,
-                                       const GURL& effective_url) override {
-    if (test_state_->force_new_render_processes) {
-      return true;
-    }
-    return ContentBrowserClient::DoesSiteRequireDedicatedProcess(
-        browser_context, effective_url);
-  }
-
  private:
   WebAuthBrowserTestState* const test_state_;
 
@@ -964,45 +942,6 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest,
-                       RegisterDuringUnload) {
-  // Request new render processes for each site in order to test concurrent
-  // unloading with a different RenderFrame showing the new page.
-  test_state()->force_new_render_processes = true;
-
-  NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html"));
-  const std::string script = base::ReplaceStringPlaceholders(
-      R"(
-        window.addEventListener('unload', function(e) {
-          $1
-        });
-
-        // Trigger a webauthn operation so that the bindings are established
-        // before unload.
-        navigator.credentials.get({ publicKey: {
-          challenge: new TextEncoder().encode('climb a mountain'),
-          timeout: 1,
-        }}).catch(c => window.location = '$2');
-      )",
-      {BuildCreateCallWithParameters(CreateParameters()),
-       GetHttpsURL("www.acme2.com", "/title2.html").spec()},
-      nullptr);
-
-  RenderFrameHost* render_frame_host = shell()->web_contents()->GetMainFrame();
-  RenderFrameDeletedObserver observer(render_frame_host);
-  render_frame_host->ExecuteJavaScriptForTests(base::UTF8ToUTF16(script));
-  observer.WaitUntilDeleted();
-
-  // The |MakeCredential| call from the unload handler should not have reached
-  // the point where focus was checked.
-  EXPECT_FALSE(test_state()->focus_checked);
-
-  // Two delegates should have been created: one for the GetAssertion call that
-  // primes the binding and a second for the MakeCredential call in the unload
-  // handler.
-  ASSERT_EQ(2, test_state()->delegate_create_count);
-}
-
 // WebAuthBrowserCtapTest ----------------------------------------------
 
 class WebAuthBrowserCtapTest : public WebAuthLocalClientBrowserTest {
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 99314b5..ad5e640 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -468,6 +468,7 @@
     deps += [
       "//third_party/fuchsia-sdk/sdk:fdio",
       "//third_party/fuchsia-sdk/sdk:fonts",
+      "//third_party/fuchsia-sdk/sdk:mediacodec",
       "//third_party/fuchsia-sdk/sdk:scenic",
     ]
   }
diff --git a/content/common/sandbox_policy_fuchsia.cc b/content/common/sandbox_policy_fuchsia.cc
index 26e32780..90de422 100644
--- a/content/common/sandbox_policy_fuchsia.cc
+++ b/content/common/sandbox_policy_fuchsia.cc
@@ -9,6 +9,7 @@
 #include <zircon/processargs.h>
 
 #include <fuchsia/fonts/cpp/fidl.h>
+#include <fuchsia/mediacodec/cpp/fidl.h>
 #include <fuchsia/ui/scenic/cpp/fidl.h>
 #include <memory>
 #include <utility>
@@ -30,7 +31,7 @@
 namespace {
 
 constexpr const char* const kRendererServices[] = {
-    fuchsia::fonts::Provider::Name_};
+    fuchsia::fonts::Provider::Name_, fuchsia::mediacodec::CodecFactory::Name_};
 
 constexpr const char* const kGpuServices[] = {
     fuchsia::ui::scenic::Scenic::Name_};
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index f4b8f5aa..ab36d92e 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -450,7 +450,6 @@
     "//third_party/android_support_test_runner:runner_java",
     "//third_party/blink/public:android_mojo_bindings_java",
     "//third_party/blink/public:blink_headers_java",
-    "//third_party/hamcrest:hamcrest_java",
     "//third_party/jsr-305:jsr_305_javalib",
     "//third_party/junit",
     "//ui/android:ui_java",
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 5b1d8f5..3bd6767 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -579,6 +579,17 @@
 const char kMainFrameResizesAreOrientationChanges[] =
     "main-frame-resizes-are-orientation-changes";
 
+// Specifies the maximum disk cache size for the ApplicationCache. The default
+// value is 250MB.
+// TODO(crbug.com/895825): Remove this flag in Feb 2019.
+const char kMaxAppCacheDiskCacheSizeMb[] = "max-appcache-disk-cache-size-mb";
+
+// Specifies the maximum cache size per an origin for the ApplicationCache.
+// The default value is 5MB.
+// TODO(crbug.com/895825): Remove this flag in Feb 2019.
+const char kMaxAppCacheOriginCacheSizeMb[] =
+    "max-appcache-origin-cache-size-mb";
+
 // Sets the maximium decoded image size limitation.
 const char kMaxDecodedImageSizeMb[] = "max-decoded-image-size-mb";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 4bda11a..f5815a0 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -174,6 +174,8 @@
 CONTENT_EXPORT extern const char kLoggingLevel[];
 CONTENT_EXPORT extern const char kLogFile[];
 CONTENT_EXPORT extern const char kMainFrameResizesAreOrientationChanges[];
+extern const char kMaxAppCacheDiskCacheSizeMb[];
+extern const char kMaxAppCacheOriginCacheSizeMb[];
 extern const char kMaxDecodedImageSizeMb[];
 extern const char kMaxUntiledLayerHeight[];
 extern const char kMaxUntiledLayerWidth[];
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 005311f..fdb2672 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -485,6 +485,8 @@
     "p2p/ipc_network_manager.h",
     "p2p/ipc_socket_factory.cc",
     "p2p/ipc_socket_factory.h",
+    "p2p/mdns_responder_adapter.cc",
+    "p2p/mdns_responder_adapter.h",
     "p2p/network_list_manager.h",
     "p2p/network_list_observer.h",
     "p2p/network_manager_uma.cc",
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc
index f9d5578..42ab4bac 100644
--- a/content/renderer/loader/url_loader_client_impl.cc
+++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -13,6 +13,7 @@
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/renderer/loader/resource_dispatcher.h"
 #include "content/renderer/loader/url_response_body_consumer.h"
+#include "net/base/filename_util.h"
 #include "net/url_request/redirect_info.h"
 #include "services/network/public/cpp/features.h"
 
@@ -308,8 +309,14 @@
     return;
   }
 
+  // Special handling for *.svgz files loaded from the file scheme.
+  base::FilePath file_path;
+  bool inflate_response =
+      net::FileURLToFilePath(last_loaded_url_, &file_path) &&
+      file_path.MatchesExtension(FILE_PATH_LITERAL(".svgz"));
   body_consumer_ = new URLResponseBodyConsumer(
-      request_id_, resource_dispatcher_, std::move(body), task_runner_);
+      request_id_, resource_dispatcher_, std::move(body), inflate_response,
+      task_runner_);
 
   if (NeedsStoringMessage()) {
     body_consumer_->SetDefersLoading();
diff --git a/content/renderer/loader/url_response_body_consumer.cc b/content/renderer/loader/url_response_body_consumer.cc
index f5ac29b..ffb2b1c 100644
--- a/content/renderer/loader/url_response_body_consumer.cc
+++ b/content/renderer/loader/url_response_body_consumer.cc
@@ -9,30 +9,56 @@
 #include "base/macros.h"
 #include "content/public/renderer/request_peer.h"
 #include "content/renderer/loader/resource_dispatcher.h"
+#include "net/base/io_buffer.h"
+#include "net/filter/zlib_stream_wrapper.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
 
 namespace content {
 
 constexpr uint32_t URLResponseBodyConsumer::kMaxNumConsumedBytesInTask;
+const size_t kInflateBufferSize = 4 * 1024;
+
+class URLResponseBodyConsumer::ReclaimAccountant
+    : public base::RefCounted<URLResponseBodyConsumer::ReclaimAccountant> {
+ public:
+  explicit ReclaimAccountant(scoped_refptr<URLResponseBodyConsumer> consumer)
+      : consumer_(consumer) {}
+
+  void Reclaim(uint32_t reclaim_bytes) { reclaim_length_ += reclaim_bytes; }
+
+ private:
+  friend class base::RefCounted<URLResponseBodyConsumer::ReclaimAccountant>;
+
+  ~ReclaimAccountant() { consumer_->Reclaim(reclaim_length_); }
+
+  scoped_refptr<URLResponseBodyConsumer> consumer_;
+  uint32_t reclaim_length_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(ReclaimAccountant);
+};
 
 class URLResponseBodyConsumer::ReceivedData final
     : public RequestPeer::ReceivedData {
  public:
   ReceivedData(const char* payload,
-               int length,
-               scoped_refptr<URLResponseBodyConsumer> consumer)
-      : payload_(payload), length_(length), consumer_(consumer) {}
+               int payload_length,
+               int reclaim_length,
+               scoped_refptr<ReclaimAccountant> reclaim_accountant)
+      : payload_(payload),
+        payload_length_(payload_length),
+        reclaim_length_(reclaim_length),
+        reclaim_accountant_(reclaim_accountant) {}
 
-  ~ReceivedData() override { consumer_->Reclaim(length_); }
+  ~ReceivedData() override { reclaim_accountant_->Reclaim(reclaim_length_); }
 
   const char* payload() const override { return payload_; }
-  int length() const override { return length_; }
+  int length() const override { return payload_length_; }
 
  private:
   const char* const payload_;
-  const uint32_t length_;
-
-  scoped_refptr<URLResponseBodyConsumer> consumer_;
+  const uint32_t payload_length_;
+  const uint32_t reclaim_length_;
+  scoped_refptr<ReclaimAccountant> reclaim_accountant_;
 
   DISALLOW_COPY_AND_ASSIGN(ReceivedData);
 };
@@ -41,6 +67,7 @@
     int request_id,
     ResourceDispatcher* resource_dispatcher,
     mojo::ScopedDataPipeConsumerHandle handle,
+    bool inflate_response,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : request_id_(request_id),
       resource_dispatcher_(resource_dispatcher),
@@ -49,7 +76,19 @@
                       mojo::SimpleWatcher::ArmingPolicy::MANUAL,
                       task_runner),
       task_runner_(task_runner),
+      zlib_wrapper_(inflate_response
+                        ? new net::ZLibStreamWrapper(
+                              net::ZLibStreamWrapper::SourceType::kGzip)
+                        : nullptr),
+      inflate_buffer_(inflate_response ? new net::IOBuffer(kInflateBufferSize)
+                                       : nullptr),
       has_seen_end_of_data_(!handle_.is_valid()) {
+  if (zlib_wrapper_ && !zlib_wrapper_->Init()) {
+    // If zlib can't be initialized then release the wrapper which will result
+    // in the compressed response being received and unable to be processed.
+    zlib_wrapper_.release();
+    inflate_buffer_.reset();
+  }
   handle_watcher_.Watch(
       handle_.get(), MOJO_HANDLE_SIGNAL_READABLE,
       base::Bind(&URLResponseBodyConsumer::OnReadable, base::Unretained(this)));
@@ -146,8 +185,42 @@
         resource_dispatcher_->GetPendingRequestInfo(request_id_);
     DCHECK(request_info);
 
-    request_info->peer->OnReceivedData(std::make_unique<ReceivedData>(
-        static_cast<const char*>(buffer), available, this));
+    scoped_refptr<ReclaimAccountant> reclaim_accountant =
+        new ReclaimAccountant(this);
+    if (zlib_wrapper_) {
+      const char* input_buffer_ptr = static_cast<const char*>(buffer);
+      int input_buffer_available = available;
+      while (input_buffer_available) {
+        scoped_refptr<net::WrappedIOBuffer> input_buffer =
+            new net::WrappedIOBuffer(input_buffer_ptr);
+        int consumed_bytes = 0;
+        int output_bytes_written = zlib_wrapper_->FilterData(
+            inflate_buffer_.get(), kInflateBufferSize, input_buffer.get(),
+            input_buffer_available, &consumed_bytes, has_seen_end_of_data_);
+        if (output_bytes_written < 0) {
+          status_.error_code = output_bytes_written;
+          has_seen_end_of_data_ = true;
+          has_received_completion_ = true;
+          NotifyCompletionIfAppropriate();
+          return;
+        }
+
+        input_buffer_ptr += consumed_bytes;
+        input_buffer_available -= consumed_bytes;
+        DCHECK_GE(input_buffer_available, 0);
+
+        if (output_bytes_written > 0) {
+          request_info->peer->OnReceivedData(std::make_unique<ReceivedData>(
+              inflate_buffer_->data(), output_bytes_written, consumed_bytes,
+              reclaim_accountant));
+        }
+      }
+    } else {
+      request_info->peer->OnReceivedData(std::make_unique<ReceivedData>(
+          static_cast<const char*>(buffer), available, available,
+          reclaim_accountant));
+    }
+    reclaim_accountant.reset();
   }
 }
 
diff --git a/content/renderer/loader/url_response_body_consumer.h b/content/renderer/loader/url_response_body_consumer.h
index 3b6061b3..26883ca 100644
--- a/content/renderer/loader/url_response_body_consumer.h
+++ b/content/renderer/loader/url_response_body_consumer.h
@@ -9,7 +9,6 @@
 #include <stdint.h>
 
 #include <utility>
-#include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -20,6 +19,11 @@
 #include "mojo/public/cpp/system/simple_watcher.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 
+namespace net {
+class IOBuffer;
+class ZLibStreamWrapper;
+}  // namespace net
+
 namespace network {
 struct URLLoaderCompletionStatus;
 }  // namespace network
@@ -34,10 +38,13 @@
     : public base::RefCounted<URLResponseBodyConsumer>,
       public base::SupportsWeakPtr<URLResponseBodyConsumer> {
  public:
+  // If |inflate_response| is true then the response body will be inflated
+  // using zlib.
   URLResponseBodyConsumer(
       int request_id,
       ResourceDispatcher* resource_dispatcher,
       mojo::ScopedDataPipeConsumerHandle handle,
+      bool inflate_response,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   // Sets the completion status. The completion status is dispatched to the
@@ -71,6 +78,8 @@
   ~URLResponseBodyConsumer();
 
   class ReceivedData;
+  class ReclaimAccountant;
+
   void Reclaim(uint32_t size);
 
   void NotifyCompletionIfAppropriate();
@@ -81,6 +90,10 @@
   mojo::SimpleWatcher handle_watcher_;
   network::URLLoaderCompletionStatus status_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  // zlib_wrapper_ and inflate_buffer_ will only be non-null when inflating
+  // the response body.
+  std::unique_ptr<net::ZLibStreamWrapper> zlib_wrapper_;
+  scoped_refptr<net::IOBuffer> inflate_buffer_;
 
   bool has_received_completion_ = false;
   bool has_been_cancelled_ = false;
diff --git a/content/renderer/loader/url_response_body_consumer_unittest.cc b/content/renderer/loader/url_response_body_consumer_unittest.cc
index a2e1a0906..642414e 100644
--- a/content/renderer/loader/url_response_body_consumer_unittest.cc
+++ b/content/renderer/loader/url_response_body_consumer_unittest.cc
@@ -15,6 +15,7 @@
 #include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/loader/resource_dispatcher.h"
 #include "net/base/request_priority.h"
+#include "net/filter/filter_source_stream_test_util.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
@@ -183,6 +184,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
+      /*inflate_response=*/false,
       blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
@@ -200,6 +202,77 @@
   EXPECT_EQ("hello", context.data);
 }
 
+TEST_F(URLResponseBodyConsumerTest, ReceiveValidGzipData) {
+  TestRequestPeer::Context context;
+  std::unique_ptr<network::ResourceRequest> request(CreateResourceRequest());
+  int request_id = SetUpRequestPeer(std::move(request), &context);
+  mojo::DataPipe data_pipe(CreateDataPipeOptions());
+
+  scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
+      request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
+      /*inflate_response=*/true,
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
+  consumer->ArmOrNotify();
+
+  mojo::ScopedDataPipeProducerHandle writer =
+      std::move(data_pipe.producer_handle);
+  const std::string uncompressed_data = "hello";
+
+  size_t compressed_data_len = 2048;
+  auto compressed_data = std::make_unique<char[]>(compressed_data_len);
+  net::CompressGzip(uncompressed_data.data(), uncompressed_data.size(),
+                    compressed_data.get(), &compressed_data_len,
+                    /*gzip_framing=*/true);
+
+  uint32_t num_bytes = compressed_data_len;
+  MojoResult result =
+      writer->WriteData(compressed_data.get(), &num_bytes, kNone);
+  ASSERT_EQ(MOJO_RESULT_OK, result);
+  ASSERT_EQ(compressed_data_len, num_bytes);
+
+  Run(&context);
+
+  EXPECT_FALSE(context.complete);
+  EXPECT_EQ(uncompressed_data, context.data);
+}
+
+TEST_F(URLResponseBodyConsumerTest, ReceiveInvalidGzipData) {
+  TestRequestPeer::Context context;
+  std::unique_ptr<network::ResourceRequest> request(CreateResourceRequest());
+  int request_id = SetUpRequestPeer(std::move(request), &context);
+  mojo::DataPipe data_pipe(CreateDataPipeOptions());
+
+  scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
+      request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
+      /*inflate_response=*/true,
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
+  consumer->ArmOrNotify();
+
+  mojo::ScopedDataPipeProducerHandle writer =
+      std::move(data_pipe.producer_handle);
+  const std::string uncompressed_data = "hello";
+
+  size_t compressed_data_len = 2048;
+  auto compressed_data = std::make_unique<char[]>(compressed_data_len);
+  net::CompressGzip(uncompressed_data.data(), uncompressed_data.size(),
+                    compressed_data.get(), &compressed_data_len,
+                    /*gzip_framing=*/true);
+
+  // Corrupt the Gzip data stream.
+  compressed_data[1] = 'A';
+
+  uint32_t num_bytes = compressed_data_len;
+  MojoResult result =
+      writer->WriteData(compressed_data.get(), &num_bytes, kNone);
+  ASSERT_EQ(MOJO_RESULT_OK, result);
+  ASSERT_EQ(compressed_data_len, num_bytes);
+
+  Run(&context);
+
+  EXPECT_TRUE(context.complete);
+  EXPECT_EQ("", context.data);
+}
+
 TEST_F(URLResponseBodyConsumerTest, OnCompleteThenClose) {
   TestRequestPeer::Context context;
   std::unique_ptr<network::ResourceRequest> request(CreateResourceRequest());
@@ -208,6 +281,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
+      /*inflate_response=*/false,
       blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
@@ -243,6 +317,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
+      /*inflate_response=*/false,
       blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
@@ -275,6 +350,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
+      /*inflate_response=*/false,
       blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
@@ -318,6 +394,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
+      /*inflate_response=*/false,
       blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 87c3c87..0c67b3d 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -45,6 +45,7 @@
 #include "content/renderer/p2p/filtering_network_manager.h"
 #include "content/renderer/p2p/ipc_network_manager.h"
 #include "content/renderer/p2p/ipc_socket_factory.h"
+#include "content/renderer/p2p/mdns_responder_adapter.h"
 #include "content/renderer/p2p/port_allocator.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
@@ -207,11 +208,18 @@
   base::WaitableEvent create_network_manager_event(
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
+  std::unique_ptr<MdnsResponderAdapter> mdns_responder;
+#if BUILDFLAG(ENABLE_MDNS)
+  if (base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns)) {
+    mdns_responder = std::make_unique<MdnsResponderAdapter>();
+  }
+#endif  // BUILDFLAG(ENABLE_MDNS)
   chrome_worker_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&PeerConnectionDependencyFactory::
                          CreateIpcNetworkManagerOnWorkerThread,
-                     base::Unretained(this), &create_network_manager_event));
+                     base::Unretained(this), &create_network_manager_event,
+                     std::move(mdns_responder)));
 
   start_worker_event.Wait();
   create_network_manager_event.Wait();
@@ -471,11 +479,11 @@
   std::unique_ptr<rtc::NetworkManager> network_manager;
   if (port_config.enable_multiple_routes) {
     FilteringNetworkManager* filtering_network_manager =
-        new FilteringNetworkManager(network_manager_, requesting_origin,
+        new FilteringNetworkManager(network_manager_.get(), requesting_origin,
                                     media_permission);
     network_manager.reset(filtering_network_manager);
   } else {
-    network_manager.reset(new EmptyNetworkManager(network_manager_));
+    network_manager.reset(new EmptyNetworkManager(network_manager_.get()));
   }
   auto port_allocator = std::make_unique<P2PPortAllocator>(
       p2p_socket_dispatcher_, std::move(network_manager), socket_factory_.get(),
@@ -567,21 +575,22 @@
     const std::string& params) {
   DCHECK(network_manager_);
   DCHECK(chrome_worker_thread_.task_runner()->BelongsToCurrentThread());
-  stun_trial_.reset(
-      new StunProberTrial(network_manager_, params, socket_factory_.get()));
+  stun_trial_.reset(new StunProberTrial(network_manager_.get(), params,
+                                        socket_factory_.get()));
 }
 
 void PeerConnectionDependencyFactory::CreateIpcNetworkManagerOnWorkerThread(
-    base::WaitableEvent* event) {
+    base::WaitableEvent* event,
+    std::unique_ptr<MdnsResponderAdapter> mdns_responder) {
   DCHECK(chrome_worker_thread_.task_runner()->BelongsToCurrentThread());
-  network_manager_ = new IpcNetworkManager(p2p_socket_dispatcher_.get());
+  network_manager_ = std::make_unique<IpcNetworkManager>(
+      p2p_socket_dispatcher_.get(), std::move(mdns_responder));
   event->Signal();
 }
 
 void PeerConnectionDependencyFactory::DeleteIpcNetworkManager() {
   DCHECK(chrome_worker_thread_.task_runner()->BelongsToCurrentThread());
-  delete network_manager_;
-  network_manager_ = nullptr;
+  network_manager_.reset();
 }
 
 void PeerConnectionDependencyFactory::CleanupPeerConnectionFactory() {
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
index 39f6f9ed..720c39087 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.h
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
@@ -42,6 +42,7 @@
 
 class IpcNetworkManager;
 class IpcPacketSocketFactory;
+class MdnsResponderAdapter;
 class P2PPortAllocator;
 class WebRtcAudioDeviceImpl;
 
@@ -49,8 +50,7 @@
 class CONTENT_EXPORT PeerConnectionDependencyFactory
     : base::MessageLoopCurrent::DestructionObserver {
  public:
-  PeerConnectionDependencyFactory(
-      P2PSocketDispatcher* p2p_socket_dispatcher);
+  PeerConnectionDependencyFactory(P2PSocketDispatcher* p2p_socket_dispatcher);
   ~PeerConnectionDependencyFactory() override;
 
   // Create a RTCPeerConnectionHandler object that implements the
@@ -146,13 +146,15 @@
   void InitializeWorkerThread(rtc::Thread** thread,
                               base::WaitableEvent* event);
 
-  void CreateIpcNetworkManagerOnWorkerThread(base::WaitableEvent* event);
+  void CreateIpcNetworkManagerOnWorkerThread(
+      base::WaitableEvent* event,
+      std::unique_ptr<MdnsResponderAdapter> mdns_responder);
   void DeleteIpcNetworkManager();
   void CleanupPeerConnectionFactory();
 
-  // We own network_manager_, must be deleted on the worker thread.
-  // The network manager uses |p2p_socket_dispatcher_|.
-  IpcNetworkManager* network_manager_;
+  // network_manager_ must be deleted on the worker thread. The network manager
+  // uses |p2p_socket_dispatcher_|.
+  std::unique_ptr<IpcNetworkManager> network_manager_;
   std::unique_ptr<IpcPacketSocketFactory> socket_factory_;
 
   scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory_;
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
index a4687f9..feeba80 100644
--- a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
+++ b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
@@ -297,7 +297,7 @@
   media::VideoDecoderConfig config(
       ToVideoCodec(video_codec_type_),
       GuessVideoCodecProfile(video_codec_type_), kDefaultPixelFormat,
-      media::COLOR_SPACE_UNSPECIFIED, media::VIDEO_ROTATION_0, kDefaultSize,
+      media::VideoColorSpace(), media::VIDEO_ROTATION_0, kDefaultSize,
       gfx::Rect(kDefaultSize), kDefaultSize, media::EmptyExtraData(),
       media::Unencrypted());
 
diff --git a/content/renderer/p2p/filtering_network_manager.cc b/content/renderer/p2p/filtering_network_manager.cc
index f8b2ec4..66fb08a 100644
--- a/content/renderer/p2p/filtering_network_manager.cc
+++ b/content/renderer/p2p/filtering_network_manager.cc
@@ -91,6 +91,11 @@
   return network_manager_->GetDefaultLocalAddress(family, ipaddress);
 }
 
+webrtc::MdnsResponderInterface* FilteringNetworkManager::GetMdnsResponder()
+    const {
+  return network_manager_->GetMdnsResponder();
+}
+
 void FilteringNetworkManager::CheckPermission() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!started_permission_check_);
diff --git a/content/renderer/p2p/filtering_network_manager.h b/content/renderer/p2p/filtering_network_manager.h
index 16ef60d..7d3b292c 100644
--- a/content/renderer/p2p/filtering_network_manager.h
+++ b/content/renderer/p2p/filtering_network_manager.h
@@ -54,6 +54,8 @@
   bool GetDefaultLocalAddress(int family,
                               rtc::IPAddress* ipaddress) const override;
 
+  webrtc::MdnsResponderInterface* GetMdnsResponder() const override;
+
  private:
   // Check mic/camera permission.
   void CheckPermission();
diff --git a/content/renderer/p2p/ipc_network_manager.cc b/content/renderer/p2p/ipc_network_manager.cc
index 169c27a0..2f64d9a 100644
--- a/content/renderer/p2p/ipc_network_manager.cc
+++ b/content/renderer/p2p/ipc_network_manager.cc
@@ -43,10 +43,11 @@
 
 }  // namespace
 
-IpcNetworkManager::IpcNetworkManager(NetworkListManager* network_list_manager)
+IpcNetworkManager::IpcNetworkManager(
+    NetworkListManager* network_list_manager,
+    std::unique_ptr<MdnsResponderAdapter> mdns_responder)
     : network_list_manager_(network_list_manager),
-      start_count_(0),
-      network_list_received_(false),
+      mdns_responder_(std::move(mdns_responder)),
       weak_factory_(this) {
   network_list_manager_->AddNetworkListObserver(this);
 }
@@ -184,6 +185,10 @@
                            stats.ipv6_network_count);
 }
 
+webrtc::MdnsResponderInterface* IpcNetworkManager::GetMdnsResponder() const {
+  return mdns_responder_.get();
+}
+
 void IpcNetworkManager::SendNetworksChangedSignal() {
   SignalNetworksChanged();
 }
diff --git a/content/renderer/p2p/ipc_network_manager.h b/content/renderer/p2p/ipc_network_manager.h
index 1d511ff0..c0395753 100644
--- a/content/renderer/p2p/ipc_network_manager.h
+++ b/content/renderer/p2p/ipc_network_manager.h
@@ -5,18 +5,21 @@
 #ifndef CONTENT_RENDERER_P2P_IPC_NETWORK_MANAGER_H_
 #define CONTENT_RENDERER_P2P_IPC_NETWORK_MANAGER_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
+#include "content/renderer/p2p/mdns_responder_adapter.h"
 #include "content/renderer/p2p/network_list_manager.h"
 #include "content/renderer/p2p/network_list_observer.h"
+#include "third_party/webrtc/rtc_base/mdns_responder_interface.h"
 #include "third_party/webrtc/rtc_base/network.h"
 
 namespace net {
 class IPAddress;
-}
+}  // namespace net
 
 namespace content {
 
@@ -26,12 +29,15 @@
                           public NetworkListObserver {
  public:
   // Constructor doesn't take ownership of the |network_list_manager|.
-  CONTENT_EXPORT IpcNetworkManager(NetworkListManager* network_list_manager);
+  CONTENT_EXPORT IpcNetworkManager(
+      NetworkListManager* network_list_manager,
+      std::unique_ptr<MdnsResponderAdapter> mdns_responder);
   ~IpcNetworkManager() override;
 
   // rtc:::NetworkManager:
   void StartUpdating() override;
   void StopUpdating() override;
+  webrtc::MdnsResponderInterface* GetMdnsResponder() const override;
 
   // P2PSocketDispatcher::NetworkListObserver interface.
   void OnNetworkListChanged(
@@ -43,8 +49,9 @@
   void SendNetworksChangedSignal();
 
   NetworkListManager* network_list_manager_;
-  int start_count_;
-  bool network_list_received_;
+  std::unique_ptr<MdnsResponderAdapter> mdns_responder_;
+  int start_count_ = 0;
+  bool network_list_received_ = false;
 
   base::WeakPtrFactory<IpcNetworkManager> weak_factory_;
 };
diff --git a/content/renderer/p2p/ipc_network_manager_unittest.cc b/content/renderer/p2p/ipc_network_manager_unittest.cc
index 06bb29c..26b96cf 100644
--- a/content/renderer/p2p/ipc_network_manager_unittest.cc
+++ b/content/renderer/p2p/ipc_network_manager_unittest.cc
@@ -41,7 +41,8 @@
  public:
   IpcNetworkManagerTest()
       : network_list_manager_(new MockP2PSocketDispatcher()),
-        network_manager_(new IpcNetworkManager(network_list_manager_.get())) {}
+        network_manager_(
+            new IpcNetworkManager(network_list_manager_.get(), nullptr)) {}
 
  protected:
   std::unique_ptr<MockP2PSocketDispatcher> network_list_manager_;
diff --git a/content/renderer/p2p/mdns_responder_adapter.cc b/content/renderer/p2p/mdns_responder_adapter.cc
new file mode 100644
index 0000000..849a946
--- /dev/null
+++ b/content/renderer/p2p/mdns_responder_adapter.cc
@@ -0,0 +1,62 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/p2p/mdns_responder_adapter.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "content/child/child_thread_impl.h"
+#include "content/public/common/service_names.mojom.h"
+#include "jingle/glue/utils.h"
+#include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "third_party/webrtc/rtc_base/ipaddress.h"
+
+namespace content {
+
+namespace {
+
+void OnNameCreatedForAddress(
+    webrtc::MdnsResponderInterface::NameCreatedCallback callback,
+    const rtc::IPAddress& addr,
+    const std::string& name,
+    bool announcement_scheduled) {
+  // We currently ignore whether there is an announcement sent for the name.
+  callback(addr, name);
+}
+
+void OnNameRemovedForAddress(
+    webrtc::MdnsResponderInterface::NameRemovedCallback callback,
+    bool removed,
+    bool goodbye_scheduled) {
+  // We currently ignore whether there is a goodbye sent for the name.
+  callback(removed);
+}
+
+}  // namespace
+
+MdnsResponderAdapter::MdnsResponderAdapter() {
+  ChildThreadImpl::current()->GetConnector()->BindInterface(
+      mojom::kBrowserServiceName, mojo::MakeRequest(&client_));
+}
+
+MdnsResponderAdapter::~MdnsResponderAdapter() = default;
+
+void MdnsResponderAdapter::CreateNameForAddress(const rtc::IPAddress& addr,
+                                                NameCreatedCallback callback) {
+  client_->CreateNameForAddress(
+      jingle_glue::RtcIPAddressToNetIPAddress(addr),
+      base::BindOnce(&OnNameCreatedForAddress, callback, addr));
+}
+
+void MdnsResponderAdapter::RemoveNameForAddress(const rtc::IPAddress& addr,
+                                                NameRemovedCallback callback) {
+  client_->RemoveNameForAddress(
+      jingle_glue::RtcIPAddressToNetIPAddress(addr),
+      base::BindOnce(&OnNameRemovedForAddress, callback));
+}
+
+}  // namespace content
diff --git a/content/renderer/p2p/mdns_responder_adapter.h b/content/renderer/p2p/mdns_responder_adapter.h
new file mode 100644
index 0000000..dfada7f
--- /dev/null
+++ b/content/renderer/p2p/mdns_responder_adapter.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_P2P_MDNS_RESPONDER_ADAPTER_H_
+#define CONTENT_RENDERER_P2P_MDNS_RESPONDER_ADAPTER_H_
+
+#include "services/network/public/mojom/mdns_responder.mojom.h"
+#include "third_party/webrtc/rtc_base/mdns_responder_interface.h"
+
+namespace rtc {
+class IPAddress;
+}  // namespace rtc
+
+namespace content {
+
+// This class is created on the main thread but is used only on the WebRTC
+// worker threads. The MdnsResponderAdapter implements the WebRTC mDNS responder
+// interface via the MdnsResponder service in Chromium, and is used to register
+// and resolve mDNS hostnames to conceal local IP addresses.
+class MdnsResponderAdapter : public webrtc::MdnsResponderInterface {
+ public:
+  // The adapter should be created on the main thread to have access to the
+  // connector to the service manager.
+  MdnsResponderAdapter();
+  ~MdnsResponderAdapter() override;
+
+  // webrtc::MdnsResponderInterface implementation.
+  void CreateNameForAddress(const rtc::IPAddress& addr,
+                            NameCreatedCallback callback) override;
+  void RemoveNameForAddress(const rtc::IPAddress& addr,
+                            NameRemovedCallback callback) override;
+
+ private:
+  network::mojom::MdnsResponderPtr client_;
+
+  DISALLOW_COPY_AND_ASSIGN(MdnsResponderAdapter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_P2P_MDNS_RESPONDER_ADAPTER_H_
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index b7ea303d..44d2e6a4d 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -892,7 +892,7 @@
 
   media::VideoDecoderConfig video_decoder_config(
       codec, vda_config.profile, media::PIXEL_FORMAT_I420,
-      media::COLOR_SPACE_UNSPECIFIED, media::VIDEO_ROTATION_0,
+      media::VideoColorSpace(), media::VIDEO_ROTATION_0,
       gfx::Size(32, 24),  // Small sizes that won't fail.
       gfx::Rect(32, 24), gfx::Size(32, 24),
       // TODO(bbudge): Verify extra data isn't needed.
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 9cd0d75..5935f8a 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -2258,7 +2258,12 @@
   DCHECK(main_thread_runner()->BelongsToCurrentThread());
   if (!media_thread_) {
     media_thread_.reset(new base::Thread("Media"));
-    media_thread_->Start();
+    base::Thread::Options options;
+#if defined(OS_FUCHSIA)
+    // Start IO thread on Fuchsia to make that thread usable for FIDL.
+    options = base::Thread::Options(base::MessageLoop::TYPE_IO, 0);
+#endif
+    media_thread_->StartWithOptions(options);
   }
   return media_thread_->task_runner();
 }
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index ec96ae7..a828f8e0 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -15,7 +15,6 @@
 #include "base/json/json_reader.h"
 #include "base/macros.h"
 #include "base/path_service.h"
-#include "base/strings/pattern.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "content/public/browser/client_certificate_delegate.h"
@@ -161,30 +160,6 @@
   return shell_browser_main_parts_;
 }
 
-bool ShellContentBrowserClient::DoesSiteRequireDedicatedProcess(
-    BrowserContext* browser_context,
-    const GURL& effective_site_url) {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (!command_line->HasSwitch(switches::kIsolateSitesForTesting))
-    return false;
-  std::string pattern =
-      command_line->GetSwitchValueASCII(switches::kIsolateSitesForTesting);
-
-  url::Origin origin = url::Origin::Create(effective_site_url);
-
-  if (!origin.opaque()) {
-    // Schemes like blob or filesystem, which have an embedded origin, should
-    // already have been canonicalized to the origin site.
-    CHECK_EQ(origin.scheme(), effective_site_url.scheme())
-        << "a site url should have the same scheme as its origin.";
-  }
-
-  // Practically |origin.Serialize()| is the same as
-  // |effective_site_url.spec()|, except Origin serialization strips the
-  // trailing "/", which makes for cleaner wildcard patterns.
-  return base::MatchPattern(origin.Serialize(), pattern);
-}
-
 bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
   if (!url.is_valid())
     return false;
@@ -306,13 +281,6 @@
             switches::kCrashDumpsDir));
   }
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kIsolateSitesForTesting)) {
-    command_line->AppendSwitchASCII(
-        switches::kIsolateSitesForTesting,
-        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-            switches::kIsolateSitesForTesting));
-  }
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kRegisterFontFiles)) {
     command_line->AppendSwitchASCII(
         switches::kRegisterFontFiles,
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
index 9a8f29c..4df003a 100644
--- a/content/shell/browser/shell_content_browser_client.h
+++ b/content/shell/browser/shell_content_browser_client.h
@@ -33,8 +33,6 @@
   // ContentBrowserClient overrides.
   BrowserMainParts* CreateBrowserMainParts(
       const MainFunctionParams& parameters) override;
-  bool DoesSiteRequireDedicatedProcess(BrowserContext* browser_context,
-                                       const GURL& effective_site_url) override;
   bool IsHandledURL(const GURL& url) override;
   void BindInterfaceRequestFromFrame(
       content::RenderFrameHost* render_frame_host,
diff --git a/content/shell/common/shell_switches.cc b/content/shell/common/shell_switches.cc
index 569ee5b..3949629 100644
--- a/content/shell/common/shell_switches.cc
+++ b/content/shell/common/shell_switches.cc
@@ -20,14 +20,6 @@
 // and debugging of layout tests that rely on it.
 const char kExposeInternalsForTesting[] = "expose-internals-for-testing";
 
-// Enable site isolation (--site-per-process style isolation) for a subset of
-// sites. The argument is a wildcard pattern which will be matched against the
-// site URL to determine which sites to isolate. This can be used to isolate
-// just one top-level domain, or just one scheme. Example usages:
-//     --isolate-sites-for-testing=*.com
-//     --isolate-sites-for-testing=https://*
-const char kIsolateSitesForTesting[] = "isolate-sites-for-testing";
-
 // Registers additional font files on Windows (for fonts outside the usual
 // %WINDIR%\Fonts location). Multiple files can be used by separating them
 // with a semicolon (;).
diff --git a/content/shell/common/shell_switches.h b/content/shell/common/shell_switches.h
index b8bc4d7c..e73a9542 100644
--- a/content/shell/common/shell_switches.h
+++ b/content/shell/common/shell_switches.h
@@ -15,7 +15,6 @@
 extern const char kContentShellDataPath[];
 extern const char kCrashDumpsDir[];
 extern const char kExposeInternalsForTesting[];
-extern const char kIsolateSitesForTesting[];
 extern const char kRegisterFontFiles[];
 extern const char kContentShellHostWindowSize[];
 extern const char kContentShellHideToolbar[];
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc
index 46023e9..92c895e 100644
--- a/extensions/common/extension_features.cc
+++ b/extensions/common/extension_features.cc
@@ -17,6 +17,6 @@
 // Forces extensions with <all_hosts> to use activeTab-style runtime host
 // permissions.
 const base::Feature kRuntimeHostPermissions{"RuntimeHostPermissions",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
+                                            base::FEATURE_ENABLED_BY_DEFAULT};
 
 }  // namespace extensions_features
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 67136e00..be5b33b5 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -5,6 +5,7 @@
 import("//build/config/jumbo.gni")
 import("//build/config/ui.gni")
 import("//third_party/protobuf/proto_library.gni")
+import("//gpu/vulkan/features.gni")
 
 group("service") {
   if (is_component_build) {
@@ -293,6 +294,7 @@
     "//gpu/command_buffer/common:gles2_utils",
     "//gpu/config",
     "//gpu/ipc/common:surface_handle_type",
+    "//gpu/vulkan:buildflags",
     "//third_party/angle:angle_image_util",
     "//third_party/angle:commit_id",
     "//third_party/angle:translator",
@@ -307,6 +309,10 @@
     "//ui/gl/init",
   ]
 
+  if (enable_vulkan) {
+    deps += [ "//components/viz/common:vulkan_context_provider" ]
+  }
+
   if (is_mac) {
     # Required by gles2_cmd_decoder.cc on Mac.
     libs = [
diff --git a/gpu/command_buffer/service/DEPS b/gpu/command_buffer/service/DEPS
index 7c6a3bce..1373db1 100644
--- a/gpu/command_buffer/service/DEPS
+++ b/gpu/command_buffer/service/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+cc/paint",
   "+third_party/skia",
+  "+components/viz/common/gpu/vulkan_context_provider.h",
   "+components/viz/common/resources/resource_format.h",
   "+components/viz/common/resources/resource_format_utils.h",
   "+components/viz/common/resources/resource_sizes.h",
diff --git a/gpu/command_buffer/service/raster_decoder_context_state.cc b/gpu/command_buffer/service/raster_decoder_context_state.cc
index 3fad5d903..9e605ae3 100644
--- a/gpu/command_buffer/service/raster_decoder_context_state.cc
+++ b/gpu/command_buffer/service/raster_decoder_context_state.cc
@@ -9,12 +9,17 @@
 #include "gpu/command_buffer/common/activity_flags.h"
 #include "gpu/command_buffer/service/service_transfer_cache.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
+#include "gpu/vulkan/buildflags.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_share_group.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/init/create_gr_gl_interface.h"
 
+#if BUILDFLAG(ENABLE_VULKAN)
+#include "components/viz/common/gpu/vulkan_context_provider.h"
+#endif
+
 namespace gpu {
 namespace raster {
 
@@ -22,13 +27,10 @@
     scoped_refptr<gl::GLShareGroup> share_group,
     scoped_refptr<gl::GLSurface> surface,
     scoped_refptr<gl::GLContext> context,
-    bool use_virtualized_gl_contexts,
-    GrContext* vulkan_gr_context)
+    bool use_virtualized_gl_contexts)
     : share_group(std::move(share_group)),
       surface(std::move(surface)),
       context(std::move(context)),
-      gr_context(vulkan_gr_context),
-      use_vulkan_gr_context(!!gr_context),
       use_virtualized_gl_contexts(use_virtualized_gl_contexts) {
   if (base::ThreadTaskRunnerHandle::IsSet()) {
     base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
@@ -36,6 +38,27 @@
   }
 }
 
+RasterDecoderContextState::RasterDecoderContextState(
+    viz::VulkanContextProvider* vulkan_context_provider)
+#if BUILDFLAG(ENABLE_VULKAN)
+    : vk_context_provider(vulkan_context_provider),
+      gr_context(vk_context_provider->GetGrContext()),
+      use_vulkan_gr_context(true)
+#endif
+{
+// This constructor should not be called if Vulkan is not enabled.
+#if !BUILDFLAG(ENABLE_VULKAN)
+  DCHECK(false);
+#endif
+
+  // gr_context should not be null.
+  DCHECK(gr_context);
+  if (base::ThreadTaskRunnerHandle::IsSet()) {
+    base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+        this, "RasterDecoderContextState", base::ThreadTaskRunnerHandle::Get());
+  }
+}
+
 RasterDecoderContextState::~RasterDecoderContextState() {
   if (gr_context)
     gr_context->abandonContext();
diff --git a/gpu/command_buffer/service/raster_decoder_context_state.h b/gpu/command_buffer/service/raster_decoder_context_state.h
index 1d8d006..26d3f4f 100644
--- a/gpu/command_buffer/service/raster_decoder_context_state.h
+++ b/gpu/command_buffer/service/raster_decoder_context_state.h
@@ -19,6 +19,10 @@
 class GLSurface;
 }  // namespace gl
 
+namespace viz {
+class VulkanContextProvider;
+}  // namespace viz
+
 namespace gpu {
 class GpuDriverBugWorkarounds;
 class GpuProcessActivityFlags;
@@ -30,11 +34,16 @@
     : public base::RefCounted<RasterDecoderContextState>,
       public base::trace_event::MemoryDumpProvider {
  public:
+  // Used for GL.
   RasterDecoderContextState(scoped_refptr<gl::GLShareGroup> share_group,
                             scoped_refptr<gl::GLSurface> surface,
                             scoped_refptr<gl::GLContext> context,
-                            bool use_virtualized_gl_contexts,
-                            GrContext* vulkan_gr_context = nullptr);
+                            bool use_virtualized_gl_contexts);
+
+  // Used for Vulkan.
+  RasterDecoderContextState(
+      viz::VulkanContextProvider* vulkan_context_provider);
+
   void InitializeGrContext(const GpuDriverBugWorkarounds& workarounds,
                            GrContextOptions::PersistentCache* cache,
                            GpuProcessActivityFlags* activity_flags = nullptr,
@@ -42,10 +51,14 @@
   void PurgeMemory(
       base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
 
+  // These should be null for Vulkan mode.
   scoped_refptr<gl::GLShareGroup> share_group;
   scoped_refptr<gl::GLSurface> surface;
   scoped_refptr<gl::GLContext> context;
-  GrContext* gr_context;
+
+  // Should be null for GL mode.
+  viz::VulkanContextProvider* vk_context_provider = nullptr;
+  GrContext* gr_context = nullptr;
   sk_sp<GrContext> owned_gr_context;
   std::unique_ptr<ServiceTransferCache> transfer_cache;
   const bool use_vulkan_gr_context = false;
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index 39d421b..901c611 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -63,7 +63,7 @@
     const GpuFeatureInfo& gpu_feature_info,
     GpuProcessActivityFlags activity_flags,
     scoped_refptr<gl::GLSurface> default_offscreen_surface,
-    GrContext* vulkan_gr_context)
+    viz::VulkanContextProvider* vulkan_context_provider)
     : task_runner_(task_runner),
       io_task_runner_(io_task_runner),
       gpu_preferences_(gpu_preferences),
@@ -84,7 +84,7 @@
       memory_pressure_listener_(
           base::Bind(&GpuChannelManager::HandleMemoryPressure,
                      base::Unretained(this))),
-      vulkan_gr_context_(vulkan_gr_context),
+      vulkan_context_provider_(vulkan_context_provider),
       weak_factory_(this) {
   DCHECK(task_runner->BelongsToCurrentThread());
   DCHECK(io_task_runner);
@@ -432,9 +432,15 @@
   }
 
   // TODO(penghuang): https://crbug.com/899735 Handle device lost for Vulkan.
-  raster_decoder_context_state_ = new raster::RasterDecoderContextState(
-      std::move(share_group), std::move(surface), std::move(context),
-      use_virtualized_gl_contexts, vulkan_gr_context_);
+  if (vulkan_context_provider_) {
+    raster_decoder_context_state_ =
+        new raster::RasterDecoderContextState(vulkan_context_provider_);
+  } else {
+    raster_decoder_context_state_ = new raster::RasterDecoderContextState(
+        std::move(share_group), std::move(surface), std::move(context),
+        use_virtualized_gl_contexts);
+  }
+
   const bool enable_raster_transport =
       gpu_feature_info_.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] ==
       gpu::kGpuFeatureStatusEnabled;
diff --git a/gpu/ipc/service/gpu_channel_manager.h b/gpu/ipc/service/gpu_channel_manager.h
index e0b60d571..301cc1b 100644
--- a/gpu/ipc/service/gpu_channel_manager.h
+++ b/gpu/ipc/service/gpu_channel_manager.h
@@ -37,8 +37,6 @@
 #include "ui/gl/gl_surface.h"
 #include "url/gurl.h"
 
-class GrContext;
-
 namespace gl {
 class GLShareGroup;
 }
@@ -68,18 +66,19 @@
 class GPU_IPC_SERVICE_EXPORT GpuChannelManager
     : public raster::GrShaderCache::Client {
  public:
-  GpuChannelManager(const GpuPreferences& gpu_preferences,
-                    GpuChannelManagerDelegate* delegate,
-                    GpuWatchdogThread* watchdog,
-                    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-                    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
-                    Scheduler* scheduler,
-                    SyncPointManager* sync_point_manager,
-                    GpuMemoryBufferFactory* gpu_memory_buffer_factory,
-                    const GpuFeatureInfo& gpu_feature_info,
-                    GpuProcessActivityFlags activity_flags,
-                    scoped_refptr<gl::GLSurface> default_offscreen_surface,
-                    GrContext* vulkan_gr_context = nullptr);
+  GpuChannelManager(
+      const GpuPreferences& gpu_preferences,
+      GpuChannelManagerDelegate* delegate,
+      GpuWatchdogThread* watchdog,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+      Scheduler* scheduler,
+      SyncPointManager* sync_point_manager,
+      GpuMemoryBufferFactory* gpu_memory_buffer_factory,
+      const GpuFeatureInfo& gpu_feature_info,
+      GpuProcessActivityFlags activity_flags,
+      scoped_refptr<gl::GLSurface> default_offscreen_surface,
+      viz::VulkanContextProvider* vulkan_context_provider = nullptr);
   ~GpuChannelManager() override;
 
   GpuChannelManagerDelegate* delegate() const { return delegate_; }
@@ -241,9 +240,9 @@
   scoped_refptr<raster::RasterDecoderContextState>
       raster_decoder_context_state_;
 
-  // With --enable-vulkan, the vulkan_gr_context_ will be set from
+  // With --enable-vulkan, the vulkan_context_provider_ will be set from
   // viz::GpuServiceImpl. The raster decoders will use it for rasterization.
-  GrContext* vulkan_gr_context_;
+  viz::VulkanContextProvider* vulkan_context_provider_;
 
   // Member variables should appear before the WeakPtrFactory, to ensure
   // that any WeakPtrs to Controller are invalidated before its members
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
index 483aedf3..5c272a3 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
@@ -66,9 +66,8 @@
     gfx::BufferFormat format,
     int client_id,
     SurfaceHandle surface_handle) {
-  // We should only end up in this code path if the memory buffer has a valid
-  // AHardwareBuffer.
-  DCHECK_EQ(handle.type, gfx::ANDROID_HARDWARE_BUFFER);
+  if (handle.type != gfx::ANDROID_HARDWARE_BUFFER)
+    return nullptr;
 
   base::android::ScopedHardwareBufferHandle& buffer =
       handle.android_hardware_buffer;
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
index c3ae7805..c060224 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
@@ -111,9 +111,11 @@
     gfx::BufferFormat format,
     int client_id,
     SurfaceHandle surface_handle) {
+  if (handle.type != gfx::IO_SURFACE_BUFFER)
+    return nullptr;
+
   base::AutoLock lock(io_surfaces_lock_);
 
-  DCHECK_EQ(handle.type, gfx::IO_SURFACE_BUFFER);
   IOSurfaceMapKey key(handle.id, client_id);
   IOSurfaceMap::iterator it = io_surfaces_.find(key);
   if (it == io_surfaces_.end()) {
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
index 8d9f8923..837c62a 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
@@ -85,7 +85,8 @@
     gfx::BufferFormat format,
     int client_id,
     SurfaceHandle surface_handle) {
-  DCHECK_EQ(handle.type, gfx::NATIVE_PIXMAP);
+  if (handle.type != gfx::NATIVE_PIXMAP)
+    return nullptr;
 
   scoped_refptr<gfx::NativePixmap> pixmap;
 
diff --git a/ios/chrome/browser/ssl/insecure_input_tab_helper.h b/ios/chrome/browser/ssl/insecure_input_tab_helper.h
index ef629e8..3ba551b 100644
--- a/ios/chrome/browser/ssl/insecure_input_tab_helper.h
+++ b/ios/chrome/browser/ssl/insecure_input_tab_helper.h
@@ -48,6 +48,8 @@
       const autofill::FormActivityParams& params) override;
 
   // WebStateObserver implementation.
+  void DidFinishNavigation(web::WebState* web_state,
+                           web::NavigationContext* navigation_context) override;
   void WebStateDestroyed(web::WebState* web_state) override;
 
   // The WebState this instance is observing. Will be null after
diff --git a/ios/chrome/browser/ssl/insecure_input_tab_helper.mm b/ios/chrome/browser/ssl/insecure_input_tab_helper.mm
index 8c31757..10567997 100644
--- a/ios/chrome/browser/ssl/insecure_input_tab_helper.mm
+++ b/ios/chrome/browser/ssl/insecure_input_tab_helper.mm
@@ -15,8 +15,10 @@
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #import "ios/web/public/origin_util.h"
+#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
+#include "ui/base/page_transition_types.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -131,6 +133,24 @@
   }
 }
 
+void InsecureInputTabHelper::DidFinishNavigation(
+    web::WebState* web_state,
+    web::NavigationContext* navigation_context) {
+  DCHECK_EQ(web_state_, web_state);
+  // Check if the navigation should clear insecure input event data (i.e., not a
+  // same-document navigation).
+  if (!web::IsOriginSecure(web_state->GetLastCommittedURL()) &&
+      navigation_context->HasCommitted() &&
+      !navigation_context->IsSameDocument()) {
+    security_state::SSLStatusInputEventData* input_events =
+        GetOrCreateSSLStatusInputEventData(web_state_);
+    if (!input_events)
+      return;
+    input_events->input_events()->insecure_field_edited = false;
+    web_state_->DidChangeVisibleSecurityState();
+  }
+}
+
 void InsecureInputTabHelper::WebStateDestroyed(web::WebState* web_state) {
   DCHECK_EQ(web_state_, web_state);
   autofill::FormActivityTabHelper::GetOrCreateForWebState(web_state)
diff --git a/ios/chrome/browser/ssl/ios_security_state_tab_helper_unittest.mm b/ios/chrome/browser/ssl/ios_security_state_tab_helper_unittest.mm
index a37bc3f0..2e3f68c 100644
--- a/ios/chrome/browser/ssl/ios_security_state_tab_helper_unittest.mm
+++ b/ios/chrome/browser/ssl/ios_security_state_tab_helper_unittest.mm
@@ -138,3 +138,18 @@
   events = GetInsecureInputEventData();
   EXPECT_TRUE(events.credit_card_field_edited);
 }
+
+// Ensures that re-navigating to the same page does not keep
+// |insecure_field_set| set.
+TEST_F(IOSSecurityStateTabHelperTest, InsecureInputClearedOnRenavigation) {
+  // Simulate an edit and verify |insecure_field_edited| is noted in the
+  // insecure_input_events.
+  insecure_input()->DidEditFieldInInsecureContext();
+  security_state::InsecureInputEventData events = GetInsecureInputEventData();
+  EXPECT_TRUE(events.insecure_field_edited);
+
+  // Navigate to the same page again.
+  LoadHtml(@"<html><body></body></html>", GURL("http://chromium.test"));
+  events = GetInsecureInputEventData();
+  EXPECT_FALSE(events.insecure_field_edited);
+}
diff --git a/ios/chrome/test/app/chrome_test_util.mm b/ios/chrome/test/app/chrome_test_util.mm
index 71cb6f1..e6fda5e 100644
--- a/ios/chrome/test/app/chrome_test_util.mm
+++ b/ios/chrome/test/app/chrome_test_util.mm
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
+#import "base/test/ios/wait_util.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_service.h"
 #import "ios/chrome/app/application_delegate/metrics_mediator.h"
@@ -27,10 +28,11 @@
 #import "ios/chrome/browser/ui/main/view_controller_swapping.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_controller.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
-#include "ios/chrome/test/app/navigation_test_util.h"
 #import "ios/chrome/test/app/tab_test_util.h"
 #import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/test/fakes/test_web_state_observer.h"
 #import "ios/web/public/test/native_controller_test_util.h"
+#import "ios/web/public/web_state/navigation_context.h"
 #import "third_party/breakpad/breakpad/src/client/ios/BreakpadController.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -239,10 +241,26 @@
 
 bool PurgeCachedWebViewPages() {
   web::WebState* web_state = chrome_test_util::GetCurrentWebState();
+  const GURL last_committed_url = web_state->GetLastCommittedURL();
+
   web_state->SetWebUsageEnabled(false);
   web_state->SetWebUsageEnabled(true);
+
+  auto observer = std::make_unique<web::TestWebStateObserver>(web_state);
+  web::TestWebStateObserver* observer_ptr = observer.get();
+
   web_state->GetNavigationManager()->LoadIfNecessary();
-  return chrome_test_util::WaitForPageToFinishLoading();
+
+  // The navigation triggered by LoadIfNecessary() may only start loading in the
+  // next run loop, if it is for a web URL. The most reliable way to detect that
+  // this navigation has finished is via the WebStateObserver.
+  return base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForPageLoadTimeout, ^{
+        return observer_ptr->did_finish_navigation_info() &&
+               observer_ptr->did_finish_navigation_info()->context &&
+               observer_ptr->did_finish_navigation_info()->context->GetUrl() ==
+                   last_committed_url;
+      });
 }
 
 }  // namespace chrome_test_util
diff --git a/jingle/glue/utils.cc b/jingle/glue/utils.cc
index 816bf724..9fba7b6 100644
--- a/jingle/glue/utils.cc
+++ b/jingle/glue/utils.cc
@@ -51,6 +51,13 @@
   return rtc::IPAddress();
 }
 
+net::IPAddress RtcIPAddressToNetIPAddress(const rtc::IPAddress& ip_address) {
+  rtc::SocketAddress socket_address(ip_address, 0);
+  net::IPEndPoint ip_endpoint;
+  jingle_glue::SocketAddressToIPEndPoint(socket_address, &ip_endpoint);
+  return ip_endpoint.address();
+}
+
 std::string SerializeP2PCandidate(const cricket::Candidate& candidate) {
   // TODO(sergeyu): Use SDP to format candidates?
   base::DictionaryValue value;
diff --git a/jingle/glue/utils.h b/jingle/glue/utils.h
index 53272f9..8a5dfc77 100644
--- a/jingle/glue/utils.h
+++ b/jingle/glue/utils.h
@@ -34,6 +34,8 @@
 
 rtc::IPAddress NetIPAddressToRtcIPAddress(const net::IPAddress& ip_address);
 
+net::IPAddress RtcIPAddressToNetIPAddress(const rtc::IPAddress& ip_address);
+
 // Helper functions to serialize and deserialize P2P candidates.
 std::string SerializeP2PCandidate(const cricket::Candidate& candidate);
 bool DeserializeP2PCandidate(const std::string& address,
diff --git a/media/base/fake_demuxer_stream.cc b/media/base/fake_demuxer_stream.cc
index a327a38a..0345ce1 100644
--- a/media/base/fake_demuxer_stream.cc
+++ b/media/base/fake_demuxer_stream.cc
@@ -158,7 +158,7 @@
   const gfx::Rect kVisibleRect(kStartWidth, kStartHeight);
   video_decoder_config_.Initialize(
       kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_I420,
-      COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0, next_coded_size_, kVisibleRect,
+      VideoColorSpace(), VIDEO_ROTATION_0, next_coded_size_, kVisibleRect,
       next_coded_size_, EmptyExtraData(),
       is_encrypted_ ? AesCtrEncryptionScheme() : Unencrypted());
   next_coded_size_.Enlarge(kWidthDelta, kHeightDelta);
diff --git a/media/base/test_helpers.cc b/media/base/test_helpers.cc
index 3757bc79..8a1f79e 100644
--- a/media/base/test_helpers.cc
+++ b/media/base/test_helpers.cc
@@ -127,6 +127,7 @@
 
 static VideoDecoderConfig GetTestConfig(VideoCodec codec,
                                         VideoCodecProfile config,
+                                        const VideoColorSpace& color_space,
                                         VideoRotation rotation,
                                         gfx::Size coded_size,
                                         bool is_encrypted) {
@@ -134,7 +135,7 @@
   gfx::Size natural_size = coded_size;
 
   return VideoDecoderConfig(
-      codec, config, PIXEL_FORMAT_I420, COLOR_SPACE_JPEG, rotation, coded_size,
+      codec, config, PIXEL_FORMAT_I420, color_space, rotation, coded_size,
       visible_rect, natural_size, EmptyExtraData(),
       is_encrypted ? AesCtrEncryptionScheme() : Unencrypted());
 }
@@ -145,50 +146,64 @@
 // static
 VideoDecoderConfig TestVideoConfig::Invalid() {
   return GetTestConfig(kUnknownVideoCodec, VIDEO_CODEC_PROFILE_UNKNOWN,
-                       VIDEO_ROTATION_0, kNormalSize, false);
+                       VideoColorSpace::JPEG(), VIDEO_ROTATION_0, kNormalSize,
+                       false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::Normal(VideoCodec codec) {
-  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, VIDEO_ROTATION_0,
-                       kNormalSize, false);
+  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN,
+                       VideoColorSpace::JPEG(), VIDEO_ROTATION_0, kNormalSize,
+                       false);
+}
+
+// static
+VideoDecoderConfig TestVideoConfig::NormalWithColorSpace(
+    VideoCodec codec,
+    const VideoColorSpace& color_space) {
+  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, color_space,
+                       VIDEO_ROTATION_0, kNormalSize, false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::NormalH264(VideoCodecProfile config) {
-  return GetTestConfig(kCodecH264, config, VIDEO_ROTATION_0, kNormalSize,
-                       false);
+  return GetTestConfig(kCodecH264, config, VideoColorSpace::JPEG(),
+                       VIDEO_ROTATION_0, kNormalSize, false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::NormalCodecProfile(
     VideoCodec codec,
     VideoCodecProfile profile) {
-  return GetTestConfig(codec, profile, VIDEO_ROTATION_0, kNormalSize, false);
+  return GetTestConfig(codec, profile, VideoColorSpace::JPEG(),
+                       VIDEO_ROTATION_0, kNormalSize, false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::NormalEncrypted(VideoCodec codec) {
-  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, VIDEO_ROTATION_0,
-                       kNormalSize, true);
+  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN,
+                       VideoColorSpace::JPEG(), VIDEO_ROTATION_0, kNormalSize,
+                       true);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::NormalRotated(VideoRotation rotation) {
-  return GetTestConfig(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, rotation,
-                       kNormalSize, false);
+  return GetTestConfig(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
+                       VideoColorSpace::JPEG(), rotation, kNormalSize, false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::Large(VideoCodec codec) {
-  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, VIDEO_ROTATION_0,
-                       kLargeSize, false);
+  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN,
+                       VideoColorSpace::JPEG(), VIDEO_ROTATION_0, kLargeSize,
+                       false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::LargeEncrypted(VideoCodec codec) {
-  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, VIDEO_ROTATION_0,
-                       kLargeSize, true);
+  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN,
+                       VideoColorSpace::JPEG(), VIDEO_ROTATION_0, kLargeSize,
+                       true);
 }
 
 // static
diff --git a/media/base/test_helpers.h b/media/base/test_helpers.h
index ea54a5b..e16c6e139 100644
--- a/media/base/test_helpers.h
+++ b/media/base/test_helpers.h
@@ -88,6 +88,9 @@
   static VideoDecoderConfig Invalid();
 
   static VideoDecoderConfig Normal(VideoCodec codec = kCodecVP8);
+  static VideoDecoderConfig NormalWithColorSpace(
+      VideoCodec codec,
+      const VideoColorSpace& color_space);
   static VideoDecoderConfig NormalH264(
       VideoCodecProfile = VIDEO_CODEC_PROFILE_UNKNOWN);
   static VideoDecoderConfig NormalCodecProfile(
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc
index 11732df..aff9a78b 100644
--- a/media/base/video_decoder_config.cc
+++ b/media/base/video_decoder_config.cc
@@ -67,7 +67,7 @@
     VideoCodec codec,
     VideoCodecProfile profile,
     VideoPixelFormat format,
-    ColorSpace color_space,
+    const VideoColorSpace& color_space,
     VideoRotation rotation,
     const gfx::Size& coded_size,
     const gfx::Rect& visible_rect,
@@ -83,11 +83,6 @@
 
 VideoDecoderConfig::~VideoDecoderConfig() = default;
 
-void VideoDecoderConfig::set_color_space_info(
-    const VideoColorSpace& color_space_info) {
-  color_space_info_ = color_space_info;
-}
-
 const VideoColorSpace& VideoDecoderConfig::color_space_info() const {
   return color_space_info_;
 }
@@ -103,7 +98,7 @@
 void VideoDecoderConfig::Initialize(VideoCodec codec,
                                     VideoCodecProfile profile,
                                     VideoPixelFormat format,
-                                    ColorSpace color_space,
+                                    const VideoColorSpace& color_space,
                                     VideoRotation rotation,
                                     const gfx::Size& coded_size,
                                     const gfx::Rect& visible_rect,
@@ -119,21 +114,7 @@
   natural_size_ = natural_size;
   extra_data_ = extra_data;
   encryption_scheme_ = encryption_scheme;
-
-  switch (color_space) {
-    case ColorSpace::COLOR_SPACE_JPEG:
-      color_space_info_ = VideoColorSpace::JPEG();
-      break;
-    case ColorSpace::COLOR_SPACE_HD_REC709:
-      color_space_info_ = VideoColorSpace::REC709();
-      break;
-    case ColorSpace::COLOR_SPACE_SD_REC601:
-      color_space_info_ = VideoColorSpace::REC601();
-      break;
-    case ColorSpace::COLOR_SPACE_UNSPECIFIED:
-    default:
-      break;
-  }
+  color_space_info_ = color_space;
 }
 
 bool VideoDecoderConfig::IsValidConfig() const {
diff --git a/media/base/video_decoder_config.h b/media/base/video_decoder_config.h
index 8ac47a59..0ef659e 100644
--- a/media/base/video_decoder_config.h
+++ b/media/base/video_decoder_config.h
@@ -38,7 +38,7 @@
   VideoDecoderConfig(VideoCodec codec,
                      VideoCodecProfile profile,
                      VideoPixelFormat format,
-                     ColorSpace color_space,
+                     const VideoColorSpace& color_space,
                      VideoRotation rotation,
                      const gfx::Size& coded_size,
                      const gfx::Rect& visible_rect,
@@ -54,7 +54,7 @@
   void Initialize(VideoCodec codec,
                   VideoCodecProfile profile,
                   VideoPixelFormat format,
-                  ColorSpace color_space,
+                  const VideoColorSpace& color_space,
                   VideoRotation rotation,
                   const gfx::Size& coded_size,
                   const gfx::Rect& visible_rect,
@@ -118,7 +118,6 @@
     return encryption_scheme_;
   }
 
-  void set_color_space_info(const VideoColorSpace& color_space_info);
   const VideoColorSpace& color_space_info() const;
 
   void set_hdr_metadata(const HDRMetadata& hdr_metadata);
diff --git a/media/base/video_decoder_config_unittest.cc b/media/base/video_decoder_config_unittest.cc
index 4697c769..33d849e 100644
--- a/media/base/video_decoder_config_unittest.cc
+++ b/media/base/video_decoder_config_unittest.cc
@@ -17,7 +17,7 @@
 
 TEST(VideoDecoderConfigTest, Invalid_UnsupportedPixelFormat) {
   VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
-                            PIXEL_FORMAT_UNKNOWN, COLOR_SPACE_UNSPECIFIED,
+                            PIXEL_FORMAT_UNKNOWN, VideoColorSpace(),
                             VIDEO_ROTATION_0, kCodedSize, kVisibleRect,
                             kNaturalSize, EmptyExtraData(), Unencrypted());
   EXPECT_FALSE(config.IsValidConfig());
@@ -26,36 +26,36 @@
 TEST(VideoDecoderConfigTest, Invalid_AspectRatioNumeratorZero) {
   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 0, 1);
   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
-                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                            kCodedSize, kVisibleRect, natural_size,
-                            EmptyExtraData(), Unencrypted());
+                            VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                            kVisibleRect, natural_size, EmptyExtraData(),
+                            Unencrypted());
   EXPECT_FALSE(config.IsValidConfig());
 }
 
 TEST(VideoDecoderConfigTest, Invalid_AspectRatioDenominatorZero) {
   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, 0);
   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
-                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                            kCodedSize, kVisibleRect, natural_size,
-                            EmptyExtraData(), Unencrypted());
+                            VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                            kVisibleRect, natural_size, EmptyExtraData(),
+                            Unencrypted());
   EXPECT_FALSE(config.IsValidConfig());
 }
 
 TEST(VideoDecoderConfigTest, Invalid_AspectRatioNumeratorNegative) {
   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), -1, 1);
   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
-                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                            kCodedSize, kVisibleRect, natural_size,
-                            EmptyExtraData(), Unencrypted());
+                            VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                            kVisibleRect, natural_size, EmptyExtraData(),
+                            Unencrypted());
   EXPECT_FALSE(config.IsValidConfig());
 }
 
 TEST(VideoDecoderConfigTest, Invalid_AspectRatioDenominatorNegative) {
   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, -1);
   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
-                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                            kCodedSize, kVisibleRect, natural_size,
-                            EmptyExtraData(), Unencrypted());
+                            VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                            kVisibleRect, natural_size, EmptyExtraData(),
+                            Unencrypted());
   EXPECT_FALSE(config.IsValidConfig());
 }
 
@@ -64,9 +64,9 @@
   int num = ceil(static_cast<double>(limits::kMaxDimension + 1) / width);
   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), num, 1);
   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
-                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                            kCodedSize, kVisibleRect, natural_size,
-                            EmptyExtraData(), Unencrypted());
+                            VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                            kVisibleRect, natural_size, EmptyExtraData(),
+                            Unencrypted());
   EXPECT_FALSE(config.IsValidConfig());
 }
 
@@ -78,9 +78,9 @@
   EXPECT_EQ(320, natural_size.width());
   EXPECT_EQ(240 * 641, natural_size.height());
   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
-                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                            kCodedSize, kVisibleRect, natural_size,
-                            EmptyExtraData(), Unencrypted());
+                            VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                            kVisibleRect, natural_size, EmptyExtraData(),
+                            Unencrypted());
   EXPECT_FALSE(config.IsValidConfig());
 }
 
diff --git a/media/base/video_thumbnail_decoder_unittest.cc b/media/base/video_thumbnail_decoder_unittest.cc
index 8edfd5a..63d54bd 100644
--- a/media/base/video_thumbnail_decoder_unittest.cc
+++ b/media/base/video_thumbnail_decoder_unittest.cc
@@ -33,7 +33,7 @@
     auto mock_video_decoder = std::make_unique<MockVideoDecoder>();
     mock_video_decoder_ = mock_video_decoder.get();
     VideoDecoderConfig valid_config(
-        kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420, COLOR_SPACE_UNSPECIFIED,
+        kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420, VideoColorSpace(),
         VIDEO_ROTATION_0, gfx::Size(1, 1), gfx::Rect(1, 1), gfx::Size(1, 1),
         EmptyExtraData(), Unencrypted());
 
diff --git a/media/blink/video_decode_stats_reporter_unittest.cc b/media/blink/video_decode_stats_reporter_unittest.cc
index d6ec074..4ed0dde 100644
--- a/media/blink/video_decode_stats_reporter_unittest.cc
+++ b/media/blink/video_decode_stats_reporter_unittest.cc
@@ -41,9 +41,10 @@
                                    gfx::Size natural_size) {
   gfx::Size coded_size = natural_size;
   gfx::Rect visible_rect(coded_size.width(), coded_size.height());
-  return VideoDecoderConfig(codec, profile, PIXEL_FORMAT_I420, COLOR_SPACE_JPEG,
-                            VIDEO_ROTATION_0, coded_size, visible_rect,
-                            natural_size, EmptyExtraData(), Unencrypted());
+  return VideoDecoderConfig(codec, profile, PIXEL_FORMAT_I420,
+                            VideoColorSpace::JPEG(), VIDEO_ROTATION_0,
+                            coded_size, visible_rect, natural_size,
+                            EmptyExtraData(), Unencrypted());
 }
 
 VideoDecoderConfig MakeDefaultVideoConfig() {
diff --git a/media/cast/sender/h264_vt_encoder_unittest.cc b/media/cast/sender/h264_vt_encoder_unittest.cc
index 110eb4b..f5681b0 100644
--- a/media/cast/sender/h264_vt_encoder_unittest.cc
+++ b/media/cast/sender/h264_vt_encoder_unittest.cc
@@ -303,7 +303,7 @@
 // Failed on mac_chromium_rel_ng trybot. http://crbug.com/627260
 TEST_F(H264VideoToolboxEncoderTest, DISABLED_CheckFramesAreDecodable) {
   VideoDecoderConfig config(
-      kCodecH264, H264PROFILE_MAIN, frame_->format(), COLOR_SPACE_UNSPECIFIED,
+      kCodecH264, H264PROFILE_MAIN, frame_->format(), VideoColorSpace(),
       VIDEO_ROTATION_0, frame_->coded_size(), frame_->visible_rect(),
       frame_->natural_size(), EmptyExtraData(), Unencrypted());
   scoped_refptr<EndToEndFrameChecker> checker(new EndToEndFrameChecker(config));
diff --git a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
index ba0e4ae..32a82d6 100644
--- a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
@@ -50,15 +50,13 @@
 
   VideoDecoderConfig media_config(
       ToMediaVideoCodec(config.codec), ToMediaVideoCodecProfile(config.profile),
-      ToMediaVideoFormat(config.format), COLOR_SPACE_UNSPECIFIED,
+      ToMediaVideoFormat(config.format), ToMediaColorSpace(config.color_space),
       VideoRotation::VIDEO_ROTATION_0, coded_size, gfx::Rect(coded_size),
       coded_size,
       std::vector<uint8_t>(config.extra_data,
                            config.extra_data + config.extra_data_size),
       Unencrypted());
 
-  media_config.set_color_space_info(ToMediaColorSpace(config.color_space));
-
   return media_config;
 }
 
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index dd914e885..d3c799c5 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -589,10 +589,9 @@
     extra_data.assign(codec_context->extradata,
                       codec_context->extradata + codec_context->extradata_size);
   }
-  config->Initialize(codec, profile, format, COLOR_SPACE_UNSPECIFIED,
-                     video_rotation, coded_size, visible_rect, natural_size,
-                     extra_data, GetEncryptionScheme(stream));
-  config->set_color_space_info(color_space);
+  config->Initialize(codec, profile, format, color_space, video_rotation,
+                     coded_size, visible_rect, natural_size, extra_data,
+                     GetEncryptionScheme(stream));
   return true;
 }
 
diff --git a/media/filters/BUILD.gn b/media/filters/BUILD.gn
index d558b53..ffe1e64 100644
--- a/media/filters/BUILD.gn
+++ b/media/filters/BUILD.gn
@@ -206,6 +206,14 @@
       "h264_bitstream_buffer.h",
     ]
   }
+
+  if (is_fuchsia) {
+    sources += [
+      "fuchsia/fuchsia_video_decoder.cc",
+      "fuchsia/fuchsia_video_decoder.h",
+    ]
+    deps += [ "//third_party/fuchsia-sdk/sdk:mediacodec" ]
+  }
 }
 
 source_set("perftests") {
@@ -281,10 +289,6 @@
     "vp9_raw_bits_reader_unittest.cc",
   ]
 
-  if (is_android) {
-    sources += [ "android/video_frame_extractor_unittest.cc" ]
-  }
-
   deps = [
     "//base/test:test_support",
     "//media:test_support",
@@ -299,6 +303,7 @@
   ]
 
   if (is_android) {
+    sources += [ "android/video_frame_extractor_unittest.cc" ]
     sources -= [
       "decrypting_audio_decoder_unittest.cc",
       "decrypting_video_decoder_unittest.cc",
@@ -307,6 +312,10 @@
     deps += [ "//ui/gl" ]
   }
 
+  if (is_fuchsia) {
+    sources += [ "fuchsia/fuchsia_video_decoder_unittest.cc" ]
+  }
+
   # libvpx for running vpx test on chromecast doesn't support high bit depth.
   # This may cause some unit tests failure.
   if (is_chromecast) {
diff --git a/media/filters/aom_video_decoder.cc b/media/filters/aom_video_decoder.cc
index 920a3a7..ab54354d 100644
--- a/media/filters/aom_video_decoder.cc
+++ b/media/filters/aom_video_decoder.cc
@@ -12,6 +12,7 @@
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_log.h"
 #include "media/base/video_util.h"
+#include "media/filters/frame_buffer_pool.h"
 #include "third_party/libyuv/include/libyuv/convert.h"
 
 // Include libaom header files.
@@ -100,6 +101,28 @@
   frame->set_color_space(color_space.ToGfxColorSpace());
 }
 
+static int GetFrameBuffer(void* cb_priv,
+                          size_t min_size,
+                          aom_codec_frame_buffer* fb) {
+  DCHECK(cb_priv);
+  DCHECK(fb);
+  FrameBufferPool* pool = static_cast<FrameBufferPool*>(cb_priv);
+  fb->data = pool->GetFrameBuffer(min_size, &fb->priv);
+  fb->size = min_size;
+  return 0;
+}
+
+static int ReleaseFrameBuffer(void* cb_priv, aom_codec_frame_buffer* fb) {
+  DCHECK(cb_priv);
+  DCHECK(fb);
+  if (!fb->priv)
+    return -1;
+
+  FrameBufferPool* pool = static_cast<FrameBufferPool*>(cb_priv);
+  pool->ReleaseFrameBuffer(fb->priv);
+  return 0;
+}
+
 AomVideoDecoder::AomVideoDecoder(MediaLog* media_log) : media_log_(media_log) {
   DETACH_FROM_THREAD(thread_checker_);
 }
@@ -142,9 +165,6 @@
   // into uint8_t samples.
   aom_config.allow_lowbitdepth = 1;
 
-  // TODO(dalecurtis, tguilbert): Switch to zero-copy by specifying external
-  // frame buffer functions and use FrameBufferPool. https://crbug.com/867613
-  //
   // TODO(dalecurtis, tguilbert): Move decoding off the media thread to the
   // offload thread via OffloadingVideoDecoder. https://crbug.com/867613
 
@@ -157,6 +177,18 @@
     return;
   }
 
+  // Setup codec for zero copy frames.
+  if (!memory_pool_)
+    memory_pool_ = new FrameBufferPool();
+  if (aom_codec_set_frame_buffer_functions(
+          context.get(), &GetFrameBuffer, &ReleaseFrameBuffer,
+          memory_pool_.get()) != AOM_CODEC_OK) {
+    DLOG(ERROR) << "Failed to configure external buffers. "
+                << aom_codec_error(context.get());
+    bound_init_cb.Run(false);
+    return;
+  }
+
   config_ = config;
   state_ = DecoderState::kNormal;
   output_cb_ = BindToCurrentLoop(output_cb);
@@ -201,6 +233,7 @@
 void AomVideoDecoder::Reset(const base::Closure& reset_cb) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   state_ = DecoderState::kNormal;
+  timestamps_.clear();
   base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, reset_cb);
 }
 
@@ -210,16 +243,20 @@
     return;
   aom_codec_destroy(aom_decoder_.get());
   aom_decoder_.reset();
+
+  if (memory_pool_) {
+    memory_pool_->Shutdown();
+    memory_pool_ = nullptr;
+  }
 }
 
 bool AomVideoDecoder::DecodeBuffer(const DecoderBuffer* buffer) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!buffer->end_of_stream());
 
-  if (aom_codec_decode(
-          aom_decoder_.get(), buffer->data(), buffer->data_size(),
-          reinterpret_cast<void*>(buffer->timestamp().InMicroseconds())) !=
-      AOM_CODEC_OK) {
+  timestamps_.push_back(buffer->timestamp());
+  if (aom_codec_decode(aom_decoder_.get(), buffer->data(), buffer->data_size(),
+                       nullptr) != AOM_CODEC_OK) {
     const char* detail = aom_codec_error_detail(aom_decoder_.get());
     MEDIA_LOG(ERROR, media_log_)
         << "aom_codec_decode() failed: " << aom_codec_error(aom_decoder_.get())
@@ -237,12 +274,13 @@
       return false;
     }
 
-    frame->set_timestamp(base::TimeDelta::FromMicroseconds(
-        reinterpret_cast<int64_t>(img->user_priv)));
-
     // TODO(dalecurtis): Is this true even for low resolutions?
     frame->metadata()->SetBoolean(VideoFrameMetadata::POWER_EFFICIENT, false);
 
+    // Ensure the frame memory is returned to the MemoryPool upon discard.
+    frame->AddDestructionObserver(
+        memory_pool_->CreateFrameCallback(img->fb_priv));
+
     SetColorSpaceForFrame(img, config_, frame.get());
     output_cb_.Run(std::move(frame));
   }
@@ -258,22 +296,18 @@
   if (pixel_format == PIXEL_FORMAT_UNKNOWN)
     return nullptr;
 
-  // Since we're making a copy, only copy the visible area.
+  // Pull the expected timestamp from the front of the queue.
+  DCHECK(!timestamps_.empty());
+  const base::TimeDelta timestamp = timestamps_.front();
+  timestamps_.pop_front();
+
   const gfx::Rect visible_rect(img->d_w, img->d_h);
-  auto frame = frame_pool_.CreateFrame(
+  return VideoFrame::WrapExternalYuvData(
       pixel_format, visible_rect.size(), visible_rect,
       GetNaturalSize(visible_rect, config_.GetPixelAspectRatio()),
-      kNoTimestamp);
-  if (!frame)
-    return nullptr;
-
-  for (int plane = 0; plane < 3; plane++) {
-    libyuv::CopyPlane(img->planes[plane], img->stride[plane],
-                      frame->visible_data(plane), frame->stride(plane),
-                      frame->row_bytes(plane), frame->rows(plane));
-  }
-
-  return frame;
+      img->stride[AOM_PLANE_Y], img->stride[AOM_PLANE_U],
+      img->stride[AOM_PLANE_V], img->planes[AOM_PLANE_Y],
+      img->planes[AOM_PLANE_U], img->planes[AOM_PLANE_V], timestamp);
 }
 
 }  // namespace media
diff --git a/media/filters/aom_video_decoder.h b/media/filters/aom_video_decoder.h
index 053a91b..750e7acf 100644
--- a/media/filters/aom_video_decoder.h
+++ b/media/filters/aom_video_decoder.h
@@ -6,17 +6,18 @@
 #define MEDIA_FILTERS_AOM_VIDEO_DECODER_H_
 
 #include "base/callback_forward.h"
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
 #include "media/base/video_decoder.h"
 #include "media/base/video_decoder_config.h"
 #include "media/base/video_frame.h"
-#include "media/base/video_frame_pool.h"
 
 struct aom_codec_ctx;
 struct aom_image;
 
 namespace media {
+class FrameBufferPool;
 class MediaLog;
 
 // libaom video decoder wrapper.
@@ -73,7 +74,10 @@
   VideoDecoderConfig config_;
 
   // Pool used for memory efficiency when vending frames from the decoder.
-  VideoFramePool frame_pool_;
+  scoped_refptr<FrameBufferPool> memory_pool_;
+
+  // Timestamps are FIFO for libaom decoding.
+  base::circular_deque<base::TimeDelta> timestamps_;
 
   // The allocated decoder; null before Initialize() and anytime after
   // CloseDecoder().
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index eef8892..a918841 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -227,9 +227,9 @@
 TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) {
   // Specify Theora w/o extra data so that avcodec_open2() fails.
   VideoDecoderConfig config(kCodecTheora, VIDEO_CODEC_PROFILE_UNKNOWN,
-                            kVideoFormat, COLOR_SPACE_UNSPECIFIED,
-                            VIDEO_ROTATION_0, kCodedSize, kVisibleRect,
-                            kNaturalSize, EmptyExtraData(), Unencrypted());
+                            kVideoFormat, VideoColorSpace(), VIDEO_ROTATION_0,
+                            kCodedSize, kVisibleRect, kNaturalSize,
+                            EmptyExtraData(), Unencrypted());
   InitializeWithConfigWithResult(config, false);
 }
 
diff --git a/media/gpu/fuchsia/fuchsia_video_decoder.cc b/media/filters/fuchsia/fuchsia_video_decoder.cc
similarity index 98%
rename from media/gpu/fuchsia/fuchsia_video_decoder.cc
rename to media/filters/fuchsia/fuchsia_video_decoder.cc
index f9aaecd0..377fe0b 100644
--- a/media/gpu/fuchsia/fuchsia_video_decoder.cc
+++ b/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/fuchsia/fuchsia_video_decoder.h"
+#include "media/filters/fuchsia/fuchsia_video_decoder.h"
 
 #include <fuchsia/mediacodec/cpp/fidl.h>
 #include <zircon/rights.h>
@@ -643,8 +643,9 @@
 
   auto weak_this = weak_this_;
 
-  // Call decode callback with DECODE_ERROR before clearing input_buffers_.
-  // Otherwise InputBuffer destructor would call it with ABORTED.
+  // Call all decode callback with DECODE_ERROR before clearing input_buffers_
+  // and pending_decodes_. Otherwise PendingDecode and InputBuffer destructors
+  // would the callbacks with ABORTED.
   for (auto& buffer : input_buffers_) {
     if (buffer.is_used()) {
       buffer.OnDoneDecoding(DecodeStatus::DECODE_ERROR);
@@ -656,7 +657,13 @@
     }
   }
 
-  // Will call DecodeCB(ABORTED) for all pending decode requests.
+  for (auto& pending_decode : pending_decodes_) {
+    pending_decode.TakeDecodeCallback().Run(DecodeStatus::DECODE_ERROR);
+    if (!weak_this) {
+      return;
+    }
+  }
+
   pending_decodes_.clear();
 
   num_used_input_buffers_ = 0;
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.h b/media/filters/fuchsia/fuchsia_video_decoder.h
new file mode 100644
index 0000000..d9c37d05
--- /dev/null
+++ b/media/filters/fuchsia/fuchsia_video_decoder.h
@@ -0,0 +1,21 @@
+// Copyright 2018 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_FILTERS_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
+#define MEDIA_FILTERS_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
+
+#include <memory>
+
+#include "media/base/media_export.h"
+
+namespace media {
+
+class VideoDecoder;
+
+// Creates VideoDecoder that uses fuchsia.mediacodec API.
+MEDIA_EXPORT std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder();
+
+}  // namespace media
+
+#endif  // MEDIA_FILTERS_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
diff --git a/media/gpu/fuchsia/fuchsia_video_decoder_unittest.cc b/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
similarity index 98%
rename from media/gpu/fuchsia/fuchsia_video_decoder_unittest.cc
rename to media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
index 4ff26656..c8ec6dd0 100644
--- a/media/gpu/fuchsia/fuchsia_video_decoder_unittest.cc
+++ b/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/fuchsia/fuchsia_video_decoder.h"
+#include "media/filters/fuchsia/fuchsia_video_decoder.h"
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
diff --git a/media/filters/source_buffer_state_unittest.cc b/media/filters/source_buffer_state_unittest.cc
index 8448fef..04fe3fe 100644
--- a/media/filters/source_buffer_state_unittest.cc
+++ b/media/filters/source_buffer_state_unittest.cc
@@ -36,7 +36,7 @@
   gfx::Size size(w, h);
   gfx::Rect visible_rect(size);
   return VideoDecoderConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN,
-                            PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
+                            PIXEL_FORMAT_I420, VideoColorSpace::REC709(),
                             VIDEO_ROTATION_0, size, visible_rect, size,
                             EmptyExtraData(), Unencrypted());
 }
diff --git a/media/filters/vpx_video_decoder_fuzzertest.cc b/media/filters/vpx_video_decoder_fuzzertest.cc
index 462796c3..b4279e5 100644
--- a/media/filters/vpx_video_decoder_fuzzertest.cc
+++ b/media/filters/vpx_video_decoder_fuzzertest.cc
@@ -87,7 +87,10 @@
 
   auto profile =
       static_cast<VideoCodecProfile>(rng() % VIDEO_CODEC_PROFILE_MAX);
-  auto color_space = static_cast<ColorSpace>(rng() % COLOR_SPACE_MAX);
+  auto color_space =
+      VideoColorSpace(rng() % 256, rng() % 256, rng() % 256,
+                      (rng() & 1) ? gfx::ColorSpace::RangeID::LIMITED
+                                  : gfx::ColorSpace::RangeID::FULL);
   auto rotation = static_cast<VideoRotation>(rng() % VIDEO_ROTATION_MAX);
   auto coded_size = gfx::Size(1 + (rng() % 127), 1 + (rng() % 127));
   auto visible_rect = gfx::Rect(coded_size);
diff --git a/media/formats/mp2t/es_adapter_video_unittest.cc b/media/formats/mp2t/es_adapter_video_unittest.cc
index 60b99fa..7a6b97a 100644
--- a/media/formats/mp2t/es_adapter_video_unittest.cc
+++ b/media/formats/mp2t/es_adapter_video_unittest.cc
@@ -33,9 +33,9 @@
   gfx::Rect visible_rect(0, 0, 320, 240);
   gfx::Size natural_size(320, 240);
   return VideoDecoderConfig(kCodecH264, H264PROFILE_MAIN, PIXEL_FORMAT_I420,
-                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                            coded_size, visible_rect, natural_size,
-                            EmptyExtraData(), Unencrypted());
+                            VideoColorSpace(), VIDEO_ROTATION_0, coded_size,
+                            visible_rect, natural_size, EmptyExtraData(),
+                            Unencrypted());
 }
 
 BufferQueue GenerateFakeBuffers(const int* frame_pts_ms,
diff --git a/media/formats/mp2t/es_parser_h264.cc b/media/formats/mp2t/es_parser_h264.cc
index 14bf0ee1..b893adb3a 100644
--- a/media/formats/mp2t/es_parser_h264.cc
+++ b/media/formats/mp2t/es_parser_h264.cc
@@ -529,7 +529,7 @@
   }
 
   VideoDecoderConfig video_decoder_config(
-      kCodecH264, profile, PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
+      kCodecH264, profile, PIXEL_FORMAT_I420, VideoColorSpace::REC709(),
       VIDEO_ROTATION_0, coded_size.value(), visible_rect.value(), natural_size,
       EmptyExtraData(), scheme);
 
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index fd15800..623bc53 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -557,7 +557,7 @@
           return false;
       }
       video_config.Initialize(entry.video_codec, entry.video_codec_profile,
-                              PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
+                              PIXEL_FORMAT_I420, VideoColorSpace::REC709(),
                               CalculateRotation(track->header, moov_->header),
                               coded_size, visible_rect, natural_size,
                               // No decoder-specific buffer needed for AVC;
diff --git a/media/formats/webm/webm_video_client.cc b/media/formats/webm/webm_video_client.cc
index 813a0863..c8dd7d27 100644
--- a/media/formats/webm/webm_video_client.cc
+++ b/media/formats/webm/webm_video_client.cc
@@ -121,14 +121,15 @@
   }
   gfx::Size natural_size = gfx::Size(display_width_, display_height_);
 
-  config->Initialize(video_codec, profile, format, COLOR_SPACE_HD_REC709,
-                     VIDEO_ROTATION_0, coded_size, visible_rect, natural_size,
-                     codec_private, encryption_scheme);
+  VideoColorSpace color_space = VideoColorSpace::REC709();
   if (colour_parsed_) {
     WebMColorMetadata color_metadata = colour_parser_.GetWebMColorMetadata();
-    config->set_color_space_info(color_metadata.color_space);
+    color_space = color_metadata.color_space;
     config->set_hdr_metadata(color_metadata.hdr_metadata);
   }
+  config->Initialize(video_codec, profile, format, color_space,
+                     VIDEO_ROTATION_0, coded_size, visible_rect, natural_size,
+                     codec_private, encryption_scheme);
   return config->IsValidConfig();
 }
 
diff --git a/media/formats/webm/webm_video_client_unittest.cc b/media/formats/webm/webm_video_client_unittest.cc
index a8c3192..bcdce3a6 100644
--- a/media/formats/webm/webm_video_client_unittest.cc
+++ b/media/formats/webm/webm_video_client_unittest.cc
@@ -56,10 +56,10 @@
   EXPECT_TRUE(webm_video_client_.InitializeConfig(kCodecId, codec_private,
                                                   EncryptionScheme(), &config));
 
-  VideoDecoderConfig expected_config(kCodecVP9, profile, PIXEL_FORMAT_I420,
-                                     COLOR_SPACE_HD_REC709, VIDEO_ROTATION_0,
-                                     kCodedSize, gfx::Rect(kCodedSize),
-                                     kCodedSize, codec_private, Unencrypted());
+  VideoDecoderConfig expected_config(
+      kCodecVP9, profile, PIXEL_FORMAT_I420, VideoColorSpace::REC709(),
+      VIDEO_ROTATION_0, kCodedSize, gfx::Rect(kCodedSize), kCodedSize,
+      codec_private, Unencrypted());
 
   EXPECT_TRUE(config.Matches(expected_config))
       << "Config (" << config.AsHumanReadableString()
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 631258ba1..35a26d08 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -214,14 +214,6 @@
     }
   }
 
-  if (is_fuchsia) {
-    sources += [
-      "fuchsia/fuchsia_video_decoder.cc",
-      "fuchsia/fuchsia_video_decoder.h",
-    ]
-    deps += [ "//third_party/fuchsia-sdk/sdk:mediacodec" ]
-  }
-
   if (use_v4lplugin) {
     sources += get_target_outputs(":libv4l2_generate_stubs")
     deps += [ ":libv4l2_generate_stubs" ]
@@ -268,6 +260,8 @@
       "windows/d3d11_h264_accelerator.h",
       "windows/d3d11_picture_buffer.cc",
       "windows/d3d11_picture_buffer.h",
+      "windows/d3d11_video_context_wrapper.cc",
+      "windows/d3d11_video_context_wrapper.h",
       "windows/d3d11_video_decoder.cc",
       "windows/d3d11_video_decoder.h",
       "windows/d3d11_video_decoder_client.h",
@@ -647,9 +641,6 @@
   if (use_v4l2_codec || use_vaapi) {
     sources += [ "vp8_decoder_unittest.cc" ]
   }
-  if (is_fuchsia) {
-    sources += [ "fuchsia/fuchsia_video_decoder_unittest.cc" ]
-  }
   if (is_win && enable_library_cdms) {
     sources += [
       "windows/d3d11_cdm_proxy_unittest.cc",
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc
index 1f4415bed..013ecf5 100644
--- a/media/gpu/android/media_codec_video_decoder_unittest.cc
+++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -963,16 +963,15 @@
 }
 
 TEST_P(MediaCodecVideoDecoderVp9Test, ColorSpaceIsIncludedInCodecConfig) {
-  VideoDecoderConfig config = TestVideoConfig::Normal(kCodecVP9);
-  VideoColorSpace color_space_info(VideoColorSpace::PrimaryID::BT2020,
-                                   VideoColorSpace::TransferID::SMPTEST2084,
-                                   VideoColorSpace::MatrixID::BT2020_CL,
-                                   gfx::ColorSpace::RangeID::LIMITED);
-
-  config.set_color_space_info(color_space_info);
+  VideoColorSpace color_space(VideoColorSpace::PrimaryID::BT2020,
+                              VideoColorSpace::TransferID::SMPTEST2084,
+                              VideoColorSpace::MatrixID::BT2020_CL,
+                              gfx::ColorSpace::RangeID::LIMITED);
+  VideoDecoderConfig config =
+      TestVideoConfig::NormalWithColorSpace(kCodecVP9, color_space);
   EXPECT_TRUE(InitializeFully_OneDecodePending(config));
 
-  EXPECT_EQ(color_space_info,
+  EXPECT_EQ(color_space,
             codec_allocator_->most_recent_config->container_color_space);
 }
 
diff --git a/media/gpu/fuchsia/fuchsia_video_decoder.h b/media/gpu/fuchsia/fuchsia_video_decoder.h
deleted file mode 100644
index 8388025..0000000
--- a/media/gpu/fuchsia/fuchsia_video_decoder.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2018 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_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
-#define MEDIA_GPU_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
-
-#include <memory>
-
-#include "media/gpu/media_gpu_export.h"
-
-namespace media {
-
-class VideoDecoder;
-
-// Creates VideoDecoder that uses fuchsia.mediacodec API.
-MEDIA_GPU_EXPORT std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder();
-
-}  // namespace media
-
-#endif  // MEDIA_GPU_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
diff --git a/media/gpu/ipc/service/vda_video_decoder_unittest.cc b/media/gpu/ipc/service/vda_video_decoder_unittest.cc
index 5af911db..edb0e1ff 100644
--- a/media/gpu/ipc/service/vda_video_decoder_unittest.cc
+++ b/media/gpu/ipc/service/vda_video_decoder_unittest.cc
@@ -159,7 +159,7 @@
     EXPECT_CALL(init_cb_, Run(true));
     InitializeWithConfig(VideoDecoderConfig(
         kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420,
-        COLOR_SPACE_HD_REC709, VIDEO_ROTATION_0, gfx::Size(1920, 1088),
+        VideoColorSpace::REC709(), VIDEO_ROTATION_0, gfx::Size(1920, 1088),
         gfx::Rect(1920, 1080), gfx::Size(1920, 1080), EmptyExtraData(),
         Unencrypted()));
     RunUntilIdle();
@@ -327,10 +327,11 @@
 }
 
 TEST_P(VdaVideoDecoderTest, Initialize_UnsupportedSize) {
-  InitializeWithConfig(VideoDecoderConfig(
-      kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, COLOR_SPACE_SD_REC601,
-      VIDEO_ROTATION_0, gfx::Size(320, 240), gfx::Rect(320, 240),
-      gfx::Size(320, 240), EmptyExtraData(), Unencrypted()));
+  InitializeWithConfig(
+      VideoDecoderConfig(kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420,
+                         VideoColorSpace::REC601(), VIDEO_ROTATION_0,
+                         gfx::Size(320, 240), gfx::Rect(320, 240),
+                         gfx::Size(320, 240), EmptyExtraData(), Unencrypted()));
   EXPECT_CALL(init_cb_, Run(false));
   RunUntilIdle();
 }
@@ -338,7 +339,7 @@
 TEST_P(VdaVideoDecoderTest, Initialize_UnsupportedCodec) {
   InitializeWithConfig(VideoDecoderConfig(
       kCodecH264, H264PROFILE_BASELINE, PIXEL_FORMAT_I420,
-      COLOR_SPACE_HD_REC709, VIDEO_ROTATION_0, gfx::Size(1920, 1088),
+      VideoColorSpace::REC709(), VIDEO_ROTATION_0, gfx::Size(1920, 1088),
       gfx::Rect(1920, 1080), gfx::Size(1920, 1080), EmptyExtraData(),
       Unencrypted()));
   EXPECT_CALL(init_cb_, Run(false));
@@ -348,9 +349,10 @@
 TEST_P(VdaVideoDecoderTest, Initialize_RejectedByVda) {
   EXPECT_CALL(*vda_, Initialize(_, vdavd_.get())).WillOnce(Return(false));
   InitializeWithConfig(VideoDecoderConfig(
-      kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
-      VIDEO_ROTATION_0, gfx::Size(1920, 1088), gfx::Rect(1920, 1080),
-      gfx::Size(1920, 1080), EmptyExtraData(), Unencrypted()));
+      kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420,
+      VideoColorSpace::REC709(), VIDEO_ROTATION_0, gfx::Size(1920, 1088),
+      gfx::Rect(1920, 1080), gfx::Size(1920, 1080), EmptyExtraData(),
+      Unencrypted()));
   EXPECT_CALL(init_cb_, Run(false));
   RunUntilIdle();
 }
@@ -430,9 +432,10 @@
   EXPECT_CALL(*vda_, TryToSetupDecodeOnSeparateThread(_, _))
       .WillOnce(Return(GetParam()));
   InitializeWithConfig(VideoDecoderConfig(
-      kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
-      VIDEO_ROTATION_0, gfx::Size(640, 480), gfx::Rect(640, 480),
-      gfx::Size(1280, 480), EmptyExtraData(), Unencrypted()));
+      kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420,
+      VideoColorSpace::REC709(), VIDEO_ROTATION_0, gfx::Size(640, 480),
+      gfx::Rect(640, 480), gfx::Size(1280, 480), EmptyExtraData(),
+      Unencrypted()));
   EXPECT_CALL(init_cb_, Run(true));
   RunUntilIdle();
 
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index 6faab780..342326a 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -835,12 +835,12 @@
   VideoDecoderConfig config;
   if (IsVP8(profile_))
     config.Initialize(kCodecVP8, VP8PROFILE_ANY, pixel_format_,
-                      COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0, coded_size,
+                      VideoColorSpace(), VIDEO_ROTATION_0, coded_size,
                       visible_size, natural_size, EmptyExtraData(),
                       Unencrypted());
   else if (IsH264(profile_))
     config.Initialize(kCodecH264, H264PROFILE_MAIN, pixel_format_,
-                      COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0, coded_size,
+                      VideoColorSpace(), VIDEO_ROTATION_0, coded_size,
                       visible_size, natural_size, EmptyExtraData(),
                       Unencrypted());
   else
diff --git a/media/gpu/windows/d3d11_h264_accelerator.cc b/media/gpu/windows/d3d11_h264_accelerator.cc
index dd171c9..ecc7a52 100644
--- a/media/gpu/windows/d3d11_h264_accelerator.cc
+++ b/media/gpu/windows/d3d11_h264_accelerator.cc
@@ -67,13 +67,13 @@
     CdmProxyContext* cdm_proxy_context,
     Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder,
     Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device,
-    Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context)
+    std::unique_ptr<VideoContextWrapper> video_context)
     : client_(client),
       media_log_(media_log),
       cdm_proxy_context_(cdm_proxy_context),
       video_decoder_(video_decoder),
       video_device_(video_device),
-      video_context_(video_context) {}
+      video_context_(std::move(video_context)) {}
 
 D3D11H264Accelerator::~D3D11H264Accelerator() {}
 
@@ -473,7 +473,7 @@
     return false;
   }
 
-  D3D11_VIDEO_DECODER_BUFFER_DESC1 buffers[4] = {};
+  VideoContextWrapper::VideoBufferWrapper buffers[4] = {};
   buffers[0].BufferType = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
   buffers[0].DataOffset = 0;
   buffers[0].DataSize = sizeof(DXVA_PicParams_H264);
@@ -498,8 +498,8 @@
     }
   }
 
-  hr = video_context_->SubmitDecoderBuffers1(video_decoder_.Get(),
-                                             base::size(buffers), buffers);
+  hr = video_context_->SubmitDecoderBuffers(video_decoder_.Get(),
+                                            base::size(buffers), buffers);
   current_offset_ = 0;
   slice_info_.clear();
   bitstream_buffer_bytes_ = nullptr;
diff --git a/media/gpu/windows/d3d11_h264_accelerator.h b/media/gpu/windows/d3d11_h264_accelerator.h
index 0fc68c02..ec9d9ffa 100644
--- a/media/gpu/windows/d3d11_h264_accelerator.h
+++ b/media/gpu/windows/d3d11_h264_accelerator.h
@@ -16,6 +16,7 @@
 #include "media/base/video_frame.h"
 #include "media/gpu/h264_decoder.h"
 #include "media/gpu/h264_dpb.h"
+#include "media/gpu/windows/d3d11_video_context_wrapper.h"
 #include "media/gpu/windows/d3d11_video_decoder_client.h"
 #include "media/gpu/windows/return_on_failure.h"
 #include "media/video/picture.h"
@@ -32,13 +33,12 @@
 class D3D11H264Accelerator : public H264Decoder::H264Accelerator {
  public:
   // |cdm_proxy_context| may be null for clear content.
-  D3D11H264Accelerator(
-      D3D11VideoDecoderClient* client,
-      MediaLog* media_log,
-      CdmProxyContext* cdm_proxy_context,
-      Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder,
-      Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device,
-      Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context);
+  D3D11H264Accelerator(D3D11VideoDecoderClient* client,
+                       MediaLog* media_log,
+                       CdmProxyContext* cdm_proxy_context,
+                       Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder,
+                       Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device,
+                       std::unique_ptr<VideoContextWrapper> video_context);
   ~D3D11H264Accelerator() override;
 
   // H264Decoder::H264Accelerator implementation.
@@ -75,7 +75,7 @@
 
   Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder_;
   Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device_;
-  Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context_;
+  std::unique_ptr<VideoContextWrapper> video_context_;
 
   // This information set at the beginning of a frame and saved for processing
   // all the slices.
diff --git a/media/gpu/windows/d3d11_video_context_wrapper.cc b/media/gpu/windows/d3d11_video_context_wrapper.cc
new file mode 100644
index 0000000..45d05547
--- /dev/null
+++ b/media/gpu/windows/d3d11_video_context_wrapper.cc
@@ -0,0 +1,133 @@
+// Copyright 2018 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/windows/d3d11_video_context_wrapper.h"
+
+#include <memory>
+
+#include "base/memory/weak_ptr.h"
+
+namespace media {
+
+VideoContextWrapper::~VideoContextWrapper() = default;
+
+// Specialization for sample submission
+template <typename CTX>
+struct BufferSubmitter;
+
+template <>
+struct BufferSubmitter<ID3D11VideoContext1> {
+  static HRESULT SubmitDecoderBuffers(
+      Microsoft::WRL::ComPtr<ID3D11VideoContext1> context,
+      ID3D11VideoDecoder* decoder,
+      const UINT num_buffers,
+      const VideoContextWrapper::VideoBufferWrapper* src) {
+    constexpr UINT max_buffers = 4;
+    DCHECK_LE(num_buffers, max_buffers);
+    D3D11_VIDEO_DECODER_BUFFER_DESC1 buffers[max_buffers] = {};
+    for (size_t i = 0; i < num_buffers; i++) {
+      buffers[i].BufferType = src[i].BufferType;
+      buffers[i].DataOffset = src[i].DataOffset;
+      buffers[i].DataSize = src[i].DataSize;
+      buffers[i].pIV = src[i].pIV;
+      buffers[i].IVSize = src[i].IVSize;
+      buffers[i].pSubSampleMappingBlock = src[i].pSubSampleMappingBlock;
+      buffers[i].SubSampleMappingCount = src[i].SubSampleMappingCount;
+    }
+    return context->SubmitDecoderBuffers1(decoder, num_buffers, buffers);
+  }
+};
+
+template <>
+struct BufferSubmitter<ID3D11VideoContext> {
+  static HRESULT SubmitDecoderBuffers(
+      Microsoft::WRL::ComPtr<ID3D11VideoContext> context,
+      ID3D11VideoDecoder* decoder,
+      const UINT num_buffers,
+      const VideoContextWrapper::VideoBufferWrapper* src) {
+    constexpr UINT max_buffers = 4;
+    DCHECK_LE(num_buffers, max_buffers);
+    D3D11_VIDEO_DECODER_BUFFER_DESC buffers[max_buffers] = {};
+    for (size_t i = 0; i < num_buffers; i++) {
+      buffers[i].BufferType = src[i].BufferType;
+      buffers[i].DataOffset = src[i].DataOffset;
+      buffers[i].DataSize = src[i].DataSize;
+      DCHECK_EQ(src[i].pIV, nullptr);
+      DCHECK_EQ(src[i].IVSize, 0u);
+      DCHECK_EQ(src[i].pSubSampleMappingBlock, nullptr);
+      DCHECK_EQ(src[i].SubSampleMappingCount, 0u);
+    }
+    return context->SubmitDecoderBuffers(decoder, num_buffers, buffers);
+  }
+};
+
+// CTX is The type of D3D11VideoContext* that we are wrapping, whether that
+// be D3D11VideoContext or D3D11VideoContext1. Only these types will work
+// since the BufferSubmitter struct is only specialized for these two types.
+template <typename CTX>
+class VideoContextWrapperImpl : public VideoContextWrapper {
+ public:
+  explicit VideoContextWrapperImpl(Microsoft::WRL::ComPtr<CTX> video_context)
+      : video_context_(video_context) {}
+  ~VideoContextWrapperImpl() {}
+
+  HRESULT DecoderBeginFrame(ID3D11VideoDecoder* video_decoder,
+                            ID3D11VideoDecoderOutputView* output_view,
+                            UINT content_key_size,
+                            const void* content_key) override {
+    return video_context_->DecoderBeginFrame(video_decoder, output_view,
+                                             content_key_size, content_key);
+  }
+
+  HRESULT GetDecoderBuffer(ID3D11VideoDecoder* video_decoder,
+                           D3D11_VIDEO_DECODER_BUFFER_TYPE type,
+                           UINT* buffer_size,
+                           void** buffer) override {
+    return video_context_->GetDecoderBuffer(video_decoder, type, buffer_size,
+                                            buffer);
+  }
+
+  HRESULT ReleaseDecoderBuffer(ID3D11VideoDecoder* video_decoder,
+                               D3D11_VIDEO_DECODER_BUFFER_TYPE type) override {
+    return video_context_->ReleaseDecoderBuffer(video_decoder, type);
+  }
+
+  HRESULT DecoderEndFrame(ID3D11VideoDecoder* video_decoder) override {
+    return video_context_->DecoderEndFrame(video_decoder);
+  }
+
+  HRESULT SubmitDecoderBuffers(ID3D11VideoDecoder* video_decoder,
+                               UINT num_buffers,
+                               const VideoBufferWrapper* buffers) override {
+    return BufferSubmitter<CTX>::SubmitDecoderBuffers(
+        video_context_, video_decoder, num_buffers, buffers);
+  }
+
+ private:
+  Microsoft::WRL::ComPtr<CTX> video_context_;
+};
+
+std::unique_ptr<VideoContextWrapper> VideoContextWrapper::CreateWrapper(
+    D3D_FEATURE_LEVEL supported_d3d11_version,
+    Microsoft::WRL::ComPtr<ID3D11DeviceContext> device_context,
+    HRESULT* status) {
+  if (supported_d3d11_version == D3D_FEATURE_LEVEL_11_0) {
+    Microsoft::WRL::ComPtr<ID3D11VideoContext> video_context;
+    *status = device_context.CopyTo(video_context.ReleaseAndGetAddressOf());
+    return std::make_unique<VideoContextWrapperImpl<ID3D11VideoContext>>(
+        video_context);
+  }
+
+  if (supported_d3d11_version == D3D_FEATURE_LEVEL_11_1) {
+    Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context;
+    *status = device_context.CopyTo(video_context.ReleaseAndGetAddressOf());
+    return std::make_unique<VideoContextWrapperImpl<ID3D11VideoContext1>>(
+        video_context);
+  }
+
+  *status = E_FAIL;
+  return nullptr;
+}
+
+}  // namespace media
diff --git a/media/gpu/windows/d3d11_video_context_wrapper.h b/media/gpu/windows/d3d11_video_context_wrapper.h
new file mode 100644
index 0000000..71649aac
--- /dev/null
+++ b/media/gpu/windows/d3d11_video_context_wrapper.h
@@ -0,0 +1,81 @@
+// Copyright 2018 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_WINDOWS_D3D11_VIDEO_CONTEXT_WRAPPER_H_
+#define MEDIA_GPU_WINDOWS_D3D11_VIDEO_CONTEXT_WRAPPER_H_
+
+#include <d3d11_1.h>
+#include <wrl/client.h>
+#include <memory>
+
+#include "base/macros.h"
+#include "media/gpu/media_gpu_export.h"
+
+namespace media {
+
+class MEDIA_GPU_EXPORT VideoContextWrapper {
+ public:
+  VideoContextWrapper() = default;
+  virtual ~VideoContextWrapper();
+  // D3D11_VIDEO_DECODER_BUFFER_DESC1 and D3D11_VIDEO_DECODER_BUFFER_DESC
+  // have radically different sets of member variables, which means that in
+  // order to have a converter class, we need to support all fields. They are
+  // also in different orders, which prevents using a simple memcpy.
+  // It seems we don't currently use any of the D3D11_VIDEO_DECODER_BUFFER_DESC
+  // specific fields right now.
+  // Fields are named as they appear in the D3D11 Structs.
+  struct VideoBufferWrapper {
+    // Shared Fields
+    D3D11_VIDEO_DECODER_BUFFER_TYPE BufferType;
+    UINT DataOffset;
+    UINT DataSize;
+    void* pIV;
+    UINT IVSize;
+
+    // DESC1-specific fields
+    D3D11_VIDEO_DECODER_SUB_SAMPLE_MAPPING_BLOCK* pSubSampleMappingBlock;
+    UINT SubSampleMappingCount;
+  };
+
+  static std::unique_ptr<VideoContextWrapper> CreateWrapper(
+      D3D_FEATURE_LEVEL supported_d3d11_version,
+      Microsoft::WRL::ComPtr<ID3D11DeviceContext> device_context,
+      HRESULT* status);
+
+  // This method signiture is defined to match exactly that of
+  // |ID3D11VideoContext::DecoderBeginFrame|.
+  virtual HRESULT DecoderBeginFrame(ID3D11VideoDecoder* video_decoder,
+                                    ID3D11VideoDecoderOutputView* output_view,
+                                    UINT content_key_size,
+                                    const void* content_key) = 0;
+
+  // This method signiture is defined to match exactly that of
+  // |ID3D11VideoContext::GetDecoderBuffer|.
+  virtual HRESULT GetDecoderBuffer(ID3D11VideoDecoder* video_decoder,
+                                   D3D11_VIDEO_DECODER_BUFFER_TYPE type,
+                                   UINT* buffer_size,
+                                   void** buffer) = 0;
+
+  // This method signiture is defined to match exactly that of
+  // |ID3D11VideoContext::ReleaseDecoderBuffer|.
+  virtual HRESULT ReleaseDecoderBuffer(
+      ID3D11VideoDecoder* video_decoder,
+      D3D11_VIDEO_DECODER_BUFFER_TYPE type) = 0;
+
+  // This method signiture is defined to match exactly that of
+  // |ID3D11VideoContext::DecoderEndFrame|.
+  virtual HRESULT DecoderEndFrame(ID3D11VideoDecoder* video_decoder) = 0;
+
+  // This method signiture is defined to match exactly that of
+  // |ID3D11VideoContext::SubmitDecoderBuffers|.
+  virtual HRESULT SubmitDecoderBuffers(ID3D11VideoDecoder* video_decoder,
+                                       UINT num_buffers,
+                                       const VideoBufferWrapper* buffers) = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(VideoContextWrapper);
+};  // VideoContextWrapper
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_WINDOWS_D3D11_VIDEO_CONTEXT_WRAPPER_H_
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc
index 5d63543..857d0c06 100644
--- a/media/gpu/windows/d3d11_video_decoder.cc
+++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -21,6 +21,7 @@
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
 #include "media/gpu/windows/d3d11_picture_buffer.h"
+#include "media/gpu/windows/d3d11_video_context_wrapper.h"
 #include "media/gpu/windows/d3d11_video_decoder_impl.h"
 #include "ui/gl/gl_angle_util_win.h"
 
@@ -108,30 +109,41 @@
   return "D3D11VideoDecoder";
 }
 
-void D3D11VideoDecoder::InitializeAcceleratedDecoder(
+HRESULT D3D11VideoDecoder::InitializeAcceleratedDecoder(
     const VideoDecoderConfig& config,
     CdmProxyContext* proxy_context,
     Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder) {
+  // If we got an 11.1 D3D11 Device, we can use a |ID3D11VideoContext1|,
+  // otherwise we have to make sure we only use a |ID3D11VideoContext|.
+  HRESULT hr;
+
+  // |device_context_| is the primary display context, but currently
+  // we share it for decoding purposes.
+  auto video_context = VideoContextWrapper::CreateWrapper(usable_feature_level_,
+                                                          device_context_, &hr);
+
+  if (!SUCCEEDED(hr))
+    return hr;
+
   if (IsVP9(config)) {
     accelerated_video_decoder_ = std::make_unique<VP9Decoder>(
-        std::make_unique<D3D11VP9Accelerator>(this, media_log_.get(),
-                                              proxy_context, video_decoder,
-                                              video_device_, video_context_),
+        std::make_unique<D3D11VP9Accelerator>(
+            this, media_log_.get(), proxy_context, video_decoder, video_device_,
+            std::move(video_context)),
         config.color_space_info());
-    return;
+    return hr;
   }
 
   if (IsH264(config)) {
     accelerated_video_decoder_ = std::make_unique<H264Decoder>(
-        std::make_unique<D3D11H264Accelerator>(this, media_log_.get(),
-                                               proxy_context, video_decoder,
-                                               video_device_, video_context_),
+        std::make_unique<D3D11H264Accelerator>(
+            this, media_log_.get(), proxy_context, video_decoder, video_device_,
+            std::move(video_context)),
         config.color_space_info());
-    return;
+    return hr;
   }
 
-  // No other type of config should make it this far due to earlier checks.
-  NOTREACHED();
+  return E_FAIL;
 }
 
 bool D3D11VideoDecoder::DeviceHasDecoderID(GUID decoder_guid) {
@@ -203,11 +215,6 @@
 
   // TODO(liberato): Handle cleanup better.  Also consider being less chatty in
   // the logs, since this will fall back.
-  hr = device_context_.CopyTo(video_context_.ReleaseAndGetAddressOf());
-  if (!SUCCEEDED(hr)) {
-    NotifyError("Failed to get device context");
-    return;
-  }
 
   hr = device_.CopyTo(video_device_.ReleaseAndGetAddressOf());
   if (!SUCCEEDED(hr)) {
@@ -285,7 +292,12 @@
     return;
   }
 
-  InitializeAcceleratedDecoder(config, proxy_context, video_decoder);
+  hr = InitializeAcceleratedDecoder(config, proxy_context, video_decoder);
+
+  if (!SUCCEEDED(hr)) {
+    NotifyError("Failed to get device context");
+    return;
+  }
 
   // |cdm_context| could be null for clear playback.
   // TODO(liberato): On re-init, should this still happen?
@@ -654,30 +666,17 @@
 bool D3D11VideoDecoder::IsPotentiallySupported(
     const VideoDecoderConfig& config) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
   // TODO(liberato): All of this could be moved into MojoVideoDecoder, so that
   // it could run on the client side and save the IPC hop.
 
-  if (config.is_encrypted() &&
-      !base::FeatureList::IsEnabled(kD3D11EncryptedMedia)) {
-    SetWasSupportedReason(D3D11VideoNotSupportedReason::kEncryptedMedia);
+  // Must allow zero-copy of nv12 textures.
+  if (!gpu_preferences_.enable_zero_copy_dxgi_video) {
+    SetWasSupportedReason(D3D11VideoNotSupportedReason::kZeroCopyNv12Required);
     return false;
   }
 
-  // TODO(liberato): It would be nice to QueryD3D11DeviceObjectFromANGLE, but
-  // we don't know what thread we're on.
-
-  // Make sure that we support at least 11.0.
-  D3D_FEATURE_LEVEL levels[] = {
-      D3D_FEATURE_LEVEL_11_0,
-  };
-  HRESULT hr = create_device_func_.Run(
-      nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, levels, ARRAYSIZE(levels),
-      D3D11_SDK_VERSION, nullptr, nullptr, nullptr);
-
-  if (FAILED(hr)) {
-    SetWasSupportedReason(
-        D3D11VideoNotSupportedReason::kInsufficientD3D11FeatureLevel);
+  if (gpu_workarounds_.disable_dxgi_zero_copy_video) {
+    SetWasSupportedReason(D3D11VideoNotSupportedReason::kZeroCopyVideoRequired);
     return false;
   }
 
@@ -692,6 +691,13 @@
     return false;
   }
 
+  bool encrypted_stream = config.is_encrypted();
+
+  if (encrypted_stream && !base::FeatureList::IsEnabled(kD3D11EncryptedMedia)) {
+    SetWasSupportedReason(D3D11VideoNotSupportedReason::kEncryptedMedia);
+    return false;
+  }
+
   // Converts one of chromium's VideoCodecProfile options to a dxguid value.
   // If this GUID comes back empty then the profile is not supported.
   GUID decoder_GUID = GetD3D11DecoderGUID(config);
@@ -703,21 +709,33 @@
     return false;
   }
 
+  // TODO(liberato): It would be nice to QueryD3D11DeviceObjectFromANGLE, but
+  // we don't know what thread we're on.
+  D3D_FEATURE_LEVEL levels[] = {
+      D3D_FEATURE_LEVEL_11_1,  // We need 11.1 for encrypted playback,
+      D3D_FEATURE_LEVEL_11_0,  // but make sure we have at least 11.0 for clear.
+  };
+
+  // This is also the most expensive check, so make sure it is last.
+  HRESULT hr = create_device_func_.Run(
+      nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, levels, ARRAYSIZE(levels),
+      D3D11_SDK_VERSION, nullptr, &usable_feature_level_, nullptr);
+
+  if (FAILED(hr)) {
+    SetWasSupportedReason(
+        D3D11VideoNotSupportedReason::kInsufficientD3D11FeatureLevel);
+    return false;
+  }
+
+  if (encrypted_stream && usable_feature_level_ == D3D_FEATURE_LEVEL_11_0) {
+    SetWasSupportedReason(
+        D3D11VideoNotSupportedReason::kInsufficientD3D11FeatureLevel);
+    return false;
+  }
+
   // TODO(liberato): dxva checks IsHDR() in the target colorspace, but we don't
   // have the target colorspace.  It's commented as being for vpx, though, so
   // we skip it here for now.
-
-  // Must allow zero-copy of nv12 textures.
-  if (!gpu_preferences_.enable_zero_copy_dxgi_video) {
-    SetWasSupportedReason(D3D11VideoNotSupportedReason::kZeroCopyNv12Required);
-    return false;
-  }
-
-  if (gpu_workarounds_.disable_dxgi_zero_copy_video) {
-    SetWasSupportedReason(D3D11VideoNotSupportedReason::kZeroCopyVideoRequired);
-    return false;
-  }
-
   SetWasSupportedReason(D3D11VideoNotSupportedReason::kVideoIsSupported);
   return true;
 }
diff --git a/media/gpu/windows/d3d11_video_decoder.h b/media/gpu/windows/d3d11_video_decoder.h
index 5f601af..6c41a95 100644
--- a/media/gpu/windows/d3d11_video_decoder.h
+++ b/media/gpu/windows/d3d11_video_decoder.h
@@ -103,7 +103,7 @@
   void DoDecode();
 
   // instantiate |accelerated_video_decoder_| based on the video profile
-  void InitializeAcceleratedDecoder(
+  HRESULT InitializeAcceleratedDecoder(
       const VideoDecoderConfig& config,
       CdmProxyContext* proxy_context,
       Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder);
@@ -198,7 +198,8 @@
   Microsoft::WRL::ComPtr<ID3D11Device> device_;
   Microsoft::WRL::ComPtr<ID3D11DeviceContext> device_context_;
   Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device_;
-  Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context_;
+
+  D3D_FEATURE_LEVEL usable_feature_level_;
 
   std::unique_ptr<AcceleratedVideoDecoder> accelerated_video_decoder_;
 
diff --git a/media/gpu/windows/d3d11_vp9_accelerator.cc b/media/gpu/windows/d3d11_vp9_accelerator.cc
index 6844b38..be087ab 100644
--- a/media/gpu/windows/d3d11_vp9_accelerator.cc
+++ b/media/gpu/windows/d3d11_vp9_accelerator.cc
@@ -40,7 +40,7 @@
     CdmProxyContext* cdm_proxy_context,
     Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder,
     Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device,
-    Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context)
+    std::unique_ptr<VideoContextWrapper> video_context)
     : client_(client),
       media_log_(media_log),
       cdm_proxy_context_(cdm_proxy_context),
@@ -315,7 +315,7 @@
     RELEASE_BUFFER(D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL);
 
     constexpr int buffers_count = 3;
-    D3D11_VIDEO_DECODER_BUFFER_DESC1 buffers[buffers_count] = {};
+    VideoContextWrapper::VideoBufferWrapper buffers[buffers_count] = {};
     buffers[0].BufferType = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
     buffers[0].DataOffset = 0;
     buffers[0].DataSize = sizeof(pic_params);
@@ -338,8 +338,8 @@
       }
     }
 
-    RETURN_ON_HR_FAILURE(SubmitDecoderBuffers1,
-                         video_context_->SubmitDecoderBuffers1(
+    RETURN_ON_HR_FAILURE(SubmitDecoderBuffers,
+                         video_context_->SubmitDecoderBuffers(
                              video_decoder_.Get(), buffers_count, buffers));
     buffer_offset += copy_size;
   }
diff --git a/media/gpu/windows/d3d11_vp9_accelerator.h b/media/gpu/windows/d3d11_vp9_accelerator.h
index 9a2a0f8..9fbfce5 100644
--- a/media/gpu/windows/d3d11_vp9_accelerator.h
+++ b/media/gpu/windows/d3d11_vp9_accelerator.h
@@ -12,6 +12,7 @@
 
 #include "media/base/media_log.h"
 #include "media/gpu/vp9_decoder.h"
+#include "media/gpu/windows/d3d11_video_context_wrapper.h"
 #include "media/gpu/windows/d3d11_video_decoder_client.h"
 #include "media/gpu/windows/d3d11_vp9_picture.h"
 
@@ -20,13 +21,12 @@
 
 class D3D11VP9Accelerator : public VP9Decoder::VP9Accelerator {
  public:
-  D3D11VP9Accelerator(
-      D3D11VideoDecoderClient* client,
-      MediaLog* media_log,
-      CdmProxyContext* cdm_proxy_context,
-      Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder,
-      Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device,
-      Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context);
+  D3D11VP9Accelerator(D3D11VideoDecoderClient* client,
+                      MediaLog* media_log,
+                      CdmProxyContext* cdm_proxy_context,
+                      Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder,
+                      Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device,
+                      std::unique_ptr<VideoContextWrapper> video_context);
   ~D3D11VP9Accelerator() override;
 
   scoped_refptr<VP9Picture> CreateVP9Picture() override;
@@ -78,7 +78,7 @@
   UINT status_feedback_;
   Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder_;
   Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device_;
-  Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context_;
+  std::unique_ptr<VideoContextWrapper> video_context_;
 
   DISALLOW_COPY_AND_ASSIGN(D3D11VP9Accelerator);
 };
diff --git a/media/mojo/interfaces/video_decoder_config_struct_traits.cc b/media/mojo/interfaces/video_decoder_config_struct_traits.cc
index 096b5c4..ee076d7a 100644
--- a/media/mojo/interfaces/video_decoder_config_struct_traits.cc
+++ b/media/mojo/interfaces/video_decoder_config_struct_traits.cc
@@ -23,8 +23,6 @@
   if (!input.ReadFormat(&format))
     return false;
 
-  media::ColorSpace color_space = media::ColorSpace::COLOR_SPACE_UNSPECIFIED;
-
   media::VideoRotation rotation;
   if (!input.ReadVideoRotation(&rotation))
     return false;
@@ -49,8 +47,8 @@
   if (!input.ReadEncryptionScheme(&encryption_scheme))
     return false;
 
-  media::VideoColorSpace color_space_info;
-  if (!input.ReadColorSpaceInfo(&color_space_info))
+  media::VideoColorSpace color_space;
+  if (!input.ReadColorSpaceInfo(&color_space))
     return false;
 
   base::Optional<media::HDRMetadata> hdr_metadata;
@@ -60,8 +58,6 @@
   output->Initialize(codec, profile, format, color_space, rotation, coded_size,
                      visible_rect, natural_size, extra_data, encryption_scheme);
 
-  output->set_color_space_info(color_space_info);
-
   if (hdr_metadata)
     output->set_hdr_metadata(hdr_metadata.value());
 
diff --git a/media/mojo/interfaces/video_decoder_config_struct_traits_unittest.cc b/media/mojo/interfaces/video_decoder_config_struct_traits_unittest.cc
index a337d0e..fde934c5 100644
--- a/media/mojo/interfaces/video_decoder_config_struct_traits_unittest.cc
+++ b/media/mojo/interfaces/video_decoder_config_struct_traits_unittest.cc
@@ -26,9 +26,9 @@
   const std::vector<uint8_t> kExtraDataVector(
       &kExtraData[0], &kExtraData[0] + arraysize(kExtraData));
   VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
-                           COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                           kCodedSize, kVisibleRect, kNaturalSize,
-                           kExtraDataVector, Unencrypted());
+                           VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                           kVisibleRect, kNaturalSize, kExtraDataVector,
+                           Unencrypted());
   std::vector<uint8_t> data =
       media::mojom::VideoDecoderConfig::Serialize(&input);
   VideoDecoderConfig output;
@@ -40,9 +40,9 @@
 TEST(VideoDecoderConfigStructTraitsTest,
      ConvertVideoDecoderConfig_EmptyExtraData) {
   VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
-                           COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                           kCodedSize, kVisibleRect, kNaturalSize,
-                           EmptyExtraData(), Unencrypted());
+                           VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                           kVisibleRect, kNaturalSize, EmptyExtraData(),
+                           Unencrypted());
   std::vector<uint8_t> data =
       media::mojom::VideoDecoderConfig::Serialize(&input);
   VideoDecoderConfig output;
@@ -53,9 +53,9 @@
 
 TEST(VideoDecoderConfigStructTraitsTest, ConvertVideoDecoderConfig_Encrypted) {
   VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
-                           COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                           kCodedSize, kVisibleRect, kNaturalSize,
-                           EmptyExtraData(), AesCtrEncryptionScheme());
+                           VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                           kVisibleRect, kNaturalSize, EmptyExtraData(),
+                           AesCtrEncryptionScheme());
   std::vector<uint8_t> data =
       media::mojom::VideoDecoderConfig::Serialize(&input);
   VideoDecoderConfig output;
@@ -66,14 +66,14 @@
 
 TEST(VideoDecoderConfigStructTraitsTest,
      ConvertVideoDecoderConfig_ColorSpaceInfo) {
-  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
-                           COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                           kCodedSize, kVisibleRect, kNaturalSize,
-                           EmptyExtraData(), Unencrypted());
-  input.set_color_space_info(VideoColorSpace(
-      VideoColorSpace::PrimaryID::BT2020,
-      VideoColorSpace::TransferID::SMPTEST2084,
-      VideoColorSpace::MatrixID::BT2020_CL, gfx::ColorSpace::RangeID::LIMITED));
+  VideoDecoderConfig input(
+      kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
+      VideoColorSpace(VideoColorSpace::PrimaryID::BT2020,
+                      VideoColorSpace::TransferID::SMPTEST2084,
+                      VideoColorSpace::MatrixID::BT2020_CL,
+                      gfx::ColorSpace::RangeID::LIMITED),
+      VIDEO_ROTATION_0, kCodedSize, kVisibleRect, kNaturalSize,
+      EmptyExtraData(), Unencrypted());
   std::vector<uint8_t> data =
       media::mojom::VideoDecoderConfig::Serialize(&input);
   VideoDecoderConfig output;
@@ -85,9 +85,9 @@
 TEST(VideoDecoderConfigStructTraitsTest,
      ConvertVideoDecoderConfig_HDRMetadata) {
   VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
-                           COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
-                           kCodedSize, kVisibleRect, kNaturalSize,
-                           EmptyExtraData(), Unencrypted());
+                           VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
+                           kVisibleRect, kNaturalSize, EmptyExtraData(),
+                           Unencrypted());
   HDRMetadata hdr_metadata;
   hdr_metadata.max_frame_average_light_level = 123;
   hdr_metadata.max_content_light_level = 456;
@@ -127,7 +127,7 @@
   // Next try an non-empty invalid config. Natural size must not be zero.
   const gfx::Size kInvalidNaturalSize(0, 0);
   input.Initialize(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
-                   COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0, kCodedSize,
+                   VideoColorSpace(), VIDEO_ROTATION_0, kCodedSize,
                    kVisibleRect, kInvalidNaturalSize, EmptyExtraData(),
                    Unencrypted());
   EXPECT_FALSE(input.IsValidConfig());
diff --git a/media/remoting/fake_media_resource.cc b/media/remoting/fake_media_resource.cc
index dd31150..7fb2baff 100644
--- a/media/remoting/fake_media_resource.cc
+++ b/media/remoting/fake_media_resource.cc
@@ -28,7 +28,7 @@
     gfx::Size size(640, 480);
     gfx::Rect rect(0, 0, 640, 480);
     video_config_.Initialize(kCodecH264, H264PROFILE_BASELINE,
-                             PIXEL_FORMAT_I420, COLOR_SPACE_SD_REC601,
+                             PIXEL_FORMAT_I420, VideoColorSpace::REC601(),
                              VIDEO_ROTATION_0, size, rect, size,
                              std::vector<uint8_t>(), Unencrypted());
   }
diff --git a/media/remoting/proto_utils.cc b/media/remoting/proto_utils.cc
index ad7cfb4..d08f4e2 100644
--- a/media/remoting/proto_utils.cc
+++ b/media/remoting/proto_utils.cc
@@ -363,11 +363,27 @@
     VideoDecoderConfig* video_config) {
   DCHECK(video_config);
   EncryptionScheme encryption_scheme;
+
+  // TODO(hubbe): Update pb to use VideoColorSpace
+  VideoColorSpace color_space;
+  switch (video_message.color_space()) {
+    case pb::VideoDecoderConfig::COLOR_SPACE_UNSPECIFIED:
+      break;
+    case pb::VideoDecoderConfig::COLOR_SPACE_JPEG:
+      color_space = VideoColorSpace::JPEG();
+      break;
+    case pb::VideoDecoderConfig::COLOR_SPACE_HD_REC709:
+      color_space = VideoColorSpace::REC709();
+      break;
+    case pb::VideoDecoderConfig::COLOR_SPACE_SD_REC601:
+      color_space = VideoColorSpace::REC601();
+      break;
+  }
   video_config->Initialize(
       ToMediaVideoCodec(video_message.codec()).value(),
       ToMediaVideoCodecProfile(video_message.profile()).value(),
-      ToMediaVideoPixelFormat(video_message.format()).value(),
-      ToMediaColorSpace(video_message.color_space()).value(), VIDEO_ROTATION_0,
+      ToMediaVideoPixelFormat(video_message.format()).value(), color_space,
+      VIDEO_ROTATION_0,
       gfx::Size(video_message.coded_size().width(),
                 video_message.coded_size().height()),
       gfx::Rect(video_message.visible_rect().x(),
diff --git a/media/renderers/default_decoder_factory.cc b/media/renderers/default_decoder_factory.cc
index 634ea6c..56877e23 100644
--- a/media/renderers/default_decoder_factory.cc
+++ b/media/renderers/default_decoder_factory.cc
@@ -23,6 +23,10 @@
 #include "media/filters/decrypting_video_decoder.h"
 #endif
 
+#if defined(OS_FUCHSIA)
+#include "media/filters/fuchsia/fuchsia_video_decoder.h"
+#endif
+
 #if BUILDFLAG(ENABLE_AV1_DECODER)
 #include "media/filters/aom_video_decoder.h"
 #endif
@@ -107,6 +111,10 @@
     }
   }
 
+#if defined(OS_FUCHSIA)
+  video_decoders->push_back(CreateFuchsiaVideoDecoder());
+#endif
+
 #if BUILDFLAG(ENABLE_LIBVPX)
   video_decoders->push_back(std::make_unique<OffloadingVpxVideoDecoder>());
 #endif
diff --git a/mojo/core/BUILD.gn b/mojo/core/BUILD.gn
index ce271ed7..2515e87 100644
--- a/mojo/core/BUILD.gn
+++ b/mojo/core/BUILD.gn
@@ -233,6 +233,9 @@
   }
 
   config("export_only_thunks_api") {
+    inputs = [
+      "export_only_thunks_api.lst",
+    ]
     ldflags = [ "-Wl,--version-script=" +
                 rebase_path("//mojo/core/export_only_thunks_api.lst",
                             root_build_dir) ]
@@ -249,6 +252,8 @@
         "//base",
         "//base/test:test_support",
         "//mojo/public/c/system",
+        "//mojo/public/cpp/platform",
+        "//mojo/public/cpp/system",
         "//testing/gtest",
       ]
 
diff --git a/mojo/core/entrypoints.cc b/mojo/core/entrypoints.cc
index 42e74171..466da7e 100644
--- a/mojo/core/entrypoints.cc
+++ b/mojo/core/entrypoints.cc
@@ -21,8 +21,8 @@
 extern "C" {
 
 MojoResult MojoInitializeImpl(const struct MojoInitializeOptions* options) {
-  NOTREACHED() << "Do not call MojoInitialize() as an EDK embedder!";
-  return MOJO_RESULT_OK;
+  NOTREACHED() << "Do not call MojoInitialize() as a Mojo Core embedder!";
+  return MOJO_RESULT_UNIMPLEMENTED;
 }
 
 MojoTimeTicks MojoGetTimeTicksNowImpl() {
@@ -345,6 +345,11 @@
                             current_usage);
 }
 
+MojoResult MojoShutdownImpl(const MojoShutdownOptions* options) {
+  NOTREACHED() << "Do not call MojoShutdown() as a Mojo Core embedder!";
+  return MOJO_RESULT_UNIMPLEMENTED;
+}
+
 }  // extern "C"
 
 MojoSystemThunks g_thunks = {sizeof(MojoSystemThunks),
@@ -390,7 +395,8 @@
                              MojoSendInvitationImpl,
                              MojoAcceptInvitationImpl,
                              MojoSetQuotaImpl,
-                             MojoQueryQuotaImpl};
+                             MojoQueryQuotaImpl,
+                             MojoShutdownImpl};
 
 }  // namespace
 
diff --git a/mojo/core/mojo_core.cc b/mojo/core/mojo_core.cc
index 9823b201..38ddc063 100644
--- a/mojo/core/mojo_core.cc
+++ b/mojo/core/mojo_core.cc
@@ -2,18 +2,85 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stddef.h>
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/no_destructor.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
 #include "base/time/time.h"
+#include "mojo/core/configuration.h"
 #include "mojo/core/core.h"
 #include "mojo/core/entrypoints.h"
 #include "mojo/public/c/system/core.h"
 #include "mojo/public/c/system/thunks.h"
 
+namespace {
+
+class IPCSupport {
+ public:
+  IPCSupport() : ipc_thread_("Mojo IPC") {
+    base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
+    ipc_thread_.StartWithOptions(options);
+    mojo::core::Core::Get()->SetIOTaskRunner(ipc_thread_.task_runner());
+  }
+
+  ~IPCSupport() {
+    base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
+                             base::WaitableEvent::InitialState::NOT_SIGNALED);
+    mojo::core::Core::Get()->RequestShutdown(base::BindRepeating(
+        &base::WaitableEvent::Signal, base::Unretained(&wait)));
+    wait.Wait();
+  }
+
+ private:
+#if !defined(COMPONENT_BUILD)
+  // NOTE: For component builds, we assume the consumer is always a target in
+  // the Chromium tree which already depends on base initialization stuff and
+  // therefore already has an AtExitManager. For non-component builds, use of
+  // this AtExitManager is strictly isolated to Mojo Core internals, so running
+  // hooks on |MojoShutdown()| (where |this| is destroyed) makes sense.
+  base::AtExitManager at_exit_manager_;
+#endif  // !defined(COMPONENT_BUILD)
+
+  base::Thread ipc_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(IPCSupport);
+};
+
+std::unique_ptr<IPCSupport>& GetIPCSupport() {
+  static base::NoDestructor<std::unique_ptr<IPCSupport>> state;
+  return *state;
+}
+
+}  // namespace
+
 extern "C" {
 
 namespace {
 
 MojoResult InitializeImpl(const struct MojoInitializeOptions* options) {
+  mojo::core::Configuration config;
+  config.is_broker_process =
+      options && options->flags & MOJO_INITIALIZE_FLAG_AS_BROKER;
+  mojo::core::internal::g_configuration = config;
+
   mojo::core::InitializeCore();
+  GetIPCSupport() = std::make_unique<IPCSupport>();
+  return MOJO_RESULT_OK;
+}
+
+MojoResult ShutdownImpl(const struct MojoShutdownOptions* options) {
+  if (options && options->struct_size < sizeof(*options))
+    return MOJO_RESULT_INVALID_ARGUMENT;
+
+  std::unique_ptr<IPCSupport>& ipc_support = GetIPCSupport();
+  if (!ipc_support)
+    return MOJO_RESULT_FAILED_PRECONDITION;
+
+  ipc_support.reset();
   return MOJO_RESULT_OK;
 }
 
@@ -31,12 +98,19 @@
   if (!g_thunks.size) {
     g_thunks = mojo::core::GetSystemThunks();
     g_thunks.Initialize = InitializeImpl;
+    g_thunks.Shutdown = ShutdownImpl;
   }
 
-  // Since this is the first version of the library, no valid system API
-  // implementation can request fewer thunks than we have available.
-  CHECK_GE(thunks->size, g_thunks.size);
-  memcpy(thunks, &g_thunks, g_thunks.size);
+  // Caller must provide a thunk structure at least large enough to hold Core
+  // ABI version 0. SetQuota is the first function introduced in ABI version 1.
+  CHECK_GE(thunks->size, offsetof(MojoSystemThunks, SetQuota));
+
+  // NOTE: This also overrites |thunks->size| with the actual size of our own
+  // thunks if smaller than the caller's. This informs the caller that we
+  // implement an older version of the ABI.
+  if (thunks->size > g_thunks.size)
+    thunks->size = g_thunks.size;
+  memcpy(thunks, &g_thunks, thunks->size);
 }
 
 }  // extern "C"
diff --git a/mojo/core/mojo_core_unittest.cc b/mojo/core/mojo_core_unittest.cc
index 8428e098..5f54637 100644
--- a/mojo/core/mojo_core_unittest.cc
+++ b/mojo/core/mojo_core_unittest.cc
@@ -2,11 +2,36 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/process/launch.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
 #include "mojo/public/c/system/core.h"
+#include "mojo/public/cpp/platform/platform_channel.h"
+#include "mojo/public/cpp/platform/platform_handle.h"
+#include "mojo/public/cpp/system/invitation.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "mojo/public/cpp/system/wait.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
 
 namespace {
 
+uint64_t kTestPipeName = 0;
+const char kTestMessage[] = "hai";
+const char kTestReply[] = "bai";
+
+std::string ReadMessageAsString(mojo::MessagePipeHandle handle) {
+  std::vector<uint8_t> data;
+  CHECK_EQ(MOJO_RESULT_OK, mojo::ReadMessageRaw(handle, &data, nullptr,
+                                                MOJO_READ_MESSAGE_FLAG_NONE));
+  return std::string(data.begin(), data.end());
+}
+
 TEST(MojoCoreTest, SanityCheck) {
   // Exercises some APIs against the mojo_core library and expects them to work
   // as intended.
@@ -36,4 +61,47 @@
   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
 }
 
+TEST(MojoCoreTest, BasicMultiprocess) {
+  base::CommandLine child_cmd(base::GetMultiProcessTestChildBaseCommandLine());
+  base::LaunchOptions options;
+
+  mojo::PlatformChannel channel;
+  channel.PrepareToPassRemoteEndpoint(&options, &child_cmd);
+  base::Process child_process = base::SpawnMultiProcessTestChild(
+      "BasicMultiprocessClientMain", child_cmd, options);
+  channel.RemoteProcessLaunchAttempted();
+
+  mojo::OutgoingInvitation invitation;
+  auto child_pipe = invitation.AttachMessagePipe(kTestPipeName);
+  mojo::OutgoingInvitation::Send(std::move(invitation), child_process.Handle(),
+                                 channel.TakeLocalEndpoint());
+
+  mojo::Wait(child_pipe.get(), MOJO_HANDLE_SIGNAL_READABLE);
+  EXPECT_EQ(kTestMessage, ReadMessageAsString(child_pipe.get()));
+
+  mojo::WriteMessageRaw(child_pipe.get(), kTestReply, sizeof(kTestReply) - 1,
+                        nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
+
+  int rv = -1;
+  ASSERT_TRUE(base::WaitForMultiprocessTestChildExit(
+      child_process, TestTimeouts::action_timeout(), &rv));
+  EXPECT_EQ(0, rv);
+}
+
+MULTIPROCESS_TEST_MAIN(BasicMultiprocessClientMain) {
+  auto endpoint = mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(
+      *base::CommandLine::ForCurrentProcess());
+  auto invitation = mojo::IncomingInvitation::Accept(std::move(endpoint));
+  auto parent_pipe = invitation.ExtractMessagePipe(kTestPipeName);
+
+  mojo::WriteMessageRaw(parent_pipe.get(), kTestMessage,
+                        sizeof(kTestMessage) - 1, nullptr, 0,
+                        MOJO_WRITE_MESSAGE_FLAG_NONE);
+
+  mojo::Wait(parent_pipe.get(), MOJO_HANDLE_SIGNAL_READABLE);
+  EXPECT_EQ(kTestReply, ReadMessageAsString(parent_pipe.get()));
+
+  return 0;
+}
+
 }  // namespace
diff --git a/mojo/core/run_all_core_unittests.cc b/mojo/core/run_all_core_unittests.cc
index 92dcafc9..18b119e 100644
--- a/mojo/core/run_all_core_unittests.cc
+++ b/mojo/core/run_all_core_unittests.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/base_switches.h"
 #include "base/bind.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
@@ -11,8 +12,21 @@
 int main(int argc, char** argv) {
   base::TestSuite test_suite(argc, argv);
 
-  CHECK_EQ(MOJO_RESULT_OK, MojoInitialize(nullptr));
-  return base::LaunchUnitTests(
+  MojoInitializeOptions options;
+  options.struct_size = sizeof(options);
+  options.flags = MOJO_INITIALIZE_FLAG_NONE;
+  options.mojo_core_path = NULL;
+  options.mojo_core_path_length = 0;
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTestChildProcess)) {
+    options.flags = MOJO_INITIALIZE_FLAG_AS_BROKER;
+  }
+
+  CHECK_EQ(MOJO_RESULT_OK, MojoInitialize(&options));
+  int result = base::LaunchUnitTests(
       argc, argv,
       base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
+
+  CHECK_EQ(MOJO_RESULT_OK, MojoShutdown(nullptr));
+  return result;
 }
diff --git a/mojo/public/c/system/functions.h b/mojo/public/c/system/functions.h
index 9f90c38..6f47028f4 100644
--- a/mojo/public/c/system/functions.h
+++ b/mojo/public/c/system/functions.h
@@ -27,14 +27,34 @@
 // |options| may be null.
 //
 // Returns:
-//   |MOJO_RESULT_OK| if Mojo intiailization was successful.
-//   |MOJO_RESULT_INVALID_ARGUMENT| if |options| was null or invalid.
+//   |MOJO_RESULT_OK| if Mojo initialization was successful.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if |options| was non-null and invalid.
 //   |MOJO_RESULT_FAILED_PRECONDITION| if |MojoInitialize()| was already called
 //       once or if the application already explicitly initialized a Mojo Core
 //       environment as an embedder.
 MOJO_SYSTEM_EXPORT MojoResult
 MojoInitialize(const struct MojoInitializeOptions* options);
 
+// Shuts down Mojo in the calling application.
+//
+// This should only be called if |MojoInitialize()| was also called at some
+// point in the calling process. It therefore only applies to consumers of Mojo
+// as a shared library, not Mojo Core embedders.
+//
+// |options| may be null.
+//
+// NOTE: It is NOT safe to attempt to call |MojoInitialize()| again (or any
+// other Mojo APIs, for that matter) after calling |MojoShutdown()|.
+//
+// Returns:
+//   |MOJO_RESULT_OK| if shutdown was successful.
+//   |MOJO_RESULT_INVALID_ARGUMENT| if |options| was non-null and invalid.
+//   |MOJO_RESULT_FAILED_PRECONDITION| if |MojoInitialize()| was never called.
+//   |MOJO_RESULT_UNIMPLEMENTED| if the caller is a Mojo Core embedder and is
+//       therefore not loading Mojo Core as a shared library.
+MOJO_SYSTEM_EXPORT MojoResult
+MojoShutdown(const struct MojoShutdownOptions* options);
+
 // Returns the time, in microseconds, since some undefined point in the past.
 // The values are only meaningful relative to other values that were obtained
 // from the same device without an intervening system restart. Such values are
diff --git a/mojo/public/c/system/tests/core_unittest_pure_c.c b/mojo/public/c/system/tests/core_unittest_pure_c.c
index 48b3c1a3..c8fd65b2 100644
--- a/mojo/public/c/system/tests/core_unittest_pure_c.c
+++ b/mojo/public/c/system/tests/core_unittest_pure_c.c
@@ -14,6 +14,7 @@
 // core.h, since it's the most important one.
 #include "mojo/public/c/system/core.h"
 #include "mojo/public/c/system/macros.h"
+#include "mojo/public/c/system/thunks.h"
 
 // The joys of the C preprocessor....
 #define STRINGIFY(x) #x
diff --git a/mojo/public/c/system/thunks.cc b/mojo/public/c/system/thunks.cc
index cffef2c..60a9128 100644
--- a/mojo/public/c/system/thunks.cc
+++ b/mojo/public/c/system/thunks.cc
@@ -92,8 +92,21 @@
       library_path.emplace(kDefaultLibraryPathValue);
     }
 
+    // NOTE: |prefer_own_symbols| on POSIX implies that the library is loaded
+    // with RTLD_DEEPBIND, which is critical given that libmojo_core.so links
+    // against base's allocator shim. Essentially, this ensures that mojo_core
+    // internals get their own heap, and this is OK since heap pointer ownership
+    // is never passed across the ABI boundary.
     base::ScopedAllowBlocking allow_blocking;
-    library_.emplace(*library_path);
+    base::NativeLibraryOptions library_options;
+#if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) && \
+    !defined(MEMORY_SANITIZER) && !defined(LEAK_SANITIZER)
+    // Sanitizer builds cannnot support RTLD_DEEPBIND, but they also disable
+    // allocator shims, so it's unnecessary there.
+    library_options.prefer_own_symbols = true;
+#endif
+    library_.emplace(base::LoadNativeLibraryWithOptions(
+        *library_path, library_options, nullptr));
     if (!application_provided_path) {
       CHECK(library_->is_valid())
           << "Unable to load the mojo_core library. Make sure the library is "
@@ -468,6 +481,10 @@
   return INVOKE_THUNK(QueryQuota, handle, type, options, limit, usage);
 }
 
+MojoResult MojoShutdown(const MojoShutdownOptions* options) {
+  return INVOKE_THUNK(Shutdown, options);
+}
+
 }  // extern "C"
 
 void MojoEmbedderSetSystemThunks(const MojoSystemThunks* thunks) {
diff --git a/mojo/public/c/system/thunks.h b/mojo/public/c/system/thunks.h
index 1e5e2493..f3f9742a 100644
--- a/mojo/public/c/system/thunks.h
+++ b/mojo/public/c/system/thunks.h
@@ -166,7 +166,7 @@
       MojoHandle* mojo_handle);
   MojoResult (*UnwrapPlatformHandle)(
       MojoHandle mojo_handle,
-      const MojoUnwrapPlatformHandleOptions* options,
+      const struct MojoUnwrapPlatformHandleOptions* options,
       struct MojoPlatformHandle* platform_handle);
   MojoResult (*WrapPlatformSharedMemoryRegion)(
       const struct MojoPlatformHandle* platform_handles,
@@ -193,13 +193,13 @@
       MojoHandle invitation_handle,
       const void* name,
       uint32_t name_num_bytes,
-      const MojoAttachMessagePipeToInvitationOptions* options,
+      const struct MojoAttachMessagePipeToInvitationOptions* options,
       MojoHandle* message_pipe_handle);
   MojoResult (*ExtractMessagePipeFromInvitation)(
       MojoHandle invitation_handle,
       const void* name,
       uint32_t name_num_bytes,
-      const MojoExtractMessagePipeFromInvitationOptions* options,
+      const struct MojoExtractMessagePipeFromInvitationOptions* options,
       MojoHandle* message_pipe_handle);
   MojoResult (*SendInvitation)(
       MojoHandle invitation_handle,
@@ -212,6 +212,9 @@
       const struct MojoInvitationTransportEndpoint* transport_endpoint,
       const struct MojoAcceptInvitationOptions* options,
       MojoHandle* invitation_handle);
+
+  // Core ABI version 1 additions begin here.
+
   MojoResult (*SetQuota)(MojoHandle handle,
                          MojoQuotaType type,
                          uint64_t limit,
@@ -221,6 +224,10 @@
                            const struct MojoQueryQuotaOptions* options,
                            uint64_t* limit,
                            uint64_t* usage);
+
+  // Core ABI version 2 additions begin here.
+
+  MojoResult (*Shutdown)(const struct MojoShutdownOptions* options);
 };
 #pragma pack(pop)
 
diff --git a/mojo/public/c/system/types.h b/mojo/public/c/system/types.h
index 4cf566a..5575602 100644
--- a/mojo/public/c/system/types.h
+++ b/mojo/public/c/system/types.h
@@ -142,6 +142,13 @@
 // No flags.
 #define MOJO_INITIALIZE_FLAG_NONE ((MojoInitializeFlags)0)
 
+// The calling process will be initialized as the broker process for its IPC
+// network. Any connected graph of Mojo consumers must have exactly one broker
+// process. That process is always the first member of the network and it should
+// set this flag during initialization. Attempts to invite a broker process into
+// an existing network will always fail.
+#define MOJO_INITIALIZE_FLAG_AS_BROKER ((MojoInitializeFlags)1)
+
 // Options passed to |MojoInitialize()|.
 struct MOJO_ALIGNAS(8) MojoInitializeOptions {
   // The size of this structure, used for versioning.
@@ -160,6 +167,23 @@
 MOJO_STATIC_ASSERT(sizeof(MojoInitializeOptions) == 24,
                    "MojoInitializeOptions has wrong size");
 
+// Flags passed to |MojoShutdown()| via |MojoShutdownOptions|.
+typedef uint32_t MojoShutdownFlags;
+
+// No flags.
+#define MOJO_SHUTDOWN_FLAG_NONE ((MojoShutdownFlags)0)
+
+// Options passed to |MojoShutdown()|.
+struct MOJO_ALIGNAS(8) MojoShutdownOptions {
+  // The size of this structure, used for versioning.
+  uint32_t struct_size;
+
+  // See |MojoShutdownFlags|.
+  MojoShutdownFlags flags;
+};
+MOJO_STATIC_ASSERT(sizeof(MojoShutdownOptions) == 8,
+                   "MojoShutdownOptions has wrong size");
+
 // |MojoHandleSignals|: Used to specify signals that can be watched for on a
 // handle (and which can be triggered), e.g., the ability to read or write to
 // the handle.
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 53cd478..3137d96 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -732,6 +732,8 @@
       "filter/source_stream.cc",
       "filter/source_stream.h",
       "filter/source_stream_type_list.h",
+      "filter/zlib_stream_wrapper.cc",
+      "filter/zlib_stream_wrapper.h",
       "http/bidirectional_stream.cc",
       "http/bidirectional_stream.h",
       "http/bidirectional_stream_impl.cc",
@@ -4779,6 +4781,7 @@
     "filter/brotli_source_stream_unittest.cc",
     "filter/filter_source_stream_unittest.cc",
     "filter/gzip_source_stream_unittest.cc",
+    "filter/zlib_stream_wrapper_unittest.cc",
     "ftp/ftp_auth_cache_unittest.cc",
     "ftp/ftp_ctrl_response_buffer_unittest.cc",
     "ftp/ftp_directory_listing_parser_ls_unittest.cc",
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index b7ea4ac..3d041ac 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -74,8 +74,76 @@
   const char* const extensions;
 };
 
-// Order of entries in the following mapping lists matters only when the same
-// extension is shared between multiple MIME types.
+// How to use the MIME maps
+// ------------------------
+// READ THIS BEFORE MODIFYING THE MIME MAPPINGS BELOW.
+//
+// There are two hardcoded mappings from MIME types: kPrimaryMappings and
+// kSecondaryMappings.
+//
+// kPrimaryMappings:
+//
+//   Use this for mappings that are critical to the web platform.  Mappings you
+//   add to this list take priority over the underlying platform when converting
+//   from file extension -> MIME type.  Thus file extensions listed here will
+//   work consistently across platforms.
+//
+// kSecondaryMappings:
+//
+//   Use this for mappings that must exist, but can be overridden by user
+//   preferences.
+//
+// The following applies to both lists:
+//
+// * The same extension can appear multiple times in the same list under
+//   different MIME types.  Extensions that appear earlier take precedence over
+//   those that appear later.
+//
+// * A MIME type must not appear more than once in a single list.  It is valid
+//   for the same MIME type to appear in kPrimaryMappings and
+//   kSecondaryMappings.
+//
+// The MIME maps are used for three types of lookups:
+//
+// 1) MIME type -> file extension.  Implemented as
+//    GetPreferredExtensionForMimeType().
+//
+//    Sources are consulted in the following order:
+//
+//    a) As a special case application/octet-stream is mapped to nothing.  Web
+//       sites are supposed to use this MIME type to indicate that the content
+//       is opaque and shouldn't be parsed as any specific type of content.  It
+//       doesn't make sense to map this to anything.
+//
+//    b) The underlying platform.  If the operating system has a mapping from
+//       the MIME type to a file extension, then that takes priority.  The
+//       platform is assumed to represent the user's preference.
+//
+//    c) kPrimaryMappings.  Order doesn't matter since there should only be at
+//       most one entry per MIME type.
+//
+//    d) kSecondaryMappings.  Again, order doesn't matter.
+//
+// 2) File extension -> MIME type.  Implemented in GetMimeTypeFromExtension().
+//
+//    Sources are considered in the following order:
+//
+//    a) kPrimaryMappings.  Order matters here since file extensions can appear
+//       multiple times on these lists.  The first mapping in order of
+//       appearance in the list wins.
+//
+//    b) Underlying platform.
+//
+//    c) kSecondaryMappings.  Again, the order matters.
+//
+// 3) File extension -> Well known MIME type.  Implemented as
+//    GetWellKnownMimeTypeFromExtension().
+//
+//    This is similar to 2), with the exception that b) is skipped.  I.e.  Only
+//    considers the hardcoded mappings in kPrimaryMappings and
+//    kSecondaryMappings.
+
+// See comments above for details on how this list is used.
 static const MimeInfo kPrimaryMappings[] = {
     // Must precede audio/webm .
     {"video/webm", "webm"},
@@ -103,6 +171,7 @@
     {"video/ogg", "ogv,ogm"},
 };
 
+// See comments above for details on how this list is used.
 static const MimeInfo kSecondaryMappings[] = {
     // Must precede image/vnd.microsoft.icon .
     {"image/x-icon", "ico"},
diff --git a/net/base/mime_util.h b/net/base/mime_util.h
index 53c9c26..2b53c0a 100644
--- a/net/base/mime_util.h
+++ b/net/base/mime_util.h
@@ -80,11 +80,12 @@
 // this method.
 NET_EXPORT bool IsValidTopLevelMimeType(const std::string& type_string);
 
-// Get the extensions associated with the given mime type. There could be
-// multiple extensions for a given mime type, like "html,htm" for "text/html",
-// or "txt,text,html,..." for "text/*".
-// Note that we do not erase the existing elements in the the provided vector.
-// Instead, we append the result to it.
+// Get the extensions associated with the given mime type.
+//
+// There could be multiple extensions for a given mime type, like "html,htm" for
+// "text/html", or "txt,text,html,..." for "text/*".  Note that we do not erase
+// the existing elements in the the provided vector.  Instead, we append the
+// result to it.  The new extensions are returned in no particular order.
 NET_EXPORT void GetExtensionsForMimeType(
     const std::string& mime_type,
     std::vector<base::FilePath::StringType>* extensions);
diff --git a/net/base/mime_util_unittest.cc b/net/base/mime_util_unittest.cc
index f160583..04aa044 100644
--- a/net/base/mime_util_unittest.cc
+++ b/net/base/mime_util_unittest.cc
@@ -30,6 +30,8 @@
     {FILE_PATH_LITERAL("pjp"), "image/jpeg", true},
     {FILE_PATH_LITERAL("pjpeg"), "image/jpeg", true},
     {FILE_PATH_LITERAL("json"), "application/json", true},
+    {FILE_PATH_LITERAL("js"), "text/javascript", true},
+    {FILE_PATH_LITERAL("webm"), "video/webm", true},
 #if defined(OS_CHROMEOS)
     // These are test cases for testing platform mime types on Chrome OS.
     {FILE_PATH_LITERAL("epub"), "application/epub+zip", true},
@@ -55,6 +57,31 @@
   }
 }
 
+// Behavior of GetPreferredExtensionForMimeType() is dependent on the host
+// platform since the latter can override the mapping from file extensions to
+// MIME types. The tests below would only work if the platform MIME mappings
+// don't have mappings for or has an agreeing mapping for each MIME type
+// mentioned.
+TEST(MimeUtilTest, GetPreferredExtensionForMimeType) {
+  const struct {
+    const std::string mime_type;
+    const base::FilePath::StringType expected_extension;
+  } kTestCases[] = {
+      {"application/wasm", FILE_PATH_LITERAL("wasm")},      // Primary
+      {"application/javascript", FILE_PATH_LITERAL("js")},  // Secondary
+      {"text/javascript", FILE_PATH_LITERAL("js")},         // Primary
+      {"audio/webm", FILE_PATH_LITERAL("webm")},            // Primary
+      {"video/webm", FILE_PATH_LITERAL("webm")},            // Primary
+  };
+
+  for (const auto& test : kTestCases) {
+    base::FilePath::StringType extension;
+    auto rv = GetPreferredExtensionForMimeType(test.mime_type, &extension);
+    EXPECT_TRUE(rv);
+    EXPECT_EQ(test.expected_extension, extension);
+  }
+}
+
 TEST(MimeUtilTest, FileTest) {
   const struct {
     const base::FilePath::CharType* file_path;
diff --git a/net/filter/gzip_source_stream.cc b/net/filter/gzip_source_stream.cc
index 629d7b7..d3b08ca 100644
--- a/net/filter/gzip_source_stream.cc
+++ b/net/filter/gzip_source_stream.cc
@@ -4,14 +4,8 @@
 
 #include "net/filter/gzip_source_stream.h"
 
-#include <algorithm>
 #include <utility>
 
-#include "base/bind.h"
-#include "base/bit_cast.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "net/base/io_buffer.h"
 #include "third_party/zlib/zlib.h"
 
 namespace net {
@@ -21,20 +15,9 @@
 const char kDeflate[] = "DEFLATE";
 const char kGzip[] = "GZIP";
 
-// For deflate streams, if more than this many bytes have been received without
-// an error and without adding a Zlib header, assume the original stream had a
-// Zlib header. In practice, don't need nearly this much data, but since the
-// detection logic is a heuristic, best to be safe. Data is freed once it's been
-// determined whether the stream has a zlib header or not, so larger values
-// shouldn't affect memory usage, in practice.
-const int kMaxZlibHeaderSniffBytes = 1000;
-
 }  // namespace
 
-GzipSourceStream::~GzipSourceStream() {
-  if (zlib_stream_)
-    inflateEnd(zlib_stream_.get());
-}
+GzipSourceStream::~GzipSourceStream() = default;
 
 std::unique_ptr<GzipSourceStream> GzipSourceStream::Create(
     std::unique_ptr<SourceStream> upstream,
@@ -51,24 +34,12 @@
 GzipSourceStream::GzipSourceStream(std::unique_ptr<SourceStream> upstream,
                                    SourceStream::SourceType type)
     : FilterSourceStream(type, std::move(upstream)),
-      gzip_footer_bytes_left_(0),
-      input_state_(STATE_START),
-      replay_state_(STATE_COMPRESSED_BODY) {}
+      zlib_stream_(type == TYPE_DEFLATE
+                       ? ZLibStreamWrapper::SourceType::kDeflate
+                       : ZLibStreamWrapper::SourceType::kGzip) {}
 
 bool GzipSourceStream::Init() {
-  zlib_stream_.reset(new z_stream);
-  if (!zlib_stream_)
-    return false;
-  memset(zlib_stream_.get(), 0, sizeof(z_stream));
-
-  int ret;
-  if (type() == TYPE_GZIP) {
-    ret = inflateInit2(zlib_stream_.get(), -MAX_WBITS);
-  } else {
-    ret = inflateInit(zlib_stream_.get());
-  }
-  DCHECK_NE(Z_VERSION_ERROR, ret);
-  return ret == Z_OK;
+  return zlib_stream_.Init();
 }
 
 std::string GzipSourceStream::GetTypeAsString() const {
@@ -89,178 +60,9 @@
                                  int input_buffer_size,
                                  int* consumed_bytes,
                                  bool upstream_end_reached) {
-  *consumed_bytes = 0;
-  char* input_data = input_buffer->data();
-  int input_data_size = input_buffer_size;
-  int bytes_out = 0;
-  bool state_compressed_entered = false;
-  while (input_data_size > 0 && bytes_out < output_buffer_size) {
-    InputState state = input_state_;
-    switch (state) {
-      case STATE_START: {
-        if (type() == TYPE_DEFLATE) {
-          input_state_ = STATE_SNIFFING_DEFLATE_HEADER;
-          break;
-        }
-        DCHECK_LT(0, input_data_size);
-        input_state_ = STATE_GZIP_HEADER;
-        break;
-      }
-      case STATE_GZIP_HEADER: {
-        DCHECK_NE(TYPE_DEFLATE, type());
-
-        const size_t kGzipFooterBytes = 8;
-        const char* end = nullptr;
-        GZipHeader::Status status =
-            gzip_header_.ReadMore(input_data, input_data_size, &end);
-        if (status == GZipHeader::INCOMPLETE_HEADER) {
-          input_data += input_data_size;
-          input_data_size = 0;
-        } else if (status == GZipHeader::COMPLETE_HEADER) {
-          // If there is a valid header, there should also be a valid footer.
-          gzip_footer_bytes_left_ = kGzipFooterBytes;
-          int bytes_consumed = end - input_data;
-          input_data += bytes_consumed;
-          input_data_size -= bytes_consumed;
-          input_state_ = STATE_COMPRESSED_BODY;
-        } else if (status == GZipHeader::INVALID_HEADER) {
-          return ERR_CONTENT_DECODING_FAILED;
-        }
-        break;
-      }
-      case STATE_SNIFFING_DEFLATE_HEADER: {
-        DCHECK_EQ(TYPE_DEFLATE, type());
-
-        zlib_stream_.get()->next_in = bit_cast<Bytef*>(input_data);
-        zlib_stream_.get()->avail_in = input_data_size;
-        zlib_stream_.get()->next_out = bit_cast<Bytef*>(output_buffer->data());
-        zlib_stream_.get()->avail_out = output_buffer_size;
-
-        int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
-
-        // On error, try adding a zlib header and replaying the response. Note
-        // that data just received doesn't have to be replayed, since it hasn't
-        // been removed from input_data yet, only data from previous FilterData
-        // calls needs to be replayed.
-        if (ret != Z_STREAM_END && ret != Z_OK) {
-          if (!InsertZlibHeader())
-            return ERR_CONTENT_DECODING_FAILED;
-
-          input_state_ = STATE_REPLAY_DATA;
-          // |replay_state_| should still have its initial value.
-          DCHECK_EQ(STATE_COMPRESSED_BODY, replay_state_);
-          break;
-        }
-
-        int bytes_used = input_data_size - zlib_stream_.get()->avail_in;
-        bytes_out = output_buffer_size - zlib_stream_.get()->avail_out;
-        // If any bytes are output, enough total bytes have been received, or at
-        // the end of the stream, assume the response had a valid Zlib header.
-        if (bytes_out > 0 ||
-            bytes_used + replay_data_.size() >= kMaxZlibHeaderSniffBytes ||
-            ret == Z_STREAM_END) {
-          replay_data_.clear();
-          if (ret == Z_STREAM_END) {
-            input_state_ = STATE_GZIP_FOOTER;
-          } else {
-            input_state_ = STATE_COMPRESSED_BODY;
-          }
-        } else {
-          replay_data_.append(input_data, bytes_used);
-        }
-
-        input_data_size -= bytes_used;
-        input_data += bytes_used;
-        break;
-      }
-      case STATE_REPLAY_DATA: {
-        DCHECK_EQ(TYPE_DEFLATE, type());
-
-        if (replay_data_.empty()) {
-          input_state_ = replay_state_;
-          break;
-        }
-
-        // Call FilterData recursively, after updating |input_state_|, with
-        // |replay_data_|. This recursive call makes handling data from
-        // |replay_data_| and |input_buffer| much simpler than the alternative
-        // operations, though it's not pretty.
-        input_state_ = replay_state_;
-        int bytes_used;
-        scoped_refptr<IOBuffer> replay_buffer =
-            base::MakeRefCounted<WrappedIOBuffer>(replay_data_.data());
-        int result =
-            FilterData(output_buffer, output_buffer_size, replay_buffer.get(),
-                       replay_data_.size(), &bytes_used, upstream_end_reached);
-        replay_data_.erase(0, bytes_used);
-        // Back up resulting state, and return state to STATE_REPLAY_DATA.
-        replay_state_ = input_state_;
-        input_state_ = STATE_REPLAY_DATA;
-
-        // On error, or if bytes were read, just return result immediately.
-        // Could continue consuming data in the success case, but simplest not
-        // to.
-        if (result != 0)
-          return result;
-        break;
-      }
-      case STATE_COMPRESSED_BODY: {
-        DCHECK(!state_compressed_entered);
-        DCHECK_LE(0, input_data_size);
-
-        state_compressed_entered = true;
-        zlib_stream_.get()->next_in = bit_cast<Bytef*>(input_data);
-        zlib_stream_.get()->avail_in = input_data_size;
-        zlib_stream_.get()->next_out = bit_cast<Bytef*>(output_buffer->data());
-        zlib_stream_.get()->avail_out = output_buffer_size;
-
-        int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
-        if (ret != Z_STREAM_END && ret != Z_OK)
-          return ERR_CONTENT_DECODING_FAILED;
-
-        int bytes_used = input_data_size - zlib_stream_.get()->avail_in;
-        bytes_out = output_buffer_size - zlib_stream_.get()->avail_out;
-        input_data_size -= bytes_used;
-        input_data += bytes_used;
-        if (ret == Z_STREAM_END)
-          input_state_ = STATE_GZIP_FOOTER;
-        // zlib has written as much data to |output_buffer| as it could.
-        // There might still be some unconsumed data in |input_buffer| if there
-        // is no space in |output_buffer|.
-        break;
-      }
-      case STATE_GZIP_FOOTER: {
-        size_t to_read = std::min(gzip_footer_bytes_left_,
-                                  base::checked_cast<size_t>(input_data_size));
-        gzip_footer_bytes_left_ -= to_read;
-        input_data_size -= to_read;
-        input_data += to_read;
-        if (gzip_footer_bytes_left_ == 0)
-          input_state_ = STATE_IGNORING_EXTRA_BYTES;
-        break;
-      }
-      case STATE_IGNORING_EXTRA_BYTES: {
-        input_data_size = 0;
-        break;
-      }
-    }
-  }
-  *consumed_bytes = input_buffer_size - input_data_size;
-  return bytes_out;
-}
-
-bool GzipSourceStream::InsertZlibHeader() {
-  char dummy_header[] = {0x78, 0x01};
-  char dummy_output[4];
-
-  inflateReset(zlib_stream_.get());
-  zlib_stream_.get()->next_in = bit_cast<Bytef*>(&dummy_header[0]);
-  zlib_stream_.get()->avail_in = sizeof(dummy_header);
-  zlib_stream_.get()->next_out = bit_cast<Bytef*>(&dummy_output[0]);
-  zlib_stream_.get()->avail_out = sizeof(dummy_output);
-
-  int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
-  return ret == Z_OK;
+  return zlib_stream_.FilterData(output_buffer, output_buffer_size,
+                                 input_buffer, input_buffer_size,
+                                 consumed_bytes, upstream_end_reached);
 }
 
 }  // namespace net
diff --git a/net/filter/gzip_source_stream.h b/net/filter/gzip_source_stream.h
index ab554fa..bb24535 100644
--- a/net/filter/gzip_source_stream.h
+++ b/net/filter/gzip_source_stream.h
@@ -11,9 +11,7 @@
 #include "base/macros.h"
 #include "net/base/net_export.h"
 #include "net/filter/filter_source_stream.h"
-#include "net/filter/gzip_header.h"
-
-typedef struct z_stream_s z_stream;
+#include "net/filter/zlib_stream_wrapper.h"
 
 namespace net {
 
@@ -36,33 +34,6 @@
       SourceStream::SourceType type);
 
  private:
-  enum InputState {
-    // Starts processing the input stream. Checks whether the stream is valid
-    // and whether a fallback to plain data is needed.
-    STATE_START,
-    // Gzip header of the input stream is being processed.
-    STATE_GZIP_HEADER,
-    // Deflate responses may or may not have a zlib header. In this state until
-    // enough has been inflated that this stream most likely has a zlib header,
-    // or until a zlib header has been added. Data is appended to |replay_data_|
-    // in case it needs to be replayed after adding a header.
-    STATE_SNIFFING_DEFLATE_HEADER,
-    // If a zlib header has to be added to the response, this state will replay
-    // data passed to inflate before it was determined that no zlib header was
-    // present.
-    // See https://crbug.com/677001
-    STATE_REPLAY_DATA,
-    // The input stream is being decoded.
-    STATE_COMPRESSED_BODY,
-    // Gzip footer of the input stream is being processed.
-    STATE_GZIP_FOOTER,
-    // The end of the gzipped body has been reached. If any extra bytes are
-    // received, just silently ignore them. Doing this, rather than failing the
-    // request or passing the extra bytes alone with the rest of the response
-    // body, matches the behavior of other browsers.
-    STATE_IGNORING_EXTRA_BYTES,
-  };
-
   GzipSourceStream(std::unique_ptr<SourceStream> previous,
                    SourceStream::SourceType type);
 
@@ -80,33 +51,7 @@
                  int* consumed_bytes,
                  bool upstream_end_reached) override;
 
-  // Inserts a zlib header to the data stream before calling zlib inflate.
-  // This is used to work around server bugs. The function returns true on
-  // success.
-  bool InsertZlibHeader();
-
-  // The control block of zlib which actually does the decoding.
-  // This data structure is initialized by Init and updated only by
-  // FilterData(), with InsertZlibHeader() being the exception as a workaround.
-  std::unique_ptr<z_stream> zlib_stream_;
-
-  // While in STATE_SNIFFING_DEFLATE_HEADER, it may be determined that a zlib
-  // header needs to be added, and all received data needs to be replayed. In
-  // that case, this buffer holds the data to be replayed.
-  std::string replay_data_;
-
-  // Used to parse the gzip header in gzip stream.
-  // It is used when the decoding mode is GZIP_SOURCE_STREAM_GZIP.
-  GZipHeader gzip_header_;
-
-  // Tracks how many bytes of gzip footer are yet to be filtered.
-  size_t gzip_footer_bytes_left_;
-
-  // Tracks the state of the input stream.
-  InputState input_state_;
-
-  // Used when replaying data.
-  InputState replay_state_;
+  ZLibStreamWrapper zlib_stream_;
 
   DISALLOW_COPY_AND_ASSIGN(GzipSourceStream);
 };
diff --git a/net/filter/zlib_stream_wrapper.cc b/net/filter/zlib_stream_wrapper.cc
new file mode 100644
index 0000000..0a14fbc
--- /dev/null
+++ b/net/filter/zlib_stream_wrapper.cc
@@ -0,0 +1,232 @@
+// Copyright 2018 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 "net/filter/zlib_stream_wrapper.h"
+
+#include <algorithm>
+
+#include "base/bit_cast.h"
+#include "base/logging.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+namespace net {
+
+namespace {
+
+// For deflate streams, if more than this many bytes have been received without
+// an error and without adding a Zlib header, assume the original stream had a
+// Zlib header. In practice, don't need nearly this much data, but since the
+// detection logic is a heuristic, best to be safe. Data is freed once it's been
+// determined whether the stream has a zlib header or not, so larger values
+// shouldn't affect memory usage, in practice.
+const int kMaxZlibHeaderSniffBytes = 1000;
+
+}  // anonymous namespace
+
+ZLibStreamWrapper::ZLibStreamWrapper(SourceType type)
+    : type_(type),
+      input_state_(STATE_START),
+      replay_state_(STATE_COMPRESSED_BODY),
+      gzip_footer_bytes_left_(0) {}
+
+bool ZLibStreamWrapper::Init() {
+  memset(&zlib_stream_, 0, sizeof(z_stream));
+
+  int ret;
+  if (type_ == SourceType::kGzip) {
+    ret = inflateInit2(&zlib_stream_, -MAX_WBITS);
+  } else {
+    ret = inflateInit(&zlib_stream_);
+  }
+  DCHECK_NE(Z_VERSION_ERROR, ret);
+
+  return ret == Z_OK;
+}
+
+ZLibStreamWrapper::~ZLibStreamWrapper() {
+  inflateEnd(&zlib_stream_);
+}
+
+bool ZLibStreamWrapper::InsertZlibHeader() {
+  char dummy_header[] = {0x78, 0x01};
+  char dummy_output[4];
+
+  inflateReset(&zlib_stream_);
+  zlib_stream_.next_in = bit_cast<Bytef*>(&dummy_header[0]);
+  zlib_stream_.avail_in = sizeof(dummy_header);
+  zlib_stream_.next_out = bit_cast<Bytef*>(&dummy_output[0]);
+  zlib_stream_.avail_out = sizeof(dummy_output);
+
+  int ret = inflate(&zlib_stream_, Z_NO_FLUSH);
+  return ret == Z_OK;
+}
+
+int ZLibStreamWrapper::FilterData(IOBuffer* output_buffer,
+                                  int output_buffer_size,
+                                  IOBuffer* input_buffer,
+                                  int input_buffer_size,
+                                  int* consumed_bytes,
+                                  bool upstream_end_reached) {
+  *consumed_bytes = 0;
+  char* input_data = input_buffer->data();
+  int input_data_size = input_buffer_size;
+  int bytes_out = 0;
+  bool state_compressed_entered = false;
+  while (input_data_size > 0 && bytes_out < output_buffer_size) {
+    InputState state = input_state_;
+    switch (state) {
+      case STATE_START: {
+        if (type_ == SourceType::kDeflate) {
+          input_state_ = STATE_SNIFFING_DEFLATE_HEADER;
+          break;
+        }
+        DCHECK_LT(0, input_data_size);
+        input_state_ = STATE_GZIP_HEADER;
+        break;
+      }
+      case STATE_GZIP_HEADER: {
+        DCHECK_NE(SourceType::kDeflate, type_);
+
+        const size_t kGzipFooterBytes = 8;
+        const char* end = nullptr;
+        GZipHeader::Status status =
+            gzip_header_.ReadMore(input_data, input_data_size, &end);
+        if (status == GZipHeader::INCOMPLETE_HEADER) {
+          input_data += input_data_size;
+          input_data_size = 0;
+        } else if (status == GZipHeader::COMPLETE_HEADER) {
+          // If there is a valid header, there should also be a valid footer.
+          gzip_footer_bytes_left_ = kGzipFooterBytes;
+          int bytes_consumed = end - input_data;
+          input_data += bytes_consumed;
+          input_data_size -= bytes_consumed;
+          input_state_ = STATE_COMPRESSED_BODY;
+        } else if (status == GZipHeader::INVALID_HEADER) {
+          return ERR_CONTENT_DECODING_FAILED;
+        }
+        break;
+      }
+      case STATE_SNIFFING_DEFLATE_HEADER: {
+        DCHECK_EQ(SourceType::kDeflate, type_);
+
+        zlib_stream_.next_in = bit_cast<Bytef*>(input_data);
+        zlib_stream_.avail_in = input_data_size;
+        zlib_stream_.next_out = bit_cast<Bytef*>(output_buffer->data());
+        zlib_stream_.avail_out = output_buffer_size;
+
+        int ret = inflate(&zlib_stream_, Z_NO_FLUSH);
+
+        // On error, try adding a zlib header and replaying the response. Note
+        // that data just received doesn't have to be replayed, since it hasn't
+        // been removed from input_data yet, only data from previous FilterData
+        // calls needs to be replayed.
+        if (ret != Z_STREAM_END && ret != Z_OK) {
+          if (!InsertZlibHeader())
+            return ERR_CONTENT_DECODING_FAILED;
+
+          input_state_ = STATE_REPLAY_DATA;
+          // |replay_state_| should still have its initial value.
+          DCHECK_EQ(STATE_COMPRESSED_BODY, replay_state_);
+          break;
+        }
+
+        int bytes_used = input_data_size - zlib_stream_.avail_in;
+        bytes_out = output_buffer_size - zlib_stream_.avail_out;
+        // If any bytes are output, enough total bytes have been received, or at
+        // the end of the stream, assume the response had a valid Zlib header.
+        if (bytes_out > 0 ||
+            bytes_used + replay_data_.size() >= kMaxZlibHeaderSniffBytes ||
+            ret == Z_STREAM_END) {
+          replay_data_.clear();
+          if (ret == Z_STREAM_END) {
+            input_state_ = STATE_GZIP_FOOTER;
+          } else {
+            input_state_ = STATE_COMPRESSED_BODY;
+          }
+        } else {
+          replay_data_.append(input_data, bytes_used);
+        }
+
+        input_data_size -= bytes_used;
+        input_data += bytes_used;
+        break;
+      }
+      case STATE_REPLAY_DATA: {
+        DCHECK_EQ(SourceType::kDeflate, type_);
+
+        if (replay_data_.empty()) {
+          input_state_ = replay_state_;
+          break;
+        }
+
+        // Call FilterData recursively, after updating |input_state_|, with
+        // |replay_data_|. This recursive call makes handling data from
+        // |replay_data_| and |input_buffer| much simpler than the alternative
+        // operations, though it's not pretty.
+        input_state_ = replay_state_;
+        int bytes_used;
+        scoped_refptr<IOBuffer> replay_buffer =
+            base::MakeRefCounted<WrappedIOBuffer>(replay_data_.data());
+        int result =
+            FilterData(output_buffer, output_buffer_size, replay_buffer.get(),
+                       replay_data_.size(), &bytes_used, upstream_end_reached);
+        replay_data_.erase(0, bytes_used);
+        // Back up resulting state, and return state to STATE_REPLAY_DATA.
+        replay_state_ = input_state_;
+        input_state_ = STATE_REPLAY_DATA;
+
+        // On error, or if bytes were read, just return result immediately.
+        // Could continue consuming data in the success case, but simplest not
+        // to.
+        if (result != 0)
+          return result;
+        break;
+      }
+      case STATE_COMPRESSED_BODY: {
+        DCHECK(!state_compressed_entered);
+        DCHECK_LE(0, input_data_size);
+
+        state_compressed_entered = true;
+        zlib_stream_.next_in = bit_cast<Bytef*>(input_data);
+        zlib_stream_.avail_in = input_data_size;
+        zlib_stream_.next_out = bit_cast<Bytef*>(output_buffer->data());
+        zlib_stream_.avail_out = output_buffer_size;
+
+        int ret = inflate(&zlib_stream_, Z_NO_FLUSH);
+        if (ret != Z_STREAM_END && ret != Z_OK)
+          return ERR_CONTENT_DECODING_FAILED;
+
+        int bytes_used = input_data_size - zlib_stream_.avail_in;
+        bytes_out = output_buffer_size - zlib_stream_.avail_out;
+        input_data_size -= bytes_used;
+        input_data += bytes_used;
+        if (ret == Z_STREAM_END)
+          input_state_ = STATE_GZIP_FOOTER;
+        // zlib has written as much data to |output_buffer| as it could.
+        // There might still be some unconsumed data in |input_buffer| if there
+        // is no space in |output_buffer|.
+        break;
+      }
+      case STATE_GZIP_FOOTER: {
+        size_t to_read = std::min(gzip_footer_bytes_left_,
+                                  base::checked_cast<size_t>(input_data_size));
+        gzip_footer_bytes_left_ -= to_read;
+        input_data_size -= to_read;
+        input_data += to_read;
+        if (gzip_footer_bytes_left_ == 0)
+          input_state_ = STATE_IGNORING_EXTRA_BYTES;
+        break;
+      }
+      case STATE_IGNORING_EXTRA_BYTES: {
+        input_data_size = 0;
+        break;
+      }
+    }
+  }
+  *consumed_bytes = input_buffer_size - input_data_size;
+  return bytes_out;
+}
+
+}  // namespace net
diff --git a/net/filter/zlib_stream_wrapper.h b/net/filter/zlib_stream_wrapper.h
new file mode 100644
index 0000000..8a151f2
--- /dev/null
+++ b/net/filter/zlib_stream_wrapper.h
@@ -0,0 +1,104 @@
+// Copyright 2018 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 NET_FILTER_ZLIB_STREAM_WRAPPER_H_
+#define NET_FILTER_ZLIB_STREAM_WRAPPER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/filter/gzip_header.h"
+#include "third_party/zlib/zlib.h"
+
+namespace net {
+
+class IOBuffer;
+
+// Class to wrap and provide an easier to use interface to zlib for inflating
+// zlib or gzip wrapped deflated data streams.
+class NET_EXPORT ZLibStreamWrapper {
+ public:
+  // The stream source type to be inflated.
+  enum class SourceType {
+    // Source stream is a gzip-wrapped deflate data.
+    kGzip,
+    // Source stream is a zlib-wrapped deflate data.
+    kDeflate
+  };
+
+  explicit ZLibStreamWrapper(SourceType type);
+  ~ZLibStreamWrapper();
+
+  // Returns true if initialization is successful, false otherwise.
+  // For instance, this method returns false if there is not enough memory or
+  // if there is a version mismatch.
+  // Note: Must be called before FilterData.
+  bool Init();
+
+  // Filter (i.e. inflate) the data from |input_buffer| into |output_buffer|.
+  // Will return the number bytes written to the output buffer or a net::Error.
+  // |consumed_bytes| will be set to the number of bytes read from
+  // |input_buffer| when expanding.
+  // Note: Must call Init() before using this method.
+  int FilterData(net::IOBuffer* output_buffer,
+                 int output_buffer_size,
+                 net::IOBuffer* input_buffer,
+                 int input_buffer_size,
+                 int* consumed_bytes,
+                 bool upstream_end_reached);
+
+ private:
+  enum InputState {
+    // Starts processing the input stream. Checks whether the stream is valid
+    // and whether a fallback to plain data is needed.
+    STATE_START,
+    // Gzip header of the input stream is being processed.
+    STATE_GZIP_HEADER,
+    // Deflate responses may or may not have a zlib header. In this state until
+    // enough has been inflated that this stream most likely has a zlib header,
+    // or until a zlib header has been added. Data is appended to |replay_data_|
+    // in case it needs to be replayed after adding a header.
+    STATE_SNIFFING_DEFLATE_HEADER,
+    // If a zlib header has to be added to the response, this state will replay
+    // data passed to inflate before it was determined that no zlib header was
+    // present.
+    // See https://crbug.com/677001
+    STATE_REPLAY_DATA,
+    // The input stream is being decoded.
+    STATE_COMPRESSED_BODY,
+    // Gzip footer of the input stream is being processed.
+    STATE_GZIP_FOOTER,
+    // The end of the gzipped body has been reached. If any extra bytes are
+    // received, just silently ignore them. Doing this, rather than failing the
+    // request or passing the extra bytes alone with the rest of the response
+    // body, matches the behavior of other browsers.
+    STATE_IGNORING_EXTRA_BYTES,
+  };
+
+  bool InsertZlibHeader();
+
+  SourceType type_;
+  InputState input_state_;
+  InputState replay_state_;
+  z_stream_s zlib_stream_;
+  // Used to parse the gzip header in gzip stream.
+  // It is used when the decoding mode is SourceType::kDeflate.
+  net::GZipHeader gzip_header_;
+
+  // While in STATE_SNIFFING_DEFLATE_HEADER, it may be determined that a zlib
+  // header needs to be added, and all received data needs to be replayed. In
+  // that case, this buffer holds the data to be replayed.
+  std::string replay_data_;
+
+  // Tracks how many bytes of gzip footer are yet to be filtered.
+  size_t gzip_footer_bytes_left_;
+
+  DISALLOW_COPY_AND_ASSIGN(ZLibStreamWrapper);
+};
+
+}  // namespace net
+
+#endif  // NET_FILTER_ZLIB_STREAM_WRAPPER_H_
diff --git a/net/filter/zlib_stream_wrapper_unittest.cc b/net/filter/zlib_stream_wrapper_unittest.cc
new file mode 100644
index 0000000..35f0c3d
--- /dev/null
+++ b/net/filter/zlib_stream_wrapper_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2018 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 "net/filter/zlib_stream_wrapper.h"
+#include "base/memory/scoped_refptr.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/filter/filter_source_stream_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+class ZLibStreamWrapperTest
+    : public testing::Test,
+      public testing::WithParamInterface<ZLibStreamWrapper::SourceType> {
+ public:
+  ZLibStreamWrapper::SourceType source_type() { return GetParam(); }
+
+  bool compress_with_gzip_framing() {
+    return GetParam() == ZLibStreamWrapper::SourceType::kGzip;
+  }
+};
+
+TEST_P(ZLibStreamWrapperTest, SmallInflate) {
+  const std::string uncompressed_data = "hello";
+
+  size_t compressed_data_len = 2048;
+  auto compressed_data = std::make_unique<char[]>(compressed_data_len);
+  net::CompressGzip(uncompressed_data.data(), uncompressed_data.size(),
+                    compressed_data.get(), &compressed_data_len,
+                    compress_with_gzip_framing());
+
+  ZLibStreamWrapper zlib_wrapper(source_type());
+
+  ASSERT_TRUE(zlib_wrapper.Init());
+
+  scoped_refptr<WrappedIOBuffer> input_buffer =
+      new WrappedIOBuffer(compressed_data.get());
+  scoped_refptr<IOBuffer> output_buffer =
+      new IOBuffer(uncompressed_data.size());
+  int consumed_bytes(0);
+  int bytes_written = zlib_wrapper.FilterData(
+      output_buffer.get(), uncompressed_data.size(), input_buffer.get(),
+      compressed_data_len, &consumed_bytes,
+      /*upstream_end_reached=*/true);
+
+  ASSERT_EQ(static_cast<int>(uncompressed_data.size()), bytes_written);
+  EXPECT_EQ(static_cast<int>(compressed_data_len), consumed_bytes);
+  EXPECT_EQ(0, memcmp(output_buffer->data(), uncompressed_data.data(),
+                      uncompressed_data.size()));
+}
+
+TEST_P(ZLibStreamWrapperTest, SmallCorruptedInflate) {
+  const std::string uncompressed_data = "hello";
+
+  size_t compressed_data_len = 2048;
+  auto compressed_data = std::make_unique<char[]>(compressed_data_len);
+  net::CompressGzip(uncompressed_data.data(), uncompressed_data.size(),
+                    compressed_data.get(), &compressed_data_len,
+                    compress_with_gzip_framing());
+
+  // Corrupt the compressed data stream.
+  compressed_data[1] = 'X';
+
+  ZLibStreamWrapper zlib_wrapper(source_type());
+
+  ASSERT_TRUE(zlib_wrapper.Init());
+
+  scoped_refptr<WrappedIOBuffer> input_buffer =
+      new WrappedIOBuffer(compressed_data.get());
+  scoped_refptr<IOBuffer> output_buffer =
+      new IOBuffer(uncompressed_data.size());
+  int consumed_bytes(0);
+  int bytes_written = zlib_wrapper.FilterData(
+      output_buffer.get(), uncompressed_data.size(), input_buffer.get(),
+      compressed_data_len, &consumed_bytes,
+      /*upstream_end_reached=*/true);
+
+  EXPECT_EQ(net::ERR_CONTENT_DECODING_FAILED, bytes_written);
+  EXPECT_EQ(0, consumed_bytes);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    ,
+    ZLibStreamWrapperTest,
+    testing::Values(ZLibStreamWrapper::SourceType::kGzip,
+                    ZLibStreamWrapper::SourceType::kDeflate));
+}  // namespace net
diff --git a/services/ws/test_ws/test_window_service.cc b/services/ws/test_ws/test_window_service.cc
index 4b14f7bb..ee05f4d 100644
--- a/services/ws/test_ws/test_window_service.cc
+++ b/services/ws/test_ws/test_window_service.cc
@@ -16,6 +16,7 @@
 #include "services/ws/test_host_event_dispatcher.h"
 #include "services/ws/test_ws/test_gpu_interface_provider.h"
 #include "services/ws/window_service.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 #include "ui/aura/mus/property_utils.h"
 #include "ui/compositor/test/context_factories_for_test.h"
@@ -74,6 +75,11 @@
     property_converter->SetPropertyFromTransportValue(
         top_level.get(), property.first, &property.second);
   }
+  if (maximize_next_window_) {
+    top_level->SetProperty(aura::client::kShowStateKey,
+                           ui::SHOW_STATE_MAXIMIZED);
+    maximize_next_window_ = false;
+  }
   return top_level;
 }
 
@@ -164,6 +170,11 @@
     std::move(pending_create_service_).Run();
 }
 
+void TestWindowService::MaximizeNextWindow(MaximizeNextWindowCallback cb) {
+  maximize_next_window_ = true;
+  std::move(cb).Run();
+}
+
 void TestWindowService::Shutdown(
     test_ws::mojom::TestWs::ShutdownCallback callback) {
   // WindowService depends upon Screen, which is owned by AuraTestHelper.
diff --git a/services/ws/test_ws/test_window_service.h b/services/ws/test_ws/test_window_service.h
index 3a26e29f..b6b4e7d 100644
--- a/services/ws/test_ws/test_window_service.h
+++ b/services/ws/test_ws/test_window_service.h
@@ -91,6 +91,7 @@
   void OnGpuServiceInitialized() override;
 
   // test_ws::mojom::TestWs:
+  void MaximizeNextWindow(MaximizeNextWindowCallback cb) override;
   void Shutdown(test_ws::mojom::TestWs::ShutdownCallback callback) override;
 
   void BindServiceFactory(
@@ -127,6 +128,7 @@
 
   bool started_ = false;
   bool ui_service_created_ = false;
+  bool maximize_next_window_ = false;
 
   base::OnceClosure pending_create_service_;
 
diff --git a/services/ws/test_ws/test_ws.mojom b/services/ws/test_ws/test_ws.mojom
index 14e97982..7af604a5 100644
--- a/services/ws/test_ws/test_ws.mojom
+++ b/services/ws/test_ws/test_ws.mojom
@@ -8,6 +8,10 @@
 
 // Implemented by TestWindowService.
 interface TestWs {
+  // Requests that the window service create the next top-level window with
+  // show state maximized.
+  MaximizeNextWindow() => ();
+
   // Used when caller needs to explicitly shutdown the window service hosted
   // in test_ws. Callback is provided so that caller can resume its shutdown
   // sequence.
diff --git a/storage/browser/blob/blob_url_loader.cc b/storage/browser/blob/blob_url_loader.cc
index ca16d56..975f7ed 100644
--- a/storage/browser/blob/blob_url_loader.cc
+++ b/storage/browser/blob/blob_url_loader.cc
@@ -133,6 +133,7 @@
 void BlobURLLoader::DidRead(int num_bytes) {
   if (response_body_consumer_handle_.is_valid()) {
     // Send the data pipe on the first OnReadCompleted call.
+    CHECK(on_receive_response_sent_);
     client_->OnStartLoadingResponseBody(
         std::move(response_body_consumer_handle_));
   }
@@ -165,7 +166,7 @@
   // TODO(jam): some of this code can be shared with
   // services/network/url_loader.h
   client_->OnReceiveResponse(response);
-  sent_headers_ = true;
+  on_receive_response_sent_ = true;
 
   if (metadata) {
     const uint8_t* data = reinterpret_cast<const uint8_t*>(metadata->data());
diff --git a/storage/browser/blob/blob_url_loader.h b/storage/browser/blob/blob_url_loader.h
index 12d005e..238b2371 100644
--- a/storage/browser/blob/blob_url_loader.h
+++ b/storage/browser/blob/blob_url_loader.h
@@ -68,11 +68,13 @@
   net::HttpByteRange byte_range_;
 
   uint64_t total_size_ = 0;
-  bool sent_headers_ = false;
 
   std::unique_ptr<BlobDataHandle> blob_handle_;
   mojo::ScopedDataPipeConsumerHandle response_body_consumer_handle_;
 
+  // TODO(https://crbug.com/882661): Remove this as soon as the bug is fixed.
+  bool on_receive_response_sent_ = false;
+
   base::WeakPtrFactory<BlobURLLoader> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(BlobURLLoader);
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 72178c3..695fdfd 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -5861,6 +5861,14 @@
           "shards": 2
         },
         "test": "base_unittests"
+      },
+      {
+        "isolate_coverage_data": true,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 2
+        },
+        "test": "url_unittests"
       }
     ]
   },
diff --git a/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter b/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
index 9bd628d..6545709 100644
--- a/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
+++ b/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
@@ -126,9 +126,6 @@
 -LauncherPlatformAppBrowserTest.PanelAttentionStatus
 -LauncherPlatformAppBrowserTest.PanelItemClickBehavior
 
-# JS failure: hasAccessToCurrentWindow: FAIL (no message)
--LockScreenNoteTakingTest.*
-
 # Missing magnification manager and also RefCounted check failed:
 # CalledOnValidSequence() from SchedulerWorkerDelegate::OnMainExit
 -LoginScreenDefaultPolicyInSessionBrowsertest.*
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter b/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
index 41031580..13a19df 100644
--- a/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
+++ b/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
@@ -31,9 +31,6 @@
 # Viz hit testing not supported with Mash https://crbug.com/879308
 -PDFExtensionHitTestTest.MouseLeave/1
 
-# https://crbug.com/899055
--LockScreenNoteTakingTest.*
-
 # Flaky. https://crbug.com/888188.
 -ChromeSessionManagerTest.LoginExistingUsers
 -ChromeSessionManagerTest.PRE_LoginExistingUsers
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter b/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
index 3421b63e..fe1a1d3 100644
--- a/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
+++ b/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
@@ -40,7 +40,6 @@
 # TabDragging: crbug.com/890071
 -TabDragging/DetachToBrowserInSeparateDisplayTabDragControllerTest.DragBrowserWindowWhenMajorityOfBoundsInSecondDisplay/0
 -TabDragging/DetachToBrowserTabDragControllerTest.DetachToOwnWindowWhileInImmersiveFullscreenMode/1
--TabDragging/DetachToBrowserTabDragControllerTest.DragToOverviewWindow/1
 -TabDragging/DetachToBrowserTabDragControllerTest.DragToSeparateWindow/1
 -TabDragging/DetachToBrowserTabDragControllerTest.DragWithMaskedWindows/0
 -TabDragging/DetachToBrowserTabDragControllerTest.DragWithMaskedWindows/1
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 866b920..1596b90f 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -679,6 +679,11 @@
           'shards': 2,
         },
       },
+      'url_unittests': {
+        'swarming': {
+          'shards': 2,
+        },
+      },
     },
 
     'chromium_linux_scripts': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c53a011..bf76c638 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3965,24 +3965,6 @@
             ]
         }
     ],
-    "RuntimeHostPermissions": [
-        {
-            "platforms": [
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "RuntimeHostPermissions"
-                    ]
-                }
-            ]
-        }
-    ],
     "SRTPromptFieldTrial": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 9dc12463..2238fb5 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -3001,6 +3001,8 @@
 crbug.com/893480 external/wpt/infrastructure/testdriver/actions/multiDevice.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac10.10 Mac10.13 Retina ] virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/simplecall-no-ssrcs.https.html [ Timeout ]
+crbug.com/626703 [ Mac10.12 ] virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/simplecall-no-ssrcs.https.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/css/css-text/letter-spacing/letter-spacing-bidi-002.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/letter-spacing/letter-spacing-nesting-002.html [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/css/css-text/word-break/word-break-keep-all-005.html [ Failure ]
@@ -5526,5 +5528,8 @@
 #Sheriff 2018-11-02
 crbug.com/901314 [ Win7 Mac10.10 Mac10.11 ] inspector-protocol/css/css-coverage-new-stylesheet.js [ Failure Pass ]
 crbug.com/901317 [ Mac10.10 Mac10.13 ] virtual/outofblink-cors/external/wpt/service-workers/service-worker/update-registration-with-type.https.html [ Failure Pass ]
-crbug.com/901317 [ Mac10.10 Mac10.11 ] virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https.html [ Failure Pass ]
-crbug.com/901317 [ Mac10.11 Mac10.13 Win10 ] virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/update-registration-with-type.https.html [ Failure Pass ]
+crbug.com/901317 [ Mac10.11 Mac10.12 Mac10.13 ] virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https.html [ Failure Pass ]
+crbug.com/901317 [ Mac10.11 Mac10.13 Win10 Linux ] virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/update-registration-with-type.https.html [ Failure Pass ]
+crbug.com/901489 [ Mac10.13 ] http/tests/security/document-domain-canonicalizes.html [ Crash Pass ]
+crbug.com/901489 [ Mac10.13 ] virtual/outofblink-cors-ns/http/tests/security/document-domain-canonicalizes.html [ Crash Pass ]
+crbug.com/901489 [ Mac10.13 ] virtual/outofblink-cors/http/tests/security/document-domain-canonicalizes.html [ Crash Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
index 74f2893..5f69d56f 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
@@ -38303,6 +38303,18 @@
      {}
     ]
    ],
+   "css/css-display/display-contents-shadow-host-whitespace.html": [
+    [
+     "/css/css-display/display-contents-shadow-host-whitespace.html",
+     [
+      [
+       "/css/reference/pass_if_two_words.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-display/display-contents-sharing-001.html": [
     [
      "/css/css-display/display-contents-sharing-001.html",
@@ -38920,7 +38932,7 @@
      "/css/css-flexbox/anonymous-flex-item-001.html",
      [
       [
-       "/css/css-flexbox/anonymous-flex-item-ref.html",
+       "/css/reference/pass_if_two_words.html",
        "=="
       ]
      ],
@@ -38932,7 +38944,7 @@
      "/css/css-flexbox/anonymous-flex-item-002.html",
      [
       [
-       "/css/css-flexbox/anonymous-flex-item-ref.html",
+       "/css/reference/pass_if_two_words.html",
        "=="
       ]
      ],
@@ -38944,7 +38956,7 @@
      "/css/css-flexbox/anonymous-flex-item-003.html",
      [
       [
-       "/css/css-flexbox/anonymous-flex-item-ref.html",
+       "/css/reference/pass_if_two_words.html",
        "=="
       ]
      ],
@@ -60535,6 +60547,18 @@
      {}
     ]
    ],
+   "css/css-text/overflow-wrap/overflow-wrap-break-word-005.html": [
+    [
+     "/css/css-text/overflow-wrap/overflow-wrap-break-word-005.html",
+     [
+      [
+       "/css/css-text/overflow-wrap/reference/overflow-wrap-break-word-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/overflow-wrap/overflow-wrap-break-word-fit-content-001.html": [
     [
      "/css/css-text/overflow-wrap/overflow-wrap-break-word-fit-content-001.html",
@@ -63308,7 +63332,7 @@
      "/css/css-text/white-space/white-space-empty-text-sibling.html",
      [
       [
-       "/css/css-text/white-space/reference/white-space-empty-text-sibling-ref.html",
+       "/css/reference/pass_if_two_words.html",
        "=="
       ]
      ],
@@ -120593,6 +120617,11 @@
      {}
     ]
    ],
+   "css/css-animations/idlharness-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-animations/parsing/animation-name-invalid-expected.txt": [
     [
      {}
@@ -120603,6 +120632,11 @@
      {}
     ]
    ],
+   "css/css-animations/parsing/animation-timing-function-valid-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-animations/support/testcommon.js": [
     [
      {}
@@ -122823,6 +122857,31 @@
      {}
     ]
    ],
+   "css/css-easing/META.yml": [
+    [
+     {}
+    ]
+   ],
+   "css/css-easing/cubic-bezier-timing-functions-output-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-easing/step-timing-functions-output-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-easing/step-timing-functions-syntax-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-easing/testcommon.js": [
+    [
+     {}
+    ]
+   ],
    "css/css-env/META.yml": [
     [
      {}
@@ -122873,11 +122932,6 @@
      {}
     ]
    ],
-   "css/css-flexbox/anonymous-flex-item-ref.html": [
-    [
-     {}
-    ]
-   ],
    "css/css-flexbox/anonymous-flex-item-split-ref.html": [
     [
      {}
@@ -138803,11 +138857,6 @@
      {}
     ]
    ],
-   "css/css-text/white-space/reference/white-space-empty-text-sibling-ref.html": [
-    [
-     {}
-    ]
-   ],
    "css/css-text/white-space/reference/white-space-pre-wrap-trailing-spaces-001-ref.html": [
     [
      {}
@@ -139018,11 +139067,6 @@
      {}
     ]
    ],
-   "css/css-timing/META.yml": [
-    [
-     {}
-    ]
-   ],
    "css/css-timing/OWNERS": [
     [
      {}
@@ -139033,7 +139077,12 @@
      {}
     ]
    ],
-   "css/css-timing/testcommon.js": [
+   "css/css-timing/frames-timing-functions-output-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-timing/frames-timing-functions-syntax-expected.txt": [
     [
      {}
     ]
@@ -140553,6 +140602,16 @@
      {}
     ]
    ],
+   "css/css-transitions/idlharness-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-transitions/parsing/transition-timing-function-valid-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-transitions/properties-value-001-expected.txt": [
     [
      {}
@@ -146573,6 +146632,11 @@
      {}
     ]
    ],
+   "css/reference/pass_if_two_words.html": [
+    [
+     {}
+    ]
+   ],
    "css/reference/ref-filled-green-100px-square-only.html": [
     [
      {}
@@ -154818,6 +154882,21 @@
      {}
     ]
    ],
+   "hr-time/idlharness.any.serviceworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "hr-time/idlharness.any.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "hr-time/idlharness.any.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "hr-time/resources/now_frame.html": [
     [
      {}
@@ -156173,6 +156252,11 @@
      {}
     ]
    ],
+   "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/no_window_open_when_term_nesting_level_nonzero.window-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/non_automated/001-1.html": [
     [
      {}
@@ -170183,6 +170267,11 @@
      {}
     ]
    ],
+   "payment-request/payment-request-canmakepayment-method-protection.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "payment-request/payment-request-canmakepayment-method.https-expected.txt": [
     [
      {}
@@ -173808,6 +173897,11 @@
      {}
     ]
    ],
+   "resources/chromium/url.mojom.js": [
+    [
+     {}
+    ]
+   ],
    "resources/chromium/uuid.mojom.js": [
     [
      {}
@@ -177218,6 +177312,11 @@
      {}
     ]
    ],
+   "signed-exchange/META.yml": [
+    [
+     {}
+    ]
+   ],
    "signed-exchange/README.md": [
     [
      {}
@@ -180518,6 +180617,26 @@
      {}
     ]
    ],
+   "webrtc-identity/META.yml": [
+    [
+     {}
+    ]
+   ],
+   "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "webrtc-identity/RTCPeerConnection-peerIdentity-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "webrtc-identity/identity-helper.sub.js": [
+    [
+     {}
+    ]
+   ],
    "webrtc-stats/META.yml": [
     [
      {}
@@ -180548,6 +180667,11 @@
      {}
     ]
    ],
+   "webrtc/RTCCertificate-postMessage-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webrtc/RTCConfiguration-helper.js": [
     [
      {}
@@ -180933,11 +181057,6 @@
      {}
     ]
    ],
-   "webrtc/identity-helper.sub.js": [
-    [
-     {}
-    ]
-   ],
    "webrtc/idlharness.https.window-expected.txt": [
     [
      {}
@@ -180953,6 +181072,11 @@
      {}
     ]
    ],
+   "webrtc/resources/RTCCertificate-postMessage-iframe.html": [
+    [
+     {}
+    ]
+   ],
    "webrtc/tools/README.md": [
     [
      {}
@@ -199037,6 +199161,54 @@
      {}
     ]
    ],
+   "css/CSS2/normal-flow/containing-block-percent-margin-bottom.html": [
+    [
+     "/css/CSS2/normal-flow/containing-block-percent-margin-bottom.html",
+     {}
+    ]
+   ],
+   "css/CSS2/normal-flow/containing-block-percent-margin-left.html": [
+    [
+     "/css/CSS2/normal-flow/containing-block-percent-margin-left.html",
+     {}
+    ]
+   ],
+   "css/CSS2/normal-flow/containing-block-percent-margin-right.html": [
+    [
+     "/css/CSS2/normal-flow/containing-block-percent-margin-right.html",
+     {}
+    ]
+   ],
+   "css/CSS2/normal-flow/containing-block-percent-margin-top.html": [
+    [
+     "/css/CSS2/normal-flow/containing-block-percent-margin-top.html",
+     {}
+    ]
+   ],
+   "css/CSS2/normal-flow/containing-block-percent-padding-bottom.html": [
+    [
+     "/css/CSS2/normal-flow/containing-block-percent-padding-bottom.html",
+     {}
+    ]
+   ],
+   "css/CSS2/normal-flow/containing-block-percent-padding-left.html": [
+    [
+     "/css/CSS2/normal-flow/containing-block-percent-padding-left.html",
+     {}
+    ]
+   ],
+   "css/CSS2/normal-flow/containing-block-percent-padding-right.html": [
+    [
+     "/css/CSS2/normal-flow/containing-block-percent-padding-right.html",
+     {}
+    ]
+   ],
+   "css/CSS2/normal-flow/containing-block-percent-padding-top.html": [
+    [
+     "/css/CSS2/normal-flow/containing-block-percent-padding-top.html",
+     {}
+    ]
+   ],
    "css/CSS2/normal-flow/unresolvable-max-height.html": [
     [
      "/css/CSS2/normal-flow/unresolvable-max-height.html",
@@ -200355,6 +200527,24 @@
      {}
     ]
    ],
+   "css/css-easing/cubic-bezier-timing-functions-output.html": [
+    [
+     "/css/css-easing/cubic-bezier-timing-functions-output.html",
+     {}
+    ]
+   ],
+   "css/css-easing/step-timing-functions-output.html": [
+    [
+     "/css/css-easing/step-timing-functions-output.html",
+     {}
+    ]
+   ],
+   "css/css-easing/step-timing-functions-syntax.html": [
+    [
+     "/css/css-easing/step-timing-functions-syntax.html",
+     {}
+    ]
+   ],
    "css/css-env/at-supports.tentative.html": [
     [
      "/css/css-env/at-supports.tentative.html",
@@ -205877,12 +206067,6 @@
      {}
     ]
    ],
-   "css/css-timing/cubic-bezier-timing-functions-output.html": [
-    [
-     "/css/css-timing/cubic-bezier-timing-functions-output.html",
-     {}
-    ]
-   ],
    "css/css-timing/frames-timing-functions-output.html": [
     [
      "/css/css-timing/frames-timing-functions-output.html",
@@ -205895,12 +206079,6 @@
      {}
     ]
    ],
-   "css/css-timing/step-timing-functions-output.html": [
-    [
-     "/css/css-timing/step-timing-functions-output.html",
-     {}
-    ]
-   ],
    "css/css-transforms/2d-rotate-js.html": [
     [
      "/css/css-transforms/2d-rotate-js.html",
@@ -226825,6 +227003,12 @@
      }
     ]
    ],
+   "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/no_window_open_when_term_nesting_level_nonzero.window.js": [
+    [
+     "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/no_window_open_when_term_nesting_level_nonzero.window.html",
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html": [
     [
      "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html",
@@ -252803,6 +252987,14 @@
      }
     ]
    ],
+   "payment-request/payment-request-canmakepayment-method-protection.https.html": [
+    [
+     "/payment-request/payment-request-canmakepayment-method-protection.https.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "payment-request/payment-request-canmakepayment-method.https.html": [
     [
      "/payment-request/payment-request-canmakepayment-method.https.html",
@@ -271539,12 +271731,30 @@
      {}
     ]
    ],
+   "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html": [
+    [
+     "/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html",
+     {}
+    ]
+   ],
+   "webrtc-identity/RTCPeerConnection-peerIdentity.html": [
+    [
+     "/webrtc-identity/RTCPeerConnection-peerIdentity.html",
+     {}
+    ]
+   ],
    "webrtc-stats/idlharness.window.js": [
     [
      "/webrtc-stats/idlharness.window.html",
      {}
     ]
    ],
+   "webrtc/RTCCertificate-postMessage.html": [
+    [
+     "/webrtc/RTCCertificate-postMessage.html",
+     {}
+    ]
+   ],
    "webrtc/RTCCertificate.html": [
     [
      "/webrtc/RTCCertificate.html",
@@ -271727,12 +271937,6 @@
      {}
     ]
    ],
-   "webrtc/RTCPeerConnection-getIdentityAssertion.sub.html": [
-    [
-     "/webrtc/RTCPeerConnection-getIdentityAssertion.sub.html",
-     {}
-    ]
-   ],
    "webrtc/RTCPeerConnection-getStats.https.html": [
     [
      "/webrtc/RTCPeerConnection-getStats.https.html",
@@ -271775,12 +271979,6 @@
      {}
     ]
    ],
-   "webrtc/RTCPeerConnection-peerIdentity.html": [
-    [
-     "/webrtc/RTCPeerConnection-peerIdentity.html",
-     {}
-    ]
-   ],
    "webrtc/RTCPeerConnection-remote-track-mute.https.html": [
     [
      "/webrtc/RTCPeerConnection-remote-track-mute.https.html",
@@ -272069,6 +272267,12 @@
      {}
     ]
    ],
+   "webrtc/simplecall-no-ssrcs.https.html": [
+    [
+     "/webrtc/simplecall-no-ssrcs.https.html",
+     {}
+    ]
+   ],
    "webrtc/simplecall.https.html": [
     [
      "/webrtc/simplecall.https.html",
@@ -289997,7 +290201,7 @@
    "testharness"
   ],
   "IndexedDB/get-databases.any.js": [
-   "f054e0fec2f0543eae7978303ae2a24858bdf245",
+   "823cfce284b2beed49821825f2794849edda5753",
    "testharness"
   ],
   "IndexedDB/globalscope-indexedDB-SameObject.html": [
@@ -293569,7 +293773,7 @@
    "testharness"
   ],
   "bluetooth/idl/idlharness.tentative.https.window-expected.txt": [
-   "e5d18e75caf74f49ee2f1ad67ca2dc18f627be24",
+   "4a16e4f396b4419bb1d7b77bcb10f584dc1bb5b9",
    "support"
   ],
   "bluetooth/idl/idlharness.tentative.https.window.js": [
@@ -294529,7 +294733,7 @@
    "support"
   ],
   "common/performance-timeline-utils.js": [
-   "6845d6cbc689fc5183c2bc07f381299bc51da1dc",
+   "3efce5b5d8b3cbc9ac17171e674d317de8797a55",
    "support"
   ],
   "common/performance-timeline-utils.js.headers": [
@@ -294617,7 +294821,7 @@
    "testharness"
   ],
   "compat/idlharness.window-expected.txt": [
-   "6deefcc139986cd0068208e6baa4f1accc6ac70f",
+   "0104eb394c86d999c034644eedddba2609bc191e",
    "support"
   ],
   "compat/idlharness.window.js": [
@@ -305040,6 +305244,38 @@
    "b3a7420c630ad4c84e5593ad48f48f3072a88b98",
    "visual"
   ],
+  "css/CSS2/normal-flow/containing-block-percent-margin-bottom.html": [
+   "9dfc1963ac8a3bbccdd317e2b21613d08db21452",
+   "testharness"
+  ],
+  "css/CSS2/normal-flow/containing-block-percent-margin-left.html": [
+   "aa077d9ea83656debaca6009e86f0321b8c2872c",
+   "testharness"
+  ],
+  "css/CSS2/normal-flow/containing-block-percent-margin-right.html": [
+   "9ae84bd16ca2829ce0606cf69c17cbc76f22355e",
+   "testharness"
+  ],
+  "css/CSS2/normal-flow/containing-block-percent-margin-top.html": [
+   "7698f27240ebe2b8f6a98e8c5bfb495ec6b12461",
+   "testharness"
+  ],
+  "css/CSS2/normal-flow/containing-block-percent-padding-bottom.html": [
+   "5eea503005da0a38840fc4a708ea37870772feb6",
+   "testharness"
+  ],
+  "css/CSS2/normal-flow/containing-block-percent-padding-left.html": [
+   "0f793e715d67c20719b28b64ccf031acb5fe831a",
+   "testharness"
+  ],
+  "css/CSS2/normal-flow/containing-block-percent-padding-right.html": [
+   "28fd9590cdf5d30d5dce298ca52e331f64d836ff",
+   "testharness"
+  ],
+  "css/CSS2/normal-flow/containing-block-percent-padding-top.html": [
+   "f30ace92e9def67f70bc1b6b6b4ad6e43f1561bd",
+   "testharness"
+  ],
   "css/CSS2/normal-flow/float-percentage-resolution-quirks-mode.html": [
    "a3794579f0ea242f9e7faaffcc16de5a3a69cf7c",
    "reftest"
@@ -314876,6 +315112,10 @@
    "5b96a422f55f45cddabdf011acb83e5081ec1ef3",
    "testharness"
   ],
+  "css/css-animations/idlharness-expected.txt": [
+   "50b4cddbf768e2e5b8d8a786b6db59a432fb8a0b",
+   "support"
+  ],
   "css/css-animations/idlharness.html": [
    "1d3ed2b9b806792c7efaeeee9ab264101dd222bc",
    "testharness"
@@ -314960,8 +315200,12 @@
    "adc1cc10e39d09df78c4398ffca008739d751076",
    "testharness"
   ],
+  "css/css-animations/parsing/animation-timing-function-valid-expected.txt": [
+   "fabf009d1bb5d988bae745769463b2a7f36a86e2",
+   "support"
+  ],
   "css/css-animations/parsing/animation-timing-function-valid.html": [
-   "63e2805485bfb1f8db9dfe3ad70979ade7e11cd4",
+   "7ab823ea1da1535606ac4aad30fb21f423ba6703",
    "testharness"
   ],
   "css/css-animations/pending-style-changes-001.html": [
@@ -320828,6 +321072,10 @@
    "82321b9c07edaf471f64829f0f0efa232aeb99c0",
    "support"
   ],
+  "css/css-display/display-contents-shadow-host-whitespace.html": [
+   "84b04dba1013af9091f3d943ca106ab655676842",
+   "reftest"
+  ],
   "css/css-display/display-contents-sharing-001-ref.html": [
    "a047f326fe216487e0d9c294437de88fb9d51149",
    "support"
@@ -320964,6 +321212,38 @@
    "08024b52d5fd82e18fc482888164cbe127239329",
    "support"
   ],
+  "css/css-easing/META.yml": [
+   "2c412b40f0f1b6059099682bc5c787310e8d2991",
+   "support"
+  ],
+  "css/css-easing/cubic-bezier-timing-functions-output-expected.txt": [
+   "8e41c9ca3f348827919bc8f4ad8ef59311eba947",
+   "support"
+  ],
+  "css/css-easing/cubic-bezier-timing-functions-output.html": [
+   "168f4cd907ec93d84bafcd11b00a7c78878569c8",
+   "testharness"
+  ],
+  "css/css-easing/step-timing-functions-output-expected.txt": [
+   "f36703d27c887f306722beb71ab183bd5b080954",
+   "support"
+  ],
+  "css/css-easing/step-timing-functions-output.html": [
+   "978ac25df696dff029614733920a5155d8d96ecf",
+   "testharness"
+  ],
+  "css/css-easing/step-timing-functions-syntax-expected.txt": [
+   "34dcb6ba1f5b135bcc24c2e9e2b0ac5ed7b9ab89",
+   "support"
+  ],
+  "css/css-easing/step-timing-functions-syntax.html": [
+   "4e8b21e4413f8000ae584396355ed7df1c44a447",
+   "testharness"
+  ],
+  "css/css-easing/testcommon.js": [
+   "9fd25b86507258b900911df892540bdb1ae17cd3",
+   "support"
+  ],
   "css/css-env/META.yml": [
    "9d264a62281358545e6e842edb6a56105cb7dd5f",
    "support"
@@ -321213,15 +321493,15 @@
    "reftest"
   ],
   "css/css-flexbox/anonymous-flex-item-001.html": [
-   "e1c6ec6d8aecfbd704830ba442e625bae9114971",
+   "3e749d43f76981a5cc0b372c7ba0c364c350b6b2",
    "reftest"
   ],
   "css/css-flexbox/anonymous-flex-item-002.html": [
-   "4b571fe5fc39529d9b22db5ae6dd85f7c81f0587",
+   "8fdeb27110e15c743e0b84cd4f278f1d8996c994",
    "reftest"
   ],
   "css/css-flexbox/anonymous-flex-item-003.html": [
-   "1449e1df60e4b1f7157be83c191fd6abf39dd970",
+   "cc896e9410cd1706a61d083494801cda98bd72af",
    "reftest"
   ],
   "css/css-flexbox/anonymous-flex-item-004.html": [
@@ -321236,10 +321516,6 @@
    "6320b814294cdbf0a91fee0bb5b597a5f70d57d6",
    "reftest"
   ],
-  "css/css-flexbox/anonymous-flex-item-ref.html": [
-   "4a2285400c9f58cf499c58c36a3fe45f2777f102",
-   "support"
-  ],
   "css/css-flexbox/anonymous-flex-item-split-ref.html": [
    "163efd401c4d24ce205dc9c39431b79598a7fb6f",
    "support"
@@ -336273,7 +336549,7 @@
    "support"
   ],
   "css/css-masking/idlharness-expected.txt": [
-   "f188afc0043b727bb09f4342f294a737793f51e3",
+   "002bd396362453e0ae6a208635e6f529dd1b7a6b",
    "support"
   ],
   "css/css-masking/idlharness.html": [
@@ -338813,7 +339089,7 @@
    "reftest"
   ],
   "css/css-pseudo/idlharness-expected.txt": [
-   "4ccc625263f54e24750d9a852a714c4f3b1405b5",
+   "8b356c8339d2c644a365e2473da60bc5278d26d7",
    "support"
   ],
   "css/css-pseudo/idlharness.html": [
@@ -344400,6 +344676,10 @@
    "560ef63b2f94c5eeca83ee5ef63cdfc15fbdfe34",
    "reftest"
   ],
+  "css/css-text/overflow-wrap/overflow-wrap-break-word-005.html": [
+   "3ef61bc9eff78b860c0bd2ed5c6bc4c28c168008",
+   "reftest"
+  ],
   "css/css-text/overflow-wrap/overflow-wrap-break-word-fit-content-001.html": [
    "bce6c68389c32960d79e8fbbf61f9fa28c733165",
    "reftest"
@@ -346100,10 +346380,6 @@
    "01ce8eae718170c4eb65e9629f6618e9458a1aca",
    "support"
   ],
-  "css/css-text/white-space/reference/white-space-empty-text-sibling-ref.html": [
-   "3837f7f62f4686226ef4dff3318c2b6961dac85b",
-   "support"
-  ],
   "css/css-text/white-space/reference/white-space-pre-wrap-trailing-spaces-001-ref.html": [
    "8db147766bc3fa769df5601b8b32964fb59bcbc1",
    "support"
@@ -346289,7 +346565,7 @@
    "reftest"
   ],
   "css/css-text/white-space/white-space-empty-text-sibling.html": [
-   "56a5cad875dbb7f3225e7ae382d9417e5cc6bae4",
+   "50439df433cea8d4191989cb3d5444ff9f8d15c1",
    "reftest"
   ],
   "css/css-text/white-space/white-space-pre-wrap-trailing-spaces-001.html": [
@@ -346608,10 +346884,6 @@
    "e1a67bb1dc7d157d4bf57e1af40c039d67001923",
    "reftest"
   ],
-  "css/css-timing/META.yml": [
-   "1ee250307b7043a0b1ac28af8e9e28413ab0d75b",
-   "support"
-  ],
   "css/css-timing/OWNERS": [
    "ada3963c8f75f6489dd2682016d680d54d0dbe9a",
    "support"
@@ -346620,26 +346892,22 @@
    "8e41c9ca3f348827919bc8f4ad8ef59311eba947",
    "support"
   ],
-  "css/css-timing/cubic-bezier-timing-functions-output.html": [
-   "5c2003b13944256e4ef2bf15a759aa534363da66",
-   "testharness"
+  "css/css-timing/frames-timing-functions-output-expected.txt": [
+   "7b821e7d36ba62d53562d73baac0879e0e232dc9",
+   "support"
   ],
   "css/css-timing/frames-timing-functions-output.html": [
    "40e03286e71f7126bfbbdd50bc74e25c191a4d30",
    "testharness"
   ],
+  "css/css-timing/frames-timing-functions-syntax-expected.txt": [
+   "d10139494132ead9dc0f8d911f0bcdbc2e0905d9",
+   "support"
+  ],
   "css/css-timing/frames-timing-functions-syntax.html": [
    "1616bcffa740c20aa73d5af8a84fc4a435baef02",
    "testharness"
   ],
-  "css/css-timing/step-timing-functions-output.html": [
-   "9a2aa507c888ee303ee52df2e96c4b4c8ad282c9",
-   "testharness"
-  ],
-  "css/css-timing/testcommon.js": [
-   "9fd25b86507258b900911df892540bdb1ae17cd3",
-   "support"
-  ],
   "css/css-transforms/2d-rotate-001.html": [
    "3f28db8f4e3e17c8420e0af3a2d33d65766d557f",
    "reftest"
@@ -352272,6 +352540,10 @@
    "8d0360a8ecf7a37b81acb10917b63abc7c9543cc",
    "testharness"
   ],
+  "css/css-transitions/idlharness-expected.txt": [
+   "74256a1bb72f5d4fba014477682264522fedd0cf",
+   "support"
+  ],
   "css/css-transitions/idlharness.html": [
    "4cc7ee50eb4915fcf95843f7eeee266abfa7b81a",
    "testharness"
@@ -352309,11 +352581,15 @@
    "testharness"
   ],
   "css/css-transitions/parsing/transition-timing-function-invalid.html": [
-   "936defa6cce5dd7b69bf9344c60add178de6589a",
+   "00bd2131e0927ba38e633ad7be404b8ec26e51a9",
    "testharness"
   ],
+  "css/css-transitions/parsing/transition-timing-function-valid-expected.txt": [
+   "8e64c2aadef6fa50090a032f236f39b32a56b825",
+   "support"
+  ],
   "css/css-transitions/parsing/transition-timing-function-valid.html": [
-   "e11ef0002e43b65e06c8aec7dffab2fe7d48377f",
+   "2e2c1827bfbef9d4cc58e32ec88da3c7fd614225",
    "testharness"
   ],
   "css/css-transitions/properties-value-001-expected.txt": [
@@ -352817,11 +353093,11 @@
    "reftest"
   ],
   "css/css-transitions/transition-timing-function-001-expected.txt": [
-   "42c270197a5ebdf8b0f1039d87e7d3c007ccf750",
+   "7adb70862c47e6a60dcd86cf6ce156ecd35adf6f",
    "support"
   ],
   "css/css-transitions/transition-timing-function-001.html": [
-   "75665450a1a8ea33b7ef3205755211099fd91490",
+   "4c9598f3919b84dc79d7c92c76b74b7f950423aa",
    "testharness"
   ],
   "css/css-transitions/transition-timing-function-002.html": [
@@ -352925,7 +353201,7 @@
    "testharness"
   ],
   "css/css-typed-om/interfaces-expected.txt": [
-   "20b1327353b09f826aa79eec3be678e9383665f9",
+   "7c32597684e932b0aa43e0af9ffa37ce7cdf2654",
    "support"
   ],
   "css/css-typed-om/interfaces.html": [
@@ -364133,7 +364409,7 @@
    "testharness"
   ],
   "css/cssom-view/interfaces-expected.txt": [
-   "62a5805456e6bb6d7b6e1990b80a66e77c65dd32",
+   "977491375e8572fdec53c1137603e49cc6f89046",
    "support"
   ],
   "css/cssom-view/interfaces.html": [
@@ -364821,7 +365097,7 @@
    "testharness"
   ],
   "css/cssom/interfaces-expected.txt": [
-   "a83ae3f6f059d12f3eabd5b9aee6d5153b71db55",
+   "706e87a3a58aba9b66678871282668e92f61acb3",
    "support"
   ],
   "css/cssom/interfaces.html": [
@@ -365656,6 +365932,10 @@
    "7d9cb8910789e378e7406f3b4ec94afa9d77ced4",
    "support"
   ],
+  "css/reference/pass_if_two_words.html": [
+   "e33eea5e6ea237139f9d86da07a09ef2e4874789",
+   "support"
+  ],
   "css/reference/ref-filled-green-100px-square-only.html": [
    "82fcaa3b2aa4a271db14feb00256d0aedbce2d85",
    "support"
@@ -372997,7 +373277,7 @@
    "testharness"
   ],
   "dom/interfaces_exclude=Node-expected.txt": [
-   "41fe5fad5348f067d6775f565a2233662c6093a0",
+   "33ba6302ac10570d37fa9b0f229142761ab21151",
    "support"
   ],
   "dom/lists/DOMTokenList-Iterable.html": [
@@ -374489,7 +374769,7 @@
    "testharness"
   ],
   "domparsing/interfaces.any.worker-expected.txt": [
-   "ac6137df9df30045488ad21d7cee76c7e270539c",
+   "a7bebc632f47797738405ff3f7fa844a4da84485",
    "support"
   ],
   "domparsing/outerhtml-01.html": [
@@ -378161,7 +378441,7 @@
    "support"
   ],
   "feature-policy/idlharness.window-expected.txt": [
-   "71a041e90710f0287c8b864a511e49caf1305ba3",
+   "c4a5606274e6baaec4fe2f0b8fe0e62c56bde332",
    "support"
   ],
   "feature-policy/idlharness.window.js": [
@@ -378757,7 +379037,7 @@
    "testharness"
   ],
   "fetch/api/idl.any-expected.txt": [
-   "c0f63b02ed266a31f8b42a8a395de157201feaf9",
+   "b013c5c01cf6101d4a24aed21b7933fbae0ea904",
    "support"
   ],
   "fetch/api/idl.any.js": [
@@ -378765,15 +379045,15 @@
    "testharness"
   ],
   "fetch/api/idl.any.serviceworker-expected.txt": [
-   "47b603335d336fe1011f5ad2bd5e48a8f45d478d",
+   "cf90de4569b1aad191d590b2d2aeebcbd19b209c",
    "support"
   ],
   "fetch/api/idl.any.sharedworker-expected.txt": [
-   "c0f63b02ed266a31f8b42a8a395de157201feaf9",
+   "20b02f1c54a7b0383a719fa01306d620949c9938",
    "support"
   ],
   "fetch/api/idl.any.worker-expected.txt": [
-   "c0f63b02ed266a31f8b42a8a395de157201feaf9",
+   "20b02f1c54a7b0383a719fa01306d620949c9938",
    "support"
   ],
   "fetch/api/policies/csp-blocked-worker-expected.txt": [
@@ -379649,15 +379929,15 @@
    "testharness"
   ],
   "fetch/cors-rfc1918/idlharness.tentative.any.serviceworker-expected.txt": [
-   "8558fae4a9e5dd1078f39f63c19c2d34931b8bb4",
+   "2d89b4412e3e2b8623ee2e3f1fea430ad85bbe80",
    "support"
   ],
   "fetch/cors-rfc1918/idlharness.tentative.any.sharedworker-expected.txt": [
-   "8558fae4a9e5dd1078f39f63c19c2d34931b8bb4",
+   "2d89b4412e3e2b8623ee2e3f1fea430ad85bbe80",
    "support"
   ],
   "fetch/cors-rfc1918/idlharness.tentative.any.worker-expected.txt": [
-   "8558fae4a9e5dd1078f39f63c19c2d34931b8bb4",
+   "2d89b4412e3e2b8623ee2e3f1fea430ad85bbe80",
    "support"
   ],
   "fetch/cross-origin-resource-policy/fetch-expected.txt": [
@@ -380817,7 +381097,7 @@
    "support"
   ],
   "gamepad/idlharness.window-expected.txt": [
-   "915af06444db6fc8d6b7b3254057b2eacea971b8",
+   "dc95c50da05b27c95fee09b9d044819c6a867833",
    "support"
   ],
   "gamepad/idlharness.window.js": [
@@ -381164,6 +381444,18 @@
    "4e266c09e3358034e6fac6fb282bbeb138e4278a",
    "testharness"
   ],
+  "hr-time/idlharness.any.serviceworker-expected.txt": [
+   "02975ba0f63852a89c92413ddf0077d92e56a6a7",
+   "support"
+  ],
+  "hr-time/idlharness.any.sharedworker-expected.txt": [
+   "02975ba0f63852a89c92413ddf0077d92e56a6a7",
+   "support"
+  ],
+  "hr-time/idlharness.any.worker-expected.txt": [
+   "02975ba0f63852a89c92413ddf0077d92e56a6a7",
+   "support"
+  ],
   "hr-time/monotonic-clock.any.js": [
    "f7f254557f4296f8e69757eb9ed3ac11a05d3a33",
    "testharness"
@@ -381285,7 +381577,7 @@
    "support"
   ],
   "html-media-capture/idlharness.window-expected.txt": [
-   "c8248ba917fd886a519cc6cf2bfa29912dfc1675",
+   "b887ef5b2298ecfa2197c00b81783941fb827c8c",
    "support"
   ],
   "html-media-capture/idlharness.window.js": [
@@ -383316,6 +383608,14 @@
    "062f61949dc820634999e58045383065b179b49f",
    "testharness"
   ],
+  "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/no_window_open_when_term_nesting_level_nonzero.window-expected.txt": [
+   "85e1b00703f2f1810216ae09d5bdb214ccc51817",
+   "support"
+  ],
+  "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/no_window_open_when_term_nesting_level_nonzero.window.js": [
+   "3dff403b9c66e84b8fb0da93e97cdbecabfe1b5c",
+   "testharness"
+  ],
   "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/non_automated/001-1.html": [
    "7dd48b41c23b4ff1fdff95edd87af6b03ea0c814",
    "support"
@@ -385061,7 +385361,7 @@
    "testharness"
   ],
   "html/dom/interfaces.https_exclude=(Document_Window_HTML._)-expected.txt": [
-   "fa4972aa45cd156bc80ec41fa77dd732c5d50212",
+   "32ee1e59eb978b361d2011fb518c3ff7c3271c3b",
    "support"
   ],
   "html/dom/interfaces.https_include=(Document_Window)-expected.txt": [
@@ -400985,7 +401285,7 @@
    "support"
   ],
   "interfaces/fullscreen.idl": [
-   "87f1599750a6e72e8540865ee3a21cab88eac56b",
+   "491aa7af13e6703023f723cfd6ef41cc6c0e6ace",
    "support"
   ],
   "interfaces/gamepad.idl": [
@@ -401121,7 +401421,7 @@
    "support"
   ],
   "interfaces/payment-request.idl": [
-   "0795c03627da479992512c334e5b395a81c237dc",
+   "baf9ee36db9c898e500609dcdaf152ccbfbc704a",
    "support"
   ],
   "interfaces/performance-timeline.idl": [
@@ -401577,7 +401877,7 @@
    "support"
   ],
   "lint.whitelist": [
-   "23f20555e8c30784cbf5ba87ae5ec6b81165b81f",
+   "3de5698c229d7c8b7f32207030540283b9efec63",
    "support"
   ],
   "longtask-timing/META.yml": [
@@ -402469,7 +402769,7 @@
    "support"
   ],
   "mediacapture-fromelement/idlharness.window-expected.txt": [
-   "e2149ce949cb54bf34daf519d0ece6f17d8d2565",
+   "124357262486faeca6da07bde09d0fd09765195c",
    "support"
   ],
   "mediacapture-fromelement/idlharness.window.js": [
@@ -402785,7 +403085,7 @@
    "testharness"
   ],
   "mediacapture-streams/idlharness.https.window-expected.txt": [
-   "da7a86a02110e86d0302242a95e9b11d354bd8f8",
+   "aa959031a0539255b84d7e964add7b4e7c7c1d21",
    "support"
   ],
   "mediacapture-streams/idlharness.https.window.js": [
@@ -413160,12 +413460,20 @@
    "64886a6b7cc91b3aa05a34e6f8650808d3f1ab0b",
    "testharness"
   ],
+  "payment-request/payment-request-canmakepayment-method-protection.https-expected.txt": [
+   "0f09114186bb4b3c975473f189a79237b7901944",
+   "support"
+  ],
+  "payment-request/payment-request-canmakepayment-method-protection.https.html": [
+   "b0582d520d306760d75754779de1ceef1d064a92",
+   "testharness"
+  ],
   "payment-request/payment-request-canmakepayment-method.https-expected.txt": [
    "0f09114186bb4b3c975473f189a79237b7901944",
    "support"
   ],
   "payment-request/payment-request-canmakepayment-method.https.html": [
-   "2943c2da688fae9257b663395ae3388287549750",
+   "03a9c19fb8fd774ccea9cf2a9740be0971fa4910",
    "testharness"
   ],
   "payment-request/payment-request-constructor-crash.https.html": [
@@ -413261,7 +413569,7 @@
    "manual"
   ],
   "payment-request/payment-response/retry-method-manual.https.html": [
-   "82821a9a39c6c9ce6def2c076e39aa08f00921cc",
+   "16ed15e54902b93485ee3be7a2635823e8763b06",
    "manual"
   ],
   "payment-request/payment-response/shippingAddress-attribute-manual.https.html": [
@@ -413569,7 +413877,7 @@
    "support"
   ],
   "pointerevents/idlharness.window-expected.txt": [
-   "fd20b3c8f221720c598c8117fb4ebac37212d429",
+   "fb85fa069a511a66975e9507ca9072b8de118652",
    "support"
   ],
   "pointerevents/idlharness.window.js": [
@@ -414413,7 +414721,7 @@
    "testharness"
   ],
   "push-api/idlharness.https.any.serviceworker-expected.txt": [
-   "d0869e0c2479d67cc748449dbca84525e06e60de",
+   "2a17bcb16d14ab27fedf9b39526592e2dc556e1f",
    "support"
   ],
   "quirks/META.yml": [
@@ -423045,7 +423353,7 @@
    "support"
   ],
   "resources/chromium/device.mojom.js": [
-   "435fc1fc7addabfddb093e003795512c28360357",
+   "495971c23192ece2b832392baea4f7af97a4d557",
    "support"
   ],
   "resources/chromium/device.mojom.js.headers": [
@@ -423128,6 +423436,10 @@
    "6805c323df5a975231648b830e33ce183c3cbbd3",
    "support"
   ],
+  "resources/chromium/url.mojom.js": [
+   "abe7d00e7f9ce659c925baeebea94b535ae7a5d3",
+   "support"
+  ],
   "resources/chromium/uuid.mojom.js": [
    "3b1b616ee3450f5ceb94f3f7e74ce5eea7af1bf9",
    "support"
@@ -423177,7 +423489,7 @@
    "support"
   ],
   "resources/idlharness.js": [
-   "40a5fa59cd209d12e6d42dcdff92c4974ae49cf2",
+   "9e6ed236b0a43f32ffaecbbbb2b8fbe7540b83c5",
    "support"
   ],
   "resources/idlharness.js.headers": [
@@ -423685,7 +423997,7 @@
    "support"
   ],
   "server-timing/cross_origin.https.html": [
-   "1421b38a05eb8c64cc80d69baedce9f2166fdd30",
+   "d31c7b006caf2311563b2c36171422d81d2979b8",
    "testharness"
   ],
   "server-timing/idlharness.https.any.js": [
@@ -423693,11 +424005,11 @@
    "testharness"
   ],
   "server-timing/navigation_timing_idl.https.html": [
-   "290bb889b149335a47b4b7ddcebc318bff32ca0c",
+   "d911d64e47ced02caadfca54b620218ace024f87",
    "testharness"
   ],
   "server-timing/resource_timing_idl.https.html": [
-   "d2c3c9274eab862e8962019a7cc7c39d27804b16",
+   "b1d8699cc6057407f79dbe83b56a8477a38d7c96",
    "testharness"
   ],
   "server-timing/resources/blue.png": [
@@ -424413,11 +424725,11 @@
    "support"
   ],
   "server-timing/server_timing_header-parsing.https.html": [
-   "156dfcd344f36c36186b088561213ad76d934097",
+   "737cc08045ae94f1dc98417500e5e1400474a584",
    "testharness"
   ],
   "server-timing/service_worker_idl.https.html": [
-   "1c1be8995b33102926254790f0abfdc972fcf46e",
+   "5c493fdcb0ab581a267a084e7e2383617d99677e",
    "testharness"
   ],
   "server-timing/sw.js": [
@@ -424425,7 +424737,7 @@
    "support"
   ],
   "server-timing/test_server_timing.https.html": [
-   "2d43aa2d43b722ff489db10b2df6f2c218e1f1d7",
+   "4f3554aa4a4572e8dbef83fcea3ce8cdd946a858",
    "testharness"
   ],
   "server-timing/test_server_timing.https.html.sub.headers": [
@@ -427676,6 +427988,10 @@
    "4b2b19ef79c61e0c71f1f938c34b89e5344b0c6b",
    "support"
   ],
+  "signed-exchange/META.yml": [
+   "f56fbab13ecc0256f23133a1086e8925729121f9",
+   "support"
+  ],
   "signed-exchange/README.md": [
    "f1dbfe6d1adbe7ef7663c5298692872897ce3e0c",
    "support"
@@ -427873,7 +428189,7 @@
    "testharness"
   ],
   "speech-api/idlharness.window-expected.txt": [
-   "ee63d6ddb08884ca48c46c9428fbf14dbddfeab0",
+   "e0bc129a438f03e6d93d833c179aa14f5f33f5aa",
    "support"
   ],
   "speech-api/idlharness.window.js": [
@@ -429521,7 +429837,7 @@
    "testharness"
   ],
   "svg/idlharness.window-expected.txt": [
-   "36ed012772ed16804638a6ba9f1ebdeca0158acc",
+   "b4aa8b69006486f5f3ca3877c9b4ff9f775479c0",
    "support"
   ],
   "svg/idlharness.window.js": [
@@ -430477,7 +430793,7 @@
    "testharness"
   ],
   "touch-events/idlharness.window-expected.txt": [
-   "8ac9fbeb9c574d441a29bb53d936e135c29fbb7f",
+   "610536241ea584ec951f8f93798739f0dce704a3",
    "support"
   ],
   "touch-events/idlharness.window.js": [
@@ -432689,11 +433005,11 @@
    "testharness"
   ],
   "web-animations/timing-model/time-transformations/transformed-progress-expected.txt": [
-   "b9b99897655288c0cab925a25dce10865c4850c3",
+   "1046b2df664ae2dbd021465ef2d9c456980622bb",
    "support"
   ],
   "web-animations/timing-model/time-transformations/transformed-progress.html": [
-   "839ebe1093e5daf2bd2f309711c6174cb6a38a84",
+   "960e333c09268f68d23ba2d0208202f8262ec3ef",
    "testharness"
   ],
   "web-animations/timing-model/timelines/document-timelines.html": [
@@ -433037,7 +433353,7 @@
    "support"
   ],
   "webaudio/idlharness.https.window-expected.txt": [
-   "1e99acda1386d360603d7fc5ed3f506a04b9bc2c",
+   "64ec9f4302453321fba932e2a2e8fd5f6fc48d7a",
    "support"
   ],
   "webaudio/idlharness.https.window.js": [
@@ -434637,7 +434953,7 @@
    "support"
   ],
   "webmidi/idlharness.https.window-expected.txt": [
-   "85db0f6a3d1aca55117e386a8305728747103d32",
+   "c2d675a6233a1ba9ffb23bea0408018149d53f17",
    "support"
   ],
   "webmidi/idlharness.https.window.js": [
@@ -434648,6 +434964,30 @@
    "3b29d8963b28881b347e54afc0afa3ad051924bc",
    "support"
   ],
+  "webrtc-identity/META.yml": [
+   "900769b9d4334bb38d6413beea6a28235d8c927c",
+   "support"
+  ],
+  "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub-expected.txt": [
+   "f3902089fe1c9958c8dd3ee598efb73a5b7ed4c4",
+   "support"
+  ],
+  "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html": [
+   "2bd860d901ded78c9635da65413ac63e7dbf4460",
+   "testharness"
+  ],
+  "webrtc-identity/RTCPeerConnection-peerIdentity-expected.txt": [
+   "76951f17b1cb799f48035501a0ae4d57db7a1d61",
+   "support"
+  ],
+  "webrtc-identity/RTCPeerConnection-peerIdentity.html": [
+   "64ad212a5ba4e0c6bf5589f4cda3a4c7a508cdc2",
+   "testharness"
+  ],
+  "webrtc-identity/identity-helper.sub.js": [
+   "90363662f742fbf1d31634030d2b470e08fe1421",
+   "support"
+  ],
   "webrtc-stats/META.yml": [
    "489264f23d6e8c096652620e6e7732a94644353f",
    "support"
@@ -434676,8 +435016,16 @@
    "883749d713afb94ff7559b9c32fa5045b568ba2a",
    "support"
   ],
+  "webrtc/RTCCertificate-postMessage-expected.txt": [
+   "7c5a5696c295e3cfa409e1a7bdb6cbc198fe7aed",
+   "support"
+  ],
+  "webrtc/RTCCertificate-postMessage.html": [
+   "5885f9fb1bbc3e97e5916d07e3df706316c170e8",
+   "testharness"
+  ],
   "webrtc/RTCCertificate.html": [
-   "e5f1749eb5bfbccbf769510acda806f2a5eb8dc3",
+   "a33ba9ae5f2b201e663c5aa70d1984f0687c613a",
    "testharness"
   ],
   "webrtc/RTCConfiguration-bundlePolicy.html": [
@@ -434769,11 +435117,11 @@
    "testharness"
   ],
   "webrtc/RTCIceCandidate-constructor-expected.txt": [
-   "8df706d35c33584683310b753ee9add2d0f9c588",
+   "af3000f58a964647e8a0ae1f8ef069c7eeb0eb7a",
    "support"
   ],
   "webrtc/RTCIceCandidate-constructor.html": [
-   "974ed0c76cfafb788e865c0b1c71fa19007c55b9",
+   "9842593a83c5330e0ed19bedac9f6c9908362c41",
    "testharness"
   ],
   "webrtc/RTCIceTransport-expected.txt": [
@@ -434797,11 +435145,11 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-addIceCandidate-expected.txt": [
-   "030996a9eb021924a992fc46535bf6468fc36891",
+   "1f68f03b9bae4c0e1ec2df585397a3d249da60ca",
    "support"
   ],
   "webrtc/RTCPeerConnection-addIceCandidate.html": [
-   "5e321681336ece75202d9c469227d60da4ceee39",
+   "1dd1350acd25ea865631c45f7345cb3d06822f3b",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-addTrack.https-expected.txt": [
@@ -434900,10 +435248,6 @@
    "f3902089fe1c9958c8dd3ee598efb73a5b7ed4c4",
    "support"
   ],
-  "webrtc/RTCPeerConnection-getIdentityAssertion.sub.html": [
-   "2bd860d901ded78c9635da65413ac63e7dbf4460",
-   "testharness"
-  ],
   "webrtc/RTCPeerConnection-getStats.https-expected.txt": [
    "438277749f7ba8a886995fdc583a6e4c0bbbfde9",
    "support"
@@ -434917,7 +435261,7 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-helper.js": [
-   "b13e580998efce83c8bb158bce3d7747ec6f8bd9",
+   "330ce1992d97a5d3fc825f882fcdaa3f1f4a95bf",
    "support"
   ],
   "webrtc/RTCPeerConnection-iceConnectionState-expected.txt": [
@@ -434964,10 +435308,6 @@
    "76951f17b1cb799f48035501a0ae4d57db7a1d61",
    "support"
   ],
-  "webrtc/RTCPeerConnection-peerIdentity.html": [
-   "64ad212a5ba4e0c6bf5589f4cda3a4c7a508cdc2",
-   "testharness"
-  ],
   "webrtc/RTCPeerConnection-remote-track-mute.https.html": [
    "56fe761425096e963589309b828a8a7f7d36a9be",
    "testharness"
@@ -435093,7 +435433,7 @@
    "support"
   ],
   "webrtc/RTCPeerConnectionIceEvent-constructor.html": [
-   "07e9736441285536e0549c55b110a562b49276cc",
+   "7de7fcaeb10ef209ece63ad346f668e1c634c4db",
    "testharness"
   ],
   "webrtc/RTCQuicStream.https.html": [
@@ -435316,10 +435656,6 @@
    "d49503e16d6c5de6f7ea991120e7fb2b53bbcfd5",
    "testharness"
   ],
-  "webrtc/identity-helper.sub.js": [
-   "90363662f742fbf1d31634030d2b470e08fe1421",
-   "support"
-  ],
   "webrtc/idlharness.https.window-expected.txt": [
    "794763f85fa85e75d061590307bdae997e742071",
    "support"
@@ -435348,6 +435684,14 @@
    "547856f2a271b5c349b529ec7f1fe1acb5a48ef0",
    "testharness"
   ],
+  "webrtc/resources/RTCCertificate-postMessage-iframe.html": [
+   "9e52ba0c888a8d500072c1669599d88f64cb22c3",
+   "support"
+  ],
+  "webrtc/simplecall-no-ssrcs.https.html": [
+   "266b57663781115154f1ad8ddd2dd69143bc44b9",
+   "testharness"
+  ],
   "webrtc/simplecall.https.html": [
    "681c42d4cd855dcf53543a7add231d2665c381a9",
    "testharness"
@@ -436757,7 +437101,7 @@
    "support"
   ],
   "webusb/resources/usb-helpers.js": [
-   "a3a4a31ba889f719c68cd2ca4f263bc56d67b7a6",
+   "161a7d270bbad085dc34300b389286dd045123a1",
    "support"
   ],
   "webusb/usb-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [
@@ -439893,7 +440237,7 @@
    "support"
   ],
   "webxr/idlharness.https.window-expected.txt": [
-   "2528268adbdf0d79fa4f072caff9f76bea547abf",
+   "794ad858937207b7b438a3d9764e0018a2c7ca72",
    "support"
   ],
   "webxr/idlharness.https.window.js": [
@@ -442165,11 +442509,11 @@
    "testharness"
   ],
   "xhr/idlharness.any.sharedworker-expected.txt": [
-   "50788e8c4785fc44f06fad8e5541710990a0f94f",
+   "a388bd716506badb035b9eb9bd4fd99542e88561",
    "support"
   ],
   "xhr/idlharness.any.worker-expected.txt": [
-   "50788e8c4785fc44f06fad8e5541710990a0f94f",
+   "a388bd716506badb035b9eb9bd4fd99542e88561",
    "support"
   ],
   "xhr/loadstart-and-state.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/get-databases.any.js b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/get-databases.any.js
index f054e0f..823cfce 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/get-databases.any.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/get-databases.any.js
@@ -1,20 +1,29 @@
 // META: script=support-promises.js
 
 promise_test(async testCase => {
-  // Delete any databases that may not have been cleaned up after
-  // previous test runs.
+  assert_true(indexedDB.databases() instanceof Promise,
+      "databases() should return a promise.");
+}, "Ensure that databases() returns a promise.");
+
+promise_test(async testCase => {
+  // Delete any databases that may not have been cleaned up after previous test
+  // runs.
   await deleteAllDatabases(testCase);
 
   const db_name = "TestDatabase";
   const db = await createNamedDatabase(testCase, db_name, ()=>{});
-  const databases_promise = await indexedDB.databases();
-  const expected_result = [
-    {"name": db_name, "version": 1},
-  ];
-  assert_object_equals(
-      databases_promise,
-      expected_result,
-      "Call to databases() did not retrieve the single expected result.");
+  const databases_result = await indexedDB.databases();
+  db.close();
+  const expected_result = {"name": db_name, "version": 1};
+  assert_equals(
+      databases_result.length,
+      1,
+      "The result of databases() should contain one result per database.");
+  assert_true(
+      databases_result[0].name === expected_result.name
+          && databases_result[0].version === expected_result.version,
+      "The result of databases() should be a sequence of the correct names "
+      + "and versions of all databases for the origin.");
 }, "Enumerate one database.");
 
 promise_test(async testCase => {
@@ -28,35 +37,81 @@
   const db1 = await createNamedDatabase(testCase, db_name1, ()=>{});
   const db2 = await createNamedDatabase(testCase, db_name2, ()=>{});
   const db3 = await createNamedDatabase(testCase, db_name3, ()=>{});
-  const databases_promise = await indexedDB.databases();
+  db1.close();
+  db2.close();
+  db3.close();
+  const version_promise =
+      await migrateNamedDatabase(testCase, db_name2, 2, () => {});
+  const databases_result = await indexedDB.databases();
   const expected_result = [
     {"name": db_name1, "version": 1},
-    {"name": db_name2, "version": 1},
+    {"name": db_name2, "version": 2},
     {"name": db_name3, "version": 1},
   ];
-  assert_object_equals(
-    databases_promise,
-    expected_result,
-    "Call to databases() did not retrieve the multiple expected results");
+  assert_equals(
+      databases_result.length,
+      expected_result.length,
+      "The result of databases() should contain one result per database.");
+  for ( let i = 0; i < expected_result.length; i += 1 ) {
+    result = expected_result[i];
+    assert_true(
+        databases_result.some(
+            e => e.name === result.name && e.version === result.version),
+        "The result of databases() should be a sequence of the correct names "
+        + "and versions of all databases for the origin.");
+  }
 }, "Enumerate multiple databases.");
 
 promise_test(async testCase => {
   // Add some databases and close their connections.
-  const db1 = await createNamedDatabase(testCase, "DB1", ()=>{});
-  const db2 = await createNamedDatabase(testCase, "DB2", ()=>{});
-  db1.onversionchange = () => { db1.close() };
-  db2.onversionchange = () => { db2.close() };
+  const db1 = await createNamedDatabase(testCase, "DB1", () => {});
+  const db2 = await createNamedDatabase(testCase, "DB2", () => {});
+  db1.close();
+  db2.close();
 
   // Delete any databases that may not have been cleaned up after previous test
   // runs as well as the two databases made above.
   await deleteAllDatabases(testCase);
 
   // Make sure the databases are no longer returned.
-  const databases_promise = await indexedDB.databases();
-  assert_object_equals(
-    databases_promise,
-    [],
-    "Call to databases() found database it should not have.")
+  const databases_result = await indexedDB.databases();
+  assert_equals(
+      databases_result.length,
+      0,
+      "The result of databases() should be an empty sequence for the case of "
+      + "no databases for the origin.");
 }, "Make sure an empty list is returned for the case of no databases.");
 
-done();
+promise_test(async testCase => {
+  // Delete any databases that may not have been cleaned up after previous test
+  // runs as well as the two databases made above.
+  await deleteAllDatabases(testCase);
+
+  const db1 = await createNamedDatabase(testCase, "DB1", ()=>{});
+  const db2 = await createNamedDatabase(testCase, "DB2", async () => {
+    const databases_result1 = await indexedDB.databases();
+    assert_equals(
+        databases_result1.length,
+        1,
+        "The result of databases() should be only those databases which have "
+        + "been created at the time of calling, regardless of versionchange "
+        + "transactions currently running.");
+  });
+  db1.close();
+  db2.close();
+  const databases_result2 = await indexedDB.databases();
+  assert_equals(
+      databases_result2.length,
+      2,
+      "The result of databases() should include all databases which have "
+      + "been created at the time of calling.");
+  await migrateNamedDatabase(testCase, "DB2", 2, async () => {
+    const databases_result3 = await indexedDB.databases();
+    assert_true(
+        databases_result3[0].version === 1
+        && databases_result3[1].version === 1,
+        "The result of databases() should contain the versions of databases "
+        + "at the time of calling, regardless of versionchange transactions "
+        + "currently running.");
+  });
+}, "Ensure that databases() doesn't pick up changes that haven't commited.");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/idl/idlharness.tentative.https.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/idl/idlharness.tentative.https.window-expected.txt
index e5d18e75c..4a16e4f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/idl/idlharness.tentative.https.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/idl/idlharness.tentative.https.window-expected.txt
@@ -179,5 +179,6 @@
 PASS BluetoothUUID interface: operation canonicalUUID(unsigned long)
 PASS Navigator interface: attribute bluetooth
 PASS Navigator interface: navigator must inherit property "bluetooth" with the proper type
+PASS WorkerNavigator interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/common/performance-timeline-utils.js b/third_party/WebKit/LayoutTests/external/wpt/common/performance-timeline-utils.js
index 6845d6cb..3efce5b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/common/performance-timeline-utils.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/common/performance-timeline-utils.js
@@ -42,3 +42,10 @@
     }
   })
 }
+
+function delayedLoadListener(callback) {
+  window.addEventListener('load', function() {
+    // TODO(cvazac) Remove this setTimeout when spec enforces sync entries.
+    step_timeout(callback, 0)
+  })
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/compat/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/compat/idlharness.window-expected.txt
index 6deefcc..0104eb3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/compat/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/compat/idlharness.window-expected.txt
@@ -8,5 +8,6 @@
 FAIL Window interface: attribute onorientationchange assert_own_property: The global object must have a property "onorientationchange" expected property "onorientationchange" missing
 FAIL Window interface: window must inherit property "orientation" with the proper type assert_own_property: expected property "orientation" missing
 FAIL Window interface: window must inherit property "onorientationchange" with the proper type assert_own_property: expected property "onorientationchange" missing
+PASS WorkerGlobalScope interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-bottom.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-bottom.html
new file mode 100644
index 0000000..9dfc1963
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-bottom.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-margin-bottom">
+<style>
+  #container { overflow:hidden; background:blue; }
+  #container > div { margin-bottom:50%; height:50px; }
+</style>
+<p>There should be a blue square below.</p>
+<div id="container" style="width:456px;" data-expected-width="100" data-expected-height="100">
+  <div></div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+  document.body.offsetTop;
+  document.getElementById("container").style.width = "100px";
+  checkLayout("#container");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-left.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-left.html
new file mode 100644
index 0000000..aa077d9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-left.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-margin-left">
+<style>
+  #container > div { margin-left:50%; height:100px; background:blue; }
+</style>
+<p>There should be a blue square below.</p>
+<div id="container" style="width:456px;">
+  <div data-expected-width="100" data-expected-height="100"></div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+  document.body.offsetTop;
+  document.getElementById("container").style.width = "200px";
+  checkLayout("#container");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-right.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-right.html
new file mode 100644
index 0000000..9ae84bd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-right.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-margin-right">
+<style>
+  #container > div { margin-right:50%; height:100px; background:blue; }
+</style>
+<p>There should be a blue square below.</p>
+<div id="container" style="width:456px;">
+  <div data-expected-width="100" data-expected-height="100"></div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+  document.body.offsetTop;
+  document.getElementById("container").style.width = "200px";
+  checkLayout("#container");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-top.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-top.html
new file mode 100644
index 0000000..7698f27
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-margin-top.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-margin-top">
+<style>
+  #container { overflow:hidden; background:blue; }
+  #container > div { margin-top:50%; height:50px; }
+</style>
+<p>There should be a blue square below.</p>
+<div id="container" style="width:456px;" data-expected-width="100" data-expected-height="100">
+  <div></div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+  document.body.offsetTop;
+  document.getElementById("container").style.width = "100px";
+  checkLayout("#container");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-bottom.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-bottom.html
new file mode 100644
index 0000000..5eea503
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-bottom.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-padding-bottom">
+<style>
+  #container > div { padding-bottom:10%; width:100px; height:50px; background:blue; }
+</style>
+<p>There should be a blue square below.</p>
+<div id="container" style="width:123px;">
+  <div data-expected-width="100" data-expected-height="100"></div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+  document.body.offsetTop;
+  document.getElementById("container").style.width = "500px";
+  checkLayout("#container");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-left.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-left.html
new file mode 100644
index 0000000..0f793e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-left.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-padding-left">
+<style>
+  #container > div { padding-left:10%; width:50px; height:100px; background:blue; }
+</style>
+<p>There should be a blue square below.</p>
+<div id="container" style="width:123px;">
+  <div data-expected-width="100" data-expected-height="100"></div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+  document.body.offsetTop;
+  document.getElementById("container").style.width = "500px";
+  checkLayout("#container");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-right.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-right.html
new file mode 100644
index 0000000..28fd959
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-right.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-padding-right">
+<style>
+  #container > div { padding-right:10%; width:50px; height:100px; background:blue; }
+</style>
+<p>There should be a blue square below.</p>
+<div id="container" style="width:123px;">
+  <div data-expected-width="100" data-expected-height="100"></div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+  document.body.offsetTop;
+  document.getElementById("container").style.width = "500px";
+  checkLayout("#container");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-top.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-top.html
new file mode 100644
index 0000000..f30ace92
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/containing-block-percent-padding-top.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#propdef-padding-top">
+<style>
+  #container > div { padding-top:10%; width:100px; height:50px; background:blue; }
+</style>
+<p>There should be a blue square below.</p>
+<div id="container" style="width:123px;">
+  <div data-expected-width="100" data-expected-height="100"></div>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+  document.body.offsetTop;
+  document.getElementById("container").style.width = "500px";
+  checkLayout("#container");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/idlharness-expected.txt
new file mode 100644
index 0000000..50b4cddb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/idlharness-expected.txt
@@ -0,0 +1,75 @@
+This is a testharness.js-based test.
+Found 71 tests; 62 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS idl_test setup
+PASS Partial interface CSSRule: original interface defined
+PASS Partial interface mixin GlobalEventHandlers: original interface mixin defined
+PASS AnimationEvent interface: existence and properties of interface object
+PASS AnimationEvent interface object length
+PASS AnimationEvent interface object name
+PASS AnimationEvent interface: existence and properties of interface prototype object
+PASS AnimationEvent interface: existence and properties of interface prototype object's "constructor" property
+PASS AnimationEvent interface: existence and properties of interface prototype object's @@unscopables property
+PASS AnimationEvent interface: attribute animationName
+PASS AnimationEvent interface: attribute elapsedTime
+PASS AnimationEvent interface: attribute pseudoElement
+PASS AnimationEvent must be primary interface of new AnimationEvent("animationstart")
+PASS Stringification of new AnimationEvent("animationstart")
+PASS AnimationEvent interface: new AnimationEvent("animationstart") must inherit property "animationName" with the proper type
+PASS AnimationEvent interface: new AnimationEvent("animationstart") must inherit property "elapsedTime" with the proper type
+PASS AnimationEvent interface: new AnimationEvent("animationstart") must inherit property "pseudoElement" with the proper type
+PASS CSSKeyframeRule interface: existence and properties of interface object
+PASS CSSKeyframeRule interface object length
+PASS CSSKeyframeRule interface object name
+PASS CSSKeyframeRule interface: existence and properties of interface prototype object
+PASS CSSKeyframeRule interface: existence and properties of interface prototype object's "constructor" property
+PASS CSSKeyframeRule interface: existence and properties of interface prototype object's @@unscopables property
+PASS CSSKeyframeRule interface: attribute keyText
+PASS CSSKeyframeRule interface: attribute style
+PASS CSSKeyframeRule must be primary interface of keyframes.cssRules[0]
+PASS Stringification of keyframes.cssRules[0]
+PASS CSSKeyframeRule interface: keyframes.cssRules[0] must inherit property "keyText" with the proper type
+PASS CSSKeyframeRule interface: keyframes.cssRules[0] must inherit property "style" with the proper type
+PASS CSSRule interface: keyframes.cssRules[0] must inherit property "KEYFRAMES_RULE" with the proper type
+PASS CSSRule interface: keyframes.cssRules[0] must inherit property "KEYFRAME_RULE" with the proper type
+PASS CSSKeyframesRule interface: existence and properties of interface object
+PASS CSSKeyframesRule interface object length
+PASS CSSKeyframesRule interface object name
+PASS CSSKeyframesRule interface: existence and properties of interface prototype object
+PASS CSSKeyframesRule interface: existence and properties of interface prototype object's "constructor" property
+PASS CSSKeyframesRule interface: existence and properties of interface prototype object's @@unscopables property
+PASS CSSKeyframesRule interface: attribute name
+PASS CSSKeyframesRule interface: attribute cssRules
+PASS CSSKeyframesRule interface: operation appendRule(CSSOMString)
+PASS CSSKeyframesRule interface: operation deleteRule(CSSOMString)
+PASS CSSKeyframesRule interface: operation findRule(CSSOMString)
+PASS CSSKeyframesRule must be primary interface of keyframes
+PASS Stringification of keyframes
+PASS CSSKeyframesRule interface: keyframes must inherit property "name" with the proper type
+PASS CSSKeyframesRule interface: keyframes must inherit property "cssRules" with the proper type
+PASS CSSKeyframesRule interface: keyframes must inherit property "appendRule(CSSOMString)" with the proper type
+PASS CSSKeyframesRule interface: calling appendRule(CSSOMString) on keyframes with too few arguments must throw TypeError
+PASS CSSKeyframesRule interface: keyframes must inherit property "deleteRule(CSSOMString)" with the proper type
+PASS CSSKeyframesRule interface: calling deleteRule(CSSOMString) on keyframes with too few arguments must throw TypeError
+PASS CSSKeyframesRule interface: keyframes must inherit property "findRule(CSSOMString)" with the proper type
+PASS CSSKeyframesRule interface: calling findRule(CSSOMString) on keyframes with too few arguments must throw TypeError
+PASS CSSRule interface: keyframes must inherit property "KEYFRAMES_RULE" with the proper type
+PASS CSSRule interface: keyframes must inherit property "KEYFRAME_RULE" with the proper type
+FAIL HTMLElement interface: attribute onanimationstart assert_true: The prototype object must have a property "onanimationstart" expected true got false
+FAIL HTMLElement interface: attribute onanimationiteration assert_true: The prototype object must have a property "onanimationiteration" expected true got false
+FAIL HTMLElement interface: attribute onanimationend assert_true: The prototype object must have a property "onanimationend" expected true got false
+FAIL HTMLElement interface: attribute onanimationcancel assert_true: The prototype object must have a property "onanimationcancel" expected true got false
+PASS Window interface: attribute onanimationstart
+PASS Window interface: attribute onanimationiteration
+PASS Window interface: attribute onanimationend
+FAIL Window interface: attribute onanimationcancel assert_own_property: The global object must have a property "onanimationcancel" expected property "onanimationcancel" missing
+PASS WorkerGlobalScope interface: existence and properties of interface object
+FAIL Document interface: attribute onanimationstart assert_true: The prototype object must have a property "onanimationstart" expected true got false
+FAIL Document interface: attribute onanimationiteration assert_true: The prototype object must have a property "onanimationiteration" expected true got false
+FAIL Document interface: attribute onanimationend assert_true: The prototype object must have a property "onanimationend" expected true got false
+FAIL Document interface: attribute onanimationcancel assert_true: The prototype object must have a property "onanimationcancel" expected true got false
+PASS CSSRule interface: constant KEYFRAMES_RULE on interface object
+PASS CSSRule interface: constant KEYFRAMES_RULE on interface prototype object
+PASS CSSRule interface: constant KEYFRAME_RULE on interface object
+PASS CSSRule interface: constant KEYFRAME_RULE on interface prototype object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/parsing/animation-timing-function-valid-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/parsing/animation-timing-function-valid-expected.txt
new file mode 100644
index 0000000..fabf009
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/parsing/animation-timing-function-valid-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS e.style['animation-timing-function'] = "linear" should set the property value
+PASS e.style['animation-timing-function'] = "ease" should set the property value
+PASS e.style['animation-timing-function'] = "ease-in" should set the property value
+PASS e.style['animation-timing-function'] = "ease-out" should set the property value
+PASS e.style['animation-timing-function'] = "ease-in-out" should set the property value
+PASS e.style['animation-timing-function'] = "cubic-bezier(0.1, 0.2, 0.8, 0.9)" should set the property value
+PASS e.style['animation-timing-function'] = "cubic-bezier(0, -2, 1, 3)" should set the property value
+PASS e.style['animation-timing-function'] = "cubic-bezier(0, 0.7, 1, 1.3)" should set the property value
+PASS e.style['animation-timing-function'] = "steps(4, start)" should set the property value
+FAIL e.style['animation-timing-function'] = "steps(2, end)" should set the property value assert_equals: serialization should be canonical expected "steps(2)" but got "steps(2, end)"
+FAIL e.style['animation-timing-function'] = "steps(2, jump-start)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['animation-timing-function'] = "steps(2, jump-end)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['animation-timing-function'] = "steps(2, jump-both)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['animation-timing-function'] = "steps(2, jump-none)" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['animation-timing-function'] = "linear, ease, linear" should set the property value
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/parsing/animation-timing-function-valid.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/parsing/animation-timing-function-valid.html
index 63e28054..7ab823e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/parsing/animation-timing-function-valid.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-animations/parsing/animation-timing-function-valid.html
@@ -23,7 +23,11 @@
 
 
 test_valid_value("animation-timing-function", "steps(4, start)");
-test_valid_value("animation-timing-function", "steps(2, end)");
+test_valid_value("animation-timing-function", "steps(2, end)", "steps(2)");
+test_valid_value("animation-timing-function", "steps(2, jump-start)");
+test_valid_value("animation-timing-function", "steps(2, jump-end)", "steps(2)");
+test_valid_value("animation-timing-function", "steps(2, jump-both)");
+test_valid_value("animation-timing-function", "steps(2, jump-none)");
 
 test_valid_value("animation-timing-function", "linear, ease, linear");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/META.yml b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/META.yml
new file mode 100644
index 0000000..2c412b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/META.yml
@@ -0,0 +1,4 @@
+spec: https://drafts.csswg.org/css-easing/
+suggested_reviewers:
+  - birtles
+  - BorisChiou
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/cubic-bezier-timing-functions-output-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/cubic-bezier-timing-functions-output-expected.txt
new file mode 100644
index 0000000..8e41c9c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/cubic-bezier-timing-functions-output-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL cubic-bezier easing with input progress greater than 1 assert_approx_equals: The left of the animation should be approximately 98.8706654939602 at 230ms expected 98.8706654939602 +/- 0.01 but got 98.3585
+FAIL cubic-bezier easing with input progress greater than 1 and where the tangent on the upper boundary is infinity assert_approx_equals: The left of the animation should be approximately 106.31755608768113 at 230ms expected 106.31755608768113 +/- 0.01 but got 107.559
+FAIL cubic-bezier easing with input progress less than 0 assert_approx_equals: The left of the animation should be approximately -16.589193103032184 at 10ms expected -16.589193103032184 +/- 0.01 but got -18.0387
+FAIL cubic-bezier easing with input progress less than 0 and where the tangent on the lower boundary is infinity assert_approx_equals: The left of the animation should be approximately -6.317556087681108 at 770ms expected -6.317556087681108 +/- 0.01 but got -7.55879
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/cubic-bezier-timing-functions-output.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/cubic-bezier-timing-functions-output.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/external/wpt/css/css-timing/cubic-bezier-timing-functions-output.html
rename to third_party/WebKit/LayoutTests/external/wpt/css/css-easing/cubic-bezier-timing-functions-output.html
index 5c2003b..168f4cd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/cubic-bezier-timing-functions-output.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/cubic-bezier-timing-functions-output.html
@@ -4,7 +4,7 @@
 content="This test checks the output of Cubic Bézier functions" />
 <title>Tests for the output of Cubic Bézier timing functions</title>
 <link rel="help"
-href="https://drafts.csswg.org/css-timing/#cubic-bezier-timing-functions">
+href="https://drafts.csswg.org/css-easing/#cubic-bezier-timing-functions">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="testcommon.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-output-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-output-expected.txt
new file mode 100644
index 0000000..f36703d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-output-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS step-start easing with input progress greater than 1
+PASS step-start easing with input progress greater than 2
+PASS step-start easing with input progress less than 0
+PASS step-start easing with input progress less than -1
+PASS step-end easing with input progress greater than 1
+PASS step-end easing with input progress greater than 2
+PASS step-end easing with input progress less than 0
+FAIL steps(1, jump-both) easing with input progress greater than 1 Failed to execute 'animate' on 'Element': 'steps(1, jump-both)' is not a valid value for easing
+FAIL steps(1, jump-both) easing with input progress greater than 2 Failed to execute 'animate' on 'Element': 'steps(1, jump-both)' is not a valid value for easing
+FAIL steps(1, jump-both) easing with input progress less than 0 Failed to execute 'animate' on 'Element': 'steps(1, jump-both)' is not a valid value for easing
+FAIL steps(2, jump-none) easing with input progress greater than 1 Failed to execute 'animate' on 'Element': 'steps(2, jump-none)' is not a valid value for easing
+FAIL steps(2, jump-none) easing with input progress greater than 2 Failed to execute 'animate' on 'Element': 'steps(2, jump-none)' is not a valid value for easing
+FAIL steps(2, jump-none) easing with input progress less than 0 Failed to execute 'animate' on 'Element': 'steps(2, jump-none)' is not a valid value for easing
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-output.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-output.html
new file mode 100644
index 0000000..978ac25
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-output.html
@@ -0,0 +1,318 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="assert"
+content="This test checks the output of step timing functions" />
+<title>Tests for the output of step timing functions</title>
+<link rel="help"
+href="https://drafts.csswg.org/css-easing/#step-timing-functions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-start' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values greater than 1 (but always less than 2)
+  // in (0.23368794, 1)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '200px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-start easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-start' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 3, 1, 3)' });
+
+  // The bezier function produces values:
+  // Input           ->  Output
+  // 0.0                 0.0
+  // 0.114 ~ 0.245       1.5~2.0, so current step is 2, jumps is 1 => 2.0
+  // 0.245 ~ 0.6         2.0~2.4, so current step is 3, jumps is 1 => 3.0
+  // 0.6   ~ 0.882       2.4~2.0, so current step is 3, jumps is 1 => 3.0
+  // 0.882 ~ 0.976       2.0~1.5, so current step is 2, jumps is 1 => 2.0
+  // 1.0                 1.0
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 114;
+  assert_equals(getComputedStyle(target).left, '200px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '300px');
+  anim.currentTime = 900;
+  assert_equals(getComputedStyle(target).left, '200px');
+}, 'step-start easing with input progress greater than 2');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-start' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+
+  // The bezier function produces negative values (but always greater than -1)
+  // in (0, 0.766312060)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 750;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 800;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-start easing with input progress less than 0');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-start' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -2, 1, -2)' });
+
+  // The bezier function produces values less than -1 (but always greater than
+  // -2) in the range (~0.118, ~0.755)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 100;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '-100px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-start easing with input progress less than -1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-end' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values greater than 1 (but always less than 2)
+  // in (0.23368794, 1)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-end easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-end' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 3, 1, 3)' });
+
+  // The bezier function produces values:
+  // Input           ->  Output
+  // 0.0                 0.0
+  // 0.114 ~ 0.245       1.5~2.0, so current step is 1, jumps is 1 => 1.0
+  // 0.245 ~ 0.6         2.0~2.4, so current step is 2, jumps is 1 => 2.0
+  // 0.6   ~ 0.882       2.4~2.0, so current step is 2, jumps is 1 => 2.0
+  // 0.882 ~ 0.976       2.0~1.5, so current step is 1, jumps is 1 => 1.0
+  // 1.0                 1.0
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 114;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '200px');
+  anim.currentTime = 900;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-end easing with input progress greater than 2');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-end' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+
+  // The bezier function produces negative values (but always greater than -1)
+  // in (0, 0.766312060)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 750;
+  assert_equals(getComputedStyle(target).left, '-100px');
+  anim.currentTime = 800;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-end easing with input progress less than 0');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values greater than 1 (but always less than 2)
+  // in (0.23368794, 1)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(1, jump-both) easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 3, 1, 3)' });
+
+  // The bezier function produces values:
+  // Input           ->  Output
+  // 0.0                 0.0,     so current step is 1, jumps is 2 => 0.5
+  // 0.114 ~ 0.245       1.5~2.0, so current step is 2, jumps is 2 => 1.0
+  // 0.245 ~ 0.6         2.0~2.4, so current step is 3, jumps is 2 => 1.5
+  // 0.6   ~ 0.882       2.4~2.0, so current step is 3, jumps is 2 => 1.5
+  // 0.882 ~ 0.976       2.0~1.5, so current step is 2, jumps is 2 => 1.0
+  // 1.0                 1.0
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 114;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '150px');
+  anim.currentTime = 900;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(1, jump-both) easing with input progress greater than 2');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+
+  // The bezier function produces negative values (but always greater than -0.5)
+  // in (0, 0.766312060).
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 750;
+  // current step is 0, jumps is 2.
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 800;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(1, jump-both) easing with input progress less than 0');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values between 0.5 and 1 in
+  // (~0.0442, 0.23368), and values between 1 and 2 in (0.23368794, 1).
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 45;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '200px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(2, jump-none) easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 3, 1, 3)' });
+
+  // The bezier function produces values:
+  // Input           ->  Output
+  // 0.0                 0.0,     so current step is 0, jumps is 1 => 0.0
+  // 0.114 ~ 0.245       1.5~2.0, so current step is 3, jumps is 1 => 3.0
+  // 0.245 ~ 0.6         2.0~2.4, so current step is 4, jumps is 1 => 4.0
+  // 0.6   ~ 0.882       2.4~2.0, so current step is 4, jumps is 1 => 4.0
+  // 0.882 ~ 0.976       2.0~1.5, so current step is 3, jumps is 1 => 3.0
+  // 1.0                 1.0
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 114;
+  assert_equals(getComputedStyle(target).left, '300px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '400px');
+  anim.currentTime = 900;
+  assert_equals(getComputedStyle(target).left, '300px');
+}, 'steps(2, jump-none) easing with input progress greater than 2');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+
+  // The bezier function produces negative values (but always greater than -0.5)
+  // in (0, 0.766312060).
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 750;
+  // current step is -1, jumps is 1.
+  assert_equals(getComputedStyle(target).left, '-100px');
+  anim.currentTime = 800;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(2, jump-none) easing with input progress less than 0');
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-syntax-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-syntax-expected.txt
new file mode 100644
index 0000000..34dcb6b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-syntax-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+FAIL e.style['animation-timing-function'] = "step-start" should set the property value assert_equals: serialization should be canonical expected "steps(1, start)" but got "step-start"
+FAIL e.style['animation-timing-function'] = "step-end" should set the property value assert_equals: serialization should be canonical expected "steps(1)" but got "step-end"
+PASS e.style['animation-timing-function'] = "steps(1, start)" should set the property value
+FAIL e.style['animation-timing-function'] = "steps(1, end)" should set the property value assert_equals: serialization should be canonical expected "steps(1)" but got "steps(1, end)"
+FAIL e.style['animation-timing-function'] = "steps(1, jump-start)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['animation-timing-function'] = "steps(1, jump-end)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['animation-timing-function'] = "steps(1, jump-both)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['animation-timing-function'] = "steps(2, jump-none)" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['animation-timing-function'] = "steps(0, start)" should not set the property value
+PASS e.style['animation-timing-function'] = "steps(0, end)" should not set the property value
+PASS e.style['animation-timing-function'] = "steps(0, jump-start)" should not set the property value
+PASS e.style['animation-timing-function'] = "steps(0, jump-end)" should not set the property value
+PASS e.style['animation-timing-function'] = "steps(0, jump-both)" should not set the property value
+PASS e.style['animation-timing-function'] = "steps(1, jump-none)" should not set the property value
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-syntax.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-syntax.html
new file mode 100644
index 0000000..4e8b21e4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/step-timing-functions-syntax.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="assert"
+content="This test checks the syntax output of step timing functions" />
+<title>Step timing function syntax tests</title>
+<link rel="help"
+      href="https://drafts.csswg.org/css-easing-1/#step-timing-functions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="testcommon.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+"use strict";
+
+test_valid_value("animation-timing-function", "step-start", "steps(1, start)");
+test_valid_value("animation-timing-function", "step-end", "steps(1)");
+test_valid_value("animation-timing-function", "steps(1, start)");
+test_valid_value("animation-timing-function", "steps(1, end)", "steps(1)");
+test_valid_value("animation-timing-function", "steps(1, jump-start)");
+test_valid_value("animation-timing-function", "steps(1, jump-end)", "steps(1)");
+test_valid_value("animation-timing-function", "steps(1, jump-both)");
+test_valid_value("animation-timing-function", "steps(2, jump-none)");
+
+test_invalid_value("animation-timing-function", "steps(0, start)");
+test_invalid_value("animation-timing-function", "steps(0, end)");
+test_invalid_value("animation-timing-function", "steps(0, jump-start)");
+test_invalid_value("animation-timing-function", "steps(0, jump-end)");
+test_invalid_value("animation-timing-function", "steps(0, jump-both)");
+test_invalid_value("animation-timing-function", "steps(1, jump-none)");
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-easing/testcommon.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/css/css-timing/testcommon.js
rename to third_party/WebKit/LayoutTests/external/wpt/css/css-easing/testcommon.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/idlharness-expected.txt
index f188afc0..002bd39 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/idlharness-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/idlharness-expected.txt
@@ -32,5 +32,6 @@
 PASS SVGMaskElement interface: [object SVGMaskElement] must inherit property "y" with the proper type
 PASS SVGMaskElement interface: [object SVGMaskElement] must inherit property "width" with the proper type
 PASS SVGMaskElement interface: [object SVGMaskElement] must inherit property "height" with the proper type
+PASS WorkerGlobalScope interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-pseudo/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-pseudo/idlharness-expected.txt
index 4ccc625..8b356c83 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-pseudo/idlharness-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-pseudo/idlharness-expected.txt
@@ -32,5 +32,6 @@
 FAIL Window interface: operation getPseudoElements(Element, CSSOMString) assert_own_property: global object missing non-static operation expected property "getPseudoElements" missing
 FAIL Window interface: window must inherit property "getPseudoElements(Element, CSSOMString)" with the proper type assert_own_property: expected property "getPseudoElements" missing
 FAIL Window interface: calling getPseudoElements(Element, CSSOMString) on window with too few arguments must throw TypeError assert_own_property: expected property "getPseudoElements" missing
+PASS WorkerGlobalScope interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/META.yml b/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/META.yml
deleted file mode 100644
index 1ee2503..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/META.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-spec: https://drafts.csswg.org/css-timing/
-suggested_reviewers:
-  - birtles
-  - BorisChiou
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/frames-timing-functions-output-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/frames-timing-functions-output-expected.txt
new file mode 100644
index 0000000..7b821e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/frames-timing-functions-output-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL For an input progress of 0.0, the output of a frames timing function is the first frame createDiv is not defined
+FAIL At a frame boundary, the output of a frames timing function is the next frame createDiv is not defined
+FAIL For an input progress of 1.0, the output of a frames timing function is the final frame createDiv is not defined
+FAIL The number of frames is correctly reflected in the frames timing function output createDiv is not defined
+FAIL The number of frames is correctly reflected in the frames timing function output on CSS Transitions createDiv is not defined
+FAIL frames easing with input progress greater than 1 createDiv is not defined
+FAIL frames easing with input progress greater than 1.5 createDiv is not defined
+FAIL frames easing with input progress less than 0 createDiv is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/frames-timing-functions-syntax-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/frames-timing-functions-syntax-expected.txt
new file mode 100644
index 0000000..d101394
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/frames-timing-functions-syntax-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL The number of frames must be a positive integer greater than 1, or we fallback to the previously-set easing createDiv is not defined
+FAIL The serialization of frames is 'frames(n)', n is the number of frames createDiv is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/step-timing-functions-output.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/step-timing-functions-output.html
deleted file mode 100644
index 9a2aa507c..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-timing/step-timing-functions-output.html
+++ /dev/null
@@ -1,141 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<meta name="assert"
-content="This test checks the output of step timing functions" />
-<title>Tests for the output of step timing functions</title>
-<link rel="help"
-href="https://drafts.csswg.org/css-timing/#step-timing-functions">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-'use strict';
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-start' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
-
-  // The bezier function produces values greater than 1 (but always less than 2)
-  // in (0.23368794, 1)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 230;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 250;
-  assert_equals(getComputedStyle(target).left, '200px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-start easing with input progress greater than 1');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-end' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
-
-  // The bezier function produces values greater than 1 (but always less than 2)
-  // in (0.23368794, 1)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 230;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 250;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-end easing with input progress greater than 1');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-end' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, 3, 1, 3)' });
-
-  // The bezier function produces values greater than 2 (but always less than 3)
-  // in the range (~0.245, ~0.882)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 500;
-  assert_equals(getComputedStyle(target).left, '200px');
-  anim.currentTime = 900;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-end easing with input progress greater than 2');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-start' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
-
-  // The bezier function produces negative values (but always greater than -1)
-  // in (0, 0.766312060)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 750;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 800;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-start easing with input progress less than 0');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-start' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, -2, 1, -2)' });
-
-  // The bezier function produces values less than -1 (but always greater than
-  // -2) in the range (~0.118, ~0.755)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 100;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 500;
-  assert_equals(getComputedStyle(target).left, '-100px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-start easing with input progress less than -1');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-end' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
-
-  // The bezier function produces negative values (but always greater than -1)
-  // in (0, 0.766312060)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 750;
-  assert_equals(getComputedStyle(target).left, '-100px');
-  anim.currentTime = 800;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-end easing with input progress less than 0');
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/idlharness-expected.txt
new file mode 100644
index 0000000..74256a1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/idlharness-expected.txt
@@ -0,0 +1,44 @@
+This is a testharness.js-based test.
+PASS idl_test setup
+PASS Partial interface GlobalEventHandlers: original interface defined
+PASS TransitionEvent interface: existence and properties of interface object
+PASS TransitionEvent interface object length
+PASS TransitionEvent interface object name
+PASS TransitionEvent interface: existence and properties of interface prototype object
+PASS TransitionEvent interface: existence and properties of interface prototype object's "constructor" property
+PASS TransitionEvent interface: existence and properties of interface prototype object's @@unscopables property
+PASS TransitionEvent interface: attribute propertyName
+PASS TransitionEvent interface: attribute elapsedTime
+PASS TransitionEvent interface: attribute pseudoElement
+PASS TransitionEvent must be primary interface of new TransitionEvent("transitionend")
+PASS Stringification of new TransitionEvent("transitionend")
+PASS TransitionEvent interface: new TransitionEvent("transitionend") must inherit property "propertyName" with the proper type
+PASS TransitionEvent interface: new TransitionEvent("transitionend") must inherit property "elapsedTime" with the proper type
+PASS TransitionEvent interface: new TransitionEvent("transitionend") must inherit property "pseudoElement" with the proper type
+FAIL HTMLElement interface: attribute ontransitionrun assert_true: The prototype object must have a property "ontransitionrun" expected true got false
+FAIL HTMLElement interface: attribute ontransitionstart assert_true: The prototype object must have a property "ontransitionstart" expected true got false
+FAIL HTMLElement interface: attribute ontransitionend assert_true: The prototype object must have a property "ontransitionend" expected true got false
+FAIL HTMLElement interface: attribute ontransitioncancel assert_true: The prototype object must have a property "ontransitioncancel" expected true got false
+FAIL HTMLElement interface: document must inherit property "ontransitionrun" with the proper type assert_inherits: property "ontransitionrun" not found in prototype chain
+FAIL HTMLElement interface: document must inherit property "ontransitionstart" with the proper type assert_inherits: property "ontransitionstart" not found in prototype chain
+FAIL HTMLElement interface: document must inherit property "ontransitionend" with the proper type assert_inherits: property "ontransitionend" not found in prototype chain
+FAIL HTMLElement interface: document must inherit property "ontransitioncancel" with the proper type assert_inherits: property "ontransitioncancel" not found in prototype chain
+FAIL Window interface: attribute ontransitionrun assert_own_property: The global object must have a property "ontransitionrun" expected property "ontransitionrun" missing
+FAIL Window interface: attribute ontransitionstart assert_own_property: The global object must have a property "ontransitionstart" expected property "ontransitionstart" missing
+PASS Window interface: attribute ontransitionend
+FAIL Window interface: attribute ontransitioncancel assert_own_property: The global object must have a property "ontransitioncancel" expected property "ontransitioncancel" missing
+FAIL Window interface: window must inherit property "ontransitionrun" with the proper type assert_own_property: expected property "ontransitionrun" missing
+FAIL Window interface: window must inherit property "ontransitionstart" with the proper type assert_own_property: expected property "ontransitionstart" missing
+PASS Window interface: window must inherit property "ontransitionend" with the proper type
+FAIL Window interface: window must inherit property "ontransitioncancel" with the proper type assert_own_property: expected property "ontransitioncancel" missing
+PASS WorkerGlobalScope interface: existence and properties of interface object
+FAIL Document interface: attribute ontransitionrun assert_true: The prototype object must have a property "ontransitionrun" expected true got false
+FAIL Document interface: attribute ontransitionstart assert_true: The prototype object must have a property "ontransitionstart" expected true got false
+FAIL Document interface: attribute ontransitionend assert_true: The prototype object must have a property "ontransitionend" expected true got false
+FAIL Document interface: attribute ontransitioncancel assert_true: The prototype object must have a property "ontransitioncancel" expected true got false
+FAIL Document interface: document must inherit property "ontransitionrun" with the proper type assert_inherits: property "ontransitionrun" not found in prototype chain
+FAIL Document interface: document must inherit property "ontransitionstart" with the proper type assert_inherits: property "ontransitionstart" not found in prototype chain
+FAIL Document interface: document must inherit property "ontransitionend" with the proper type assert_inherits: property "ontransitionend" not found in prototype chain
+FAIL Document interface: document must inherit property "ontransitioncancel" with the proper type assert_inherits: property "ontransitioncancel" not found in prototype chain
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-invalid.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-invalid.html
index 936defa..00bd213 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-invalid.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-invalid.html
@@ -4,7 +4,7 @@
 <meta charset="utf-8">
 <title>CSS Animations: parsing transition-timing-function with invalid values</title>
 <link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function">
-<link rel="help" href="https://drafts.csswg.org/css-timing-1/#typedef-timing-function">
+<link rel="help" href="https://drafts.csswg.org/css-easing-1/#typedef-timing-function">
 <meta name="assert" content="transition-timing-function supports only the grammar '<timing-function> #'.">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-valid-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-valid-expected.txt
new file mode 100644
index 0000000..8e64c2a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-valid-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS e.style['transition-timing-function'] = "linear" should set the property value
+PASS e.style['transition-timing-function'] = "ease" should set the property value
+PASS e.style['transition-timing-function'] = "ease-in" should set the property value
+PASS e.style['transition-timing-function'] = "ease-out" should set the property value
+PASS e.style['transition-timing-function'] = "ease-in-out" should set the property value
+PASS e.style['transition-timing-function'] = "cubic-bezier(0.1, 0.2, 0.8, 0.9)" should set the property value
+PASS e.style['transition-timing-function'] = "cubic-bezier(0, -2, 1, 3)" should set the property value
+PASS e.style['transition-timing-function'] = "cubic-bezier(0, 0.7, 1, 1.3)" should set the property value
+PASS e.style['transition-timing-function'] = "steps(4, start)" should set the property value
+FAIL e.style['transition-timing-function'] = "steps(2, end)" should set the property value assert_equals: serialization should be canonical expected "steps(2)" but got "steps(2, end)"
+FAIL e.style['transition-timing-function'] = "steps(2, jump-start)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['transition-timing-function'] = "steps(2, jump-end)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['transition-timing-function'] = "steps(2, jump-both)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['transition-timing-function'] = "steps(2, jump-none)" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['transition-timing-function'] = "linear, ease, linear" should set the property value
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-valid.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-valid.html
index e11ef000..2e2c182 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-valid.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/parsing/transition-timing-function-valid.html
@@ -4,7 +4,7 @@
 <meta charset="utf-8">
 <title>CSS Transitions: parsing transition-timing-function with valid values</title>
 <link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function">
-<link rel="help" href="https://drafts.csswg.org/css-timing-1/#typedef-timing-function">
+<link rel="help" href="https://drafts.csswg.org/css-easing-1/#typedef-timing-function">
 <meta name="assert" content="transition-timing-function supports the full grammar '<timing-function> #'.">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
@@ -23,7 +23,11 @@
 test_valid_value("transition-timing-function", "cubic-bezier(0, 0.7, 1, 1.3)");
 
 test_valid_value("transition-timing-function", "steps(4, start)");
-test_valid_value("transition-timing-function", "steps(2, end)");
+test_valid_value("transition-timing-function", "steps(2, end)", "steps(2)");
+test_valid_value("transition-timing-function", "steps(2, jump-start)");
+test_valid_value("transition-timing-function", "steps(2, jump-end)", "steps(2)");
+test_valid_value("transition-timing-function", "steps(2, jump-both)");
+test_valid_value("transition-timing-function", "steps(2, jump-none)");
 
 test_valid_value("transition-timing-function", "linear, ease, linear");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/transition-timing-function-001-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/transition-timing-function-001-expected.txt
index 42c2701..7adb708 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/transition-timing-function-001-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/transition-timing-function-001-expected.txt
@@ -12,11 +12,19 @@
 PASS parse 'steps(3, start)'
 FAIL parse 'steps(3, end)' assert_equals: Expected computed value expected "steps(3)" but got "steps(3, end)"
 FAIL parse 'steps(3)' assert_equals: Expected computed value expected "steps(3)" but got "steps(3, end)"
+FAIL parse 'steps(3, jump-start)' assert_equals: Expected computed value expected "steps(3, jump-start)" but got "ease"
+FAIL parse 'steps(3, jump-end)' assert_equals: Expected computed value expected "steps(3)" but got "ease"
+FAIL parse 'steps(3, jump-both)' assert_equals: Expected computed value expected "steps(3, jump-both)" but got "ease"
+FAIL parse 'steps(3, jump-none)' assert_equals: Expected computed value expected "steps(3, jump-none)" but got "ease"
 PASS parse 'cubic-bezier(foobar)'
 PASS parse 'steps(foobar)'
 PASS parse 'steps(3.3, end)'
 PASS parse 'steps(3, top)'
 PASS parse 'steps(-3, top)'
+PASS parse 'steps(0, jump-start)'
+PASS parse 'steps(0, jump-end)'
+PASS parse 'steps(0, jump-both)'
+PASS parse 'steps(1, jump-none)'
 PASS parse 'cubic-bezier(-0.1, -0.2, -0.3, -0.4)'
 PASS parse 'cubic-bezier(1.1, 1.2, 1.3, 1.4)'
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/transition-timing-function-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/transition-timing-function-001.html
index 7566545..4c9598f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/transition-timing-function-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transitions/transition-timing-function-001.html
@@ -42,12 +42,20 @@
                 'steps(3, start)': 'steps(3, start)',
                 'steps(3, end)': 'steps(3)',
                 'steps(3)': 'steps(3)',
+                'steps(3, jump-start)': 'steps(3, jump-start)',
+                'steps(3, jump-end)': 'steps(3)',
+                'steps(3, jump-both)': 'steps(3, jump-both)',
+                'steps(3, jump-none)': 'steps(3, jump-none)',
                 // invalid
                 'cubic-bezier(foobar)': defaultValue,
                 'steps(foobar)': defaultValue,
                 'steps(3.3, end)': defaultValue,
                 'steps(3, top)': defaultValue,
                 'steps(-3, top)': defaultValue,
+                'steps(0, jump-start)': defaultValue,
+                'steps(0, jump-end)': defaultValue,
+                'steps(0, jump-both)': defaultValue,
+                'steps(1, jump-none)': defaultValue,
                 // Both x values must be in the range [0, 1]
                 'cubic-bezier(-0.1, -0.2, -0.3, -0.4)': defaultValue,
                 'cubic-bezier(1.1, 1.2, 1.3, 1.4)': defaultValue
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/interfaces-expected.txt
index 20b1327..7c325976 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 436 tests; 405 PASS, 31 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 439 tests; 406 PASS, 33 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface Element: original interface defined
 PASS Partial interface CSSStyleRule: original interface defined
@@ -453,6 +453,9 @@
 PASS CSS namespace: operation dpcm(double)
 PASS CSS namespace: operation dppx(double)
 PASS CSS namespace: operation fr(double)
+FAIL SVGElement interface: attribute attributeStyleMap assert_own_property: expected property "attributeStyleMap" missing
+FAIL HTMLElement interface: attribute attributeStyleMap assert_own_property: expected property "attributeStyleMap" missing
+PASS WorkerGlobalScope interface: existence and properties of interface object
 PASS Element interface: operation computedStyleMap()
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces-expected.txt
index 62a5805..97749137 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 325 tests; 246 PASS, 79 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 326 tests; 247 PASS, 79 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface Window: original interface defined
 PASS Partial interface Document: original interface defined
@@ -233,6 +233,7 @@
 PASS Window interface: window must inherit property "outerWidth" with the proper type
 PASS Window interface: window must inherit property "outerHeight" with the proper type
 PASS Window interface: window must inherit property "devicePixelRatio" with the proper type
+PASS WorkerGlobalScope interface: existence and properties of interface object
 PASS Document interface: operation elementFromPoint(double, double)
 PASS Document interface: operation elementsFromPoint(double, double)
 FAIL Document interface: operation caretPositionFromPoint(double, double) assert_own_property: interface prototype object missing non-static operation expected property "caretPositionFromPoint" missing
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces-expected.txt
index a83ae3f..706e87a3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 376 tests; 321 PASS, 55 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 377 tests; 322 PASS, 55 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface Document: original interface defined
 PASS Partial interface Window: original interface defined
@@ -371,6 +371,7 @@
 PASS Window interface: operation getComputedStyle(Element, CSSOMString)
 PASS Window interface: window must inherit property "getComputedStyle(Element, CSSOMString)" with the proper type
 PASS Window interface: calling getComputedStyle(Element, CSSOMString) on window with too few arguments must throw TypeError
+PASS WorkerGlobalScope interface: existence and properties of interface object
 PASS Document interface: attribute styleSheets
 PASS Document interface: document must inherit property "styleSheets" with the proper type
 PASS Document interface: new Document() must inherit property "styleSheets" with the proper type
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces_exclude=Node-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces_exclude=Node-expected.txt
index 41fe5fad..33ba630 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces_exclude=Node-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces_exclude=Node-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 1102 tests; 1078 PASS, 24 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 1103 tests; 1079 PASS, 24 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver
 PASS Partial interface Window: original interface defined
 PASS Event interface: existence and properties of interface object
@@ -1102,5 +1102,6 @@
 PASS DOMTokenList interface: calling supports(DOMString) on document.body.classList with too few arguments must throw TypeError
 PASS DOMTokenList interface: document.body.classList must inherit property "value" with the proper type
 FAIL Window interface: attribute event assert_true: property should be enumerable expected true got false
+PASS WorkerGlobalScope interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/domparsing/interfaces.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/domparsing/interfaces.any.worker-expected.txt
index ac6137d..a7bebc63 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/domparsing/interfaces.any.worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/domparsing/interfaces.any.worker-expected.txt
@@ -11,10 +11,16 @@
 FAIL Stringification of new XMLSerializer() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: XMLSerializer is not defined"
 FAIL XMLSerializer interface: new XMLSerializer() must not have property "serializeToString" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: XMLSerializer is not defined"
 PASS Node interface: existence and properties of interface object
+PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
 PASS Element interface: existence and properties of interface object
 FAIL Element interface: document.createElement("div") must not have property "innerHTML" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: document is not defined"
 FAIL Element interface: document.createElement("div") must not have property "outerHTML" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: document is not defined"
 FAIL Element interface: document.createElement("div") must not have property "insertAdjacentHTML" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: document is not defined"
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 PASS AbstractRange interface: existence and properties of interface object
 PASS Range interface: existence and properties of interface object
 FAIL Range interface: new Range() must not have property "createContextualFragment" assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Range is not defined"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/idlharness.window-expected.txt
index 71a041e..c4a5606 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/idlharness.window-expected.txt
@@ -20,6 +20,7 @@
 FAIL FeaturePolicyViolationReportBody interface: attribute columnNumber assert_own_property: self does not have own property "FeaturePolicyViolationReportBody" expected property "FeaturePolicyViolationReportBody" missing
 FAIL FeaturePolicyViolationReportBody interface: attribute disposition assert_own_property: self does not have own property "FeaturePolicyViolationReportBody" expected property "FeaturePolicyViolationReportBody" missing
 PASS HTMLIFrameElement interface: attribute policy
+PASS WorkerGlobalScope interface: existence and properties of interface object
 PASS Document interface: attribute policy
 PASS Document interface: document must inherit property "policy" with the proper type
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any-expected.txt
index c0f63b02..b013c5c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 135 tests; 129 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 139 tests; 133 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
 PASS Headers interface: existence and properties of interface object
@@ -135,5 +135,9 @@
 PASS Response interface: new Response() must inherit property "formData()" with the proper type
 PASS Response interface: new Response() must inherit property "json()" with the proper type
 PASS Response interface: new Response() must inherit property "text()" with the proper type
+PASS Window interface: operation fetch(RequestInfo, RequestInit)
+PASS Window interface: window must inherit property "fetch(RequestInfo, RequestInit)" with the proper type
+PASS Window interface: calling fetch(RequestInfo, RequestInit) on window with too few arguments must throw TypeError
+PASS WorkerGlobalScope interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.serviceworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.serviceworker-expected.txt
index 47b60333..cf90de4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.serviceworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.serviceworker-expected.txt
@@ -134,5 +134,20 @@
 PASS Response interface: new Response() must inherit property "formData()" with the proper type
 PASS Response interface: new Response() must inherit property "json()" with the proper type
 PASS Response interface: new Response() must inherit property "text()" with the proper type
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
+FAIL WorkerGlobalScope interface: operation fetch(RequestInfo, RequestInit) assert_unreached: Should have rejected: calling operation with this = null didn't throw TypeError Reached unreachable code
+FAIL WorkerGlobalScope interface: self must inherit property "fetch(RequestInfo, RequestInit)" with the proper type assert_inherits: property "fetch" found on object expected in prototype chain
+FAIL WorkerGlobalScope interface: calling fetch(RequestInfo, RequestInit) on self with too few arguments must throw TypeError assert_inherits: property "fetch" found on object expected in prototype chain
+PASS HTMLFrameSetElement interface: existence and properties of interface object
+PASS Node interface: existence and properties of interface object
+PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.sharedworker-expected.txt
index c0f63b02..20b02f1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.sharedworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.sharedworker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 135 tests; 129 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 150 tests; 144 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
 PASS Headers interface: existence and properties of interface object
@@ -135,5 +135,20 @@
 PASS Response interface: new Response() must inherit property "formData()" with the proper type
 PASS Response interface: new Response() must inherit property "json()" with the proper type
 PASS Response interface: new Response() must inherit property "text()" with the proper type
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
+PASS WorkerGlobalScope interface: operation fetch(RequestInfo, RequestInit)
+PASS WorkerGlobalScope interface: self must inherit property "fetch(RequestInfo, RequestInit)" with the proper type
+PASS WorkerGlobalScope interface: calling fetch(RequestInfo, RequestInit) on self with too few arguments must throw TypeError
+PASS HTMLFrameSetElement interface: existence and properties of interface object
+PASS Node interface: existence and properties of interface object
+PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.worker-expected.txt
index c0f63b02..20b02f1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/idl.any.worker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 135 tests; 129 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 150 tests; 144 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
 PASS Headers interface: existence and properties of interface object
@@ -135,5 +135,20 @@
 PASS Response interface: new Response() must inherit property "formData()" with the proper type
 PASS Response interface: new Response() must inherit property "json()" with the proper type
 PASS Response interface: new Response() must inherit property "text()" with the proper type
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
+PASS WorkerGlobalScope interface: operation fetch(RequestInfo, RequestInit)
+PASS WorkerGlobalScope interface: self must inherit property "fetch(RequestInfo, RequestInit)" with the proper type
+PASS WorkerGlobalScope interface: calling fetch(RequestInfo, RequestInit) on self with too few arguments must throw TypeError
+PASS HTMLFrameSetElement interface: existence and properties of interface object
+PASS Node interface: existence and properties of interface object
+PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.serviceworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.serviceworker-expected.txt
index 8558fae..2d89b44 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.serviceworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.serviceworker-expected.txt
@@ -2,9 +2,19 @@
 PASS idl_test setup
 PASS Partial interface Document: original interface defined
 PASS Partial interface WorkerGlobalScope: original interface defined
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
 FAIL WorkerGlobalScope interface: attribute addressSpace assert_true: The prototype object must have a property "addressSpace" expected true got false
 FAIL WorkerGlobalScope interface: self must inherit property "addressSpace" with the proper type assert_inherits: property "addressSpace" not found in prototype chain
+PASS HTMLFrameSetElement interface: existence and properties of interface object
 PASS Node interface: existence and properties of interface object
 PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.sharedworker-expected.txt
index 8558fae..2d89b44 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.sharedworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.sharedworker-expected.txt
@@ -2,9 +2,19 @@
 PASS idl_test setup
 PASS Partial interface Document: original interface defined
 PASS Partial interface WorkerGlobalScope: original interface defined
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
 FAIL WorkerGlobalScope interface: attribute addressSpace assert_true: The prototype object must have a property "addressSpace" expected true got false
 FAIL WorkerGlobalScope interface: self must inherit property "addressSpace" with the proper type assert_inherits: property "addressSpace" not found in prototype chain
+PASS HTMLFrameSetElement interface: existence and properties of interface object
 PASS Node interface: existence and properties of interface object
 PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.worker-expected.txt
index 8558fae..2d89b44 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/cors-rfc1918/idlharness.tentative.any.worker-expected.txt
@@ -2,9 +2,19 @@
 PASS idl_test setup
 PASS Partial interface Document: original interface defined
 PASS Partial interface WorkerGlobalScope: original interface defined
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
 FAIL WorkerGlobalScope interface: attribute addressSpace assert_true: The prototype object must have a property "addressSpace" expected true got false
 FAIL WorkerGlobalScope interface: self must inherit property "addressSpace" with the proper type assert_inherits: property "addressSpace" not found in prototype chain
+PASS HTMLFrameSetElement interface: existence and properties of interface object
 PASS Node interface: existence and properties of interface object
 PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/gamepad/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/gamepad/idlharness.window-expected.txt
index 915af064..dc95c50 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/gamepad/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/gamepad/idlharness.window-expected.txt
@@ -36,5 +36,6 @@
 PASS GamepadEvent interface: new GamepadEvent("gamepad") must inherit property "gamepad" with the proper type
 PASS Navigator interface: operation getGamepads()
 PASS Navigator interface: navigator must inherit property "getGamepads()" with the proper type
+PASS WorkerNavigator interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.any.serviceworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.any.serviceworker-expected.txt
new file mode 100644
index 0000000..02975ba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.any.serviceworker-expected.txt
@@ -0,0 +1,34 @@
+This is a testharness.js-based test.
+PASS idl_test setup
+PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
+PASS Performance interface: existence and properties of interface object
+PASS Performance interface object length
+PASS Performance interface object name
+PASS Performance interface: existence and properties of interface prototype object
+PASS Performance interface: existence and properties of interface prototype object's "constructor" property
+PASS Performance interface: existence and properties of interface prototype object's @@unscopables property
+PASS Performance interface: operation now()
+PASS Performance interface: attribute timeOrigin
+PASS Performance interface: operation toJSON()
+PASS Performance must be primary interface of performance
+PASS Stringification of performance
+PASS Performance interface: performance must inherit property "now()" with the proper type
+PASS Performance interface: performance must inherit property "timeOrigin" with the proper type
+PASS Performance interface: performance must inherit property "toJSON()" with the proper type
+PASS Test default toJSON operation of Performance
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
+FAIL WorkerGlobalScope interface: attribute performance assert_equals: setter must be function for PutForwards, Replaceable, or non-readonly attributes expected "function" but got "undefined"
+PASS WorkerGlobalScope interface: self must inherit property "performance" with the proper type
+PASS HTMLFrameSetElement interface: existence and properties of interface object
+PASS Node interface: existence and properties of interface object
+PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.any.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.any.sharedworker-expected.txt
new file mode 100644
index 0000000..02975ba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.any.sharedworker-expected.txt
@@ -0,0 +1,34 @@
+This is a testharness.js-based test.
+PASS idl_test setup
+PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
+PASS Performance interface: existence and properties of interface object
+PASS Performance interface object length
+PASS Performance interface object name
+PASS Performance interface: existence and properties of interface prototype object
+PASS Performance interface: existence and properties of interface prototype object's "constructor" property
+PASS Performance interface: existence and properties of interface prototype object's @@unscopables property
+PASS Performance interface: operation now()
+PASS Performance interface: attribute timeOrigin
+PASS Performance interface: operation toJSON()
+PASS Performance must be primary interface of performance
+PASS Stringification of performance
+PASS Performance interface: performance must inherit property "now()" with the proper type
+PASS Performance interface: performance must inherit property "timeOrigin" with the proper type
+PASS Performance interface: performance must inherit property "toJSON()" with the proper type
+PASS Test default toJSON operation of Performance
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
+FAIL WorkerGlobalScope interface: attribute performance assert_equals: setter must be function for PutForwards, Replaceable, or non-readonly attributes expected "function" but got "undefined"
+PASS WorkerGlobalScope interface: self must inherit property "performance" with the proper type
+PASS HTMLFrameSetElement interface: existence and properties of interface object
+PASS Node interface: existence and properties of interface object
+PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.any.worker-expected.txt
new file mode 100644
index 0000000..02975ba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.any.worker-expected.txt
@@ -0,0 +1,34 @@
+This is a testharness.js-based test.
+PASS idl_test setup
+PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
+PASS Performance interface: existence and properties of interface object
+PASS Performance interface object length
+PASS Performance interface object name
+PASS Performance interface: existence and properties of interface prototype object
+PASS Performance interface: existence and properties of interface prototype object's "constructor" property
+PASS Performance interface: existence and properties of interface prototype object's @@unscopables property
+PASS Performance interface: operation now()
+PASS Performance interface: attribute timeOrigin
+PASS Performance interface: operation toJSON()
+PASS Performance must be primary interface of performance
+PASS Stringification of performance
+PASS Performance interface: performance must inherit property "now()" with the proper type
+PASS Performance interface: performance must inherit property "timeOrigin" with the proper type
+PASS Performance interface: performance must inherit property "toJSON()" with the proper type
+PASS Test default toJSON operation of Performance
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
+FAIL WorkerGlobalScope interface: attribute performance assert_equals: setter must be function for PutForwards, Replaceable, or non-readonly attributes expected "function" but got "undefined"
+PASS WorkerGlobalScope interface: self must inherit property "performance" with the proper type
+PASS HTMLFrameSetElement interface: existence and properties of interface object
+PASS Node interface: existence and properties of interface object
+PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html-media-capture/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html-media-capture/idlharness.window-expected.txt
index c8248ba9..b887ef5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html-media-capture/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html-media-capture/idlharness.window-expected.txt
@@ -3,5 +3,6 @@
 PASS Partial interface HTMLInputElement: original interface defined
 FAIL HTMLInputElement interface: attribute capture assert_true: The prototype object must have a property "capture" expected true got false
 FAIL HTMLInputElement interface: input must inherit property "capture" with the proper type assert_inherits: property "capture" not found in prototype chain
+PASS WorkerGlobalScope interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git "a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.https_exclude=\050Document_Window_HTML._\051-expected.txt" "b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.https_exclude=\050Document_Window_HTML._\051-expected.txt"
index fa4972aa..32ee1e59 100644
--- "a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.https_exclude=\050Document_Window_HTML._\051-expected.txt"
+++ "b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.https_exclude=\050Document_Window_HTML._\051-expected.txt"
@@ -1119,5 +1119,75 @@
 PASS Stringification of window.external
 PASS External interface: window.external must inherit property "AddSearchProvider()" with the proper type
 PASS External interface: window.external must inherit property "IsSearchProviderInstalled()" with the proper type
+PASS SVGElement interface: attribute onabort
+PASS SVGElement interface: attribute onauxclick
+PASS SVGElement interface: attribute onblur
+PASS SVGElement interface: attribute oncancel
+PASS SVGElement interface: attribute oncanplay
+PASS SVGElement interface: attribute oncanplaythrough
+PASS SVGElement interface: attribute onchange
+PASS SVGElement interface: attribute onclick
+PASS SVGElement interface: attribute onclose
+PASS SVGElement interface: attribute oncontextmenu
+PASS SVGElement interface: attribute oncuechange
+PASS SVGElement interface: attribute ondblclick
+PASS SVGElement interface: attribute ondrag
+PASS SVGElement interface: attribute ondragend
+PASS SVGElement interface: attribute ondragenter
+FAIL SVGElement interface: attribute ondragexit assert_true: The prototype object must have a property "ondragexit" expected true got false
+PASS SVGElement interface: attribute ondragleave
+PASS SVGElement interface: attribute ondragover
+PASS SVGElement interface: attribute ondragstart
+PASS SVGElement interface: attribute ondrop
+PASS SVGElement interface: attribute ondurationchange
+PASS SVGElement interface: attribute onemptied
+PASS SVGElement interface: attribute onended
+PASS SVGElement interface: attribute onerror
+PASS SVGElement interface: attribute onfocus
+PASS SVGElement interface: attribute oninput
+PASS SVGElement interface: attribute oninvalid
+PASS SVGElement interface: attribute onkeydown
+PASS SVGElement interface: attribute onkeypress
+PASS SVGElement interface: attribute onkeyup
+PASS SVGElement interface: attribute onload
+PASS SVGElement interface: attribute onloadeddata
+PASS SVGElement interface: attribute onloadedmetadata
+FAIL SVGElement interface: attribute onloadend assert_true: The prototype object must have a property "onloadend" expected true got false
+PASS SVGElement interface: attribute onloadstart
+PASS SVGElement interface: attribute onmousedown
+PASS SVGElement interface: attribute onmouseenter
+PASS SVGElement interface: attribute onmouseleave
+PASS SVGElement interface: attribute onmousemove
+PASS SVGElement interface: attribute onmouseout
+PASS SVGElement interface: attribute onmouseover
+PASS SVGElement interface: attribute onmouseup
+PASS SVGElement interface: attribute onwheel
+PASS SVGElement interface: attribute onpause
+PASS SVGElement interface: attribute onplay
+PASS SVGElement interface: attribute onplaying
+PASS SVGElement interface: attribute onprogress
+PASS SVGElement interface: attribute onratechange
+PASS SVGElement interface: attribute onreset
+PASS SVGElement interface: attribute onresize
+PASS SVGElement interface: attribute onscroll
+FAIL SVGElement interface: attribute onsecuritypolicyviolation assert_true: The prototype object must have a property "onsecuritypolicyviolation" expected true got false
+PASS SVGElement interface: attribute onseeked
+PASS SVGElement interface: attribute onseeking
+PASS SVGElement interface: attribute onselect
+PASS SVGElement interface: attribute onstalled
+PASS SVGElement interface: attribute onsubmit
+PASS SVGElement interface: attribute onsuspend
+PASS SVGElement interface: attribute ontimeupdate
+PASS SVGElement interface: attribute ontoggle
+PASS SVGElement interface: attribute onvolumechange
+PASS SVGElement interface: attribute onwaiting
+PASS SVGElement interface: attribute oncopy
+PASS SVGElement interface: attribute oncut
+PASS SVGElement interface: attribute onpaste
+PASS SVGElement interface: attribute dataset
+PASS SVGElement interface: attribute nonce
+PASS SVGElement interface: attribute tabIndex
+PASS SVGElement interface: operation focus(FocusOptions)
+PASS SVGElement interface: operation blur()
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/fullscreen.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/fullscreen.idl
index 87f15997..491aa7a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/fullscreen.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/fullscreen.idl
@@ -30,6 +30,6 @@
   attribute EventHandler onfullscreenerror;
 };
 
-partial interface DocumentOrShadowRoot {
+partial interface mixin DocumentOrShadowRoot {
   [LenientSetter] readonly attribute Element? fullscreenElement;
 };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl
index 0795c03..baf9ee3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl
@@ -153,7 +153,7 @@
   [NewObject]
   Promise<void> complete(optional PaymentComplete result = "unknown");
   [NewObject]
-  Promise<void> retry(PaymentValidationErrors errorFields);
+  Promise<void> retry(optional PaymentValidationErrors errorFields);
 
   attribute EventHandler onpayerdetailchange;
 };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist b/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist
index 23f2055..3de5698 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist
+++ b/third_party/WebKit/LayoutTests/external/wpt/lint.whitelist
@@ -760,7 +760,7 @@
 MISSING-LINK: css/css-scroll-anchoring/start-edge-in-block-layout-direction.html
 MISSING-LINK: css/css-scroll-anchoring/subtree-exclusion.html
 MISSING-LINK: css/css-scroll-anchoring/wrapped-text.html
-SUPPORT-WRONG-DIR: css/css-timing/testcommon.js
+SUPPORT-WRONG-DIR: css/css-easing/testcommon.js
 MISSING-LINK: css/css-typed-om/CSSMatrixComponent-DOMMatrix-mutable.html
 MISSING-LINK: css/css-typed-om/declared-styleMap-accepts-inherit.html
 SUPPORT-WRONG-DIR: css/cssom/stylesheet-same-origin.css
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/idlharness.window-expected.txt
index e2149ce..1243572 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/idlharness.window-expected.txt
@@ -19,5 +19,6 @@
 PASS HTMLCanvasElement interface: operation captureStream(double)
 PASS HTMLCanvasElement interface: canvas must inherit property "captureStream(double)" with the proper type
 PASS HTMLCanvasElement interface: calling captureStream(double) on canvas with too few arguments must throw TypeError
+PASS WorkerGlobalScope interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt
index da7a86a..aa959031 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt
@@ -162,5 +162,6 @@
 PASS Navigator interface: navigator must inherit property "mediaDevices" with the proper type
 PASS Navigator interface: navigator must inherit property "getUserMedia(MediaStreamConstraints, NavigatorUserMediaSuccessCallback, NavigatorUserMediaErrorCallback)" with the proper type
 PASS Navigator interface: calling getUserMedia(MediaStreamConstraints, NavigatorUserMediaSuccessCallback, NavigatorUserMediaErrorCallback) on navigator with too few arguments must throw TypeError
+PASS WorkerNavigator interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https-expected.txt
new file mode 100644
index 0000000..0f09114
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Tests for PaymentRequest.canMakePayment() method Uncaught TypeError: Cannot set property 'click' of undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https.html
new file mode 100644
index 0000000..b0582d5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests for PaymentRequest.canMakePayment() method</title>
+<link rel="help" href="https://w3c.github.io/browser-payment-api/#show-method">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src='/resources/testdriver-vendor.js'></script>
+<script src="/resources/testdriver.js"></script>
+<script>
+const basicCard = Object.freeze({ supportedMethods: "basic-card" });
+const applePay = Object.freeze({ supportedMethods: "https://apple.com/apple-pay" });
+const defaultMethods = Object.freeze([basicCard, applePay]);
+const defaultDetails = Object.freeze({
+  total: {
+    label: "Total",
+    amount: {
+      currency: "USD",
+      value: "1.00",
+    },
+  },
+});
+
+promise_test(async t => {
+  // This test might never actually hit its assertion, but that's allowed.
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  for (let i = 0; i < 1000; i++) {
+    try {
+      await request.canMakePayment();
+    } catch (err) {
+      assert_equals(
+        err.name,
+        "NotAllowedError",
+        "if it throws, then it must be a NotAllowedError."
+      );
+      break;
+    }
+  }
+  for (let i = 0; i < 1000; i++) {
+    try {
+      await new PaymentRequest(defaultMethods, defaultDetails).canMakePayment();
+    } catch (err) {
+      assert_equals(
+        err.name,
+        "NotAllowedError",
+        "if it throws, then it must be a NotAllowedError."
+      );
+      break;
+    }
+  }
+}, `Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException.`);
+</script>
+
+<small>
+  If you find a buggy test, please <a href="https://github.com/web-platform-tests/wpt/issues">file a bug</a>
+  and tag one of the <a href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml">suggested reviewers</a>.
+</small>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
index 2943c2d..03a9c19f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
@@ -22,6 +22,56 @@
 
 promise_test(async t => {
   const request = new PaymentRequest(defaultMethods, defaultDetails);
+  assert_true(await request.canMakePayment(), "one of the methods should be supported");
+}, `If payment method identifier and serialized parts are supported, resolve promise with true.`);
+
+promise_test(async t => {
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  const acceptPromise = test_driver.bless("show payment request", () => {
+    request.show() // Sets state to "interactive"
+  });
+  const canMakePaymentPromise = request.canMakePayment();
+  try {
+    const result = await canMakePaymentPromise;
+    assert_true(
+      false,
+      `canMakePaymentPromise should have thrown InvalidStateError`
+    );
+  } catch (err) {
+    await promise_rejects(t, "InvalidStateError", canMakePaymentPromise);
+  } finally {
+    await request.abort();
+    await promise_rejects(t, "AbortError", acceptPromise);
+  }
+  // The state should be "closed"
+  await promise_rejects(t, "InvalidStateError", request.canMakePayment());
+}, 'If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException.');
+
+promise_test(async t => {
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  const acceptPromise = test_driver.bless("show payment request", () => {
+    request.show() // Sets state to "interactive"
+  });
+  acceptPromise.catch(() => {}); // no-op, just to silence unhandled rejection in devtools.
+  await request.abort(); // The state is now "closed"
+  await promise_rejects(t, "InvalidStateError", request.canMakePayment());
+  try {
+    const result = await request.canMakePayment();
+    assert_true(
+      false,
+      `should have thrown InvalidStateError, but instead returned "${result}"`
+    );
+  } catch (err) {
+    assert_equals(
+      err.name,
+      "InvalidStateError",
+      "must be an InvalidStateError."
+    );
+  }
+}, 'If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException.');
+
+promise_test(async t => {
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
   try {
     assert_true(
       await request.canMakePayment(),
@@ -41,11 +91,6 @@
 }, `If request.[[state]] is "created", then return a promise that resolves to true for known method.`);
 
 promise_test(async t => {
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  assert_true(await request.canMakePayment(), "one of the methods should be supported");
-}, `If payment method identifier and serialized parts are supported, resolve promise with true.`);
-
-promise_test(async t => {
   const unsupportedMethods = [
     "this-is-not-supported",
     "https://not.supported",
@@ -92,81 +137,6 @@
     }
   }
 }, `If payment method identifier is unknown, resolve promise with false.`);
-
-promise_test(async t => {
-  // This test might never actually hit its assertion, but that's allowed.
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  for (let i = 0; i < 1000; i++) {
-    try {
-      await request.canMakePayment();
-    } catch (err) {
-      assert_equals(
-        err.name,
-        "NotAllowedError",
-        "if it throws, then it must be a NotAllowedError."
-      );
-      break;
-    }
-  }
-  for (let i = 0; i < 1000; i++) {
-    try {
-      await new PaymentRequest(defaultMethods, defaultDetails).canMakePayment();
-    } catch (err) {
-      assert_equals(
-        err.name,
-        "NotAllowedError",
-        "if it throws, then it must be a NotAllowedError."
-      );
-      break;
-    }
-  }
-}, `Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException.`);
-
-promise_test(async t => {
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  const acceptPromise = test_driver.bless("show payment request", () => {
-    request.show() // Sets state to "interactive"
-  });
-  const canMakePaymentPromise = request.canMakePayment();
-  try {
-    const result = await canMakePaymentPromise;
-    assert_true(
-      false,
-      `canMakePaymentPromise should have thrown InvalidStateError`
-    );
-  } catch (err) {
-    await promise_rejects(t, "InvalidStateError", canMakePaymentPromise);
-  } finally {
-    await request.abort();
-    await promise_rejects(t, "AbortError", acceptPromise);
-  }
-  // The state should be "closed"
-  await promise_rejects(t, "InvalidStateError", request.canMakePayment());
-}, 'If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException.');
-
-promise_test(async t => {
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  const acceptPromise = test_driver.bless("show payment request", () => {
-    request.show() // Sets state to "interactive"
-  });
-  acceptPromise.catch(() => {}); // no-op, just to silence unhandled rejection in devtools.
-  await request.abort(); // The state is now "closed"
-  await promise_rejects(t, "InvalidStateError", request.canMakePayment());
-  try {
-    const result = await request.canMakePayment();
-    assert_true(
-      false,
-      `should have thrown InvalidStateError, but instead returned "${result}"`
-    );
-  } catch (err) {
-    assert_equals(
-      err.name,
-      "InvalidStateError",
-      "must be an InvalidStateError."
-    );
-  }
-}, 'If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException.');
-
 </script>
 
 <small>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/retry-method-manual.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/retry-method-manual.https.html
index 82821a9..16ed15e5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/retry-method-manual.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/retry-method-manual.https.html
@@ -28,7 +28,7 @@
     return promise_rejects(
       t,
       "InvalidStateError",
-      response.retry({}),
+      response.retry(),
       "response.[[complete]] is true, so rejects with InvalidStateError."
     );
   }, button.textContent.trim());
@@ -38,11 +38,11 @@
   button.disabled = true;
   promise_test(async t => {
     const { response } = await getPaymentRequestResponse();
-    const retryPromise = response.retry({});
+    const retryPromise = response.retry();
     await promise_rejects(
       t,
       "InvalidStateError",
-      response.retry({}),
+      response.retry(),
       "Calling retry() again rejects with an InvalidStateError"
     );
     await retryPromise;
@@ -54,7 +54,7 @@
   button.disabled = true;
   promise_test(async t => {
     const { response } = await getPaymentRequestResponse();
-    const retryPromise = response.retry({});
+    const retryPromise = response.retry();
     await promise_rejects(
       t,
       "InvalidStateError",
@@ -70,7 +70,7 @@
   button.disabled = true;
   promise_test(async t => {
     const { response, request } = await getPaymentRequestResponse();
-    const retryPromise = response.retry({});
+    const retryPromise = response.retry();
     await promise_rejects(
       t,
       "InvalidStateError",
@@ -87,12 +87,12 @@
   promise_test(async t => {
     const { response } = await getPaymentRequestResponse();
     assert_equals(
-      await response.retry({}),
+      await response.retry(),
       undefined,
       "Expected undefined as the resolve value"
     );
     assert_equals(
-      await response.retry({}),
+      await response.retry(),
       undefined,
       "Expected undefined as the resolve value"
     );
@@ -100,7 +100,7 @@
     await promise_rejects(
       t,
       "InvalidStateError",
-      response.retry({}),
+      response.retry(),
       "Calling retry() after complete() rejects with a InvalidStateError"
     );
   }, button.textContent.trim());
@@ -113,13 +113,13 @@
     await promise_rejects(
       t,
       "AbortError",
-      response.retry({}),
+      response.retry(),
       "The user aborting a retry rejects with a AbortError"
     );
     await promise_rejects(
       t,
       "InvalidStateError",
-      response.retry({}),
+      response.retry(),
       "After the user aborts, response [[complete]] is true so retry() must reject with InvalidStateError"
     );
     await promise_rejects(
@@ -154,7 +154,7 @@
         resolve();
       };
     });
-    const retryPromise = response.retry({});
+    const retryPromise = response.retry();
     await shippingChangedPromise;
     await promise_rejects(
       t,
@@ -175,11 +175,11 @@
   button.disabled = true;
   promise_test(async t => {
     const { response } = await getPaymentRequestResponse();
-    const retryPromise = response.retry({});
+    const retryPromise = response.retry();
     const promises = new Set([
       retryPromise,
-      response.retry({}),
-      response.retry({}),
+      response.retry(),
+      response.retry(),
     ]);
     assert_equals(promises.size, 3, "Must have three unique objects");
     await retryPromise;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness.window-expected.txt
index fd20b3c..fb85fa0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness.window-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 85 tests; 79 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface Element: original interface defined
 PASS Partial interface GlobalEventHandlers: original interface defined
@@ -31,6 +32,16 @@
 PASS PointerEvent interface: new PointerEvent("type") must inherit property "twist" with the proper type
 PASS PointerEvent interface: new PointerEvent("type") must inherit property "pointerType" with the proper type
 PASS PointerEvent interface: new PointerEvent("type") must inherit property "isPrimary" with the proper type
+PASS Document interface: attribute ongotpointercapture
+PASS Document interface: attribute onlostpointercapture
+PASS Document interface: attribute onpointerdown
+PASS Document interface: attribute onpointermove
+PASS Document interface: attribute onpointerup
+PASS Document interface: attribute onpointercancel
+PASS Document interface: attribute onpointerover
+PASS Document interface: attribute onpointerout
+PASS Document interface: attribute onpointerenter
+PASS Document interface: attribute onpointerleave
 PASS Element interface: operation setPointerCapture(long)
 PASS Element interface: operation releasePointerCapture(long)
 PASS Element interface: operation hasPointerCapture(long)
@@ -40,7 +51,39 @@
 FAIL Element interface: calling releasePointerCapture(long) on document with too few arguments must throw TypeError assert_inherits: property "releasePointerCapture" not found in prototype chain
 FAIL Element interface: document must inherit property "hasPointerCapture(long)" with the proper type assert_inherits: property "hasPointerCapture" not found in prototype chain
 FAIL Element interface: calling hasPointerCapture(long) on document with too few arguments must throw TypeError assert_inherits: property "hasPointerCapture" not found in prototype chain
+PASS HTMLElement interface: attribute ongotpointercapture
+PASS HTMLElement interface: attribute onlostpointercapture
+PASS HTMLElement interface: attribute onpointerdown
+PASS HTMLElement interface: attribute onpointermove
+PASS HTMLElement interface: attribute onpointerup
+PASS HTMLElement interface: attribute onpointercancel
+PASS HTMLElement interface: attribute onpointerover
+PASS HTMLElement interface: attribute onpointerout
+PASS HTMLElement interface: attribute onpointerenter
+PASS HTMLElement interface: attribute onpointerleave
+PASS Window interface: attribute ongotpointercapture
+PASS Window interface: attribute onlostpointercapture
+PASS Window interface: attribute onpointerdown
+PASS Window interface: attribute onpointermove
+PASS Window interface: attribute onpointerup
+PASS Window interface: attribute onpointercancel
+PASS Window interface: attribute onpointerover
+PASS Window interface: attribute onpointerout
+PASS Window interface: attribute onpointerenter
+PASS Window interface: attribute onpointerleave
+PASS Window interface: window must inherit property "ongotpointercapture" with the proper type
+PASS Window interface: window must inherit property "onlostpointercapture" with the proper type
+PASS Window interface: window must inherit property "onpointerdown" with the proper type
+PASS Window interface: window must inherit property "onpointermove" with the proper type
+PASS Window interface: window must inherit property "onpointerup" with the proper type
+PASS Window interface: window must inherit property "onpointercancel" with the proper type
+PASS Window interface: window must inherit property "onpointerover" with the proper type
+PASS Window interface: window must inherit property "onpointerout" with the proper type
+PASS Window interface: window must inherit property "onpointerenter" with the proper type
+PASS Window interface: window must inherit property "onpointerleave" with the proper type
 PASS Navigator interface: attribute maxTouchPoints
 PASS Navigator interface: navigator must inherit property "maxTouchPoints" with the proper type
+PASS WorkerGlobalScope interface: existence and properties of interface object
+PASS WorkerNavigator interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/push-api/idlharness.https.any.serviceworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/push-api/idlharness.https.any.serviceworker-expected.txt
index d0869e0..2a17bcb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/push-api/idlharness.https.any.serviceworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/push-api/idlharness.https.any.serviceworker-expected.txt
@@ -79,5 +79,17 @@
 FAIL ServiceWorkerGlobalScope interface: attribute onpushsubscriptionchange assert_own_property: The global object must have a property "onpushsubscriptionchange" expected property "onpushsubscriptionchange" missing
 PASS ServiceWorkerGlobalScope interface: self must inherit property "onpush" with the proper type
 FAIL ServiceWorkerGlobalScope interface: self must inherit property "onpushsubscriptionchange" with the proper type assert_own_property: expected property "onpushsubscriptionchange" missing
+PASS HTMLElement interface: existence and properties of interface object
+PASS HTMLBodyElement interface: existence and properties of interface object
+PASS Window interface: existence and properties of interface object
+PASS HTMLFrameSetElement interface: existence and properties of interface object
+PASS Node interface: existence and properties of interface object
+PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/idlharness.js b/third_party/WebKit/LayoutTests/external/wpt/resources/idlharness.js
index 40a5fa59..9e6ed23 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/resources/idlharness.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/idlharness.js
@@ -305,13 +305,7 @@
                 if (parsed[dep_type]) {
                     const inheriting = parsed[dep_type];
                     const inheritor = parsed.name || parsed.target;
-                    const deps = [inheriting];
-                    // For A includes B, we can ignore A unless B is being tested.
-                    if (dep_type !== "includes"
-                        || (inheriting in this.members && !this.members[inheriting].untested)) {
-                        deps.push(inheritor);
-                    }
-                    for (const dep of deps) {
+                    for (const dep of [inheriting, inheritor]) {
                         new_options.only.push(dep);
                         all_deps.add(dep);
                         follow_up.add(dep);
@@ -326,7 +320,7 @@
                     next.forEach(process);
                 }
             }
-        }.bind(this));
+        });
     }.bind(this);
 
     for (let parsed of parsed_idls) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/cross_origin.https.html b/third_party/WebKit/LayoutTests/external/wpt/server-timing/cross_origin.https.html
index 1421b38..d31c7b0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/cross_origin.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/cross_origin.https.html
@@ -2,7 +2,7 @@
 <head>
     <meta charset='utf-8' />
     <script src="/resources/testharness.js"></script>
-    <script src='/resources/testharnessreport.js'></script>
+    <script src="/resources/testharnessreport.js"></script>
     <script src="/common/performance-timeline-utils.js"></script>
     <script src="/common/get-host-info.sub.js"></script>
     <script>
@@ -20,7 +20,7 @@
         document.getElementsByTagName('script')[0].parentNode.appendChild(img)
       })
 
-      window.addEventListener('load', function() {
+      delayedLoadListener(function() {
         function assertServerTimingEntries(url, expectedEntryCount) {
           test_equals(performance.getEntriesByName(url)[0].serverTiming.length,
             expectedEntryCount,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/navigation_timing_idl.https.html b/third_party/WebKit/LayoutTests/external/wpt/server-timing/navigation_timing_idl.https.html
index 290bb88..d911d64 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/navigation_timing_idl.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/navigation_timing_idl.https.html
@@ -2,10 +2,11 @@
 <head>
     <meta charset='utf-8' />
     <script src="/resources/testharness.js"></script>
-    <script src='/resources/testharnessreport.js'></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/performance-timeline-utils.js"></script>
     <script>
       setup({explicit_done: true})
-      window.addEventListener('load', function(){
+      delayedLoadListener(function(){
         assert_not_equals(typeof performance.getEntriesByType('navigation')[0].serverTiming, 'undefined',
           'An instance of `PerformanceNavigationTiming` should have a `serverTiming` attribute.')
         done()
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/resource_timing_idl.https.html b/third_party/WebKit/LayoutTests/external/wpt/server-timing/resource_timing_idl.https.html
index d2c3c92..b1d8699 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/resource_timing_idl.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/resource_timing_idl.https.html
@@ -2,10 +2,11 @@
 <head>
     <meta charset='utf-8' />
     <script src="/resources/testharness.js"></script>
-    <script src='/resources/testharnessreport.js'></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/performance-timeline-utils.js"></script>
     <script>
       setup({explicit_done: true})
-      window.addEventListener('load', function(){
+      delayedLoadListener(function(){
         assert_not_equals(typeof performance.getEntriesByType('resource')[0].serverTiming, 'undefined',
           'An instance of `PerformanceResourceTiming` should have a `serverTiming` attribute.')
         done()
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https.html b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https.html
index 156dfcd..737cc08 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/server_timing_header-parsing.https.html
@@ -7,7 +7,7 @@
 <head>
     <meta charset='utf-8' />
     <script src="/resources/testharness.js"></script>
-    <script src='/resources/testharnessreport.js'></script>
+    <script src="/resources/testharnessreport.js"></script>
     <script src="/common/performance-timeline-utils.js"></script>
     <script>
       setup({explicit_done: true})
@@ -49,6 +49,6 @@
         document.getElementsByTagName('head')[0].appendChild(script)
         urlToIndex[script.src] = i
       }
-      window.addEventListener('load', runTests)
+      delayedLoadListener(runTests)
     </script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/service_worker_idl.https.html b/third_party/WebKit/LayoutTests/external/wpt/server-timing/service_worker_idl.https.html
index 1c1be899..5c493fd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/service_worker_idl.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/service_worker_idl.https.html
@@ -2,7 +2,7 @@
 <head>
     <meta charset='utf-8' />
     <script src="/resources/testharness.js"></script>
-    <script src='/resources/testharnessreport.js'></script>
+    <script src="/resources/testharnessreport.js"></script>
     <script>
       (async () => {
         const scope = 'does/not/exist'
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/test_server_timing.https.html b/third_party/WebKit/LayoutTests/external/wpt/server-timing/test_server_timing.https.html
index 2d43aa2..4f3554a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/test_server_timing.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/test_server_timing.https.html
@@ -2,12 +2,12 @@
 <head>
     <meta charset='utf-8' />
     <script src="/resources/testharness.js"></script>
-    <script src='/resources/testharnessreport.js'></script>
+    <script src="/resources/testharnessreport.js"></script>
     <script src="/common/performance-timeline-utils.js"></script>
     <script>
       setup({explicit_done: true})
 
-      window.addEventListener('load', function() {
+      delayedLoadListener(function() {
         // there should be exactly three server-timing entries, 2 for document, 1 for img#one
         test_entries(performance.getEntriesByType('navigation')[0].serverTiming, [{
           duration: 1.1,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/signed-exchange/META.yml b/third_party/WebKit/LayoutTests/external/wpt/signed-exchange/META.yml
new file mode 100644
index 0000000..f56fbab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/signed-exchange/META.yml
@@ -0,0 +1,5 @@
+spec: https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
+suggested_reviewers:
+  - irori
+  - jyasskin
+  - nyaxt
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt
index ee63d6d..e0bc129a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 65 PASS, 157 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 223 tests; 66 PASS, 157 FAIL, 0 TIMEOUT, 0 NOTRUN.
 FAIL idl_test setup promise_test: Unhandled rejection with value: "Timed out waiting for voice"
 PASS Partial interface Window: original interface defined
 FAIL SpeechRecognition interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
@@ -222,5 +222,6 @@
 FAIL SpeechSynthesisVoice interface: voice must inherit property "default" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: voice is not defined"
 PASS Window interface: attribute speechSynthesis
 PASS Window interface: self must inherit property "speechSynthesis" with the proper type
+PASS WorkerGlobalScope interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/idlharness.window-expected.txt
index 36ed012..b4aa8b69 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/idlharness.window-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 1600 tests; 1477 PASS, 123 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 1601 tests; 1478 PASS, 123 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface Document: original interface defined
 PASS SVGElement interface: existence and properties of interface object
@@ -1599,6 +1599,7 @@
 PASS SVGElement interface: objects.view must inherit property "viewportElement" with the proper type
 FAIL SVGElement interface: objects.view must inherit property "correspondingElement" with the proper type assert_inherits: property "correspondingElement" not found in prototype chain
 FAIL SVGElement interface: objects.view must inherit property "correspondingUseElement" with the proper type assert_inherits: property "correspondingUseElement" not found in prototype chain
+PASS WorkerGlobalScope interface: existence and properties of interface object
 PASS Document interface: attribute rootElement
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/touch-events/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/touch-events/idlharness.window-expected.txt
index 8ac9fbe..6105362 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/touch-events/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/touch-events/idlharness.window-expected.txt
@@ -1,86 +1,5 @@
 This is a testharness.js-based test.
-Found 82 tests; 72 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS idl_test setup
+FAIL idl_test setup promise_test: Unhandled rejection with value: "Document includes GlobalEventHandlers, but Document is undefined."
 PASS Partial interface GlobalEventHandlers: original interface defined
-PASS Touch interface: existence and properties of interface object
-PASS Touch interface object length
-PASS Touch interface object name
-PASS Touch interface: existence and properties of interface prototype object
-PASS Touch interface: existence and properties of interface prototype object's "constructor" property
-PASS Touch interface: existence and properties of interface prototype object's @@unscopables property
-PASS Touch interface: attribute identifier
-PASS Touch interface: attribute target
-PASS Touch interface: attribute screenX
-PASS Touch interface: attribute screenY
-PASS Touch interface: attribute clientX
-PASS Touch interface: attribute clientY
-PASS Touch interface: attribute pageX
-PASS Touch interface: attribute pageY
-PASS Touch interface: attribute radiusX
-PASS Touch interface: attribute radiusY
-PASS Touch interface: attribute rotationAngle
-PASS Touch interface: attribute force
-FAIL Touch interface: attribute altitudeAngle assert_true: The prototype object must have a property "altitudeAngle" expected true got false
-FAIL Touch interface: attribute azimuthAngle assert_true: The prototype object must have a property "azimuthAngle" expected true got false
-FAIL Touch interface: attribute touchType assert_true: The prototype object must have a property "touchType" expected true got false
-PASS Touch must be primary interface of new Touch({identifier: 1, target: document})
-PASS Stringification of new Touch({identifier: 1, target: document})
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "identifier" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "target" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "screenX" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "screenY" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "clientX" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "clientY" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "pageX" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "pageY" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "radiusX" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "radiusY" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "rotationAngle" with the proper type
-PASS Touch interface: new Touch({identifier: 1, target: document}) must inherit property "force" with the proper type
-FAIL Touch interface: new Touch({identifier: 1, target: document}) must inherit property "altitudeAngle" with the proper type assert_inherits: property "altitudeAngle" not found in prototype chain
-FAIL Touch interface: new Touch({identifier: 1, target: document}) must inherit property "azimuthAngle" with the proper type assert_inherits: property "azimuthAngle" not found in prototype chain
-FAIL Touch interface: new Touch({identifier: 1, target: document}) must inherit property "touchType" with the proper type assert_inherits: property "touchType" not found in prototype chain
-PASS TouchList interface: existence and properties of interface object
-PASS TouchList interface object length
-PASS TouchList interface object name
-PASS TouchList interface: existence and properties of interface prototype object
-PASS TouchList interface: existence and properties of interface prototype object's "constructor" property
-PASS TouchList interface: existence and properties of interface prototype object's @@unscopables property
-PASS TouchList interface: attribute length
-PASS TouchList interface: operation item(unsigned long)
-PASS TouchEvent interface: existence and properties of interface object
-PASS TouchEvent interface object length
-PASS TouchEvent interface object name
-PASS TouchEvent interface: existence and properties of interface prototype object
-PASS TouchEvent interface: existence and properties of interface prototype object's "constructor" property
-PASS TouchEvent interface: existence and properties of interface prototype object's @@unscopables property
-PASS TouchEvent interface: attribute touches
-PASS TouchEvent interface: attribute targetTouches
-PASS TouchEvent interface: attribute changedTouches
-PASS TouchEvent interface: attribute altKey
-PASS TouchEvent interface: attribute metaKey
-PASS TouchEvent interface: attribute ctrlKey
-PASS TouchEvent interface: attribute shiftKey
-PASS TouchEvent must be primary interface of new TouchEvent("name")
-PASS Stringification of new TouchEvent("name")
-PASS TouchEvent interface: new TouchEvent("name") must inherit property "touches" with the proper type
-PASS TouchEvent interface: new TouchEvent("name") must inherit property "targetTouches" with the proper type
-PASS TouchEvent interface: new TouchEvent("name") must inherit property "changedTouches" with the proper type
-PASS TouchEvent interface: new TouchEvent("name") must inherit property "altKey" with the proper type
-PASS TouchEvent interface: new TouchEvent("name") must inherit property "metaKey" with the proper type
-PASS TouchEvent interface: new TouchEvent("name") must inherit property "ctrlKey" with the proper type
-PASS TouchEvent interface: new TouchEvent("name") must inherit property "shiftKey" with the proper type
-FAIL GlobalEventHandlers interface: window must inherit property "ontouchstart" with the proper type assert_inherits: property "ontouchstart" found on object expected in prototype chain
-FAIL GlobalEventHandlers interface: window must inherit property "ontouchend" with the proper type assert_inherits: property "ontouchend" found on object expected in prototype chain
-FAIL GlobalEventHandlers interface: window must inherit property "ontouchmove" with the proper type assert_inherits: property "ontouchmove" found on object expected in prototype chain
-FAIL GlobalEventHandlers interface: window must inherit property "ontouchcancel" with the proper type assert_inherits: property "ontouchcancel" found on object expected in prototype chain
-PASS GlobalEventHandlers interface: document must inherit property "ontouchstart" with the proper type
-PASS GlobalEventHandlers interface: document must inherit property "ontouchend" with the proper type
-PASS GlobalEventHandlers interface: document must inherit property "ontouchmove" with the proper type
-PASS GlobalEventHandlers interface: document must inherit property "ontouchcancel" with the proper type
-PASS GlobalEventHandlers interface: document.body must inherit property "ontouchstart" with the proper type
-PASS GlobalEventHandlers interface: document.body must inherit property "ontouchend" with the proper type
-PASS GlobalEventHandlers interface: document.body must inherit property "ontouchmove" with the proper type
-PASS GlobalEventHandlers interface: document.body must inherit property "ontouchcancel" with the proper type
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt
index b9b9989..1046b2d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt
@@ -25,7 +25,11 @@
 PASS Test bounds point of step-end easing
 FAIL Test bounds point of step-end easing with iterationStart and delay assert_equals: Progress at 0ms expected 0 but got 0.5
 PASS Test bounds point of step-end easing with iterationStart not at a transition point
-PASS Test bounds point of frames easing
-PASS Test bounds point of frames easing with iterationStart and delay
+FAIL Test bounds point of steps(jump-both) easing Failed to execute 'animate' on 'Element': 'steps(2, jump-both)' is not a valid value for easing
+FAIL Test bounds point of steps(jump-both) easing with iterationStart and delay Failed to execute 'animate' on 'Element': 'steps(2, jump-both)' is not a valid value for easing
+FAIL Test bounds point of steps(jump-both) easing with iterationStart not at a transition point Failed to execute 'animate' on 'Element': 'steps(2, jump-both)' is not a valid value for easing
+FAIL Test bounds point of steps(jump-none) easing Failed to execute 'animate' on 'Element': 'steps(2, jump-none)' is not a valid value for easing
+FAIL Test bounds point of steps(jump-none) easing with iterationStart and delay Failed to execute 'animate' on 'Element': 'steps(2, jump-none)' is not a valid value for easing
+FAIL Test bounds point of steps(jump-none) easing with iterationStart not at a transition point Failed to execute 'animate' on 'Element': 'steps(2, jump-none)' is not a valid value for easing
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress.html
index 839ebe1..960e333c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress.html
@@ -32,10 +32,9 @@
   }, `Transformed progress for ${params.desc}`);
 }
 
-// Additional tests for various boundary conditions of step timing functions and
-// frames timing functions.
+// Additional tests for various boundary conditions of step timing functions.
 
-const gStepAndFramesTimingFunctionTests = [
+const gStepTimingFunctionTests = [
   {
     description: 'Test bounds point of step-start easing',
     effect:     {
@@ -255,12 +254,72 @@
                 ]
   },
   {
-    description: 'Test bounds point of frames easing',
+    description: 'Test bounds point of steps(jump-both) easing',
     effect:     {
                   delay: 1000,
                   duration: 1000,
                   fill: 'both',
-                  easing: 'frames(2)'
+                  easing: 'steps(2, jump-both)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 0 },
+                  { currentTime: 999,  progress: 0 },
+                  { currentTime: 1000, progress: 1/3 },
+                  { currentTime: 1499, progress: 1/3 },
+                  { currentTime: 1500, progress: 2/3 },
+                  { currentTime: 2000, progress: 1 }
+                ]
+  },
+  {
+    description: 'Test bounds point of steps(jump-both) easing ' +
+                 'with iterationStart and delay',
+    effect:     {
+                  duration: 1000,
+                  fill: 'both',
+                  delay: 1000,
+                  iterationStart: 0.5,
+                  easing: 'steps(2, jump-both)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 1/3 },
+                  { currentTime: 999,  progress: 1/3 },
+                  { currentTime: 1000, progress: 2/3 },
+                  { currentTime: 1499, progress: 2/3 },
+                  { currentTime: 1500, progress: 1/3 },
+                  { currentTime: 1999, progress: 1/3 },
+                  { currentTime: 2000, progress: 2/3 },
+                  { currentTime: 2500, progress: 2/3 }
+                ]
+  },
+  {
+    description: 'Test bounds point of steps(jump-both) easing ' +
+                 'with iterationStart not at a transition point',
+    effect:     {
+                  delay: 1000,
+                  duration: 1000,
+                  fill: 'both',
+                  iterationStart: 0.75,
+                  easing: 'steps(2, jump-both)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 2/3 },
+                  { currentTime: 999,  progress: 2/3 },
+                  { currentTime: 1000, progress: 2/3 },
+                  { currentTime: 1249, progress: 2/3 },
+                  { currentTime: 1250, progress: 1/3 },
+                  { currentTime: 1749, progress: 1/3 },
+                  { currentTime: 1750, progress: 2/3 },
+                  { currentTime: 2000, progress: 2/3 },
+                  { currentTime: 2500, progress: 2/3 }
+                ]
+  },
+  {
+    description: 'Test bounds point of steps(jump-none) easing',
+    effect:     {
+                  delay: 1000,
+                  duration: 1000,
+                  fill: 'both',
+                  easing: 'steps(2, jump-none)'
                 },
     conditions: [
                   { currentTime: 0,    progress: 0 },
@@ -271,27 +330,51 @@
                 ]
   },
   {
-    description: 'Test bounds point of frames easing ' +
+    description: 'Test bounds point of steps(jump-none) easing ' +
                  'with iterationStart and delay',
     effect:     {
-                  delay: 1000,
                   duration: 1000,
                   fill: 'both',
+                  delay: 1000,
                   iterationStart: 0.5,
-                  easing: 'frames(2)'
+                  easing: 'steps(2, jump-none)'
                 },
     conditions: [
-                  { currentTime: 0,    progress: 1 },
+                  { currentTime: 0,    progress: 0 },
+                  { currentTime: 999,  progress: 0 },
                   { currentTime: 1000, progress: 1 },
                   { currentTime: 1499, progress: 1 },
                   { currentTime: 1500, progress: 0 },
                   { currentTime: 1999, progress: 0 },
-                  { currentTime: 2000, progress: 1 }
+                  { currentTime: 2000, progress: 1 },
+                  { currentTime: 2500, progress: 1 }
                 ]
-  }
+  },
+  {
+    description: 'Test bounds point of steps(jump-none) easing ' +
+                 'with iterationStart not at a transition point',
+    effect:     {
+                  delay: 1000,
+                  duration: 1000,
+                  fill: 'both',
+                  iterationStart: 0.75,
+                  easing: 'steps(2, jump-none)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 1 },
+                  { currentTime: 999,  progress: 1 },
+                  { currentTime: 1000, progress: 1 },
+                  { currentTime: 1249, progress: 1 },
+                  { currentTime: 1250, progress: 0 },
+                  { currentTime: 1749, progress: 0 },
+                  { currentTime: 1750, progress: 1 },
+                  { currentTime: 2000, progress: 1 },
+                  { currentTime: 2500, progress: 1 }
+                ]
+  },
 ];
 
-for (const options of gStepAndFramesTimingFunctionTests) {
+for (const options of gStepTimingFunctionTests) {
   test(t => {
     const target = createDiv(t);
     const animation = target.animate(null, options.effect);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/idlharness.https.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webaudio/idlharness.https.window-expected.txt
index 1e99acd..64ec9f4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/idlharness.https.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/idlharness.https.window-expected.txt
@@ -1124,5 +1124,6 @@
 PASS AudioNode interface: worklet_node must inherit property "channelCountMode" with the proper type
 PASS AudioNode interface: worklet_node must inherit property "channelInterpretation" with the proper type
 PASS AudioWorkletProcessor interface: existence and properties of interface object
+PASS WorkerGlobalScope interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webmidi/idlharness.https.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webmidi/idlharness.https.window-expected.txt
index 85db0f6..c2d675a6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webmidi/idlharness.https.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webmidi/idlharness.https.window-expected.txt
@@ -82,5 +82,6 @@
 PASS Stringification of new MIDIConnectionEvent("type")
 PASS MIDIConnectionEvent interface: new MIDIConnectionEvent("type") must inherit property "port" with the proper type
 PASS Navigator interface: operation requestMIDIAccess(MIDIOptions)
+PASS WorkerNavigator interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/META.yml b/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/META.yml
new file mode 100644
index 0000000..900769b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/META.yml
@@ -0,0 +1,3 @@
+spec: https://github.com/w3c/webrtc-identity
+suggested_reviewers:
+  - martinthomson
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub-expected.txt
new file mode 100644
index 0000000..f390208
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+FAIL getIdentityAssertion() should load IdP proxy and return assertion generated pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should succeed if mock-idp.js return different domain and protocol in assertion pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should reject with RTCError('idp-execution-failure') if mock-idp.js throws error assert_equals: Expect initial pc.idpErrorInfo to be null expected (object) null but got (undefined) undefined
+FAIL getIdentityAssertion() should reject with RTCError('idp-bad-script-failure') if IdP proxy script do not register its callback pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should reject with OperationError if mock-idp.js return invalid result pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should reject with RTCError('idp-load-failure') if IdP cannot be loaded pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should reject with RTCError('idp-need-login') when mock-idp.js requires login assert_equals: Expect initial pc.idpLoginUrl to be null expected (object) null but got (undefined) undefined
+FAIL setIdentityProvider() with no peerIdentity provided should use peerIdentity value from getConfiguration() pc.setIdentityProvider is not a function
+FAIL Calling setIdentityProvider() multiple times should reset identity assertions pc.setIdentityProvider is not a function
+FAIL createOffer() should return SDP containing identity assertion string if identity provider is set pc.setIdentityProvider is not a function
+FAIL createOffer() should reject with NotReadableError if identitity assertion request fails pc.setIdentityProvider is not a function
+FAIL createAnswer() should reject with NotReadableError if identitity assertion request fails pc.setIdentityProvider is not a function
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-getIdentityAssertion.sub.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-getIdentityAssertion.sub.html
rename to third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity-expected.txt
new file mode 100644
index 0000000..76951f1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL setRemoteDescription() on offer with a=identity should establish peerIdentity pc1.setIdentityProvider is not a function
+FAIL setRemoteDescription() on offer with a=identity that resolve to value different from target peer identity should reject with InvalidModificationError pc1.setIdentityProvider is not a function
+FAIL setRemoteDescription() with peerIdentity set and with IdP proxy that return validationAssertion with mismatch contents should reject with OperationError pc1.setIdentityProvider is not a function
+FAIL setRemoteDescription() and peerIdentity should reject with OperationError if IdP return validated identity that is different from its own domain pc1.setIdentityProvider is not a function
+FAIL When IdP throws error and pc has target peer identity, setRemoteDescription() and peerIdentity rejected with RTCError('idp-execution-error') pc1.setIdentityProvider is not a function
+FAIL IdP failure with no target peer identity should have following setRemoteDescription() succeed and replace pc.peerIdentity with a new promise pc1.setIdentityProvider is not a function
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-peerIdentity.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-peerIdentity.html
rename to third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/identity-helper.sub.js b/third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/identity-helper.sub.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/webrtc/identity-helper.sub.js
rename to third_party/WebKit/LayoutTests/external/wpt/webrtc-identity/identity-helper.sub.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate-postMessage-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate-postMessage-expected.txt
new file mode 100644
index 0000000..7c5a569
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate-postMessage-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+PASS Check same-origin RTCCertificate serialization
+PASS Check cross-origin RTCCertificate serialization
+FAIL Check cross-origin created RTCCertificate assert_throws: function "() => { new RTCPeerConnection({certificates: [certificate2]}) }" did not throw
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate-postMessage.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate-postMessage.html
new file mode 100644
index 0000000..5885f9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate-postMessage.html
@@ -0,0 +1,77 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>RTCCertificate persistent Tests</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+<script>
+    function findMatchingFingerprint(fingerprints, fingerprint) {
+        for (let f of fingerprints) {
+            if (f.value == fingerprint.value && f.algorithm == fingerprint.algorithm)
+                return true;
+        }
+        return false;
+    }
+
+    function with_iframe(url) {
+        return new Promise(function(resolve) {
+            var frame = document.createElement('iframe');
+            frame.src = url;
+            frame.onload = function() { resolve(frame); };
+            document.body.appendChild(frame);
+        });
+    }
+
+    function testPostMessageCertificate(isCrossOrigin) {
+        promise_test(async t => {
+            let certificate = await  RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256' });
+
+            let url = "resources/RTCCertificate-postMessage-iframe.html";
+            if (isCrossOrigin)
+                url = get_host_info().HTTP_REMOTE_ORIGIN + "/webrtc/" + url;
+
+            let iframe = await with_iframe(url);
+
+            let promise = new Promise((resolve, reject) => {
+                window.onmessage = (event) => {
+                    resolve(event.data);
+                };
+                t.step_timeout(() => reject("Timed out waiting for frame to send back certificate"), 5000);
+            });
+            iframe.contentWindow.postMessage(certificate, "*");
+            let certificate2 = await promise;
+
+            new RTCPeerConnection({certificates: [certificate]});
+
+            new RTCPeerConnection({certificates: [certificate2]});
+
+            assert_equals(certificate.expires, certificate2.expires);
+            for (let fingerprint of certificate2.getFingerprints())
+                assert_true(findMatchingFingerprint(certificate.getFingerprints(), fingerprint), "check fingerprints");
+
+            iframe.remove();
+        }, "Check " + (isCrossOrigin ? "cross-origin" : "same-origin") + " RTCCertificate serialization");
+    }
+
+    testPostMessageCertificate(false);
+    testPostMessageCertificate(true);
+
+    promise_test(async t => {
+        let url = get_host_info().HTTP_REMOTE_ORIGIN + "/webrtc/resources/RTCCertificate-postMessage-iframe.html";
+        let iframe = await with_iframe(url);
+
+        let promise = new Promise((resolve, reject) => {
+            window.onmessage = (event) => {
+                resolve(event.data);
+            };
+            t.step_timeout(() => reject("Timed out waiting for frame to send back certificate"), 5000);
+        });
+        iframe.contentWindow.postMessage(null, "*");
+        let certificate2 = await promise;
+
+        assert_throws("InvalidAccessError", () => { new RTCPeerConnection({certificates: [certificate2]}) });
+        iframe.remove();
+    }, "Check cross-origin created RTCCertificate");
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate.html
index e5f1749..a33ba9a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCCertificate.html
@@ -6,8 +6,8 @@
 <script>
   'use strict';
 
-  // Test is based on the following editor draft:
-  // https://w3c.github.io/webrtc-pc/archives/20170515/webrtc.html
+  // Test is based on the Candidate Recommendation:
+  // https://www.w3.org/TR/webrtc/
 
   /*
     4.2.1. RTCConfiguration Dictionary
@@ -26,8 +26,8 @@
     4.10.2. RTCCertificate Interface
       interface RTCCertificate {
         readonly attribute DOMTimeStamp expires;
+        static sequence<AlgorithmIdentifier> getSupportedAlgorithms();
         sequence<RTCDtlsFingerprint>    getFingerprints();
-        AlgorithmIdentifier             getAlgorithm();
       };
 
     5.5.1 The RTCDtlsFingerprint Dictionary
@@ -257,10 +257,9 @@
     TODO
 
     4.10.2. RTCCertificate Interface
-      getAlgorithm
-        Returns the result of the WebCrypto algorithm normalization process
-        [WebCryptoAPI] that occurred when this certificate was generated
-        with generateCertificate().
+      getSupportedAlgorithms
+           Returns a sequence providing a representative set of supported
+           certificate algorithms. At least one algorithm MUST be returned.
 
       The RTCCertificate object can be stored and retrieved from persistent
       storage by an application. When a user agent is required to obtain a
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceCandidate-constructor-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceCandidate-constructor-expected.txt
index 8df706d..af3000f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceCandidate-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceCandidate-constructor-expected.txt
@@ -5,7 +5,7 @@
         candidate: '',
         sdpMid: null,
         sdpMLineIndex: null,
-        ufrag: undefined
+        usernameFragment: undefined
       })" threw object "TypeMismatchError: Failed to construct 'RTCIceCandidate': The 'candidate' property is not a string, or is empty." ("TypeMismatchError") expected object "TypeError" ("TypeError")
 FAIL new RTCIceCandidate({ sdpMid: null, sdpMLineIndex: null }) assert_throws: function "() => new RTCIceCandidate({
         sdpMid: null,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceCandidate-constructor.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceCandidate-constructor.html
index 974ed0c..9842593 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceCandidate-constructor.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCIceCandidate-constructor.html
@@ -34,7 +34,7 @@
         candidate: '',
         sdpMid: null,
         sdpMLineIndex: null,
-        ufrag: undefined
+        usernameFragment: undefined
       }));
   }, 'new RTCIceCandidate({ ... }) with manually filled default values');
 
@@ -77,7 +77,7 @@
     assert_equals(candidate.candidate, '');
     assert_equals(candidate.sdpMid, 'audio');
     assert_equals(candidate.sdpMLineIndex, null);
-    assert_equals(candidate.ufrag, null);
+    assert_equals(candidate.usernameFragment, null);
   }, `new RTCIceCandidate({ sdpMid: 'audio' })`);
 
   test(t => {
@@ -86,7 +86,7 @@
     assert_equals(candidate.candidate, '');
     assert_equals(candidate.sdpMid, null);
     assert_equals(candidate.sdpMLineIndex, 0);
-    assert_equals(candidate.ufrag, null);
+    assert_equals(candidate.usernameFragment, null);
   }, 'new RTCIceCandidate({ sdpMLineIndex: 0 })');
 
   test(t => {
@@ -98,7 +98,7 @@
     assert_equals(candidate.candidate, '');
     assert_equals(candidate.sdpMid, 'audio');
     assert_equals(candidate.sdpMLineIndex, 0);
-    assert_equals(candidate.ufrag, null);
+    assert_equals(candidate.usernameFragment, null);
   }, `new RTCIceCandidate({ sdpMid: 'audio', sdpMLineIndex: 0 })`);
 
   test(t => {
@@ -110,7 +110,7 @@
     assert_equals(candidate.candidate, '');
     assert_equals(candidate.sdpMid, 'audio');
     assert_equals(candidate.sdpMLineIndex, null);
-    assert_equals(candidate.ufrag, null);
+    assert_equals(candidate.usernameFragment, null);
   }, `new RTCIceCandidate({ candidate: '', sdpMid: 'audio' }`);
 
   test(t => {
@@ -122,7 +122,7 @@
     assert_equals(candidate.candidate, '');
     assert_equals(candidate.sdpMid, null);
     assert_equals(candidate.sdpMLineIndex, 0);
-    assert_equals(candidate.ufrag, null);
+    assert_equals(candidate.usernameFragment, null);
   }, `new RTCIceCandidate({ candidate: '', sdpMLineIndex: 0 }`);
 
   test(t => {
@@ -134,7 +134,7 @@
     assert_equals(candidate.candidate, candidateString);
     assert_equals(candidate.sdpMid, 'audio');
     assert_equals(candidate.sdpMLineIndex, null);
-    assert_equals(candidate.ufrag, null);
+    assert_equals(candidate.usernameFragment, null);
   }, 'new RTCIceCandidate({ ... }) with valid candidate string and sdpMid');
 
   test(t =>{
@@ -147,7 +147,7 @@
     assert_equals(candidate.candidate, arbitraryString);
     assert_equals(candidate.sdpMid, 'audio');
     assert_equals(candidate.sdpMLineIndex, null);
-    assert_equals(candidate.ufrag, null);
+    assert_equals(candidate.usernameFragment, null);
   }, 'new RTCIceCandidate({ ... }) with invalid candidate string and sdpMid');
 
   test(t => {
@@ -155,13 +155,13 @@
       candidate: candidateString,
       sdpMid: 'video',
       sdpMLineIndex: 1,
-      ufrag: 'test'
+      usernameFragment: 'test'
     });
 
     assert_equals(candidate.candidate, candidateString);
     assert_equals(candidate.sdpMid, 'video');
     assert_equals(candidate.sdpMLineIndex, 1);
-    assert_equals(candidate.ufrag, 'test');
+    assert_equals(candidate.usernameFragment, 'test');
   }, 'new RTCIceCandidate({ ... }) with non default value for all fields');
 
 
@@ -174,7 +174,7 @@
     assert_equals(candidate.candidate, '');
     assert_equals(candidate.sdpMid, arbitraryString);
     assert_equals(candidate.sdpMLineIndex, null);
-    assert_equals(candidate.ufrag, null);
+    assert_equals(candidate.usernameFragment, null);
   }, 'new RTCIceCandidate({ ... }) with invalid sdpMid');
 
 
@@ -190,7 +190,7 @@
     assert_equals(candidate.candidate, '');
     assert_equals(candidate.sdpMid, null);
     assert_equals(candidate.sdpMLineIndex, 65535);
-    assert_equals(candidate.ufrag, null);
+    assert_equals(candidate.usernameFragment, null);
   }, 'new RTCIceCandidate({ ... }) with invalid sdpMLineIndex');
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt
index 030996a..1f68f03 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt
@@ -7,7 +7,7 @@
 FAIL Add candidate with only valid sdpMLineIndex should succeed promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
 PASS addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream
 PASS addIceCandidate with second sdpMid and sdpMLineIndex should add candidate to second media stream
-PASS Add candidate for first media stream with null ufrag should add candidate to first media stream
+PASS Add candidate for first media stream with null usernameFragment should add candidate to first media stream
 PASS Adding multiple candidates should add candidates to their corresponding media stream
 FAIL Add with empty candidate string (end of candidate) should succeed promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
 FAIL Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate" ("OperationError") expected object "TypeError" ("TypeError")
@@ -18,9 +18,9 @@
 PASS Add candidate with invalid sdpMid should reject with OperationError
 PASS Add candidate with invalid sdpMLineIndex should reject with OperationError
 FAIL Invalid sdpMLineIndex should be ignored if valid sdpMid is provided promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
-PASS Add candidate for media stream 2 with null ufrag should succeed
-FAIL Add candidate with invalid ufrag should reject with OperationError assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Add candidate for media stream 2 with null usernameFragment should succeed
+FAIL Add candidate with invalid usernameFragment should reject with OperationError assert_unreached: Should have rejected: undefined Reached unreachable code
 PASS Add candidate with invalid candidate string should reject with OperationError
-FAIL Add candidate with sdpMid belonging to different ufrag should reject with OperationError assert_unreached: Should have rejected: undefined Reached unreachable code
+FAIL Add candidate with sdpMid belonging to different usernameFragment should reject with OperationError assert_unreached: Should have rejected: undefined Reached unreachable code
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate.html
index 5e32168..1dd1350 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate.html
@@ -5,32 +5,6 @@
 <script>
   'use strict';
 
-  // Test is based on the following editor draft:
-  // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.htm
-
-  /*
-    4.3.2.  Interface Definition
-      interface RTCPeerConnection : EventTarget {
-        ...
-        Promise<void> addIceCandidate((RTCIceCandidateInit or RTCIceCandidate) candidate);
-      };
-
-      interface RTCIceCandidate {
-        readonly attribute DOMString               candidate;
-        readonly attribute DOMString?              sdpMid;
-        readonly attribute unsigned short?         sdpMLineIndex;
-        readonly attribute DOMString?              ufrag;
-        ...
-      };
-
-      dictionary RTCIceCandidateInit {
-        DOMString       candidate = "";
-        DOMString?      sdpMid = null;
-        unsigned short? sdpMLineIndex = null;
-        DOMString       ufrag;
-      };
-   */
-
   // SDP copied from JSEP Example 7.1
   // It contains two media streams with different ufrags
   // to test if candidate is added to the correct stream
@@ -89,11 +63,11 @@
   // valid candidate attributes
   const sdpMid = 'a1';
   const sdpMLineIndex = 0;
-  const ufrag = 'ETEn';
+  const usernameFragment = 'ETEn';
 
   const sdpMid2 = 'v1';
   const sdpMLineIndex2 = 1;
-  const ufrag2 = 'BGKk';
+  const usernameFragment2 = 'BGKk';
 
   const mediaLine1 = 'm=audio';
   const mediaLine2 = 'm=video';
@@ -151,7 +125,7 @@
   }, 'Add null candidate should reject with TypeError');
 
   /*
-    4.3.2.  addIceCandidate
+    4.4.2.  addIceCandidate
       4.  Return the result of enqueuing the following steps:
         1.  If remoteDescription is null return a promise rejected with a
             newly created InvalidStateError.
@@ -164,7 +138,7 @@
     return promise_rejects(t, 'InvalidStateError',
       pc.addIceCandidate({
         candidate: candidateStr1,
-        sdpMid, sdpMLineIndex, ufrag
+        sdpMid, sdpMLineIndex, usernameFragment
       }));
   }, 'Add ICE candidate before setting remote description should reject with InvalidStateError');
 
@@ -179,7 +153,7 @@
     return pc.setRemoteDescription(sessionDesc)
     .then(() => pc.addIceCandidate({
       candidate: candidateStr1,
-      sdpMid, sdpMLineIndex, ufrag
+      sdpMid, sdpMLineIndex, usernameFragment
     }));
   }, 'Add ICE candidate after setting remote description should succeed');
 
@@ -191,7 +165,7 @@
     return pc.setRemoteDescription(sessionDesc)
     .then(() => pc.addIceCandidate(new RTCIceCandidate({
       candidate: candidateStr1,
-      sdpMid, sdpMLineIndex, ufrag
+      sdpMid, sdpMLineIndex, usernameFragment
     })));
   }, 'Add ICE candidate with RTCIceCandidate should succeed');
 
@@ -214,12 +188,15 @@
   }, 'Add candidate with only valid sdpMLineIndex should succeed');
 
   /*
-    4.3.2.  addIceCandidate
+    4.4.2.  addIceCandidate
       4.6.2.  If candidate is applied successfully, the user agent MUST queue
               a task that runs the following steps:
-        2.  Let remoteDescription be connection's pendingRemoteDescription
-            if not null, otherwise connection's currentRemoteDescription.
-        3.  Add candidate to remoteDescription.
+        2.  If connection.pendingRemoteDescription is non-null, and represents
+            the ICE generation for which candidate was processed, add
+            candidate to connection.pendingRemoteDescription.
+        3.  If connection.currentRemoteDescription is non-null, and represents
+            the ICE generation for which candidate was processed, add
+            candidate to connection.currentRemoteDescription.
    */
   promise_test(t => {
     const pc = new RTCPeerConnection();
@@ -229,7 +206,7 @@
     return pc.setRemoteDescription(sessionDesc)
     .then(() => pc.addIceCandidate({
       candidate: candidateStr1,
-      sdpMid, sdpMLineIndex, ufrag
+      sdpMid, sdpMLineIndex, usernameFragment
     }))
     .then(() => {
       assert_candidate_line_between(pc.remoteDescription.sdp,
@@ -247,7 +224,7 @@
       candidate: candidateStr2,
       sdpMid: sdpMid2,
       sdpMLineIndex: sdpMLineIndex2,
-      ufrag: ufrag2
+      usernameFragment: usernameFragment2
     }))
     .then(() => {
       assert_candidate_line_after(pc.remoteDescription.sdp,
@@ -264,13 +241,13 @@
     .then(() => pc.addIceCandidate({
       candidate: candidateStr1,
       sdpMid, sdpMLineIndex,
-      ufrag: null
+      usernameFragment: null
     }))
     .then(() => {
       assert_candidate_line_between(pc.remoteDescription.sdp,
         mediaLine1, candidateLine1, mediaLine2);
     });
-  }, 'Add candidate for first media stream with null ufrag should add candidate to first media stream');
+  }, 'Add candidate for first media stream with null usernameFragment should add candidate to first media stream');
 
   promise_test(t => {
     const pc = new RTCPeerConnection();
@@ -280,13 +257,13 @@
     return pc.setRemoteDescription(sessionDesc)
     .then(() => pc.addIceCandidate({
       candidate: candidateStr1,
-      sdpMid, sdpMLineIndex, ufrag
+      sdpMid, sdpMLineIndex, usernameFragment
     }))
     .then(() => pc.addIceCandidate({
       candidate: candidateStr2,
       sdpMid: sdpMid2,
       sdpMLineIndex: sdpMLineIndex2,
-      ufrag: ufrag2
+      usernameFragment: usernameFragment2
     }))
     .then(() => {
       assert_candidate_line_between(pc.remoteDescription.sdp,
@@ -298,15 +275,18 @@
   }, 'Adding multiple candidates should add candidates to their corresponding media stream');
 
   /*
-    4.3.2.  addIceCandidate
+    4.4.2.  addIceCandidate
       4.6.  If candidate.candidate is an empty string, process candidate as an
             end-of-candidates indication for the corresponding media description
             and ICE candidate generation.
         2.  If candidate is applied successfully, the user agent MUST queue
             a task that runs the following steps:
-          2.  Let remoteDescription be connection's pendingRemoteDescription
-              if not null, otherwise connection's currentRemoteDescription.
-          3.  Add candidate to remoteDescription.
+          2.  If connection.pendingRemoteDescription is non-null, and represents
+              the ICE generation for which candidate was processed, add
+              candidate to connection.pendingRemoteDescription.
+          3.  If connection.currentRemoteDescription is non-null, and represents
+              the ICE generation for which candidate was processed, add
+              candidate to connection.currentRemoteDescription.
    */
   promise_test(t => {
     const pc = new RTCPeerConnection();
@@ -316,12 +296,12 @@
     return pc.setRemoteDescription(sessionDesc)
     .then(() => pc.addIceCandidate({
       candidate: candidateStr1,
-      sdpMid, sdpMLineIndex, ufrag
+      sdpMid, sdpMLineIndex, usernameFragment
     }))
     .then(() => pc.addIceCandidate({
       candidate: '',
       sdpMid, sdpMLineIndex,
-      ufrag
+      usernameFragment
     }))
     .then(() => {
       assert_candidate_line_between(pc.remoteDescription.sdp,
@@ -333,7 +313,7 @@
   }, 'Add with empty candidate string (end of candidate) should succeed');
 
   /*
-    4.3.2.  addIceCandidate
+    4.4.2.  addIceCandidate
       3.  If both sdpMid and sdpMLineIndex are null, return a promise rejected
           with a newly created TypeError.
    */
@@ -403,12 +383,12 @@
           candidate: '',
           sdpMid: null,
           sdpMLineIndex: null,
-          ufrag: undefined
+          usernameFragment: undefined
         })));
   }, 'Add candidate with manually filled default values should reject with TypeError');
 
   /*
-    4.3.2.  addIceCandidate
+    4.4.2.  addIceCandidate
       4.3.  If candidate.sdpMid is not null, run the following steps:
         1.  If candidate.sdpMid is not equal to the mid of any media
             description in remoteDescription , reject p with a newly
@@ -424,12 +404,12 @@
       promise_rejects(t, 'OperationError',
         pc.addIceCandidate({
           candidate: candidateStr1,
-          sdpMid: 'invalid', sdpMLineIndex, ufrag
+          sdpMid: 'invalid', sdpMLineIndex, usernameFragment
         })));
   }, 'Add candidate with invalid sdpMid should reject with OperationError');
 
   /*
-    4.3.2.  addIceCandidate
+    4.4.2.  addIceCandidate
       4.4.  Else, if candidate.sdpMLineIndex is not null, run the following
           steps:
         1.  If candidate.sdpMLineIndex is equal to or larger than the
@@ -447,7 +427,7 @@
         pc.addIceCandidate({
           candidate: candidateStr1,
           sdpMLineIndex: 2,
-          ufrag
+          usernameFragment
         })));
   }, 'Add candidate with invalid sdpMLineIndex should reject with OperationError');
 
@@ -463,7 +443,7 @@
       candidate: candidateStr1,
       sdpMid,
       sdpMLineIndex: 2,
-      ufrag
+      usernameFragment
     }));
   }, 'Invalid sdpMLineIndex should be ignored if valid sdpMid is provided');
 
@@ -477,18 +457,18 @@
       candidate: candidateStr2,
       sdpMid: sdpMid2,
       sdpMLineIndex: sdpMLineIndex2,
-      ufrag: null
+      usernameFragment: null
     }))
     .then(() => {
       assert_candidate_line_after(pc.remoteDescription.sdp,
         mediaLine2, candidateLine2);
     });
-  }, 'Add candidate for media stream 2 with null ufrag should succeed');
+  }, 'Add candidate for media stream 2 with null usernameFragment should succeed');
 
   /*
     4.3.2.  addIceCandidate
-      4.5.  If candidate.ufrag is neither undefined nor null, and is not equal
-            to any ufrag present in the corresponding media description of an
+      4.5.  If candidate.usernameFragment is neither undefined nor null, and is not equal
+            to any usernameFragment present in the corresponding media description of an
             applied remote description, reject p with a newly created
             OperationError and abort these steps.
    */
@@ -503,12 +483,12 @@
         pc.addIceCandidate({
           candidate: candidateStr1,
           sdpMid, sdpMLineIndex,
-          ufrag: 'invalid'
+          usernameFragment: 'invalid'
         })));
-  }, 'Add candidate with invalid ufrag should reject with OperationError');
+  }, 'Add candidate with invalid usernameFragment should reject with OperationError');
 
   /*
-    4.3.2.  addIceCandidate
+    4.4.2.  addIceCandidate
       4.6.1.  If candidate could not be successfully added the user agent MUST
              queue a task that runs the following steps:
         2.  Reject p with a DOMException object whose name attribute has
@@ -524,7 +504,7 @@
       promise_rejects(t, 'OperationError',
         pc.addIceCandidate({
           candidate: invalidCandidateStr,
-          sdpMid, sdpMLineIndex, ufrag
+          sdpMid, sdpMLineIndex, usernameFragment
         })));
   }, 'Add candidate with invalid candidate string should reject with OperationError');
 
@@ -540,52 +520,8 @@
           candidate: candidateStr2,
           sdpMid: sdpMid2,
           sdpMLineIndex: sdpMLineIndex2,
-          ufrag: ufrag
+          usernameFragment
         })));
-  }, 'Add candidate with sdpMid belonging to different ufrag should reject with OperationError');
+  }, 'Add candidate with sdpMid belonging to different usernameFragment should reject with OperationError');
 
-  /*
-    TODO
-    4.3.2.  addIceCandidate
-      4.6.  In parallel, add the ICE candidate candidate as described in [JSEP]
-            (section 4.1.17.). Use candidate.ufrag to identify the ICE generation;
-
-            If the ufrag is null, process the candidate for the most recent ICE
-            generation.
-
-    - Call with candidate string containing partial malformed syntax, i.e. malformed IP.
-      Some browsers may ignore the syntax error and add it to the SDP regardless.
-
-    Non-Testable
-    4.3.2.  addIceCandidate
-      4.6.  (The steps are non-testable because the abort step in enqueue operation
-            steps in before they can reach here):
-        1.  If candidate could not be successfully added the user agent MUST
-            queue a task that runs the following steps:
-          1.  If connection's [[isClosed]] slot is true, then abort
-              these steps.
-
-        2.  If candidate is applied successfully, the user agent MUST queue
-            a task that runs the following steps:
-          1.  If connection's [[isClosed]] slot is true, then abort these steps.
-
-    Issues
-      w3c/webrtc-pc#1213
-        addIceCandidate end of candidates woes
-
-      w3c/webrtc-pc#1216
-        Clarify addIceCandidate behavior when adding candidate after end of candidate
-
-     w3c/webrtc-pc#1227
-        addIceCandidate may add ice candidate to the wrong remote description
-
-      w3c/webrtc-pc#1345
-        Make promise rejection/enqueing consistent
-
-    Coverage Report
-      Total:        23
-      Tested:       19
-      Not Tested:    2
-      Non-Testable:  2
-   */
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-helper.js b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-helper.js
index b13e5809..330ce19 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-helper.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-helper.js
@@ -358,7 +358,7 @@
    */
   canCreate(requested) {
     const supported = {
-      audio: !!window.MediaStreamAudioDestinationNode,
+      audio: !!window.AudioContext && !!window.MediaStreamAudioDestinationNode,
       video: !!HTMLCanvasElement.prototype.captureStream
     };
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnectionIceEvent-constructor.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnectionIceEvent-constructor.html
index 07e9736..7de7fca 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnectionIceEvent-constructor.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnectionIceEvent-constructor.html
@@ -92,11 +92,11 @@
 const candidate = "";
 const sdpMid = "sdpMid";
 const sdpMLineIndex = 1;
-const ufrag = "";
+const usernameFragment = "";
 const url = "foo.bar";
 
 test(() => {
-  const iceCandidate = new RTCIceCandidate({ candidate, sdpMid, sdpMLineIndex, ufrag });
+  const iceCandidate = new RTCIceCandidate({ candidate, sdpMid, sdpMLineIndex, usernameFragment });
   const event = new RTCPeerConnectionIceEvent("type", {
     candidate: iceCandidate,
     url,
@@ -108,33 +108,10 @@
 }, "RTCPeerConnectionIceEvent with RTCIceCandidate");
 
 test(() => {
-  const plain = { candidate, sdpMid, sdpMLineIndex, ufrag };
+  const plain = { candidate, sdpMid, sdpMLineIndex, usernameFragment };
   assert_throws(new TypeError(), () => new RTCPeerConnectionIceEvent("type", { candidate: plain }));
 }, "RTCPeerConnectionIceEvent with non RTCIceCandidate object throws");
 
-/*
-This will remain commented out until https://github.com/w3c/webrtc-pc/issues/1232
-is resolved.
-
-test(() => {
-  // When firing an RTCPeerConnectionIceEvent event that contains a RTCIceCandidate
-  // object, it must include values for both sdpMid and sdpMLineIndex.
-
-  assert_throws(new TypeError(), () => {
-    new RTCPeerConnectionIceEvent("type", {
-      candidate: new RTCIceCandidate({ candidate, sdpMid, ufrag })
-    });
-  });
-
-  assert_throws(new TypeError(), () => {
-    new RTCPeerConnectionIceEvent("type", {
-      candidate: new RTCIceCandidate({ candidate, sdpMLineIndex, ufrag })
-    });
-  });
-
-}, "RTCIceCandidate must include values for both sdpMid and sdpMLineIndex");
-*/
-
 test(() => {
   const event = new RTCPeerConnectionIceEvent("type", {
     candidate: null,
@@ -145,4 +122,5 @@
   assert_true(event.bubbles);
   assert_true(event.cancelable);
 }, "RTCPeerConnectionIceEvent bubbles and cancelable");
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/resources/RTCCertificate-postMessage-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/resources/RTCCertificate-postMessage-iframe.html
new file mode 100644
index 0000000..9e52ba0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/resources/RTCCertificate-postMessage-iframe.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<script>
+window.onmessage = async (event) => {
+    let certificate = event.data;
+    if (!certificate)
+        certificate = await RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256'});
+    event.source.postMessage(certificate, "*");
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/simplecall-no-ssrcs.https.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/simplecall-no-ssrcs.https.html
new file mode 100644
index 0000000..266b576
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/simplecall-no-ssrcs.https.html
@@ -0,0 +1,122 @@
+<!doctype html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <title>RTCPeerConnection Connection Test</title>
+  <script src="RTCPeerConnection-helper.js"></script>
+</head>
+<body>
+  <div id="log"></div>
+  <div>
+    <video id="local-view" muted autoplay="autoplay"></video>
+    <video id="remote-view" muted autoplay="autoplay"/>
+    </video>
+  </div>
+
+  <!-- These files are in place when executing on W3C. -->
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script type="text/javascript">
+  var test = async_test('Can set up a basic WebRTC call without announcing ssrcs.', {timeout: 5000});
+
+  var gFirstConnection = null;
+  var gSecondConnection = null;
+
+  // if the remote video gets video data that implies the negotiation
+  // as well as the ICE and DTLS connection are up.
+  document.getElementById('remote-view')
+      .addEventListener('loadedmetadata', function() {
+    // Call negotiated: done.
+    test.done();
+  });
+
+  function getNoiseStreamOkCallback(localStream) {
+    gFirstConnection = new RTCPeerConnection(null);
+    gFirstConnection.onicecandidate = onIceCandidateToFirst;
+    localStream.getTracks().forEach(function(track) {
+      gFirstConnection.addTrack(track, localStream);
+    });
+    gFirstConnection.createOffer().then(onOfferCreated, failed('createOffer'));
+
+    var videoTag = document.getElementById('local-view');
+    videoTag.srcObject = localStream;
+  };
+
+  var onOfferCreated = test.step_func(function(offer) {
+    gFirstConnection.setLocalDescription(offer);
+
+    // remove all a=ssrc: lines, the msid-semantic line and any a=msid:.
+    var sdp = offer.sdp.replace(/^a=ssrc:.*$\r\n/gm, '')
+      .replace(/^a=msid-semantic.*$\r\n/gm, '')
+      .replace(/^a=msid:.*$\r\n/gm, '');
+
+    // This would normally go across the application's signaling solution.
+    // In our case, the "signaling" is to call this function.
+    receiveCall(sdp);
+  });
+
+  function receiveCall(offerSdp) {
+    gSecondConnection = new RTCPeerConnection(null);
+    gSecondConnection.onicecandidate = onIceCandidateToSecond;
+    gSecondConnection.ontrack = onRemoteTrack;
+
+    var parsedOffer = new RTCSessionDescription({ type: 'offer',
+                                                  sdp: offerSdp });
+    gSecondConnection.setRemoteDescription(parsedOffer);
+
+    gSecondConnection.createAnswer().then(onAnswerCreated,
+                                   failed('createAnswer'));
+  };
+
+  var onAnswerCreated = test.step_func(function(answer) {
+    gSecondConnection.setLocalDescription(answer);
+
+    // remove all a=ssrc: lines, the msid-semantic line and any a=msid:.
+    var sdp = answer.sdp.replace(/^a=ssrc:.*$\r\n/gm, '')
+      .replace(/^a=msid-semantic.*$\r\n/gm, '')
+      .replace(/^a=msid:.*$\r\n/gm, '');
+
+    // Similarly, this would go over the application's signaling solution.
+    handleAnswer(sdp);
+  });
+
+  function handleAnswer(answerSdp) {
+    var parsedAnswer = new RTCSessionDescription({ type: 'answer',
+                                                   sdp: answerSdp });
+    gFirstConnection.setRemoteDescription(parsedAnswer);
+  };
+
+  var onIceCandidateToFirst = test.step_func(function(event) {
+    // If event.candidate is null = no more candidates.
+    if (event.candidate) {
+      gSecondConnection.addIceCandidate(event.candidate);
+    }
+  });
+
+  var onIceCandidateToSecond = test.step_func(function(event) {
+    if (event.candidate) {
+      gFirstConnection.addIceCandidate(event.candidate);
+    }
+  });
+
+  var onRemoteTrack = test.step_func(function(event) {
+    var videoTag = document.getElementById('remote-view');
+    if (!videoTag.srcObject) {
+      videoTag.srcObject = event.streams[0];
+    }
+  });
+
+  // Returns a suitable error callback.
+  function failed(function_name) {
+    return test.unreached_func('WebRTC called error callback for ' + function_name);
+  }
+
+  // This function starts the test.
+  test.step(function() {
+    getNoiseStream({ video: true, audio: true })
+      .then(test.step_func(getNoiseStreamOkCallback), failed('getNoiseStream'));
+  });
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webxr/idlharness.https.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webxr/idlharness.https.window-expected.txt
index 2528268..794ad858 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webxr/idlharness.https.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webxr/idlharness.https.window-expected.txt
@@ -186,7 +186,10 @@
 FAIL XRCoordinateSystemEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "XRCoordinateSystemEvent" expected property "XRCoordinateSystemEvent" missing
 FAIL XRCoordinateSystemEvent interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "XRCoordinateSystemEvent" expected property "XRCoordinateSystemEvent" missing
 FAIL XRCoordinateSystemEvent interface: attribute coordinateSystem assert_own_property: self does not have own property "XRCoordinateSystemEvent" expected property "XRCoordinateSystemEvent" missing
+PASS WebGLRenderingContext interface: operation setCompatibleXRDevice(XRDevice)
 PASS Navigator interface: attribute xr
 PASS Navigator interface: navigator must inherit property "xr" with the proper type
+PASS WorkerGlobalScope interface: existence and properties of interface object
+PASS WorkerNavigator interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/idlharness.any.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/xhr/idlharness.any.sharedworker-expected.txt
index 50788e8..a388bd7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/xhr/idlharness.any.sharedworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/idlharness.any.sharedworker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 164 tests; 162 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 170 tests; 168 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS XMLHttpRequestEventTarget interface: existence and properties of interface object
 PASS XMLHttpRequestEventTarget interface object length
@@ -164,5 +164,11 @@
 PASS ProgressEvent interface: new ProgressEvent("type") must inherit property "total" with the proper type
 PASS Node interface: existence and properties of interface object
 PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/idlharness.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/xhr/idlharness.any.worker-expected.txt
index 50788e8..a388bd7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/xhr/idlharness.any.worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/idlharness.any.worker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 164 tests; 162 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 170 tests; 168 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS XMLHttpRequestEventTarget interface: existence and properties of interface object
 PASS XMLHttpRequestEventTarget interface object length
@@ -164,5 +164,11 @@
 PASS ProgressEvent interface: new ProgressEvent("type") must inherit property "total" with the proper type
 PASS Node interface: existence and properties of interface object
 PASS Document interface: existence and properties of interface object
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentFragment interface: existence and properties of interface object
+PASS ShadowRoot interface: existence and properties of interface object
+PASS Element interface: existence and properties of interface object
+PASS CharacterData interface: existence and properties of interface object
+PASS Text interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt
index 03a5dbd..90f5fed 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt
@@ -59,16 +59,6 @@
           "object": "LayoutNGBlockFlow (positioned) DIV class='container'",
           "rect": [0, 0, 400, 250],
           "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
-          "rect": [0, 0, 6, 250],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'",
-          "rect": [0, 125, 6, 30],
-          "reason": "geometry"
         }
       ]
     }
@@ -150,16 +140,6 @@
           "object": "Scrolling background of LayoutView #document",
           "rect": [400, 0, 400, 600],
           "reason": "incremental"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
-          "rect": [0, 0, 6, 600],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'",
-          "rect": [0, 300, 6, 30],
-          "reason": "geometry"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/platform/fuchsia/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt b/third_party/WebKit/LayoutTests/platform/fuchsia/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt
new file mode 100644
index 0000000..b9b9989
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/fuchsia/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+PASS Transformed progress for step-start function
+PASS Transformed progress for steps(1, start) function
+PASS Transformed progress for steps(2, start) function
+PASS Transformed progress for step-end function
+PASS Transformed progress for steps(1) function
+PASS Transformed progress for steps(1, end) function
+PASS Transformed progress for steps(2, end) function
+PASS Transformed progress for frames function
+PASS Transformed progress for linear function
+FAIL Transformed progress for ease function assert_approx_equals: The progress should be approximately 0.40851059137130497 at 250ms expected 0.40851059137130497 +/- 0.01 but got 0.41869212962962965
+PASS Transformed progress for ease-in function
+PASS Transformed progress for ease-in-out function
+PASS Transformed progress for ease-out function
+PASS Transformed progress for easing function which produces values greater than 1
+PASS Transformed progress for easing function which produces values less than 1
+FAIL Test bounds point of step-start easing assert_equals: Progress at 0ms expected 0 but got 0.5
+FAIL Test bounds point of step-start easing with reverse direction assert_equals: Progress at 2000ms expected 0 but got 0.5
+PASS Test bounds point of step-start easing with iterationStart not at a transition point
+FAIL Test bounds point of step-start easing with iterationStart and delay assert_equals: Progress at 0ms expected 0.5 but got 1
+FAIL Test bounds point of step-start easing with iterationStart and reverse direction assert_equals: Progress at 2000ms expected 0.5 but got 1
+FAIL Test bounds point of step(4, start) easing with iterationStart 0.75 and delay assert_equals: Progress at 0ms expected 0.75 but got 1
+FAIL Test bounds point of step-start easing with alternate direction assert_equals: Progress at 3000ms expected 0.5 but got 1
+FAIL Test bounds point of step-start easing with alternate-reverse direction assert_equals: Progress at 3000ms expected 0.5 but got 1
+PASS Test bounds point of step-end easing
+FAIL Test bounds point of step-end easing with iterationStart and delay assert_equals: Progress at 0ms expected 0 but got 0.5
+PASS Test bounds point of step-end easing with iterationStart not at a transition point
+PASS Test bounds point of frames easing
+PASS Test bounds point of frames easing with iterationStart and delay
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
similarity index 81%
rename from third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
index 072fce1..5c4ccbcc 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
@@ -5,6 +5,6 @@
 PASS Update the registration with a different script type (module => classic) and with a same main script.
 PASS Does not update the registration with the same script type and the same main script.
 FAIL Update the registration with a different script type (classic => module) and with a same main script. Expect evaluation failed. assert_unreached: Should have rejected: Registering with invalid evaluation should be failed. Reached unreachable code
-FAIL Update the registration with a different script type (module => classic) and with a same main script. Expect evaluation failed. assert_unreached: Should have rejected: Registering with invalid evaluation should be failed. Reached unreachable code
+PASS Update the registration with a different script type (module => classic) and with a same main script. Expect evaluation failed.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
deleted file mode 100644
index 072fce1..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a testharness.js-based test.
-PASS Update the registration with a different script type (classic => module).
-PASS Update the registration with a different script type (module => classic).
-PASS Update the registration with a different script type (classic => module) and with a same main script.
-PASS Update the registration with a different script type (module => classic) and with a same main script.
-PASS Does not update the registration with the same script type and the same main script.
-FAIL Update the registration with a different script type (classic => module) and with a same main script. Expect evaluation failed. assert_unreached: Should have rejected: Registering with invalid evaluation should be failed. Reached unreachable code
-FAIL Update the registration with a different script type (module => classic) and with a same main script. Expect evaluation failed. assert_unreached: Should have rejected: Registering with invalid evaluation should be failed. Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/simplecall-no-ssrcs.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/simplecall-no-ssrcs.https-expected.txt
new file mode 100644
index 0000000..d918011
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/simplecall-no-ssrcs.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+TIMEOUT Can set up a basic WebRTC call without announcing ssrcs. Test timed out
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
index 072fce1..5c4ccbcc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
@@ -5,6 +5,6 @@
 PASS Update the registration with a different script type (module => classic) and with a same main script.
 PASS Does not update the registration with the same script type and the same main script.
 FAIL Update the registration with a different script type (classic => module) and with a same main script. Expect evaluation failed. assert_unreached: Should have rejected: Registering with invalid evaluation should be failed. Reached unreachable code
-FAIL Update the registration with a different script type (module => classic) and with a same main script. Expect evaluation failed. assert_unreached: Should have rejected: Registering with invalid evaluation should be failed. Reached unreachable code
+PASS Update the registration with a different script type (module => classic) and with a same main script. Expect evaluation failed.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/simplecall-no-ssrcs.https-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/simplecall-no-ssrcs.https-expected.txt
new file mode 100644
index 0000000..d918011
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/simplecall-no-ssrcs.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+TIMEOUT Can set up a basic WebRTC call without announcing ssrcs. Test timed out
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
deleted file mode 100644
index 072fce1..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-registration-with-type.https-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a testharness.js-based test.
-PASS Update the registration with a different script type (classic => module).
-PASS Update the registration with a different script type (module => classic).
-PASS Update the registration with a different script type (classic => module) and with a same main script.
-PASS Update the registration with a different script type (module => classic) and with a same main script.
-PASS Does not update the registration with the same script type and the same main script.
-FAIL Update the registration with a different script type (classic => module) and with a same main script. Expect evaluation failed. assert_unreached: Should have rejected: Registering with invalid evaluation should be failed. Reached unreachable code
-FAIL Update the registration with a different script type (module => classic) and with a same main script. Expect evaluation failed. assert_unreached: Should have rejected: Registering with invalid evaluation should be failed. Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/scrollbars/mock-scrollbars-expected.html b/third_party/WebKit/LayoutTests/scrollbars/mock-scrollbars-expected.html
new file mode 100644
index 0000000..c6e79bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/scrollbars/mock-scrollbars-expected.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<style>body { overflow:hidden; }</style>
+<p>The scrollable container below should not appear to be scrollable.</p>
+<div id="child" style="display:none; overflow:scroll; width:200px; height:200px;">
+  <div style="box-sizing:border-box; border:solid; width:100%; height:100%;"></div>
+</div>
+<script>
+onload = ()=> {
+  if (!window.internals)
+    return;
+  internals.settings.setMockScrollbarsEnabled(true);
+  child.style.display = "block";
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/scrollbars/mock-scrollbars.html b/third_party/WebKit/LayoutTests/scrollbars/mock-scrollbars.html
new file mode 100644
index 0000000..1835dbf8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/scrollbars/mock-scrollbars.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<style>body { overflow:hidden; }</style>
+<p>The scrollable container below should not appear to be scrollable.</p>
+<div style="overflow:scroll; width:200px; height:200px;">
+  <div style="box-sizing:border-box; border:solid; width:100%; height:100%;"></div>
+</div>
+<script>
+onload = ()=> {
+  if (!window.internals)
+    return;
+  internals.settings.setMockScrollbarsEnabled(true);
+}
+</script>
diff --git a/third_party/blink/common/manifest/manifest_mojom_traits.cc b/third_party/blink/common/manifest/manifest_mojom_traits.cc
index d5b2743..9362b4f 100644
--- a/third_party/blink/common/manifest/manifest_mojom_traits.cc
+++ b/third_party/blink/common/manifest/manifest_mojom_traits.cc
@@ -6,7 +6,7 @@
 
 #include "mojo/public/cpp/base/string16_mojom_traits.h"
 #include "third_party/blink/public/common/manifest/web_display_mode_mojom_traits.h"
-#include "third_party/blink/public/common/screen_orientation/web_screen_orientation_enum_traits.h"
+#include "third_party/blink/public/common/screen_orientation/web_screen_orientation_mojom_traits.h"
 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
 #include "url/mojom/url_gurl_mojom_traits.h"
 
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index 25d4fa9..30824751 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -76,7 +76,7 @@
     "page/launching_process_state.h",
     "picture_in_picture/picture_in_picture_control_info.h",
     "privacy_preferences.h",
-    "screen_orientation/web_screen_orientation_enum_traits.h",
+    "screen_orientation/web_screen_orientation_mojom_traits.h",
     "screen_orientation/web_screen_orientation_lock_type.h",
     "screen_orientation/web_screen_orientation_type.h",
     "service_worker/service_worker_status_code.h",
diff --git a/third_party/blink/public/common/screen_orientation/OWNERS b/third_party/blink/public/common/screen_orientation/OWNERS
index 3dc1051..107f97c 100644
--- a/third_party/blink/public/common/screen_orientation/OWNERS
+++ b/third_party/blink/public/common/screen_orientation/OWNERS
@@ -3,7 +3,7 @@
 per-file *.typemap=set noparent
 per-file *.typemap=file://ipc/SECURITY_OWNERS
 
-per-file *enum_traits*.*=set noparent
-per-file *enum_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
 
 # COMPONENT: Blink>ScreenOrientation
diff --git a/third_party/blink/public/common/screen_orientation/screen_orientation_lock_types.typemap b/third_party/blink/public/common/screen_orientation/screen_orientation_lock_types.typemap
index 27e516c..a262ea5 100644
--- a/third_party/blink/public/common/screen_orientation/screen_orientation_lock_types.typemap
+++ b/third_party/blink/public/common/screen_orientation/screen_orientation_lock_types.typemap
@@ -4,5 +4,5 @@
 
 mojom = "//services/device/public/mojom/screen_orientation_lock_types.mojom"
 public_headers = [ "//third_party/blink/public/common/screen_orientation/web_screen_orientation_lock_type.h" ]
-traits_headers = [ "//third_party/blink/public/common/screen_orientation/web_screen_orientation_enum_traits.h" ]
+traits_headers = [ "//third_party/blink/public/common/screen_orientation/web_screen_orientation_mojom_traits.h" ]
 type_mappings = [ "device.mojom.ScreenOrientationLockType=::blink::WebScreenOrientationLockType" ]
diff --git a/third_party/blink/public/common/screen_orientation/web_screen_orientation_enum_traits.h b/third_party/blink/public/common/screen_orientation/web_screen_orientation_mojom_traits.h
similarity index 96%
rename from third_party/blink/public/common/screen_orientation/web_screen_orientation_enum_traits.h
rename to third_party/blink/public/common/screen_orientation/web_screen_orientation_mojom_traits.h
index 0f58d67..05d523f 100644
--- a/third_party/blink/public/common/screen_orientation/web_screen_orientation_enum_traits.h
+++ b/third_party/blink/public/common/screen_orientation/web_screen_orientation_mojom_traits.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_SCREEN_ORIENTATION_WEB_SCREEN_ORIENTATION_ENUM_TRAITS_H_
-#define THIRD_PARTY_BLINK_PUBLIC_COMMON_SCREEN_ORIENTATION_WEB_SCREEN_ORIENTATION_ENUM_TRAITS_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_SCREEN_ORIENTATION_WEB_SCREEN_ORIENTATION_MOJOM_TRAITS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_SCREEN_ORIENTATION_WEB_SCREEN_ORIENTATION_MOJOM_TRAITS_H_
 
 #include "services/device/public/mojom/screen_orientation_lock_types.mojom-shared.h"
 #include "third_party/blink/public/common/screen_orientation/web_screen_orientation_lock_type.h"
@@ -77,4 +77,4 @@
 
 }  // namespace mojo
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_SCREEN_ORIENTATION_WEB_SCREEN_ORIENTATION_ENUM_TRAITS_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_SCREEN_ORIENTATION_WEB_SCREEN_ORIENTATION_MOJOM_TRAITS_H_
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 32134d7..0ec5e150 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -2066,6 +2066,8 @@
   kCSSValueAppearanceNoImplementationSkipBorder = 2614,
   kInstantiateModuleScript = 2615,
   kDynamicImportModuleScript = 2616,
+  kHistoryPushState = 2617,
+  kHistoryReplaceState = 2618,
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
   // Also, run update_use_counter_feature_enum.py in
diff --git a/third_party/blink/renderer/core/frame/history.cc b/third_party/blink/renderer/core/frame/history.cc
index a235dd3..5446de4 100644
--- a/third_party/blink/renderer/core/frame/history.cc
+++ b/third_party/blink/renderer/core/frame/history.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/loader/frame_loader.h"
@@ -212,6 +213,16 @@
                         ExceptionState& exception_state) {
   StateObjectAdded(std::move(data), title, url, ScrollRestorationInternal(),
                    WebFrameLoadType::kStandard, exception_state);
+  UseCounter::Count(GetFrame(), WebFeature::kHistoryPushState);
+}
+
+void History::replaceState(scoped_refptr<SerializedScriptValue> data,
+                           const String& title,
+                           const String& url,
+                           ExceptionState& exception_state) {
+  StateObjectAdded(std::move(data), title, url, ScrollRestorationInternal(),
+                   WebFrameLoadType::kReplaceCurrentItem, exception_state);
+  UseCounter::Count(GetFrame(), WebFeature::kHistoryReplaceState);
 }
 
 KURL History::UrlForState(const String& url_string) {
diff --git a/third_party/blink/renderer/core/frame/history.h b/third_party/blink/renderer/core/frame/history.h
index 2ba91ea..abacee7 100644
--- a/third_party/blink/renderer/core/frame/history.h
+++ b/third_party/blink/renderer/core/frame/history.h
@@ -68,10 +68,7 @@
   void replaceState(scoped_refptr<SerializedScriptValue> data,
                     const String& title,
                     const String& url,
-                    ExceptionState& exception_state) {
-    StateObjectAdded(std::move(data), title, url, ScrollRestorationInternal(),
-                     WebFrameLoadType::kReplaceCurrentItem, exception_state);
-  }
+                    ExceptionState& exception_state);
 
   void setScrollRestoration(const String& value, ExceptionState&);
   String scrollRestoration(ExceptionState&);
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index 8793fdaa..3be6f638 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -2539,7 +2539,7 @@
 
 scoped_refptr<NGLayoutResult> LayoutBlockFlow::CachedLayoutResult(
     const NGConstraintSpace&,
-    const NGBreakToken*) const {
+    const NGBreakToken*) {
   return nullptr;
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h
index 1878f27..2a7cbc5 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -458,7 +458,7 @@
   virtual NGPaintFragment* PaintFragment() const { return nullptr; }
   virtual scoped_refptr<NGLayoutResult> CachedLayoutResult(
       const NGConstraintSpace&,
-      const NGBreakToken*) const;
+      const NGBreakToken*);
   virtual scoped_refptr<const NGLayoutResult> CachedLayoutResultForTesting();
   virtual void SetCachedLayoutResult(const NGConstraintSpace&,
                                      const NGBreakToken*,
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h
index e322d63..cbeb617 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h
@@ -34,6 +34,9 @@
   bool operator==(const NGPhysicalSize& other) const {
     return std::tie(other.width, other.height) == std::tie(width, height);
   }
+  bool operator!=(const NGPhysicalSize& other) const {
+    return !(*this == other);
+  }
 
   bool IsEmpty() const {
     return width == LayoutUnit() || height == LayoutUnit();
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 5f9ef98..c250c2c 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -219,19 +219,14 @@
 
 template <typename Base>
 scoped_refptr<NGLayoutResult> LayoutNGMixin<Base>::CachedLayoutResult(
-    const NGConstraintSpace& constraint_space,
-    const NGBreakToken* break_token) const {
+    const NGConstraintSpace& new_space,
+    const NGBreakToken* break_token) {
   if (!RuntimeEnabledFeatures::LayoutNGFragmentCachingEnabled())
     return nullptr;
   if (!cached_result_ || !Base::cached_constraint_space_ || break_token ||
       Base::NeedsLayout())
     return nullptr;
-  if (constraint_space != *Base::cached_constraint_space_)
-    return nullptr;
-  // The checks above should be enough to bail if layout is incomplete, but
-  // let's verify:
-  DCHECK(
-      IsBlockLayoutComplete(*Base::cached_constraint_space_, *cached_result_));
+  const NGConstraintSpace& old_space = *Base::cached_constraint_space_;
   // If we used to contain abspos items, we can't reuse the fragment, because
   // we can't be sure that the list of items hasn't changed (as we bubble them
   // up during layout). In the case of newly-added abspos items to this
@@ -240,6 +235,32 @@
   // TODO(layout-ng): Come up with a better solution for this
   if (cached_result_->OutOfFlowPositionedDescendants().size())
     return nullptr;
+  if (!new_space.MaySkipLayout(old_space))
+    return nullptr;
+
+  // We won't attempt to guess how initial containing block changes might affect
+  // orthogonal flow root descendants. In that case, just bail if the size has
+  // changed.
+  if (cached_result_->HasOrthogonalFlowRoots() &&
+      new_space.InitialContainingBlockSize() !=
+          old_space.InitialContainingBlockSize())
+    return nullptr;
+
+  if (!new_space.AreSizesEqual(old_space)) {
+    // We need to descend all the way down into BODY if we're in quirks mode,
+    // since it magically follows the viewport size.
+    if (NGBlockNode(this).IsQuirkyAndFillsViewport())
+      return nullptr;
+
+    // If the available / percentage sizes have changed in a way that may affect
+    // layout, we cannot re-use the previous result.
+    if (SizeMayChange(Base::StyleRef(), new_space, old_space))
+      return nullptr;
+  }
+
+  // The checks above should be enough to bail if layout is incomplete, but
+  // let's verify:
+  DCHECK(IsBlockLayoutComplete(old_space, *cached_result_));
   return base::AdoptRef(new NGLayoutResult(*cached_result_));
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
index 26e4f67..eccfd23 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -58,9 +58,8 @@
   // Returns the last layout result for this block flow with the given
   // constraint space and break token, or null if it is not up-to-date or
   // otherwise unavailable.
-  scoped_refptr<NGLayoutResult> CachedLayoutResult(
-      const NGConstraintSpace&,
-      const NGBreakToken*) const final;
+  scoped_refptr<NGLayoutResult> CachedLayoutResult(const NGConstraintSpace&,
+                                                   const NGBreakToken*) final;
 
   void SetCachedLayoutResult(const NGConstraintSpace&,
                              const NGBreakToken*,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index 09c6b0b..f522e15 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -2278,11 +2278,7 @@
 // containing block. Percentage resolution size is minimal size
 // that would fill the ICB.
 LayoutUnit NGBlockLayoutAlgorithm::CalculateDefaultBlockSize() {
-  if (!Node().GetDocument().InQuirksMode())
-    return NGSizeIndefinite;
-
-  bool is_quirky_element = Node().IsDocumentElement() || Node().IsBody();
-  if (is_quirky_element && !Style().HasOutOfFlowPosition()) {
+  if (Node().IsQuirkyAndFillsViewport()) {
     LayoutUnit block_size = ConstraintSpace().AvailableSize().block_size;
     block_size -= ComputeMarginsForSelf(ConstraintSpace(), Style()).BlockSum();
     return block_size.ClampNegativeToZero();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
index 3632a6a..aa9f73485 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -95,12 +95,12 @@
   ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
 
   SetBodyInnerHTML(R"HTML(
-    <div id="box" style="width:30px; height:40px"></div>
+    <div id="box" style="width:30px; height:40%;"></div>
   )HTML");
 
   NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
       WritingMode::kHorizontalTb, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(100), NGSizeIndefinite));
+      NGLogicalSize(LayoutUnit(100), LayoutUnit(100)));
 
   LayoutBlockFlow* block_flow =
       ToLayoutBlockFlow(GetLayoutObjectByElementId("box"));
@@ -117,14 +117,22 @@
   // Test identical, but not pointer-equal, constraint space
   space = ConstructBlockLayoutTestConstraintSpace(
       WritingMode::kHorizontalTb, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(100), NGSizeIndefinite));
+      NGLogicalSize(LayoutUnit(100), LayoutUnit(100)));
   result = block_flow->CachedLayoutResult(space, nullptr);
   EXPECT_NE(result.get(), nullptr);
 
   // Test different constraint space
   space = ConstructBlockLayoutTestConstraintSpace(
       WritingMode::kHorizontalTb, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(200), NGSizeIndefinite));
+      NGLogicalSize(LayoutUnit(200), LayoutUnit(100)));
+  result = block_flow->CachedLayoutResult(space, nullptr);
+  EXPECT_NE(result.get(), nullptr);
+
+  // Test a different constraint space that will actually result in a different
+  // size.
+  space = ConstructBlockLayoutTestConstraintSpace(
+      WritingMode::kHorizontalTb, TextDirection::kLtr,
+      NGLogicalSize(LayoutUnit(200), LayoutUnit(200)));
   result = block_flow->CachedLayoutResult(space, nullptr);
   EXPECT_EQ(result.get(), nullptr);
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
index 0bddc84..225081f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -244,29 +244,10 @@
 }
 
 bool NGConstraintSpace::operator==(const NGConstraintSpace& other) const {
-  return available_size_ == other.available_size_ &&
-         percentage_resolution_size_ == other.percentage_resolution_size_ &&
-         replaced_percentage_resolution_size_ ==
-             other.replaced_percentage_resolution_size_ &&
+  return AreSizesEqual(other) &&
          initial_containing_block_size_ ==
              other.initial_containing_block_size_ &&
-         fragmentainer_block_size_ == other.fragmentainer_block_size_ &&
-         fragmentainer_space_at_bfc_start_ ==
-             other.fragmentainer_space_at_bfc_start_ &&
-         block_direction_fragmentation_type_ ==
-             other.block_direction_fragmentation_type_ &&
-         table_cell_child_layout_phase_ ==
-             other.table_cell_child_layout_phase_ &&
-         flags_ == other.flags_ &&
-         adjoining_floats_ == other.adjoining_floats_ &&
-         writing_mode_ == other.writing_mode_ &&
-         direction_ == other.direction_ &&
-         margin_strut_ == other.margin_strut_ &&
-         bfc_offset_ == other.bfc_offset_ &&
-         floats_bfc_block_offset_ == other.floats_bfc_block_offset_ &&
-         exclusion_space_ == other.exclusion_space_ &&
-         clearance_offset_ == other.clearance_offset_ &&
-         baseline_requests_ == other.baseline_requests_;
+         MaySkipLayout(other);
 }
 
 String NGConstraintSpace::ToString() const {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index afb0548..6aa25234 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -284,6 +284,35 @@
     return NGBaselineRequestList(baseline_requests_);
   }
 
+  // Return true if the two constraint spaces are similar enough that it *may*
+  // be possible to skip re-layout. If true is returned, the caller is expected
+  // to verify that any constraint space size (available size, percentage size,
+  // and so on) changes won't require re-layout, before skipping.
+  bool MaySkipLayout(const NGConstraintSpace& other) const {
+    return fragmentainer_block_size_ == other.fragmentainer_block_size_ &&
+           fragmentainer_space_at_bfc_start_ ==
+               other.fragmentainer_space_at_bfc_start_ &&
+           block_direction_fragmentation_type_ ==
+               other.block_direction_fragmentation_type_ &&
+           table_cell_child_layout_phase_ ==
+               other.table_cell_child_layout_phase_ &&
+           flags_ == other.flags_ &&
+           adjoining_floats_ == other.adjoining_floats_ &&
+           writing_mode_ == other.writing_mode_ &&
+           direction_ == other.direction_ &&
+           margin_strut_ == other.margin_strut_ &&
+           bfc_offset_ == other.bfc_offset_ &&
+           floats_bfc_block_offset_ == other.floats_bfc_block_offset_ &&
+           exclusion_space_ == other.exclusion_space_ &&
+           clearance_offset_ == other.clearance_offset_ &&
+           baseline_requests_ == other.baseline_requests_;
+  }
+  bool AreSizesEqual(const NGConstraintSpace& other) const {
+    return available_size_ == other.available_size_ &&
+           percentage_resolution_size_ == other.percentage_resolution_size_ &&
+           replaced_percentage_resolution_size_ ==
+               other.replaced_percentage_resolution_size_;
+  }
   bool operator==(const NGConstraintSpace&) const;
   bool operator!=(const NGConstraintSpace& other) const {
     return !(*this == other);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 8ace774b..e0a67db 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/text/writing_mode.h"
 
 namespace blink {
 
@@ -56,6 +57,9 @@
     }
   }
 
+  if (child.HasOrthogonalFlowRoots())
+    has_orthogonal_flow_roots_ = true;
+
   return AddChild(child.PhysicalFragment(), child_offset);
 }
 
@@ -82,6 +86,10 @@
     }
   }
 
+  if (!IsParallelWritingMode(child->Style().GetWritingMode(),
+                             Style().GetWritingMode()))
+    has_orthogonal_flow_roots_ = true;
+
   if (!has_last_resort_break_) {
     if (const auto* token = child->BreakToken()) {
       if (token->IsBlockType() &&
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index 7807816..afc2a2a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -229,6 +229,8 @@
 
   bool is_pushed_by_floats_ = false;
 
+  bool has_orthogonal_flow_roots_ = false;
+
   friend class NGPhysicalContainerFragment;
 };
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index a32071c..2711556 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -110,6 +110,14 @@
            (box_->IsBody() || box_->IsTableCell());
   }
 
+  // In quirks mode, in-flow positioned BODY and root elements must completely
+  // fill the viewport. Return true if this is such a node.
+  bool IsQuirkyAndFillsViewport() const {
+    if (!GetDocument().InQuirksMode())
+      return false;
+    return (IsDocumentElement() || IsBody()) && !Style().HasOutOfFlowPosition();
+  }
+
   bool CreatesNewFormattingContext() const {
     return IsBlock() && box_->AvoidsFloats();
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
index 872fdef..fce4aee 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -29,6 +29,7 @@
       has_forced_break_(builder->has_forced_break_),
       is_pushed_by_floats_(builder->is_pushed_by_floats_),
       adjoining_floats_(builder->adjoining_floats_),
+      has_orthogonal_flow_roots_(builder->has_orthogonal_flow_roots_),
       status_(kSuccess) {
   DCHECK(physical_fragment) << "Use the other constructor for aborting layout";
   root_fragment_.fragment_ = std::move(physical_fragment);
@@ -45,6 +46,7 @@
       has_forced_break_(false),
       is_pushed_by_floats_(false),
       adjoining_floats_(kFloatTypeNone),
+      has_orthogonal_flow_roots_(builder->has_orthogonal_flow_roots_),
       status_(status) {
   DCHECK_NE(status, kSuccess)
       << "Use the other constructor for successful layout";
@@ -64,6 +66,7 @@
       has_forced_break_(false),
       is_pushed_by_floats_(builder->is_pushed_by_floats_),
       adjoining_floats_(builder->adjoining_floats_),
+      has_orthogonal_flow_roots_(builder->has_orthogonal_flow_roots_),
       status_(kSuccess) {
   root_fragment_.fragment_ = std::move(physical_fragment);
   oof_positioned_descendants_ = std::move(builder->oof_positioned_descendants_);
@@ -87,6 +90,7 @@
       has_forced_break_(other.has_forced_break_),
       is_pushed_by_floats_(other.is_pushed_by_floats_),
       adjoining_floats_(other.adjoining_floats_),
+      has_orthogonal_flow_roots_(other.has_orthogonal_flow_roots_),
       status_(other.status_) {}
 
 // Define the destructor here, so that we can forward-declare more in the
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
index f2eb0ee..c00139a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -113,6 +113,8 @@
   // the block, and the block will fail to clear).
   NGFloatTypes AdjoiningFloatTypes() const { return adjoining_floats_; }
 
+  bool HasOrthogonalFlowRoots() const { return has_orthogonal_flow_roots_; }
+
  private:
   friend class NGBoxFragmentBuilder;
   friend class NGLineBoxFragmentBuilder;
@@ -147,6 +149,8 @@
   unsigned is_pushed_by_floats_ : 1;
   unsigned adjoining_floats_ : 2;  // NGFloatTypes
 
+  unsigned has_orthogonal_flow_roots_ : 1;
+
   unsigned status_ : 1;
 };
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index 07d5ead..2f7e75d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -51,6 +51,49 @@
   }
 }
 
+inline bool InlineLengthMayChange(Length length,
+                                  const NGConstraintSpace& new_space,
+                                  const NGConstraintSpace& old_space) {
+  // Percentage inline margins will affect the size if the size is unspecified
+  // (auto and similar). So we need to check both available size and the
+  // percentage resolution size in that case.
+  bool is_unspecified =
+      length.IsAuto() || length.IsFitContent() || length.IsFillAvailable();
+  if (is_unspecified) {
+    if (new_space.AvailableSize().inline_size !=
+        old_space.AvailableSize().inline_size)
+      return true;
+  }
+  if (is_unspecified || length.IsPercentOrCalc()) {
+    if (new_space.PercentageResolutionSize().inline_size !=
+        old_space.PercentageResolutionSize().inline_size)
+      return true;
+  }
+  return false;
+}
+
+inline bool BlockLengthMayChange(Length length,
+                                 const NGConstraintSpace& new_space,
+                                 const NGConstraintSpace& old_space) {
+  if (length.IsFillAvailable()) {
+    if (new_space.AvailableSize().block_size !=
+        old_space.AvailableSize().block_size)
+      return true;
+  } else if (length.IsAuto() || length.IsPercentOrCalc()) {
+    // Note that we check percentage resolution changes for 'auto' values here
+    // (in addition to percent values). The reason is that percentage resolution
+    // block sizes may be passed through auto-sized blocks, in some cases,
+    // e.g. for anonymous blocks, and also in quirks mode.
+    if (new_space.PercentageResolutionSize().block_size !=
+        old_space.PercentageResolutionSize().block_size)
+      return true;
+    if (new_space.ReplacedPercentageResolutionSize().block_size !=
+        old_space.ReplacedPercentageResolutionSize().block_size)
+      return true;
+  }
+  return false;
+}
+
 }  // anonymous namespace
 
 bool NeedMinMaxSizeForContentContribution(WritingMode mode,
@@ -617,6 +660,58 @@
   return replaced_size;
 }
 
+bool SizeMayChange(const ComputedStyle& style,
+                   const NGConstraintSpace& new_space,
+                   const NGConstraintSpace& old_space) {
+  DCHECK_EQ(new_space.IsFixedSizeInline(), old_space.IsFixedSizeInline());
+  DCHECK_EQ(new_space.IsFixedSizeBlock(), old_space.IsFixedSizeBlock());
+
+  // Go through all length properties, and, depending on length type
+  // (percentages, auto, etc.), check whether the constraint spaces differ in
+  // such a way that the resulting size *may* change. There are currently many
+  // possible false-positive situations here, as we don't rule out length
+  // changes that won't have any effect on the final size (e.g. if inline-size
+  // is 100px, max-inline-size is 50%, and percentage resolution inline size
+  // changes from 1000px to 500px). If the constraint space has "fixed" size in
+  // a dimension, we can skip checking properties in that dimension and just
+  // look for available size changes, since that's how a "fixed" constraint
+  // space works.
+  if (new_space.IsFixedSizeInline()) {
+    if (new_space.AvailableSize().inline_size !=
+        old_space.AvailableSize().inline_size)
+      return true;
+  } else {
+    if (InlineLengthMayChange(style.LogicalWidth(), new_space, old_space) ||
+        InlineLengthMayChange(style.LogicalMaxWidth(), new_space, old_space) ||
+        InlineLengthMayChange(style.LogicalMaxWidth(), new_space, old_space))
+      return true;
+  }
+
+  if (new_space.IsFixedSizeBlock()) {
+    if (new_space.AvailableSize().block_size !=
+        old_space.AvailableSize().block_size)
+      return true;
+  } else {
+    if (BlockLengthMayChange(style.LogicalHeight(), new_space, old_space) ||
+        BlockLengthMayChange(style.LogicalMinHeight(), new_space, old_space) ||
+        BlockLengthMayChange(style.LogicalMaxHeight(), new_space, old_space))
+      return true;
+  }
+
+  if (new_space.PercentageResolutionSize().inline_size !=
+      old_space.PercentageResolutionSize().inline_size) {
+    // Percentage-based padding is resolved against the inline content box size
+    // of the containing block.
+    if (style.PaddingTop().IsPercentOrCalc() ||
+        style.PaddingRight().IsPercentOrCalc() ||
+        style.PaddingBottom().IsPercentOrCalc() ||
+        style.PaddingLeft().IsPercentOrCalc())
+      return true;
+  }
+
+  return false;
+}
+
 int ResolveUsedColumnCount(int computed_count,
                            LayoutUnit computed_size,
                            LayoutUnit used_gap,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
index 0ad5af7d1..05525c5 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
@@ -158,6 +158,13 @@
                     const NGConstraintSpace&,
                     const base::Optional<MinMaxSize>&);
 
+// Return true if it's possible (but not necessarily guaranteed) that the new
+// constraint space will give a different size compared to the old one, when
+// computed style and child content remain unchanged.
+bool SizeMayChange(const ComputedStyle&,
+                   const NGConstraintSpace& new_space,
+                   const NGConstraintSpace& old_space);
+
 // Based on available inline size, CSS computed column-width, CSS computed
 // column-count and CSS used column-gap, return CSS used column-count.
 CORE_EXPORT int ResolveUsedColumnCount(int computed_count,
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index b9fb338f..931dcb1 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -975,9 +975,13 @@
            !GetLayoutBox()->IsHorizontalWritingMode())) {
         GetLayoutBox()->SetPreferredLogicalWidthsDirty();
       }
-      // If the box is managed by LayoutNG, don't go here. We don't want to
-      // re-enter the NG layout algorithm for this box from here.
-      if (!IsManagedByLayoutNG(*GetLayoutBox())) {
+      if (IsManagedByLayoutNG(*GetLayoutBox())) {
+        // If the box is managed by LayoutNG, don't go here. We don't want to
+        // re-enter the NG layout algorithm for this box from here. Just update
+        // the rectangles, in case scrollbars were added or removed. LayoutNG
+        // has its own scrollbar change detection mechanism.
+        UpdateScrollDimensions();
+      } else {
         if (PreventRelayoutScope::RelayoutIsPrevented()) {
           // We're not doing re-layout right now, but we still want to
           // add the scrollbar to the logical width now, to facilitate parent
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
index 29cd4cdd..24ea094 100644
--- a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
+++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
@@ -613,6 +613,7 @@
     const section = new ObjectUI.ObjectPropertiesSection(obj, titleElement, this._linkifier);
     section.element.classList.add('console-view-object-properties-section');
     section.enableContextMenu();
+    section.setShowSelectionOnKeyboardFocus(true, true);
     this._treeOutlines.push(section);
     return section.element;
   }
diff --git a/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js b/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
index 32fc7dd2..80708be 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
+++ b/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
@@ -1596,7 +1596,7 @@
           treeOutline._element.classList.add('single-node');
         treeOutline.setVisible(true);
         treeOutline.element.treeElementForTest = treeOutline.firstChild();
-        treeOutline.setShowSelectionOnKeyboardFocus(true);
+        treeOutline.setShowSelectionOnKeyboardFocus(true, true);
         resolve({node: treeOutline.element, tree: treeOutline});
       }
     }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/treeoutline.js b/third_party/blink/renderer/devtools/front_end/ui/treeoutline.js
index fd2da1cc..cb4ed7c 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/treeoutline.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/treeoutline.js
@@ -43,6 +43,7 @@
     this.contentElement = this._rootElement._childrenListNode;
     this.contentElement.addEventListener('keydown', this._treeKeyDown.bind(this), false);
 
+    this._preventTabOrder = false;
     this._showSelectionOnKeyboardFocus = false;
     this._focusable = true;
     this.setFocusable(this._focusable);
@@ -54,9 +55,11 @@
 
   /**
    * @param {boolean} show
+   * @param {boolean=} preventTabOrder
    */
-  setShowSelectionOnKeyboardFocus(show) {
+  setShowSelectionOnKeyboardFocus(show, preventTabOrder) {
     this.contentElement.classList.toggle('hide-selection-when-blurred', show);
+    this._preventTabOrder = !!preventTabOrder;
     this._showSelectionOnKeyboardFocus = show;
   }
 
@@ -1072,7 +1075,7 @@
    */
   _setFocusable(focusable) {
     if (focusable) {
-      this._listItemNode.setAttribute('tabIndex', 0);
+      this._listItemNode.setAttribute('tabIndex', this.treeOutline && this.treeOutline._preventTabOrder ? -1 : 0);
       this._listItemNode.addEventListener('focus', this._boundOnFocus, false);
       this._listItemNode.addEventListener('blur', this._boundOnBlur, false);
     } else {
diff --git a/third_party/blink/renderer/modules/payments/payment_response.idl b/third_party/blink/renderer/modules/payments/payment_response.idl
index 31096ecec..f5d94a3 100644
--- a/third_party/blink/renderer/modules/payments/payment_response.idl
+++ b/third_party/blink/renderer/modules/payments/payment_response.idl
@@ -30,7 +30,7 @@
     readonly attribute DOMString? payerPhone;
 
     [CallWith=ScriptState, NewObject] Promise<void> complete(optional PaymentComplete paymentResult = "unknown");
-    [CallWith=ScriptState, NewObject, RuntimeEnabled=PaymentRetry] Promise<void> retry(PaymentValidationErrors errorFields);
+    [CallWith=ScriptState, NewObject, RuntimeEnabled=PaymentRetry] Promise<void> retry(optional PaymentValidationErrors errorFields);
 
     [RuntimeEnabled=PaymentRetry] attribute EventHandler onpayerdetailchange;
 };
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index f57ad1e..6715e71b 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -374,7 +374,8 @@
     return;
 
   UMA_HISTOGRAM_ENUMERATION(
-      "Blink.Canvas.GPUAccelerated2DCanvasDisableDeferralReason", reason);
+      "Blink.Canvas.GPUAccelerated2DCanvasDisableDeferralReason", reason,
+      kDisableDeferralReasonCount);
   FlushRecording();
   // Because we will be discarding the recorder, if the flush failed
   // content will be lost -> force m_haveRecordedDrawCommands to false
diff --git a/third_party/blink/renderer/platform/graphics/graphics_types.h b/third_party/blink/renderer/platform/graphics/graphics_types.h
index 89a94a5..5c71afd 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_types.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_types.h
@@ -135,7 +135,7 @@
   kDisableDeferralReasonSubPixelTextAntiAliasingSupport = 5,
   kDisableDeferralDrawImageWithTextureBackedSourceImage = 6,
   kDisableDeferralReasonLowEndDevice = 7,
-  kMaxValue = kDisableDeferralReasonLowEndDevice,
+  kDisableDeferralReasonCount,
 };
 
 enum MailboxSyncMode {
diff --git a/third_party/byte_buddy/BUILD.gn b/third_party/byte_buddy/BUILD.gn
index 6e9c9a1..b0c1b5d 100644
--- a/third_party/byte_buddy/BUILD.gn
+++ b/third_party/byte_buddy/BUILD.gn
@@ -7,20 +7,17 @@
 java_prebuilt("byte_buddy_java") {
   supports_android = true
   testonly = true
-  enable_bytecode_checks = false
   jar_path = "lib/byte-buddy.jar"
 }
 
 java_prebuilt("byte_buddy_agent_java") {
   supports_android = true
   testonly = true
-  enable_bytecode_checks = false
   jar_path = "lib/byte-buddy-agent.jar"
 }
 
 android_java_prebuilt("byte_buddy_android_java") {
   testonly = true
-  enable_bytecode_checks = false
   deps = [
     "//third_party/android_tools:dx_25_0_2_java",
   ]
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index e17b6465..4c1be06d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -10718,19 +10718,6 @@
   <int value="12" label="LOG_IN_STARTED_FROM_REGISTER_OVERLAY_PROMO"/>
 </enum>
 
-<enum name="DeviceSyncRequestFailureReason">
-  <int value="0" label="Requested succeeded but unexpected result"/>
-  <int value="1" label="Service not yet initialized"/>
-  <int value="2" label="Device offline"/>
-  <int value="3" label="Server endpoint not found"/>
-  <int value="4" label="Authentication error"/>
-  <int value="5" label="Bad request"/>
-  <int value="6" label="Response malformed"/>
-  <int value="7" label="Internal server error"/>
-  <int value="8" label="Unknown network error"/>
-  <int value="9" label="Unknown error"/>
-</enum>
-
 <enum name="DeviceTechnologyType">
   <int value="0" label="Unknown"/>
   <int value="1" label="Ethernet"/>
@@ -20652,6 +20639,8 @@
   <int value="2614" label="CSSValueAppearanceNoImplementationSkipBorder"/>
   <int value="2615" label="InstantiateModuleScript"/>
   <int value="2616" label="DynamicImportModuleScript"/>
+  <int value="2617" label="HistoryPushState"/>
+  <int value="2618" label="HistoryReplaceState"/>
 </enum>
 
 <enum name="FeaturePolicyFeature">
@@ -29827,6 +29816,8 @@
   <int value="-471405972" label="ViewsProfileChooser:disabled"/>
   <int value="-471085510" label="MultiDeviceApi:enabled"/>
   <int value="-470948890" label="OfflinePagesDescriptivePendingStatus:enabled"/>
+  <int value="-470247915"
+      label="AutofillUpstreamEditableExpirationDate:enabled"/>
   <int value="-468697885" label="ArcInputMethod:enabled"/>
   <int value="-462205750" label="enable-service-worker-sync"/>
   <int value="-461292699" label="ContentSuggestionsCategoryOrder:enabled"/>
@@ -30029,6 +30020,7 @@
   <int value="-59401847" label="ContentSuggestionsLargeThumbnail:disabled"/>
   <int value="-58242474" label="ash-disable-swipe-to-close-in-overview-mode"/>
   <int value="-57986995" label="DisablePostScriptPrinting:enabled"/>
+  <int value="-56235502" label="WebRtcHideLocalIpsWithMdns:enabled"/>
   <int value="-55944747" label="disable-child-account-detection"/>
   <int value="-52483823" label="disable-new-video-renderer"/>
   <int value="-52241456" label="enable-single-click-autofill"/>
@@ -30319,6 +30311,7 @@
   <int value="513356954" label="InstantTethering:disabled"/>
   <int value="513372959" label="ViewsProfileChooser:enabled"/>
   <int value="517568645" label="AnimatedAppMenuIcon:disabled"/>
+  <int value="533064367" label="WebRtcHideLocalIpsWithMdns:disabled"/>
   <int value="535131384" label="OmniboxTailSuggestions:enabled"/>
   <int value="535976218" label="enable-plugin-power-saver"/>
   <int value="538468149" label="OfflinePagesCT:enabled"/>
@@ -31094,6 +31087,8 @@
   <int value="1955677113" label="trace-export-events-to-etw"/>
   <int value="1957273171" label="PageAlmostIdle:disabled"/>
   <int value="1957358530" label="ContextualSearchSecondTap:enabled"/>
+  <int value="1957472162"
+      label="AutofillUpstreamEditableExpirationDate:disabled"/>
   <int value="1958387645" label="ScanCardsInWebPayments:enabled"/>
   <int value="1959148757" label="OffMainThreadFetch:enabled"/>
   <int value="1960169775" label="NewPhotoPicker:disabled"/>
@@ -33787,6 +33782,24 @@
   <int value="2" label="SUCCESS">All operations succeeded.</int>
 </enum>
 
+<enum name="MultiDevice_DeviceSyncService_DeviceSyncRequestFailureReason">
+  <int value="0" label="Requested succeeded but unexpected result"/>
+  <int value="1" label="Service not yet initialized"/>
+  <int value="2" label="Device offline"/>
+  <int value="3" label="Server endpoint not found"/>
+  <int value="4" label="Authentication error"/>
+  <int value="5" label="Bad request"/>
+  <int value="6" label="Response malformed"/>
+  <int value="7" label="Internal server error"/>
+  <int value="8" label="Unknown network error"/>
+  <int value="9" label="Unknown error"/>
+</enum>
+
+<enum name="MultiDevice_DeviceSyncService_ForceCryptAuthOperationResult">
+  <int value="0" label="Success"/>
+  <int value="1" label="Service not ready"/>
+</enum>
+
 <enum name="MultiDevice_PostOOBESetupFlow_Page">
   <int value="0" label="Unknown page"/>
   <int value="1" label="Start page"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index d87aca2c..cf4d88f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -17029,6 +17029,11 @@
   </summary>
 </histogram>
 
+<histogram name="CryptAuth.DeviceSync.Result" enum="BooleanSuccess">
+  <owner>hansberry@chromium.org</owner>
+  <summary>Indicates success of performing a DeviceSync.</summary>
+</histogram>
+
 <histogram name="CryptAuth.DeviceSyncSoftwareFeaturesResult"
     enum="BooleanSuccess">
   <owner>hansberry@chromium.org</owner>
@@ -51025,7 +51030,7 @@
 
 <histogram
     name="MultiDevice.DeviceSyncService.FindEligibleDevices.Result.FailureReason"
-    enum="DeviceSyncRequestFailureReason">
+    enum="MultiDevice_DeviceSyncService_DeviceSyncRequestFailureReason">
   <owner>hansberry@chromium.org</owner>
   <summary>
     Breaks down the percentages of reasons when failure occurs on
@@ -51033,6 +51038,18 @@
   </summary>
 </histogram>
 
+<histogram name="MultiDevice.DeviceSyncService.ForceEnrollmentNow.Result"
+    enum="MultiDevice_DeviceSyncService_ForceCryptAuthOperationResult">
+  <owner>hansberry@chromium.org</owner>
+  <summary>Result for when ForceEnrollmentNow is called.</summary>
+</histogram>
+
+<histogram name="MultiDevice.DeviceSyncService.ForceSyncNow.Result"
+    enum="MultiDevice_DeviceSyncService_ForceCryptAuthOperationResult">
+  <owner>hansberry@chromium.org</owner>
+  <summary>Result for when ForceSyncNow is called.</summary>
+</histogram>
+
 <histogram name="MultiDevice.DeviceSyncService.SetSoftwareFeatureState.Result"
     enum="BooleanSuccess">
   <owner>hansberry@chromium.org</owner>
@@ -51041,7 +51058,7 @@
 
 <histogram
     name="MultiDevice.DeviceSyncService.SetSoftwareFeatureState.Result.FailureReason"
-    enum="DeviceSyncRequestFailureReason">
+    enum="MultiDevice_DeviceSyncService_DeviceSyncRequestFailureReason">
   <owner>hansberry@chromium.org</owner>
   <summary>
     Breaks down the percentages of reasons when failure occurs on
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index d2b7982..3912bbf 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -368,6 +368,7 @@
 crbug.com/799080 [ Nexus_5X Android_Webview ] v8.browsing_mobile-future/browse:social:facebook [ Skip ]
 crbug.com/799080 [ Nexus_5X Android_Webview ] v8.browsing_mobile-future/browse:social:facebook [ Skip ]
 crbug.com/875159 [ Win_10 ] v8.browsing_desktop-future/browse:social:facebook_infinite_scroll [ Skip ]
+crbug.com/901534 [ Nexus6_Webview ] v8.browsing_mobile-future/browse:news:toi [ Skip ]
 
 # Benchmark: v8.detached_context_age_in_gc
 crbug.com/770982 [ Win ] v8.detached_context_age_in_gc/Docs_(1_open_document_tab) [ Skip ]
diff --git a/ui/android/window_android.cc b/ui/android/window_android.cc
index c557911a..aed6c8e 100644
--- a/ui/android/window_android.cc
+++ b/ui/android/window_android.cc
@@ -5,6 +5,7 @@
 #include "ui/android/window_android.h"
 
 #include <utility>
+#include <vector>
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
@@ -48,14 +49,30 @@
 
   void OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period);
   void OnPauseChanged(bool paused);
+  void AddBeginFrameCompletionCallback(base::OnceClosure callback);
 
  private:
+  friend class WindowAndroid::ScopedOnBeginFrame;
+
   WindowAndroid* const window_;
   base::ObserverList<viz::BeginFrameObserver>::Unchecked observers_;
   int observer_count_;
   viz::BeginFrameArgs last_begin_frame_args_;
   uint64_t next_sequence_number_;
   bool paused_;
+
+  // Set by ScopedOnBeginFrame.
+  std::vector<base::OnceClosure>* vsync_complete_callbacks_ptr_ = nullptr;
+};
+
+class WindowAndroid::ScopedOnBeginFrame {
+ public:
+  explicit ScopedOnBeginFrame(WindowAndroid::WindowBeginFrameSource* bfs);
+  ~ScopedOnBeginFrame();
+
+ private:
+  WindowAndroid::WindowBeginFrameSource* const begin_frame_source_;
+  std::vector<base::OnceClosure> vsync_complete_callbacks_;
 };
 
 void WindowAndroid::WindowBeginFrameSource::AddObserver(
@@ -83,6 +100,7 @@
       // BeginFrames.
       last_begin_frame_args_.deadline =
           base::TimeTicks::Now() + last_begin_frame_args_.interval;
+      ScopedOnBeginFrame scope(this);
       obs->OnBeginFrame(last_begin_frame_args_);
     }
   }
@@ -100,6 +118,7 @@
 }
 
 void WindowAndroid::WindowBeginFrameSource::OnGpuNoLongerBusy() {
+  ScopedOnBeginFrame scope(this);
   for (auto& obs : observers_)
     obs.OnBeginFrame(last_begin_frame_args_);
 }
@@ -125,6 +144,28 @@
     obs.OnBeginFrameSourcePausedChanged(paused_);
 }
 
+void WindowAndroid::WindowBeginFrameSource::AddBeginFrameCompletionCallback(
+    base::OnceClosure callback) {
+  CHECK(vsync_complete_callbacks_ptr_);
+  vsync_complete_callbacks_ptr_->emplace_back(std::move(callback));
+}
+
+WindowAndroid::ScopedOnBeginFrame::ScopedOnBeginFrame(
+    WindowAndroid::WindowBeginFrameSource* bfs)
+    : begin_frame_source_(bfs) {
+  DCHECK(!begin_frame_source_->vsync_complete_callbacks_ptr_);
+  begin_frame_source_->vsync_complete_callbacks_ptr_ =
+      &vsync_complete_callbacks_;
+}
+
+WindowAndroid::ScopedOnBeginFrame::~ScopedOnBeginFrame() {
+  DCHECK_EQ(&vsync_complete_callbacks_,
+            begin_frame_source_->vsync_complete_callbacks_ptr_);
+  begin_frame_source_->vsync_complete_callbacks_ptr_ = nullptr;
+  for (base::OnceClosure& callback : vsync_complete_callbacks_)
+    std::move(callback).Run();
+}
+
 // static
 WindowAndroid* WindowAndroid::FromJavaWindowAndroid(
     const JavaParamRef<jobject>& jwindow_android) {
@@ -180,8 +221,9 @@
     observer_list_.AddObserver(observer);
 }
 
-void WindowAndroid::AddVSyncCompleteCallback(base::OnceClosure callback) {
-  vsync_complete_callbacks_.emplace_back(std::move(callback));
+void WindowAndroid::AddBeginFrameCompletionCallback(
+    base::OnceClosure callback) {
+  begin_frame_source_->AddBeginFrameCompletionCallback(std::move(callback));
 }
 
 void WindowAndroid::RemoveObserver(WindowAndroidObserver* observer) {
@@ -251,10 +293,6 @@
 
   begin_frame_source_->OnVSync(frame_time, vsync_period);
 
-  for (base::OnceClosure& callback : vsync_complete_callbacks_)
-    std::move(callback).Run();
-  vsync_complete_callbacks_.clear();
-
   if (needs_begin_frames_)
     RequestVSyncUpdate();
 }
diff --git a/ui/android/window_android.h b/ui/android/window_android.h
index 99c2004f..62e7f5ff2 100644
--- a/ui/android/window_android.h
+++ b/ui/android/window_android.h
@@ -8,7 +8,6 @@
 #include <jni.h>
 #include <memory>
 #include <string>
-#include <vector>
 
 #include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
@@ -63,7 +62,9 @@
   viz::BeginFrameSource* GetBeginFrameSource();
 
   // Runs the provided callback as soon as the current vsync was handled.
-  void AddVSyncCompleteCallback(base::OnceClosure callback);
+  // This call is only allowed from inside the OnBeginFrame call from the
+  // BeginFrameSource of this window.
+  void AddBeginFrameCompletionCallback(base::OnceClosure callback);
 
   void SetNeedsAnimate();
   void Animate(base::TimeTicks begin_frame_time);
@@ -96,6 +97,7 @@
 
  private:
   class WindowBeginFrameSource;
+  class ScopedOnBeginFrame;
   friend class DisplayAndroidManager;
   friend class WindowBeginFrameSource;
 
@@ -116,7 +118,6 @@
 
   std::unique_ptr<WindowBeginFrameSource> begin_frame_source_;
   bool needs_begin_frames_;
-  std::vector<base::OnceClosure> vsync_complete_callbacks_;
   float mouse_wheel_scroll_factor_;
   bool vsync_paused_ = false;
 
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index b8e90da..7ee7e8f 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -550,12 +550,10 @@
 }
 
 void Window::AddObserver(WindowObserver* observer) {
-  observer->OnObservingWindow(this);
   observers_.AddObserver(observer);
 }
 
 void Window::RemoveObserver(WindowObserver* observer) {
-  observer->OnUnobservingWindow(this);
   observers_.RemoveObserver(observer);
 }
 
diff --git a/ui/aura/window.h b/ui/aura/window.h
index 025f498..02dc2059 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -659,7 +659,7 @@
   // Makes the window pass all events through to any windows behind it.
   ws::mojom::EventTargetingPolicy event_targeting_policy_;
 
-  base::ObserverList<WindowObserver, true>::Unchecked observers_;
+  base::ObserverList<WindowObserver, true> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(Window);
 };
diff --git a/ui/aura/window_observer.cc b/ui/aura/window_observer.cc
index 9301f4c..1c8a745 100644
--- a/ui/aura/window_observer.cc
+++ b/ui/aura/window_observer.cc
@@ -5,27 +5,13 @@
 #include "ui/aura/window_observer.h"
 
 #include "base/logging.h"
-#include "ui/aura/window.h"
 
 namespace aura {
 
-WindowObserver::WindowObserver() : observing_(0) {
-}
+WindowObserver::WindowObserver() = default;
 
 WindowObserver::~WindowObserver() {
-  CHECK_EQ(0, observing_);
+  CHECK(!IsInObserverList());
 }
 
-void WindowObserver::OnObservingWindow(aura::Window* window) {
-  if (!window->HasObserver(this))
-    observing_++;
-}
-
-void WindowObserver::OnUnobservingWindow(aura::Window* window) {
-  if (window->HasObserver(this))
-    observing_--;
-}
-
-void WindowObserver::OnEmbeddedAppDisconnected(Window* window) {}
-
 }  // namespace aura
diff --git a/ui/aura/window_observer.h b/ui/aura/window_observer.h
index 3f81110..1da8e5f 100644
--- a/ui/aura/window_observer.h
+++ b/ui/aura/window_observer.h
@@ -5,7 +5,7 @@
 #ifndef UI_AURA_WINDOW_OBSERVER_H_
 #define UI_AURA_WINDOW_OBSERVER_H_
 
-#include "base/macros.h"
+#include "base/observer_list_types.h"
 #include "base/strings/string16.h"
 #include "ui/aura/aura_export.h"
 #include "ui/compositor/property_change_reason.h"
@@ -19,7 +19,7 @@
 
 class Window;
 
-class AURA_EXPORT WindowObserver {
+class AURA_EXPORT WindowObserver : public base::CheckedObserver {
  public:
   struct HierarchyChangeParams {
     enum HierarchyChangePhase {
@@ -172,25 +172,10 @@
 
   // Called when the app embedded in |window| disconnects (is no longer
   // embedded).
-  virtual void OnEmbeddedAppDisconnected(Window* window);
+  virtual void OnEmbeddedAppDisconnected(Window* window) {}
 
  protected:
-  virtual ~WindowObserver();
-
- private:
-  friend class Window;
-
-  // Called when this is added as an observer on |window|.
-  void OnObservingWindow(Window* window);
-
-  // Called when this is removed from the observers on |window|.
-  void OnUnobservingWindow(Window* window);
-
-  // Tracks the number of windows being observed to track down
-  // http://crbug.com/365364.
-  int observing_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowObserver);
+  ~WindowObserver() override;
 };
 
 }  // namespace aura
diff --git a/ui/aura/window_port.cc b/ui/aura/window_port.cc
index 2c3b716..80f9c4b 100644
--- a/ui/aura/window_port.cc
+++ b/ui/aura/window_port.cc
@@ -16,7 +16,7 @@
 }
 
 // static
-base::ObserverList<WindowObserver, true>::Unchecked* WindowPort::GetObservers(
+base::ObserverList<WindowObserver, true>* WindowPort::GetObservers(
     Window* window) {
   return &(window->observers_);
 }
diff --git a/ui/aura/window_port.h b/ui/aura/window_port.h
index fa32ae2..be61a6c 100644
--- a/ui/aura/window_port.h
+++ b/ui/aura/window_port.h
@@ -146,8 +146,7 @@
   static WindowPort* Get(Window* window);
 
   // Returns the ObserverList of a Window.
-  static base::ObserverList<WindowObserver, true>::Unchecked* GetObservers(
-      Window* window);
+  static base::ObserverList<WindowObserver, true>* GetObservers(Window* window);
 
  private:
   const Type type_;
diff --git a/ui/base/class_property.cc b/ui/base/class_property.cc
index 01941ed..4aea3041 100644
--- a/ui/base/class_property.cc
+++ b/ui/base/class_property.cc
@@ -67,4 +67,4 @@
   return keys;
 }
 
-} // namespace ui
\ No newline at end of file
+}  // namespace ui
diff --git a/ui/base/test/view_tree_validator.mm b/ui/base/test/view_tree_validator.mm
index 0c59600..8d9ab0d 100644
--- a/ui/base/test/view_tree_validator.mm
+++ b/ui/base/test/view_tree_validator.mm
@@ -5,6 +5,7 @@
 #include "ui/base/test/view_tree_validator.h"
 
 #include <Cocoa/Cocoa.h>
+#include "base/mac/mac_util.h"
 #include "base/strings/sys_string_conversions.h"
 
 namespace {
@@ -28,6 +29,15 @@
          [view isKindOfClass:[NSText class]];
 }
 
+// Returns whether to expect children of |view| to perhaps not fit within its
+// bounds.
+bool IgnoreChildBoundsChecks(NSView* view) {
+  // On macOS 10.14, NSButton has a subview of a private helper class whose
+  // bounds extend a bit outside the NSButton itself. We don't care about this
+  // helper class's bounds being outside the button.
+  return base::mac::IsOS10_14() && [view isKindOfClass:[NSButton class]];
+}
+
 }  // namespace
 
 namespace ui {
@@ -39,7 +49,8 @@
     // 1: Check that every subview's frame lies entirely inside this view's
     // bounds.
     for (NSView* child in view.subviews) {
-      if (!NSContainsRect(view.bounds, child.frame)) {
+      if (!NSContainsRect(view.bounds, child.frame) &&
+          !IgnoreChildBoundsChecks(view)) {
         return base::Optional<ViewTreeProblemDetails>(
             {ViewTreeProblemDetails::VIEW_OUTSIDE_PARENT, child, view});
       }
diff --git a/ui/gfx/mojo/OWNERS b/ui/gfx/mojo/OWNERS
index 34d76d9..8c29d1b 100644
--- a/ui/gfx/mojo/OWNERS
+++ b/ui/gfx/mojo/OWNERS
@@ -3,7 +3,7 @@
 
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
 per-file *.typemap=set noparent
 per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/ui/gfx/mojo/swap_result.typemap b/ui/gfx/mojo/swap_result.typemap
index 76d24a50..ee4deac5 100644
--- a/ui/gfx/mojo/swap_result.typemap
+++ b/ui/gfx/mojo/swap_result.typemap
@@ -4,5 +4,5 @@
 
 mojom = "//ui/gfx/mojo/swap_result.mojom"
 public_headers = [ "//ui/gfx/swap_result.h" ]
-traits_headers = [ "//ui/gfx/mojo/swap_result_enum_traits.h" ]
+traits_headers = [ "//ui/gfx/mojo/swap_result_mojom_traits.h" ]
 type_mappings = [ "gfx.mojom.SwapResult=gfx::SwapResult" ]
diff --git a/ui/gfx/mojo/swap_result_enum_traits.h b/ui/gfx/mojo/swap_result_mojom_traits.h
similarity index 89%
rename from ui/gfx/mojo/swap_result_enum_traits.h
rename to ui/gfx/mojo/swap_result_mojom_traits.h
index c32ca59b..3c37116e 100644
--- a/ui/gfx/mojo/swap_result_enum_traits.h
+++ b/ui/gfx/mojo/swap_result_mojom_traits.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_GFX_MOJO_SWAP_RESULT_ENUM_TRAITS_H_
-#define UI_GFX_MOJO_SWAP_RESULT_ENUM_TRAITS_H_
+#ifndef UI_GFX_MOJO_SWAP_RESULT_MOJOM_TRAITS_H_
+#define UI_GFX_MOJO_SWAP_RESULT_MOJOM_TRAITS_H_
 
 #include "mojo/public/cpp/bindings/enum_traits.h"
 #include "ui/gfx/mojo/swap_result.mojom-shared.h"
@@ -45,4 +45,4 @@
 
 }  // namespace mojo
 
-#endif  // UI_GFX_MOJO_SWAP_RESULT_ENUM_TRAITS_H_
+#endif  // UI_GFX_MOJO_SWAP_RESULT_MOJOM_TRAITS_H_
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn
index 899adc7..e6361d5 100644
--- a/ui/views/mus/BUILD.gn
+++ b/ui/views/mus/BUILD.gn
@@ -169,6 +169,7 @@
     "//cc",
     "//net",
     "//services/ws/public/mojom",
+    "//services/ws/test_ws:mojom",
     "//skia",
     "//testing/gtest",
     "//third_party/icu",
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc
index f9aaac4..4d8ddc7 100644
--- a/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -416,7 +416,10 @@
   content_window()->SetTransparent(translucent);
   window()->SetTransparent(translucent);
 
-  window()->SetProperty(aura::client::kShowStateKey, params.show_state);
+  // The window manager may provide the initial show state, for example for
+  // Chrome OS lock screen windows. https://crbug.com/899055
+  if (params.show_state != ui::SHOW_STATE_DEFAULT)
+    window()->SetProperty(aura::client::kShowStateKey, params.show_state);
 
   if (!params.bounds.IsEmpty())
     SetBoundsInDIP(params.bounds);
diff --git a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
index caeb38a..61782d3 100644
--- a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
+#include "services/ws/test_ws/test_ws.mojom.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/focus_client.h"
@@ -102,6 +103,29 @@
   DISALLOW_COPY_AND_ASSIGN(ExpectsNullCursorClientDuringTearDown);
 };
 
+// Tests that the window service can set the initial show state for a window.
+// https://crbug.com/899055
+TEST_F(DesktopWindowTreeHostMusTest, ShowStateFromWindowService) {
+  // Configure the window service to maximize the next top-level window.
+  test_ws::mojom::TestWsPtr test_ws_ptr;
+  MusClient::Get()->window_tree_client()->connector()->BindInterface(
+      test_ws::mojom::kServiceName, &test_ws_ptr);
+  test_ws::mojom::TestWsAsyncWaiter wait_for(test_ws_ptr.get());
+  wait_for.MaximizeNextWindow();
+
+  // Create a widget with the default show state.
+  Widget widget;
+  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params.bounds = gfx::Rect(0, 0, 100, 100);
+  EXPECT_EQ(ui::SHOW_STATE_DEFAULT, params.show_state);
+  widget.Init(params);
+  aura::test::WaitForAllChangesToComplete();
+
+  // Window service provided the show state.
+  EXPECT_TRUE(widget.IsMaximized());
+}
+
 TEST_F(DesktopWindowTreeHostMusTest, Visibility) {
   std::unique_ptr<Widget> widget(CreateWidget());
   EXPECT_FALSE(widget->IsVisible());