diff --git a/DEPS b/DEPS
index 0408441..fe19d652 100644
--- a/DEPS
+++ b/DEPS
@@ -74,7 +74,7 @@
   # 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': 'c0720db247f466e91a1567de3ed2a6f8b2538fa0',
+  'skia_revision': '526c39f41f62f9ab82ebbeb30cc8762bb0eaa417',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -86,7 +86,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': '9db70de8ecb6bf744c759fc8cd25b1cde717142c',
+  'angle_revision': '87cc90dfaaf78e306eb4758bfdcb4c8977de4452',
   # 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.
@@ -639,7 +639,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '05591bbeae6592fd924caec8e728a4ea86cbb8c9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '3fe1b15413a6fdc1a01451e51b1ee634ad9faa4a', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + '844ce8bb3ac1c5cbc31dd0026cfaf6694ddee631', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index 96eaa9b5..ce72a720 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -15,6 +15,7 @@
   "+components/autofill/core/common",
   "+components/cdm/browser",
   "+components/crash/content/browser",
+  "+components/crash/core",
   "+components/navigation_interception",
   "+components/policy/core/browser",
   "+components/policy/core/common",
diff --git a/android_webview/browser/aw_debug.cc b/android_webview/browser/aw_debug.cc
index 8937cf9..bd9cdf95 100644
--- a/android_webview/browser/aw_debug.cc
+++ b/android_webview/browser/aw_debug.cc
@@ -6,11 +6,11 @@
 #include "android_webview/common/crash_reporter/crash_keys.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
-#include "base/debug/crash_logging.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/threading/thread_restrictions.h"
+#include "components/crash/core/common/crash_key.h"
 #include "jni/AwDebug_jni.h"
 
 using base::android::ConvertJavaStringToUTF16;
@@ -43,12 +43,20 @@
   crash_keys::InitCrashKeysForWebViewTesting();
 }
 
-static void JNI_AwDebug_SetCrashKeyValue(JNIEnv* env,
-                                         const JavaParamRef<jclass>& clazz,
-                                         const JavaParamRef<jstring>& key,
-                                         const JavaParamRef<jstring>& value) {
-  base::debug::SetCrashKeyValue(ConvertJavaStringToUTF8(env, key),
-                                ConvertJavaStringToUTF8(env, value));
+static void JNI_AwDebug_SetWhiteListedKeyForTesting(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz) {
+  static ::crash_reporter::CrashKeyString<32> crash_key(
+      "AW_WHITELISTED_DEBUG_KEY");
+  crash_key.Set("AW_DEBUG_VALUE");
+}
+
+static void JNI_AwDebug_SetNonWhiteListedKeyForTesting(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz) {
+  static ::crash_reporter::CrashKeyString<32> crash_key(
+      "AW_NONWHITELISTED_DEBUG_KEY");
+  crash_key.Set("AW_DEBUG_VALUE");
 }
 
 }  // namespace android_webview
diff --git a/android_webview/common/crash_reporter/crash_keys.cc b/android_webview/common/crash_reporter/crash_keys.cc
index 72c4051..3662ad04a 100644
--- a/android_webview/common/crash_reporter/crash_keys.cc
+++ b/android_webview/common/crash_reporter/crash_keys.cc
@@ -29,8 +29,6 @@
 
 size_t RegisterWebViewCrashKeys() {
   base::debug::CrashKey fixed_keys[] = {
-      {"AW_WHITELISTED_DEBUG_KEY", kSmallSize},
-      {"AW_NONWHITELISTED_DEBUG_KEY", kSmallSize},
       {kClientId, kSmallSize},
       {kChannel, kSmallSize},
       {kActiveURL, kLargeSize},
diff --git a/android_webview/java/src/org/chromium/android_webview/AwDebug.java b/android_webview/java/src/org/chromium/android_webview/AwDebug.java
index 9721789..a3cd6fd1 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwDebug.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwDebug.java
@@ -46,11 +46,16 @@
         nativeInitCrashKeysForWebViewTesting();
     }
 
-    public static void setCrashKeyValue(String key, String value) {
-        nativeSetCrashKeyValue(key, value);
+    public static void setWhiteListedKeyForTesting() {
+        nativeSetWhiteListedKeyForTesting();
+    }
+
+    public static void setNonWhiteListedKeyForTesting() {
+        nativeSetNonWhiteListedKeyForTesting();
     }
 
     private static native boolean nativeDumpWithoutCrashing(String dumpPath);
     private static native void nativeInitCrashKeysForWebViewTesting();
-    private static native void nativeSetCrashKeyValue(String key, String value);
+    private static native void nativeSetWhiteListedKeyForTesting();
+    private static native void nativeSetNonWhiteListedKeyForTesting();
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwDebugTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwDebugTest.java
index 8ff2ce36..9c36a57 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwDebugTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwDebugTest.java
@@ -33,6 +33,8 @@
     public AwActivityTestRule mActivityTestRule = new AwActivityTestRule();
 
     private static final String TAG = "cr_AwDebugTest";
+
+    // These constants must match android_webview/browser/aw_debug.cc.
     private static final String WHITELISTED_DEBUG_KEY = "AW_WHITELISTED_DEBUG_KEY";
     private static final String NON_WHITELISTED_DEBUG_KEY = "AW_NONWHITELISTED_DEBUG_KEY";
     private static final String DEBUG_VALUE = "AW_DEBUG_VALUE";
@@ -58,7 +60,7 @@
         File f = File.createTempFile("dump", ".dmp");
         try {
             AwDebug.initCrashKeysForTesting();
-            AwDebug.setCrashKeyValue(WHITELISTED_DEBUG_KEY, DEBUG_VALUE);
+            AwDebug.setWhiteListedKeyForTesting();
             Assert.assertTrue(AwDebug.dumpWithoutCrashing(f));
             assertContainsCrashKeyValue(f, WHITELISTED_DEBUG_KEY, DEBUG_VALUE);
         } finally {
@@ -73,7 +75,7 @@
         File f = File.createTempFile("dump", ".dmp");
         try {
             AwDebug.initCrashKeysForTesting();
-            AwDebug.setCrashKeyValue(NON_WHITELISTED_DEBUG_KEY, DEBUG_VALUE);
+            AwDebug.setNonWhiteListedKeyForTesting();
             Assert.assertTrue(AwDebug.dumpWithoutCrashing(f));
             assertNotContainsCrashKeyValue(f, NON_WHITELISTED_DEBUG_KEY);
         } finally {
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index ae5b9a4..f15adbe1 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -115,17 +115,6 @@
       ui::ScopedAnimationDurationScaleMode::ZERO_DURATION));
   ui::InitializeInputMethodForTesting();
 
-  if (config_ == Config::MUS && !::switches::IsMusHostingViz()) {
-    ui::ContextFactory* context_factory = nullptr;
-    ui::ContextFactoryPrivate* context_factory_private = nullptr;
-    ui::InitializeContextFactoryForTests(false /* enable_pixel_output */,
-                                         &context_factory,
-                                         &context_factory_private);
-    auto* env = aura::Env::GetInstance();
-    env->set_context_factory(context_factory);
-    env->set_context_factory_private(context_factory_private);
-  }
-
   // Creates Shell and hook with Desktop.
   if (!test_shell_delegate_)
     test_shell_delegate_ = new TestShellDelegate;
@@ -232,7 +221,8 @@
     dbus_thread_manager_initialized_ = false;
   }
 
-  ui::TerminateContextFactoryForTests();
+  if (config_ == Config::CLASSIC)
+    ui::TerminateContextFactoryForTests();
 
   ui::ShutdownInputMethodForTesting();
   zero_duration_mode_.reset();
diff --git a/ash/test/ash_test_suite.cc b/ash/test/ash_test_suite.cc
index 40d7d7f2..74b22840 100644
--- a/ash/test/ash_test_suite.cc
+++ b/ash/test/ash_test_suite.cc
@@ -18,7 +18,6 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
 #include "ui/base/ui_base_switches.h"
-#include "ui/compositor/test/context_factories_for_test.h"
 #include "ui/gfx/gfx_paths.h"
 #include "ui/gl/test/gl_surface_test_support.h"
 
@@ -71,13 +70,15 @@
   env_ = aura::Env::CreateInstance(is_mus || is_mash ? aura::Env::Mode::MUS
                                                      : aura::Env::Mode::LOCAL);
 
-  if (is_mash) {
+  if (is_mus || is_mash) {
     context_factory_ = std::make_unique<aura::test::AuraTestContextFactory>();
     env_->set_context_factory(context_factory_.get());
     env_->set_context_factory_private(nullptr);
     // mus needs to host viz, because ash by itself cannot.
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kMus, switches::kMusHostVizValue);
+    if (is_mash) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kMus, switches::kMusHostVizValue);
+    }
   }
 }
 
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
index 0313b15..7961722 100644
--- a/build/android/pylib/gtest/gtest_test_instance.py
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -282,16 +282,17 @@
     # TODO(jbudorick): Support multiple test suites.
     if len(args.suite_name) > 1:
       raise ValueError('Platform mode currently supports only 1 gtest suite')
+    self._chartjson_result_file = args.chartjson_result_file
     self._exe_dist_dir = None
     self._external_shard_index = args.test_launcher_shard_index
     self._extract_test_list_from_filter = args.extract_test_list_from_filter
     self._filter_tests_lock = threading.Lock()
+    self._gs_test_artifacts_bucket = args.gs_test_artifacts_bucket
     self._shard_timeout = args.shard_timeout
     self._store_tombstones = args.store_tombstones
-    self._total_external_shards = args.test_launcher_total_shards
     self._suite = args.suite_name[0]
     self._symbolizer = stack_symbolizer.Symbolizer(None, False)
-    self._gs_test_artifacts_bucket = args.gs_test_artifacts_bucket
+    self._total_external_shards = args.test_launcher_total_shards
     self._wait_for_java_debugger = args.wait_for_java_debugger
 
     # GYP:
@@ -430,6 +431,10 @@
     return self._gtest_filter
 
   @property
+  def chartjson_result_file(self):
+    return self._chartjson_result_file
+
+  @property
   def package(self):
     return self._apk_helper and self._apk_helper.GetPackageName()
 
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py
index 2e599359..53033406c 100644
--- a/build/android/pylib/local/device/local_device_gtest_run.py
+++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -469,54 +469,71 @@
           device_temp_file.NamedDeviceTemporaryDirectory(
               adb=device.adb, dir='/sdcard/'),
           self._test_instance.gs_test_artifacts_bucket) as test_artifacts_dir:
+        with contextlib_ext.Optional(
+            device_temp_file.DeviceTempFile(
+                adb=device.adb, dir=self._delegate.ResultsDirectory(device)),
+            self._test_instance.chartjson_result_file) as chartjson_result_file:
 
-        flags = list(self._test_instance.flags)
-        if self._test_instance.enable_xml_result_parsing:
-          flags.append('--gtest_output=xml:%s' % device_tmp_results_file.name)
+          flags = list(self._test_instance.flags)
+          if self._test_instance.enable_xml_result_parsing:
+            flags.append('--gtest_output=xml:%s' % device_tmp_results_file.name)
 
-        if self._test_instance.gs_test_artifacts_bucket:
-          flags.append('--test_artifacts_dir=%s' % test_artifacts_dir.name)
+          if self._test_instance.gs_test_artifacts_bucket:
+            flags.append('--test_artifacts_dir=%s' % test_artifacts_dir.name)
 
-        logging.info('flags:')
-        for f in flags:
-          logging.info('  %s', f)
+          if self._test_instance.chartjson_result_file:
+            flags.append('--chartjson_result_file=%s'
+                         % chartjson_result_file.name)
 
-        stream_name = 'logcat_%s_%s_%s' % (
-            hash(tuple(test)),
-            time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()),
-            device.serial)
+          logging.info('flags:')
+          for f in flags:
+            logging.info('  %s', f)
 
-        with self._env.output_manager.ArchivedTempfile(
-            stream_name, 'logcat') as logcat_file:
-          with logcat_monitor.LogcatMonitor(
-              device.adb,
-              filter_specs=local_device_environment.LOGCAT_FILTERS,
-              output_file=logcat_file.name) as logmon:
-            with contextlib_ext.Optional(
-                trace_event.trace(str(test)),
-                self._env.trace_output):
-              output = self._delegate.Run(
-                  test, device, flags=' '.join(flags),
-                  timeout=timeout, retries=0)
-          logmon.Close()
+          stream_name = 'logcat_%s_%s_%s' % (
+              hash(tuple(test)),
+              time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()),
+              device.serial)
 
-        if logcat_file.Link():
-          logging.info('Logcat saved to %s', logcat_file.Link())
+          with self._env.output_manager.ArchivedTempfile(
+              stream_name, 'logcat') as logcat_file:
+            with logcat_monitor.LogcatMonitor(
+                device.adb,
+                filter_specs=local_device_environment.LOGCAT_FILTERS,
+                output_file=logcat_file.name) as logmon:
+              with contextlib_ext.Optional(
+                  trace_event.trace(str(test)),
+                  self._env.trace_output):
+                output = self._delegate.Run(
+                    test, device, flags=' '.join(flags),
+                    timeout=timeout, retries=0)
+            logmon.Close()
 
-        if self._test_instance.enable_xml_result_parsing:
-          try:
-            gtest_xml = device.ReadFile(
-                device_tmp_results_file.name,
-                as_root=True)
-          except device_errors.CommandFailedError as e:
-            logging.warning(
-                'Failed to pull gtest results XML file %s: %s',
-                device_tmp_results_file.name,
-                str(e))
-            gtest_xml = None
+          if logcat_file.Link():
+            logging.info('Logcat saved to %s', logcat_file.Link())
 
-        test_artifacts_url = self._UploadTestArtifacts(device,
-                                                       test_artifacts_dir)
+          if self._test_instance.enable_xml_result_parsing:
+            try:
+              gtest_xml = device.ReadFile(
+                  device_tmp_results_file.name,
+                  as_root=True)
+            except device_errors.CommandFailedError as e:
+              logging.warning(
+                  'Failed to pull gtest results XML file %s: %s',
+                  device_tmp_results_file.name,
+                  str(e))
+              gtest_xml = None
+
+          if self._test_instance.chartjson_result_file:
+            try:
+              device.PullFile(chartjson_result_file.name,
+                              self._test_instance.chartjson_result_file)
+            except device_errors.CommandFailedError as e:
+              logging.warning(
+                  'Failed to pull chartjson results %s: %s',
+                  chartjson_result_file.name, str(e))
+
+          test_artifacts_url = self._UploadTestArtifacts(device,
+                                                         test_artifacts_dir)
 
     for s in self._servers[str(device)]:
       s.Reset()
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 82a4786..3d0350fc3 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -300,6 +300,9 @@
       help='Host directory to which app data files will be'
            ' saved. Used with --app-data-file.')
   parser.add_argument(
+      '--chartjson-result-file',
+      help='If present, store chartjson results on this path.')
+  parser.add_argument(
       '--delete-stale-data',
       dest='delete_stale_data', action='store_true',
       help='Delete stale test data on the device.')
@@ -320,6 +323,10 @@
            'development, but is not safe to use on bots ('
            'http://crbug.com/549214')
   parser.add_argument(
+      '--gs-test-artifacts-bucket',
+      help=('If present, test artifacts will be uploaded to this Google '
+            'Storage bucket.'))
+  parser.add_argument(
       '--gtest_also_run_disabled_tests', '--gtest-also-run-disabled-tests',
       dest='run_disabled', action='store_true',
       help='Also run disabled tests if applicable.')
@@ -360,11 +367,6 @@
       help='Path to file that contains googletest-style filter strings. '
            'See also //testing/buildbot/filters/README.md.')
 
-  parser.add_argument(
-      '--gs-test-artifacts-bucket',
-      help=('If present, test artifacts will be uploaded to this Google '
-            'Storage bucket.'))
-
 
 def AddInstrumentationTestOptions(parser):
   """Adds Instrumentation test options to |parser|."""
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index d91b3e6..8cdfee3 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -301,7 +301,10 @@
         deps += [ "//third_party/adobe/flash:flapper_binaries" ]
       }
 
-      data_deps += [ "//third_party/widevine/cdm:widevinecdmadapter" ]
+      data_deps += [
+        "//chrome/browser/resources/media/mei_preload:component",
+        "//third_party/widevine/cdm:widevinecdmadapter",
+      ]
 
       if (is_multi_dll_chrome) {
         defines += [ "CHROME_MULTIPLE_DLL" ]
@@ -649,7 +652,9 @@
     }
 
     foreach(locale, locales_as_mac_outputs) {
-      outputs += [ "$target_gen_dir/app_infoplist_strings/$locale.lproj/InfoPlist.strings" ]
+      outputs += [
+        "$target_gen_dir/app_infoplist_strings/$locale.lproj/InfoPlist.strings",
+      ]
     }
 
     args =
@@ -1207,9 +1212,7 @@
       if (enable_nacl) {
         framework_contents += [ "Internet Plug-Ins" ]
       }
-      if (_should_bundle_widevine) {
-        framework_contents += [ "Libraries" ]
-      }
+      framework_contents += [ "Libraries" ]
     }
 
     configs += [ "//build/config/compiler:wexit_time_destructors" ]
@@ -1233,6 +1236,7 @@
       ":widevine_cdm_library",
       "//build/config:exe_and_shlib_deps",
       "//chrome/app/nibs:chrome_xibs",
+      "//chrome/browser/resources/media/mei_preload:component_bundle",
     ]
 
     if (is_chrome_branded) {
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f8817bf..8b9d59d 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -273,6 +273,8 @@
     "component_updater/crl_set_component_installer.h",
     "component_updater/file_type_policies_component_installer.cc",
     "component_updater/file_type_policies_component_installer.h",
+    "component_updater/mei_preload_component_installer.cc",
+    "component_updater/mei_preload_component_installer.h",
     "component_updater/optimization_hints_component_installer.cc",
     "component_updater/optimization_hints_component_installer.h",
     "component_updater/origin_trials_component_installer.cc",
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index f3c4b02d..5b4474d 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -1084,6 +1084,17 @@
       << message_;
 }
 
+// Test that WebView does not override autoplay policy.
+IN_PROC_BROWSER_TEST_P(WebViewTest, AutoplayPolicy) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kAutoplayPolicy,
+      switches::autoplay::kDocumentUserActivationRequiredPolicy);
+
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/autoplay"))
+      << message_;
+}
+
 // This test verifies that hiding the guest triggers WebContents::WasHidden().
 IN_PROC_BROWSER_TEST_P(WebViewVisibilityTest, GuestVisibilityChanged) {
   LoadAppWithGuest("web_view/visibility_changed");
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 17ec1d7..c748134 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -57,6 +57,7 @@
 #include "chrome/browser/component_updater/crl_set_component_installer.h"
 #include "chrome/browser/component_updater/downloadable_strings_component_installer.h"
 #include "chrome/browser/component_updater/file_type_policies_component_installer.h"
+#include "chrome/browser/component_updater/mei_preload_component_installer.h"
 #include "chrome/browser/component_updater/optimization_hints_component_installer.h"
 #include "chrome/browser/component_updater/origin_trials_component_installer.h"
 #include "chrome/browser/component_updater/pepper_flash_component_installer.h"
@@ -534,6 +535,8 @@
 #endif
   }
 
+  RegisterMediaEngagementPreloadComponent(cus, base::OnceClosure());
+
 #if defined(OS_WIN)
 #if defined(GOOGLE_CHROME_BUILD)
   RegisterSwReporterComponent(cus);
diff --git a/chrome/browser/component_updater/mei_preload_component_installer.cc b/chrome/browser/component_updater/mei_preload_component_installer.cc
new file mode 100644
index 0000000..f710643
--- /dev/null
+++ b/chrome/browser/component_updater/mei_preload_component_installer.cc
@@ -0,0 +1,144 @@
+// 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/component_updater/mei_preload_component_installer.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/path_service.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/version.h"
+#include "chrome/browser/media/media_engagement_preloaded_list.h"
+#include "components/component_updater/component_updater_paths.h"
+#include "media/base/media_switches.h"
+
+using component_updater::ComponentUpdateService;
+
+namespace {
+
+constexpr base::FilePath::CharType kMediaEngagementPreloadBinaryPbFileName[] =
+    FILE_PATH_LITERAL("preloaded_data.pb");
+
+// The extension id is: aemomkdncapdnfajjbbcbdebjljbpmpj
+constexpr uint8_t kPublicKeySHA256[32] = {
+    0x04, 0xce, 0xca, 0x3d, 0x20, 0xf3, 0xd5, 0x09, 0x91, 0x12, 0x13,
+    0x41, 0x9b, 0x91, 0xfc, 0xf9, 0x19, 0xc4, 0x94, 0x6a, 0xb9, 0x9a,
+    0xe1, 0xaf, 0x3b, 0x9a, 0x95, 0x85, 0x5b, 0x9e, 0x99, 0xed};
+
+constexpr char kMediaEngagementPreloadManifestName[] = "MEI Preload";
+
+void LoadPreloadedDataFromDisk(const base::FilePath& pb_path) {
+  DCHECK(!pb_path.empty());
+  MediaEngagementPreloadedList::GetInstance()->LoadFromFile(pb_path);
+}
+
+}  // namespace
+
+namespace component_updater {
+
+MediaEngagementPreloadComponentInstallerPolicy::
+    MediaEngagementPreloadComponentInstallerPolicy(
+        base::OnceClosure on_load_closure)
+    : on_load_closure_(std::move(on_load_closure)) {}
+
+MediaEngagementPreloadComponentInstallerPolicy::
+    ~MediaEngagementPreloadComponentInstallerPolicy() = default;
+
+bool MediaEngagementPreloadComponentInstallerPolicy::
+    SupportsGroupPolicyEnabledComponentUpdates() const {
+  return false;
+}
+
+bool MediaEngagementPreloadComponentInstallerPolicy::RequiresNetworkEncryption()
+    const {
+  return false;
+}
+
+update_client::CrxInstaller::Result
+MediaEngagementPreloadComponentInstallerPolicy::OnCustomInstall(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) {
+  return update_client::CrxInstaller::Result(0);  // Nothing custom here.
+}
+
+void MediaEngagementPreloadComponentInstallerPolicy::OnCustomUninstall() {}
+
+base::FilePath MediaEngagementPreloadComponentInstallerPolicy::GetInstalledPath(
+    const base::FilePath& base) {
+  return base.Append(kMediaEngagementPreloadBinaryPbFileName);
+}
+
+void MediaEngagementPreloadComponentInstallerPolicy::ComponentReady(
+    const base::Version& version,
+    const base::FilePath& install_dir,
+    std::unique_ptr<base::DictionaryValue> manifest) {
+  base::TaskTraits task_traits = {
+      base::MayBlock(), base::TaskPriority::BACKGROUND,
+      base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN};
+  base::OnceClosure task =
+      base::BindOnce(&LoadPreloadedDataFromDisk, GetInstalledPath(install_dir));
+
+  if (!on_load_closure_) {
+    base::PostTaskWithTraits(FROM_HERE, task_traits, std::move(task));
+  } else {
+    base::PostTaskWithTraitsAndReply(FROM_HERE, task_traits, std::move(task),
+                                     std::move(on_load_closure_));
+  }
+}
+
+// Called during startup and installation before ComponentReady().
+bool MediaEngagementPreloadComponentInstallerPolicy::VerifyInstallation(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) const {
+  // No need to actually validate the proto here, since we'll do the checking
+  // in LoadFromFile().
+  return base::PathExists(GetInstalledPath(install_dir));
+}
+
+base::FilePath
+MediaEngagementPreloadComponentInstallerPolicy::GetRelativeInstallDir() const {
+  return base::FilePath(FILE_PATH_LITERAL("MEIPreload"));
+}
+
+void MediaEngagementPreloadComponentInstallerPolicy::GetHash(
+    std::vector<uint8_t>* hash) const {
+  hash->assign(kPublicKeySHA256,
+               kPublicKeySHA256 + arraysize(kPublicKeySHA256));
+}
+
+std::string MediaEngagementPreloadComponentInstallerPolicy::GetName() const {
+  return kMediaEngagementPreloadManifestName;
+}
+
+update_client::InstallerAttributes
+MediaEngagementPreloadComponentInstallerPolicy::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
+}
+
+std::vector<std::string>
+MediaEngagementPreloadComponentInstallerPolicy::GetMimeTypes() const {
+  return std::vector<std::string>();
+}
+
+void RegisterMediaEngagementPreloadComponent(ComponentUpdateService* cus,
+                                             base::OnceClosure on_load) {
+  if (!base::FeatureList::IsEnabled(media::kPreloadMediaEngagementData))
+    return;
+
+  auto installer = base::MakeRefCounted<ComponentInstaller>(
+      std::make_unique<MediaEngagementPreloadComponentInstallerPolicy>(
+          std::move(on_load)));
+  installer->Register(cus, base::OnceClosure());
+}
+
+}  // namespace component_updater
diff --git a/chrome/browser/component_updater/mei_preload_component_installer.h b/chrome/browser/component_updater/mei_preload_component_installer.h
new file mode 100644
index 0000000..3507d89
--- /dev/null
+++ b/chrome/browser/component_updater/mei_preload_component_installer.h
@@ -0,0 +1,69 @@
+// 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_COMPONENT_UPDATER_MEI_PRELOAD_COMPONENT_INSTALLER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_MEI_PRELOAD_COMPONENT_INSTALLER_H_
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/values.h"
+#include "components/component_updater/component_installer.h"
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace component_updater {
+
+class ComponentUpdateService;
+
+class MediaEngagementPreloadComponentInstallerPolicy
+    : public ComponentInstallerPolicy {
+ public:
+  explicit MediaEngagementPreloadComponentInstallerPolicy(
+      base::OnceClosure on_load_closure);
+  ~MediaEngagementPreloadComponentInstallerPolicy() override;
+
+ private:
+  // The following methods override ComponentInstallerPolicy.
+  bool SupportsGroupPolicyEnabledComponentUpdates() const override;
+  bool RequiresNetworkEncryption() const override;
+  update_client::CrxInstaller::Result OnCustomInstall(
+      const base::DictionaryValue& manifest,
+      const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
+  bool VerifyInstallation(const base::DictionaryValue& manifest,
+                          const base::FilePath& install_dir) const override;
+  void ComponentReady(const base::Version& version,
+                      const base::FilePath& install_dir,
+                      std::unique_ptr<base::DictionaryValue> manifest) override;
+  base::FilePath GetRelativeInstallDir() const override;
+  void GetHash(std::vector<uint8_t>* hash) const override;
+  std::string GetName() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
+  std::vector<std::string> GetMimeTypes() const override;
+
+  static base::FilePath GetInstalledPath(const base::FilePath& base);
+
+  // Called when the data is loaded into the preloaded list.
+  base::OnceClosure on_load_closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaEngagementPreloadComponentInstallerPolicy);
+};
+
+// Call once during startup to make the component update service aware of
+// the MEI Preload component.
+void RegisterMediaEngagementPreloadComponent(ComponentUpdateService* cus,
+                                             base::OnceClosure on_load);
+
+}  // namespace component_updater
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_MEI_PRELOAD_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/extensions/autoplay_browsertest.cc b/chrome/browser/extensions/autoplay_browsertest.cc
new file mode 100644
index 0000000..f1a0210
--- /dev/null
+++ b/chrome/browser/extensions/autoplay_browsertest.cc
@@ -0,0 +1,20 @@
+// 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/extensions/extension_apitest.h"
+#include "media/base/media_switches.h"
+
+class AutoplayExtensionBrowserTest : public ExtensionApiTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ExtensionBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(
+        switches::kAutoplayPolicy,
+        switches::autoplay::kDocumentUserActivationRequiredPolicy);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(AutoplayExtensionBrowserTest, AutoplayAllowed) {
+  ASSERT_TRUE(RunExtensionTest("autoplay")) << message_;
+}
diff --git a/chrome/browser/extensions/extension_webkit_preferences.cc b/chrome/browser/extensions/extension_webkit_preferences.cc
index 73ce8c3..d810d22fe 100644
--- a/chrome/browser/extensions/extension_webkit_preferences.cc
+++ b/chrome/browser/extensions/extension_webkit_preferences.cc
@@ -39,6 +39,11 @@
   // Enable WebGL features that regular pages can't access, since they add
   // more risk of fingerprinting.
   webkit_prefs->privileged_webgl_extensions_enabled = true;
+
+  // Autoplay restrictions should not apply to extensions, packaged apps,
+  // hosted apps, etc. However, they should not apply to apps' webviews.
+  webkit_prefs->autoplay_policy =
+      content::AutoplayPolicy::kNoUserGestureRequired;
 }
 
 }  // namespace extension_webkit_preferences
diff --git a/chrome/browser/media/media_engagement_browsertest.cc b/chrome/browser/media/media_engagement_browsertest.cc
index 6f7db07..10b26b63 100644
--- a/chrome/browser/media/media_engagement_browsertest.cc
+++ b/chrome/browser/media/media_engagement_browsertest.cc
@@ -9,12 +9,16 @@
 #include "base/test/simple_test_clock.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/time/time.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/component_updater/mei_preload_component_installer.h"
 #include "chrome/browser/media/media_engagement_contents_observer.h"
+#include "chrome/browser/media/media_engagement_preloaded_list.h"
 #include "chrome/browser/media/media_engagement_service.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/component_updater/component_updater_service.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/browser_test_utils.h"
 #include "media/base/media_switches.h"
@@ -34,7 +38,7 @@
   // |web_contents| must be non-NULL and needs to stay alive for the
   // entire lifetime of |this|.
   explicit WasRecentlyAudibleWatcher(content::WebContents* web_contents)
-      : web_contents_(web_contents), timer_(new base::Timer(true, true)){};
+      : web_contents_(web_contents), timer_(new base::Timer(true, true)) {}
   ~WasRecentlyAudibleWatcher() = default;
 
   // Waits until WasRecentlyAudible is true.
@@ -47,7 +51,7 @@
       run_loop_.reset(new base::RunLoop());
       run_loop_->Run();
     }
-  };
+  }
 
  private:
   void TestWasRecentlyAudible() {
@@ -55,7 +59,7 @@
       run_loop_->Quit();
       timer_->Stop();
     }
-  };
+  }
 
   content::WebContents* web_contents_;
 
@@ -69,7 +73,7 @@
 
 // Class used to test the Media Engagement service.
 class MediaEngagementBrowserTest : public InProcessBrowserTest {
- public:
+ protected:
   MediaEngagementBrowserTest()
       : task_runner_(new base::TestMockTimeTaskRunner()) {
     http_server_.ServeFilesFromSourceDirectory(kMediaEngagementTestDataPath);
@@ -89,7 +93,7 @@
     InProcessBrowserTest::SetUp();
 
     injected_clock_ = false;
-  };
+  }
 
   void LoadTestPage(const GURL& url) {
     // We can't do this in SetUp as the browser isn't ready yet and we
@@ -97,7 +101,7 @@
     InjectTimerTaskRunner();
 
     ui_test_utils::NavigateToURL(browser(), url);
-  };
+  }
 
   void LoadTestPageAndWaitForPlay(const GURL& url, bool web_contents_muted) {
     LoadTestPage(url);
@@ -110,13 +114,13 @@
                                             bool web_contents_muted) {
     LoadTestPageAndWaitForPlayAndAudible(http_server_.GetURL("/" + page),
                                          web_contents_muted);
-  };
+  }
 
   void LoadTestPageAndWaitForPlayAndAudible(const GURL& url,
                                             bool web_contents_muted) {
     LoadTestPageAndWaitForPlay(url, web_contents_muted);
     WaitForWasRecentlyAudible();
-  };
+  }
 
   void OpenTab(const GURL& url) {
     NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK);
@@ -262,6 +266,23 @@
       base::TimeDelta::FromSeconds(2);
 };
 
+// Class used to test the MEI preload component.
+class MediaEngagementPreloadBrowserTest : public InProcessBrowserTest {
+ public:
+  MediaEngagementPreloadBrowserTest() = default;
+  ~MediaEngagementPreloadBrowserTest() override = default;
+
+  void SetUp() override {
+    scoped_feature_list_.InitWithFeatures({media::kPreloadMediaEngagementData},
+                                          {});
+
+    InProcessBrowserTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
 IN_PROC_BROWSER_TEST_F(MediaEngagementBrowserTest, RecordEngagement) {
   LoadTestPageAndWaitForPlayAndAudible("engagement_test.html", false);
   AdvanceMeaningfulPlaybackTime();
@@ -568,3 +589,14 @@
 
   ExpectScores(1, 1, 3, 3);
 }
+
+IN_PROC_BROWSER_TEST_F(MediaEngagementPreloadBrowserTest,
+                       EnsureSingletonListIsLoaded) {
+  base::RunLoop run_loop;
+  component_updater::RegisterMediaEngagementPreloadComponent(
+      g_browser_process->component_updater(), run_loop.QuitClosure());
+  run_loop.Run();
+
+  // The list should be loaded now.
+  EXPECT_TRUE(MediaEngagementPreloadedList::GetInstance()->loaded());
+}
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 57aebd6..a9a9d00 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -92,7 +92,7 @@
 
 body.hide-fakebox-logo #logo,
 body.hide-fakebox-logo #fakebox {
-  visibility: hidden;
+  opacity: 0;
 }
 
 #logo {
diff --git a/chrome/browser/resources/media/mei_preload/BUILD.gn b/chrome/browser/resources/media/mei_preload/BUILD.gn
new file mode 100644
index 0000000..4216d0e
--- /dev/null
+++ b/chrome/browser/resources/media/mei_preload/BUILD.gn
@@ -0,0 +1,26 @@
+# 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.
+
+mei_preload_sources = [
+  "manifest.json",
+  "preloaded_data.pb",
+]
+
+mei_preload_out_dir = "MEIPreload"
+
+copy("component") {
+  sources = mei_preload_sources
+
+  outputs = [
+    "$root_out_dir/$mei_preload_out_dir/{{source_file_part}}",
+  ]
+}
+
+bundle_data("component_bundle") {
+  sources = mei_preload_sources
+
+  outputs = [
+    "{{bundle_contents_dir}}/Libraries/$mei_preload_out_dir/{{source_file_part}}",
+  ]
+}
diff --git a/chrome/browser/resources/media/mei_preload/manifest.json b/chrome/browser/resources/media/mei_preload/manifest.json
new file mode 100644
index 0000000..bf7e19a1
--- /dev/null
+++ b/chrome/browser/resources/media/mei_preload/manifest.json
@@ -0,0 +1,8 @@
+{
+  "update_url": "https://clients2.google.com/service/update2/crx",
+  "name": "MEI Preload",
+  "description": "Contains preloaded data for Media Engagement",
+  "version": "0.0.0.1",
+  "manifest_version": 2,
+  "icons": {}
+}
diff --git a/chrome/browser/resources/media/mei_preload/preloaded_data.pb b/chrome/browser/resources/media/mei_preload/preloaded_data.pb
new file mode 100644
index 0000000..1302db90
--- /dev/null
+++ b/chrome/browser/resources/media/mei_preload/preloaded_data.pb
Binary files differ
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 58fe4a7e..c324c609 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -545,7 +545,7 @@
 #if !defined(OS_ANDROID)
 // Enables or disables Voice Search on the local NTP.
 const base::Feature kVoiceSearchOnLocalNtp{"VoiceSearchOnLocalNtp",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
+                                           base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn
index 5f4cd50e..fbf86a5 100644
--- a/chrome/installer/linux/BUILD.gn
+++ b/chrome/installer/linux/BUILD.gn
@@ -61,6 +61,8 @@
                     "$root_out_dir/xdg-mime",
                     "$root_out_dir/xdg-settings",
                     "$root_out_dir/locales/en-US.pak",
+                    "$root_out_dir/MEIPreload/manifest.json",
+                    "$root_out_dir/MEIPreload/preloaded_data.pb",
                   ]
 
 action_foreach("calculate_deb_dependencies") {
@@ -348,6 +350,7 @@
     ":theme_files",
     "//chrome",
     "//chrome:packed_resources",
+    "//chrome/browser/resources/media/mei_preload:component",
     "//sandbox/linux:chrome_sandbox",
   ]
   if (enable_nacl) {
diff --git a/chrome/installer/linux/common/installer.include b/chrome/installer/linux/common/installer.include
index 71e8c3f7..73d801a 100644
--- a/chrome/installer/linux/common/installer.include
+++ b/chrome/installer/linux/common/installer.include
@@ -185,6 +185,13 @@
     cp -a '{}' "${STAGEDIR}/${INSTALLDIR}/locales/" \;
   find "${STAGEDIR}/${INSTALLDIR}/locales" -type f -exec chmod 644 '{}' \;
 
+  # MEI Preload
+  if [ -f "${BUILDDIR}/MEIPreload/manifest.json" ]; then
+    install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/MEIPreload/"
+    install -m 644 "${BUILDDIR}/MEIPreload/manifest.json" "${STAGEDIR}/${INSTALLDIR}/MEIPreload/"
+    install -m 644 "${BUILDDIR}/MEIPreload/preloaded_data.pb" "${STAGEDIR}/${INSTALLDIR}/MEIPreload/"
+  fi
+
   # Widevine CDM.
   if [ -f "${BUILDDIR}/libwidevinecdmadapter.so" ]; then
     install -m ${SHLIB_PERMS} -s "${BUILDDIR}/libwidevinecdmadapter.so" "${STAGEDIR}/${INSTALLDIR}/"
diff --git a/chrome/installer/mini_installer/chrome.release b/chrome/installer/mini_installer/chrome.release
index fe8c8c0..bb66e6b 100644
--- a/chrome/installer/mini_installer/chrome.release
+++ b/chrome/installer/mini_installer/chrome.release
@@ -83,3 +83,9 @@
 WidevineCdm\_platform_specific\win_x64\widevinecdm.dll: %(VersionDir)s\WidevineCdm\_platform_specific\win_x64\
 WidevineCdm\_platform_specific\win_x64\widevinecdm.dll.sig: %(VersionDir)s\WidevineCdm\_platform_specific\win_x64\
 WidevineCdm\_platform_specific\win_x64\widevinecdmadapter.dll: %(VersionDir)s\WidevineCdm\_platform_specific\win_x64\
+
+#
+# MEI Preload sub dir
+#
+MEIPreload\manifest.json: %(VersionDir)s\MEIPreload\
+MEIPreload\preloaded_data.pb: %(VersionDir)s\MEIPreload\
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 9abb57ea..bc7d2ce 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1170,6 +1170,7 @@
         "../browser/extensions/app_background_page_apitest.cc",
         "../browser/extensions/app_process_apitest.cc",
         "../browser/extensions/app_window_overrides_browsertest.cc",
+        "../browser/extensions/autoplay_browsertest.cc",
         "../browser/extensions/background_app_browsertest.cc",
         "../browser/extensions/background_page_apitest.cc",
         "../browser/extensions/background_scripts_apitest.cc",
@@ -1981,6 +1982,10 @@
     if (is_chromeos || (is_linux && use_dbus)) {
       sources += [ "../browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc" ]
     }
+
+    if (!is_android && !is_mac) {
+      data_deps += [ "//chrome/browser/resources/media/mei_preload:component" ]
+    }
   }
 }
 
diff --git a/chrome/test/data/extensions/autoplay/background.js b/chrome/test/data/extensions/autoplay/background.js
new file mode 100644
index 0000000..acca268
--- /dev/null
+++ b/chrome/test/data/extensions/autoplay/background.js
@@ -0,0 +1,19 @@
+// 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.
+
+chrome.test.runTests([
+  function autoplay_allowed_without_gesture() {
+    var audio = new Audio();
+    audio.src = 'test.mp4';
+    var allowed = false;
+    audio.play().then(function() {
+      allowed = true;
+    }, function(e) {
+      allowed = e.name != 'NotAllowedError';
+    }).then(function() {
+      chrome.test.assertTrue(allowed);
+      chrome.test.succeed();
+    });
+  }
+]);
diff --git a/chrome/test/data/extensions/autoplay/manifest.json b/chrome/test/data/extensions/autoplay/manifest.json
new file mode 100644
index 0000000..e557187
--- /dev/null
+++ b/chrome/test/data/extensions/autoplay/manifest.json
@@ -0,0 +1,10 @@
+{
+  "name": "autoplay",
+  "description": "autoplay policy test",
+  "version": "1.0",
+  "manifest_version": 2,
+  "background": {
+    "scripts": ["background.js"]
+  },
+  "permissions": [ ]
+}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/autoplay/guest.html b/chrome/test/data/extensions/platform_apps/web_view/autoplay/guest.html
new file mode 100644
index 0000000..9c9c03e
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/autoplay/guest.html
@@ -0,0 +1,11 @@
+<!--
+ * 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.
+-->
+<!DOCTYPE html>
+<html>
+<body>
+  <script src=guest.js></script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/autoplay/guest.js b/chrome/test/data/extensions/platform_apps/web_view/autoplay/guest.js
new file mode 100644
index 0000000..a65cea13
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/autoplay/guest.js
@@ -0,0 +1,13 @@
+// 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.
+
+window.addEventListener('message', function() {
+  var audio = document.createElement('audio');
+  audio.src = 'test.mp4';
+  audio.play().then(() => {
+    console.log('autoplayed');
+  }, e => {
+    console.log(e.name);
+  });
+});
diff --git a/chrome/test/data/extensions/platform_apps/web_view/autoplay/main.html b/chrome/test/data/extensions/platform_apps/web_view/autoplay/main.html
new file mode 100644
index 0000000..55ce5d8b
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/autoplay/main.html
@@ -0,0 +1,12 @@
+<!--
+ * 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.
+-->
+<!DOCTYPE html>
+<html>
+<body>
+  <webview></webview>
+  <script src=main.js></script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/autoplay/main.js b/chrome/test/data/extensions/platform_apps/web_view/autoplay/main.js
new file mode 100644
index 0000000..07d8a62
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/autoplay/main.js
@@ -0,0 +1,20 @@
+// 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.
+
+chrome.test.getConfig(function(config) {
+  var guestUrl = 'http://localhost:' + config.testServer.port +
+      '/extensions/platform_apps/web_view/autoplay/guest.html';
+
+  var webview = document.querySelector('webview');
+  webview.addEventListener('loadstop', function() {
+    webview.onconsolemessage = function(e) {
+      chrome.test.assertEq('NotAllowedError', e.message);
+      chrome.test.succeed();
+    };
+
+    webview.contentWindow.postMessage(JSON.stringify('start'), '*');
+  }, { once: true });
+
+  webview.src = guestUrl;
+});
diff --git a/chrome/test/data/extensions/platform_apps/web_view/autoplay/manifest.json b/chrome/test/data/extensions/platform_apps/web_view/autoplay/manifest.json
new file mode 100644
index 0000000..951d3811
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/autoplay/manifest.json
@@ -0,0 +1,12 @@
+{
+  "name": "<webview> autoplay policy api tests.",
+  "version": "1",
+  "permissions": [
+    "webview"
+  ],
+  "app": {
+    "background": {
+      "scripts": ["test.js"]
+    }
+  }
+}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/autoplay/test.js b/chrome/test/data/extensions/platform_apps/web_view/autoplay/test.js
new file mode 100644
index 0000000..179e639
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/autoplay/test.js
@@ -0,0 +1,7 @@
+// 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.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+  chrome.app.window.create('main.html', {}, function() {});
+});
diff --git a/chrome/test/data/local_ntp/test_utils.js b/chrome/test/data/local_ntp/test_utils.js
index 48995196b..6a818afd 100644
--- a/chrome/test/data/local_ntp/test_utils.js
+++ b/chrome/test/data/local_ntp/test_utils.js
@@ -185,7 +185,8 @@
  */
 function elementIsVisible(elem) {
   return elem && elem.offsetWidth > 0 && elem.offsetHeight > 0 &&
-      window.getComputedStyle(elem).visibility != 'hidden';
+      window.getComputedStyle(elem).visibility != 'hidden' &&
+      window.getComputedStyle(elem).opacity > 0;
 }
 
 
diff --git a/chrome/tools/build/chromeos/FILES.cfg b/chrome/tools/build/chromeos/FILES.cfg
index 53e0e2db..7f936fa 100644
--- a/chrome/tools/build/chromeos/FILES.cfg
+++ b/chrome/tools/build/chromeos/FILES.cfg
@@ -123,4 +123,13 @@
     'filename': 'nacl_helper_nonsfi',
     'buildtype': ['dev', 'official'],
   },
+  # MEI Preload files:
+  {
+    'filename': 'MEIPreload/manifest.json',
+    'buildtype': ['dev', 'official'],
+  },
+  {
+    'filename': 'MEIPreload/preloaded_data.pb',
+    'buildtype': ['dev', 'official'],
+  },
 ]
diff --git a/chrome/tools/build/linux/FILES.cfg b/chrome/tools/build/linux/FILES.cfg
index d6f82c1..19182648 100644
--- a/chrome/tools/build/linux/FILES.cfg
+++ b/chrome/tools/build/linux/FILES.cfg
@@ -300,4 +300,13 @@
     'archive': 'content-shell.zip',
     'optional': ['dev'],
   },
- ]
+  # MEI Preload files:
+  {
+    'filename': 'MEIPreload/manifest.json',
+    'buildtype': ['dev', 'official'],
+  },
+  {
+    'filename': 'MEIPreload/preloaded_data.pb',
+    'buildtype': ['dev', 'official'],
+  },
+]
diff --git a/chrome/tools/build/win/FILES.cfg b/chrome/tools/build/win/FILES.cfg
index d0e5b99..e82d791 100644
--- a/chrome/tools/build/win/FILES.cfg
+++ b/chrome/tools/build/win/FILES.cfg
@@ -862,4 +862,13 @@
     'archive': 'metrics-metadata.zip',
     'optional': ['dev', 'official'],
   },
+  # MEI Preload files:
+  {
+    'filename': 'MEIPreload/manifest.json',
+    'buildtype': ['dev', 'official'],
+  },
+  {
+    'filename': 'MEIPreload/preloaded_data.pb',
+    'buildtype': ['dev', 'official'],
+  },
 ]
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 3825b62..10fa790 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -270,12 +270,7 @@
     bool last_chance,
     const ServiceWorkerVersion::LegacyStatusCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DispatchSyncEvent(
-      tag, std::move(active_version),
-      last_chance
-          ? blink::mojom::BackgroundSyncEventLastChance::IS_LAST_CHANCE
-          : blink::mojom::BackgroundSyncEventLastChance::IS_NOT_LAST_CHANCE,
-      callback);
+  DispatchSyncEvent(tag, std::move(active_version), last_chance, callback);
 }
 
 BackgroundSyncManager::BackgroundSyncManager(
@@ -761,7 +756,7 @@
 void BackgroundSyncManager::DispatchSyncEvent(
     const std::string& tag,
     scoped_refptr<ServiceWorkerVersion> active_version,
-    blink::mojom::BackgroundSyncEventLastChance last_chance,
+    bool last_chance,
     const ServiceWorkerVersion::LegacyStatusCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(active_version);
@@ -998,10 +993,8 @@
 
   num_firing_registrations_ += 1;
 
-  blink::mojom::BackgroundSyncEventLastChance last_chance =
-      registration->num_attempts() == parameters_->max_sync_attempts - 1
-          ? blink::mojom::BackgroundSyncEventLastChance::IS_LAST_CHANCE
-          : blink::mojom::BackgroundSyncEventLastChance::IS_NOT_LAST_CHANCE;
+  const bool last_chance =
+      registration->num_attempts() == parameters_->max_sync_attempts - 1;
 
   HasMainFrameProviderHost(
       service_worker_registration->pattern().GetOrigin(),
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h
index f4f71f3..f91a47f 100644
--- a/content/browser/background_sync/background_sync_manager.h
+++ b/content/browser/background_sync/background_sync_manager.h
@@ -127,7 +127,7 @@
   virtual void DispatchSyncEvent(
       const std::string& tag,
       scoped_refptr<ServiceWorkerVersion> active_version,
-      blink::mojom::BackgroundSyncEventLastChance last_chance,
+      bool last_chance,
       const ServiceWorkerVersion::LegacyStatusCallback& callback);
   virtual void ScheduleDelayedTask(base::OnceClosure callback,
                                    base::TimeDelta delay);
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index 1a2bbb21..1de4472 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -1339,8 +1339,7 @@
   InitFailedSyncEventTest();
 
   EXPECT_TRUE(Register(sync_options_1_));
-  EXPECT_EQ(blink::mojom::BackgroundSyncEventLastChance::IS_NOT_LAST_CHANCE,
-            test_background_sync_manager_->last_chance());
+  EXPECT_FALSE(test_background_sync_manager_->last_chance());
   EXPECT_TRUE(GetRegistration(sync_options_1_));
 
   // Run it again.
@@ -1348,8 +1347,7 @@
   test_background_sync_manager_->RunDelayedTask();
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(GetRegistration(sync_options_1_));
-  EXPECT_EQ(blink::mojom::BackgroundSyncEventLastChance::IS_LAST_CHANCE,
-            test_background_sync_manager_->last_chance());
+  EXPECT_TRUE(test_background_sync_manager_->last_chance());
 }
 
 }  // namespace content
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 3526a90..86261926 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -292,10 +292,9 @@
     helper_->OnPushEventStub(payload, std::move(callback));
   }
 
-  void DispatchSyncEvent(
-      const std::string& tag,
-      blink::mojom::BackgroundSyncEventLastChance last_chance,
-      DispatchSyncEventCallback callback) override {
+  void DispatchSyncEvent(const std::string& tag,
+                         bool last_chance,
+                         DispatchSyncEventCallback callback) override {
     NOTIMPLEMENTED();
   }
 
diff --git a/content/common/service_worker/service_worker_event_dispatcher.mojom b/content/common/service_worker/service_worker_event_dispatcher.mojom
index c462f3a..e3114605 100644
--- a/content/common/service_worker/service_worker_event_dispatcher.mojom
+++ b/content/common/service_worker/service_worker_event_dispatcher.mojom
@@ -8,7 +8,6 @@
 import "content/public/common/url_loader.mojom";
 import "mojo/common/string16.mojom";
 import "mojo/common/time.mojom";
-import "third_party/WebKit/public/platform/modules/background_sync/background_sync.mojom";
 import "third_party/WebKit/public/platform/modules/fetch/fetch_api_request.mojom";
 import "third_party/WebKit/public/platform/modules/payments/payment_app.mojom";
 import "third_party/WebKit/common/service_worker/service_worker_event_status.mojom";
@@ -126,8 +125,7 @@
           mojo.common.mojom.Time dispatch_event_time);
   // Arguments are passed to the event handler as parameters of SyncEvent.
   // Ref: https://wicg.github.io/BackgroundSync/spec/#sync-event
-  DispatchSyncEvent(string id,
-                    blink.mojom.BackgroundSyncEventLastChance last_chance)
+  DispatchSyncEvent(string id, bool last_chance)
       => (blink.mojom.ServiceWorkerEventStatus status,
           mojo.common.mojom.Time dispatch_event_time);
   DispatchAbortPaymentEvent(
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index f667fa82..a2b7b145 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -501,6 +501,10 @@
                                   base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_MACOSX)
 
+// Enables V8 background compilation
+const base::Feature kV8BackgroundCompile{"V8BackgroundCompile",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables to use a snapshot file in creating V8 contexts.
 const base::Feature kV8ContextSnapshot{"V8ContextSnapshot",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 211f61b..915cf124 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -98,6 +98,7 @@
 CONTENT_EXPORT extern const base::Feature kUseMojoAudioOutputStreamFactory;
 CONTENT_EXPORT extern const base::Feature kUserActivationV2;
 CONTENT_EXPORT extern const base::Feature kV8ContextSnapshot;
+CONTENT_EXPORT extern const base::Feature kV8BackgroundCompile;
 CONTENT_EXPORT extern const base::Feature kV8VmFuture;
 CONTENT_EXPORT extern const base::Feature kVibrateRequiresUserGesture;
 CONTENT_EXPORT extern const base::Feature kWebAssembly;
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 997157f9..1c67f37a 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -54,8 +54,6 @@
     "appcache/appcache_frontend_impl.h",
     "appcache/web_application_cache_host_impl.cc",
     "appcache/web_application_cache_host_impl.h",
-    "background_sync/background_sync_type_converters.cc",
-    "background_sync/background_sync_type_converters.h",
     "blob_storage/blob_consolidation.cc",
     "blob_storage/blob_consolidation.h",
     "blob_storage/blob_message_filter.cc",
diff --git a/content/renderer/background_sync/OWNERS b/content/renderer/background_sync/OWNERS
deleted file mode 100644
index 01f2d32..0000000
--- a/content/renderer/background_sync/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-iclelland@chromium.org
-jkarlin@chromium.org
-
-per-file *_type_converter*.*=set noparent
-per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
-# COMPONENT: Blink>BackgroundSync
diff --git a/content/renderer/background_sync/background_sync_type_converters.cc b/content/renderer/background_sync/background_sync_type_converters.cc
deleted file mode 100644
index 19962a6..0000000
--- a/content/renderer/background_sync/background_sync_type_converters.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2015 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/background_sync/background_sync_type_converters.h"
-
-#include "base/logging.h"
-
-namespace mojo {
-
-#define COMPILE_ASSERT_MATCHING_ENUM(mojo_name, blink_name) \
-  static_assert(static_cast<int>(blink::mojo_name) ==       \
-                    static_cast<int>(blink::blink_name),    \
-                "mojo and blink enums must match")
-
-COMPILE_ASSERT_MATCHING_ENUM(
-    mojom::BackgroundSyncEventLastChance::IS_NOT_LAST_CHANCE,
-    WebServiceWorkerContextProxy::kIsNotLastChance);
-COMPILE_ASSERT_MATCHING_ENUM(
-    mojom::BackgroundSyncEventLastChance::IS_LAST_CHANCE,
-    WebServiceWorkerContextProxy::kIsLastChance);
-
-// static
-blink::WebServiceWorkerContextProxy::LastChanceOption
-TypeConverter<blink::WebServiceWorkerContextProxy::LastChanceOption,
-              blink::mojom::BackgroundSyncEventLastChance>::
-    Convert(blink::mojom::BackgroundSyncEventLastChance input) {
-  return static_cast<blink::WebServiceWorkerContextProxy::LastChanceOption>(
-      input);
-}
-
-// static
-blink::mojom::BackgroundSyncEventLastChance
-TypeConverter<blink::mojom::BackgroundSyncEventLastChance,
-              blink::WebServiceWorkerContextProxy::LastChanceOption>::
-    Convert(blink::WebServiceWorkerContextProxy::LastChanceOption input) {
-  return static_cast<blink::mojom::BackgroundSyncEventLastChance>(input);
-}
-
-}  // namespace mojo
diff --git a/content/renderer/background_sync/background_sync_type_converters.h b/content/renderer/background_sync/background_sync_type_converters.h
deleted file mode 100644
index dd9c151..0000000
--- a/content/renderer/background_sync/background_sync_type_converters.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2015 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_BACKGROUND_SYNC_BACKGROUND_SYNC_TYPE_CONVERTERS_H_
-#define CONTENT_RENDERER_BACKGROUND_SYNC_BACKGROUND_SYNC_TYPE_CONVERTERS_H_
-
-#include <memory>
-
-#include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-#include "third_party/WebKit/public/platform/modules/background_sync/background_sync.mojom.h"
-#include "third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h"
-
-namespace mojo {
-
-// blink::WebSyncRegistration::NetworkState <=>
-//     blink::mojom::BackgroundSyncNetworkState
-
-template <>
-struct CONTENT_EXPORT
-    TypeConverter<blink::WebServiceWorkerContextProxy::LastChanceOption,
-                  blink::mojom::BackgroundSyncEventLastChance> {
-  static blink::WebServiceWorkerContextProxy::LastChanceOption Convert(
-      blink::mojom::BackgroundSyncEventLastChance input);
-};
-
-template <>
-struct CONTENT_EXPORT
-    TypeConverter<blink::mojom::BackgroundSyncEventLastChance,
-                  blink::WebServiceWorkerContextProxy::LastChanceOption> {
-  static blink::mojom::BackgroundSyncEventLastChance Convert(
-      blink::WebServiceWorkerContextProxy::LastChanceOption input);
-};
-
-}  // namespace mojo
-
-#endif  // CONTENT_RENDERER_BACKGROUND_SYNC_BACKGROUND_SYNC_TYPE_CONVERTERS_H_
diff --git a/content/renderer/render_process_impl.cc b/content/renderer/render_process_impl.cc
index c3316088c..963cda5 100644
--- a/content/renderer/render_process_impl.cc
+++ b/content/renderer/render_process_impl.cc
@@ -156,6 +156,7 @@
   SetV8FlagIfNotFeature(features::kAsmJsToWebAssembly, "--no-validate-asm");
   SetV8FlagIfNotFeature(features::kWebAssembly,
                         "--wasm-disable-structured-cloning");
+  SetV8FlagIfFeature(features::kV8BackgroundCompile, "--background-compile");
 
   SetV8FlagIfFeature(features::kV8VmFuture, "--future");
   SetV8FlagIfNotFeature(features::kV8VmFuture, "--no-future");
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 22cedcf..b094876 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -31,7 +31,6 @@
 #include "content/public/renderer/child_url_loader_factory_getter.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/document_state.h"
-#include "content/renderer/background_sync/background_sync_type_converters.h"
 #include "content/renderer/devtools/devtools_agent.h"
 #include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/loader/web_data_consumer_handle_impl.h"
@@ -1289,7 +1288,7 @@
 
 void ServiceWorkerContextClient::DispatchSyncEvent(
     const std::string& tag,
-    blink::mojom::BackgroundSyncEventLastChance last_chance,
+    bool last_chance,
     DispatchSyncEventCallback callback) {
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerContextClient::DispatchSyncEvent");
@@ -1297,15 +1296,10 @@
       CreateAbortCallback(&context_->sync_event_callbacks));
   context_->sync_event_callbacks.emplace(request_id, std::move(callback));
 
-  // TODO(shimazu): Use typemap when this is moved to blink-side.
-  blink::WebServiceWorkerContextProxy::LastChanceOption web_last_chance =
-      mojo::ConvertTo<blink::WebServiceWorkerContextProxy::LastChanceOption>(
-          last_chance);
-
   // TODO(jkarlin): Make this blink::WebString::FromUTF8Lenient once
   // https://crrev.com/1768063002/ lands.
   proxy_->DispatchSyncEvent(request_id, blink::WebString::FromUTF8(tag),
-                            web_last_chance);
+                            last_chance);
 }
 
 void ServiceWorkerContextClient::DispatchAbortPaymentEvent(
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 2bacf9f8..3c66408 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -333,10 +333,9 @@
       DispatchNotificationCloseEventCallback callback) override;
   void DispatchPushEvent(const PushEventPayload& payload,
                          DispatchPushEventCallback callback) override;
-  void DispatchSyncEvent(
-      const std::string& tag,
-      blink::mojom::BackgroundSyncEventLastChance last_chance,
-      DispatchSyncEventCallback callback) override;
+  void DispatchSyncEvent(const std::string& tag,
+                         bool last_chance,
+                         DispatchSyncEventCallback callback) override;
   void DispatchAbortPaymentEvent(
       int payment_request_id,
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc
index 8b2c9e7..bba4a7f 100644
--- a/content/renderer/service_worker/service_worker_context_client_unittest.cc
+++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -150,7 +150,7 @@
   }
   void DispatchSyncEvent(int sync_event_id,
                          const blink::WebString& tag,
-                         LastChanceOption) override {
+                         bool last_chance) override {
     NOTREACHED();
   }
   void DispatchAbortPaymentEvent(int event_id) override { NOTREACHED(); }
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index c2e2bbd..fa6b67bd 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -197,9 +197,11 @@
     if (!command_line.HasSwitch(switches::kForceDeviceScaleFactor))
       command_line.AppendSwitchASCII(switches::kForceDeviceScaleFactor, "1.0");
 
-    command_line.AppendSwitchASCII(
-        switches::kAutoplayPolicy,
-        switches::autoplay::kNoUserGestureRequiredPolicy);
+    if (!command_line.HasSwitch(switches::kAutoplayPolicy)) {
+      command_line.AppendSwitchASCII(
+          switches::kAutoplayPolicy,
+          switches::autoplay::kNoUserGestureRequiredPolicy);
+    }
 
     if (!command_line.HasSwitch(switches::kStableReleaseMode)) {
       command_line.AppendSwitch(
diff --git a/content/test/test_background_sync_manager.cc b/content/test/test_background_sync_manager.cc
index 3cc040f..bc2a57b 100644
--- a/content/test/test_background_sync_manager.cc
+++ b/content/test/test_background_sync_manager.cc
@@ -78,7 +78,7 @@
 void TestBackgroundSyncManager::DispatchSyncEvent(
     const std::string& tag,
     scoped_refptr<ServiceWorkerVersion> active_version,
-    blink::mojom::BackgroundSyncEventLastChance last_chance,
+    bool last_chance,
     const ServiceWorkerVersion::LegacyStatusCallback& callback) {
   ASSERT_TRUE(dispatch_sync_callback_);
   last_chance_ = last_chance;
diff --git a/content/test/test_background_sync_manager.h b/content/test/test_background_sync_manager.h
index 7762cf8..6abf376 100644
--- a/content/test/test_background_sync_manager.h
+++ b/content/test/test_background_sync_manager.h
@@ -80,9 +80,7 @@
 
   // Accessors to internal state
   base::TimeDelta delayed_task_delta() const { return delayed_task_delta_; }
-  blink::mojom::BackgroundSyncEventLastChance last_chance() const {
-    return last_chance_;
-  }
+  bool last_chance() const { return last_chance_; }
   const BackgroundSyncParameters* background_sync_parameters() const {
     return parameters_.get();
   }
@@ -107,7 +105,7 @@
   void DispatchSyncEvent(
       const std::string& tag,
       scoped_refptr<ServiceWorkerVersion> active_version,
-      blink::mojom::BackgroundSyncEventLastChance last_chance,
+      bool last_chance,
       const ServiceWorkerVersion::LegacyStatusCallback& callback) override;
 
   // Override to just store delayed task, and allow tests to control the clock
@@ -139,8 +137,7 @@
   bool corrupt_backend_ = false;
   bool delay_backend_ = false;
   bool has_main_frame_provider_host_ = true;
-  blink::mojom::BackgroundSyncEventLastChance last_chance_ =
-      blink::mojom::BackgroundSyncEventLastChance::IS_NOT_LAST_CHANCE;
+  bool last_chance_ = false;
   base::OnceClosure continuation_;
   DispatchSyncCallback dispatch_sync_callback_;
   base::OnceClosure delayed_task_;
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 8d24f5c..70af6dcf 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -300,9 +300,32 @@
     "//third_party/skia/src/sfnt/SkOTUtils.cpp",
   ]
   if (!is_ios) {
+    sources -= [ "//third_party/skia/src/ports/SkImageGenerator_none.cpp" ]
     sources += [
+      "//third_party/skia/src/codec/SkBmpBaseCodec.cpp",
+      "//third_party/skia/src/codec/SkBmpCodec.cpp",
+      "//third_party/skia/src/codec/SkBmpMaskCodec.cpp",
+      "//third_party/skia/src/codec/SkBmpRLECodec.cpp",
+      "//third_party/skia/src/codec/SkBmpStandardCodec.cpp",
+      "//third_party/skia/src/codec/SkCodec.cpp",
+      "//third_party/skia/src/codec/SkCodecImageGenerator.cpp",
+      "//third_party/skia/src/codec/SkGifCodec.cpp",
+      "//third_party/skia/src/codec/SkIcoCodec.cpp",
+      "//third_party/skia/src/codec/SkJpegCodec.cpp",
+      "//third_party/skia/src/codec/SkJpegDecoderMgr.cpp",
+      "//third_party/skia/src/codec/SkJpegUtility.cpp",
+      "//third_party/skia/src/codec/SkMaskSwizzler.cpp",
+      "//third_party/skia/src/codec/SkMasks.cpp",
+      "//third_party/skia/src/codec/SkPngCodec.cpp",
+      "//third_party/skia/src/codec/SkSampler.cpp",
+      "//third_party/skia/src/codec/SkStreamBuffer.cpp",
+      "//third_party/skia/src/codec/SkSwizzler.cpp",
+      "//third_party/skia/src/codec/SkWbmpCodec.cpp",
+      "//third_party/skia/src/codec/SkWebpCodec.cpp",
       "//third_party/skia/src/images/SkJPEGWriteUtility.cpp",
       "//third_party/skia/src/images/SkJpegEncoder.cpp",
+      "//third_party/skia/src/ports/SkImageGenerator_skia.cpp",
+      "//third_party/skia/third_party/gif/SkGifImageReader.cpp",
     ]
   }
 
diff --git a/skia/ext/skia_utils_base.cc b/skia/ext/skia_utils_base.cc
index 078480b0..695226e 100644
--- a/skia/ext/skia_utils_base.cc
+++ b/skia/ext/skia_utils_base.cc
@@ -8,44 +8,11 @@
 
 #include "base/pickle.h"
 #include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkImageDeserializer.h"
-#include "third_party/skia/include/core/SkPixelSerializer.h"
-#include "third_party/skia/include/core/SkWriteBuffer.h"
-#include "third_party/skia/src/core/SkValidatingReadBuffer.h"
+#include "third_party/skia/include/core/SkEncodedImageFormat.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkSerialProcs.h"
 
 namespace skia {
-namespace {
-
-class CodecDecodingPixelSerializer : public SkPixelSerializer {
- public:
-  CodecDecodingPixelSerializer() = default;
-  ~CodecDecodingPixelSerializer() override = default;
-
- protected:
-  // Disallowing serializing the encoded data.
-  bool onUseEncodedData(const void* data, size_t len) override { return false; }
-
-  // Don't return any encoded data to ensure the decoded bitmap is serialized.
-  SkData* onEncode(const SkPixmap&) override { return nullptr; }
-};
-
-class CodecDisallowingImageDeserializer : public SkImageDeserializer {
- public:
-  ~CodecDisallowingImageDeserializer() override = default;
-
-  sk_sp<SkImage> makeFromData(SkData*, const SkIRect* subset) override {
-    LOG(ERROR) << "Encoded image rejected during SkFlattenable deserialization";
-    return nullptr;
-  }
-  sk_sp<SkImage> makeFromMemory(const void* data,
-                                size_t length,
-                                const SkIRect* subset) override {
-    LOG(ERROR) << "Encoded image rejected during SkFlattenable deserialization";
-    return nullptr;
-  }
-};
-
-}  // namespace
 
 bool ReadSkString(base::PickleIterator* iter, SkString* str) {
   int reply_length;
@@ -115,22 +82,24 @@
 }
 
 sk_sp<SkData> ValidatingSerializeFlattenable(SkFlattenable* flattenable) {
-  SkBinaryWriteBuffer writer;
-  writer.setPixelSerializer(sk_make_sp<CodecDecodingPixelSerializer>());
-  writer.writeFlattenable(flattenable);
-  size_t size = writer.bytesWritten();
-  auto data = SkData::MakeUninitialized(size);
-  writer.writeToMemory(data->writable_data());
-  return data;
+  SkSerialProcs procs;
+  procs.fImageProc = [](SkImage* image, void*) {
+    // We choose to not trust natively encoded images, but we are fine to force
+    // a "clean" encoded version for transport.
+    return image->encodeToData(SkEncodedImageFormat::kPNG, 100);
+  };
+  return flattenable->serialize(&procs);
 }
 
 SkFlattenable* ValidatingDeserializeFlattenable(const void* data,
                                                 size_t size,
                                                 SkFlattenable::Type type) {
-  SkValidatingReadBuffer buffer(data, size);
-  CodecDisallowingImageDeserializer image_deserializer;
-  buffer.setImageDeserializer(&image_deserializer);
-  return buffer.readFlattenable(type);
+  SkDeserialProcs procs;
+  procs.fImageProc = [](const void* data, size_t length, void*) {
+    // Our custom encode is standard, so we can just call Skia to deserialize
+    return SkImage::MakeFromEncoded(SkData::MakeWithCopy(data, length));
+  };
+  return SkFlattenable::Deserialize(type, data, size, &procs).release();
 }
 
 }  // namespace skia
diff --git a/skia/ext/skia_utils_base_unittest.cc b/skia/ext/skia_utils_base_unittest.cc
index ab6f3af2..b7dac6d 100644
--- a/skia/ext/skia_utils_base_unittest.cc
+++ b/skia/ext/skia_utils_base_unittest.cc
@@ -7,121 +7,55 @@
 #include "base/memory/ptr_util.h"
 #include "base/test/gtest_util.h"
 #include "base/test/test_discardable_memory_allocator.h"
+#include "build/build_config.h"
+#include "skia/ext/skia_utils_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkFlattenableSerialization.h"
-#include "third_party/skia/include/core/SkImageGenerator.h"
-#include "third_party/skia/include/core/SkPixelSerializer.h"
-#include "third_party/skia/include/core/SkWriteBuffer.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkSerialProcs.h"
 #include "third_party/skia/include/effects/SkImageSource.h"
-#include "third_party/skia/include/effects/SkPaintImageFilter.h"
+#include "ui/gfx/codec/png_codec.h"
 
 namespace skia {
 namespace {
 
-// Raw data for a PNG file with 1x1 white pixels.
-const unsigned char kWhitePNG[] = {
-    0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
-    0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
-    0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xde, 0x00, 0x00, 0x00,
-    0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
-    0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00,
-    0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x49,
-    0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff, 0xff, 0x3f, 0x00, 0x05,
-    0xfe, 0x02, 0xfe, 0xdc, 0xcc, 0x59, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x49,
-    0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
-};
-
-class FakeImageGenerator : public SkImageGenerator {
- public:
-  FakeImageGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(10, 10)) {}
-  ~FakeImageGenerator() override { EXPECT_TRUE(decoded_); }
-
-  SkData* onRefEncodedData() override {
-    // Use a generator that lets the caller encode it.
-    return SkData::MakeWithCString("evilimage").release();
-  }
-
-  bool onGetPixels(const SkImageInfo& info,
-                   void* pixels,
-                   size_t,
-                   const Options&) override {
-    decoded_ = true;
-    memset(pixels, 0, info.computeMinByteSize());
-    return true;
-  }
-
- private:
-  bool decoded_ = false;
-};
-
-class PixelSerializer : public SkPixelSerializer {
- public:
-  bool onUseEncodedData(const void* data, size_t len) override {
-    CHECK(false);
-    return false;
-  }
-
-  SkData* onEncode(const SkPixmap&) override {
-    EXPECT_TRUE(has_decoded_images_);
-    return nullptr;
-  }
-
-  bool has_decoded_images_ = false;
-};
-
-TEST(SkiaUtilsBaseTest, ImageSerializationDecodesImage) {
+TEST(SkiaUtilsBaseTest, DeserializationWithEncodedImages) {
+// codecs are not available on iOS, so skip this test crbug.com/794298
+#if !defined(OS_IOS)
   base::TestDiscardableMemoryAllocator allocator;
   base::DiscardableMemoryAllocator::SetInstance(&allocator);
 
-  auto image =
-      SkImage::MakeFromGenerator(base::MakeUnique<FakeImageGenerator>());
-  auto filter = SkImageSource::Make(image);
+  SkPMColor pixel = 0xFFFFFFFF;  // white;
+  SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
+  SkPixmap pm = {info, &pixel, sizeof(SkPMColor)};
+  auto image = SkImage::MakeRasterCopy(pm);
+  EXPECT_TRUE(image);
+  auto jpeg_data = image->encodeToData(SkEncodedImageFormat::kJPEG, 100);
+  EXPECT_TRUE(jpeg_data);
+  auto filter = SkImageSource::Make(SkImage::MakeFromEncoded(jpeg_data));
+  EXPECT_TRUE(filter);
 
-  // Serialize the filter. This decodes the image.
-  sk_sp<SkData> data = ValidatingSerializeFlattenable(filter.get());
+  sk_sp<SkData> data(ValidatingSerializeFlattenable(filter.get()));
 
-  // Deserialize.
-  auto deserialized_filter =
-      sk_sp<SkImageFilter>((SkImageFilter*)ValidatingDeserializeFlattenable(
-          data->data(), data->size(), SkImageFilter::GetFlattenableType()));
-
-  // Now serialize again to ensure that the deserialized filter did not have any
-  // encoded images. Serialization is the only way to deep inspect the filter.
-  SkBinaryWriteBuffer writer;
-  auto pixel_serializer = sk_make_sp<PixelSerializer>();
-  pixel_serializer->has_decoded_images_ = true;
-  writer.setPixelSerializer(pixel_serializer);
-  writer.writeFlattenable(deserialized_filter.get());
-  EXPECT_GT(writer.bytesWritten(), 0u);
+  // Now we install a proc to see that all embedded images have been converted
+  // to png.
+  bool was_called = false;
+  SkDeserialProcs procs;
+  procs.fImageProc = [](const void* data, size_t length,
+                        void* was_called) -> sk_sp<SkImage> {
+    *(bool*)was_called = true;
+    SkBitmap bitmap;
+    EXPECT_TRUE(gfx::PNGCodec::Decode(static_cast<const uint8_t*>(data), length,
+                                      &bitmap));
+    return nullptr;  // allow for normal deserialization
+  };
+  procs.fImageCtx = &was_called;
+  auto flat = SkFlattenable::Deserialize(SkImageFilter::GetFlattenableType(),
+                                         data->data(), data->size(), &procs);
+  EXPECT_TRUE(flat);
+  EXPECT_TRUE(was_called);
 
   base::DiscardableMemoryAllocator::SetInstance(nullptr);
-}
-
-TEST(SkiaUtilsBaseTest, DeserializationWithEncodedImagesFails) {
-  base::TestDiscardableMemoryAllocator allocator;
-  base::DiscardableMemoryAllocator::SetInstance(&allocator);
-
-  auto image = SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(
-      SkData::MakeWithoutCopy(kWhitePNG, sizeof(kWhitePNG))));
-  auto filter = SkImageSource::Make(image);
-
-  // Serialize the filter using default serialization.
-  sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
-
-  // Deserialize with images disabled.
-  auto deserialized_filter =
-      sk_sp<SkImageFilter>((SkImageFilter*)ValidatingDeserializeFlattenable(
-          data->data(), data->size(), SkImageFilter::GetFlattenableType()));
-
-  // Now serialize again to make sure that all encoded images were rejected
-  // during serialization.
-  SkBinaryWriteBuffer writer;
-  auto pixel_serializer = sk_make_sp<PixelSerializer>();
-  writer.setPixelSerializer(pixel_serializer);
-  writer.writeFlattenable(deserialized_filter.get());
-  EXPECT_GT(writer.bytesWritten(), 0u);
-
-  base::DiscardableMemoryAllocator::SetInstance(nullptr);
+#endif
 }
 
 }  // namespace
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 943a2e0..7a56a3c4 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2084,8 +2084,7 @@
                     },
                     "enable_features": [
                         "DoodlesOnLocalNtp",
-                        "UseGoogleLocalNtp",
-                        "VoiceSearchOnLocalNtp"
+                        "UseGoogleLocalNtp"
                     ]
                 }
             ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index ce47f84..fb010ad 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -4470,7 +4470,7 @@
 crbug.com/591099 fast/multicol/abspos-new-width-rebalance.html [ Failure ]
 crbug.com/591099 fast/multicol/anonymous-block-split-crash.html [ Crash ]
 crbug.com/591099 fast/multicol/balance-break-inside-avoid.html [ Failure ]
-crbug.com/591099 fast/multicol/balance-breakafter-before-nested-block.html [ Crash ]
+crbug.com/591099 fast/multicol/balance-breakafter-before-nested-block.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-fixed-height-unused-space-after-strutless-break.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-fixed-height-unused-space-nested-block.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-fixed-height-unused-space.html [ Failure ]
@@ -4487,7 +4487,7 @@
 crbug.com/591099 fast/multicol/balance-short-trailing-empty-block.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-table-with-border-spacing.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-trailing-border-after-break.html [ Failure ]
-crbug.com/591099 fast/multicol/balance-trailing-border.html [ Crash ]
+crbug.com/591099 fast/multicol/balance-trailing-border.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-unbreakable.html [ Failure ]
 crbug.com/591099 fast/multicol/basic-rtl.html [ Failure ]
 crbug.com/591099 fast/multicol/border-radius-clipped-layer-second-column.html [ Failure ]
@@ -4624,7 +4624,7 @@
 crbug.com/591099 fast/multicol/hit-test-end-of-column-with-line-height.html [ Failure ]
 crbug.com/591099 fast/multicol/hit-test-end-of-column.html [ Failure ]
 crbug.com/591099 fast/multicol/hit-test-gap-between-pages-flipped.html [ Failure ]
-crbug.com/591099 fast/multicol/image-inside-nested-blocks-with-border.html [ Crash ]
+crbug.com/591099 fast/multicol/image-inside-nested-blocks-with-border.html [ Failure ]
 crbug.com/591099 fast/multicol/infinite-height-causing-fractional-row-height-crash.html [ Crash ]
 # This one is really just very slow:
 crbug.com/591099 fast/multicol/infinitely-tall-content-in-outer-crash.html [ Pass Timeout ]
@@ -4688,7 +4688,6 @@
 crbug.com/591099 fast/multicol/newmulticol/fixed-height-fill-balance-2.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-lr.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-rl.html [ Failure ]
-crbug.com/591099 fast/multicol/newmulticol/leading-margin.html [ Crash ]
 crbug.com/591099 fast/multicol/newmulticol/list-item.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/orphans-and-widows-balance.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/spanner-inside-child-crash.html [ Crash ]
@@ -4824,7 +4823,7 @@
 crbug.com/591099 fast/multicol/vertical-lr/abspos-auto-position-on-line.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/balancing/balance-short-trailing-empty-block.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/balancing/balance-trailing-border-after-break.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-lr/balancing/balance-trailing-border.html [ Crash ]
+crbug.com/591099 fast/multicol/vertical-lr/balancing/balance-trailing-border.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/balancing/balance-unbreakable.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/break-properties.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/caret-range-anonymous-block-rtl.html [ Failure ]
@@ -4843,7 +4842,7 @@
 crbug.com/591099 fast/multicol/vertical-lr/float-content-break.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/float-edge.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/float-paginate.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-lr/image-inside-nested-blocks-with-border.html [ Crash ]
+crbug.com/591099 fast/multicol/vertical-lr/image-inside-nested-blocks-with-border.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/nested-columns.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/offset-top-and-left-at-boundaries-nested.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/offset-top-and-left-at-boundaries.html [ Crash ]
@@ -4852,7 +4851,7 @@
 crbug.com/591099 fast/multicol/vertical-rl/abspos-auto-position-on-line.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/balancing/balance-short-trailing-empty-block.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/balancing/balance-trailing-border-after-break.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-rl/balancing/balance-trailing-border.html [ Crash ]
+crbug.com/591099 fast/multicol/vertical-rl/balancing/balance-trailing-border.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/balancing/balance-unbreakable.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/break-properties.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/caret-range-anonymous-block-rtl.html [ Failure ]
@@ -4872,7 +4871,7 @@
 crbug.com/591099 fast/multicol/vertical-rl/float-edge.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/float-paginate.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/float-truncation.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-rl/image-inside-nested-blocks-with-border.html [ Crash ]
+crbug.com/591099 fast/multicol/vertical-rl/image-inside-nested-blocks-with-border.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/offset-top-and-left-at-boundaries-nested.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/offset-top-and-left-at-boundaries.html [ Crash ]
 crbug.com/591099 fast/multicol/vertical-rl/offset-top-and-left-nested.html [ Failure ]
@@ -7034,7 +7033,7 @@
 crbug.com/591099 fast/text/justify-ideograph-vertical.html [ Failure ]
 crbug.com/714962 fast/text/justify-padding-distribution.html [ Failure Pass ]
 crbug.com/591099 fast/text/large-text-composed-char.html [ Timeout ]
-crbug.com/591099 fast/text/letter-spacing-leading-and-trailing.html [ Crash ]
+crbug.com/591099 fast/text/letter-spacing-leading-and-trailing.html [ Failure ]
 crbug.com/714962 fast/text/line-break-after-inline-latin1.html [ Failure ]
 crbug.com/591099 fast/text/long-word.html [ Failure Pass ]
 crbug.com/714962 fast/text/multiglyph-characters.html [ Failure ]
@@ -7207,7 +7206,7 @@
 crbug.com/591099 fragmentation/block-after-float-first-child.html [ Failure ]
 crbug.com/591099 fragmentation/block-with-float-and-1-orphaned-line.html [ Failure ]
 crbug.com/591099 fragmentation/border-spacing-break-before-unbreakable-row.html [ Failure ]
-crbug.com/591099 fragmentation/break-before-empty-child-block.html [ Crash ]
+crbug.com/591099 fragmentation/break-before-empty-child-block.html [ Failure ]
 crbug.com/591099 fragmentation/break-in-first-table-row-only.html [ Failure ]
 crbug.com/591099 fragmentation/break-in-second-table-section.html [ Failure ]
 crbug.com/591099 fragmentation/break-in-tbody-after-caption.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/MSANExpectations b/third_party/WebKit/LayoutTests/MSANExpectations
index 74bda5e..118e0b9 100644
--- a/third_party/WebKit/LayoutTests/MSANExpectations
+++ b/third_party/WebKit/LayoutTests/MSANExpectations
@@ -57,6 +57,8 @@
 # them as "Slow" doesn't seem to help the problem (see discussion on bug), so
 # marking them as "Timeout" while crbug.com/729136 is worked out.
 crbug.com/729136 [ Linux ] external/wpt/encoding/textdecoder-fatal-single-byte.html [ Timeout ]
+crbug.com/729136 [ Linux ] external/wpt/mimesniff/mime-types/parsing.any.html [ Timeout ]
+crbug.com/729136 [ Linux ] external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Timeout ]
 crbug.com/729136 [ Linux ] fast/css/css-selector-deeply-nested.html [ Timeout ]
 crbug.com/729136 [ Linux ] http/tests/devtools/forced-layout-in-microtask.js [ Timeout ]
 crbug.com/729136 [ Linux ] http/tests/devtools/tracing/timeline-xhr-response-type-blob-event.js [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index 394f559b..fcf8b9b2 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -1824,9 +1824,6 @@
 external/wpt/css/mediaqueries/device-aspect-ratio-001.html [ WontFix ]
 external/wpt/css/mediaqueries/device-aspect-ratio-005.html [ WontFix ]
 
-# https://github.com/w3c/web-platform-tests/pull/8631
-external/wpt/css/css-style-attr/style-attr-urls-003.xht [ WontFix ]
-
 # https://github.com/w3c/web-platform-tests/issues/8633
 external/wpt/css/css-style-attr/style-attr-braces-002-quirks.htm [ WontFix ]
 
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 8469eb19a..8f32db8c 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1378,8 +1378,6 @@
 crbug.com/492664 [ Mac ] external/wpt/css/css-writing-modes/text-baseline-vrl-006.xht [ Failure ]
 crbug.com/492664 [ Mac ] external/wpt/css/css-writing-modes/text-baseline-vlr-007.xht [ Failure ]
 
-crbug.com/793792 [ Linux ] external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Pass Timeout ]
-
 crbug.com/498845 [ Win ] fast/multicol/vertical-rl/float-content-break.html [ Failure ]
 crbug.com/443615 [ Linux Win ] external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-027.html [ Failure ]
 
@@ -3695,3 +3693,8 @@
 
 # Sheriff faulures 2017-12-12
 crbug.com/794180 http/tests/devtools/layers/layer-compositing-reasons.js [ Failure Pass ]
+
+# These tests require Unified Autoplay.
+crbug.com/779087 external/wpt/feature-policy/autoplay-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html [ Skip ]
+crbug.com/779087 external/wpt/feature-policy/autoplay-default-feature-policy.https.sub.html [ Skip ]
+crbug.com/779087 external/wpt/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 77fcab0..bd26ef1f 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -613,5 +613,10 @@
     "prefix": "modern-media-controls",
     "base": "media/controls/modern",
     "args": ["--enable-features=UseModernMediaControls"]
+  },
+  {
+    "prefix": "unified-autoplay",
+    "base": "external/wpt/feature-policy",
+    "args": ["--autoplay-policy=document-user-activation-required"]
   }
 ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html
new file mode 100644
index 0000000..6f11f899
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src=/resources/testdriver.js></script>
+  <script src=/resources/testdriver-vendor.js></script>
+  <script src=/common/media.js></script>
+  <script src=/feature-policy/resources/featurepolicy.js></script>
+  <script src=/feature-policy/resources/autoplay.js></script>
+  <script>
+  'use strict';
+  const relative_path = '/feature-policy/resources/feature-policy-autoplay.html';
+  const base_src = '/feature-policy/resources/redirect-on-load.html#';
+  const same_origin_src = base_src + relative_path;
+  const cross_origin_src = base_src + 'https://{{domains[www]}}:{{ports[https][0]}}' +
+    relative_path;
+  const header = 'Feature-Policy allow="autoplay"';
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability(
+          'autoplay', t, same_origin_src,
+          expect_feature_available_default, 'autoplay');
+    });
+  }, header + ' allows same-origin navigation in an iframe.');
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability(
+          'autoplay', t, cross_origin_src,
+          expect_feature_unavailable_default, 'autoplay');
+    });
+  }, header + ' disallows cross-origin navigation in an iframe.');
+  </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html
new file mode 100644
index 0000000..59b33d7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src=/resources/testdriver.js></script>
+  <script src=/resources/testdriver-vendor.js></script>
+  <script src=/common/media.js></script>
+  <script src=/feature-policy/resources/featurepolicy.js></script>
+  <script src=/feature-policy/resources/autoplay.js></script>
+  <script>
+  'use strict';
+  const same_origin_src = '/feature-policy/resources/feature-policy-autoplay.html';
+  const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+    same_origin_src;
+  const feature_name = 'Feature policy "autoplay"';
+  const header = 'allow="autoplay" attribute';
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability(
+          'autoplay', t, same_origin_src,
+          expect_feature_available_default, 'autoplay');
+    });
+  }, feature_name + ' can be enabled in same-origin iframe using ' + header);
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability(
+          'autoplay', t, cross_origin_src,
+          expect_feature_available_default, 'autoplay');
+    });
+  }, feature_name + ' can be enabled in cross-origin iframe using ' + header);
+  </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html
new file mode 100644
index 0000000..63479c0c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src=/resources/testdriver.js></script>
+  <script src=/resources/testdriver-vendor.js></script>
+  <script src=/common/media.js></script>
+  <script src=/feature-policy/resources/featurepolicy.js></script>
+  <script src=/feature-policy/resources/autoplay.js></script>
+  <script>
+  'use strict';
+  const same_origin_src = '/feature-policy/resources/feature-policy-autoplay.html';
+  const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+    same_origin_src;
+  const header = 'Feature-Policy header: autoplay *';
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      isAutoplayAllowed().then(t.step_func_done((result) => {
+        assert_true(result);
+      }));
+    });
+  }, header + ' allows the top-level document.');
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability('autoplay', t, same_origin_src,
+          expect_feature_available_default);
+    });
+  }, header + ' allows same-origin iframes.');
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability('autoplay', t, cross_origin_src,
+          expect_feature_available_default);
+    });
+  }, header + ' allows cross-origin iframes.');
+  </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html.headers b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html.headers
new file mode 100644
index 0000000..08461fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Feature-Policy: autoplay *
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-default-feature-policy.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-default-feature-policy.https.sub.html
new file mode 100644
index 0000000..763073e4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-default-feature-policy.https.sub.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src=/resources/testdriver.js></script>
+  <script src=/resources/testdriver-vendor.js></script>
+  <script src=/common/media.js></script>
+  <script src=/feature-policy/resources/featurepolicy.js></script>
+  <script src=/feature-policy/resources/autoplay.js></script>
+  <script>
+  'use strict';
+  const same_origin_src = '/feature-policy/resources/feature-policy-autoplay.html';
+  const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+    same_origin_src;
+  const header = 'Default "autoplay" feature policy ["self"]';
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      isAutoplayAllowed().then(t.step_func_done((result) => {
+        assert_true(result);
+      }));
+    });
+  }, header + ' allows the top-level document.');
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability('autoplay', t, same_origin_src,
+          expect_feature_available_default);
+    });
+  }, header + ' allows same-origin iframes.');
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability('autoplay', t, cross_origin_src,
+          expect_feature_unavailable_default,);
+    });
+  }, header + ' disallows cross-origin iframes.');
+  </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html
new file mode 100644
index 0000000..7761246e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src=/resources/testdriver.js></script>
+  <script src=/resources/testdriver-vendor.js></script>
+  <script src=/common/media.js></script>
+  <script src=/feature-policy/resources/featurepolicy.js></script>
+  <script src=/feature-policy/resources/autoplay.js></script>
+  <script>
+  'use strict';
+  const same_origin_src = '/feature-policy/resources/feature-policy-autoplay.html';
+  const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+    same_origin_src;
+  const header = 'Feature-Policy header: autoplay "none"';
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      isAutoplayAllowed().then(t.step_func_done((result) => {
+        assert_false(result);
+      }));
+    });
+  }, header + ' disallows the top-level document.');
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability('autoplay', t, same_origin_src,
+          expect_feature_unavailable_default);
+    });
+  }, header + ' disallows same-origin iframes.');
+
+  async_test(t => {
+    simulateGesture(t, () => {
+      test_feature_availability('autoplay', t, cross_origin_src,
+          expect_feature_unavailable_default,);
+    });
+  }, header + ' disallows cross-origin iframes.');
+  </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html.headers b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html.headers
new file mode 100644
index 0000000..69ce436
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/autoplay-disabled-by-feature-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Feature-Policy: autoplay 'none'
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html
index 9a792173..daa2aa1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html
@@ -16,24 +16,24 @@
     test_feature_availability(
         'PaymentRequest()', t, same_origin_src,
         expect_feature_available_default, 'payment');
-  }, header + ' allows same-origin relocation.');
+  }, header + ' allows same-origin navigation in an iframe.');
 
   async_test(t => {
     test_feature_availability(
         'PaymentRequest()', t, cross_origin_src,
         expect_feature_unavailable_default, 'payment');
-  }, header + ' disallows cross-origin relocation.');
+  }, header + ' disallows cross-origin navigation in an iframe.');
 
   async_test(t => {
     test_feature_availability(
         'PaymentRequest()', t, same_origin_src,
         expect_feature_available_default, 'payment', 'allowpaymentrequest');
-  }, header + ' allowpaymentrequest=true allows same-origin relocation.');
+  }, header + ' allowpaymentrequest=true allows same-origin navigation in an iframe.');
 
   async_test(t => {
     test_feature_availability(
         'PaymentRequest()', t, cross_origin_src,
         expect_feature_unavailable_default, 'payment', 'allowpaymentrequest');
-  }, header + ' allowpaymentrequest=true disallows cross-origin relocation.');
+  }, header + ' allowpaymentrequest=true disallows cross-origin navigation in an iframe.');
   </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/autoplay.js b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/autoplay.js
new file mode 100644
index 0000000..56780cf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/autoplay.js
@@ -0,0 +1,28 @@
+
+
+function simulateGesture(t, callback) {
+  // Get or create the target element.
+  let target = document.getElementById('target');
+  if (!target) {
+    target = document.createElement('button');
+    target.setAttribute('id', 'target');
+    document.body.appendChild(target);
+  }
+
+  // Simulate a gesture in the top frame to remove any gesture based autoplay
+  // restrictions.
+  test_driver.click(target).then(callback, t.unreached_func('click failed'));
+}
+
+function isAutoplayAllowed() {
+  return new Promise((resolve, reject) => {
+    const video = document.createElement('video');
+    video.src = getVideoURI('/media/A4');
+    video.play().then(() => resolve(true), (e) => {
+      if (e.name == 'NotAllowedError')
+        resolve(false);
+      else
+        resolve(true);
+    });
+  });
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/feature-policy-autoplay.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/feature-policy-autoplay.html
new file mode 100644
index 0000000..79f8eef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/feature-policy-autoplay.html
@@ -0,0 +1,11 @@
+<script src="/common/media.js"></script>
+<script src=/feature-policy/resources/autoplay.js></script>
+<script>
+'use strict';
+
+window.addEventListener('load', () => {
+  isAutoplayAllowed().then((result) => {
+    window.parent.postMessage({ enabled: result }, '*');
+  });
+}, { once: true });
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/unified-autoplay/external/wpt/feature-policy/README.txt b/third_party/WebKit/LayoutTests/virtual/unified-autoplay/external/wpt/feature-policy/README.txt
new file mode 100644
index 0000000..f94966b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/unified-autoplay/external/wpt/feature-policy/README.txt
@@ -0,0 +1 @@
+This suite runs feature policy tests with Unified Autoplay enabled.
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
index 00f4d83..0eb2f43 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
@@ -1656,7 +1656,10 @@
       }
       break;
     }
-
+    case CSSPropertyDisplay:
+      if (value_id == CSSValueContents)
+        context.Count(WebFeature::kCSSValueDisplayContents);
+      break;
     default:
       break;
   }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
index 544eb35..c9f3198 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -967,6 +967,42 @@
   EXPECT_EQ(expectation, dump);
 }
 
+TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideWithBorder) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #parent {
+        columns: 3;
+        column-fill: auto;
+        column-gap: 10px;
+        width: 320px;
+        height: 100px;
+      }
+    </style>
+    <div id="container">
+      <div id="parent">
+        <div style="height:85px;"></div>
+        <div style="border:10px solid;">
+          <div style="height:10px;"></div>
+        </div>
+      </div>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x100
+        offset:0,0 size:100x85
+        offset:0,85 size:100x15
+          offset:10,10 size:80x5
+      offset:110,0 size:100x15
+        offset:0,0 size:100x15
+          offset:10,0 size:80x5
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
 TEST_F(NGColumnLayoutAlgorithmTest, MinMax) {
   // The multicol container here contains two inline-blocks with a line break
   // opportunity between them. We'll test what min/max values we get for the
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
index 068d501..0e1825a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
@@ -179,10 +179,15 @@
     case kMinContent:
     case kMaxContent:
     case kFitContent:
+#if DCHECK_IS_ON()
       // Due to how content_size is calculated, it should always include border
-      // and padding.
-      if (content_size != LayoutUnit(-1))
+      // and padding. We cannot check for this if we are block-fragmented,
+      // though, because then the block-start border/padding may be in a
+      // different fragmentainer than the block-end border/padding.
+      if (content_size != LayoutUnit(-1) &&
+          !constraint_space.HasBlockFragmentation())
         DCHECK_GE(content_size, border_and_padding.BlockSum());
+#endif  // DCHECK_IS_ON()
       return content_size;
     case kDeviceWidth:
     case kDeviceHeight:
diff --git a/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css b/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css
index bada381..74dfb33a 100644
--- a/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css
@@ -258,14 +258,22 @@
   -webkit-appearance: -internal-media-control;
 
   height: 2px;
-  padding-top: 5px;
   padding-left: 16px;
   padding-right: 16px;
-  padding-bottom: 17px;
   margin: 0;
   background: transparent;
 }
 
+audio::-webkit-media-controls-timeline {
+  padding-top: 26px;
+  padding-bottom: 26px;
+}
+
+video::-webkit-media-controls-timeline {
+  padding-top: 5px;
+  padding-bottom: 17px;
+}
+
 input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segmented-track {
   -webkit-appearance: -internal-media-control;
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
index 838290c..88c8fd8 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
@@ -423,15 +423,14 @@
   WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
 }
 
-void ServiceWorkerGlobalScopeProxy::DispatchSyncEvent(
-    int event_id,
-    const WebString& id,
-    LastChanceOption last_chance) {
+void ServiceWorkerGlobalScopeProxy::DispatchSyncEvent(int event_id,
+                                                      const WebString& id,
+                                                      bool last_chance) {
   DCHECK(WorkerGlobalScope()->IsContextThread());
   WaitUntilObserver* observer = WaitUntilObserver::Create(
       WorkerGlobalScope(), WaitUntilObserver::kSync, event_id);
-  Event* event = SyncEvent::Create(EventTypeNames::sync, id,
-                                   last_chance == kIsLastChance, observer);
+  Event* event =
+      SyncEvent::Create(EventTypeNames::sync, id, last_chance, observer);
   WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
 }
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.h
index cb7f232a..7cf620f2 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.h
@@ -119,7 +119,7 @@
                                       const WebString& notification_id,
                                       const WebNotificationData&) override;
   void DispatchPushEvent(int, const WebString& data) override;
-  void DispatchSyncEvent(int, const WebString& tag, LastChanceOption) override;
+  void DispatchSyncEvent(int, const WebString& tag, bool last_chance) override;
   void DispatchAbortPaymentEvent(int) override;
   void DispatchCanMakePaymentEvent(int,
                                    const WebCanMakePaymentEventData&) override;
diff --git a/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
index aaf4fb3..edef035 100644
--- a/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
@@ -205,6 +205,7 @@
 }
 
 void WebRuntimeFeatures::EnableNotificationsWithMojo(bool enable) {
+  RuntimeEnabledFeatures::SetNotificationsWithMojoEnabled(enable);
 }
 
 void WebRuntimeFeatures::EnableNavigatorContentUtils(bool enable) {
diff --git a/third_party/WebKit/Source/platform/heap/BUILD.gn b/third_party/WebKit/Source/platform/heap/BUILD.gn
index 6d59d08..d8c2f1df 100644
--- a/third_party/WebKit/Source/platform/heap/BUILD.gn
+++ b/third_party/WebKit/Source/platform/heap/BUILD.gn
@@ -72,6 +72,10 @@
     "//third_party/icu",
     "//v8",
   ]
+
+  public_deps = [
+    "//third_party/WebKit/public:blink_headers",
+  ]
 }
 
 test("blink_heap_unittests") {
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index 176967eb..a2bd98cb 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1782,6 +1782,7 @@
   kAudioWorkletGlobalScopeRegisterProcessor = 2262,
   kAudioWorkletNodeConstructor = 2263,
   kHTMLMediaElementEmptyLoadWithFutureData = 2264,
+  kCSSValueDisplayContents = 2265,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h
index 26d26b825..b32e9ca 100644
--- a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h
+++ b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h
@@ -107,13 +107,11 @@
 
   virtual bool HasFetchEventHandler() = 0;
 
-  enum LastChanceOption { kIsNotLastChance, kIsLastChance };
-
   // Once the ServiceWorker has finished handling the sync event,
   // didHandleSyncEvent is called on the context client.
   virtual void DispatchSyncEvent(int sync_event_id,
                                  const WebString& tag,
-                                 LastChanceOption) = 0;
+                                 bool last_chance) = 0;
 
   virtual void DispatchAbortPaymentEvent(int event_id) = 0;
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 025c47a..20cf2f8 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -17238,6 +17238,7 @@
   <int value="2262" label="AudioWorkletGlobalScopeRegisterProcessor"/>
   <int value="2263" label="AudioWorkletNodeConstructor"/>
   <int value="2264" label="HTMLMediaElementEmptyLoadWithFutureData"/>
+  <int value="2265" label="CSSValueDisplayContents"/>
 </enum>
 
 <enum name="FeedbackSource">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 6feba9e4..04716509 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -92636,6 +92636,30 @@
   </summary>
 </histogram>
 
+<histogram name="V8.GCBackgroundMarking" units="ms">
+  <owner>ulan@chromium.org</owner>
+  <summary>
+    Time spent in background tasks doing marking in one GC cycle. It is recorded
+    after each GC.
+  </summary>
+</histogram>
+
+<histogram name="V8.GCBackgroundScavenger" units="ms">
+  <owner>ulan@chromium.org</owner>
+  <summary>
+    Time spent in background tasks doing scavenging in one GC cycle. It is
+    recorded after each GC.
+  </summary>
+</histogram>
+
+<histogram name="V8.GCBackgroundSweeping" units="ms">
+  <owner>ulan@chromium.org</owner>
+  <summary>
+    Time spent in background tasks doing sweeping in one GC cycle. It is
+    recorded after each GC.
+  </summary>
+</histogram>
+
 <histogram name="V8.GCCompactor" units="ms">
   <owner>hpayer@chromium.org</owner>
   <summary>Time spent in mark-sweep phase of GC.</summary>
diff --git a/tools/traffic_annotation/scripts/check_annotations.py b/tools/traffic_annotation/scripts/check_annotations.py
index 4f0d8a7..9b2d042 100755
--- a/tools/traffic_annotation/scripts/check_annotations.py
+++ b/tools/traffic_annotation/scripts/check_annotations.py
@@ -137,6 +137,34 @@
     return command.returncode
 
 
+  def GetModifiedFiles(self):
+    """Gets the list of modified files from git. Returns None if any error
+    happens."""
+
+    # List of files is extracted the same way as the following test recipe:
+    # https://cs.chromium.org/chromium/tools/depot_tools/recipes/recipe_modules/
+    # tryserver/api.py?l=66
+    args = ["git.bat"] if sys.platform == "win32" else ["git"]
+    args += ["diff", "--cached", "--name-only"]
+
+    original_path = os.getcwd()
+
+    # Change directory to src (two levels upper than build path).
+    os.chdir(os.path.join(self.build_path, "..", ".."))
+    command = subprocess.Popen(args, stdout=subprocess.PIPE,
+                               stderr=subprocess.PIPE)
+    stdout_text, stderr_text = command.communicate()
+
+    if stderr_text:
+      print("Could not run '%s' to get the list of changed files "
+            "beacuse: %s" % (" ".join(args), stderr_text))
+      os.chdir(original_path)
+      return None
+
+    os.chdir(original_path)
+    return stdout_text.splitlines()
+
+
 def main():
   parser = argparse.ArgumentParser(
       description="Traffic Annotation Auditor Presubmit checker.")
@@ -149,11 +177,24 @@
       '--limit', default=5,
       help='Limit for the maximum number of returned errors and warnings. '
            'Default value is 5, use 0 for unlimited.')
+  parser.add_argument(
+      '--complete', action='store_true',
+      help='Run the test on the complete repository. Otherwise only the '
+           'modified files are tested.')
 
   args = parser.parse_args()
 
   checker = NetworkTrafficAnnotationChecker(args.build_path)
-  return checker.CheckFiles(limit=args.limit)
+  if args.complete:
+    file_paths = None
+  else:
+    file_paths = checker.GetModifiedFiles()
+    if file_paths is None:
+      return -1
+    if len(file_paths) == 0:
+      return 0
+
+  return checker.CheckFiles(file_paths=file_paths, limit=args.limit)
 
 
 if '__main__' == __name__:
diff --git a/ui/aura/local/layer_tree_frame_sink_local.h b/ui/aura/local/layer_tree_frame_sink_local.h
index 25dc6cf..98ba1ae 100644
--- a/ui/aura/local/layer_tree_frame_sink_local.h
+++ b/ui/aura/local/layer_tree_frame_sink_local.h
@@ -44,10 +44,6 @@
 
   base::WeakPtr<LayerTreeFrameSinkLocal> GetWeakPtr();
 
-  const viz::LocalSurfaceId& local_surface_id() const {
-    return local_surface_id_;
-  }
-
   // cc::LayerTreeFrameSink:
   bool BindToClient(cc::LayerTreeFrameSinkClient* client) override;
   void DetachFromClient() override;
diff --git a/ui/aura/mus/DEPS b/ui/aura/mus/DEPS
index 8e72cf0..f572556f 100644
--- a/ui/aura/mus/DEPS
+++ b/ui/aura/mus/DEPS
@@ -7,7 +7,6 @@
   "+components/discardable_memory/client/client_discardable_shared_memory_manager.h",
   "+components/viz/client",
   "+components/viz/common",
-  "+components/viz/service/frame_sinks/frame_sink_manager_impl.h",
   "+gpu/command_buffer/client/gpu_memory_buffer_manager.h",
   "+gpu/ipc/client/gpu_channel_host.h",
   "+mojo/public/cpp/system/buffer.h",
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc
index aedc2838..1e499673 100644
--- a/ui/aura/mus/window_port_mus.cc
+++ b/ui/aura/mus/window_port_mus.cc
@@ -6,7 +6,6 @@
 
 #include "base/memory/ptr_util.h"
 #include "components/viz/client/local_surface_id_provider.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/transient_window_client.h"
 #include "ui/aura/env.h"
@@ -37,9 +36,7 @@
 
 WindowPortMus::WindowPortMus(WindowTreeClient* client,
                              WindowMusType window_mus_type)
-    : WindowMus(window_mus_type),
-      window_tree_client_(client),
-      weak_ptr_factory_(this) {}
+    : WindowMus(window_mus_type), window_tree_client_(client) {}
 
 WindowPortMus::~WindowPortMus() {
   client_surface_embedder_.reset();
@@ -553,64 +550,25 @@
 WindowPortMus::CreateLayerTreeFrameSink() {
   DCHECK_EQ(window_mus_type(), WindowMusType::LOCAL);
   DCHECK(!local_layer_tree_frame_sink_);
-
-  std::unique_ptr<cc::LayerTreeFrameSink> frame_sink;
-  if (switches::IsMusHostingViz()) {
-    auto client_layer_tree_frame_sink =
-        RequestLayerTreeFrameSink(nullptr, aura::Env::GetInstance()
-                                               ->context_factory()
-                                               ->GetGpuMemoryBufferManager());
-    local_layer_tree_frame_sink_ = client_layer_tree_frame_sink->GetWeakPtr();
-    frame_sink = std::move(client_layer_tree_frame_sink);
-  } else {
-    auto* context_factory_private =
-        aura::Env::GetInstance()->context_factory_private();
-    auto frame_sink_id = GetFrameSinkId();
-    DCHECK(frame_sink_id.is_valid());
-    auto layer_tree_frame_sink_local =
-        std::make_unique<LayerTreeFrameSinkLocal>(
-            frame_sink_id, context_factory_private->GetHostFrameSinkManager(),
-            window_->GetName());
-    layer_tree_frame_sink_local->SetSurfaceChangedCallback(base::BindRepeating(
-        &WindowPortMus::OnSurfaceChanged, weak_ptr_factory_.GetWeakPtr()));
-    if (window_->layer()->GetCompositor()) {
-      window_->layer()->GetCompositor()->AddFrameSink(GetFrameSinkId());
-      is_frame_sink_id_added_to_compositor_ = true;
-    }
-    local_layer_tree_frame_sink_ = layer_tree_frame_sink_local->GetWeakPtr();
-    frame_sink = std::move(layer_tree_frame_sink_local);
-  }
-
-  gfx::Size size_in_pixel =
+  auto frame_sink = RequestLayerTreeFrameSink(
+      nullptr,
+      aura::Env::GetInstance()->context_factory()->GetGpuMemoryBufferManager());
+  local_layer_tree_frame_sink_ = frame_sink->GetWeakPtr();
+  auto size_in_pixel =
       gfx::ConvertSizeToPixel(GetDeviceScaleFactor(), window_->bounds().size());
   // Make sure |local_surface_id_| and |last_surface_size_in_pixels_| are
-  // correct for the new created |local_layer_tree_frame_sink_|.
+  // correct for the new created |frame_sink|.
   GetOrAllocateLocalSurfaceId(size_in_pixel);
-  return frame_sink;
+  return std::move(frame_sink);
 }
 
 viz::SurfaceId WindowPortMus::GetSurfaceId() const {
   return viz::SurfaceId(window_->embed_frame_sink_id(), local_surface_id_);
 }
 
-void WindowPortMus::OnWindowAddedToRootWindow() {
-  if (switches::IsMusHostingViz())
-    return;
-  if (local_layer_tree_frame_sink_) {
-    DCHECK(!is_frame_sink_id_added_to_compositor_);
-    window_->layer()->GetCompositor()->AddFrameSink(GetFrameSinkId());
-    is_frame_sink_id_added_to_compositor_ = true;
-  }
-}
+void WindowPortMus::OnWindowAddedToRootWindow() {}
 
-void WindowPortMus::OnWillRemoveWindowFromRootWindow() {
-  if (switches::IsMusHostingViz())
-    return;
-  if (is_frame_sink_id_added_to_compositor_) {
-    window_->layer()->GetCompositor()->RemoveFrameSink(GetFrameSinkId());
-    is_frame_sink_id_added_to_compositor_ = false;
-  }
-}
+void WindowPortMus::OnWillRemoveWindowFromRootWindow() {}
 
 void WindowPortMus::OnEventTargetingPolicyChanged() {
   SetEventTargetingPolicy(window_->event_targeting_policy());
@@ -656,19 +614,4 @@
   client_surface_embedder_->SetFallbackSurfaceInfo(fallback_surface_info_);
 }
 
-void WindowPortMus::OnSurfaceChanged(const viz::SurfaceInfo& surface_info) {
-  DCHECK(!switches::IsMusHostingViz());
-  DCHECK_EQ(surface_info.id().frame_sink_id(), GetFrameSinkId());
-  DCHECK_EQ(surface_info.id().local_surface_id(), local_surface_id_);
-  scoped_refptr<viz::SurfaceReferenceFactory> reference_factory =
-      aura::Env::GetInstance()
-          ->context_factory_private()
-          ->GetFrameSinkManager()
-          ->surface_manager()
-          ->reference_factory();
-  window_->layer()->SetShowPrimarySurface(
-      surface_info.id(), window_->bounds().size(), reference_factory);
-  window_->layer()->SetFallbackSurfaceId(surface_info.id());
-}
-
 }  // namespace aura
diff --git a/ui/aura/mus/window_port_mus.h b/ui/aura/mus/window_port_mus.h
index 732ca7b..449979e 100644
--- a/ui/aura/mus/window_port_mus.h
+++ b/ui/aura/mus/window_port_mus.h
@@ -12,14 +12,12 @@
 
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "components/viz/client/client_layer_tree_frame_sink.h"
 #include "components/viz/common/surfaces/surface_info.h"
 #include "services/ui/public/interfaces/cursor/cursor.mojom.h"
 #include "services/ui/public/interfaces/window_tree.mojom.h"
 #include "services/ui/public/interfaces/window_tree_constants.mojom.h"
 #include "ui/aura/aura_export.h"
-#include "ui/aura/local/layer_tree_frame_sink_local.h"
 #include "ui/aura/mus/mus_types.h"
 #include "ui/aura/mus/window_mus.h"
 #include "ui/aura/window_port.h"
@@ -282,8 +280,6 @@
   void UpdatePrimarySurfaceId();
   void UpdateClientSurfaceEmbedder();
 
-  void OnSurfaceChanged(const viz::SurfaceInfo& surface_info);
-
   WindowTreeClient* window_tree_client_;
 
   Window* window_ = nullptr;
@@ -309,10 +305,7 @@
   // When a frame sink is created
   // for a local aura::Window, we need keep a weak ptr of it, so we can update
   // the local surface id when necessary.
-  base::WeakPtr<cc::LayerTreeFrameSink> local_layer_tree_frame_sink_;
-  bool is_frame_sink_id_added_to_compositor_ = false;
-
-  base::WeakPtrFactory<WindowPortMus> weak_ptr_factory_;
+  base::WeakPtr<viz::ClientLayerTreeFrameSink> local_layer_tree_frame_sink_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowPortMus);
 };
diff --git a/ui/aura/mus/window_port_mus_unittest.cc b/ui/aura/mus/window_port_mus_unittest.cc
index 107d663e..bd40c6d 100644
--- a/ui/aura/mus/window_port_mus_unittest.cc
+++ b/ui/aura/mus/window_port_mus_unittest.cc
@@ -6,10 +6,8 @@
 
 #include "components/viz/client/client_layer_tree_frame_sink.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/local/layer_tree_frame_sink_local.h"
 #include "ui/aura/test/aura_test_base.h"
 #include "ui/aura/window.h"
-#include "ui/base/ui_base_switches_util.h"
 
 namespace aura {
 
@@ -19,7 +17,7 @@
 
   ~WindowPortMusTest() override = default;
 
-  base::WeakPtr<cc::LayerTreeFrameSink> GetFrameSinkFor(Window* window) {
+  base::WeakPtr<viz::ClientLayerTreeFrameSink> GetFrameSinkFor(Window* window) {
     auto* window_mus = WindowPortMus::Get(window);
     return window_mus->local_layer_tree_frame_sink_;
   }
@@ -45,14 +43,8 @@
 
   auto mus_frame_sink = GetFrameSinkFor(&window);
   ASSERT_TRUE(mus_frame_sink);
-  auto frame_sink_local_surface_id =
-      switches::IsMusHostingViz()
-          ? static_cast<viz::ClientLayerTreeFrameSink*>(mus_frame_sink.get())
-                ->local_surface_id()
-          : static_cast<LayerTreeFrameSinkLocal*>(mus_frame_sink.get())
-                ->local_surface_id();
-  EXPECT_TRUE(frame_sink_local_surface_id.is_valid());
-  EXPECT_EQ(frame_sink_local_surface_id, local_surface_id);
+  EXPECT_TRUE(mus_frame_sink->local_surface_id().is_valid());
+  EXPECT_EQ(mus_frame_sink->local_surface_id(), local_surface_id);
 }
 
 }  // namespace aura
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index 4e67c9d..37e176f 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -4,7 +4,6 @@
 
 #include "ui/compositor/test/in_process_context_factory.h"
 
-#include <limits>
 #include <utility>
 
 #include "base/bind.h"
@@ -46,8 +45,8 @@
 namespace ui {
 namespace {
 // The client_id used here should not conflict with the client_id generated
-// from RenderWidgetHostImpl and client_id(0) used by aura::WindowPortMus.
-constexpr uint32_t kDefaultClientId = std::numeric_limits<uint32_t>::max();
+// from RenderWidgetHostImpl.
+constexpr uint32_t kDefaultClientId = 0u;
 
 class FakeReflector : public Reflector {
  public:
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 9a0efae..7060731 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -61,6 +61,7 @@
     "//ui/display/manager",
     "//ui/events",
     "//ui/events:dom_keycode_converter",
+    "//ui/events/ozone:events_ozone_evdev",
     "//ui/events/ozone:events_ozone_layout",
     "//ui/events/platform",
     "//ui/gfx",
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index f62ed70..843d7c99 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -75,10 +75,6 @@
   }
 
   void InitializeUI(const InitParams& args) override {
-    connection_.reset(new WaylandConnection);
-    if (!connection_->Initialize())
-      LOG(FATAL) << "Failed to initialize Wayland platform";
-
 #if BUILDFLAG(USE_XKBCOMMON)
     KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
         std::make_unique<WaylandXkbKeyboardLayoutEngine>(
@@ -87,6 +83,9 @@
     KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
         std::make_unique<StubKeyboardLayoutEngine>());
 #endif
+    connection_.reset(new WaylandConnection);
+    if (!connection_->Initialize())
+      LOG(FATAL) << "Failed to initialize Wayland platform";
 
     cursor_factory_.reset(new BitmapCursorFactoryOzone);
     overlay_manager_.reset(new StubOverlayManager);
diff --git a/ui/ozone/platform/wayland/wayland_keyboard.cc b/ui/ozone/platform/wayland/wayland_keyboard.cc
index 036eecb6..66ac9bd 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard.cc
+++ b/ui/ozone/platform/wayland/wayland_keyboard.cc
@@ -9,6 +9,7 @@
 
 #include "base/files/scoped_file.h"
 #include "ui/base/ui_features.h"
+#include "ui/events/base_event_utils.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
@@ -23,15 +24,13 @@
 
 namespace ui {
 
-namespace {
-
-const int kXkbKeycodeOffset = 8;
-
-}  // namespace
-
 WaylandKeyboard::WaylandKeyboard(wl_keyboard* keyboard,
                                  const EventDispatchCallback& callback)
-    : obj_(keyboard), callback_(callback) {
+    : obj_(keyboard),
+      callback_(callback),
+      evdev_keyboard_(&modifiers_,
+                      KeyboardLayoutEngineManager::GetKeyboardLayoutEngine(),
+                      callback_) {
   static const wl_keyboard_listener listener = {
       &WaylandKeyboard::Keymap,    &WaylandKeyboard::Enter,
       &WaylandKeyboard::Leave,     &WaylandKeyboard::Key,
@@ -79,6 +78,12 @@
                             uint32_t serial,
                             wl_surface* surface) {
   WaylandWindow::FromSurface(surface)->set_keyboard_focus(false);
+
+  WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
+
+  // Reset all modifiers once focus is lost. Otherwise, the modifiers may be
+  // left with old flags, which are no longer valid.
+  keyboard->modifiers_.ResetKeyboardModifiers();
 }
 
 void WaylandKeyboard::Key(void* data,
@@ -90,26 +95,9 @@
   WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
   keyboard->connection_->set_serial(serial);
 
-  DomCode dom_code =
-      KeycodeConverter::NativeKeycodeToDomCode(key + kXkbKeycodeOffset);
-  if (dom_code == ui::DomCode::NONE)
-    return;
-
-  uint8_t flags = keyboard->modifiers_;
-  DomKey dom_key;
-  KeyboardCode key_code;
-  if (!KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
-          dom_code, flags, &dom_key, &key_code))
-    return;
-
-  // TODO(tonikitoo): handle repeat here.
-  bool down = state == WL_KEYBOARD_KEY_STATE_PRESSED;
-  ui::KeyEvent event(
-      down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code, dom_code,
-      keyboard->modifiers_, dom_key,
-      base::TimeTicks() + base::TimeDelta::FromMilliseconds(time));
-  event.set_source_device_id(keyboard->obj_.id());
-  keyboard->callback_.Run(&event);
+  keyboard->evdev_keyboard_.OnKeyChange(
+      key, state == WL_KEYBOARD_KEY_STATE_PRESSED, false, EventTimeForNow(),
+      keyboard->obj_.id());
 }
 
 void WaylandKeyboard::Modifiers(void* data,
@@ -119,23 +107,20 @@
                                 uint32_t mods_latched,
                                 uint32_t mods_locked,
                                 uint32_t group) {
-#if BUILDFLAG(USE_XKBCOMMON)
-  WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
-  auto* engine = static_cast<WaylandXkbKeyboardLayoutEngine*>(
-      KeyboardLayoutEngineManager::GetKeyboardLayoutEngine());
-
-  keyboard->modifiers_ =
-      engine->UpdateModifiers(mods_depressed, mods_latched, mods_locked, group);
-
-#endif
+  // KeyboardEvDev handles modifiers.
 }
 
 void WaylandKeyboard::RepeatInfo(void* data,
                                  wl_keyboard* obj,
                                  int32_t rate,
                                  int32_t delay) {
-  // TODO(tonikitoo): Implement proper repeat handling.
-  NOTIMPLEMENTED();
+  WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
+  keyboard->evdev_keyboard_.SetAutoRepeatRate(
+      base::TimeDelta::FromMilliseconds(delay),
+      base::TimeDelta::FromMilliseconds(rate));
+
+  // Keyboard rate less than 0 means, wayland wants to disable autorepeat.
+  keyboard->evdev_keyboard_.SetAutoRepeatEnabled(rate > 0 ? true : false);
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_keyboard.h b/ui/ozone/platform/wayland/wayland_keyboard.h
index e0ce521..372522a 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard.h
+++ b/ui/ozone/platform/wayland/wayland_keyboard.h
@@ -5,7 +5,9 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_KEYBOARD_H_
 #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_KEYBOARD_H_
 
+#include "ui/events/event_modifiers.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
+#include "ui/events/ozone/evdev/keyboard_evdev.h"
 #include "ui/ozone/platform/wayland/wayland_object.h"
 
 namespace ui {
@@ -21,7 +23,7 @@
     connection_ = connection;
   }
 
-  int modifiers() { return modifiers_; }
+  int modifiers() { return modifiers_.GetModifierFlags(); }
 
  private:
   // wl_keyboard_listener
@@ -60,7 +62,9 @@
   WaylandConnection* connection_ = nullptr;
   wl::Object<wl_keyboard> obj_;
   EventDispatchCallback callback_;
-  int modifiers_ = 0;
+
+  EventModifiers modifiers_;
+  KeyboardEvdev evdev_keyboard_;
 };
 
 }  // namespace ui