diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index edbf9e0..6c414b5 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1538,6 +1538,7 @@
     "//gin:gin_features",
     "//google_apis",
     "//gpu/config",
+    "//ipc",
     "//media",
     "//media:media_features",
     "//media/midi",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index fabc19c..fb8fbf2 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1080,9 +1080,6 @@
                                          "1",
                                          switches::kScrollEndEffect,
                                          "0")},
-    {"enable-icon-ntp", IDS_FLAGS_ICON_NTP_NAME, IDS_FLAGS_ICON_NTP_DESCRIPTION,
-     kOsAll, ENABLE_DISABLE_VALUE_TYPE(switches::kEnableIconNtp,
-                                       switches::kDisableIconNtp)},
     {"enable-touch-drag-drop", IDS_FLAGS_TOUCH_DRAG_DROP_NAME,
      IDS_FLAGS_TOUCH_DRAG_DROP_DESCRIPTION, kOsWin | kOsCrOS,
      ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchDragDrop,
diff --git a/chrome/browser/chromeos/arc/PRESUBMIT.py b/chrome/browser/chromeos/arc/PRESUBMIT.py
new file mode 100644
index 0000000..43ec8845
--- /dev/null
+++ b/chrome/browser/chromeos/arc/PRESUBMIT.py
@@ -0,0 +1,6 @@
+# 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.
+
+def CheckChangeOnUpload(input_api, output_api):
+  return input_api.canned_checks.CheckChangeLintsClean(input_api, output_api)
diff --git a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
index 21a1e42..925f9cdf 100644
--- a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
+++ b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
@@ -156,12 +156,12 @@
 }
 
 class ExtensionSignedInDevicesTest : public ExtensionApiUnittest {
- public:
-  void SetUp() override {
-    ExtensionApiUnittest::SetUp();
-
-    ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
-        profile(), CreateProfileSyncServiceMock);
+ private:
+  TestingProfile* CreateProfile() override {
+    TestingProfile::Builder builder;
+    builder.AddTestingFactory(ProfileSyncServiceFactory::GetInstance(),
+                              CreateProfileSyncServiceMock);
+    return builder.Build().release();
   }
 };
 
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index b4dbd5c..41b0fae 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -860,13 +860,9 @@
             return;
 
           var isArcEnabled = !e.value.value;
-          var androidAppSettings = $('android-apps-settings');
-          if (androidAppSettings != null)
-            androidAppSettings.hidden = isArcEnabled;
-
-          var talkbackSettingsButton = $('talkback-settings-button');
-          if (talkbackSettingsButton != null)
-            talkbackSettingsButton.hidden = isArcEnabled;
+          $('android-apps-settings').hidden = isArcEnabled;
+          $('talkback-settings-button').hidden = isArcEnabled;
+          $('stylus-find-more-link').hidden = isArcEnabled;
         });
 
         $('android-apps-settings-link').addEventListener('click', function(e) {
diff --git a/chrome/browser/resources/options/chromeos/stylus_overlay.html b/chrome/browser/resources/options/chromeos/stylus_overlay.html
index ade2323..bc955bbe 100644
--- a/chrome/browser/resources/options/chromeos/stylus_overlay.html
+++ b/chrome/browser/resources/options/chromeos/stylus_overlay.html
@@ -32,10 +32,8 @@
       </div>
     </div>
     <div class="settings-row">
-      <!-- TODO(jdufault): Real webstore link -->
-      <a is="action-link" i18n-content="stylusFindMoreApps" target="_blank"
-         id='stylus-find-more-link'
-         href="https://play.google.com/store/apps/collection/promotion_30023cb_stylus_apps"></a>
+      <a is="action-link" i18n-content="stylusFindMoreApps"
+         id='stylus-find-more-link'></a>
     </div>
   </div>
 
diff --git a/chrome/browser/resources/options/chromeos/stylus_overlay.js b/chrome/browser/resources/options/chromeos/stylus_overlay.js
index 9462dc2..9fa277fa 100644
--- a/chrome/browser/resources/options/chromeos/stylus_overlay.js
+++ b/chrome/browser/resources/options/chromeos/stylus_overlay.js
@@ -57,6 +57,12 @@
       $('stylus-note-taking-app-select')
           .addEventListener(
               'change', this.handleNoteTakingAppSelected_.bind(this));
+
+      var stylusAppsUrl = "https://play.google.com/store/apps/collection/" +
+          "promotion_30023cb_stylus_apps";
+      $('stylus-find-more-link').onclick = function(event) {
+        chrome.send('showPlayStoreApps', [stylusAppsUrl]);
+      };
     },
 
     /** @override */
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
index 2f4c318..20c4e173 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -240,6 +240,17 @@
                         event_flags);
 }
 
+bool LaunchPlayStoreWithUrl(const std::string& url) {
+  arc::mojom::IntentHelperInstance* instance =
+      GET_INTENT_HELPER_INSTANCE(HandleUrl);
+  if (!instance) {
+    VLOG(1) << "Cannot find a mojo instance, ARC is unreachable";
+    return false;
+  }
+  instance->HandleUrl(url, kPlayStorePackage);
+  return true;
+}
+
 bool LaunchApp(content::BrowserContext* context,
                const std::string& app_id,
                int event_flags) {
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.h b/chrome/browser/ui/app_list/arc/arc_app_utils.h
index e60f40f5..475fc7f3 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.h
@@ -38,6 +38,9 @@
 bool LaunchAndroidSettingsApp(content::BrowserContext* context,
                               int event_flags);
 
+// Launch Play Store app.
+bool LaunchPlayStoreWithUrl(const std::string& url);
+
 // Launch an app with given layout and let the system decides how big and where
 // to place it.
 bool LaunchApp(content::BrowserContext* context,
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index a30bfaf..5b9b1d4 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -885,6 +885,10 @@
       base::Bind(&BrowserOptionsHandler::ShowAndroidAppsSettings,
                  base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
+      "showPlayStoreApps",
+      base::Bind(&BrowserOptionsHandler::ShowPlayStoreApps,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "showAccessibilityTalkBackSettings",
       base::Bind(&BrowserOptionsHandler::ShowAccessibilityTalkBackSettings,
                  base::Unretained(this)));
@@ -2041,6 +2045,18 @@
   arc::LaunchAndroidSettingsApp(profile, flags);
 }
 
+void BrowserOptionsHandler::ShowPlayStoreApps(const base::ListValue* args) {
+  std::string apps_url;
+  args->GetString(0, &apps_url);
+  Profile* profile = Profile::FromWebUI(web_ui());
+  if (!arc::IsArcAllowedForProfile(profile)) {
+    VLOG(1) << "ARC is not enabled for this profile";
+    return;
+  }
+
+  arc::LaunchPlayStoreWithUrl(apps_url);
+}
+
 void BrowserOptionsHandler::ShowAccessibilityTalkBackSettings(
     const base::ListValue *args) {
   Profile* profile = Profile::FromWebUI(web_ui());
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.h b/chrome/browser/ui/webui/options/browser_options_handler.h
index e84a212..37ba5f6 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.h
+++ b/chrome/browser/ui/webui/options/browser_options_handler.h
@@ -341,6 +341,9 @@
   // Called to show Android apps settings.
   void ShowAndroidAppsSettings(const base::ListValue* args);
 
+  // Called to show apps based on a url for the Play Store.
+  void ShowPlayStoreApps(const base::ListValue* args);
+
   // Called to show TalkBack settings.
   void ShowAccessibilityTalkBackSettings(const base::ListValue *args);
 #endif
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index 72d0b6b..5cd4a6e2 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -6,12 +6,12 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <string>
+#include <vector>
 
-#include "base/command_line.h"
 #include "base/i18n/rtl.h"
 #include "base/json/string_escape.h"
 #include "base/macros.h"
-#include "base/metrics/field_trial.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -31,7 +31,6 @@
 #include "third_party/WebKit/public/web/WebScriptSource.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_switches.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "url/gurl.h"
@@ -70,21 +69,6 @@
   return base::string16(reinterpret_cast<const base::char16*>(*s), s.length());
 }
 
-// Returns whether icon NTP is enabled by experiment.
-// TODO(huangs): Remove all 3 copies of this routine once Icon NTP launches.
-bool IsIconNTPEnabled() {
-  // Note: It's important to query the field trial state first, to ensure that
-  // UMA reports the correct group.
-  const std::string group_name = base::FieldTrialList::FindFullName("IconNTP");
-  using base::CommandLine;
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableIconNtp))
-    return false;
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableIconNtp))
-    return true;
-
-  return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
-}
-
 // Converts string16 to V8 String.
 v8::Local<v8::String> UTF16ToV8String(v8::Isolate* isolate,
                                        const base::string16& s) {
@@ -189,18 +173,6 @@
 
   obj->Set(v8::String::NewFromUtf8(isolate, "tileSource"),
            v8::Integer::New(isolate, static_cast<int>(mv_item.source)));
-
-  if (IsIconNTPEnabled()) {
-    // Update website http://www.chromium.org/embeddedsearch when we make this
-    // permanent.
-    // Large icon size is 48px * window.devicePixelRatio. This is easier to set
-    // from JS, where IsIconNTPEnabled() is not available. So we add stubs
-    // here, and let JS fill in details.
-    obj->Set(v8::String::NewFromUtf8(isolate, "largeIconUrl"),
-             v8::String::NewFromUtf8(isolate, "chrome-search://large-icon/"));
-    obj->Set(v8::String::NewFromUtf8(isolate, "fallbackIconUrl"),
-        v8::String::NewFromUtf8(isolate, "chrome-search://fallback-icon/"));
-  }
   obj->Set(v8::String::NewFromUtf8(isolate, "title"),
            UTF16ToV8String(isolate, title));
   obj->Set(v8::String::NewFromUtf8(isolate, "domain"),
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 26ba839..730545c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3773,6 +3773,7 @@
         [ "../browser/download/download_request_infobar_delegate_unittest.cc" ]
     deps += [
       "//device/battery:mojo_bindings",
+      "//ipc",
       "//third_party/libaddressinput",
     ]
   }
@@ -4384,7 +4385,10 @@
       "../utility/cloud_print/pwg_encoder_unittest.cc",
     ]
 
-    deps += [ "//printing:test_support" ]
+    deps += [
+      "//ipc",
+      "//printing:test_support",
+    ]
   }
 
   if (enable_media_router) {
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index f4c66341..3f660b4 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -49,6 +49,7 @@
     "//content/public/utility",
     "//courgette:courgette_lib",
     "//extensions/features",
+    "//ipc",
     "//media",
     "//net:net_with_v8",
     "//printing/features",
diff --git a/chromecast/app/BUILD.gn b/chromecast/app/BUILD.gn
index cf2b992..8de02c8 100644
--- a/chromecast/app/BUILD.gn
+++ b/chromecast/app/BUILD.gn
@@ -68,6 +68,7 @@
     "//base/test:test_support",
     "//chromecast/base",
     "//content/test:test_support",
+    "//ipc",
     "//mojo/edk/embedder:headers",
   ]
 }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 34556d25..c49043cd 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-9248.0.0
\ No newline at end of file
+9266.0.0
\ No newline at end of file
diff --git a/components/arc/PRESUBMIT.py b/components/arc/PRESUBMIT.py
new file mode 100644
index 0000000..43ec8845
--- /dev/null
+++ b/components/arc/PRESUBMIT.py
@@ -0,0 +1,6 @@
+# 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.
+
+def CheckChangeOnUpload(input_api, output_api):
+  return input_api.canned_checks.CheckChangeLintsClean(input_api, output_api)
diff --git a/components/favicon/core/favicon_driver_impl.cc b/components/favicon/core/favicon_driver_impl.cc
index 8539b03..2aecafd3 100644
--- a/components/favicon/core/favicon_driver_impl.cc
+++ b/components/favicon/core/favicon_driver_impl.cc
@@ -4,9 +4,7 @@
 
 #include "components/favicon/core/favicon_driver_impl.h"
 
-#include "base/command_line.h"
 #include "base/logging.h"
-#include "base/metrics/field_trial.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "components/bookmarks/browser/bookmark_model.h"
@@ -14,26 +12,10 @@
 #include "components/favicon/core/favicon_handler.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/history/core/browser/history_service.h"
-#include "ui/base/ui_base_switches.h"
 
 namespace favicon {
 namespace {
 
-// Returns whether icon NTP is enabled by experiment.
-// TODO(huangs): Remove all 3 copies of this routine once Icon NTP launches.
-bool IsIconNTPEnabled() {
-  // Note: It's important to query the field trial state first, to ensure that
-  // UMA reports the correct group.
-  const std::string group_name = base::FieldTrialList::FindFullName("IconNTP");
-  using base::CommandLine;
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableIconNtp))
-    return false;
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableIconNtp))
-    return true;
-
-  return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
-}
-
 #if defined(OS_ANDROID) || defined(OS_IOS)
 const bool kEnableTouchIcon = true;
 #else
@@ -52,7 +34,7 @@
       favicon_service_, this, kEnableTouchIcon
                                   ? FaviconDriverObserver::NON_TOUCH_LARGEST
                                   : FaviconDriverObserver::NON_TOUCH_16_DIP));
-  if (kEnableTouchIcon || IsIconNTPEnabled()) {
+  if (kEnableTouchIcon) {
     touch_icon_handler_.reset(new FaviconHandler(
         favicon_service_, this, FaviconDriverObserver::TOUCH_LARGEST));
   }
diff --git a/components/gcm_driver/gcm_account_tracker.cc b/components/gcm_driver/gcm_account_tracker.cc
index 56808d94..f3be5ff4d 100644
--- a/components/gcm_driver/gcm_account_tracker.cc
+++ b/components/gcm_driver/gcm_account_tracker.cc
@@ -308,8 +308,11 @@
 
 void GCMAccountTracker::DeleteTokenRequest(
     const OAuth2TokenService::Request* request) {
-  ScopedVector<OAuth2TokenService::Request>::iterator iter = std::find(
-      pending_token_requests_.begin(), pending_token_requests_.end(), request);
+  auto iter = std::find_if(
+      pending_token_requests_.begin(), pending_token_requests_.end(),
+      [request](const std::unique_ptr<OAuth2TokenService::Request>& r) {
+        return request == r.get();
+      });
   if (iter != pending_token_requests_.end())
     pending_token_requests_.erase(iter);
 }
@@ -341,7 +344,7 @@
   std::unique_ptr<OAuth2TokenService::Request> request =
       GetTokenService()->StartRequest(account_iter->first, scopes, this);
 
-  pending_token_requests_.push_back(request.release());
+  pending_token_requests_.push_back(std::move(request));
   account_iter->second.state = GETTING_TOKEN;
 }
 
diff --git a/components/gcm_driver/gcm_account_tracker.h b/components/gcm_driver/gcm_account_tracker.h
index 5535014..ec72cde 100644
--- a/components/gcm_driver/gcm_account_tracker.h
+++ b/components/gcm_driver/gcm_account_tracker.h
@@ -8,10 +8,11 @@
 #include <stddef.h>
 
 #include <map>
+#include <memory>
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
-#include "base/memory/scoped_vector.h"
 #include "components/gcm_driver/gcm_client.h"
 #include "components/gcm_driver/gcm_connection_observer.h"
 #include "google_apis/gaia/account_tracker.h"
@@ -154,7 +155,8 @@
   // Indicates whether shutdown has been called.
   bool shutdown_called_;
 
-  ScopedVector<OAuth2TokenService::Request> pending_token_requests_;
+  std::vector<std::unique_ptr<OAuth2TokenService::Request>>
+      pending_token_requests_;
 
   // Creates weak pointers used to postpone reporting tokens. See
   // ScheduleReportTokens.
diff --git a/components/nacl/common/BUILD.gn b/components/nacl/common/BUILD.gn
index de3d469..8859d08 100644
--- a/components/nacl/common/BUILD.gn
+++ b/components/nacl/common/BUILD.gn
@@ -36,7 +36,6 @@
       "//base:base_static",
       "//content/public/common:service_names",
       "//ipc",
-      "//ipc:mojom",
       "//mojo/edk/system",
       "//services/service_manager/public/cpp",
     ]
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn
index cdd9410..21d91f9 100644
--- a/content/app/BUILD.gn
+++ b/content/app/BUILD.gn
@@ -126,7 +126,10 @@
     }
 
     configs += extra_configs
-    deps = content_app_deps + [ ":$runner_target_name" ]
+    deps = content_app_deps + [
+             ":$runner_target_name",
+             "//ipc",
+           ]
     forward_variables_from(invoker,
                            [
                              "defines",
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index d42b36b6..73d3316 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -86,7 +86,6 @@
     "//gpu/command_buffer/client:gles2_interface",
     "//gpu/ipc/host",
     "//ipc",
-    "//ipc:mojom",
     "//media",
     "//media/capture",
     "//media/capture/mojo:image_capture",
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index a2f19a9f..6f88159 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -9,6 +9,7 @@
 
 #include <algorithm>
 #include <limits>
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -1722,7 +1723,6 @@
     switches::kDisableGpuVsync,
     switches::kDisableLowResTiling,
     switches::kDisableHistogramCustomizer,
-    switches::kDisableIconNtp,
     switches::kDisableLCDText,
     switches::kDisableLocalStorage,
     switches::kDisableLogging,
@@ -1759,7 +1759,6 @@
     switches::kEnableGpuClientTracing,
     switches::kEnableGpuMemoryBufferVideoFrames,
     switches::kEnableGPUServiceLogging,
-    switches::kEnableIconNtp,
     switches::kEnableLowResTiling,
     switches::kEnableMediaSuspend,
     switches::kEnableInbandTextTracks,
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
index d72cd20..2d7522cc 100644
--- a/content/child/BUILD.gn
+++ b/content/child/BUILD.gn
@@ -233,7 +233,6 @@
     "//crypto:platform",
     "//gpu/command_buffer/client",
     "//ipc",
-    "//ipc:mojom",
     "//media",
     "//mojo/common",
     "//mojo/edk/system",
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index 1d70521d..9bc53f5 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -914,8 +914,7 @@
 }
 
 bool WebURLLoaderImpl::Context::CanHandleDataURLRequestLocally() const {
-  GURL url = request_.url();
-  if (!url.SchemeIs(url::kDataScheme))
+  if (!request_.url().protocolIs(url::kDataScheme))
     return false;
 
   // The fast paths for data URL, Start() and HandleDataURL(), don't support
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 2e169434..7a76a91d 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -372,7 +372,6 @@
     "//gpu/ipc/common",
     "//gpu/skia_bindings",
     "//ipc",
-    "//ipc:mojom",
     "//media",
     "//media:shared_memory_support",
     "//media/base/ipc",
@@ -620,6 +619,9 @@
     "//url/mojo:url_mojom_origin",
   ]
 
+  overridden_deps = [ "//ipc:mojom" ]
+  component_deps = [ "//ipc" ]
+
   export_class_attribute = "CONTENT_EXPORT"
   export_define = "CONTENT_IMPLEMENTATION=1"
   export_header = "content/common/content_export.h"
diff --git a/content/public/test/test_utils.h b/content/public/test/test_utils.h
index 6a3ab90..29f5965 100644
--- a/content/public/test/test_utils.h
+++ b/content/public/test/test_utils.h
@@ -100,7 +100,7 @@
 // GetDeferredQuitTaskForRunLoop directly.
 // If you found a case where base::RunLoop is inconvenient or can not be used at
 // all, please post details in a comment on https://crbug.com/668707.
-class MessageLoopRunner : public base::RefCounted<MessageLoopRunner> {
+class MessageLoopRunner : public base::RefCountedThreadSafe<MessageLoopRunner> {
  public:
   enum class QuitMode {
     // Message loop stops after finishing the current task.
@@ -129,7 +129,7 @@
   bool loop_running() const { return loop_running_; }
 
  private:
-  friend class base::RefCounted<MessageLoopRunner>;
+  friend class base::RefCountedThreadSafe<MessageLoopRunner>;
   ~MessageLoopRunner();
 
   QuitMode quit_mode_;
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 7ecd0bec..e9432902 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -263,7 +263,6 @@
     "mojo/blink_interface_registry_impl.h",
     "mojo/interface_provider_js_wrapper.cc",
     "mojo/interface_provider_js_wrapper.h",
-    "mojo/thread_safe_associated_interface_ptr_provider.h",
     "mojo_bindings_controller.cc",
     "mojo_bindings_controller.h",
     "mojo_context_state.cc",
diff --git a/content/renderer/mojo/thread_safe_associated_interface_ptr_provider.h b/content/renderer/mojo/thread_safe_associated_interface_ptr_provider.h
deleted file mode 100644
index 87dd2ab..0000000
--- a/content/renderer/mojo/thread_safe_associated_interface_ptr_provider.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2016 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_MOJO_THREAD_SAFE_ASSOCIATED_INTERFACE_PTR_PROVIDER_H_
-#define CONTENT_RENDERER_MOJO_THREAD_SAFE_ASSOCIATED_INTERFACE_PTR_PROVIDER_H_
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "ipc/ipc_channel_proxy.h"
-#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
-
-namespace content {
-
-// This class provides a way to create ThreadSafeAssociatedInterfacePtr's from
-// the main thread that can be used right away (even though the backing
-// AssociatedInterfacePtr is created on the IO thread and the channel may not be
-// connected yet).
-class ThreadSafeAssociatedInterfacePtrProvider {
- public:
-  // Note that this does not take ownership of |channel_proxy|. It's the
-  // caller responsibility to ensure |channel_proxy| outlives this object.
-  explicit ThreadSafeAssociatedInterfacePtrProvider(
-      IPC::ChannelProxy* channel_proxy)
-      : channel_proxy_(channel_proxy) {}
-
-  template <typename Interface>
-  scoped_refptr<mojo::ThreadSafeAssociatedInterfacePtr<Interface>>
-  CreateInterfacePtr() {
-    scoped_refptr<mojo::ThreadSafeAssociatedInterfacePtr<Interface>> ptr =
-        mojo::ThreadSafeAssociatedInterfacePtr<Interface>::CreateUnbound(
-            channel_proxy_->ipc_task_runner());
-    channel_proxy_->RetrieveAssociatedInterfaceOnIOThread<Interface>(base::Bind(
-        &ThreadSafeAssociatedInterfacePtrProvider::BindInterfacePtr<Interface>,
-        ptr));
-    return ptr;
-  }
-
- private:
-  template <typename Interface>
-  static void BindInterfacePtr(
-      const scoped_refptr<mojo::ThreadSafeAssociatedInterfacePtr<Interface>>&
-          ptr,
-      mojo::AssociatedInterfacePtr<Interface> interface_ptr) {
-    bool success = ptr->Bind(std::move(interface_ptr));
-    DCHECK(success);
-  }
-
-  IPC::ChannelProxy* channel_proxy_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadSafeAssociatedInterfacePtrProvider);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MOJO_THREAD_SAFE_ASSOCIATED_INTERFACE_PTR_PROVIDER_H_
\ No newline at end of file
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index acb26cb2..56d9e1a 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -109,7 +109,6 @@
 #include "content/renderer/media/render_media_client.h"
 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
 #include "content/renderer/media/video_capture_impl_manager.h"
-#include "content/renderer/mojo/thread_safe_associated_interface_ptr_provider.h"
 #include "content/renderer/net_info_helper.h"
 #include "content/renderer/p2p/socket_dispatcher.h"
 #include "content/renderer/render_frame_proxy.h"
@@ -630,11 +629,8 @@
     gpu_ = ui::Gpu::Create(GetRemoteInterfaces(), GetIOTaskRunner());
   }
 
-  thread_safe_associated_interface_ptr_provider_ =
-      base::MakeUnique<ThreadSafeAssociatedInterfacePtrProvider>(channel());
-  thread_safe_render_message_filter_ =
-      thread_safe_associated_interface_ptr_provider_
-          ->CreateInterfacePtr<mojom::RenderMessageFilter>();
+  channel()->GetThreadSafeRemoteAssociatedInterface(
+      &thread_safe_render_message_filter_);
   shared_bitmap_manager_.reset(
       new ChildSharedBitmapManager(thread_safe_render_message_filter_));
 
@@ -2218,36 +2214,18 @@
 }
 
 void RenderThreadImpl::OnMemoryStateChange(base::MemoryState state) {
-  // TODO(hajimehoshi): Adjust the size of this memory usage according to
-  // |state|. RenderThreadImpl doesn't have a feature to limit memory usage at
-  // present.
   if (blink_platform_impl_) {
     blink::WebMemoryCoordinator::onMemoryStateChange(
         static_cast<blink::MemoryState>(state));
   }
-  switch (state) {
-    case base::MemoryState::NORMAL:
-      break;
-    case base::MemoryState::THROTTLED:
-      // TODO(bashi): Figure out what kind of strategy is suitable on
-      // THROTTLED state. crbug.com/674815
-#if defined(OS_ANDROID)
-      OnTrimMemoryImmediately();
-#else
-      OnSyncMemoryPressure(
-          base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
-#endif
-      ReleaseFreeMemory();
-      break;
-    case base::MemoryState::SUSPENDED:
-      OnTrimMemoryImmediately();
-      ReleaseFreeMemory();
-      ClearMemory();
-      break;
-    case base::MemoryState::UNKNOWN:
-      NOTREACHED();
-      break;
-  }
+}
+
+void RenderThreadImpl::OnPurgeMemory() {
+  OnTrimMemoryImmediately();
+  ReleaseFreeMemory();
+  ClearMemory();
+  if (blink_platform_impl_)
+    blink::WebMemoryCoordinator::onPurgeMemory();
 }
 
 void RenderThreadImpl::ClearMemory() {
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 3924b340..22870b37 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -129,7 +129,6 @@
 class RendererBlinkPlatformImpl;
 class RendererGpuVideoAcceleratorFactories;
 class ResourceDispatchThrottler;
-class ThreadSafeAssociatedInterfacePtrProvider;
 class VideoCaptureImplManager;
 
 #if defined(OS_ANDROID)
@@ -526,6 +525,7 @@
 
   // base::MemoryCoordinatorClient implementation:
   void OnMemoryStateChange(base::MemoryState state) override;
+  void OnPurgeMemory() override;
 
   void ClearMemory();
 
@@ -626,8 +626,6 @@
 
   // Used on the render thread.
   std::unique_ptr<VideoCaptureImplManager> vc_manager_;
-  std::unique_ptr<ThreadSafeAssociatedInterfacePtrProvider>
-      thread_safe_associated_interface_ptr_provider_;
 
   std::unique_ptr<ChildSharedBitmapManager> shared_bitmap_manager_;
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 4c72abf..d39cc9c 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -719,7 +719,7 @@
     "//gin",
     "//gpu",
     "//gpu/ipc/host",
-    "//ipc:mojom",
+    "//ipc",
     "//ipc:test_support",
     "//media",
     "//media:test_support",
diff --git a/extensions/renderer/api_binding.cc b/extensions/renderer/api_binding.cc
index d34ebdc..6056346 100644
--- a/extensions/renderer/api_binding.cc
+++ b/extensions/renderer/api_binding.cc
@@ -20,6 +20,7 @@
 #include "extensions/renderer/v8_helpers.h"
 #include "gin/arguments.h"
 #include "gin/per_context_data.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
 
 namespace extensions {
 
@@ -335,8 +336,8 @@
         isolate, callback, context, callback_args);
     request->has_callback = true;
   }
-  // TODO(devlin): Query and curry user gestures around.
-  request->has_user_gesture = false;
+  request->has_user_gesture =
+      blink::WebUserGestureIndicator::isProcessingUserGestureThreadSafe();
   request->arguments = std::move(converted_arguments);
   request->method_name = name;
 
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/api_binding_unittest.cc
index e8b4fff..389d6ec 100644
--- a/extensions/renderer/api_binding_unittest.cc
+++ b/extensions/renderer/api_binding_unittest.cc
@@ -17,6 +17,7 @@
 #include "gin/converter.h"
 #include "gin/public/context_holder.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
@@ -126,8 +127,7 @@
  public:
   void OnFunctionCall(std::unique_ptr<APIBinding::Request> request,
                       v8::Local<v8::Context> context) {
-    arguments_ = std::move(request->arguments);
-    had_callback_ = request->has_callback;
+    last_request_ = std::move(request);
   }
 
  protected:
@@ -206,7 +206,11 @@
             expected_error);
   }
 
-  bool HandlerWasInvoked() const { return arguments_ != nullptr; }
+  bool HandlerWasInvoked() const { return last_request_ != nullptr; }
+  const APIBinding::Request* last_request() const {
+    return last_request_.get();
+  }
+  void reset_last_request() { last_request_.reset(); }
   APIBinding* binding() { return binding_.get(); }
   APIEventHandler* event_handler() { return event_handler_.get(); }
   APIRequestHandler* request_handler() { return request_handler_.get(); }
@@ -221,8 +225,7 @@
                bool expect_callback,
                const std::string& expected_error);
 
-  std::unique_ptr<base::ListValue> arguments_;
-  bool had_callback_ = false;
+  std::unique_ptr<APIBinding::Request> last_request_;
   std::unique_ptr<APIBinding> binding_;
   std::unique_ptr<APIEventHandler> event_handler_;
   std::unique_ptr<APIRequestHandler> request_handler_;
@@ -243,7 +246,7 @@
                                  const std::string& expected_json_arguments,
                                  bool expect_callback,
                                  const std::string& expected_error) {
-  EXPECT_FALSE(arguments_);
+  EXPECT_FALSE(last_request_);
   std::string wrapped_script_source =
       base::StringPrintf("(function(obj) { %s })", script_source.c_str());
 
@@ -255,16 +258,16 @@
 
   if (should_pass) {
     RunFunction(func, context, 1, argv);
-    ASSERT_TRUE(arguments_) << script_source;
-    EXPECT_EQ(expected_json_arguments, ValueToString(*arguments_));
-    EXPECT_EQ(expect_callback, had_callback_) << script_source;
+    ASSERT_TRUE(last_request_) << script_source;
+    EXPECT_EQ(expected_json_arguments,
+              ValueToString(*last_request_->arguments));
+    EXPECT_EQ(expect_callback, last_request_->has_callback) << script_source;
   } else {
     RunFunctionAndExpectError(func, context, 1, argv, expected_error);
-    EXPECT_FALSE(arguments_);
+    EXPECT_FALSE(last_request_);
   }
 
-  arguments_.reset();
-  had_callback_ = false;
+  last_request_.reset();
 }
 
 TEST_F(APIBindingUnittest, TestEmptyAPI) {
@@ -985,4 +988,33 @@
              "['foo',42]", false);
 }
 
+// Test that user gestures are properly recorded when calling APIs.
+TEST_F(APIBindingUnittest, TestUserGestures) {
+  SetFunctions(kFunctions);
+  InitializeBinding();
+
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = ContextLocal();
+
+  v8::Local<v8::Object> binding_object = binding()->CreateInstance(
+      context, isolate(), event_handler(), base::Bind(&AllowAllAPIs));
+
+  v8::Local<v8::Function> function =
+      FunctionFromString(context, "(function(obj) { obj.oneString('foo');})");
+  ASSERT_FALSE(function.IsEmpty());
+
+  v8::Local<v8::Value> argv[] = {binding_object};
+  RunFunction(function, context, arraysize(argv), argv);
+  ASSERT_TRUE(last_request());
+  EXPECT_FALSE(last_request()->has_user_gesture);
+  reset_last_request();
+
+  blink::WebScopedUserGesture user_gesture(nullptr);
+  RunFunction(function, context, arraysize(argv), argv);
+  ASSERT_TRUE(last_request());
+  EXPECT_TRUE(last_request()->has_user_gesture);
+
+  reset_last_request();
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/api_request_handler.cc b/extensions/renderer/api_request_handler.cc
index 5319aa0..ef360c87 100644
--- a/extensions/renderer/api_request_handler.cc
+++ b/extensions/renderer/api_request_handler.cc
@@ -9,6 +9,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
 #include "content/public/child/v8_value_converter.h"
+#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
 
 namespace extensions {
 
@@ -17,7 +19,11 @@
     v8::Local<v8::Function> callback,
     v8::Local<v8::Context> context,
     const std::vector<v8::Local<v8::Value>>& local_callback_args)
-    : isolate(isolate), context(isolate, context), callback(isolate, callback) {
+    : isolate(isolate),
+      context(isolate, context),
+      callback(isolate, callback),
+      user_gesture_token(
+          blink::WebUserGestureIndicator::currentUserGestureToken()) {
   if (!local_callback_args.empty()) {
     callback_arguments.reserve(local_callback_args.size());
     for (const auto& arg : local_callback_args)
@@ -74,6 +80,7 @@
   for (const auto& arg : response_args)
     args.push_back(converter->ToV8Value(arg.get(), context));
 
+  blink::WebScopedUserGesture user_gesture(pending_request.user_gesture_token);
   // args.size() is converted to int, but args is controlled by chrome and is
   // never close to std::numeric_limits<int>::max.
   call_js_.Run(pending_request.callback.Get(isolate), context, args.size(),
diff --git a/extensions/renderer/api_request_handler.h b/extensions/renderer/api_request_handler.h
index f5ce48f..9d3c8e9 100644
--- a/extensions/renderer/api_request_handler.h
+++ b/extensions/renderer/api_request_handler.h
@@ -11,6 +11,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "third_party/WebKit/public/web/WebUserGestureToken.h"
 #include "v8/include/v8.h"
 
 namespace base {
@@ -63,6 +64,7 @@
     v8::Global<v8::Context> context;
     v8::Global<v8::Function> callback;
     std::vector<v8::Global<v8::Value>> callback_arguments;
+    blink::WebUserGestureToken user_gesture_token;
   };
 
   // The next available request identifier.
diff --git a/extensions/renderer/api_request_handler_unittest.cc b/extensions/renderer/api_request_handler_unittest.cc
index 3bff9eaa..164edea 100644
--- a/extensions/renderer/api_request_handler_unittest.cc
+++ b/extensions/renderer/api_request_handler_unittest.cc
@@ -3,14 +3,18 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/optional.h"
 #include "base/values.h"
 #include "extensions/renderer/api_binding_test.h"
 #include "extensions/renderer/api_binding_test_util.h"
 #include "extensions/renderer/api_request_handler.h"
 #include "gin/converter.h"
+#include "gin/function_template.h"
 #include "gin/public/context_holder.h"
 #include "gin/public/isolate_holder.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
 
 namespace extensions {
 
@@ -192,4 +196,56 @@
   EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty());
 }
 
+// Test user gestures being curried around for API requests.
+TEST_F(APIRequestHandlerTest, UserGestureTest) {
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = ContextLocal();
+
+  APIRequestHandler request_handler(
+      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)));
+
+  auto callback = [](base::Optional<bool>* ran_with_user_gesture) {
+    *ran_with_user_gesture =
+        blink::WebUserGestureIndicator::isProcessingUserGestureThreadSafe();
+  };
+
+  // Set up a callback to be used with the request so we can check if a user
+  // gesture was active.
+  base::Optional<bool> ran_with_user_gesture;
+  v8::Local<v8::FunctionTemplate> function_template =
+      gin::CreateFunctionTemplate(isolate(),
+                                  base::Bind(callback, &ran_with_user_gesture));
+  v8::Local<v8::Function> v8_callback =
+      function_template->GetFunction(context).ToLocalChecked();
+
+  // Try first without a user gesture.
+  int request_id = request_handler.AddPendingRequest(isolate(), v8_callback,
+                                                     context, ArgumentList());
+  request_handler.CompleteRequest(request_id, *ListValueFromString("[]"));
+
+  ASSERT_TRUE(ran_with_user_gesture);
+  EXPECT_FALSE(*ran_with_user_gesture);
+  ran_with_user_gesture.reset();
+
+  // Next try calling with a user gesture. Since a gesture will be active at the
+  // time of the call, it should also be active during the callback.
+  {
+    blink::WebScopedUserGesture user_gesture(nullptr);
+    EXPECT_TRUE(
+        blink::WebUserGestureIndicator::isProcessingUserGestureThreadSafe());
+    request_id = request_handler.AddPendingRequest(isolate(), v8_callback,
+                                                   context, ArgumentList());
+  }
+  EXPECT_FALSE(
+      blink::WebUserGestureIndicator::isProcessingUserGestureThreadSafe());
+
+  request_handler.CompleteRequest(request_id, *ListValueFromString("[]"));
+  ASSERT_TRUE(ran_with_user_gesture);
+  EXPECT_TRUE(*ran_with_user_gesture);
+  // Sanity check - after the callback ran, there shouldn't be an active
+  // gesture.
+  EXPECT_FALSE(
+      blink::WebUserGestureIndicator::isProcessingUserGestureThreadSafe());
+}
+
 }  // namespace extensions
diff --git a/ios/chrome/browser/ui/alert_coordinator/BUILD.gn b/ios/chrome/browser/ui/alert_coordinator/BUILD.gn
index 8094e9c..7a7ff731 100644
--- a/ios/chrome/browser/ui/alert_coordinator/BUILD.gn
+++ b/ios/chrome/browser/ui/alert_coordinator/BUILD.gn
@@ -67,6 +67,7 @@
 }
 
 source_set("eg_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
     "alert_coordinator_egtest.mm",
diff --git a/ios/chrome/browser/ui/alert_coordinator/alert_coordinator_egtest.mm b/ios/chrome/browser/ui/alert_coordinator/alert_coordinator_egtest.mm
index 02a8360..f881234 100644
--- a/ios/chrome/browser/ui/alert_coordinator/alert_coordinator_egtest.mm
+++ b/ios/chrome/browser/ui/alert_coordinator/alert_coordinator_egtest.mm
@@ -6,13 +6,16 @@
 #import <UIKit/UIKit.h>
 #import <XCTest/XCTest.h>
 
-#import "base/mac/scoped_nsobject.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/testing/earl_grey/disabled_test_macros.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace {
 NSString* kTitle = @"Foo Title";
 }  // namespace
@@ -39,16 +42,16 @@
   UIViewController* topViewController =
       [[[UIApplication sharedApplication] keyWindow] rootViewController];
 
-  base::scoped_nsobject<AlertCoordinator> alertCoordinator(
+  AlertCoordinator* alertCoordinator =
       [[AlertCoordinator alloc] initWithBaseViewController:topViewController
                                                      title:kTitle
-                                                   message:nil]);
+                                                   message:nil];
 
   [alertCoordinator start];
 
   GREYAssertTrue([self isPresentingAlert], @"An alert should be presented");
 
-  alertCoordinator.reset();
+  alertCoordinator = nil;
 
   GREYAssertFalse([self isPresentingAlert], @"The alert should be removed");
 }
@@ -64,10 +67,10 @@
   UIViewController* topViewController =
       [[[UIApplication sharedApplication] keyWindow] rootViewController];
 
-  base::scoped_nsobject<AlertCoordinator> alertCoordinator(
+  AlertCoordinator* alertCoordinator =
       [[AlertCoordinator alloc] initWithBaseViewController:topViewController
                                                      title:kTitle
-                                                   message:nil]);
+                                                   message:nil];
 
   __block BOOL blockCalled = NO;
 
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn
index 07b878a..16959fb 100644
--- a/ipc/BUILD.gn
+++ b/ipc/BUILD.gn
@@ -98,12 +98,12 @@
   defines = [ "IPC_IMPLEMENTATION" ]
 
   public_deps = [
+    ":mojom",
     ":param_traits",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
   ]
   deps = [
-    ":mojom",
     "//base",
   ]
 
@@ -122,6 +122,9 @@
   sources = [
     "ipc.mojom",
   ]
+  export_class_attribute = "IPC_EXPORT"
+  export_define = "IPC_IMPLEMENTATION"
+  export_header = "ipc/ipc_export.h"
 }
 
 mojom("test_interfaces") {
@@ -180,7 +183,6 @@
 
     deps = [
       ":ipc",
-      ":mojom",
       ":run_all_unittests",
       ":test_interfaces",
       ":test_support",
diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h
index 1c0a89d..4a201441 100644
--- a/ipc/ipc_channel.h
+++ b/ipc/ipc_channel.h
@@ -18,6 +18,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "ipc/ipc.mojom.h"
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_message.h"
 #include "ipc/ipc_sender.h"
@@ -25,6 +26,7 @@
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "mojo/public/cpp/bindings/associated_interface_request.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
+#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
 
 #if defined(OS_POSIX)
 #include <sys/types.h>
@@ -94,6 +96,11 @@
     // with this Channel. Must be safe to call from any thread.
     virtual mojo::AssociatedGroup* GetAssociatedGroup() = 0;
 
+    // Returns a ThreadSafeForwarded for this channel which can be used to
+    // safely send mojom::Channel requests from arbitrary threads.
+    virtual std::unique_ptr<mojo::ThreadSafeForwarder<mojom::Channel>>
+    CreateThreadSafeChannel() = 0;
+
     // Adds an interface factory to this channel for interface |name|. Must be
     // safe to call from any thread.
     virtual void AddGenericAssociatedInterface(
diff --git a/ipc/ipc_channel_mojo.cc b/ipc/ipc_channel_mojo.cc
index 4189b9c0..3d5e855 100644
--- a/ipc/ipc_channel_mojo.cc
+++ b/ipc/ipc_channel_mojo.cc
@@ -274,25 +274,49 @@
     Mode mode,
     Listener* listener,
     const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner)
-    : pipe_(handle.get()), listener_(listener), weak_factory_(this) {
-  // Create MojoBootstrap after all members are set as it touches
-  // ChannelMojo from a different thread.
-  bootstrap_ =
-      MojoBootstrap::Create(std::move(handle), mode, this, ipc_task_runner);
+    : task_runner_(ipc_task_runner),
+      pipe_(handle.get()),
+      listener_(listener),
+      weak_factory_(this) {
+  bootstrap_ = MojoBootstrap::Create(std::move(handle), mode, ipc_task_runner);
+}
+
+void ChannelMojo::ForwardMessageFromThreadSafePtr(mojo::Message message) {
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  if (!message_reader_)
+    return;
+  message_reader_->sender().internal_state()->ForwardMessage(
+      std::move(message));
+}
+
+void ChannelMojo::ForwardMessageWithResponderFromThreadSafePtr(
+    mojo::Message message,
+    std::unique_ptr<mojo::MessageReceiver> responder) {
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  if (!message_reader_)
+    return;
+  message_reader_->sender().internal_state()->ForwardMessageWithResponder(
+      std::move(message), std::move(responder));
 }
 
 ChannelMojo::~ChannelMojo() {
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
   Close();
 }
 
 bool ChannelMojo::Connect() {
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
   WillConnect();
 
-  DCHECK(!task_runner_);
-  task_runner_ = base::ThreadTaskRunnerHandle::Get();
-  DCHECK(!message_reader_);
+  mojom::ChannelAssociatedPtr sender;
+  mojom::ChannelAssociatedRequest receiver;
+  bootstrap_->Connect(&sender, &receiver);
 
-  bootstrap_->Connect();
+  DCHECK(!message_reader_);
+  sender->SetPeerPid(GetSelfPID());
+  message_reader_.reset(new internal::MessagePipeReader(
+      pipe_, std::move(sender), std::move(receiver), this));
   return true;
 }
 
@@ -321,14 +345,6 @@
   associated_interfaces_.clear();
 }
 
-// MojoBootstrap::Delegate implementation
-void ChannelMojo::OnPipesAvailable(mojom::ChannelAssociatedPtr sender,
-                                   mojom::ChannelAssociatedRequest receiver) {
-  sender->SetPeerPid(GetSelfPID());
-  message_reader_.reset(new internal::MessagePipeReader(
-      pipe_, std::move(sender), std::move(receiver), this));
-}
-
 void ChannelMojo::OnPipeError() {
   DCHECK(task_runner_);
   if (task_runner_->RunsTasksOnCurrentThread()) {
@@ -377,6 +393,15 @@
 Channel::AssociatedInterfaceSupport*
 ChannelMojo::GetAssociatedInterfaceSupport() { return this; }
 
+std::unique_ptr<mojo::ThreadSafeForwarder<mojom::Channel>>
+ChannelMojo::CreateThreadSafeChannel() {
+  return base::MakeUnique<mojo::ThreadSafeForwarder<mojom::Channel>>(
+      task_runner_, base::Bind(&ChannelMojo::ForwardMessageFromThreadSafePtr,
+                               weak_factory_.GetWeakPtr()),
+      base::Bind(&ChannelMojo::ForwardMessageWithResponderFromThreadSafePtr,
+                 weak_factory_.GetWeakPtr()));
+}
+
 void ChannelMojo::OnPeerPidReceived(int32_t peer_pid) {
   listener_->OnChannelConnected(peer_pid);
 }
diff --git a/ipc/ipc_channel_mojo.h b/ipc/ipc_channel_mojo.h
index 215b198..d2d6880f 100644
--- a/ipc/ipc_channel_mojo.h
+++ b/ipc/ipc_channel_mojo.h
@@ -21,11 +21,13 @@
 #include "base/task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "ipc/ipc.mojom.h"
 #include "ipc/ipc_channel.h"
 #include "ipc/ipc_channel_factory.h"
 #include "ipc/ipc_export.h"
 #include "ipc/ipc_message_pipe_reader.h"
 #include "ipc/ipc_mojo_bootstrap.h"
+#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
 #include "mojo/public/cpp/system/core.h"
 
 namespace IPC {
@@ -42,7 +44,6 @@
 class IPC_EXPORT ChannelMojo
     : public Channel,
       public Channel::AssociatedInterfaceSupport,
-      public NON_EXPORTED_BASE(MojoBootstrap::Delegate),
       public NON_EXPORTED_BASE(internal::MessagePipeReader::Delegate) {
  public:
   // Creates a ChannelMojo.
@@ -84,10 +85,6 @@
       Message* message,
       base::Optional<std::vector<mojom::SerializedHandlePtr>>* handles);
 
-  // MojoBootstrapDelegate implementation
-  void OnPipesAvailable(mojom::ChannelAssociatedPtr sender,
-                        mojom::ChannelAssociatedRequest receiver) override;
-
   // MessagePipeReader::Delegate
   void OnPeerPidReceived(int32_t peer_pid) override;
   void OnMessageReceived(const Message& message) override;
@@ -103,8 +100,15 @@
       Listener* listener,
       const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner);
 
+  void ForwardMessageFromThreadSafePtr(mojo::Message message);
+  void ForwardMessageWithResponderFromThreadSafePtr(
+      mojo::Message message,
+      std::unique_ptr<mojo::MessageReceiver> responder);
+
   // Channel::AssociatedInterfaceSupport:
   mojo::AssociatedGroup* GetAssociatedGroup() override;
+  std::unique_ptr<mojo::ThreadSafeForwarder<mojom::Channel>>
+  CreateThreadSafeChannel() override;
   void AddGenericAssociatedInterface(
       const std::string& name,
       const GenericAssociatedInterfaceFactory& factory) override;
@@ -113,7 +117,7 @@
       mojo::ScopedInterfaceEndpointHandle handle) override;
 
   // A TaskRunner which runs tasks on the ChannelMojo's owning thread.
-  scoped_refptr<base::TaskRunner> task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   const mojo::MessagePipeHandle pipe_;
   std::unique_ptr<MojoBootstrap> bootstrap_;
diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc
index 91e8236..6759c49 100644
--- a/ipc/ipc_channel_proxy.cc
+++ b/ipc/ipc_channel_proxy.cc
@@ -68,6 +68,7 @@
       channel_->GetAssociatedInterfaceSupport();
   if (support) {
     associated_group_ = *support->GetAssociatedGroup();
+    thread_safe_channel_ = support->CreateThreadSafeChannel();
 
     base::AutoLock l(pending_filters_lock_);
     for (auto& entry : pending_io_thread_interfaces_)
@@ -398,19 +399,6 @@
                             base::Passed(base::WrapUnique(message))));
 }
 
-// Called on the IPC::Channel thread
-void ChannelProxy::Context::GetRemoteAssociatedInterface(
-    const std::string& name,
-    mojo::ScopedInterfaceEndpointHandle handle) {
-  if (!channel_)
-    return;
-  Channel::AssociatedInterfaceSupport* associated_interface_support =
-      channel_->GetAssociatedInterfaceSupport();
-  DCHECK(associated_interface_support);
-  associated_interface_support->GetGenericRemoteAssociatedInterface(
-      name, std::move(handle));
-}
-
 //-----------------------------------------------------------------------------
 
 // static
@@ -580,14 +568,14 @@
     const std::string& name,
     mojo::ScopedInterfaceEndpointHandle handle) {
   DCHECK(did_init_);
-  context_->ipc_task_runner()->PostTask(
-      FROM_HERE, base::Bind(&Context::GetRemoteAssociatedInterface,
-                            context_, name, base::Passed(&handle)));
+  mojom::GenericInterfaceAssociatedRequest request;
+  request.Bind(std::move(handle));
+  context()->thread_safe_channel().GetAssociatedInterface(name,
+                                                          std::move(request));
 }
 
 void ChannelProxy::ClearIPCTaskRunner() {
   DCHECK(CalledOnValidThread());
-
   context()->ClearIPCTaskRunner();
 }
 
diff --git a/ipc/ipc_channel_proxy.h b/ipc/ipc_channel_proxy.h
index bda83bb18..cde6a896 100644
--- a/ipc/ipc_channel_proxy.h
+++ b/ipc/ipc_channel_proxy.h
@@ -22,8 +22,10 @@
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
 #include "mojo/public/cpp/bindings/associated_group.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "mojo/public/cpp/bindings/associated_interface_request.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
+#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -209,17 +211,22 @@
   }
 #endif
 
+  // Creates a ThreadSafeAssociatedInterfacePtr for |Interface|. This object
+  // may be used to send messages on the interface from any thread and those
+  // messages will remain ordered with respect to other messages sent on the
+  // same thread over other ThreadSafeAssociatedInterfacePtrs associated with
+  // the same Channel.
   template <typename Interface>
-  using AssociatedInterfaceRetrievedCallback =
-      base::Callback<void(mojo::AssociatedInterfacePtr<Interface>)>;
-  // Creates an AssociatedInterfacePtr to |Interface| on the IO thread and
-  // passes it to |callback|, also invoked on the IO thread.
-  template <typename Interface>
-  void RetrieveAssociatedInterfaceOnIOThread(
-      const AssociatedInterfaceRetrievedCallback<Interface>& callback) {
-    context_->ipc_task_runner()->PostTask(
-        FROM_HERE, base::Bind(&Context::RetrieveAssociatedInterface<Interface>,
-                              context_, callback));
+  void GetThreadSafeRemoteAssociatedInterface(
+      scoped_refptr<mojo::ThreadSafeAssociatedInterfacePtr<Interface>>*
+          out_ptr) {
+    mojo::AssociatedInterfacePtrInfo<Interface> ptr_info;
+    mojo::AssociatedInterfaceRequest<Interface> request;
+    GetAssociatedGroup()->CreateAssociatedInterface(
+        mojo::AssociatedGroup::WILL_PASS_REQUEST, &ptr_info, &request);
+    GetGenericRemoteAssociatedInterface(Interface::Name_, request.PassHandle());
+    *out_ptr = mojo::ThreadSafeAssociatedInterfacePtr<Interface>::Create(
+        std::move(ptr_info), ipc_task_runner());
   }
 
   base::SingleThreadTaskRunner* ipc_task_runner() const {
@@ -251,11 +258,6 @@
     // Sends |message| from appropriate thread.
     void Send(Message* message);
 
-    // Requests a remote associated interface on the IPC thread.
-    void GetRemoteAssociatedInterface(
-        const std::string& name,
-        mojo::ScopedInterfaceEndpointHandle handle);
-
    protected:
     friend class base::RefCountedThreadSafe<Context>;
     ~Context() override;
@@ -299,14 +301,6 @@
     void OnSendMessage(std::unique_ptr<Message> message_ptr);
     void OnAddFilter();
     void OnRemoveFilter(MessageFilter* filter);
-    template <typename Interface>
-    void RetrieveAssociatedInterface(
-        const AssociatedInterfaceRetrievedCallback<Interface>& callback) {
-      mojo::AssociatedInterfacePtr<Interface> interface_ptr;
-      channel_->GetAssociatedInterfaceSupport()->GetRemoteAssociatedInterface(
-          &interface_ptr);
-      callback.Run(std::move(interface_ptr));
-    }
 
     // Methods called on the listener thread.
     void AddFilter(MessageFilter* filter);
@@ -320,6 +314,9 @@
     void ClearChannel();
 
     mojo::AssociatedGroup* associated_group() { return &associated_group_; }
+    mojom::Channel& thread_safe_channel() {
+      return thread_safe_channel_->proxy();
+    }
 
     void AddGenericAssociatedInterfaceForIOThread(
         const std::string& name,
@@ -360,6 +357,11 @@
 
     mojo::AssociatedGroup associated_group_;
 
+    // A thread-safe mojom::Channel interface we use to make remote interface
+    // requests from the proxy thread.
+    std::unique_ptr<mojo::ThreadSafeForwarder<mojom::Channel>>
+        thread_safe_channel_;
+
     // Holds associated interface binders added by
     // AddGenericAssociatedInterfaceForIOThread until the underlying channel has
     // been initialized.
diff --git a/ipc/ipc_message_pipe_reader.h b/ipc/ipc_message_pipe_reader.h
index 686982a9..b441960 100644
--- a/ipc/ipc_message_pipe_reader.h
+++ b/ipc/ipc_message_pipe_reader.h
@@ -84,7 +84,7 @@
   void GetRemoteInterface(const std::string& name,
                           mojo::ScopedInterfaceEndpointHandle handle);
 
-  mojom::Channel* sender() const { return sender_.get(); }
+  mojom::ChannelAssociatedPtr& sender() { return sender_; }
 
  protected:
   void OnPipeClosed();
diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc
index 68454ae..5e6f5459a 100644
--- a/ipc/ipc_mojo_bootstrap.cc
+++ b/ipc/ipc_mojo_bootstrap.cc
@@ -885,11 +885,8 @@
  public:
   MojoBootstrapImpl(
       mojo::ScopedMessagePipeHandle handle,
-      Delegate* delegate,
       const scoped_refptr<ChannelAssociatedGroupController> controller)
-            : controller_(controller),
-        handle_(std::move(handle)),
-        delegate_(delegate) {
+      : controller_(controller), handle_(std::move(handle)) {
     associated_group_ = controller_->CreateAssociatedGroup();
   }
 
@@ -898,15 +895,10 @@
   }
 
  private:
-  // MojoBootstrap:
-  void Connect() override {
+  void Connect(mojom::ChannelAssociatedPtr* sender,
+               mojom::ChannelAssociatedRequest* receiver) override {
     controller_->Bind(std::move(handle_));
-
-    IPC::mojom::ChannelAssociatedPtr sender;
-    IPC::mojom::ChannelAssociatedRequest receiver;
-    controller_->CreateChannelEndpoints(&sender, &receiver);
-
-    delegate_->OnPipesAvailable(std::move(sender), std::move(receiver));
+    controller_->CreateChannelEndpoints(sender, receiver);
   }
 
   void Pause() override {
@@ -928,7 +920,6 @@
   scoped_refptr<ChannelAssociatedGroupController> controller_;
 
   mojo::ScopedMessagePipeHandle handle_;
-  Delegate* delegate_;
   std::unique_ptr<mojo::AssociatedGroup> associated_group_;
 
   DISALLOW_COPY_AND_ASSIGN(MojoBootstrapImpl);
@@ -940,12 +931,10 @@
 std::unique_ptr<MojoBootstrap> MojoBootstrap::Create(
     mojo::ScopedMessagePipeHandle handle,
     Channel::Mode mode,
-    Delegate* delegate,
     const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
   return base::MakeUnique<MojoBootstrapImpl>(
-      std::move(handle), delegate,
-      new ChannelAssociatedGroupController(mode == Channel::MODE_SERVER,
-                                           ipc_task_runner));
+      std::move(handle), new ChannelAssociatedGroupController(
+                             mode == Channel::MODE_SERVER, ipc_task_runner));
 }
 
 }  // namespace IPC
diff --git a/ipc/ipc_mojo_bootstrap.h b/ipc/ipc_mojo_bootstrap.h
index 5188cd0..cb4bcdc 100644
--- a/ipc/ipc_mojo_bootstrap.h
+++ b/ipc/ipc_mojo_bootstrap.h
@@ -31,14 +31,6 @@
 // UI thread as Channel::Create() can be.
 class IPC_EXPORT MojoBootstrap {
  public:
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-
-    virtual void OnPipesAvailable(mojom::ChannelAssociatedPtr sender,
-                                  mojom::ChannelAssociatedRequest receiver) = 0;
-  };
-
   virtual ~MojoBootstrap() {}
 
   // Create the MojoBootstrap instance, using |handle| as the message pipe, in
@@ -46,11 +38,11 @@
   static std::unique_ptr<MojoBootstrap> Create(
       mojo::ScopedMessagePipeHandle handle,
       Channel::Mode mode,
-      Delegate* delegate,
       const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner);
 
   // Start the handshake over the underlying message pipe.
-  virtual void Connect() = 0;
+  virtual void Connect(mojom::ChannelAssociatedPtr* sender,
+                       mojom::ChannelAssociatedRequest* receiver) = 0;
 
   // Stop transmitting messages and start queueing them instead.
   virtual void Pause() = 0;
diff --git a/ipc/ipc_mojo_bootstrap_unittest.cc b/ipc/ipc_mojo_bootstrap_unittest.cc
index b036faca..c6cde3e 100644
--- a/ipc/ipc_mojo_bootstrap_unittest.cc
+++ b/ipc/ipc_mojo_bootstrap_unittest.cc
@@ -18,6 +18,7 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/test/mojo_test_base.h"
 #include "mojo/edk/test/multiprocess_test_helper.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 
 #if defined(OS_POSIX)
 #include "base/file_descriptor_posix.h"
@@ -25,47 +26,62 @@
 
 namespace {
 
+constexpr int32_t kTestServerPid = 42;
+constexpr int32_t kTestClientPid = 4242;
+
+class PeerPidReceiver : public IPC::mojom::Channel {
+ public:
+  PeerPidReceiver(IPC::mojom::ChannelAssociatedRequest request,
+                  const base::Closure& on_peer_pid_set)
+      : binding_(this, std::move(request)), on_peer_pid_set_(on_peer_pid_set) {}
+  ~PeerPidReceiver() override {}
+
+  // mojom::Channel:
+  void SetPeerPid(int32_t pid) override {
+    peer_pid_ = pid;
+    on_peer_pid_set_.Run();
+  }
+
+  void Receive(const std::vector<uint8_t>& data,
+               base::Optional<std::vector<IPC::mojom::SerializedHandlePtr>>
+                   handles) override {}
+
+  void GetAssociatedInterface(
+      const std::string& name,
+      IPC::mojom::GenericInterfaceAssociatedRequest request) override {}
+
+  int32_t peer_pid() const { return peer_pid_; }
+
+ private:
+  mojo::AssociatedBinding<IPC::mojom::Channel> binding_;
+  const base::Closure on_peer_pid_set_;
+  int32_t peer_pid_ = -1;
+
+  DISALLOW_COPY_AND_ASSIGN(PeerPidReceiver);
+};
+
 class IPCMojoBootstrapTest : public testing::Test {
  protected:
   mojo::edk::test::MultiprocessTestHelper helper_;
 };
 
-class TestingDelegate : public IPC::MojoBootstrap::Delegate {
- public:
-  explicit TestingDelegate(const base::Closure& quit_callback)
-      : passed_(false), quit_callback_(quit_callback) {}
-
-  void OnPipesAvailable(
-      IPC::mojom::ChannelAssociatedPtr sender,
-      IPC::mojom::ChannelAssociatedRequest receiver) override;
-
-  bool passed() const { return passed_; }
-
- private:
-  bool passed_;
-  const base::Closure quit_callback_;
-};
-
-void TestingDelegate::OnPipesAvailable(
-    IPC::mojom::ChannelAssociatedPtr sender,
-    IPC::mojom::ChannelAssociatedRequest receiver) {
-  passed_ = true;
-  quit_callback_.Run();
-}
-
 TEST_F(IPCMojoBootstrapTest, Connect) {
   base::MessageLoop message_loop;
-  base::RunLoop run_loop;
-  TestingDelegate delegate(run_loop.QuitClosure());
   std::unique_ptr<IPC::MojoBootstrap> bootstrap = IPC::MojoBootstrap::Create(
       helper_.StartChild("IPCMojoBootstrapTestClient"),
-      IPC::Channel::MODE_SERVER, &delegate,
-      base::ThreadTaskRunnerHandle::Get());
+      IPC::Channel::MODE_SERVER, base::ThreadTaskRunnerHandle::Get());
 
-  bootstrap->Connect();
+  IPC::mojom::ChannelAssociatedPtr sender;
+  IPC::mojom::ChannelAssociatedRequest receiver;
+  bootstrap->Connect(&sender, &receiver);
+  sender->SetPeerPid(kTestServerPid);
+
+  base::RunLoop run_loop;
+  PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
   run_loop.Run();
 
-  EXPECT_TRUE(delegate.passed());
+  EXPECT_EQ(kTestClientPid, impl.peer_pid());
+
   EXPECT_TRUE(helper_.WaitForChildTestShutdown());
 }
 
@@ -74,18 +90,22 @@
     IPCMojoBootstrapTestClientTestChildMain,
     ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) {
   base::MessageLoop message_loop;
-  base::RunLoop run_loop;
-  TestingDelegate delegate(run_loop.QuitClosure());
   std::unique_ptr<IPC::MojoBootstrap> bootstrap = IPC::MojoBootstrap::Create(
       std::move(mojo::edk::test::MultiprocessTestHelper::primordial_pipe),
-      IPC::Channel::MODE_CLIENT, &delegate,
-      base::ThreadTaskRunnerHandle::Get());
+      IPC::Channel::MODE_CLIENT, base::ThreadTaskRunnerHandle::Get());
 
-  bootstrap->Connect();
+  IPC::mojom::ChannelAssociatedPtr sender;
+  IPC::mojom::ChannelAssociatedRequest receiver;
+  bootstrap->Connect(&sender, &receiver);
+  sender->SetPeerPid(kTestClientPid);
 
+  base::RunLoop run_loop;
+  PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
   run_loop.Run();
 
-  return delegate.passed() ? 0 : 1;
+  EXPECT_EQ(kTestServerPid, impl.peer_pid());
+
+  return 0;
 }
 
 }  // namespace
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr.h b/mojo/public/cpp/bindings/associated_interface_ptr.h
index 42cb9dc6..f44da8f 100644
--- a/mojo/public/cpp/bindings/associated_interface_ptr.h
+++ b/mojo/public/cpp/bindings/associated_interface_ptr.h
@@ -31,6 +31,9 @@
 template <typename Interface>
 class AssociatedInterfacePtr {
  public:
+  using InterfaceType = Interface;
+  using PtrInfoType = AssociatedInterfacePtrInfo<Interface>;
+
   // Constructs an unbound AssociatedInterfacePtr.
   AssociatedInterfacePtr() {}
   AssociatedInterfacePtr(decltype(nullptr)) {}
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h
index 4db5e674..9d9a5a5 100644
--- a/mojo/public/cpp/bindings/interface_ptr.h
+++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -40,6 +40,9 @@
 template <typename Interface>
 class InterfacePtr {
  public:
+  using InterfaceType = Interface;
+  using PtrInfoType = InterfacePtrInfo<Interface>;
+
   // Constructs an unbound InterfacePtr.
   InterfacePtr() {}
   InterfacePtr(decltype(nullptr)) {}
diff --git a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
index 12482d1..56c1e87 100644
--- a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
@@ -1055,50 +1055,53 @@
 struct ForwarderTestContext {
   IntegerSenderConnectionPtr connection_ptr;
   std::unique_ptr<IntegerSenderConnectionImpl> interface_impl;
+  IntegerSenderAssociatedRequest sender_request;
 };
 
-TEST_F(AssociatedInterfaceTest, BindLaterThreadSafeAssociatedInterfacePtr) {
+TEST_F(AssociatedInterfaceTest,
+       ThreadSafeAssociatedInterfacePtrWithTaskRunner) {
   // Start the thread from where we'll bind the interface pointer.
   base::Thread other_thread("service test thread");
   other_thread.Start();
   const scoped_refptr<base::SingleThreadTaskRunner>& other_thread_task_runner =
       other_thread.message_loop()->task_runner();
-  ForwarderTestContext* context = new ForwarderTestContext();
 
-  base::WaitableEvent echo_called_event(
+  ForwarderTestContext* context = new ForwarderTestContext();
+  IntegerSenderAssociatedPtrInfo sender_info;
+  base::WaitableEvent sender_info_bound_event(
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
+  auto setup = [](base::WaitableEvent* sender_info_bound_event,
+                  IntegerSenderAssociatedPtrInfo* sender_info,
+                  ForwarderTestContext* context) {
+    context->interface_impl = base::MakeUnique<IntegerSenderConnectionImpl>(
+        MakeRequest(&context->connection_ptr));
 
-  // Create a ThreadSafeAssociatedPtr that we'll bind from a different thread.
+    IntegerSenderAssociatedPtr sender;
+    IntegerSenderAssociatedRequest sender_request =
+        MakeRequest(&sender, context->connection_ptr.associated_group());
+    *sender_info = sender.PassInterface();
+
+    context->connection_ptr->GetSender(std::move(sender_request));
+
+    // Unblock the main thread as soon as |sender_info| is set.
+    sender_info_bound_event->Signal();
+  };
+  other_thread_task_runner->PostTask(
+      FROM_HERE,
+      base::Bind(setup, &sender_info_bound_event, &sender_info, context));
+  sender_info_bound_event.Wait();
+
+  // Create a ThreadSafeAssociatedPtr that binds on the background thread and is
+  // associated with |connection_ptr| there.
   scoped_refptr<ThreadSafeIntegerSenderAssociatedPtr> thread_safe_ptr =
-      ThreadSafeIntegerSenderAssociatedPtr::CreateUnbound(
-          other_thread_task_runner);
+      ThreadSafeIntegerSenderAssociatedPtr::Create(std::move(sender_info),
+                                                   other_thread_task_runner);
 
-  base::RunLoop bind_run_loop;
-  auto run_method = base::Bind(
-      [](base::WaitableEvent* echo_called_event,
-         const scoped_refptr<ThreadSafeIntegerSenderAssociatedPtr>&
-             thread_safe_ptr,
-          ForwarderTestContext* context) {
-        // Wait for echo to be called on the main thread so the interface method
-        // call happens before the bind.
-        echo_called_event->Wait();
-
-        // We are on the background thread, create the interface ptr.
-        context->interface_impl =
-            base::MakeUnique<IntegerSenderConnectionImpl>(
-                MakeRequest(&(context->connection_ptr)));
-        IntegerSenderAssociatedPtr sender;
-        context->connection_ptr->GetSender(
-            MakeRequest(&sender, context->connection_ptr.associated_group()));
-        thread_safe_ptr->Bind(std::move(sender));
-      },
-      &echo_called_event, thread_safe_ptr, context);
-
-  other_thread_task_runner->PostTask(FROM_HERE, run_method);
-
+  // Issue a call on the thread-safe ptr immediately. Note that this may happen
+  // before the interface is bound on the background thread, and that must be
+  // OK.
   {
-    // Now we can call methods on the interface from the main thread.
     auto echo_callback =
         base::Bind([](const base::Closure& quit_closure, int32_t result) {
           EXPECT_EQ(123, result);
@@ -1108,9 +1111,6 @@
     (*thread_safe_ptr)
         ->Echo(123, base::Bind(echo_callback, run_loop.QuitClosure()));
 
-    // Let the bind happen on the background thread.
-    echo_called_event.Signal();
-
     // Block until the method callback is called.
     run_loop.Run();
   }
diff --git a/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
index 4849c61..fb602f5 100644
--- a/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
@@ -853,16 +853,20 @@
   run_loop.Run();
 }
 
-TEST_F(InterfacePtrTest, BindLaterThreadSafeInterfacePointer) {
+TEST_F(InterfacePtrTest, ThreadSafeInterfacePointerWithTaskRunner) {
   // Create and start the thread from where we'll bind the interface pointer.
   base::Thread other_thread("service test thread");
   other_thread.Start();
   const scoped_refptr<base::SingleThreadTaskRunner>& other_thread_task_runner =
       other_thread.message_loop()->task_runner();
 
+  math::CalculatorPtr ptr;
+  math::CalculatorRequest request(&ptr);
+
   // Create a ThreadSafeInterfacePtr that we'll bind from a different thread.
   scoped_refptr<math::ThreadSafeCalculatorPtr> thread_safe_ptr =
-      math::ThreadSafeCalculatorPtr::CreateUnbound(other_thread_task_runner);
+      math::ThreadSafeCalculatorPtr::Create(ptr.PassInterface(),
+                                            other_thread_task_runner);
   ASSERT_TRUE(thread_safe_ptr);
 
   MathCalculatorImpl* math_calc_impl = nullptr;
@@ -872,15 +876,15 @@
         [](const scoped_refptr<base::TaskRunner>& main_task_runner,
            const base::Closure& quit_closure,
            const scoped_refptr<math::ThreadSafeCalculatorPtr>& thread_safe_ptr,
+           math::CalculatorRequest request,
            MathCalculatorImpl** math_calc_impl) {
           math::CalculatorPtr ptr;
           // In real life, the implementation would have a legitimate owner.
-          *math_calc_impl = new MathCalculatorImpl(MakeRequest(&ptr));
-          thread_safe_ptr->Bind(std::move(ptr));
+          *math_calc_impl = new MathCalculatorImpl(std::move(request));
           main_task_runner->PostTask(FROM_HERE, quit_closure);
         },
         base::SequencedTaskRunnerHandle::Get(), run_loop.QuitClosure(),
-        thread_safe_ptr, &math_calc_impl);
+        thread_safe_ptr, base::Passed(&request), &math_calc_impl);
     other_thread.message_loop()->task_runner()->PostTask(FROM_HERE, run_method);
     run_loop.Run();
   }
diff --git a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
index 605bddda1..f475c1f 100644
--- a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
+++ b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
@@ -18,134 +18,55 @@
 
 namespace mojo {
 
-struct ThreadSafeInterfacePtrDeleter;
-
-// ThreadSafeInterfacePtr and ThreadSafeAssociatedInterfacePtr are versions of
-// InterfacePtr and AssociatedInterfacePtr that let callers invoke
-// interface methods from any threads. Callbacks are received on the thread that
-// performed the interface call.
-//
-// To create a ThreadSafeInterfacePtr/ThreadSafeAssociatedInterfacePtr, first
-// create a regular InterfacePtr/AssociatedInterfacePtr that
-// you then provide to ThreadSafeInterfacePtr/AssociatedInterfacePtr::Create.
-// You can then call methods on the
-// ThreadSafeInterfacePtr/AssociatedInterfacePtr instance from any thread.
-//
-// Ex for ThreadSafeInterfacePtr:
-// frob::FrobinatorPtr frobinator;
-// frob::FrobinatorImpl impl(MakeRequest(&frobinator));
-// scoped_refptr<frob::ThreadSafeFrobinatorPtr> thread_safe_frobinator =
-//     frob::ThreadSafeFrobinatorPtr::Create(std::move(frobinator));
-// (*thread_safe_frobinator)->FrobinateToTheMax();
-//
-// An alternate way is to create the ThreadSafeInterfacePtr unbound (not
-// associated with an InterfacePtr) and call Bind() at a later time when the
-// InterfacePtr becomes available. Note that you shouldn't call any interface
-// methods on the ThreadSafeInterfacePtr before it is bound.
-
-template <typename Interface, template <typename> class InterfacePtrType>
-class ThreadSafeInterfacePtrBase
-    : public MessageReceiverWithResponder,
-      public base::RefCountedThreadSafe<
-          ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>,
-          ThreadSafeInterfacePtrDeleter> {
+// Instances of this class may be used from any thread to serialize |Interface|
+// messages and forward them elsewhere. In general you should use one of the
+// ThreadSafeInterfacePtrBase helper aliases defined below, but this type may be
+// useful if you need/want to manually manage the lifetime of the underlying
+// proxy object which will be used to ultimately send messages.
+template <typename Interface>
+class ThreadSafeForwarder : public MessageReceiverWithResponder {
  public:
   using ProxyType = typename Interface::Proxy_;
+  using ForwardMessageCallback = base::Callback<void(Message)>;
+  using ForwardMessageWithResponderCallback =
+      base::Callback<void(Message, std::unique_ptr<MessageReceiver>)>;
 
-  static scoped_refptr<ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>>
-  Create(InterfacePtrType<Interface> interface_ptr) {
-    scoped_refptr<ThreadSafeInterfacePtrBase> ptr(
-        new ThreadSafeInterfacePtrBase());
-    return ptr->Bind(std::move(interface_ptr)) ? ptr : nullptr;
-  }
+  // Constructs a ThreadSafeForwarder through which Messages are forwarded to
+  // |forward| or |forward_with_responder| by posting to |task_runner|.
+  //
+  // Any message sent through this forwarding interface will dispatch its reply,
+  // if any, back to the thread which called the corresponding interface method.
+  ThreadSafeForwarder(
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+      const ForwardMessageCallback& forward,
+      const ForwardMessageWithResponderCallback& forward_with_responder)
+      : proxy_(this),
+        task_runner_(task_runner),
+        forward_(forward),
+        forward_with_responder_(forward_with_responder) {}
 
-  // Creates a ThreadSafeInterfacePtrBase with no associated InterfacePtr.
-  // Call Bind() with the InterfacePtr once available, which must be called on
-  // the |bind_task_runner|.
-  // Providing the TaskRunner here allows you to post a task to
-  // |bind_task_runner| to do the bind and then immediately start calling
-  // methods on the returned interface.
-  static scoped_refptr<ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>>
-  CreateUnbound(
-      const scoped_refptr<base::SingleThreadTaskRunner>& bind_task_runner) {
-    scoped_refptr<ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>> ptr =
-        new ThreadSafeInterfacePtrBase();
-    ptr->interface_ptr_task_runner_ = bind_task_runner;
-    return ptr;
-  }
+  ~ThreadSafeForwarder() override {}
 
-  // Binds a ThreadSafeInterfacePtrBase previously created with CreateUnbound().
-  // This must be called on the thread that |interface_ptr| should be used.
-  // If created with CreateUnbound() that thread should be the same as the one
-  // provided at creation time.
-  bool Bind(InterfacePtrType<Interface> interface_ptr) {
-    DCHECK(!interface_ptr_task_runner_ ||
-        interface_ptr_task_runner_ == base::ThreadTaskRunnerHandle::Get());
-    if (!interface_ptr.is_bound()) {
-      LOG(ERROR) << "Attempting to bind a ThreadSafe[Associated]InterfacePtr "
-                    "from an unbound InterfacePtr.";
-      return false;
-    }
-    interface_ptr_ = std::move(interface_ptr);
-    interface_ptr_task_runner_ = base::ThreadTaskRunnerHandle::Get();
-    return true;
-  }
-
-  ~ThreadSafeInterfacePtrBase() override {}
-
-  Interface* get() { return &proxy_; }
-  Interface* operator->() { return get(); }
-  Interface& operator*() { return *get(); }
+  ProxyType& proxy() { return proxy_; }
 
  private:
-  friend class base::RefCountedThreadSafe<
-      ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>>;
-  friend struct ThreadSafeInterfacePtrDeleter;
-
-  ThreadSafeInterfacePtrBase() : proxy_(this), weak_ptr_factory_(this) {}
-
-  void DeleteOnCorrectThread() const {
-    if (interface_ptr_task_runner_ &&
-        !interface_ptr_task_runner_->BelongsToCurrentThread() &&
-        interface_ptr_task_runner_->DeleteSoon(FROM_HERE, this)) {
-      return;
-    }
-    delete this;
-  }
-
   // MessageReceiverWithResponder implementation:
   bool Accept(Message* message) override {
-    interface_ptr_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&ThreadSafeInterfacePtrBase::AcceptOnInterfacePtrThread,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   base::Passed(std::move(*message))));
+    task_runner_->PostTask(FROM_HERE,
+                           base::Bind(forward_, base::Passed(message)));
     return true;
   }
 
   bool AcceptWithResponder(Message* message,
-                           MessageReceiver* responder) override {
-    auto forward_responder = base::MakeUnique<ForwardToCallingThread>(
-        base::WrapUnique(responder));
-    interface_ptr_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ThreadSafeInterfacePtrBase::
-                                  AcceptWithResponderOnInterfacePtrThread,
-                              weak_ptr_factory_.GetWeakPtr(),
-                              base::Passed(std::move(*message)),
-                              base::Passed(std::move(forward_responder))));
+                           MessageReceiver* response_receiver) override {
+    auto responder = base::MakeUnique<ForwardToCallingThread>(
+        base::WrapUnique(response_receiver));
+    task_runner_->PostTask(
+        FROM_HERE, base::Bind(forward_with_responder_, base::Passed(message),
+                              base::Passed(&responder)));
     return true;
   }
 
-  void AcceptOnInterfacePtrThread(Message message) {
-    interface_ptr_.internal_state()->ForwardMessage(std::move(message));
-  }
-  void AcceptWithResponderOnInterfacePtrThread(
-      Message message,
-      std::unique_ptr<MessageReceiver> responder) {
-    interface_ptr_.internal_state()->ForwardMessageWithResponder(
-        std::move(message), std::move(responder));
-  }
-
   class ForwardToCallingThread : public MessageReceiver {
    public:
     explicit ForwardToCallingThread(std::unique_ptr<MessageReceiver> responder)
@@ -175,28 +96,143 @@
     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
   };
 
-  scoped_refptr<base::SingleThreadTaskRunner> interface_ptr_task_runner_;
   ProxyType proxy_;
-  InterfacePtrType<Interface> interface_ptr_;
-  base::WeakPtrFactory<ThreadSafeInterfacePtrBase> weak_ptr_factory_;
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  const ForwardMessageCallback forward_;
+  const ForwardMessageWithResponderCallback forward_with_responder_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadSafeForwarder);
 };
 
-struct ThreadSafeInterfacePtrDeleter {
-  template <typename Interface, template <typename> class InterfacePtrType>
-  static void Destruct(
-      const ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>*
-          interface_ptr) {
-    interface_ptr->DeleteOnCorrectThread();
+template <typename InterfacePtrType>
+class ThreadSafeInterfacePtrBase
+    : public base::RefCountedThreadSafe<
+          ThreadSafeInterfacePtrBase<InterfacePtrType>> {
+ public:
+  using InterfaceType = typename InterfacePtrType::InterfaceType;
+  using PtrInfoType = typename InterfacePtrType::PtrInfoType;
+
+  explicit ThreadSafeInterfacePtrBase(
+      std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder)
+      : forwarder_(std::move(forwarder)) {}
+
+  // Creates a ThreadSafeInterfacePtrBase wrapping an underlying non-thread-safe
+  // InterfacePtrType which is bound to the calling thread. All messages sent
+  // via this thread-safe proxy will internally be sent by first posting to this
+  // (the calling) thread's TaskRunner.
+  static scoped_refptr<ThreadSafeInterfacePtrBase> Create(
+      InterfacePtrType interface_ptr) {
+    scoped_refptr<PtrWrapper> wrapper =
+        new PtrWrapper(std::move(interface_ptr));
+    return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder());
   }
+
+  // Creates a ThreadSafeInterfacePtrBase which binds the underlying
+  // non-thread-safe InterfacePtrType on the specified TaskRunner. All messages
+  // sent via this thread-safe proxy will internally be sent by first posting to
+  // that TaskRunner.
+  static scoped_refptr<ThreadSafeInterfacePtrBase> Create(
+      PtrInfoType ptr_info,
+      const scoped_refptr<base::SingleThreadTaskRunner>& bind_task_runner) {
+    scoped_refptr<PtrWrapper> wrapper = new PtrWrapper(bind_task_runner);
+    wrapper->BindOnTaskRunner(std::move(ptr_info));
+    return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder());
+  }
+
+  InterfaceType* get() { return &forwarder_->proxy(); }
+  InterfaceType* operator->() { return get(); }
+  InterfaceType& operator*() { return *get(); }
+
+ private:
+  friend class base::RefCountedThreadSafe<
+      ThreadSafeInterfacePtrBase<InterfacePtrType>>;
+
+  struct PtrWrapperDeleter;
+
+  // Helper class which owns an |InterfacePtrType| instance on an appropriate
+  // thread. This is kept alive as long its bound within some
+  // ThreadSafeForwarder's callbacks.
+  class PtrWrapper
+      : public base::RefCountedThreadSafe<PtrWrapper, PtrWrapperDeleter> {
+   public:
+    explicit PtrWrapper(InterfacePtrType ptr)
+        : PtrWrapper(base::ThreadTaskRunnerHandle::Get()) {
+      ptr_ = std::move(ptr);
+    }
+
+    explicit PtrWrapper(
+        const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+        : task_runner_(task_runner) {}
+
+    void BindOnTaskRunner(PtrInfoType ptr_info) {
+      task_runner_->PostTask(FROM_HERE, base::Bind(&PtrWrapper::Bind, this,
+                                                   base::Passed(&ptr_info)));
+    }
+
+    std::unique_ptr<ThreadSafeForwarder<InterfaceType>> CreateForwarder() {
+      return base::MakeUnique<ThreadSafeForwarder<InterfaceType>>(
+          task_runner_, base::Bind(&PtrWrapper::Accept, this),
+          base::Bind(&PtrWrapper::AcceptWithResponder, this));
+    }
+
+   private:
+    friend struct PtrWrapperDeleter;
+
+    ~PtrWrapper() {}
+
+    void Bind(PtrInfoType ptr_info) {
+      DCHECK(task_runner_->RunsTasksOnCurrentThread());
+      ptr_.Bind(std::move(ptr_info));
+    }
+
+    void Accept(Message message) {
+      ptr_.internal_state()->ForwardMessage(std::move(message));
+    }
+
+    void AcceptWithResponder(Message message,
+                             std::unique_ptr<MessageReceiver> responder) {
+      ptr_.internal_state()->ForwardMessageWithResponder(std::move(message),
+                                                         std::move(responder));
+    }
+
+    void DeleteOnCorrectThread() const {
+      if (!task_runner_->RunsTasksOnCurrentThread()) {
+        // NOTE: This is only called when there are no more references to
+        // |this|, so binding it unretained is both safe and necessary.
+        task_runner_->PostTask(FROM_HERE,
+                               base::Bind(&PtrWrapper::DeleteOnCorrectThread,
+                                          base::Unretained(this)));
+      } else {
+        delete this;
+      }
+    }
+
+    InterfacePtrType ptr_;
+    const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+    DISALLOW_COPY_AND_ASSIGN(PtrWrapper);
+  };
+
+  struct PtrWrapperDeleter {
+    static void Destruct(const PtrWrapper* interface_ptr) {
+      interface_ptr->DeleteOnCorrectThread();
+    }
+  };
+
+  ~ThreadSafeInterfacePtrBase() {}
+
+  const std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadSafeInterfacePtrBase);
 };
 
 template <typename Interface>
 using ThreadSafeAssociatedInterfacePtr =
-    ThreadSafeInterfacePtrBase<Interface, AssociatedInterfacePtr>;
+    ThreadSafeInterfacePtrBase<AssociatedInterfacePtr<Interface>>;
 
 template <typename Interface>
 using ThreadSafeInterfacePtr =
-    ThreadSafeInterfacePtrBase<Interface, InterfacePtr>;
+    ThreadSafeInterfacePtrBase<InterfacePtr<Interface>>;
 
 }  // namespace mojo
 
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index db787d6..95457d7d 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -725,6 +725,7 @@
       "//base",
       "//base:i18n",
       "//components/policy/core/common",
+      "//ipc",
       "//net",
       "//remoting/base",
       "//remoting/host",
diff --git a/remoting/host/security_key/BUILD.gn b/remoting/host/security_key/BUILD.gn
index ff462ab..422dd84 100644
--- a/remoting/host/security_key/BUILD.gn
+++ b/remoting/host/security_key/BUILD.gn
@@ -36,6 +36,7 @@
   ]
 
   deps = [
+    "//ipc",
     "//mojo/edk/system",
     "//remoting/proto",
     "//third_party/webrtc/modules/desktop_capture",
@@ -112,6 +113,7 @@
   ]
 
   deps = [
+    "//ipc",
     "//remoting/proto",
     "//testing/gtest",
   ]
diff --git a/remoting/host/win/BUILD.gn b/remoting/host/win/BUILD.gn
index 3248a04..4d864c65 100644
--- a/remoting/host/win/BUILD.gn
+++ b/remoting/host/win/BUILD.gn
@@ -152,6 +152,7 @@
   ]
 
   deps = [
+    "//ipc",
     "//remoting/host",
     "//remoting/host:test_support",
     "//remoting/host/it2me:common",
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index f006541..5391046 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -942,18 +942,6 @@
             ]
         }
     ],
-    "IconNTP": [
-        {
-            "platforms": [
-                "win"
-            ],
-            "experiments": [
-                {
-                    "name": "Default"
-                }
-            ]
-        }
-    ],
     "ImportantSitesInCBD": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations
index d18c531c..4a3a9cb 100644
--- a/third_party/WebKit/LayoutTests/W3CImportExpectations
+++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -285,7 +285,8 @@
 ## Owners: phoglund@chromium.org
 # external/wpt/mediacapture-streams [ Pass ]
 external/wpt/microdata [ Skip ]
-external/wpt/mixed-content [ Skip ]
+## Owners: mkwst@chromium.org
+# external/wpt/mixed-content [ Pass ]
 ## Owners: sunjian@chromium.org,panicker@chromium.org
 external/wpt/navigation-timing [ Pass ]
 external/wpt/notifications [ Skip ]
@@ -303,11 +304,10 @@
 external/wpt/proximity [ Skip ]
 ## Owners: rob.buis@samsung.com
 # external/wpt/quirks-mode [ Skip ]
-## Owners: mkwst@chromium.org
-# http://crbug.com/360762: Requires HTTPS server with python.
-external/wpt/referrer-policy [ Skip ]
 ## Owners: avayvod@chromium.org,mlamouri@chromium.org
 # external/wpt/remote-playback [ Pass ]
+## Owners: jochen@chromium.org,estark@chromium.org
+# external/wpt/referrer-policy [ Pass ]
 external/wpt/resource-timing [ Skip ]
 ## Owners: jsbell@chromium.org
 # external/wpt/resources [ Pass ]
@@ -332,8 +332,8 @@
 # external/wpt/shadow-dom [ Pass ]
 ## Owners: domenic@chromium.org,ricea@chromium.org,tyoshino@chromium.org
 external/wpt/streams [ Pass ]
-## Owners: jww@chromium.org
-external/wpt/subresource-integrity [ Skip ]
+## Owners: mkwst@chromium.org,jochen@chromium.org
+# external/wpt/subresource-integrity [ Pass ]
 ## Owners: foolip@chromium.org
 # external/wpt/svg [ Pass ]
 external/wpt/svg/import [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/relayout-nested-float-after-line.html b/third_party/WebKit/LayoutTests/fast/block/float/relayout-nested-float-after-line.html
new file mode 100644
index 0000000..396d127
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/relayout-nested-float-after-line.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<p>The word "BONZER" should be adjacent to the hotpink square.</p>
+<div style="position:relative; overflow:hidden;">
+    &nbsp;
+    <div style="float:left; width:100%; height:1px;"></div>
+    <div style="float:left; width:100%;">
+        <div id="innerFloat" style="float:left; width:666px; height:20px; background:hotpink;"></div>
+        <span id="targetSpan">BONZER<br></span>
+    </div>
+</div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+test(() => {
+    document.body.offsetTop;
+    innerFloat.style.width = "20px";
+    assert_equals(targetSpan.offsetLeft, 20);
+}, "Resize inner float next to line");
+</script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
index 051c4551..2108dc9 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
@@ -801,13 +801,6 @@
       isolate(), transferables->offscreenCanvases, exceptionState);
 }
 
-// static
-String ScriptValueSerializer::serializeWTFString(const String& data) {
-  SerializedScriptValueWriter valueWriter;
-  valueWriter.writeWebCoreString(data);
-  return valueWriter.takeWireString();
-}
-
 ScriptValueSerializer::StateBase* ScriptValueSerializer::doSerialize(
     v8::Local<v8::Value> value,
     StateBase* next) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.h b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.h
index 7e8a59fa..03ca5c5 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.h
@@ -233,8 +233,6 @@
                                               Transferables*,
                                               ExceptionState&);
 
-  static String serializeWTFString(const String&);
-
  protected:
   class StateBase {
     USING_FAST_MALLOC(StateBase);
diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
index a9edce8..986d3f3c 100644
--- a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
@@ -70,11 +70,6 @@
       isolate, value, transferables, blobInfo, exception);
 }
 
-PassRefPtr<SerializedScriptValue> SerializedScriptValue::serialize(
-    const String& str) {
-  return create(ScriptValueSerializer::serializeWTFString(str));
-}
-
 PassRefPtr<SerializedScriptValue>
 SerializedScriptValue::serializeAndSwallowExceptions(
     v8::Isolate* isolate,
diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.h b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.h
index 85f0f0dd..7799d5bd 100644
--- a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.h
+++ b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.h
@@ -79,7 +79,6 @@
                                                      Transferables*,
                                                      WebBlobInfoArray*,
                                                      ExceptionState&);
-  static PassRefPtr<SerializedScriptValue> serialize(const String&);
   static PassRefPtr<SerializedScriptValue> serializeAndSwallowExceptions(
       v8::Isolate*,
       v8::Local<v8::Value>);
diff --git a/third_party/WebKit/Source/build/scripts/json5_generator.py b/third_party/WebKit/Source/build/scripts/json5_generator.py
index 5b7184b..4c7a63d 100644
--- a/third_party/WebKit/Source/build/scripts/json5_generator.py
+++ b/third_party/WebKit/Source/build/scripts/json5_generator.py
@@ -152,11 +152,7 @@
             return entry
         if "name" not in item:
             raise Exception("Missing name in item: %s" % item)
-        if not self.parameters:
-            entry.update(item)
-            return entry
         entry["name"] = item.pop("name")
-        # Validate parameters if it's specified.
         for key, value in item.items():
             if key not in self.parameters:
                 raise Exception(
diff --git a/third_party/WebKit/Source/build/scripts/make_element_factory.py b/third_party/WebKit/Source/build/scripts/make_element_factory.py
index 68606172..5e9af05 100755
--- a/third_party/WebKit/Source/build/scripts/make_element_factory.py
+++ b/third_party/WebKit/Source/build/scripts/make_element_factory.py
@@ -30,7 +30,7 @@
 import sys
 from collections import defaultdict
 
-import json5_generator
+import in_generator
 import template_expander
 import name_utilities
 
@@ -38,23 +38,23 @@
 
 
 class MakeElementFactoryWriter(MakeQualifiedNamesWriter):
-    default_parameters = {
-        'JSInterfaceName': {},
-        'Conditional': {},
-        'constructorNeedsCreatedByParser': {},
-        'interfaceName': {},
-        'noConstructor': {},
-        'noTypeHelpers': {},
-        'runtimeEnabled': {},
-    }
-    default_metadata = dict(MakeQualifiedNamesWriter.default_metadata, **{
+    defaults = dict(MakeQualifiedNamesWriter.default_parameters, **{
+        'JSInterfaceName': None,
+        'Conditional': None,
+        'constructorNeedsCreatedByParser': None,
+        'interfaceName': None,
+        'noConstructor': None,
+        'noTypeHelpers': None,
+        'runtimeEnabled': None,
+    })
+    default_parameters = dict(MakeQualifiedNamesWriter.default_parameters, **{
         'fallbackInterfaceName': '',
         'fallbackJSInterfaceName': '',
     })
     filters = MakeQualifiedNamesWriter.filters
 
-    def __init__(self, json5_file_paths):
-        super(MakeElementFactoryWriter, self).__init__(json5_file_paths)
+    def __init__(self, in_file_paths):
+        super(MakeElementFactoryWriter, self).__init__(in_file_paths)
 
         # FIXME: When we start using these element factories, we'll want to
         # remove the "new" prefix and also have our base class generate
@@ -64,8 +64,8 @@
             (self.namespace + 'ElementFactory.cpp'): self.generate_factory_implementation,
         })
 
-        fallback_interface = self.tags_json5_file.metadata['fallbackInterfaceName'].strip('"')
-        fallback_js_interface = self.tags_json5_file.metadata['fallbackJSInterfaceName'].strip('"') or fallback_interface
+        fallback_interface = self.tags_in_file.parameters['fallbackInterfaceName'].strip('"')
+        fallback_js_interface = self.tags_in_file.parameters['fallbackJSInterfaceName'].strip('"') or fallback_interface
 
         interface_counts = defaultdict(int)
         tags = self._template_context['tags']
@@ -114,4 +114,4 @@
 
 
 if __name__ == "__main__":
-    json5_generator.Maker(MakeElementFactoryWriter).main()
+    in_generator.Maker(MakeElementFactoryWriter).main(sys.argv)
diff --git a/third_party/WebKit/Source/build/scripts/make_element_lookup_trie.py b/third_party/WebKit/Source/build/scripts/make_element_lookup_trie.py
index 89b0d36b..5663f300 100755
--- a/third_party/WebKit/Source/build/scripts/make_element_lookup_trie.py
+++ b/third_party/WebKit/Source/build/scripts/make_element_lookup_trie.py
@@ -29,21 +29,21 @@
 
 import sys
 
-import json5_generator
+import in_generator
 import trie_builder
 import template_expander
 
 
-class ElementLookupTrieWriter(json5_generator.Writer):
+class ElementLookupTrieWriter(in_generator.Writer):
     # FIXME: Inherit all these from somewhere.
-    default_parameters = {
-        'JSInterfaceName': {},
-        'constructorNeedsCreatedByParser': {},
-        'interfaceName': {},
-        'noConstructor': {},
-        'runtimeEnabled': {},
+    defaults = {
+        'JSInterfaceName': None,
+        'constructorNeedsCreatedByParser': None,
+        'interfaceName': None,
+        'noConstructor': None,
+        'runtimeEnabled': None,
     }
-    default_metadata = {
+    default_parameters = {
         'attrsNullNamespace': None,
         'export': '',
         'fallbackInterfaceName': '',
@@ -53,12 +53,12 @@
         'namespaceURI': '',
     }
 
-    def __init__(self, json5_file_paths):
-        super(ElementLookupTrieWriter, self).__init__(json5_file_paths)
+    def __init__(self, in_file_paths):
+        super(ElementLookupTrieWriter, self).__init__(in_file_paths)
         self._tags = {}
-        for entry in self.json5_file.name_dictionaries:
+        for entry in self.in_file.name_dictionaries:
             self._tags[entry['name']] = entry['name']
-        self._namespace = self.json5_file.metadata['namespace'].strip('"')
+        self._namespace = self.in_file.parameters['namespace'].strip('"')
         self._outputs = {
             (self._namespace + 'ElementLookupTrie.h'): self.generate_header,
             (self._namespace + 'ElementLookupTrie.cpp'): self.generate_implementation,
@@ -79,4 +79,4 @@
 
 
 if __name__ == '__main__':
-    json5_generator.Maker(ElementLookupTrieWriter).main()
+    in_generator.Maker(ElementLookupTrieWriter).main(sys.argv)
diff --git a/third_party/WebKit/Source/build/scripts/make_element_type_helpers.py b/third_party/WebKit/Source/build/scripts/make_element_type_helpers.py
index 035bf730..c6b4063 100755
--- a/third_party/WebKit/Source/build/scripts/make_element_type_helpers.py
+++ b/third_party/WebKit/Source/build/scripts/make_element_type_helpers.py
@@ -7,27 +7,31 @@
 from collections import defaultdict
 
 import hasher
-import json5_generator
+import in_generator
 import name_utilities
 import template_expander
 
+from in_file import InFile
+
 
 def _symbol(tag):
+    # FIXME: Remove this special case for the ugly x-webkit-foo attributes.
+    if tag['name'].startswith('-webkit-'):
+        return tag['name'].replace('-', '_')[1:]
     return name_utilities.cpp_name(tag).replace('-', '_')
 
-
-class MakeElementTypeHelpersWriter(json5_generator.Writer):
-    default_parameters = {
-        'Conditional': {},
-        'ImplementedAs': {},
-        'JSInterfaceName': {},
-        'constructorNeedsCreatedByParser': {},
-        'interfaceName': {},
-        'noConstructor': {},
-        'noTypeHelpers': {},
-        'runtimeEnabled': {},
+class MakeElementTypeHelpersWriter(in_generator.Writer):
+    defaults = {
+        'Conditional': None,
+        'ImplementedAs': None,
+        'JSInterfaceName': None,
+        'constructorNeedsCreatedByParser': None,
+        'interfaceName': None,
+        'noConstructor': None,
+        'noTypeHelpers': None,
+        'runtimeEnabled': None,
     }
-    default_metadata = {
+    default_parameters = {
         'attrsNullNamespace': None,
         'export': '',
         'fallbackInterfaceName': '',
@@ -41,11 +45,11 @@
         'symbol': _symbol,
     }
 
-    def __init__(self, json5_file_path):
-        super(MakeElementTypeHelpersWriter, self).__init__(json5_file_path)
+    def __init__(self, in_file_path):
+        super(MakeElementTypeHelpersWriter, self).__init__(in_file_path)
 
-        self.namespace = self.json5_file.metadata['namespace'].strip('"')
-        self.fallback_interface = self.json5_file.metadata['fallbackInterfaceName'].strip('"')
+        self.namespace = self.in_file.parameters['namespace'].strip('"')
+        self.fallbackInterface = self.in_file.parameters['fallbackInterfaceName'].strip('"')
 
         assert self.namespace, 'A namespace is required.'
 
@@ -56,7 +60,7 @@
 
         self._template_context = {
             'namespace': self.namespace,
-            'tags': self.json5_file.name_dictionaries,
+            'tags': self.in_file.name_dictionaries,
             'elements': set(),
         }
 
@@ -69,7 +73,7 @@
             elements.add(tag['interface'])
 
         for tag in tags:
-            tag['multipleTagNames'] = (interface_counts[tag['interface']] > 1 or tag['interface'] == self.fallback_interface)
+            tag['multipleTagNames'] = (interface_counts[tag['interface']] > 1 or tag['interface'] == self.fallbackInterface)
 
     @template_expander.use_jinja("ElementTypeHelpers.h.tmpl", filters=filters)
     def generate_helper_header(self):
@@ -93,4 +97,4 @@
         return '%s%sElement' % (self.namespace, name)
 
 if __name__ == "__main__":
-    json5_generator.Maker(MakeElementTypeHelpersWriter).main()
+    in_generator.Maker(MakeElementTypeHelpersWriter).main(sys.argv)
diff --git a/third_party/WebKit/Source/build/scripts/make_qualified_names.py b/third_party/WebKit/Source/build/scripts/make_qualified_names.py
index b9b5ff5..a7d9d1a7 100755
--- a/third_party/WebKit/Source/build/scripts/make_qualified_names.py
+++ b/third_party/WebKit/Source/build/scripts/make_qualified_names.py
@@ -30,20 +30,24 @@
 import sys
 
 import hasher
-import json5_generator
+import in_generator
 import name_utilities
 import template_expander
 
-from json5_generator import Json5File
+from in_file import InFile
 
 
 def _symbol(entry):
+    # FIXME: Remove this special case for the ugly x-webkit-foo attributes.
+    if entry['name'].startswith('x-webkit-'):
+        return entry['name'].replace('-', '')[1:]
     return entry['name'].replace('-', '_')
 
 
-class MakeQualifiedNamesWriter(json5_generator.Writer):
-    default_parameters = {}
-    default_metadata = {
+class MakeQualifiedNamesWriter(in_generator.Writer):
+    defaults = {
+    }
+    default_parameters = {
         'attrsNullNamespace': None,
         'export': '',
         'namespace': '',
@@ -56,44 +60,43 @@
         'to_macro_style': name_utilities.to_macro_style,
     }
 
-    def __init__(self, json5_file_paths):
+    def __init__(self, in_file_paths):
         super(MakeQualifiedNamesWriter, self).__init__(None)
-        assert len(json5_file_paths) <= 2, 'MakeQualifiedNamesWriter requires at most 2 in files, got %d.' % len(json5_file_paths)
+        assert len(in_file_paths) <= 2, 'MakeQualifiedNamesWriter requires at most 2 in files, got %d.' % len(in_file_paths)
 
-        if len(json5_file_paths) == 2:
-            self.tags_json5_file = Json5File.load_from_files(
-                [json5_file_paths.pop(0)], self.default_metadata, self.default_parameters)
+        if len(in_file_paths) == 2:
+            self.tags_in_file = InFile.load_from_files([in_file_paths.pop(0)], self.defaults, self.valid_values, self.default_parameters)
         else:
-            self.tags_json5_file = None
+            self.tags_in_file = None
 
-        self.attrs_json5_file = Json5File.load_from_files([json5_file_paths.pop()], self.default_metadata, self.default_parameters)
+        self.attrs_in_file = InFile.load_from_files([in_file_paths.pop()], self.defaults, self.valid_values, self.default_parameters)
 
-        self.namespace = self._metadata('namespace')
+        self.namespace = self._parameter('namespace')
 
-        namespace_prefix = self._metadata('namespacePrefix') or self.namespace.lower()
-        namespace_uri = self._metadata('namespaceURI')
+        namespace_prefix = self._parameter('namespacePrefix') or self.namespace.lower()
+        namespace_uri = self._parameter('namespaceURI')
 
-        use_namespace_for_attrs = self.attrs_json5_file.metadata['attrsNullNamespace'] is None
+        use_namespace_for_attrs = self.attrs_in_file.parameters['attrsNullNamespace'] is None
 
         self._outputs = {
             (self.namespace + "Names.h"): self.generate_header,
             (self.namespace + "Names.cpp"): self.generate_implementation,
         }
         self._template_context = {
-            'attrs': self.attrs_json5_file.name_dictionaries,
-            'export': self._metadata('export'),
+            'attrs': self.attrs_in_file.name_dictionaries,
+            'export': self._parameter('export'),
             'namespace': self.namespace,
             'namespace_prefix': namespace_prefix,
             'namespace_uri': namespace_uri,
-            'tags': self.tags_json5_file.name_dictionaries if self.tags_json5_file else [],
+            'tags': self.tags_in_file.name_dictionaries if self.tags_in_file else [],
             'use_namespace_for_attrs': use_namespace_for_attrs,
         }
 
-    def _metadata(self, name):
-        metadata = self.attrs_json5_file.metadata[name].strip('"')
-        if self.tags_json5_file:
-            assert metadata == self.tags_json5_file.metadata[name].strip('"'), 'Both files must have the same %s.' % name
-        return metadata
+    def _parameter(self, name):
+        parameter = self.attrs_in_file.parameters[name].strip('"')
+        if self.tags_in_file:
+            assert parameter == self.tags_in_file.parameters[name].strip('"'), 'Both in files must have the same %s.' % name
+        return parameter
 
     @template_expander.use_jinja('MakeQualifiedNames.h.tmpl', filters=filters)
     def generate_header(self):
@@ -104,5 +107,5 @@
         return self._template_context
 
 
-if __name__ == "__majson5__":
-    json5_generator.Maker(MakeQualifiedNamesWriter).main()
+if __name__ == "__main__":
+    in_generator.Maker(MakeQualifiedNamesWriter).main(sys.argv)
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 02b4257..1b8461c1 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -510,8 +510,8 @@
   script = "../build/scripts/make_element_factory.py"
 
   in_files = [
-    "html/HTMLTagNames.json5",
-    "html/HTMLAttributeNames.json5",
+    "html/HTMLTagNames.in",
+    "html/HTMLAttributeNames.in",
   ]
   other_inputs = make_element_factory_files
   outputs = [
@@ -525,7 +525,7 @@
 process_in_files("make_core_generated_html_element_type_helpers") {
   script = "../build/scripts/make_element_type_helpers.py"
 
-  in_files = [ "html/HTMLTagNames.json5" ]
+  in_files = [ "html/HTMLTagNames.in" ]
   other_inputs = make_element_type_helpers_files
   outputs = [
     "$blink_core_output_dir/HTMLElementTypeHelpers.cpp",
@@ -537,8 +537,8 @@
   script = "../build/scripts/make_element_factory.py"
 
   in_files = [
-    "svg/SVGTagNames.json5",
-    "svg/SVGAttributeNames.json5",
+    "svg/SVGTagNames.in",
+    "svg/SVGAttributeNames.in",
   ]
   other_inputs = make_element_factory_files
   outputs = [
@@ -552,7 +552,7 @@
 process_in_files("make_core_generated_svg_element_type_helpers") {
   script = "../build/scripts/make_element_type_helpers.py"
 
-  in_files = [ "svg/SVGTagNames.json5" ]
+  in_files = [ "svg/SVGTagNames.in" ]
   other_inputs = make_element_type_helpers_files
   outputs = [
     "$blink_core_output_dir/SVGElementTypeHelpers.h",
@@ -644,8 +644,8 @@
 
 make_qualified_names("make_core_generated_math_ml_names") {
   in_files = [
-    "html/parser/MathMLTagNames.json5",
-    "html/parser/MathMLAttributeNames.json5",
+    "html/parser/MathMLTagNames.in",
+    "html/parser/MathMLAttributeNames.in",
   ]
   outputs = [
     "$blink_core_output_dir/MathMLNames.cpp",
@@ -654,7 +654,7 @@
 }
 
 make_qualified_names("make_core_generated_xlink_names") {
-  in_files = [ "svg/xlinkattrs.json5" ]
+  in_files = [ "svg/xlinkattrs.in" ]
   outputs = [
     "$blink_core_output_dir/XLinkNames.cpp",
     "$blink_core_output_dir/XLinkNames.h",
@@ -662,7 +662,7 @@
 }
 
 make_qualified_names("make_core_generated_xml_ns_names") {
-  in_files = [ "xml/xmlnsattrs.json5" ]
+  in_files = [ "xml/xmlnsattrs.in" ]
   outputs = [
     "$blink_core_output_dir/XMLNSNames.cpp",
     "$blink_core_output_dir/XMLNSNames.h",
@@ -670,7 +670,7 @@
 }
 
 make_qualified_names("make_core_generated_xml_names") {
-  in_files = [ "xml/xmlattrs.json5" ]
+  in_files = [ "xml/xmlattrs.in" ]
   outputs = [
     "$blink_core_output_dir/XMLNames.cpp",
     "$blink_core_output_dir/XMLNames.h",
@@ -774,7 +774,7 @@
   visibility = [ ":*" ]
   script = "../build/scripts/make_element_lookup_trie.py"
 
-  input_file = "html/HTMLTagNames.json5"
+  input_file = "html/HTMLTagNames.in"
   inputs = make_trie_helpers_files + [
              input_file,
              "../build/scripts/templates/ElementLookupTrie.cpp.tmpl",
diff --git a/third_party/WebKit/Source/core/editing/BUILD.gn b/third_party/WebKit/Source/core/editing/BUILD.gn
index b3441fd..0449e43 100644
--- a/third_party/WebKit/Source/core/editing/BUILD.gn
+++ b/third_party/WebKit/Source/core/editing/BUILD.gn
@@ -20,6 +20,8 @@
     "EditingStrategy.cpp",
     "EditingStrategy.h",
     "EditingStyle.cpp",
+    "EditingStyleUtilities.cpp",
+    "EditingStyleUtilities.h",
     "EditingUtilities.cpp",
     "EditingUtilities.h",
     "Editor.cpp",
diff --git a/third_party/WebKit/Source/core/editing/EditingStyle.h b/third_party/WebKit/Source/core/editing/EditingStyle.h
index 336512a..12bdc3f6 100644
--- a/third_party/WebKit/Source/core/editing/EditingStyle.h
+++ b/third_party/WebKit/Source/core/editing/EditingStyle.h
@@ -148,6 +148,9 @@
   void mergeInlineStyleOfElement(HTMLElement*,
                                  CSSPropertyOverrideMode,
                                  PropertiesToInclude = AllProperties);
+  void mergeInlineAndImplicitStyleOfElement(Element*,
+                                            CSSPropertyOverrideMode,
+                                            PropertiesToInclude);
   static EditingStyle* wrappingStyleForAnnotatedSerialization(
       ContainerNode* context);
   static EditingStyle* wrappingStyleForSerialization(ContainerNode* context);
@@ -162,6 +165,8 @@
   float fontSizeDelta() const { return m_fontSizeDelta; }
   bool hasFontSizeDelta() const { return m_fontSizeDelta != NoFontDelta; }
 
+  void setProperty(CSSPropertyID, const String& value, bool important = false);
+
   static EditingStyle* styleAtSelectionStart(
       const VisibleSelection&,
       bool shouldUseBackgroundColorInEffect = false,
@@ -185,7 +190,6 @@
   EditingStyle(CSSPropertyID, const String& value);
   void init(Node*, PropertiesToInclude);
   void removeInheritedColorsIfNeeded(const ComputedStyle*);
-  void setProperty(CSSPropertyID, const String& value, bool important = false);
   void replaceFontSizeByKeywordIfPossible(const ComputedStyle*,
                                           CSSComputedStyleDeclaration*);
   void extractFontSizeDelta();
@@ -195,9 +199,6 @@
       HTMLElement*,
       EditingStyle* extractedStyle,
       Vector<CSSPropertyID>* conflictingProperties) const;
-  void mergeInlineAndImplicitStyleOfElement(Element*,
-                                            CSSPropertyOverrideMode,
-                                            PropertiesToInclude);
   void mergeStyle(const StylePropertySet*, CSSPropertyOverrideMode);
 
   Member<MutableStylePropertySet> m_mutableStyle;
diff --git a/third_party/WebKit/Source/core/editing/EditingStyleUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingStyleUtilities.cpp
index 1df94712..cdb69e51 100644
--- a/third_party/WebKit/Source/core/editing/EditingStyleUtilities.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingStyleUtilities.cpp
@@ -24,761 +24,20 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "core/editing/EditingStyle.h"
+#include "EditingStyleUtilities.h"
 
-#include "bindings/core/v8/ExceptionState.h"
-#include "core/HTMLNames.h"
 #include "core/css/CSSColorValue.h"
 #include "core/css/CSSComputedStyleDeclaration.h"
 #include "core/css/CSSIdentifierValue.h"
-#include "core/css/CSSPrimitiveValue.h"
-#include "core/css/CSSPrimitiveValueMappings.h"
-#include "core/css/CSSPropertyMetadata.h"
-#include "core/css/CSSRuleList.h"
-#include "core/css/CSSStyleRule.h"
-#include "core/css/CSSValueList.h"
-#include "core/css/FontSize.h"
 #include "core/css/StylePropertySet.h"
-#include "core/css/StyleRule.h"
 #include "core/css/parser/CSSParser.h"
-#include "core/css/resolver/StyleResolver.h"
-#include "core/dom/Document.h"
-#include "core/dom/Element.h"
-#include "core/dom/Node.h"
-#include "core/dom/NodeComputedStyle.h"
-#include "core/dom/NodeTraversal.h"
-#include "core/dom/QualifiedName.h"
+#include "core/editing/EditingStyle.h"
 #include "core/editing/EditingUtilities.h"
-#include "core/editing/Editor.h"
-#include "core/editing/FrameSelection.h"
-#include "core/editing/Position.h"
-#include "core/editing/commands/ApplyStyleCommand.h"
-#include "core/editing/serializers/HTMLInterchange.h"
-#include "core/frame/LocalFrame.h"
-#include "core/html/HTMLFontElement.h"
-#include "core/html/HTMLSpanElement.h"
-#include "core/layout/LayoutBox.h"
-#include "core/layout/LayoutObject.h"
-#include "core/style/ComputedStyle.h"
-#include "wtf/StdLibExtras.h"
 
 namespace blink {
 
-static const CSSPropertyID& textDecorationPropertyForEditing() {
-  static const CSSPropertyID property =
-      RuntimeEnabledFeatures::css3TextDecorationsEnabled()
-          ? CSSPropertyTextDecorationLine
-          : CSSPropertyTextDecoration;
-  return property;
-}
-
-// Editing style properties must be preserved during editing operation.
-// e.g. when a user inserts a new paragraph, all properties listed here must be
-// copied to the new paragraph.
-// NOTE: Use either allEditingProperties() or inheritableEditingProperties() to
-// respect runtime enabling of properties.
-static const CSSPropertyID staticEditingProperties[] = {
-    CSSPropertyBackgroundColor, CSSPropertyColor, CSSPropertyFontFamily,
-    CSSPropertyFontSize, CSSPropertyFontStyle, CSSPropertyFontVariantLigatures,
-    CSSPropertyFontVariantCaps, CSSPropertyFontWeight, CSSPropertyLetterSpacing,
-    CSSPropertyOrphans, CSSPropertyTextAlign,
-    // FIXME: CSSPropertyTextDecoration needs to be removed when CSS3 Text
-    // Decoration feature is no longer experimental.
-    CSSPropertyTextDecoration, CSSPropertyTextDecorationLine,
-    CSSPropertyTextIndent, CSSPropertyTextTransform, CSSPropertyWhiteSpace,
-    CSSPropertyWidows, CSSPropertyWordSpacing,
-    CSSPropertyWebkitTextDecorationsInEffect, CSSPropertyWebkitTextFillColor,
-    CSSPropertyWebkitTextStrokeColor, CSSPropertyWebkitTextStrokeWidth,
-    CSSPropertyCaretColor};
-
-enum EditingPropertiesType {
-  OnlyInheritableEditingProperties,
-  AllEditingProperties
-};
-
-static const Vector<CSSPropertyID>& allEditingProperties() {
-  DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
-  if (properties.isEmpty()) {
-    CSSPropertyMetadata::filterEnabledCSSPropertiesIntoVector(
-        staticEditingProperties, WTF_ARRAY_LENGTH(staticEditingProperties),
-        properties);
-    if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
-      properties.remove(properties.find(CSSPropertyTextDecoration));
-  }
-  return properties;
-}
-
-static const Vector<CSSPropertyID>& inheritableEditingProperties() {
-  DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
-  if (properties.isEmpty()) {
-    CSSPropertyMetadata::filterEnabledCSSPropertiesIntoVector(
-        staticEditingProperties, WTF_ARRAY_LENGTH(staticEditingProperties),
-        properties);
-    for (size_t index = 0; index < properties.size();) {
-      if (!CSSPropertyMetadata::isInheritedProperty(properties[index])) {
-        properties.remove(index);
-        continue;
-      }
-      ++index;
-    }
-  }
-  return properties;
-}
-
-template <class StyleDeclarationType>
-static MutableStylePropertySet* copyEditingProperties(
-    StyleDeclarationType* style,
-    EditingPropertiesType type = OnlyInheritableEditingProperties) {
-  if (type == AllEditingProperties)
-    return style->copyPropertiesInSet(allEditingProperties());
-  return style->copyPropertiesInSet(inheritableEditingProperties());
-}
-
-static inline bool isEditingProperty(int id) {
-  return allEditingProperties().contains(static_cast<CSSPropertyID>(id));
-}
-
-static MutableStylePropertySet* editingStyleFromComputedStyle(
-    CSSComputedStyleDeclaration* style,
-    EditingPropertiesType type = OnlyInheritableEditingProperties) {
-  if (!style)
-    return MutableStylePropertySet::create(HTMLQuirksMode);
-  return copyEditingProperties(style, type);
-}
-
-static CSSComputedStyleDeclaration* ensureComputedStyle(
-    const Position& position) {
-  Element* elem = associatedElementOf(position);
-  if (!elem)
-    return nullptr;
-  return CSSComputedStyleDeclaration::create(elem);
-}
-
-static MutableStylePropertySet* getPropertiesNotIn(
-    StylePropertySet* styleWithRedundantProperties,
-    CSSStyleDeclaration* baseStyle);
-enum LegacyFontSizeMode {
-  AlwaysUseLegacyFontSize,
-  UseLegacyFontSizeOnlyIfPixelValuesMatch
-};
-static int legacyFontSizeFromCSSValue(Document*,
-                                      const CSSValue*,
-                                      bool,
-                                      LegacyFontSizeMode);
-static bool isTransparentColorValue(const CSSValue*);
-static bool hasTransparentBackgroundColor(CSSStyleDeclaration*);
-static bool hasTransparentBackgroundColor(StylePropertySet*);
-static const CSSValue* backgroundColorValueInEffect(Node*);
-static bool hasAncestorVerticalAlignStyle(Node&, CSSValueID);
-
-class HTMLElementEquivalent : public GarbageCollected<HTMLElementEquivalent> {
- public:
-  static HTMLElementEquivalent* create(CSSPropertyID propertyID,
-                                       CSSValueID primitiveValue,
-                                       const HTMLQualifiedName& tagName) {
-    return new HTMLElementEquivalent(propertyID, primitiveValue, tagName);
-  }
-
-  virtual bool matches(const Element* element) const {
-    return !m_tagName || element->hasTagName(*m_tagName);
-  }
-  virtual bool hasAttribute() const { return false; }
-  virtual bool propertyExistsInStyle(const StylePropertySet* style) const {
-    return style->getPropertyCSSValue(m_propertyID);
-  }
-  virtual bool valueIsPresentInStyle(HTMLElement*, StylePropertySet*) const;
-  virtual void addToStyle(Element*, EditingStyle*) const;
-
-  DEFINE_INLINE_VIRTUAL_TRACE() { visitor->trace(m_identifierValue); }
-
- protected:
-  HTMLElementEquivalent(CSSPropertyID);
-  HTMLElementEquivalent(CSSPropertyID, const HTMLQualifiedName& tagName);
-  HTMLElementEquivalent(CSSPropertyID,
-                        CSSValueID primitiveValue,
-                        const HTMLQualifiedName& tagName);
-  const CSSPropertyID m_propertyID;
-  const Member<CSSIdentifierValue> m_identifierValue;
-  // We can store a pointer because HTML tag names are const global.
-  const HTMLQualifiedName* m_tagName;
-};
-
-HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id)
-    : m_propertyID(id), m_tagName(0) {}
-
-HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id,
-                                             const HTMLQualifiedName& tagName)
-    : m_propertyID(id), m_tagName(&tagName) {}
-
-HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id,
-                                             CSSValueID valueID,
-                                             const HTMLQualifiedName& tagName)
-    : m_propertyID(id),
-      m_identifierValue(CSSIdentifierValue::create(valueID)),
-      m_tagName(&tagName) {
-  DCHECK_NE(valueID, CSSValueInvalid);
-}
-
-bool HTMLElementEquivalent::valueIsPresentInStyle(
-    HTMLElement* element,
-    StylePropertySet* style) const {
-  const CSSValue* value = style->getPropertyCSSValue(m_propertyID);
-  return matches(element) && value && value->isIdentifierValue() &&
-         toCSSIdentifierValue(value)->getValueID() ==
-             m_identifierValue->getValueID();
-}
-
-void HTMLElementEquivalent::addToStyle(Element*, EditingStyle* style) const {
-  style->setProperty(m_propertyID, m_identifierValue->cssText());
-}
-
-class HTMLTextDecorationEquivalent final : public HTMLElementEquivalent {
- public:
-  static HTMLElementEquivalent* create(CSSValueID primitiveValue,
-                                       const HTMLQualifiedName& tagName) {
-    return new HTMLTextDecorationEquivalent(primitiveValue, tagName);
-  }
-  bool propertyExistsInStyle(const StylePropertySet*) const override;
-  bool valueIsPresentInStyle(HTMLElement*, StylePropertySet*) const override;
-
-  DEFINE_INLINE_VIRTUAL_TRACE() { HTMLElementEquivalent::trace(visitor); }
-
- private:
-  HTMLTextDecorationEquivalent(CSSValueID primitiveValue,
-                               const HTMLQualifiedName& tagName);
-};
-
-HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent(
-    CSSValueID primitiveValue,
-    const HTMLQualifiedName& tagName)
-    : HTMLElementEquivalent(textDecorationPropertyForEditing(),
-                            primitiveValue,
-                            tagName)
-// m_propertyID is used in HTMLElementEquivalent::addToStyle
-{}
-
-bool HTMLTextDecorationEquivalent::propertyExistsInStyle(
-    const StylePropertySet* style) const {
-  return style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect) ||
-         style->getPropertyCSSValue(textDecorationPropertyForEditing());
-}
-
-bool HTMLTextDecorationEquivalent::valueIsPresentInStyle(
-    HTMLElement* element,
-    StylePropertySet* style) const {
-  const CSSValue* styleValue =
-      style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
-  if (!styleValue)
-    styleValue = style->getPropertyCSSValue(textDecorationPropertyForEditing());
-  return matches(element) && styleValue && styleValue->isValueList() &&
-         toCSSValueList(styleValue)->hasValue(*m_identifierValue);
-}
-
-class HTMLAttributeEquivalent : public HTMLElementEquivalent {
- public:
-  static HTMLAttributeEquivalent* create(CSSPropertyID propertyID,
-                                         const HTMLQualifiedName& tagName,
-                                         const QualifiedName& attrName) {
-    return new HTMLAttributeEquivalent(propertyID, tagName, attrName);
-  }
-  static HTMLAttributeEquivalent* create(CSSPropertyID propertyID,
-                                         const QualifiedName& attrName) {
-    return new HTMLAttributeEquivalent(propertyID, attrName);
-  }
-
-  bool matches(const Element* element) const override {
-    return HTMLElementEquivalent::matches(element) &&
-           element->hasAttribute(m_attrName);
-  }
-  bool hasAttribute() const override { return true; }
-  bool valueIsPresentInStyle(HTMLElement*, StylePropertySet*) const override;
-  void addToStyle(Element*, EditingStyle*) const override;
-  virtual const CSSValue* attributeValueAsCSSValue(Element*) const;
-  inline const QualifiedName& attributeName() const { return m_attrName; }
-
-  DEFINE_INLINE_VIRTUAL_TRACE() { HTMLElementEquivalent::trace(visitor); }
-
- protected:
-  HTMLAttributeEquivalent(CSSPropertyID,
-                          const HTMLQualifiedName& tagName,
-                          const QualifiedName& attrName);
-  HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& attrName);
-  // We can store a reference because HTML attribute names are const global.
-  const QualifiedName& m_attrName;
-};
-
-HTMLAttributeEquivalent::HTMLAttributeEquivalent(
-    CSSPropertyID id,
-    const HTMLQualifiedName& tagName,
-    const QualifiedName& attrName)
-    : HTMLElementEquivalent(id, tagName), m_attrName(attrName) {}
-
-HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id,
-                                                 const QualifiedName& attrName)
-    : HTMLElementEquivalent(id), m_attrName(attrName) {}
-
-bool HTMLAttributeEquivalent::valueIsPresentInStyle(
-    HTMLElement* element,
-    StylePropertySet* style) const {
-  const CSSValue* value = attributeValueAsCSSValue(element);
-  const CSSValue* styleValue = style->getPropertyCSSValue(m_propertyID);
-
-  return compareCSSValuePtr(value, styleValue);
-}
-
-void HTMLAttributeEquivalent::addToStyle(Element* element,
-                                         EditingStyle* style) const {
-  if (const CSSValue* value = attributeValueAsCSSValue(element))
-    style->setProperty(m_propertyID, value->cssText());
-}
-
-const CSSValue* HTMLAttributeEquivalent::attributeValueAsCSSValue(
-    Element* element) const {
-  DCHECK(element);
-  const AtomicString& value = element->getAttribute(m_attrName);
-  if (value.isNull())
-    return nullptr;
-
-  MutableStylePropertySet* dummyStyle = nullptr;
-  dummyStyle = MutableStylePropertySet::create(HTMLQuirksMode);
-  dummyStyle->setProperty(m_propertyID, value);
-  return dummyStyle->getPropertyCSSValue(m_propertyID);
-}
-
-class HTMLFontSizeEquivalent final : public HTMLAttributeEquivalent {
- public:
-  static HTMLFontSizeEquivalent* create() {
-    return new HTMLFontSizeEquivalent();
-  }
-  const CSSValue* attributeValueAsCSSValue(Element*) const override;
-
-  DEFINE_INLINE_VIRTUAL_TRACE() { HTMLAttributeEquivalent::trace(visitor); }
-
- private:
-  HTMLFontSizeEquivalent();
-};
-
-HTMLFontSizeEquivalent::HTMLFontSizeEquivalent()
-    : HTMLAttributeEquivalent(CSSPropertyFontSize,
-                              HTMLNames::fontTag,
-                              HTMLNames::sizeAttr) {}
-
-const CSSValue* HTMLFontSizeEquivalent::attributeValueAsCSSValue(
-    Element* element) const {
-  DCHECK(element);
-  const AtomicString& value = element->getAttribute(m_attrName);
-  if (value.isNull())
-    return nullptr;
-  CSSValueID size;
-  if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size))
-    return nullptr;
-  return CSSIdentifierValue::create(size);
-}
-
-float EditingStyle::NoFontDelta = 0.0f;
-
-EditingStyle::EditingStyle(ContainerNode* node,
-                           PropertiesToInclude propertiesToInclude) {
-  init(node, propertiesToInclude);
-}
-
-EditingStyle::EditingStyle(const Position& position,
-                           PropertiesToInclude propertiesToInclude) {
-  init(position.anchorNode(), propertiesToInclude);
-}
-
-EditingStyle::EditingStyle(const StylePropertySet* style)
-    : m_mutableStyle(style ? style->mutableCopy() : nullptr) {
-  extractFontSizeDelta();
-}
-
-EditingStyle::EditingStyle(CSSPropertyID propertyID, const String& value)
-    : m_mutableStyle(nullptr) {
-  setProperty(propertyID, value);
-  m_isVerticalAlign = propertyID == CSSPropertyVerticalAlign &&
-                      (value == "sub" || value == "super");
-}
-
-static Color cssValueToColor(const CSSValue* colorValue) {
-  if (!colorValue ||
-      (!colorValue->isColorValue() && !colorValue->isPrimitiveValue() &&
-       !colorValue->isIdentifierValue()))
-    return Color::transparent;
-
-  if (colorValue->isColorValue())
-    return toCSSColorValue(colorValue)->value();
-
-  Color color = 0;
-  // FIXME: Why ignore the return value?
-  CSSParser::parseColor(color, colorValue->cssText());
-  return color;
-}
-
-static inline Color getFontColor(CSSStyleDeclaration* style) {
-  return cssValueToColor(style->getPropertyCSSValueInternal(CSSPropertyColor));
-}
-
-static inline Color getFontColor(StylePropertySet* style) {
-  return cssValueToColor(style->getPropertyCSSValue(CSSPropertyColor));
-}
-
-static inline Color getBackgroundColor(CSSStyleDeclaration* style) {
-  return cssValueToColor(
-      style->getPropertyCSSValueInternal(CSSPropertyBackgroundColor));
-}
-
-static inline Color getBackgroundColor(StylePropertySet* style) {
-  return cssValueToColor(
-      style->getPropertyCSSValue(CSSPropertyBackgroundColor));
-}
-
-static inline Color backgroundColorInEffect(Node* node) {
-  return cssValueToColor(backgroundColorValueInEffect(node));
-}
-
-static int textAlignResolvingStartAndEnd(int textAlign, int direction) {
-  switch (textAlign) {
-    case CSSValueCenter:
-    case CSSValueWebkitCenter:
-      return CSSValueCenter;
-    case CSSValueJustify:
-      return CSSValueJustify;
-    case CSSValueLeft:
-    case CSSValueWebkitLeft:
-      return CSSValueLeft;
-    case CSSValueRight:
-    case CSSValueWebkitRight:
-      return CSSValueRight;
-    case CSSValueStart:
-      return direction != CSSValueRtl ? CSSValueLeft : CSSValueRight;
-    case CSSValueEnd:
-      return direction == CSSValueRtl ? CSSValueRight : CSSValueLeft;
-  }
-  return CSSValueInvalid;
-}
-
-template <typename T>
-static int textAlignResolvingStartAndEnd(T* style) {
-  return textAlignResolvingStartAndEnd(
-      getIdentifierValue(style, CSSPropertyTextAlign),
-      getIdentifierValue(style, CSSPropertyDirection));
-}
-
-void EditingStyle::init(Node* node, PropertiesToInclude propertiesToInclude) {
-  if (isTabHTMLSpanElementTextNode(node))
-    node = tabSpanElement(node)->parentNode();
-  else if (isTabHTMLSpanElement(node))
-    node = node->parentNode();
-
-  CSSComputedStyleDeclaration* computedStyleAtPosition =
-      CSSComputedStyleDeclaration::create(node);
-  m_mutableStyle =
-      propertiesToInclude == AllProperties && computedStyleAtPosition
-          ? computedStyleAtPosition->copyProperties()
-          : editingStyleFromComputedStyle(computedStyleAtPosition);
-
-  if (propertiesToInclude == EditingPropertiesInEffect) {
-    if (const CSSValue* value = backgroundColorValueInEffect(node))
-      m_mutableStyle->setProperty(CSSPropertyBackgroundColor, value->cssText());
-    if (const CSSValue* value = computedStyleAtPosition->getPropertyCSSValue(
-            CSSPropertyWebkitTextDecorationsInEffect))
-      m_mutableStyle->setProperty(CSSPropertyTextDecoration, value->cssText());
-  }
-
-  if (node && node->ensureComputedStyle()) {
-    const ComputedStyle* computedStyle = node->ensureComputedStyle();
-    removeInheritedColorsIfNeeded(computedStyle);
-    replaceFontSizeByKeywordIfPossible(computedStyle, computedStyleAtPosition);
-  }
-
-  m_isMonospaceFont = computedStyleAtPosition->isMonospaceFont();
-  extractFontSizeDelta();
-}
-
-void EditingStyle::removeInheritedColorsIfNeeded(
-    const ComputedStyle* computedStyle) {
-  // If a node's text fill color is currentColor, then its children use
-  // their font-color as their text fill color (they don't
-  // inherit it).  Likewise for stroke color.
-  // Similar thing happens for caret-color if it's auto or currentColor.
-  if (computedStyle->textFillColor().isCurrentColor())
-    m_mutableStyle->removeProperty(CSSPropertyWebkitTextFillColor);
-  if (computedStyle->textStrokeColor().isCurrentColor())
-    m_mutableStyle->removeProperty(CSSPropertyWebkitTextStrokeColor);
-  if (computedStyle->caretColor().isAutoColor() ||
-      computedStyle->caretColor().isCurrentColor())
-    m_mutableStyle->removeProperty(CSSPropertyCaretColor);
-}
-
-void EditingStyle::setProperty(CSSPropertyID propertyID,
-                               const String& value,
-                               bool important) {
-  if (!m_mutableStyle)
-    m_mutableStyle = MutableStylePropertySet::create(HTMLQuirksMode);
-
-  m_mutableStyle->setProperty(propertyID, value, important);
-}
-
-void EditingStyle::replaceFontSizeByKeywordIfPossible(
-    const ComputedStyle* computedStyle,
-    CSSComputedStyleDeclaration* cssComputedStyle) {
-  DCHECK(computedStyle);
-  if (computedStyle->getFontDescription().keywordSize()) {
-    m_mutableStyle->setProperty(
-        CSSPropertyFontSize,
-        cssComputedStyle->getFontSizeCSSValuePreferringKeyword()->cssText());
-  }
-}
-
-void EditingStyle::extractFontSizeDelta() {
-  if (!m_mutableStyle)
-    return;
-
-  if (m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize)) {
-    // Explicit font size overrides any delta.
-    m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta);
-    return;
-  }
-
-  // Get the adjustment amount out of the style.
-  const CSSValue* value =
-      m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitFontSizeDelta);
-  if (!value || !value->isPrimitiveValue())
-    return;
-
-  const CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
-
-  // Only PX handled now. If we handle more types in the future, perhaps
-  // a switch statement here would be more appropriate.
-  if (!primitiveValue->isPx())
-    return;
-
-  m_fontSizeDelta = primitiveValue->getFloatValue();
-  m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta);
-}
-
-bool EditingStyle::isEmpty() const {
-  return (!m_mutableStyle || m_mutableStyle->isEmpty()) &&
-         m_fontSizeDelta == NoFontDelta;
-}
-
-bool EditingStyle::textDirection(WritingDirection& writingDirection) const {
-  if (!m_mutableStyle)
-    return false;
-
-  const CSSValue* unicodeBidi =
-      m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
-  if (!unicodeBidi || !unicodeBidi->isIdentifierValue())
-    return false;
-
-  CSSValueID unicodeBidiValue = toCSSIdentifierValue(unicodeBidi)->getValueID();
-  if (isEmbedOrIsolate(unicodeBidiValue)) {
-    const CSSValue* direction =
-        m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
-    if (!direction || !direction->isIdentifierValue())
-      return false;
-
-    writingDirection =
-        toCSSIdentifierValue(direction)->getValueID() == CSSValueLtr
-            ? LeftToRightWritingDirection
-            : RightToLeftWritingDirection;
-
-    return true;
-  }
-
-  if (unicodeBidiValue == CSSValueNormal) {
-    writingDirection = NaturalWritingDirection;
-    return true;
-  }
-
-  return false;
-}
-
-void EditingStyle::overrideWithStyle(const StylePropertySet* style) {
-  if (!style || style->isEmpty())
-    return;
-  if (!m_mutableStyle)
-    m_mutableStyle = MutableStylePropertySet::create(HTMLQuirksMode);
-  m_mutableStyle->mergeAndOverrideOnConflict(style);
-  extractFontSizeDelta();
-}
-
-void EditingStyle::clear() {
-  m_mutableStyle.clear();
-  m_isMonospaceFont = false;
-  m_fontSizeDelta = NoFontDelta;
-}
-
-EditingStyle* EditingStyle::copy() const {
-  EditingStyle* copy = EditingStyle::create();
-  if (m_mutableStyle)
-    copy->m_mutableStyle = m_mutableStyle->mutableCopy();
-  copy->m_isMonospaceFont = m_isMonospaceFont;
-  copy->m_fontSizeDelta = m_fontSizeDelta;
-  return copy;
-}
-
-// This is the list of CSS properties that apply specially to block-level
-// elements.
-static const CSSPropertyID staticBlockProperties[] = {
-    CSSPropertyBreakAfter,
-    CSSPropertyBreakBefore,
-    CSSPropertyBreakInside,
-    CSSPropertyOrphans,
-    CSSPropertyOverflow,  // This can be also be applied to replaced elements
-    CSSPropertyColumnCount,
-    CSSPropertyColumnGap,
-    CSSPropertyColumnRuleColor,
-    CSSPropertyColumnRuleStyle,
-    CSSPropertyColumnRuleWidth,
-    CSSPropertyWebkitColumnBreakBefore,
-    CSSPropertyWebkitColumnBreakAfter,
-    CSSPropertyWebkitColumnBreakInside,
-    CSSPropertyColumnWidth,
-    CSSPropertyPageBreakAfter,
-    CSSPropertyPageBreakBefore,
-    CSSPropertyPageBreakInside,
-    CSSPropertyTextAlign,
-    CSSPropertyTextAlignLast,
-    CSSPropertyTextIndent,
-    CSSPropertyTextJustify,
-    CSSPropertyWidows};
-
-static const Vector<CSSPropertyID>& blockPropertiesVector() {
-  DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
-  if (properties.isEmpty()) {
-    CSSPropertyMetadata::filterEnabledCSSPropertiesIntoVector(
-        staticBlockProperties, WTF_ARRAY_LENGTH(staticBlockProperties),
-        properties);
-  }
-  return properties;
-}
-
-EditingStyle* EditingStyle::extractAndRemoveBlockProperties() {
-  EditingStyle* blockProperties = EditingStyle::create();
-  if (!m_mutableStyle)
-    return blockProperties;
-
-  blockProperties->m_mutableStyle =
-      m_mutableStyle->copyPropertiesInSet(blockPropertiesVector());
-  removeBlockProperties();
-
-  return blockProperties;
-}
-
-EditingStyle* EditingStyle::extractAndRemoveTextDirection() {
-  EditingStyle* textDirection = EditingStyle::create();
-  textDirection->m_mutableStyle =
-      MutableStylePropertySet::create(HTMLQuirksMode);
-  textDirection->m_mutableStyle->setProperty(
-      CSSPropertyUnicodeBidi, CSSValueIsolate,
-      m_mutableStyle->propertyIsImportant(CSSPropertyUnicodeBidi));
-  textDirection->m_mutableStyle->setProperty(
-      CSSPropertyDirection,
-      m_mutableStyle->getPropertyValue(CSSPropertyDirection),
-      m_mutableStyle->propertyIsImportant(CSSPropertyDirection));
-
-  m_mutableStyle->removeProperty(CSSPropertyUnicodeBidi);
-  m_mutableStyle->removeProperty(CSSPropertyDirection);
-
-  return textDirection;
-}
-
-void EditingStyle::removeBlockProperties() {
-  if (!m_mutableStyle)
-    return;
-
-  m_mutableStyle->removePropertiesInSet(blockPropertiesVector().data(),
-                                        blockPropertiesVector().size());
-}
-
-void EditingStyle::removeStyleAddedByElement(Element* element) {
-  if (!element || !element->parentNode())
-    return;
-  MutableStylePropertySet* parentStyle = editingStyleFromComputedStyle(
-      CSSComputedStyleDeclaration::create(element->parentNode()),
-      AllEditingProperties);
-  MutableStylePropertySet* nodeStyle = editingStyleFromComputedStyle(
-      CSSComputedStyleDeclaration::create(element), AllEditingProperties);
-  nodeStyle->removeEquivalentProperties(parentStyle);
-  m_mutableStyle->removeEquivalentProperties(nodeStyle);
-}
-
-void EditingStyle::removeStyleConflictingWithStyleOfElement(Element* element) {
-  if (!element || !element->parentNode() || !m_mutableStyle)
-    return;
-
-  MutableStylePropertySet* parentStyle = editingStyleFromComputedStyle(
-      CSSComputedStyleDeclaration::create(element->parentNode()),
-      AllEditingProperties);
-  MutableStylePropertySet* nodeStyle = editingStyleFromComputedStyle(
-      CSSComputedStyleDeclaration::create(element), AllEditingProperties);
-  nodeStyle->removeEquivalentProperties(parentStyle);
-
-  unsigned propertyCount = nodeStyle->propertyCount();
-  for (unsigned i = 0; i < propertyCount; ++i)
-    m_mutableStyle->removeProperty(nodeStyle->propertyAt(i).id());
-}
-
-void EditingStyle::collapseTextDecorationProperties() {
-  if (!m_mutableStyle)
-    return;
-
-  const CSSValue* textDecorationsInEffect = m_mutableStyle->getPropertyCSSValue(
-      CSSPropertyWebkitTextDecorationsInEffect);
-  if (!textDecorationsInEffect)
-    return;
-
-  if (textDecorationsInEffect->isValueList()) {
-    m_mutableStyle->setProperty(textDecorationPropertyForEditing(),
-                                textDecorationsInEffect->cssText(),
-                                m_mutableStyle->propertyIsImportant(
-                                    textDecorationPropertyForEditing()));
-  } else {
-    m_mutableStyle->removeProperty(textDecorationPropertyForEditing());
-  }
-  m_mutableStyle->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
-}
-
-// CSS properties that create a visual difference only when applied to text.
-static const CSSPropertyID textOnlyProperties[] = {
-    // FIXME: CSSPropertyTextDecoration needs to be removed when CSS3 Text
-    // Decoration feature is no longer experimental.
-    CSSPropertyTextDecoration,
-    CSSPropertyTextDecorationLine,
-    CSSPropertyWebkitTextDecorationsInEffect,
-    CSSPropertyFontStyle,
-    CSSPropertyFontWeight,
-    CSSPropertyColor,
-};
-
-TriState EditingStyle::triStateOfStyle(EditingStyle* style) const {
-  if (!style || !style->m_mutableStyle)
-    return FalseTriState;
-  return triStateOfStyle(style->m_mutableStyle->ensureCSSStyleDeclaration(),
-                         DoNotIgnoreTextOnlyProperties);
-}
-
-TriState EditingStyle::triStateOfStyle(
-    CSSStyleDeclaration* styleToCompare,
-    ShouldIgnoreTextOnlyProperties shouldIgnoreTextOnlyProperties) const {
-  MutableStylePropertySet* difference =
-      getPropertiesNotIn(m_mutableStyle.get(), styleToCompare);
-
-  if (shouldIgnoreTextOnlyProperties == IgnoreTextOnlyProperties) {
-    difference->removePropertiesInSet(textOnlyProperties,
-                                      WTF_ARRAY_LENGTH(textOnlyProperties));
-  }
-
-  if (difference->isEmpty())
-    return TrueTriState;
-  if (difference->propertyCount() == m_mutableStyle->propertyCount())
-    return FalseTriState;
-
-  return MixedTriState;
-}
-
-static bool hasAncestorVerticalAlignStyle(Node& node, CSSValueID value) {
+bool EditingStyleUtilities::hasAncestorVerticalAlignStyle(Node& node,
+                                                          CSSValueID value) {
   for (Node& runner : NodeTraversal::inclusiveAncestorsOf(node)) {
     CSSComputedStyleDeclaration* ancestorStyle =
         CSSComputedStyleDeclaration::create(&runner);
@@ -788,476 +47,7 @@
   return false;
 }
 
-TriState EditingStyle::triStateOfStyle(
-    const VisibleSelection& selection) const {
-  if (selection.isNone())
-    return FalseTriState;
-
-  if (selection.isCaret())
-    return triStateOfStyle(EditingStyle::styleAtSelectionStart(selection));
-
-  TriState state = FalseTriState;
-  bool nodeIsStart = true;
-  for (Node& node : NodeTraversal::startsAt(*selection.start().anchorNode())) {
-    if (node.layoutObject() && hasEditableStyle(node)) {
-      CSSComputedStyleDeclaration* nodeStyle =
-          CSSComputedStyleDeclaration::create(&node);
-      if (nodeStyle) {
-        // If the selected element has <sub> or <sup> ancestor element, apply
-        // the corresponding style(vertical-align) to it so that
-        // document.queryCommandState() works with the style. See bug
-        // http://crbug.com/582225.
-        if (m_isVerticalAlign &&
-            getIdentifierValue(nodeStyle, CSSPropertyVerticalAlign) ==
-                CSSValueBaseline) {
-          const CSSIdentifierValue* verticalAlign = toCSSIdentifierValue(
-              m_mutableStyle->getPropertyCSSValue(CSSPropertyVerticalAlign));
-          if (hasAncestorVerticalAlignStyle(node,
-                                            verticalAlign->getValueID())) {
-            node.mutableComputedStyle()->setVerticalAlign(
-                verticalAlign->convertTo<EVerticalAlign>());
-          }
-        }
-
-        // Pass EditingStyle::DoNotIgnoreTextOnlyProperties without checking if
-        // node.isTextNode() because the node can be an element node. See bug
-        // http://crbug.com/584939.
-        TriState nodeState = triStateOfStyle(
-            nodeStyle, EditingStyle::DoNotIgnoreTextOnlyProperties);
-        if (nodeIsStart) {
-          state = nodeState;
-          nodeIsStart = false;
-        } else if (state != nodeState && node.isTextNode()) {
-          state = MixedTriState;
-          break;
-        }
-      }
-    }
-    if (&node == selection.end().anchorNode())
-      break;
-  }
-
-  return state;
-}
-
-bool EditingStyle::conflictsWithInlineStyleOfElement(
-    HTMLElement* element,
-    EditingStyle* extractedStyle,
-    Vector<CSSPropertyID>* conflictingProperties) const {
-  DCHECK(element);
-  DCHECK(!conflictingProperties || conflictingProperties->isEmpty());
-
-  const StylePropertySet* inlineStyle = element->inlineStyle();
-  if (!m_mutableStyle || !inlineStyle)
-    return false;
-
-  unsigned propertyCount = m_mutableStyle->propertyCount();
-  for (unsigned i = 0; i < propertyCount; ++i) {
-    CSSPropertyID propertyID = m_mutableStyle->propertyAt(i).id();
-
-    // We don't override whitespace property of a tab span because that would
-    // collapse the tab into a space.
-    if (propertyID == CSSPropertyWhiteSpace && isTabHTMLSpanElement(element))
-      continue;
-
-    if (propertyID == CSSPropertyWebkitTextDecorationsInEffect &&
-        inlineStyle->getPropertyCSSValue(textDecorationPropertyForEditing())) {
-      if (!conflictingProperties)
-        return true;
-      conflictingProperties->push_back(CSSPropertyTextDecoration);
-      // Because text-decoration expands to text-decoration-line when CSS3
-      // Text Decoration is enabled, we also state it as conflicting.
-      if (RuntimeEnabledFeatures::css3TextDecorationsEnabled())
-        conflictingProperties->push_back(CSSPropertyTextDecorationLine);
-      if (extractedStyle) {
-        extractedStyle->setProperty(
-            textDecorationPropertyForEditing(),
-            inlineStyle->getPropertyValue(textDecorationPropertyForEditing()),
-            inlineStyle->propertyIsImportant(
-                textDecorationPropertyForEditing()));
-      }
-      continue;
-    }
-
-    if (!inlineStyle->getPropertyCSSValue(propertyID))
-      continue;
-
-    if (propertyID == CSSPropertyUnicodeBidi &&
-        inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) {
-      if (!conflictingProperties)
-        return true;
-      conflictingProperties->push_back(CSSPropertyDirection);
-      if (extractedStyle) {
-        extractedStyle->setProperty(
-            propertyID, inlineStyle->getPropertyValue(propertyID),
-            inlineStyle->propertyIsImportant(propertyID));
-      }
-    }
-
-    if (!conflictingProperties)
-      return true;
-
-    conflictingProperties->push_back(propertyID);
-
-    if (extractedStyle) {
-      extractedStyle->setProperty(propertyID,
-                                  inlineStyle->getPropertyValue(propertyID),
-                                  inlineStyle->propertyIsImportant(propertyID));
-    }
-  }
-
-  return conflictingProperties && !conflictingProperties->isEmpty();
-}
-
-static const HeapVector<Member<HTMLElementEquivalent>>&
-htmlElementEquivalents() {
-  DEFINE_STATIC_LOCAL(HeapVector<Member<HTMLElementEquivalent>>,
-                      HTMLElementEquivalents,
-                      (new HeapVector<Member<HTMLElementEquivalent>>));
-  if (!HTMLElementEquivalents.size()) {
-    HTMLElementEquivalents.push_back(HTMLElementEquivalent::create(
-        CSSPropertyFontWeight, CSSValueBold, HTMLNames::bTag));
-    HTMLElementEquivalents.push_back(HTMLElementEquivalent::create(
-        CSSPropertyFontWeight, CSSValueBold, HTMLNames::strongTag));
-    HTMLElementEquivalents.push_back(HTMLElementEquivalent::create(
-        CSSPropertyVerticalAlign, CSSValueSub, HTMLNames::subTag));
-    HTMLElementEquivalents.push_back(HTMLElementEquivalent::create(
-        CSSPropertyVerticalAlign, CSSValueSuper, HTMLNames::supTag));
-    HTMLElementEquivalents.push_back(HTMLElementEquivalent::create(
-        CSSPropertyFontStyle, CSSValueItalic, HTMLNames::iTag));
-    HTMLElementEquivalents.push_back(HTMLElementEquivalent::create(
-        CSSPropertyFontStyle, CSSValueItalic, HTMLNames::emTag));
-
-    HTMLElementEquivalents.push_back(HTMLTextDecorationEquivalent::create(
-        CSSValueUnderline, HTMLNames::uTag));
-    HTMLElementEquivalents.push_back(HTMLTextDecorationEquivalent::create(
-        CSSValueLineThrough, HTMLNames::sTag));
-    HTMLElementEquivalents.push_back(HTMLTextDecorationEquivalent::create(
-        CSSValueLineThrough, HTMLNames::strikeTag));
-  }
-
-  return HTMLElementEquivalents;
-}
-
-bool EditingStyle::conflictsWithImplicitStyleOfElement(
-    HTMLElement* element,
-    EditingStyle* extractedStyle,
-    ShouldExtractMatchingStyle shouldExtractMatchingStyle) const {
-  if (!m_mutableStyle)
-    return false;
-
-  const HeapVector<Member<HTMLElementEquivalent>>& HTMLElementEquivalents =
-      htmlElementEquivalents();
-  for (size_t i = 0; i < HTMLElementEquivalents.size(); ++i) {
-    const HTMLElementEquivalent* equivalent = HTMLElementEquivalents[i].get();
-    if (equivalent->matches(element) &&
-        equivalent->propertyExistsInStyle(m_mutableStyle.get()) &&
-        (shouldExtractMatchingStyle == ExtractMatchingStyle ||
-         !equivalent->valueIsPresentInStyle(element, m_mutableStyle.get()))) {
-      if (extractedStyle)
-        equivalent->addToStyle(element, extractedStyle);
-      return true;
-    }
-  }
-  return false;
-}
-
-static const HeapVector<Member<HTMLAttributeEquivalent>>&
-htmlAttributeEquivalents() {
-  DEFINE_STATIC_LOCAL(HeapVector<Member<HTMLAttributeEquivalent>>,
-                      HTMLAttributeEquivalents,
-                      (new HeapVector<Member<HTMLAttributeEquivalent>>));
-  if (!HTMLAttributeEquivalents.size()) {
-    // elementIsStyledSpanOrHTMLEquivalent depends on the fact each
-    // HTMLAttriuteEquivalent matches exactly one attribute of exactly one
-    // element except dirAttr.
-    HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create(
-        CSSPropertyColor, HTMLNames::fontTag, HTMLNames::colorAttr));
-    HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create(
-        CSSPropertyFontFamily, HTMLNames::fontTag, HTMLNames::faceAttr));
-    HTMLAttributeEquivalents.push_back(HTMLFontSizeEquivalent::create());
-
-    HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create(
-        CSSPropertyDirection, HTMLNames::dirAttr));
-    HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create(
-        CSSPropertyUnicodeBidi, HTMLNames::dirAttr));
-  }
-
-  return HTMLAttributeEquivalents;
-}
-
-bool EditingStyle::conflictsWithImplicitStyleOfAttributes(
-    HTMLElement* element) const {
-  DCHECK(element);
-  if (!m_mutableStyle)
-    return false;
-
-  const HeapVector<Member<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents =
-      htmlAttributeEquivalents();
-  for (const auto& equivalent : HTMLAttributeEquivalents) {
-    if (equivalent->matches(element) &&
-        equivalent->propertyExistsInStyle(m_mutableStyle.get()) &&
-        !equivalent->valueIsPresentInStyle(element, m_mutableStyle.get()))
-      return true;
-  }
-
-  return false;
-}
-
-bool EditingStyle::extractConflictingImplicitStyleOfAttributes(
-    HTMLElement* element,
-    ShouldPreserveWritingDirection shouldPreserveWritingDirection,
-    EditingStyle* extractedStyle,
-    Vector<QualifiedName>& conflictingAttributes,
-    ShouldExtractMatchingStyle shouldExtractMatchingStyle) const {
-  DCHECK(element);
-  // HTMLAttributeEquivalent::addToStyle doesn't support unicode-bidi and
-  // direction properties
-  if (extractedStyle)
-    DCHECK_EQ(shouldPreserveWritingDirection, PreserveWritingDirection);
-  if (!m_mutableStyle)
-    return false;
-
-  const HeapVector<Member<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents =
-      htmlAttributeEquivalents();
-  bool removed = false;
-  for (const auto& attribute : HTMLAttributeEquivalents) {
-    const HTMLAttributeEquivalent* equivalent = attribute.get();
-
-    // unicode-bidi and direction are pushed down separately so don't push down
-    // with other styles.
-    if (shouldPreserveWritingDirection == PreserveWritingDirection &&
-        equivalent->attributeName() == HTMLNames::dirAttr)
-      continue;
-
-    if (!equivalent->matches(element) ||
-        !equivalent->propertyExistsInStyle(m_mutableStyle.get()) ||
-        (shouldExtractMatchingStyle == DoNotExtractMatchingStyle &&
-         equivalent->valueIsPresentInStyle(element, m_mutableStyle.get())))
-      continue;
-
-    if (extractedStyle)
-      equivalent->addToStyle(element, extractedStyle);
-    conflictingAttributes.push_back(equivalent->attributeName());
-    removed = true;
-  }
-
-  return removed;
-}
-
-bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const {
-  return !m_mutableStyle ||
-         getPropertiesNotIn(m_mutableStyle.get(),
-                            CSSComputedStyleDeclaration::create(node))
-             ->isEmpty();
-}
-
-bool EditingStyle::elementIsStyledSpanOrHTMLEquivalent(
-    const HTMLElement* element) {
-  DCHECK(element);
-  bool elementIsSpanOrElementEquivalent = false;
-  if (isHTMLSpanElement(*element)) {
-    elementIsSpanOrElementEquivalent = true;
-  } else {
-    const HeapVector<Member<HTMLElementEquivalent>>& HTMLElementEquivalents =
-        htmlElementEquivalents();
-    size_t i;
-    for (i = 0; i < HTMLElementEquivalents.size(); ++i) {
-      if (HTMLElementEquivalents[i]->matches(element)) {
-        elementIsSpanOrElementEquivalent = true;
-        break;
-      }
-    }
-  }
-
-  AttributeCollection attributes = element->attributes();
-  if (attributes.isEmpty()) {
-    // span, b, etc... without any attributes
-    return elementIsSpanOrElementEquivalent;
-  }
-
-  unsigned matchedAttributes = 0;
-  const HeapVector<Member<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents =
-      htmlAttributeEquivalents();
-  for (const auto& equivalent : HTMLAttributeEquivalents) {
-    if (equivalent->matches(element) &&
-        equivalent->attributeName() != HTMLNames::dirAttr)
-      matchedAttributes++;
-  }
-
-  if (!elementIsSpanOrElementEquivalent && !matchedAttributes) {
-    // element is not a span, a html element equivalent, or font element.
-    return false;
-  }
-
-  if (element->getAttribute(HTMLNames::classAttr) == AppleStyleSpanClass)
-    matchedAttributes++;
-
-  if (element->hasAttribute(HTMLNames::styleAttr)) {
-    if (const StylePropertySet* style = element->inlineStyle()) {
-      unsigned propertyCount = style->propertyCount();
-      for (unsigned i = 0; i < propertyCount; ++i) {
-        if (!isEditingProperty(style->propertyAt(i).id()))
-          return false;
-      }
-    }
-    matchedAttributes++;
-  }
-
-  // font with color attribute, span with style attribute, etc...
-  DCHECK_LE(matchedAttributes, attributes.size());
-  return matchedAttributes >= attributes.size();
-}
-
-void EditingStyle::prepareToApplyAt(
-    const Position& position,
-    ShouldPreserveWritingDirection shouldPreserveWritingDirection) {
-  if (!m_mutableStyle)
-    return;
-
-  // ReplaceSelectionCommand::handleStyleSpans() requires that this function
-  // only removes the editing style. If this function was modified in the future
-  // to delete all redundant properties, then add a boolean value to indicate
-  // which one of editingStyleAtPosition or computedStyle is called.
-  EditingStyle* editingStyleAtPosition =
-      EditingStyle::create(position, EditingPropertiesInEffect);
-  StylePropertySet* styleAtPosition =
-      editingStyleAtPosition->m_mutableStyle.get();
-
-  const CSSValue* unicodeBidi = nullptr;
-  const CSSValue* direction = nullptr;
-  if (shouldPreserveWritingDirection == PreserveWritingDirection) {
-    unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
-    direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
-  }
-
-  m_mutableStyle->removeEquivalentProperties(styleAtPosition);
-
-  if (textAlignResolvingStartAndEnd(m_mutableStyle.get()) ==
-      textAlignResolvingStartAndEnd(styleAtPosition))
-    m_mutableStyle->removeProperty(CSSPropertyTextAlign);
-
-  if (getFontColor(m_mutableStyle.get()) == getFontColor(styleAtPosition))
-    m_mutableStyle->removeProperty(CSSPropertyColor);
-
-  if (hasTransparentBackgroundColor(m_mutableStyle.get()) ||
-      cssValueToColor(
-          m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor)) ==
-          backgroundColorInEffect(position.computeContainerNode()))
-    m_mutableStyle->removeProperty(CSSPropertyBackgroundColor);
-
-  if (unicodeBidi && unicodeBidi->isIdentifierValue()) {
-    m_mutableStyle->setProperty(
-        CSSPropertyUnicodeBidi,
-        toCSSIdentifierValue(unicodeBidi)->getValueID());
-    if (direction && direction->isIdentifierValue()) {
-      m_mutableStyle->setProperty(
-          CSSPropertyDirection, toCSSIdentifierValue(direction)->getValueID());
-    }
-  }
-}
-
-void EditingStyle::mergeTypingStyle(Document* document) {
-  DCHECK(document);
-
-  EditingStyle* typingStyle = document->frame()->selection().typingStyle();
-  if (!typingStyle || typingStyle == this)
-    return;
-
-  mergeStyle(typingStyle->style(), OverrideValues);
-}
-
-void EditingStyle::mergeInlineStyleOfElement(
-    HTMLElement* element,
-    CSSPropertyOverrideMode mode,
-    PropertiesToInclude propertiesToInclude) {
-  DCHECK(element);
-  if (!element->inlineStyle())
-    return;
-
-  switch (propertiesToInclude) {
-    case AllProperties:
-      mergeStyle(element->inlineStyle(), mode);
-      return;
-    case OnlyEditingInheritableProperties:
-      mergeStyle(copyEditingProperties(element->inlineStyle(),
-                                       OnlyInheritableEditingProperties),
-                 mode);
-      return;
-    case EditingPropertiesInEffect:
-      mergeStyle(
-          copyEditingProperties(element->inlineStyle(), AllEditingProperties),
-          mode);
-      return;
-  }
-}
-
-static inline bool elementMatchesAndPropertyIsNotInInlineStyleDecl(
-    const HTMLElementEquivalent* equivalent,
-    const Element* element,
-    EditingStyle::CSSPropertyOverrideMode mode,
-    StylePropertySet* style) {
-  return equivalent->matches(element) &&
-         (!element->inlineStyle() ||
-          !equivalent->propertyExistsInStyle(element->inlineStyle())) &&
-         (mode == EditingStyle::OverrideValues ||
-          !equivalent->propertyExistsInStyle(style));
-}
-
-static MutableStylePropertySet* extractEditingProperties(
-    const StylePropertySet* style,
-    EditingStyle::PropertiesToInclude propertiesToInclude) {
-  if (!style)
-    return nullptr;
-
-  switch (propertiesToInclude) {
-    case EditingStyle::AllProperties:
-    case EditingStyle::EditingPropertiesInEffect:
-      return copyEditingProperties(style, AllEditingProperties);
-    case EditingStyle::OnlyEditingInheritableProperties:
-      return copyEditingProperties(style, OnlyInheritableEditingProperties);
-  }
-
-  NOTREACHED();
-  return nullptr;
-}
-
-void EditingStyle::mergeInlineAndImplicitStyleOfElement(
-    Element* element,
-    CSSPropertyOverrideMode mode,
-    PropertiesToInclude propertiesToInclude) {
-  EditingStyle* styleFromRules = EditingStyle::create();
-  styleFromRules->mergeStyleFromRulesForSerialization(element);
-
-  if (element->inlineStyle()) {
-    styleFromRules->m_mutableStyle->mergeAndOverrideOnConflict(
-        element->inlineStyle());
-  }
-
-  styleFromRules->m_mutableStyle = extractEditingProperties(
-      styleFromRules->m_mutableStyle.get(), propertiesToInclude);
-  mergeStyle(styleFromRules->m_mutableStyle.get(), mode);
-
-  const HeapVector<Member<HTMLElementEquivalent>>& elementEquivalents =
-      htmlElementEquivalents();
-  for (const auto& equivalent : elementEquivalents) {
-    if (elementMatchesAndPropertyIsNotInInlineStyleDecl(
-            equivalent.get(), element, mode, m_mutableStyle.get()))
-      equivalent->addToStyle(element, this);
-  }
-
-  const HeapVector<Member<HTMLAttributeEquivalent>>& attributeEquivalents =
-      htmlAttributeEquivalents();
-  for (const auto& attribute : attributeEquivalents) {
-    if (attribute->attributeName() == HTMLNames::dirAttr)
-      continue;  // We don't want to include directionality
-    if (elementMatchesAndPropertyIsNotInInlineStyleDecl(
-            attribute.get(), element, mode, m_mutableStyle.get()))
-      attribute->addToStyle(element, this);
-  }
-}
-
-EditingStyle* EditingStyle::wrappingStyleForAnnotatedSerialization(
+EditingStyle* EditingStyleUtilities::wrappingStyleForAnnotatedSerialization(
     ContainerNode* context) {
   EditingStyle* wrappingStyle =
       EditingStyle::create(context, EditingStyle::EditingPropertiesInEffect);
@@ -1277,7 +67,7 @@
   return wrappingStyle;
 }
 
-EditingStyle* EditingStyle::wrappingStyleForSerialization(
+EditingStyle* EditingStyleUtilities::wrappingStyleForSerialization(
     ContainerNode* context) {
   DCHECK(context);
   EditingStyle* wrappingStyle = EditingStyle::create();
@@ -1297,246 +87,7 @@
   return wrappingStyle;
 }
 
-static const CSSValueList& mergeTextDecorationValues(
-    const CSSValueList& mergedValue,
-    const CSSValueList& valueToMerge) {
-  DEFINE_STATIC_LOCAL(CSSIdentifierValue, underline,
-                      (CSSIdentifierValue::create(CSSValueUnderline)));
-  DEFINE_STATIC_LOCAL(CSSIdentifierValue, lineThrough,
-                      (CSSIdentifierValue::create(CSSValueLineThrough)));
-  CSSValueList& result = *mergedValue.copy();
-  if (valueToMerge.hasValue(underline) && !mergedValue.hasValue(underline))
-    result.append(underline);
-
-  if (valueToMerge.hasValue(lineThrough) && !mergedValue.hasValue(lineThrough))
-    result.append(lineThrough);
-
-  return result;
-}
-
-void EditingStyle::mergeStyle(const StylePropertySet* style,
-                              CSSPropertyOverrideMode mode) {
-  if (!style)
-    return;
-
-  if (!m_mutableStyle) {
-    m_mutableStyle = style->mutableCopy();
-    return;
-  }
-
-  unsigned propertyCount = style->propertyCount();
-  for (unsigned i = 0; i < propertyCount; ++i) {
-    StylePropertySet::PropertyReference property = style->propertyAt(i);
-    const CSSValue* value = m_mutableStyle->getPropertyCSSValue(property.id());
-
-    // text decorations never override values
-    if ((property.id() == textDecorationPropertyForEditing() ||
-         property.id() == CSSPropertyWebkitTextDecorationsInEffect) &&
-        property.value().isValueList() && value) {
-      if (value->isValueList()) {
-        const CSSValueList& result = mergeTextDecorationValues(
-            *toCSSValueList(value), toCSSValueList(property.value()));
-        m_mutableStyle->setProperty(property.id(), result,
-                                    property.isImportant());
-        continue;
-      }
-      // text-decoration: none is equivalent to not having the property
-      value = nullptr;
-    }
-
-    if (mode == OverrideValues || (mode == DoNotOverrideValues && !value))
-      m_mutableStyle->setProperty(property.toCSSProperty());
-  }
-}
-
-static MutableStylePropertySet* styleFromMatchedRulesForElement(
-    Element* element,
-    unsigned rulesToInclude) {
-  MutableStylePropertySet* style =
-      MutableStylePropertySet::create(HTMLQuirksMode);
-  StyleRuleList* matchedRules =
-      element->document().ensureStyleResolver().styleRulesForElement(
-          element, rulesToInclude);
-  if (matchedRules) {
-    for (unsigned i = 0; i < matchedRules->size(); ++i)
-      style->mergeAndOverrideOnConflict(&matchedRules->at(i)->properties());
-  }
-  return style;
-}
-
-void EditingStyle::mergeStyleFromRules(Element* element) {
-  MutableStylePropertySet* styleFromMatchedRules =
-      styleFromMatchedRulesForElement(
-          element,
-          StyleResolver::AuthorCSSRules | StyleResolver::CrossOriginCSSRules);
-  // Styles from the inline style declaration, held in the variable "style",
-  // take precedence over those from matched rules.
-  if (m_mutableStyle)
-    styleFromMatchedRules->mergeAndOverrideOnConflict(m_mutableStyle.get());
-
-  clear();
-  m_mutableStyle = styleFromMatchedRules;
-}
-
-void EditingStyle::mergeStyleFromRulesForSerialization(Element* element) {
-  mergeStyleFromRules(element);
-
-  // The property value, if it's a percentage, may not reflect the actual
-  // computed value.
-  // For example: style="height: 1%; overflow: visible;" in quirksmode
-  // FIXME: There are others like this, see <rdar://problem/5195123> Slashdot
-  // copy/paste fidelity problem
-  CSSComputedStyleDeclaration* computedStyleForElement =
-      CSSComputedStyleDeclaration::create(element);
-  MutableStylePropertySet* fromComputedStyle =
-      MutableStylePropertySet::create(HTMLQuirksMode);
-  {
-    unsigned propertyCount = m_mutableStyle->propertyCount();
-    for (unsigned i = 0; i < propertyCount; ++i) {
-      StylePropertySet::PropertyReference property =
-          m_mutableStyle->propertyAt(i);
-      const CSSValue& value = property.value();
-      if (!value.isPrimitiveValue())
-        continue;
-      if (toCSSPrimitiveValue(value).isPercentage()) {
-        if (const CSSValue* computedPropertyValue =
-                computedStyleForElement->getPropertyCSSValue(property.id())) {
-          fromComputedStyle->addRespectingCascade(
-              CSSProperty(property.id(), *computedPropertyValue));
-        }
-      }
-    }
-  }
-  m_mutableStyle->mergeAndOverrideOnConflict(fromComputedStyle);
-}
-
-static void removePropertiesInStyle(
-    MutableStylePropertySet* styleToRemovePropertiesFrom,
-    StylePropertySet* style) {
-  unsigned propertyCount = style->propertyCount();
-  Vector<CSSPropertyID> propertiesToRemove(propertyCount);
-  for (unsigned i = 0; i < propertyCount; ++i)
-    propertiesToRemove[i] = style->propertyAt(i).id();
-
-  styleToRemovePropertiesFrom->removePropertiesInSet(propertiesToRemove.data(),
-                                                     propertiesToRemove.size());
-}
-
-void EditingStyle::removeStyleFromRulesAndContext(Element* element,
-                                                  ContainerNode* context) {
-  DCHECK(element);
-  if (!m_mutableStyle)
-    return;
-
-  // StyleResolver requires clean style.
-  DCHECK_GE(element->document().lifecycle().state(),
-            DocumentLifecycle::StyleClean);
-  DCHECK(element->document().isActive());
-
-  // 1. Remove style from matched rules because style remain without repeating
-  // it in inline style declaration
-  MutableStylePropertySet* styleFromMatchedRules =
-      styleFromMatchedRulesForElement(element,
-                                      StyleResolver::AllButEmptyCSSRules);
-  if (styleFromMatchedRules && !styleFromMatchedRules->isEmpty()) {
-    m_mutableStyle =
-        getPropertiesNotIn(m_mutableStyle.get(),
-                           styleFromMatchedRules->ensureCSSStyleDeclaration());
-  }
-
-  // 2. Remove style present in context and not overriden by matched rules.
-  EditingStyle* computedStyle =
-      EditingStyle::create(context, EditingPropertiesInEffect);
-  if (computedStyle->m_mutableStyle) {
-    if (!computedStyle->m_mutableStyle->getPropertyCSSValue(
-            CSSPropertyBackgroundColor)) {
-      computedStyle->m_mutableStyle->setProperty(CSSPropertyBackgroundColor,
-                                                 CSSValueTransparent);
-    }
-
-    removePropertiesInStyle(computedStyle->m_mutableStyle.get(),
-                            styleFromMatchedRules);
-    m_mutableStyle = getPropertiesNotIn(
-        m_mutableStyle.get(),
-        computedStyle->m_mutableStyle->ensureCSSStyleDeclaration());
-  }
-
-  // 3. If this element is a span and has display: inline or float: none, remove
-  // them unless they are overriden by rules. These rules are added by
-  // serialization code to wrap text nodes.
-  if (isStyleSpanOrSpanWithOnlyStyleAttribute(element)) {
-    if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyDisplay) &&
-        getIdentifierValue(m_mutableStyle.get(), CSSPropertyDisplay) ==
-            CSSValueInline)
-      m_mutableStyle->removeProperty(CSSPropertyDisplay);
-    if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyFloat) &&
-        getIdentifierValue(m_mutableStyle.get(), CSSPropertyFloat) ==
-            CSSValueNone)
-      m_mutableStyle->removeProperty(CSSPropertyFloat);
-  }
-}
-
-void EditingStyle::removePropertiesInElementDefaultStyle(Element* element) {
-  if (!m_mutableStyle || m_mutableStyle->isEmpty())
-    return;
-
-  StylePropertySet* defaultStyle = styleFromMatchedRulesForElement(
-      element, StyleResolver::UAAndUserCSSRules);
-
-  removePropertiesInStyle(m_mutableStyle.get(), defaultStyle);
-}
-
-void EditingStyle::addAbsolutePositioningFromElement(const Element& element) {
-  LayoutRect rect = element.boundingBox();
-  LayoutObject* layoutObject = element.layoutObject();
-
-  LayoutUnit x = rect.x();
-  LayoutUnit y = rect.y();
-  LayoutUnit width = rect.width();
-  LayoutUnit height = rect.height();
-  if (layoutObject && layoutObject->isBox()) {
-    LayoutBox* layoutBox = toLayoutBox(layoutObject);
-
-    x -= layoutBox->marginLeft();
-    y -= layoutBox->marginTop();
-
-    m_mutableStyle->setProperty(CSSPropertyBoxSizing, CSSValueBorderBox);
-  }
-
-  m_mutableStyle->setProperty(CSSPropertyPosition, CSSValueAbsolute);
-  m_mutableStyle->setProperty(
-      CSSPropertyLeft,
-      *CSSPrimitiveValue::create(x, CSSPrimitiveValue::UnitType::Pixels));
-  m_mutableStyle->setProperty(
-      CSSPropertyTop,
-      *CSSPrimitiveValue::create(y, CSSPrimitiveValue::UnitType::Pixels));
-  m_mutableStyle->setProperty(
-      CSSPropertyWidth,
-      *CSSPrimitiveValue::create(width, CSSPrimitiveValue::UnitType::Pixels));
-  m_mutableStyle->setProperty(
-      CSSPropertyHeight,
-      *CSSPrimitiveValue::create(height, CSSPrimitiveValue::UnitType::Pixels));
-}
-
-void EditingStyle::forceInline() {
-  if (!m_mutableStyle)
-    m_mutableStyle = MutableStylePropertySet::create(HTMLQuirksMode);
-  const bool propertyIsImportant = true;
-  m_mutableStyle->setProperty(CSSPropertyDisplay, CSSValueInline,
-                              propertyIsImportant);
-}
-
-int EditingStyle::legacyFontSize(Document* document) const {
-  const CSSValue* cssValue =
-      m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize);
-  if (!cssValue ||
-      !(cssValue->isPrimitiveValue() || cssValue->isIdentifierValue()))
-    return 0;
-  return legacyFontSizeFromCSSValue(document, cssValue, m_isMonospaceFont,
-                                    AlwaysUseLegacyFontSize);
-}
-
-EditingStyle* EditingStyle::styleAtSelectionStart(
+EditingStyle* EditingStyleUtilities::styleAtSelectionStart(
     const VisibleSelection& selection,
     bool shouldUseBackgroundColorInEffect,
     MutableStylePropertySet* styleToCheck) {
@@ -1585,7 +136,7 @@
     if (getIdentifierValue(elementStyle, CSSPropertyVerticalAlign) ==
             CSSValueBaseline &&
         hasAncestorVerticalAlignStyle(*element, valueID))
-      style->m_mutableStyle->setProperty(CSSPropertyVerticalAlign, valueID);
+      style->style()->setProperty(CSSPropertyVerticalAlign, valueID);
   }
 
   // If background color is transparent, traverse parent nodes until we hit a
@@ -1593,8 +144,7 @@
   // the background color at the start of selection, and find the background
   // color of the common ancestor.
   if (shouldUseBackgroundColorInEffect &&
-      (selection.isRange() ||
-       hasTransparentBackgroundColor(style->m_mutableStyle.get()))) {
+      (selection.isRange() || hasTransparentBackgroundColor(style->style()))) {
     const EphemeralRange range(selection.toNormalizedEphemeralRange());
     if (const CSSValue* value =
             backgroundColorValueInEffect(Range::commonAncestorContainer(
@@ -1614,7 +164,7 @@
          valueID == CSSValueIsolateOverride || valueID == CSSValuePlaintext;
 }
 
-WritingDirection EditingStyle::textDirectionForSelection(
+WritingDirection EditingStyleUtilities::textDirectionForSelection(
     const VisibleSelection& selection,
     EditingStyle* typingStyle,
     bool& hasNestedOrMultipleEmbeddings) {
@@ -1717,318 +267,7 @@
   return foundDirection;
 }
 
-DEFINE_TRACE(EditingStyle) {
-  visitor->trace(m_mutableStyle);
-}
-
-static void reconcileTextDecorationProperties(MutableStylePropertySet* style) {
-  const CSSValue* textDecorationsInEffect =
-      style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
-  const CSSValue* textDecoration =
-      style->getPropertyCSSValue(textDecorationPropertyForEditing());
-  // "LayoutTests/editing/execCommand/insert-list-and-strikethrough.html" makes
-  // both |textDecorationsInEffect| and |textDecoration| non-null.
-  if (textDecorationsInEffect) {
-    style->setProperty(textDecorationPropertyForEditing(),
-                       textDecorationsInEffect->cssText());
-    style->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
-    textDecoration = textDecorationsInEffect;
-  }
-
-  // If text-decoration is set to "none", remove the property because we don't
-  // want to add redundant "text-decoration: none".
-  if (textDecoration && !textDecoration->isValueList())
-    style->removeProperty(textDecorationPropertyForEditing());
-}
-
-StyleChange::StyleChange(EditingStyle* style, const Position& position)
-    : m_applyBold(false),
-      m_applyItalic(false),
-      m_applyUnderline(false),
-      m_applyLineThrough(false),
-      m_applySubscript(false),
-      m_applySuperscript(false) {
-  Document* document = position.document();
-  if (!style || !style->style() || !document || !document->frame() ||
-      !associatedElementOf(position))
-    return;
-
-  CSSComputedStyleDeclaration* computedStyle = ensureComputedStyle(position);
-  // FIXME: take care of background-color in effect
-  MutableStylePropertySet* mutableStyle =
-      getPropertiesNotIn(style->style(), computedStyle);
-  DCHECK(mutableStyle);
-
-  reconcileTextDecorationProperties(mutableStyle);
-  if (!document->frame()->editor().shouldStyleWithCSS())
-    extractTextStyles(document, mutableStyle, computedStyle->isMonospaceFont());
-
-  // Changing the whitespace style in a tab span would collapse the tab into a
-  // space.
-  if (isTabHTMLSpanElementTextNode(position.anchorNode()) ||
-      isTabHTMLSpanElement((position.anchorNode())))
-    mutableStyle->removeProperty(CSSPropertyWhiteSpace);
-
-  // If unicode-bidi is present in mutableStyle and direction is not, then add
-  // direction to mutableStyle.
-  // FIXME: Shouldn't this be done in getPropertiesNotIn?
-  if (mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi) &&
-      !style->style()->getPropertyCSSValue(CSSPropertyDirection)) {
-    mutableStyle->setProperty(
-        CSSPropertyDirection,
-        style->style()->getPropertyValue(CSSPropertyDirection));
-  }
-
-  // Save the result for later
-  m_cssStyle = mutableStyle->asText().stripWhiteSpace();
-}
-
-static void setTextDecorationProperty(MutableStylePropertySet* style,
-                                      const CSSValueList* newTextDecoration,
-                                      CSSPropertyID propertyID) {
-  if (newTextDecoration->length()) {
-    style->setProperty(propertyID, newTextDecoration->cssText(),
-                       style->propertyIsImportant(propertyID));
-  } else {
-    // text-decoration: none is redundant since it does not remove any text
-    // decorations.
-    style->removeProperty(propertyID);
-  }
-}
-
-void StyleChange::extractTextStyles(Document* document,
-                                    MutableStylePropertySet* style,
-                                    bool isMonospaceFont) {
-  DCHECK(style);
-
-  if (getIdentifierValue(style, CSSPropertyFontWeight) == CSSValueBold) {
-    style->removeProperty(CSSPropertyFontWeight);
-    m_applyBold = true;
-  }
-
-  int fontStyle = getIdentifierValue(style, CSSPropertyFontStyle);
-  if (fontStyle == CSSValueItalic || fontStyle == CSSValueOblique) {
-    style->removeProperty(CSSPropertyFontStyle);
-    m_applyItalic = true;
-  }
-
-  // Assuming reconcileTextDecorationProperties has been called, there should
-  // not be -webkit-text-decorations-in-effect
-  // Furthermore, text-decoration: none has been trimmed so that text-decoration
-  // property is always a CSSValueList.
-  const CSSValue* textDecoration =
-      style->getPropertyCSSValue(textDecorationPropertyForEditing());
-  if (textDecoration && textDecoration->isValueList()) {
-    DEFINE_STATIC_LOCAL(CSSIdentifierValue, underline,
-                        (CSSIdentifierValue::create(CSSValueUnderline)));
-    DEFINE_STATIC_LOCAL(CSSIdentifierValue, lineThrough,
-                        (CSSIdentifierValue::create(CSSValueLineThrough)));
-    CSSValueList* newTextDecoration = toCSSValueList(textDecoration)->copy();
-    if (newTextDecoration->removeAll(underline))
-      m_applyUnderline = true;
-    if (newTextDecoration->removeAll(lineThrough))
-      m_applyLineThrough = true;
-
-    // If trimTextDecorations, delete underline and line-through
-    setTextDecorationProperty(style, newTextDecoration,
-                              textDecorationPropertyForEditing());
-  }
-
-  int verticalAlign = getIdentifierValue(style, CSSPropertyVerticalAlign);
-  switch (verticalAlign) {
-    case CSSValueSub:
-      style->removeProperty(CSSPropertyVerticalAlign);
-      m_applySubscript = true;
-      break;
-    case CSSValueSuper:
-      style->removeProperty(CSSPropertyVerticalAlign);
-      m_applySuperscript = true;
-      break;
-  }
-
-  if (style->getPropertyCSSValue(CSSPropertyColor)) {
-    m_applyFontColor = getFontColor(style).serialized();
-    style->removeProperty(CSSPropertyColor);
-  }
-
-  m_applyFontFace = style->getPropertyValue(CSSPropertyFontFamily);
-  // Remove double quotes for Outlook 2007 compatibility. See
-  // https://bugs.webkit.org/show_bug.cgi?id=79448
-  m_applyFontFace.replace('"', "");
-  style->removeProperty(CSSPropertyFontFamily);
-
-  if (const CSSValue* fontSize =
-          style->getPropertyCSSValue(CSSPropertyFontSize)) {
-    if (!fontSize->isPrimitiveValue() && !fontSize->isIdentifierValue()) {
-      // Can't make sense of the number. Put no font size.
-      style->removeProperty(CSSPropertyFontSize);
-    } else if (int legacyFontSize = legacyFontSizeFromCSSValue(
-                   document, fontSize, isMonospaceFont,
-                   UseLegacyFontSizeOnlyIfPixelValuesMatch)) {
-      m_applyFontSize = String::number(legacyFontSize);
-      style->removeProperty(CSSPropertyFontSize);
-    }
-  }
-}
-
-static void diffTextDecorations(MutableStylePropertySet* style,
-                                CSSPropertyID propertyID,
-                                const CSSValue* refTextDecoration) {
-  const CSSValue* textDecoration = style->getPropertyCSSValue(propertyID);
-  if (!textDecoration || !textDecoration->isValueList() || !refTextDecoration ||
-      !refTextDecoration->isValueList())
-    return;
-
-  CSSValueList* newTextDecoration = toCSSValueList(textDecoration)->copy();
-  const CSSValueList* valuesInRefTextDecoration =
-      toCSSValueList(refTextDecoration);
-
-  for (size_t i = 0; i < valuesInRefTextDecoration->length(); i++)
-    newTextDecoration->removeAll(valuesInRefTextDecoration->item(i));
-
-  setTextDecorationProperty(style, newTextDecoration, propertyID);
-}
-
-static bool fontWeightIsBold(const CSSValue* fontWeight) {
-  if (!fontWeight->isIdentifierValue())
-    return false;
-
-  // Because b tag can only bold text, there are only two states in plain html:
-  // bold and not bold. Collapse all other values to either one of these two
-  // states for editing purposes.
-  switch (toCSSIdentifierValue(fontWeight)->getValueID()) {
-    case CSSValue100:
-    case CSSValue200:
-    case CSSValue300:
-    case CSSValue400:
-    case CSSValue500:
-    case CSSValueNormal:
-      return false;
-    case CSSValueBold:
-    case CSSValue600:
-    case CSSValue700:
-    case CSSValue800:
-    case CSSValue900:
-      return true;
-    default:
-      break;
-  }
-
-  NOTREACHED();  // For CSSValueBolder and CSSValueLighter
-  return false;
-}
-
-static bool fontWeightNeedsResolving(const CSSValue* fontWeight) {
-  if (!fontWeight->isIdentifierValue())
-    return true;
-
-  const CSSValueID value = toCSSIdentifierValue(fontWeight)->getValueID();
-  return value == CSSValueLighter || value == CSSValueBolder;
-}
-
-MutableStylePropertySet* getPropertiesNotIn(
-    StylePropertySet* styleWithRedundantProperties,
-    CSSStyleDeclaration* baseStyle) {
-  DCHECK(styleWithRedundantProperties);
-  DCHECK(baseStyle);
-  MutableStylePropertySet* result = styleWithRedundantProperties->mutableCopy();
-
-  result->removeEquivalentProperties(baseStyle);
-
-  const CSSValue* baseTextDecorationsInEffect =
-      baseStyle->getPropertyCSSValueInternal(
-          CSSPropertyWebkitTextDecorationsInEffect);
-  diffTextDecorations(result, textDecorationPropertyForEditing(),
-                      baseTextDecorationsInEffect);
-  diffTextDecorations(result, CSSPropertyWebkitTextDecorationsInEffect,
-                      baseTextDecorationsInEffect);
-
-  if (const CSSValue* baseFontWeight =
-          baseStyle->getPropertyCSSValueInternal(CSSPropertyFontWeight)) {
-    if (const CSSValue* fontWeight =
-            result->getPropertyCSSValue(CSSPropertyFontWeight)) {
-      if (!fontWeightNeedsResolving(fontWeight) &&
-          !fontWeightNeedsResolving(baseFontWeight) &&
-          (fontWeightIsBold(fontWeight) == fontWeightIsBold(baseFontWeight)))
-        result->removeProperty(CSSPropertyFontWeight);
-    }
-  }
-
-  if (baseStyle->getPropertyCSSValueInternal(CSSPropertyColor) &&
-      getFontColor(result) == getFontColor(baseStyle))
-    result->removeProperty(CSSPropertyColor);
-
-  if (baseStyle->getPropertyCSSValueInternal(CSSPropertyTextAlign) &&
-      textAlignResolvingStartAndEnd(result) ==
-          textAlignResolvingStartAndEnd(baseStyle))
-    result->removeProperty(CSSPropertyTextAlign);
-
-  if (baseStyle->getPropertyCSSValueInternal(CSSPropertyBackgroundColor) &&
-      getBackgroundColor(result) == getBackgroundColor(baseStyle))
-    result->removeProperty(CSSPropertyBackgroundColor);
-
-  return result;
-}
-
-CSSValueID getIdentifierValue(StylePropertySet* style,
-                              CSSPropertyID propertyID) {
-  if (!style)
-    return CSSValueInvalid;
-  const CSSValue* value = style->getPropertyCSSValue(propertyID);
-  if (!value || !value->isIdentifierValue())
-    return CSSValueInvalid;
-  return toCSSIdentifierValue(value)->getValueID();
-}
-
-CSSValueID getIdentifierValue(CSSStyleDeclaration* style,
-                              CSSPropertyID propertyID) {
-  if (!style)
-    return CSSValueInvalid;
-  const CSSValue* value = style->getPropertyCSSValueInternal(propertyID);
-  if (!value || !value->isIdentifierValue())
-    return CSSValueInvalid;
-  return toCSSIdentifierValue(value)->getValueID();
-}
-
-int legacyFontSizeFromCSSValue(Document* document,
-                               const CSSValue* value,
-                               bool isMonospaceFont,
-                               LegacyFontSizeMode mode) {
-  if (value->isPrimitiveValue()) {
-    const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(*value);
-    CSSPrimitiveValue::LengthUnitType lengthType;
-    if (CSSPrimitiveValue::unitTypeToLengthUnitType(
-            primitiveValue.typeWithCalcResolved(), lengthType) &&
-        lengthType == CSSPrimitiveValue::UnitTypePixels) {
-      double conversion =
-          CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(
-              primitiveValue.typeWithCalcResolved());
-      int pixelFontSize =
-          clampTo<int>(primitiveValue.getDoubleValue() * conversion);
-      int legacyFontSize =
-          FontSize::legacyFontSize(document, pixelFontSize, isMonospaceFont);
-      // Use legacy font size only if pixel value matches exactly to that of
-      // legacy font size.
-      if (mode == AlwaysUseLegacyFontSize ||
-          FontSize::fontSizeForKeyword(document, legacyFontSize,
-                                       isMonospaceFont) == pixelFontSize)
-        return legacyFontSize;
-
-      return 0;
-    }
-  }
-
-  if (value->isIdentifierValue()) {
-    const CSSIdentifierValue& identifierValue = toCSSIdentifierValue(*value);
-    if (CSSValueXSmall <= identifierValue.getValueID() &&
-        identifierValue.getValueID() <= CSSValueWebkitXxxLarge)
-      return identifierValue.getValueID() - CSSValueXSmall + 1;
-  }
-
-  return 0;
-}
-
-bool isTransparentColorValue(const CSSValue* cssValue) {
+bool EditingStyleUtilities::isTransparentColorValue(const CSSValue* cssValue) {
   if (!cssValue)
     return true;
   if (cssValue->isColorValue())
@@ -2038,19 +277,22 @@
   return toCSSIdentifierValue(cssValue)->getValueID() == CSSValueTransparent;
 }
 
-bool hasTransparentBackgroundColor(CSSStyleDeclaration* style) {
+bool EditingStyleUtilities::hasTransparentBackgroundColor(
+    CSSStyleDeclaration* style) {
   const CSSValue* cssValue =
       style->getPropertyCSSValueInternal(CSSPropertyBackgroundColor);
   return isTransparentColorValue(cssValue);
 }
 
-bool hasTransparentBackgroundColor(StylePropertySet* style) {
+bool EditingStyleUtilities::hasTransparentBackgroundColor(
+    StylePropertySet* style) {
   const CSSValue* cssValue =
       style->getPropertyCSSValue(CSSPropertyBackgroundColor);
   return isTransparentColorValue(cssValue);
 }
 
-const CSSValue* backgroundColorValueInEffect(Node* node) {
+const CSSValue* EditingStyleUtilities::backgroundColorValueInEffect(
+    Node* node) {
   for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) {
     CSSComputedStyleDeclaration* ancestorStyle =
         CSSComputedStyleDeclaration::create(ancestor);
diff --git a/third_party/WebKit/Source/core/editing/EditingStyleUtilities.h b/third_party/WebKit/Source/core/editing/EditingStyleUtilities.h
index 6c8d53a0..0f4e7fa 100644
--- a/third_party/WebKit/Source/core/editing/EditingStyleUtilities.h
+++ b/third_party/WebKit/Source/core/editing/EditingStyleUtilities.h
@@ -34,134 +34,24 @@
 
 #include "core/CSSPropertyNames.h"
 #include "core/CSSValueKeywords.h"
-#include "core/CoreExport.h"
-#include "core/editing/Position.h"
 #include "core/editing/VisibleSelection.h"
 #include "core/editing/WritingDirection.h"
-#include "platform/heap/Handle.h"
-#include "wtf/Forward.h"
-#include "wtf/TriState.h"
-#include "wtf/Vector.h"
-#include "wtf/text/WTFString.h"
 
 namespace blink {
 
 class CSSStyleDeclaration;
-class CSSComputedStyleDeclaration;
-class ContainerNode;
-class Document;
-class Element;
-class HTMLElement;
+class EditingStyle;
 class MutableStylePropertySet;
 class Node;
-class QualifiedName;
-class ComputedStyle;
 class StylePropertySet;
 
-class CORE_EXPORT EditingStyle final : public GarbageCollected<EditingStyle> {
+class EditingStyleUtilities {
+  STATIC_ONLY(EditingStyleUtilities);
+
  public:
-  enum PropertiesToInclude {
-    AllProperties,
-    OnlyEditingInheritableProperties,
-    EditingPropertiesInEffect
-  };
-  enum ShouldPreserveWritingDirection {
-    PreserveWritingDirection,
-    DoNotPreserveWritingDirection
-  };
-  enum ShouldExtractMatchingStyle {
-    ExtractMatchingStyle,
-    DoNotExtractMatchingStyle
-  };
-  static float NoFontDelta;
-
-  static EditingStyle* create() { return new EditingStyle(); }
-
-  static EditingStyle* create(ContainerNode* node,
-                              PropertiesToInclude propertiesToInclude =
-                                  OnlyEditingInheritableProperties) {
-    return new EditingStyle(node, propertiesToInclude);
-  }
-
-  static EditingStyle* create(const Position& position,
-                              PropertiesToInclude propertiesToInclude =
-                                  OnlyEditingInheritableProperties) {
-    return new EditingStyle(position, propertiesToInclude);
-  }
-
-  static EditingStyle* create(const StylePropertySet* style) {
-    return new EditingStyle(style);
-  }
-
-  static EditingStyle* create(CSSPropertyID propertyID, const String& value) {
-    return new EditingStyle(propertyID, value);
-  }
-
-  MutableStylePropertySet* style() { return m_mutableStyle.get(); }
-  bool textDirection(WritingDirection&) const;
-  bool isEmpty() const;
-  void overrideWithStyle(const StylePropertySet*);
-  void clear();
-  EditingStyle* copy() const;
-  EditingStyle* extractAndRemoveBlockProperties();
-  EditingStyle* extractAndRemoveTextDirection();
-  void removeBlockProperties();
-  void removeStyleAddedByElement(Element*);
-  void removeStyleConflictingWithStyleOfElement(Element*);
-  void collapseTextDecorationProperties();
-  enum ShouldIgnoreTextOnlyProperties {
-    IgnoreTextOnlyProperties,
-    DoNotIgnoreTextOnlyProperties
-  };
-  TriState triStateOfStyle(EditingStyle*) const;
-  TriState triStateOfStyle(const VisibleSelection&) const;
-  bool conflictsWithInlineStyleOfElement(HTMLElement* element) const {
-    return conflictsWithInlineStyleOfElement(element, 0, 0);
-  }
-  bool conflictsWithInlineStyleOfElement(
-      HTMLElement* element,
-      EditingStyle* extractedStyle,
-      Vector<CSSPropertyID>& conflictingProperties) const {
-    return conflictsWithInlineStyleOfElement(element, extractedStyle,
-                                             &conflictingProperties);
-  }
-  bool conflictsWithImplicitStyleOfElement(
-      HTMLElement*,
-      EditingStyle* extractedStyle = nullptr,
-      ShouldExtractMatchingStyle = DoNotExtractMatchingStyle) const;
-  bool conflictsWithImplicitStyleOfAttributes(HTMLElement*) const;
-  bool extractConflictingImplicitStyleOfAttributes(
-      HTMLElement*,
-      ShouldPreserveWritingDirection,
-      EditingStyle* extractedStyle,
-      Vector<QualifiedName>& conflictingAttributes,
-      ShouldExtractMatchingStyle) const;
-  bool styleIsPresentInComputedStyleOfNode(Node*) const;
-
-  static bool elementIsStyledSpanOrHTMLEquivalent(const HTMLElement*);
-
-  void prepareToApplyAt(
-      const Position&,
-      ShouldPreserveWritingDirection = DoNotPreserveWritingDirection);
-  void mergeTypingStyle(Document*);
-  enum CSSPropertyOverrideMode { OverrideValues, DoNotOverrideValues };
-  void mergeInlineStyleOfElement(HTMLElement*,
-                                 CSSPropertyOverrideMode,
-                                 PropertiesToInclude = AllProperties);
   static EditingStyle* wrappingStyleForAnnotatedSerialization(
       ContainerNode* context);
   static EditingStyle* wrappingStyleForSerialization(ContainerNode* context);
-  void mergeStyleFromRules(Element*);
-  void mergeStyleFromRulesForSerialization(Element*);
-  void removeStyleFromRulesAndContext(Element*, ContainerNode* context);
-  void removePropertiesInElementDefaultStyle(Element*);
-  void addAbsolutePositioningFromElement(const Element&);
-  void forceInline();
-  int legacyFontSize(Document*) const;
-
-  float fontSizeDelta() const { return m_fontSizeDelta; }
-  bool hasFontSizeDelta() const { return m_fontSizeDelta != NoFontDelta; }
-
   static EditingStyle* styleAtSelectionStart(
       const VisibleSelection&,
       bool shouldUseBackgroundColorInEffect = false,
@@ -175,104 +65,13 @@
            unicodeBidi == CSSValueWebkitIsolate || unicodeBidi == CSSValueEmbed;
   }
 
-  DECLARE_TRACE();
-
- private:
-  EditingStyle() = default;
-  EditingStyle(ContainerNode*, PropertiesToInclude);
-  EditingStyle(const Position&, PropertiesToInclude);
-  explicit EditingStyle(const StylePropertySet*);
-  EditingStyle(CSSPropertyID, const String& value);
-  void init(Node*, PropertiesToInclude);
-  void removeInheritedColorsIfNeeded(const ComputedStyle*);
-  void setProperty(CSSPropertyID, const String& value, bool important = false);
-  void replaceFontSizeByKeywordIfPossible(const ComputedStyle*,
-                                          CSSComputedStyleDeclaration*);
-  void extractFontSizeDelta();
-  TriState triStateOfStyle(CSSStyleDeclaration* styleToCompare,
-                           ShouldIgnoreTextOnlyProperties) const;
-  bool conflictsWithInlineStyleOfElement(
-      HTMLElement*,
-      EditingStyle* extractedStyle,
-      Vector<CSSPropertyID>* conflictingProperties) const;
-  void mergeInlineAndImplicitStyleOfElement(Element*,
-                                            CSSPropertyOverrideMode,
-                                            PropertiesToInclude);
-  void mergeStyle(const StylePropertySet*, CSSPropertyOverrideMode);
-
-  Member<MutableStylePropertySet> m_mutableStyle;
-  bool m_isMonospaceFont = false;
-  float m_fontSizeDelta = NoFontDelta;
-  bool m_isVerticalAlign = false;
-
-  friend class HTMLElementEquivalent;
-  friend class HTMLAttributeEquivalent;
+  static bool isTransparentColorValue(const CSSValue*);
+  static bool hasTransparentBackgroundColor(CSSStyleDeclaration*);
+  static bool hasTransparentBackgroundColor(StylePropertySet*);
+  static const CSSValue* backgroundColorValueInEffect(Node*);
+  static bool hasAncestorVerticalAlignStyle(Node&, CSSValueID);
 };
 
-class StyleChange {
-  DISALLOW_NEW();
-
- public:
-  StyleChange()
-      : m_applyBold(false),
-        m_applyItalic(false),
-        m_applyUnderline(false),
-        m_applyLineThrough(false),
-        m_applySubscript(false),
-        m_applySuperscript(false) {}
-
-  StyleChange(EditingStyle*, const Position&);
-
-  String cssStyle() const { return m_cssStyle; }
-  bool applyBold() const { return m_applyBold; }
-  bool applyItalic() const { return m_applyItalic; }
-  bool applyUnderline() const { return m_applyUnderline; }
-  bool applyLineThrough() const { return m_applyLineThrough; }
-  bool applySubscript() const { return m_applySubscript; }
-  bool applySuperscript() const { return m_applySuperscript; }
-  bool applyFontColor() const { return m_applyFontColor.length() > 0; }
-  bool applyFontFace() const { return m_applyFontFace.length() > 0; }
-  bool applyFontSize() const { return m_applyFontSize.length() > 0; }
-
-  String fontColor() { return m_applyFontColor; }
-  String fontFace() { return m_applyFontFace; }
-  String fontSize() { return m_applyFontSize; }
-
-  bool operator==(const StyleChange& other) {
-    return m_cssStyle == other.m_cssStyle && m_applyBold == other.m_applyBold &&
-           m_applyItalic == other.m_applyItalic &&
-           m_applyUnderline == other.m_applyUnderline &&
-           m_applyLineThrough == other.m_applyLineThrough &&
-           m_applySubscript == other.m_applySubscript &&
-           m_applySuperscript == other.m_applySuperscript &&
-           m_applyFontColor == other.m_applyFontColor &&
-           m_applyFontFace == other.m_applyFontFace &&
-           m_applyFontSize == other.m_applyFontSize;
-  }
-  bool operator!=(const StyleChange& other) { return !(*this == other); }
-
- private:
-  void extractTextStyles(Document*,
-                         MutableStylePropertySet*,
-                         bool isMonospaceFont);
-
-  String m_cssStyle;
-  bool m_applyBold;
-  bool m_applyItalic;
-  bool m_applyUnderline;
-  bool m_applyLineThrough;
-  bool m_applySubscript;
-  bool m_applySuperscript;
-  String m_applyFontColor;
-  String m_applyFontFace;
-  String m_applyFontSize;
-};
-
-// FIXME: Remove these functions or make them non-global to discourage using
-// CSSStyleDeclaration directly.
-CSSValueID getIdentifierValue(CSSStyleDeclaration*, CSSPropertyID);
-CSSValueID getIdentifierValue(StylePropertySet*, CSSPropertyID);
-
 }  // namespace blink
 
 #endif  // EditingStyleUtilities_h
diff --git a/third_party/WebKit/Source/core/events/MessageEvent.cpp b/third_party/WebKit/Source/core/events/MessageEvent.cpp
index 2f3119c..97ca6f65 100644
--- a/third_party/WebKit/Source/core/events/MessageEvent.cpp
+++ b/third_party/WebKit/Source/core/events/MessageEvent.cpp
@@ -198,6 +198,28 @@
         ->registerMemoryAllocatedWithCurrentScriptContext();
 }
 
+void MessageEvent::initMessageEvent(const AtomicString& type,
+                                    bool canBubble,
+                                    bool cancelable,
+                                    const String& data,
+                                    const String& origin,
+                                    const String& lastEventId,
+                                    EventTarget* source,
+                                    MessagePortArray* ports) {
+  if (isBeingDispatched())
+    return;
+
+  initEvent(type, canBubble, cancelable);
+
+  m_dataType = DataTypeString;
+  m_dataAsString = data;
+  m_origin = origin;
+  m_lastEventId = lastEventId;
+  m_source = source;
+  m_ports = ports;
+  m_suborigin = "";
+}
+
 const AtomicString& MessageEvent::interfaceName() const {
   return EventNames::MessageEvent;
 }
diff --git a/third_party/WebKit/Source/core/events/MessageEvent.h b/third_party/WebKit/Source/core/events/MessageEvent.h
index de9700cad..f497a484 100644
--- a/third_party/WebKit/Source/core/events/MessageEvent.h
+++ b/third_party/WebKit/Source/core/events/MessageEvent.h
@@ -108,6 +108,14 @@
                         const String& lastEventId,
                         EventTarget* source,
                         MessagePortArray*);
+  void initMessageEvent(const AtomicString& type,
+                        bool canBubble,
+                        bool cancelable,
+                        const String& data,
+                        const String& origin,
+                        const String& lastEventId,
+                        EventTarget* source,
+                        MessagePortArray*);
 
   const String& origin() const { return m_origin; }
   const String& suborigin() const { return m_suborigin; }
diff --git a/third_party/WebKit/Source/core/html/HTMLAttributeNames.in b/third_party/WebKit/Source/core/html/HTMLAttributeNames.in
new file mode 100644
index 0000000..d7670e9
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/HTMLAttributeNames.in
@@ -0,0 +1,348 @@
+namespace="HTML"
+namespacePrefix="xhtml"
+namespaceURI="http://www.w3.org/1999/xhtml"
+attrsNullNamespace
+export="CORE_EXPORT"
+
+abbr
+accept-charset
+accept
+accesskey
+action
+align
+alink
+allowfullscreen
+allowpaymentrequest
+alt
+archive
+aria-activedescendant
+aria-atomic
+aria-autocomplete
+aria-busy
+aria-checked
+aria-colcount
+aria-colindex
+aria-colspan
+aria-controls
+aria-current
+aria-describedby
+aria-details
+aria-disabled
+aria-dropeffect
+aria-errormessage
+aria-expanded
+aria-flowto
+aria-grabbed
+aria-haspopup
+aria-help
+aria-hidden
+aria-invalid
+aria-keyshortcuts
+aria-label
+aria-labeledby
+aria-labelledby
+aria-level
+aria-live
+aria-modal
+aria-multiline
+aria-multiselectable
+aria-orientation
+aria-owns
+aria-placeholder
+aria-posinset
+aria-pressed
+aria-readonly
+aria-relevant
+aria-required
+aria-roledescription
+aria-rowcount
+aria-rowindex
+aria-rowspan
+aria-selected
+aria-setsize
+aria-sort
+aria-valuemax
+aria-valuemin
+aria-valuenow
+aria-valuetext
+as
+async
+autocapitalize
+autocomplete
+autocorrect
+autofocus
+autoplay
+axis
+background
+behavior
+bgcolor
+border
+bordercolor
+capture
+cellpadding
+cellspacing
+char
+challenge
+charoff
+charset
+checked
+cite
+class
+classid
+clear
+code
+codebase
+codetype
+color
+cols
+colspan
+compact
+content
+contenteditable
+contextmenu
+controls
+coords
+crossorigin
+csp
+data
+datetime
+declare
+default
+defer
+dir
+direction
+dirname
+disabled
+disableremoteplayback
+download
+draggable
+webkitdropzone
+enctype
+end
+event
+face
+for
+form
+formaction
+formenctype
+formmethod
+formnovalidate
+formtarget
+frame
+frameborder
+headers
+height
+hidden
+high
+href
+hreflang
+hspace
+http-equiv
+icon
+id
+incremental
+inputmode
+integrity
+is
+ismap
+keytype
+kind
+label
+lang
+language
+leftmargin
+link
+list
+longdesc
+loop
+low
+lowsrc
+manifest
+marginheight
+marginwidth
+max
+maxlength
+mayscript
+media
+method
+min
+minlength
+multiple
+muted
+name
+nohref
+nonce
+noresize
+noshade
+novalidate
+nowrap
+object
+onabort
+onanimationstart
+onanimationiteration
+onanimationend
+onauxclick
+onbeforecopy
+onbeforecut
+onbeforepaste
+onbeforeunload
+onblur
+oncancel
+oncanplay
+oncanplaythrough
+onchange
+onclick
+onclose
+oncontextmenu
+oncopy
+oncuechange
+oncut
+ondblclick
+ondrag
+ondragend
+ondragenter
+ondragleave
+ondragover
+ondragstart
+ondrop
+ondurationchange
+onemptied
+onended
+onerror
+onfocus
+onfocusin
+onfocusout
+ongotpointercapture
+onhashchange
+oninput
+oninvalid
+onkeydown
+onkeypress
+onkeyup
+onlanguagechange
+onload
+onloadeddata
+onloadedmetadata
+onloadstart
+onlostpointercapture
+onmessage
+onmousedown
+onmouseenter
+onmouseleave
+onmousemove
+onmouseout
+onmouseover
+onmouseup
+onmousewheel
+ononline
+onoffline
+onorientationchange
+onpagehide
+onpageshow
+onpaste
+onpause
+onplay
+onplaying
+onpointercancel
+onpointerdown
+onpointerenter
+onpointerleave
+onpointermove
+onpointerout
+onpointerover
+onpointerup
+onpopstate
+onprogress
+onratechange
+onreset
+onresize
+onscroll
+onsearch
+onseeked
+onseeking
+onselect
+onselectstart
+onselectionchange
+onshow
+onstalled
+onstorage
+onsuspend
+onsubmit
+ontimeupdate
+ontoggle
+ontouchstart
+ontouchmove
+ontouchend
+ontouchcancel
+ontransitionend
+onunload
+onvolumechange
+onwaiting
+onwebkitanimationstart
+onwebkitanimationiteration
+onwebkitanimationend
+onwebkitfullscreenchange
+onwebkitfullscreenerror
+onwebkittransitionend
+onwheel
+open
+optimum
+pattern
+permissions
+placeholder
+ping
+poster
+preload
+pseudo
+radiogroup
+readonly
+referrerpolicy
+rel
+required
+rev
+reversed
+role
+rows
+rowspan
+rules
+sandbox
+scheme
+scope
+scrollamount
+scrolldelay
+scrolling
+select
+selected
+shape
+size
+sizes
+slot
+span
+spellcheck
+src
+srcset
+srcdoc
+srclang
+standby
+start
+step
+style
+summary
+tabindex
+target
+text
+title
+topmargin
+translate
+truespeed
+type
+usemap
+valign
+value
+valuetype
+version
+vlink
+vspace
+webkitdirectory
+width
+wrap
diff --git a/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5 b/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5
deleted file mode 100644
index 0ad4d65e..0000000
--- a/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5
+++ /dev/null
@@ -1,354 +0,0 @@
-{
-  metadata: {
-    namespace: "HTML",
-    namespacePrefix: "xhtml",
-    namespaceURI: "http://www.w3.org/1999/xhtml",
-    attrsNullNamespace: true,
-    export: "CORE_EXPORT",
-  },
-
-  data: [
-    "abbr",
-    "accept-charset",
-    "accept",
-    "accesskey",
-    "action",
-    "align",
-    "alink",
-    "allowfullscreen",
-    "allowpaymentrequest",
-    "alt",
-    "archive",
-    "aria-activedescendant",
-    "aria-atomic",
-    "aria-autocomplete",
-    "aria-busy",
-    "aria-checked",
-    "aria-colcount",
-    "aria-colindex",
-    "aria-colspan",
-    "aria-controls",
-    "aria-current",
-    "aria-describedby",
-    "aria-details",
-    "aria-disabled",
-    "aria-dropeffect",
-    "aria-errormessage",
-    "aria-expanded",
-    "aria-flowto",
-    "aria-grabbed",
-    "aria-haspopup",
-    "aria-help",
-    "aria-hidden",
-    "aria-invalid",
-    "aria-keyshortcuts",
-    "aria-label",
-    "aria-labeledby",
-    "aria-labelledby",
-    "aria-level",
-    "aria-live",
-    "aria-modal",
-    "aria-multiline",
-    "aria-multiselectable",
-    "aria-orientation",
-    "aria-owns",
-    "aria-placeholder",
-    "aria-posinset",
-    "aria-pressed",
-    "aria-readonly",
-    "aria-relevant",
-    "aria-required",
-    "aria-roledescription",
-    "aria-rowcount",
-    "aria-rowindex",
-    "aria-rowspan",
-    "aria-selected",
-    "aria-setsize",
-    "aria-sort",
-    "aria-valuemax",
-    "aria-valuemin",
-    "aria-valuenow",
-    "aria-valuetext",
-    "as",
-    "async",
-    "autocapitalize",
-    "autocomplete",
-    "autocorrect",
-    "autofocus",
-    "autoplay",
-    "axis",
-    "background",
-    "behavior",
-    "bgcolor",
-    "border",
-    "bordercolor",
-    "capture",
-    "cellpadding",
-    "cellspacing",
-    "char",
-    "challenge",
-    "charoff",
-    "charset",
-    "checked",
-    "cite",
-    "class",
-    "classid",
-    "clear",
-    "code",
-    "codebase",
-    "codetype",
-    "color",
-    "cols",
-    "colspan",
-    "compact",
-    "content",
-    "contenteditable",
-    "contextmenu",
-    "controls",
-    "coords",
-    "crossorigin",
-    "csp",
-    "data",
-    "datetime",
-    "declare",
-    "default",
-    "defer",
-    "dir",
-    "direction",
-    "dirname",
-    "disabled",
-    "disableremoteplayback",
-    "download",
-    "draggable",
-    "webkitdropzone",
-    "enctype",
-    "end",
-    "event",
-    "face",
-    "for",
-    "form",
-    "formaction",
-    "formenctype",
-    "formmethod",
-    "formnovalidate",
-    "formtarget",
-    "frame",
-    "frameborder",
-    "headers",
-    "height",
-    "hidden",
-    "high",
-    "href",
-    "hreflang",
-    "hspace",
-    "http-equiv",
-    "icon",
-    "id",
-    "incremental",
-    "inputmode",
-    "integrity",
-    "is",
-    "ismap",
-    "keytype",
-    "kind",
-    "label",
-    "lang",
-    "language",
-    "leftmargin",
-    "link",
-    "list",
-    "longdesc",
-    "loop",
-    "low",
-    "lowsrc",
-    "manifest",
-    "marginheight",
-    "marginwidth",
-    "max",
-    "maxlength",
-    "mayscript",
-    "media",
-    "method",
-    "min",
-    "minlength",
-    "multiple",
-    "muted",
-    "name",
-    "nohref",
-    "nonce",
-    "noresize",
-    "noshade",
-    "novalidate",
-    "nowrap",
-    "object",
-    "onabort",
-    "onanimationstart",
-    "onanimationiteration",
-    "onanimationend",
-    "onauxclick",
-    "onbeforecopy",
-    "onbeforecut",
-    "onbeforepaste",
-    "onbeforeunload",
-    "onblur",
-    "oncancel",
-    "oncanplay",
-    "oncanplaythrough",
-    "onchange",
-    "onclick",
-    "onclose",
-    "oncontextmenu",
-    "oncopy",
-    "oncuechange",
-    "oncut",
-    "ondblclick",
-    "ondrag",
-    "ondragend",
-    "ondragenter",
-    "ondragleave",
-    "ondragover",
-    "ondragstart",
-    "ondrop",
-    "ondurationchange",
-    "onemptied",
-    "onended",
-    "onerror",
-    "onfocus",
-    "onfocusin",
-    "onfocusout",
-    "ongotpointercapture",
-    "onhashchange",
-    "oninput",
-    "oninvalid",
-    "onkeydown",
-    "onkeypress",
-    "onkeyup",
-    "onlanguagechange",
-    "onload",
-    "onloadeddata",
-    "onloadedmetadata",
-    "onloadstart",
-    "onlostpointercapture",
-    "onmessage",
-    "onmousedown",
-    "onmouseenter",
-    "onmouseleave",
-    "onmousemove",
-    "onmouseout",
-    "onmouseover",
-    "onmouseup",
-    "onmousewheel",
-    "ononline",
-    "onoffline",
-    "onorientationchange",
-    "onpagehide",
-    "onpageshow",
-    "onpaste",
-    "onpause",
-    "onplay",
-    "onplaying",
-    "onpointercancel",
-    "onpointerdown",
-    "onpointerenter",
-    "onpointerleave",
-    "onpointermove",
-    "onpointerout",
-    "onpointerover",
-    "onpointerup",
-    "onpopstate",
-    "onprogress",
-    "onratechange",
-    "onreset",
-    "onresize",
-    "onscroll",
-    "onsearch",
-    "onseeked",
-    "onseeking",
-    "onselect",
-    "onselectstart",
-    "onselectionchange",
-    "onshow",
-    "onstalled",
-    "onstorage",
-    "onsuspend",
-    "onsubmit",
-    "ontimeupdate",
-    "ontoggle",
-    "ontouchstart",
-    "ontouchmove",
-    "ontouchend",
-    "ontouchcancel",
-    "ontransitionend",
-    "onunload",
-    "onvolumechange",
-    "onwaiting",
-    "onwebkitanimationstart",
-    "onwebkitanimationiteration",
-    "onwebkitanimationend",
-    "onwebkitfullscreenchange",
-    "onwebkitfullscreenerror",
-    "onwebkittransitionend",
-    "onwheel",
-    "open",
-    "optimum",
-    "pattern",
-    "permissions",
-    "placeholder",
-    "ping",
-    "poster",
-    "preload",
-    "pseudo",
-    "radiogroup",
-    "readonly",
-    "referrerpolicy",
-    "rel",
-    "required",
-    "rev",
-    "reversed",
-    "role",
-    "rows",
-    "rowspan",
-    "rules",
-    "sandbox",
-    "scheme",
-    "scope",
-    "scrollamount",
-    "scrolldelay",
-    "scrolling",
-    "select",
-    "selected",
-    "shape",
-    "size",
-    "sizes",
-    "slot",
-    "span",
-    "spellcheck",
-    "src",
-    "srcset",
-    "srcdoc",
-    "srclang",
-    "standby",
-    "start",
-    "step",
-    "style",
-    "summary",
-    "tabindex",
-    "target",
-    "text",
-    "title",
-    "topmargin",
-    "translate",
-    "truespeed",
-    "type",
-    "usemap",
-    "valign",
-    "value",
-    "valuetype",
-    "version",
-    "vlink",
-    "vspace",
-    "webkitdirectory",
-    "width",
-    "wrap",
-  ],
-}
diff --git a/third_party/WebKit/Source/core/html/HTMLTagNames.in b/third_party/WebKit/Source/core/html/HTMLTagNames.in
new file mode 100644
index 0000000..0c8b5137
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/HTMLTagNames.in
@@ -0,0 +1,145 @@
+namespace="HTML"
+namespacePrefix="xhtml"
+namespaceURI="http://www.w3.org/1999/xhtml"
+fallbackInterfaceName="HTMLUnknownElement"
+export="CORE_EXPORT"
+
+a interfaceName=HTMLAnchorElement
+abbr interfaceName=HTMLElement
+acronym interfaceName=HTMLElement
+address interfaceName=HTMLElement
+applet interfaceName=HTMLUnknownElement
+area
+article interfaceName=HTMLElement
+aside interfaceName=HTMLElement
+audio
+b interfaceName=HTMLElement
+base
+basefont interfaceName=HTMLElement
+bdi interfaceName=HTMLBDIElement, JSInterfaceName=HTMLElement
+bdo interfaceName=HTMLElement
+bgsound interfaceName=HTMLUnknownElement
+big interfaceName=HTMLElement
+blockquote interfaceName=HTMLQuoteElement
+body
+br interfaceName=HTMLBRElement
+button
+canvas
+caption interfaceName=HTMLTableCaptionElement
+center interfaceName=HTMLElement
+cite interfaceName=HTMLElement
+code interfaceName=HTMLElement
+col interfaceName=HTMLTableColElement
+colgroup interfaceName=HTMLTableColElement
+command interfaceName=HTMLUnknownElement
+content interfaceName=HTMLContentElement
+datalist interfaceName=HTMLDataListElement
+dd interfaceName=HTMLElement
+del interfaceName=HTMLModElement
+details
+dfn interfaceName=HTMLElement
+dir interfaceName=HTMLDirectoryElement
+dialog
+div
+dl interfaceName=HTMLDListElement
+dt interfaceName=HTMLElement
+em interfaceName=HTMLElement
+embed constructorNeedsCreatedByParser
+fieldset interfaceName=HTMLFieldSetElement
+figcaption interfaceName=HTMLElement
+figure interfaceName=HTMLElement
+font
+footer interfaceName=HTMLElement
+form
+frame
+frameset interfaceName=HTMLFrameSetElement
+h1 interfaceName=HTMLHeadingElement
+h2 interfaceName=HTMLHeadingElement
+h3 interfaceName=HTMLHeadingElement
+h4 interfaceName=HTMLHeadingElement
+h5 interfaceName=HTMLHeadingElement
+h6 interfaceName=HTMLHeadingElement
+head
+header interfaceName=HTMLElement
+hgroup interfaceName=HTMLElement
+hr interfaceName=HTMLHRElement
+html
+i interfaceName=HTMLElement
+iframe interfaceName=HTMLIFrameElement
+image interfaceName=HTMLUnknownElement
+img interfaceName=HTMLImageElement, constructorNeedsCreatedByParser
+input constructorNeedsCreatedByParser
+ins interfaceName=HTMLModElement
+kbd interfaceName=HTMLElement
+keygen interfaceName=HTMLUnknownElement
+label
+layer interfaceName=HTMLElement
+legend
+li interfaceName=HTMLLIElement
+link constructorNeedsCreatedByParser
+listing interfaceName=HTMLPreElement
+main interfaceName=HTMLElement
+map
+mark interfaceName=HTMLElement
+marquee
+menu
+menuitem interfaceName=HTMLMenuItemElement, runtimeEnabled=contextMenu
+meta
+meter interfaceName=HTMLMeterElement
+nav interfaceName=HTMLElement
+nobr interfaceName=HTMLElement
+noembed interfaceName=HTMLNoEmbedElement, JSInterfaceName=HTMLElement
+noframes interfaceName=HTMLElement
+nolayer interfaceName=HTMLElement
+object constructorNeedsCreatedByParser
+ol interfaceName=HTMLOListElement
+optgroup interfaceName=HTMLOptGroupElement
+option
+output
+shadow interfaceName=HTMLShadowElement
+p interfaceName=HTMLParagraphElement
+param
+picture interfaceName=HTMLPictureElement
+plaintext interfaceName=HTMLElement
+pre
+progress interfaceName=HTMLProgressElement
+q interfaceName=HTMLQuoteElement
+rb interfaceName=HTMLElement
+rp interfaceName=HTMLElement
+rt interfaceName=HTMLRTElement, JSInterfaceName=HTMLElement
+rtc interfaceName=HTMLElement
+ruby interfaceName=HTMLRubyElement, JSInterfaceName=HTMLElement
+s interfaceName=HTMLElement
+samp interfaceName=HTMLElement
+script constructorNeedsCreatedByParser
+section interfaceName=HTMLElement
+select
+slot interfaceName=HTMLSlotElement
+small interfaceName=HTMLElement
+source
+span
+strike interfaceName=HTMLElement
+strong interfaceName=HTMLElement
+style constructorNeedsCreatedByParser
+sub interfaceName=HTMLElement
+summary interfaceName=HTMLSummaryElement, JSInterfaceName=HTMLElement
+sup interfaceName=HTMLElement
+table
+tbody interfaceName=HTMLTableSectionElement
+td interfaceName=HTMLTableCellElement
+template
+textarea interfaceName=HTMLTextAreaElement
+tfoot interfaceName=HTMLTableSectionElement
+th interfaceName=HTMLTableCellElement
+thead interfaceName=HTMLTableSectionElement
+title
+tr interfaceName=HTMLTableRowElement
+track
+tt interfaceName=HTMLElement
+u interfaceName=HTMLElement
+ul interfaceName=HTMLUListElement
+var interfaceName=HTMLElement
+video
+wbr interfaceName=HTMLWBRElement, JSInterfaceName=HTMLElement
+xmp interfaceName=HTMLPreElement
+noscript interfaceName=HTMLNoScriptElement, JSInterfaceName=HTMLElement
diff --git a/third_party/WebKit/Source/core/html/HTMLTagNames.json5 b/third_party/WebKit/Source/core/html/HTMLTagNames.json5
deleted file mode 100644
index 5d65b245..0000000
--- a/third_party/WebKit/Source/core/html/HTMLTagNames.json5
+++ /dev/null
@@ -1,481 +0,0 @@
-{
-  metadata: {
-    namespace: "HTML",
-    namespacePrefix: "xhtml",
-    namespaceURI: "http://www.w3.org/1999/xhtml",
-    fallbackInterfaceName: "HTMLUnknownElement",
-    export: "CORE_EXPORT",
-  },
-
-  data: [
-    {
-      name: "a",
-      interfaceName: "HTMLAnchorElement",
-    },
-    {
-      name: "abbr",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "acronym",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "address",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "applet",
-      interfaceName: "HTMLUnknownElement",
-    },
-    "area",
-    {
-      name: "article",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "aside",
-      interfaceName: "HTMLElement",
-    },
-    "audio",
-    {
-      name: "b",
-      interfaceName: "HTMLElement",
-    },
-    "base",
-    {
-      name: "basefont",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "bdi",
-      JSInterfaceName: "HTMLElement",
-      interfaceName: "HTMLBDIElement",
-    },
-    {
-      name: "bdo",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "bgsound",
-      interfaceName: "HTMLUnknownElement",
-    },
-    {
-      name: "big",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "blockquote",
-      interfaceName: "HTMLQuoteElement",
-    },
-    "body",
-    {
-      name: "br",
-      interfaceName: "HTMLBRElement",
-    },
-    "button",
-    "canvas",
-    {
-      name: "caption",
-      interfaceName: "HTMLTableCaptionElement",
-    },
-    {
-      name: "center",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "cite",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "code",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "col",
-      interfaceName: "HTMLTableColElement",
-    },
-    {
-      name: "colgroup",
-      interfaceName: "HTMLTableColElement",
-    },
-    {
-      name: "command",
-      interfaceName: "HTMLUnknownElement",
-    },
-    {
-      name: "content",
-      interfaceName: "HTMLContentElement",
-    },
-    {
-      name: "datalist",
-      interfaceName: "HTMLDataListElement",
-    },
-    {
-      name: "dd",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "del",
-      interfaceName: "HTMLModElement",
-    },
-    "details",
-    {
-      name: "dfn",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "dir",
-      interfaceName: "HTMLDirectoryElement",
-    },
-    "dialog",
-    "div",
-    {
-      name: "dl",
-      interfaceName: "HTMLDListElement",
-    },
-    {
-      name: "dt",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "em",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "embed",
-      constructorNeedsCreatedByParser: true,
-    },
-    {
-      name: "fieldset",
-      interfaceName: "HTMLFieldSetElement",
-    },
-    {
-      name: "figcaption",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "figure",
-      interfaceName: "HTMLElement",
-    },
-    "font",
-    {
-      name: "footer",
-      interfaceName: "HTMLElement",
-    },
-    "form",
-    "frame",
-    {
-      name: "frameset",
-      interfaceName: "HTMLFrameSetElement",
-    },
-    {
-      name: "h1",
-      interfaceName: "HTMLHeadingElement",
-    },
-    {
-      name: "h2",
-      interfaceName: "HTMLHeadingElement",
-    },
-    {
-      name: "h3",
-      interfaceName: "HTMLHeadingElement",
-    },
-    {
-      name: "h4",
-      interfaceName: "HTMLHeadingElement",
-    },
-    {
-      name: "h5",
-      interfaceName: "HTMLHeadingElement",
-    },
-    {
-      name: "h6",
-      interfaceName: "HTMLHeadingElement",
-    },
-    "head",
-    {
-      name: "header",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "hgroup",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "hr",
-      interfaceName: "HTMLHRElement",
-    },
-    "html",
-    {
-      name: "i",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "iframe",
-      interfaceName: "HTMLIFrameElement",
-    },
-    {
-      name: "image",
-      interfaceName: "HTMLUnknownElement",
-    },
-    {
-      name: "img",
-      constructorNeedsCreatedByParser: true,
-      interfaceName: "HTMLImageElement",
-    },
-    {
-      name: "input",
-      constructorNeedsCreatedByParser: true,
-    },
-    {
-      name: "ins",
-      interfaceName: "HTMLModElement",
-    },
-    {
-      name: "kbd",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "keygen",
-      interfaceName: "HTMLUnknownElement",
-    },
-    "label",
-    {
-      name: "layer",
-      interfaceName: "HTMLElement",
-    },
-    "legend",
-    {
-      name: "li",
-      interfaceName: "HTMLLIElement",
-    },
-    {
-      name: "link",
-      constructorNeedsCreatedByParser: true,
-    },
-    {
-      name: "listing",
-      interfaceName: "HTMLPreElement",
-    },
-    {
-      name: "main",
-      interfaceName: "HTMLElement",
-    },
-    "map",
-    {
-      name: "mark",
-      interfaceName: "HTMLElement",
-    },
-    "marquee",
-    "menu",
-    {
-      name: "menuitem",
-      interfaceName: "HTMLMenuItemElement",
-      runtimeEnabled: "contextMenu",
-    },
-    "meta",
-    {
-      name: "meter",
-      interfaceName: "HTMLMeterElement",
-    },
-    {
-      name: "nav",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "nobr",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "noembed",
-      JSInterfaceName: "HTMLElement",
-      interfaceName: "HTMLNoEmbedElement",
-    },
-    {
-      name: "noframes",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "nolayer",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "object",
-      constructorNeedsCreatedByParser: true,
-    },
-    {
-      name: "ol",
-      interfaceName: "HTMLOListElement",
-    },
-    {
-      name: "optgroup",
-      interfaceName: "HTMLOptGroupElement",
-    },
-    "option",
-    "output",
-    {
-      name: "shadow",
-      interfaceName: "HTMLShadowElement",
-    },
-    {
-      name: "p",
-      interfaceName: "HTMLParagraphElement",
-    },
-    "param",
-    {
-      name: "picture",
-      interfaceName: "HTMLPictureElement",
-    },
-    {
-      name: "plaintext",
-      interfaceName: "HTMLElement",
-    },
-    "pre",
-    {
-      name: "progress",
-      interfaceName: "HTMLProgressElement",
-    },
-    {
-      name: "q",
-      interfaceName: "HTMLQuoteElement",
-    },
-    {
-      name: "rb",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "rp",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "rt",
-      JSInterfaceName: "HTMLElement",
-      interfaceName: "HTMLRTElement",
-    },
-    {
-      name: "rtc",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "ruby",
-      JSInterfaceName: "HTMLElement",
-      interfaceName: "HTMLRubyElement",
-    },
-    {
-      name: "s",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "samp",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "script",
-      constructorNeedsCreatedByParser: true,
-    },
-    {
-      name: "section",
-      interfaceName: "HTMLElement",
-    },
-    "select",
-    {
-      name: "slot",
-      interfaceName: "HTMLSlotElement",
-    },
-    {
-      name: "small",
-      interfaceName: "HTMLElement",
-    },
-    "source",
-    "span",
-    {
-      name: "strike",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "strong",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "style",
-      constructorNeedsCreatedByParser: true,
-    },
-    {
-      name: "sub",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "summary",
-      JSInterfaceName: "HTMLElement",
-      interfaceName: "HTMLSummaryElement",
-    },
-    {
-      name: "sup",
-      interfaceName: "HTMLElement",
-    },
-    "table",
-    {
-      name: "tbody",
-      interfaceName: "HTMLTableSectionElement",
-    },
-    {
-      name: "td",
-      interfaceName: "HTMLTableCellElement",
-    },
-    "template",
-    {
-      name: "textarea",
-      interfaceName: "HTMLTextAreaElement",
-    },
-    {
-      name: "tfoot",
-      interfaceName: "HTMLTableSectionElement",
-    },
-    {
-      name: "th",
-      interfaceName: "HTMLTableCellElement",
-    },
-    {
-      name: "thead",
-      interfaceName: "HTMLTableSectionElement",
-    },
-    "title",
-    {
-      name: "tr",
-      interfaceName: "HTMLTableRowElement",
-    },
-    "track",
-    {
-      name: "tt",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "u",
-      interfaceName: "HTMLElement",
-    },
-    {
-      name: "ul",
-      interfaceName: "HTMLUListElement",
-    },
-    {
-      name: "var",
-      interfaceName: "HTMLElement",
-    },
-    "video",
-    {
-      name: "wbr",
-      JSInterfaceName: "HTMLElement",
-      interfaceName: "HTMLWBRElement",
-    },
-    {
-      name: "xmp",
-      interfaceName: "HTMLPreElement",
-    },
-    {
-      name: "noscript",
-      JSInterfaceName: "HTMLElement",
-      interfaceName: "HTMLNoScriptElement",
-    },
-  ],
-}
diff --git a/third_party/WebKit/Source/core/html/parser/MathMLAttributeNames.in b/third_party/WebKit/Source/core/html/parser/MathMLAttributeNames.in
new file mode 100644
index 0000000..2277695
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/parser/MathMLAttributeNames.in
@@ -0,0 +1,6 @@
+namespace="MathML"
+namespaceURI="http://www.w3.org/1998/Math/MathML"
+attrsNullNamespace
+
+definitionURL
+encoding
diff --git a/third_party/WebKit/Source/core/html/parser/MathMLAttributeNames.json5 b/third_party/WebKit/Source/core/html/parser/MathMLAttributeNames.json5
deleted file mode 100644
index 464ce188..0000000
--- a/third_party/WebKit/Source/core/html/parser/MathMLAttributeNames.json5
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  metadata: {
-    namespace: "MathML",
-    namespaceURI: "http://www.w3.org/1998/Math/MathML",
-    attrsNullNamespace: true,
-  },
-
-  data: [
-    "definitionURL",
-    "encoding",
-  ],
-}
diff --git a/third_party/WebKit/Source/core/html/parser/MathMLTagNames.in b/third_party/WebKit/Source/core/html/parser/MathMLTagNames.in
new file mode 100644
index 0000000..80d830f
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/parser/MathMLTagNames.in
@@ -0,0 +1,12 @@
+namespace="MathML"
+namespaceURI="http://www.w3.org/1998/Math/MathML"
+
+math
+mi
+mn
+mo
+mtext
+ms
+mglyph
+malignmark
+annotation-xml
diff --git a/third_party/WebKit/Source/core/html/parser/MathMLTagNames.json5 b/third_party/WebKit/Source/core/html/parser/MathMLTagNames.json5
deleted file mode 100644
index 4326dd7..0000000
--- a/third_party/WebKit/Source/core/html/parser/MathMLTagNames.json5
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  metadata: {
-    namespace: "MathML",
-    namespaceURI: "http://www.w3.org/1998/Math/MathML",
-  },
-
-  data: [
-    "math",
-    "mi",
-    "mn",
-    "mo",
-    "mtext",
-    "ms",
-    "mglyph",
-    "malignmark",
-    "annotation-xml",
-  ],
-}
diff --git a/third_party/WebKit/Source/core/layout/line/LineBoxList.cpp b/third_party/WebKit/Source/core/layout/line/LineBoxList.cpp
index 77b3069d..29888e5 100644
--- a/third_party/WebKit/Source/core/layout/line/LineBoxList.cpp
+++ b/third_party/WebKit/Source/core/layout/line/LineBoxList.cpp
@@ -293,11 +293,13 @@
   RootInlineBox* box = nullptr;
   LineLayoutItem curr = child.previousSibling();
   if (child.isFloating() && !curr) {
-    LineLayoutItem parent = child.parent();
-    while (parent && parent.isLayoutInline() && !parent.previousSibling())
-      parent = parent.parent();
-    if (parent)
-      curr = parent.previousSibling();
+    LineLayoutInline outerInline;
+    for (LineLayoutItem parent = child.parent();
+         parent && parent.isLayoutInline() && !parent.previousSibling();
+         parent = parent.parent())
+      outerInline = LineLayoutInline(parent);
+    if (outerInline)
+      curr = outerInline.previousSibling();
   }
 
   for (; curr; curr = curr.previousSibling()) {
diff --git a/third_party/WebKit/Source/core/svg/SVGAttributeNames.in b/third_party/WebKit/Source/core/svg/SVGAttributeNames.in
new file mode 100644
index 0000000..7952490
--- /dev/null
+++ b/third_party/WebKit/Source/core/svg/SVGAttributeNames.in
@@ -0,0 +1,243 @@
+namespace="SVG"
+namespaceURI="http://www.w3.org/2000/svg"
+attrsNullNamespace
+export="CORE_EXPORT"
+
+accent-height
+accumulate
+additive
+alignment-baseline
+alphabetic
+amplitude
+animate
+arabic-form
+ascent
+attributeName
+attributeType
+azimuth
+baseFrequency
+baseline-shift
+baseProfile
+bbox
+begin
+bias
+buffered-rendering
+by
+calcMode
+cap-height
+clip
+clip-path
+clip-rule
+clipPathUnits
+color
+color-interpolation
+color-interpolation-filters
+color-rendering
+cursor
+cx
+cy
+d
+descent
+diffuseConstant
+direction
+display
+divisor
+dominant-baseline
+dur
+dx
+dy
+edgeMode
+elevation
+end
+exponent
+fill
+fill-opacity
+fill-rule
+filter
+filterUnits
+flood-color
+flood-opacity
+font-family
+font-size
+font-size-adjust
+font-stretch
+font-style
+font-variant
+font-weight
+format
+from
+fx
+fy
+fr
+g1
+g2
+glyph-name
+glyphRef
+gradientTransform
+gradientUnits
+hanging
+height
+horiz-adv-x
+horiz-origin-x
+horiz-origin-y
+href
+ideographic
+image-rendering
+in
+in2
+intercept
+k
+k1
+k2
+k3
+k4
+kernelMatrix
+kernelUnitLength
+keyPoints
+keySplines
+keyTimes
+lang
+lengthAdjust
+letter-spacing
+lighting-color
+limitingConeAngle
+local
+marker-end
+marker-mid
+marker-start
+markerHeight
+markerUnits
+markerWidth
+mask
+mask-type
+maskContentUnits
+maskUnits
+mathematical
+max
+media
+method
+min
+mode
+name
+numOctaves
+offset
+onactivate
+onbegin
+onend
+onfocusin
+onfocusout
+onrepeat
+opacity
+operator
+order
+orient
+orientation
+origin
+overflow
+overline-position
+overline-thickness
+paint-order
+panose-1
+path
+pathLength
+patternContentUnits
+patternTransform
+patternUnits
+pointer-events
+points
+pointsAtX
+pointsAtY
+pointsAtZ
+preserveAlpha
+preserveAspectRatio
+primitiveUnits
+r
+radius
+refX
+refY
+rendering-intent
+repeatCount
+repeatDur
+requiredExtensions
+requiredFeatures
+restart
+result
+rotate
+rx
+ry
+scale
+seed
+shape-rendering
+slope
+spacing
+specularConstant
+specularExponent
+spreadMethod
+startOffset
+stdDeviation
+stemh
+stemv
+stitchTiles
+stop-color
+stop-opacity
+strikethrough-position
+strikethrough-thickness
+stroke
+stroke-dasharray
+stroke-dashoffset
+stroke-linecap
+stroke-linejoin
+stroke-miterlimit
+stroke-opacity
+stroke-width
+style
+surfaceScale
+systemLanguage
+tableValues
+target
+targetX
+targetY
+text-anchor
+text-decoration
+text-rendering
+textLength
+title
+to
+transform
+transform-origin
+type
+u1
+u2
+underline-position
+underline-thickness
+unicode
+unicode-bidi
+unicode-range
+units-per-em
+v-alphabetic
+v-hanging
+v-ideographic
+v-mathematical
+values
+vector-effect
+version
+vert-adv-y
+vert-origin-x
+vert-origin-y
+viewBox
+visibility
+width
+widths
+word-spacing
+writing-mode
+x
+x-height
+x1
+x2
+xChannelSelector
+y
+y1
+y2
+yChannelSelector
+z
+zoomAndPan
diff --git a/third_party/WebKit/Source/core/svg/SVGAttributeNames.json5 b/third_party/WebKit/Source/core/svg/SVGAttributeNames.json5
deleted file mode 100644
index 5e5121d3..0000000
--- a/third_party/WebKit/Source/core/svg/SVGAttributeNames.json5
+++ /dev/null
@@ -1,249 +0,0 @@
-{
-  metadata: {
-    namespace: "SVG",
-    namespaceURI: "http://www.w3.org/2000/svg",
-    attrsNullNamespace: true,
-    export: "CORE_EXPORT",
-  },
-
-  data: [
-    "accent-height",
-    "accumulate",
-    "additive",
-    "alignment-baseline",
-    "alphabetic",
-    "amplitude",
-    "animate",
-    "arabic-form",
-    "ascent",
-    "attributeName",
-    "attributeType",
-    "azimuth",
-    "baseFrequency",
-    "baseline-shift",
-    "baseProfile",
-    "bbox",
-    "begin",
-    "bias",
-    "buffered-rendering",
-    "by",
-    "calcMode",
-    "cap-height",
-    "clip",
-    "clip-path",
-    "clip-rule",
-    "clipPathUnits",
-    "color",
-    "color-interpolation",
-    "color-interpolation-filters",
-    "color-rendering",
-    "cursor",
-    "cx",
-    "cy",
-    "d",
-    "descent",
-    "diffuseConstant",
-    "direction",
-    "display",
-    "divisor",
-    "dominant-baseline",
-    "dur",
-    "dx",
-    "dy",
-    "edgeMode",
-    "elevation",
-    "end",
-    "exponent",
-    "fill",
-    "fill-opacity",
-    "fill-rule",
-    "filter",
-    "filterUnits",
-    "flood-color",
-    "flood-opacity",
-    "font-family",
-    "font-size",
-    "font-size-adjust",
-    "font-stretch",
-    "font-style",
-    "font-variant",
-    "font-weight",
-    "format",
-    "from",
-    "fx",
-    "fy",
-    "fr",
-    "g1",
-    "g2",
-    "glyph-name",
-    "glyphRef",
-    "gradientTransform",
-    "gradientUnits",
-    "hanging",
-    "height",
-    "horiz-adv-x",
-    "horiz-origin-x",
-    "horiz-origin-y",
-    "href",
-    "ideographic",
-    "image-rendering",
-    "in",
-    "in2",
-    "intercept",
-    "k",
-    "k1",
-    "k2",
-    "k3",
-    "k4",
-    "kernelMatrix",
-    "kernelUnitLength",
-    "keyPoints",
-    "keySplines",
-    "keyTimes",
-    "lang",
-    "lengthAdjust",
-    "letter-spacing",
-    "lighting-color",
-    "limitingConeAngle",
-    "local",
-    "marker-end",
-    "marker-mid",
-    "marker-start",
-    "markerHeight",
-    "markerUnits",
-    "markerWidth",
-    "mask",
-    "mask-type",
-    "maskContentUnits",
-    "maskUnits",
-    "mathematical",
-    "max",
-    "media",
-    "method",
-    "min",
-    "mode",
-    "name",
-    "numOctaves",
-    "offset",
-    "onactivate",
-    "onbegin",
-    "onend",
-    "onfocusin",
-    "onfocusout",
-    "onrepeat",
-    "opacity",
-    "operator",
-    "order",
-    "orient",
-    "orientation",
-    "origin",
-    "overflow",
-    "overline-position",
-    "overline-thickness",
-    "paint-order",
-    "panose-1",
-    "path",
-    "pathLength",
-    "patternContentUnits",
-    "patternTransform",
-    "patternUnits",
-    "pointer-events",
-    "points",
-    "pointsAtX",
-    "pointsAtY",
-    "pointsAtZ",
-    "preserveAlpha",
-    "preserveAspectRatio",
-    "primitiveUnits",
-    "r",
-    "radius",
-    "refX",
-    "refY",
-    "rendering-intent",
-    "repeatCount",
-    "repeatDur",
-    "requiredExtensions",
-    "requiredFeatures",
-    "restart",
-    "result",
-    "rotate",
-    "rx",
-    "ry",
-    "scale",
-    "seed",
-    "shape-rendering",
-    "slope",
-    "spacing",
-    "specularConstant",
-    "specularExponent",
-    "spreadMethod",
-    "startOffset",
-    "stdDeviation",
-    "stemh",
-    "stemv",
-    "stitchTiles",
-    "stop-color",
-    "stop-opacity",
-    "strikethrough-position",
-    "strikethrough-thickness",
-    "stroke",
-    "stroke-dasharray",
-    "stroke-dashoffset",
-    "stroke-linecap",
-    "stroke-linejoin",
-    "stroke-miterlimit",
-    "stroke-opacity",
-    "stroke-width",
-    "style",
-    "surfaceScale",
-    "systemLanguage",
-    "tableValues",
-    "target",
-    "targetX",
-    "targetY",
-    "text-anchor",
-    "text-decoration",
-    "text-rendering",
-    "textLength",
-    "title",
-    "to",
-    "transform",
-    "transform-origin",
-    "type",
-    "u1",
-    "u2",
-    "underline-position",
-    "underline-thickness",
-    "unicode",
-    "unicode-bidi",
-    "unicode-range",
-    "units-per-em",
-    "v-alphabetic",
-    "v-hanging",
-    "v-ideographic",
-    "v-mathematical",
-    "values",
-    "vector-effect",
-    "version",
-    "vert-adv-y",
-    "vert-origin-x",
-    "vert-origin-y",
-    "viewBox",
-    "visibility",
-    "width",
-    "widths",
-    "word-spacing",
-    "writing-mode",
-    "x",
-    "x-height",
-    "x1",
-    "x2",
-    "xChannelSelector",
-    "y",
-    "y1",
-    "y2",
-    "yChannelSelector",
-    "z",
-    "zoomAndPan",
-  ],
-}
diff --git a/third_party/WebKit/Source/core/svg/SVGTagNames.in b/third_party/WebKit/Source/core/svg/SVGTagNames.in
new file mode 100644
index 0000000..23f5ad8
--- /dev/null
+++ b/third_party/WebKit/Source/core/svg/SVGTagNames.in
@@ -0,0 +1,71 @@
+namespace="SVG"
+namespaceURI="http://www.w3.org/2000/svg"
+fallbackInterfaceName="SVGUnknownElement"
+fallbackJSInterfaceName="SVGElement"
+export="CORE_EXPORT"
+
+a
+animate runtimeEnabled=smil, noTypeHelpers
+animateColor runtimeEnabled=smil, interfaceName=SVGUnknownElement, JSInterfaceName=SVGElement, noConstructor
+animateMotion runtimeEnabled=smil
+animateTransform runtimeEnabled=smil
+set runtimeEnabled=smil
+circle
+clipPath
+defs
+desc
+discard runtimeEnabled=smil
+ellipse
+feBlend
+feColorMatrix
+feComponentTransfer
+feComposite
+feConvolveMatrix
+feDiffuseLighting
+feDisplacementMap
+feDistantLight
+feDropShadow
+feFlood
+feFuncA
+feFuncB
+feFuncG
+feFuncR
+feGaussianBlur
+feImage
+feMerge
+feMergeNode
+feMorphology
+feOffset
+fePointLight
+feSpecularLighting
+feSpotLight
+feTile
+feTurbulence
+filter
+foreignObject
+g
+image
+line
+linearGradient
+marker
+mask
+metadata
+mpath runtimeEnabled=smil, interfaceName=SVGMPathElement
+path
+pattern
+polygon
+polyline
+radialGradient
+rect
+script constructorNeedsCreatedByParser
+stop
+style constructorNeedsCreatedByParser
+svg interfaceName=SVGSVGElement
+switch
+symbol
+text
+textPath
+title
+tspan interfaceName=SVGTSpanElement
+use
+view
diff --git a/third_party/WebKit/Source/core/svg/SVGTagNames.json5 b/third_party/WebKit/Source/core/svg/SVGTagNames.json5
deleted file mode 100644
index bc54ea7c..0000000
--- a/third_party/WebKit/Source/core/svg/SVGTagNames.json5
+++ /dev/null
@@ -1,115 +0,0 @@
-{
-  metadata: {
-    namespace: "SVG",
-    namespaceURI: "http://www.w3.org/2000/svg",
-    fallbackInterfaceName: "SVGUnknownElement",
-    fallbackJSInterfaceName: "SVGElement",
-    export: "CORE_EXPORT",
-  },
-
-  data: [
-    "a",
-    {
-      name: "animate",
-      noTypeHelpers: true,
-      runtimeEnabled: "smil",
-    },
-    {
-      name: "animateColor",
-      JSInterfaceName: "SVGElement",
-      interfaceName: "SVGUnknownElement",
-      noConstructor: true,
-      runtimeEnabled: "smil",
-    },
-    {
-      name: "animateMotion",
-      runtimeEnabled: "smil",
-    },
-    {
-      name: "animateTransform",
-      runtimeEnabled: "smil",
-    },
-    {
-      name: "set",
-      runtimeEnabled: "smil",
-    },
-    "circle",
-    "clipPath",
-    "defs",
-    "desc",
-    {
-      name: "discard",
-      runtimeEnabled: "smil",
-    },
-    "ellipse",
-    "feBlend",
-    "feColorMatrix",
-    "feComponentTransfer",
-    "feComposite",
-    "feConvolveMatrix",
-    "feDiffuseLighting",
-    "feDisplacementMap",
-    "feDistantLight",
-    "feDropShadow",
-    "feFlood",
-    "feFuncA",
-    "feFuncB",
-    "feFuncG",
-    "feFuncR",
-    "feGaussianBlur",
-    "feImage",
-    "feMerge",
-    "feMergeNode",
-    "feMorphology",
-    "feOffset",
-    "fePointLight",
-    "feSpecularLighting",
-    "feSpotLight",
-    "feTile",
-    "feTurbulence",
-    "filter",
-    "foreignObject",
-    "g",
-    "image",
-    "line",
-    "linearGradient",
-    "marker",
-    "mask",
-    "metadata",
-    {
-      name: "mpath",
-      interfaceName: "SVGMPathElement",
-      runtimeEnabled: "smil",
-    },
-    "path",
-    "pattern",
-    "polygon",
-    "polyline",
-    "radialGradient",
-    "rect",
-    {
-      name: "script",
-      constructorNeedsCreatedByParser: true,
-    },
-    "stop",
-    {
-      name: "style",
-      constructorNeedsCreatedByParser: true,
-    },
-    {
-      name: "svg",
-      interfaceName: "SVGSVGElement",
-    },
-    "switch",
-    "symbol",
-    "text",
-    "textPath",
-    "title",
-    {
-      name: "tspan",
-      interfaceName: "SVGTSpanElement",
-    },
-    "use",
-    "view",
-  ],
-}
diff --git a/third_party/WebKit/Source/core/svg/xlinkattrs.in b/third_party/WebKit/Source/core/svg/xlinkattrs.in
new file mode 100644
index 0000000..e3e0c33
--- /dev/null
+++ b/third_party/WebKit/Source/core/svg/xlinkattrs.in
@@ -0,0 +1,11 @@
+namespace="XLink"
+namespaceURI="http://www.w3.org/1999/xlink"
+export="CORE_EXPORT"
+
+actuate
+arcrole
+href
+role
+show
+title
+type
diff --git a/third_party/WebKit/Source/core/svg/xlinkattrs.json5 b/third_party/WebKit/Source/core/svg/xlinkattrs.json5
deleted file mode 100644
index 70ac0534..0000000
--- a/third_party/WebKit/Source/core/svg/xlinkattrs.json5
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  metadata: {
-    namespace: "XLink",
-    namespaceURI: "http://www.w3.org/1999/xlink",
-    export: "CORE_EXPORT",
-  },
-
-  data: [
-    "actuate",
-    "arcrole",
-    "href",
-    "role",
-    "show",
-    "title",
-    "type",
-  ],
-}
diff --git a/third_party/WebKit/Source/core/xml/xmlattrs.in b/third_party/WebKit/Source/core/xml/xmlattrs.in
new file mode 100644
index 0000000..ae6ab01
--- /dev/null
+++ b/third_party/WebKit/Source/core/xml/xmlattrs.in
@@ -0,0 +1,6 @@
+namespace="XML"
+namespacePrefix="xml"
+namespaceURI="http://www.w3.org/XML/1998/namespace"
+
+lang
+space
diff --git a/third_party/WebKit/Source/core/xml/xmlattrs.json5 b/third_party/WebKit/Source/core/xml/xmlattrs.json5
deleted file mode 100644
index 6fa47033..0000000
--- a/third_party/WebKit/Source/core/xml/xmlattrs.json5
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  metadata: {
-    namespace: "XML",
-    namespacePrefix: "xml",
-    namespaceURI: "http://www.w3.org/XML/1998/namespace",
-  },
-
-  data: [
-    "lang",
-    "space",
-  ],
-}
diff --git a/third_party/WebKit/Source/core/xml/xmlnsattrs.in b/third_party/WebKit/Source/core/xml/xmlnsattrs.in
new file mode 100644
index 0000000..7ac415a
--- /dev/null
+++ b/third_party/WebKit/Source/core/xml/xmlnsattrs.in
@@ -0,0 +1,4 @@
+namespace="XMLNS"
+namespaceURI="http://www.w3.org/2000/xmlns/"
+
+xmlns
diff --git a/third_party/WebKit/Source/core/xml/xmlnsattrs.json5 b/third_party/WebKit/Source/core/xml/xmlnsattrs.json5
deleted file mode 100644
index 81f1684..0000000
--- a/third_party/WebKit/Source/core/xml/xmlnsattrs.json5
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  metadata: {
-    namespace: "XMLNS",
-    namespaceURI: "http://www.w3.org/2000/xmlns/",
-  },
-
-  data: [
-    "xmlns",
-  ],
-}
diff --git a/third_party/WebKit/Source/modules/eventsource/EventSource.cpp b/third_party/WebKit/Source/modules/eventsource/EventSource.cpp
index 646b470..742c938 100644
--- a/third_party/WebKit/Source/modules/eventsource/EventSource.cpp
+++ b/third_party/WebKit/Source/modules/eventsource/EventSource.cpp
@@ -350,9 +350,8 @@
                                  const String& data,
                                  const AtomicString& lastEventId) {
   MessageEvent* e = MessageEvent::create();
-  e->initMessageEvent(eventType, false, false,
-                      SerializedScriptValue::serialize(data),
-                      m_eventStreamOrigin, lastEventId, 0, nullptr);
+  e->initMessageEvent(eventType, false, false, data, m_eventStreamOrigin,
+                      lastEventId, 0, nullptr);
 
   InspectorInstrumentation::willDispatchEventSourceEvent(
       getExecutionContext(), this, eventType, lastEventId, data);
diff --git a/third_party/WebKit/Source/modules/sensor/Sensor.cpp b/third_party/WebKit/Source/modules/sensor/Sensor.cpp
index 8c01f6a..f0ed3d8 100644
--- a/third_party/WebKit/Source/modules/sensor/Sensor.cpp
+++ b/third_party/WebKit/Source/modules/sensor/Sensor.cpp
@@ -62,24 +62,24 @@
 
 Sensor::~Sensor() = default;
 
-void Sensor::start(ScriptState* scriptState, ExceptionState& exceptionState) {
+void Sensor::start() {
   if (m_state != Sensor::SensorState::Unconnected &&
       m_state != Sensor::SensorState::Idle &&
       m_state != Sensor::SensorState::Errored)
     return;
 
   initSensorProxyIfNeeded();
-
   if (!m_sensorProxy) {
-    exceptionState.throwDOMException(
-        InvalidStateError, "The Sensor is no longer associated to a frame.");
+    reportError(InvalidStateError,
+                "The Sensor is no longer associated to a frame.");
     return;
   }
+
   m_lastUpdateTimestamp = WTF::monotonicallyIncreasingTime();
   startListening();
 }
 
-void Sensor::stop(ScriptState*, ExceptionState& exceptionState) {
+void Sensor::stop() {
   if (m_state == Sensor::SensorState::Unconnected ||
       m_state == Sensor::SensorState::Idle ||
       m_state == Sensor::SensorState::Errored)
diff --git a/third_party/WebKit/Source/modules/sensor/Sensor.h b/third_party/WebKit/Source/modules/sensor/Sensor.h
index 171e3a32..f7bc333 100644
--- a/third_party/WebKit/Source/modules/sensor/Sensor.h
+++ b/third_party/WebKit/Source/modules/sensor/Sensor.h
@@ -35,8 +35,8 @@
 
   ~Sensor() override;
 
-  void start(ScriptState*, ExceptionState&);
-  void stop(ScriptState*, ExceptionState&);
+  void start();
+  void stop();
 
   // EventTarget overrides.
   const AtomicString& interfaceName() const override {
diff --git a/third_party/WebKit/Source/modules/sensor/Sensor.idl b/third_party/WebKit/Source/modules/sensor/Sensor.idl
index 56ac99f..daf1e537 100644
--- a/third_party/WebKit/Source/modules/sensor/Sensor.idl
+++ b/third_party/WebKit/Source/modules/sensor/Sensor.idl
@@ -21,8 +21,8 @@
     readonly attribute SensorState state;
     [CallWith=ScriptState] readonly attribute DOMHighResTimeStamp? timestamp;
 
-    [CallWith=ScriptState, RaisesException, MeasureAs=GenericSensorStart] void start();
-    [CallWith=ScriptState, RaisesException, MeasureAs=GenericSensorStop] void stop();
+    [MeasureAs=GenericSensorStart] void start();
+    [MeasureAs=GenericSensorStop] void stop();
 
     attribute EventHandler onerror;
     attribute EventHandler onchange;
diff --git a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp
index 2e9effb..2d0242d0a 100644
--- a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp
+++ b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp
@@ -30,6 +30,7 @@
 
 #include "modules/websockets/DocumentWebSocketChannel.h"
 
+#include <memory>
 #include "core/dom/DOMArrayBuffer.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExecutionContext.h"
@@ -45,6 +46,7 @@
 #include "modules/websockets/WebSocketChannelClient.h"
 #include "modules/websockets/WebSocketFrame.h"
 #include "modules/websockets/WebSocketHandleImpl.h"
+#include "platform/WebFrameScheduler.h"
 #include "platform/loader/fetch/UniqueIdentifier.h"
 #include "platform/network/NetworkLog.h"
 #include "platform/network/WebSocketHandshakeRequest.h"
@@ -52,7 +54,6 @@
 #include "public/platform/InterfaceProvider.h"
 #include "public/platform/Platform.h"
 #include "wtf/PtrUtil.h"
-#include <memory>
 
 namespace blink {
 
@@ -165,6 +166,11 @@
         ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message));
   }
 
+  if (document()->frame()) {
+    connection_handle_for_scheduler_ =
+        document()->frame()->frameScheduler()->onActiveConnectionCreated();
+  }
+
   m_url = url;
   Vector<String> protocols;
   // Avoid placing an empty token in the Vector when the protocol string is
@@ -288,6 +294,8 @@
   NETWORK_DVLOG(1) << this << " fail(" << reason << ")";
   // m_handle and m_client can be null here.
 
+  connection_handle_for_scheduler_.reset();
+
   InspectorInstrumentation::didReceiveWebSocketFrameError(document(),
                                                           m_identifier, reason);
   const String message = "WebSocket connection to '" + m_url.elidedString() +
@@ -311,6 +319,7 @@
         "data", InspectorWebSocketEvent::data(document(), m_identifier));
     InspectorInstrumentation::didCloseWebSocket(document(), m_identifier);
   }
+  connection_handle_for_scheduler_.reset();
   abortAsyncOperations();
   m_handle.reset();
   m_client = nullptr;
@@ -503,6 +512,8 @@
   NETWORK_DVLOG(1) << this << " didFail(" << handle << ", " << String(message)
                    << ")";
 
+  connection_handle_for_scheduler_.reset();
+
   DCHECK(m_handle);
   DCHECK_EQ(handle, m_handle.get());
 
@@ -585,6 +596,8 @@
   NETWORK_DVLOG(1) << this << " didClose(" << handle << ", " << wasClean << ", "
                    << code << ", " << String(reason) << ")";
 
+  connection_handle_for_scheduler_.reset();
+
   DCHECK(m_handle);
   DCHECK_EQ(handle, m_handle.get());
 
diff --git a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h
index 6e678c9..90eb1f2 100644
--- a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h
+++ b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h
@@ -31,6 +31,8 @@
 #ifndef DocumentWebSocketChannel_h
 #define DocumentWebSocketChannel_h
 
+#include <stdint.h>
+#include <memory>
 #include "bindings/core/v8/SourceLocation.h"
 #include "core/fileapi/Blob.h"
 #include "core/fileapi/FileError.h"
@@ -38,6 +40,7 @@
 #include "modules/websockets/WebSocketChannel.h"
 #include "modules/websockets/WebSocketHandle.h"
 #include "modules/websockets/WebSocketHandleClient.h"
+#include "platform/WebFrameScheduler.h"
 #include "platform/heap/Handle.h"
 #include "platform/weborigin/KURL.h"
 #include "wtf/Deque.h"
@@ -46,8 +49,6 @@
 #include "wtf/Vector.h"
 #include "wtf/text/CString.h"
 #include "wtf/text/WTFString.h"
-#include <memory>
-#include <stdint.h>
 
 namespace blink {
 
@@ -173,6 +174,8 @@
   uint64_t m_sendingQuota;
   uint64_t m_receivedDataSizeForFlowControl;
   size_t m_sentSizeOfTopMessage;
+  std::unique_ptr<WebFrameScheduler::ActiveConnectionHandle>
+      connection_handle_for_scheduler_;
 
   std::unique_ptr<SourceLocation> m_locationAtConstruction;
   RefPtr<WebSocketHandshakeRequest> m_handshakeRequest;
diff --git a/third_party/WebKit/Source/platform/MemoryCoordinator.cpp b/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
index b414dbf4..8dd8a65 100644
--- a/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
+++ b/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
@@ -74,6 +74,12 @@
   WTF::Partitions::decommitFreeableMemory();
 }
 
+void MemoryCoordinator::onPurgeMemory() {
+  // TODO(tasak|bashi): Move code from onMemoryStateChange(). Currently
+  // onMemoryStateChange() is called when the purge+throttled experiment is
+  // enabled.
+}
+
 void MemoryCoordinator::clearMemory() {
   // Clear the image cache.
   // TODO(tasak|bashi): Make ImageDecodingStore and FontCache be
diff --git a/third_party/WebKit/Source/platform/MemoryCoordinator.h b/third_party/WebKit/Source/platform/MemoryCoordinator.h
index bb2ab3fa..939c3cec 100644
--- a/third_party/WebKit/Source/platform/MemoryCoordinator.h
+++ b/third_party/WebKit/Source/platform/MemoryCoordinator.h
@@ -51,6 +51,8 @@
 
   void onMemoryStateChange(MemoryState);
 
+  void onPurgeMemory();
+
   DECLARE_TRACE();
 
  private:
diff --git a/third_party/WebKit/Source/platform/WebFrameScheduler.h b/third_party/WebKit/Source/platform/WebFrameScheduler.h
index 069fedf..0a14a9d9 100644
--- a/third_party/WebKit/Source/platform/WebFrameScheduler.h
+++ b/third_party/WebKit/Source/platform/WebFrameScheduler.h
@@ -7,6 +7,8 @@
 
 #include "wtf/RefPtr.h"
 
+#include <memory>
+
 namespace blink {
 
 class WebTaskRunner;
@@ -16,6 +18,15 @@
  public:
   virtual ~WebFrameScheduler() {}
 
+  class ActiveConnectionHandle {
+   public:
+    ActiveConnectionHandle() {}
+    virtual ~ActiveConnectionHandle() {}
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(ActiveConnectionHandle);
+  };
+
   // The scheduler may throttle tasks associated with offscreen frames.
   virtual void setFrameVisible(bool) {}
 
@@ -67,6 +78,13 @@
   // Tells the scheduler that the first meaningful paint has occured for this
   // frame.
   virtual void onFirstMeaningfulPaint() {}
+
+  // Notifies scheduler that this frame has established an active real time
+  // connection (websocket, webrtc, etc). When connection is closed this handle
+  // must be destroyed.
+  virtual std::unique_ptr<ActiveConnectionHandle> onActiveConnectionCreated() {
+    return nullptr;
+  };
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebMemoryCoordinator.cpp b/third_party/WebKit/Source/platform/exported/WebMemoryCoordinator.cpp
index f1ba1a8..e1721072 100644
--- a/third_party/WebKit/Source/platform/exported/WebMemoryCoordinator.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebMemoryCoordinator.cpp
@@ -17,4 +17,8 @@
   MemoryCoordinator::instance().onMemoryStateChange(state);
 }
 
+void WebMemoryCoordinator::onPurgeMemory() {
+  MemoryCoordinator::instance().onPurgeMemory();
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
index 027e3b7..b14a019 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -28,6 +28,18 @@
 
 }  // namespace
 
+WebFrameSchedulerImpl::ActiveConnectionHandleImpl::ActiveConnectionHandleImpl(
+    WebFrameSchedulerImpl* frame_scheduler)
+    : frame_scheduler_(frame_scheduler->AsWeakPtr()) {
+  frame_scheduler->didOpenActiveConnection();
+}
+
+WebFrameSchedulerImpl::ActiveConnectionHandleImpl::
+    ~ActiveConnectionHandleImpl() {
+  if (frame_scheduler_)
+    frame_scheduler_->didCloseActiveConnection();
+}
+
 WebFrameSchedulerImpl::WebFrameSchedulerImpl(
     RendererSchedulerImpl* renderer_scheduler,
     WebViewSchedulerImpl* parent_web_view_scheduler,
@@ -38,9 +50,13 @@
       frame_visible_(true),
       page_throttled_(true),
       frame_suspended_(false),
-      cross_origin_(false) {}
+      cross_origin_(false),
+      active_connection_count_(0),
+      weak_factory_(this) {}
 
 WebFrameSchedulerImpl::~WebFrameSchedulerImpl() {
+  weak_factory_.InvalidateWeakPtrs();
+
   if (loading_task_queue_) {
     loading_task_queue_->UnregisterTaskQueue();
     loading_task_queue_->SetBlameContext(nullptr);
@@ -57,8 +73,12 @@
     unthrottled_task_queue_->SetBlameContext(nullptr);
   }
 
-  if (parent_web_view_scheduler_)
+  if (parent_web_view_scheduler_) {
     parent_web_view_scheduler_->Unregister(this);
+
+    if (active_connection_count_)
+      parent_web_view_scheduler_->OnConnectionUpdated();
+  }
 }
 
 void WebFrameSchedulerImpl::DetachFromWebViewScheduler() {
@@ -167,6 +187,19 @@
     parent_web_view_scheduler_->DidStopLoading(identifier);
 }
 
+void WebFrameSchedulerImpl::didOpenActiveConnection() {
+  ++active_connection_count_;
+  if (parent_web_view_scheduler_)
+    parent_web_view_scheduler_->OnConnectionUpdated();
+}
+
+void WebFrameSchedulerImpl::didCloseActiveConnection() {
+  DCHECK_GT(active_connection_count_, 0);
+  --active_connection_count_;
+  if (parent_web_view_scheduler_)
+    parent_web_view_scheduler_->OnConnectionUpdated();
+}
+
 void WebFrameSchedulerImpl::setDocumentParsingInBackground(
     bool background_parser_active) {
   if (background_parser_active)
@@ -224,6 +257,12 @@
   renderer_scheduler_->OnFirstMeaningfulPaint();
 }
 
+std::unique_ptr<WebFrameScheduler::ActiveConnectionHandle>
+WebFrameSchedulerImpl::onActiveConnectionCreated() {
+  return base::MakeUnique<WebFrameSchedulerImpl::ActiveConnectionHandleImpl>(
+      this);
+}
+
 bool WebFrameSchedulerImpl::ShouldThrottleTimers() const {
   if (page_throttled_)
     return true;
@@ -244,5 +283,9 @@
   }
 }
 
+base::WeakPtr<WebFrameSchedulerImpl> WebFrameSchedulerImpl::AsWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
index 141ea7cb..9111528d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
@@ -9,10 +9,11 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "base/trace_event/trace_event.h"
 #include "platform/WebFrameScheduler.h"
-#include "public/platform/scheduler/base/task_queue.h"
 #include "public/platform/WebCommon.h"
+#include "public/platform/scheduler/base/task_queue.h"
 
 namespace base {
 namespace trace_event {
@@ -50,18 +51,37 @@
   void didStopLoading(unsigned long identifier) override;
   void setDocumentParsingInBackground(bool background_parser_active) override;
   void onFirstMeaningfulPaint() override;
+  std::unique_ptr<ActiveConnectionHandle> onActiveConnectionCreated() override;
 
   void AsValueInto(base::trace_event::TracedValue* state) const;
 
+  bool has_active_connection() const { return active_connection_count_; }
+
  private:
   friend class WebViewSchedulerImpl;
 
+  class ActiveConnectionHandleImpl : public ActiveConnectionHandle {
+   public:
+    ActiveConnectionHandleImpl(WebFrameSchedulerImpl* frame_scheduler);
+    ~ActiveConnectionHandleImpl() override;
+
+   private:
+    base::WeakPtr<WebFrameSchedulerImpl> frame_scheduler_;
+
+    DISALLOW_COPY_AND_ASSIGN(ActiveConnectionHandleImpl);
+  };
+
   void DetachFromWebViewScheduler();
   void RemoveTimerQueueFromBackgroundTimeBudgetPool();
   void ApplyPolicyToTimerQueue();
   bool ShouldThrottleTimers() const;
   void UpdateTimerThrottling(bool was_throttled);
 
+  void didOpenActiveConnection();
+  void didCloseActiveConnection();
+
+  base::WeakPtr<WebFrameSchedulerImpl> AsWeakPtr();
+
   scoped_refptr<TaskQueue> loading_task_queue_;
   scoped_refptr<TaskQueue> timer_task_queue_;
   scoped_refptr<TaskQueue> unthrottled_task_queue_;
@@ -77,6 +97,9 @@
   bool page_throttled_;
   bool frame_suspended_;
   bool cross_origin_;
+  int active_connection_count_;
+
+  base::WeakPtrFactory<WebFrameSchedulerImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(WebFrameSchedulerImpl);
 };
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc
index a5ccc87b..d14a7f7 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc
@@ -108,6 +108,7 @@
       virtual_time_(false),
       is_audio_playing_(false),
       reported_background_throttling_since_navigation_(false),
+      has_active_connection_(false),
       background_time_budget_pool_(nullptr),
       settings_(settings) {
   renderer_scheduler->AddWebViewScheduler(this);
@@ -238,6 +239,10 @@
   renderer_scheduler_->OnAudioStateChanged();
 }
 
+bool WebViewSchedulerImpl::hasActiveConnectionForTest() const {
+  return has_active_connection_;
+}
+
 void WebViewSchedulerImpl::ApplyVirtualTimePolicy() {
   if (virtual_time_policy_ != VirtualTimePolicy::DETERMINISTIC_LOADING) {
     return;
@@ -255,6 +260,18 @@
   return is_audio_playing_;
 }
 
+void WebViewSchedulerImpl::OnConnectionUpdated() {
+  bool has_active_connection = false;
+  for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) {
+    has_active_connection |= frame_scheduler->has_active_connection();
+  }
+
+  if (has_active_connection_ != has_active_connection) {
+    has_active_connection_ = has_active_connection;
+    UpdateBackgroundThrottlingState();
+  }
+}
+
 void WebViewSchedulerImpl::AsValueInto(
     base::trace_event::TracedValue* state) const {
   state->SetDouble("pending_loads", pending_loads_.size());
@@ -335,10 +352,7 @@
   for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) {
     frame_scheduler->setPageThrottled(true);
   }
-  if (background_time_budget_pool_) {
-    LazyNow lazy_now(renderer_scheduler_->tick_clock());
-    background_time_budget_pool_->EnableThrottling(&lazy_now);
-  }
+  UpdateBackgroundBudgetPoolThrottlingState();
 }
 
 void WebViewSchedulerImpl::UpdateBackgroundThrottlingState() {
@@ -349,15 +363,29 @@
     for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) {
       frame_scheduler->setPageThrottled(false);
     }
-    if (background_time_budget_pool_) {
-      LazyNow lazy_now(renderer_scheduler_->tick_clock());
-      background_time_budget_pool_->DisableThrottling(&lazy_now);
-    }
+    UpdateBackgroundBudgetPoolThrottlingState();
   } else {
-    // TODO(altimin): Consider moving this logic into PumpThrottledTasks.
-    renderer_scheduler_->ControlTaskRunner()->PostDelayedTask(
-        FROM_HERE, delayed_background_throttling_enabler_.callback(),
-        kBackgroundThrottlingGracePeriod);
+    if (has_active_connection_) {
+      // If connection is active, update state immediately to stop throttling.
+      UpdateBackgroundBudgetPoolThrottlingState();
+    } else {
+      // TODO(altimin): Consider moving this logic into PumpThrottledTasks.
+      renderer_scheduler_->ControlTaskRunner()->PostDelayedTask(
+          FROM_HERE, delayed_background_throttling_enabler_.callback(),
+          kBackgroundThrottlingGracePeriod);
+    }
+  }
+}
+
+void WebViewSchedulerImpl::UpdateBackgroundBudgetPoolThrottlingState() {
+  if (!background_time_budget_pool_)
+    return;
+
+  LazyNow lazy_now(renderer_scheduler_->tick_clock());
+  if (page_visible_ || has_active_connection_) {
+    background_time_budget_pool_->DisableThrottling(&lazy_now);
+  } else {
+    background_time_budget_pool_->EnableThrottling(&lazy_now);
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h
index 423100f..d762a11 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h
@@ -47,6 +47,7 @@
   bool virtualTimeAllowedToAdvance() const override;
   void setVirtualTimePolicy(VirtualTimePolicy virtual_time_policy) override;
   void audioStateChanged(bool is_audio_playing) override;
+  bool hasActiveConnectionForTest() const override;
 
   // Virtual for testing.
   virtual void ReportIntervention(const std::string& message);
@@ -63,6 +64,8 @@
 
   bool IsAudioPlaying() const;
 
+  void OnConnectionUpdated();
+
   void AsValueInto(base::trace_event::TracedValue* state) const;
 
  private:
@@ -83,6 +86,11 @@
   // call to enable it after a grace period.
   void UpdateBackgroundThrottlingState();
 
+  // As a part of UpdateBackgroundThrottlingState set correct
+  // background_time_budget_pool_ state depending on page visibility and
+  // number of active connections.
+  void UpdateBackgroundBudgetPoolThrottlingState();
+
   void EnableBackgroundThrottling();
 
   std::set<WebFrameSchedulerImpl*> frame_schedulers_;
@@ -99,6 +107,7 @@
   bool virtual_time_;
   bool is_audio_playing_;
   bool reported_background_throttling_since_navigation_;
+  bool has_active_connection_;
   TaskQueueThrottler::TimeBudgetPool*
       background_time_budget_pool_;  // Not owned.
   CancelableClosureHolder delayed_background_throttling_enabler_;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
index 5f3ccdb..61961b6 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -685,5 +685,105 @@
                   base::TimeTicks() + base::TimeDelta::FromSeconds(26)));
 }
 
+TEST_F(WebViewSchedulerImplTest, OpenWebSocketExemptsFromBudgetThrottling) {
+  ScopedExpensiveBackgroundTimerThrottlingForTest
+      budget_background_throttling_enabler(true);
+
+  std::vector<base::TimeTicks> run_times;
+  FakeWebViewSchedulerSettings web_view_scheduler_settings;
+  std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler(
+      new WebViewSchedulerImpl(nullptr, &web_view_scheduler_settings,
+                               scheduler_.get(), false));
+
+  std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler1 =
+      web_view_scheduler->createWebFrameSchedulerImpl(nullptr);
+  std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler2 =
+      web_view_scheduler->createWebFrameSchedulerImpl(nullptr);
+
+  web_view_scheduler->setPageVisible(false);
+
+  // Wait for 20s to avoid initial throttling delay.
+  mock_task_runner_->RunUntilTime(base::TimeTicks() +
+                                  base::TimeDelta::FromMilliseconds(20500));
+
+  for (size_t i = 0; i < 3; ++i) {
+    web_frame_scheduler1->timerTaskRunner()->postDelayedTask(
+        BLINK_FROM_HERE,
+        base::Bind(&ExpensiveTestTask, clock_.get(), &run_times), 1);
+  }
+
+  mock_task_runner_->RunUntilTime(base::TimeTicks() +
+                                  base::TimeDelta::FromMilliseconds(55500));
+
+  // Check that tasks are throttled.
+  EXPECT_THAT(
+      run_times,
+      ElementsAre(base::TimeTicks() + base::TimeDelta::FromSeconds(21),
+                  base::TimeTicks() + base::TimeDelta::FromSeconds(26),
+                  base::TimeTicks() + base::TimeDelta::FromSeconds(51)));
+  run_times.clear();
+
+  std::unique_ptr<WebFrameScheduler::ActiveConnectionHandle>
+      websocket_connection = web_frame_scheduler1->onActiveConnectionCreated();
+
+  for (size_t i = 0; i < 3; ++i) {
+    web_frame_scheduler1->timerTaskRunner()->postDelayedTask(
+        BLINK_FROM_HERE,
+        base::Bind(&ExpensiveTestTask, clock_.get(), &run_times), 1);
+  }
+
+  mock_task_runner_->RunUntilTime(base::TimeTicks() +
+                                  base::TimeDelta::FromMilliseconds(58500));
+
+  // Check that the timer task queue from the first frame is aligned,
+  // but not throttled.
+  EXPECT_THAT(
+      run_times,
+      ElementsAre(
+          base::TimeTicks() + base::TimeDelta::FromMilliseconds(56000),
+          base::TimeTicks() + base::TimeDelta::FromMilliseconds(56250),
+          base::TimeTicks() + base::TimeDelta::FromMilliseconds(56500)));
+  run_times.clear();
+
+  for (size_t i = 0; i < 3; ++i) {
+    web_frame_scheduler2->timerTaskRunner()->postDelayedTask(
+        BLINK_FROM_HERE,
+        base::Bind(&ExpensiveTestTask, clock_.get(), &run_times), 1);
+  }
+
+  mock_task_runner_->RunUntilTime(base::TimeTicks() +
+                                  base::TimeDelta::FromMilliseconds(59500));
+
+  // Check that the second frame scheduler becomes unthrottled.
+  EXPECT_THAT(
+      run_times,
+      ElementsAre(
+          base::TimeTicks() + base::TimeDelta::FromMilliseconds(59000),
+          base::TimeTicks() + base::TimeDelta::FromMilliseconds(59250),
+          base::TimeTicks() + base::TimeDelta::FromMilliseconds(59500)));
+  run_times.clear();
+
+  websocket_connection.reset();
+
+  // Wait for 10s to enable throttling back.
+  mock_task_runner_->RunUntilTime(base::TimeTicks() +
+                                  base::TimeDelta::FromMilliseconds(70500));
+
+  for (size_t i = 0; i < 3; ++i) {
+    web_frame_scheduler1->timerTaskRunner()->postDelayedTask(
+        BLINK_FROM_HERE,
+        base::Bind(&ExpensiveTestTask, clock_.get(), &run_times), 1);
+  }
+
+  mock_task_runner_->RunUntilIdle();
+
+  // WebSocket is closed, budget-based throttling now applies.
+  EXPECT_THAT(
+      run_times,
+      ElementsAre(base::TimeTicks() + base::TimeDelta::FromSeconds(84),
+                  base::TimeTicks() + base::TimeDelta::FromSeconds(109),
+                  base::TimeTicks() + base::TimeDelta::FromSeconds(134)));
+}
+
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index 18cc77e..93bf8b9 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -327,6 +327,7 @@
 
     # FIXME: Move the tests from web/tests/ to appropriate places.
     # crbug.com/353585
+    "tests/ActiveConnectionThrottlingTest.cpp",
     "tests/ActivityLoggerTest.cpp",
     "tests/BrowserControlsTest.cpp",
     "tests/ChromeClientImplTest.cpp",
diff --git a/third_party/WebKit/Source/web/tests/ActiveConnectionThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/ActiveConnectionThrottlingTest.cpp
new file mode 100644
index 0000000..96488cd
--- /dev/null
+++ b/third_party/WebKit/Source/web/tests/ActiveConnectionThrottlingTest.cpp
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code if governed by a BSD-style license that can be
+// found in LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebViewScheduler.h"
+#include "web/WebViewImpl.h"
+#include "web/tests/sim/SimRequest.h"
+#include "web/tests/sim/SimTest.h"
+
+using testing::_;
+
+namespace blink {
+
+class ActiveConnectionThrottlingTest : public SimTest {};
+
+TEST_F(ActiveConnectionThrottlingTest, WebSocketStopsThrottling) {
+  SimRequest mainResource("https://example.com/", "text/html");
+
+  loadURL("https://example.com/");
+
+  EXPECT_FALSE(webView().scheduler()->hasActiveConnectionForTest());
+
+  mainResource.complete(
+      "(<script>"
+      "  var socket = new WebSocket(\"ws://www.example.com/websocket\");"
+      "</script>)");
+
+  EXPECT_TRUE(webView().scheduler()->hasActiveConnectionForTest());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index a9b73309..7f22058 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -38,6 +38,7 @@
 #include "SkCanvas.h"
 #include "bindings/core/v8/SerializedScriptValueFactory.h"
 #include "bindings/core/v8/V8Node.h"
+#include "bindings/core/v8/serialization/V8ScriptValueSerializer.h"
 #include "core/clipboard/DataTransfer.h"
 #include "core/css/StyleSheetContents.h"
 #include "core/css/resolver/StyleResolver.h"
@@ -990,6 +991,21 @@
   EXPECT_EQ(std::string::npos, content.find("Message 2."));
 }
 
+namespace {
+
+RefPtr<SerializedScriptValue> serializeString(const StringView& message,
+                                              ScriptState* scriptState) {
+  // This is inefficient, but avoids duplicating serialization logic for the
+  // sake of this test.
+  NonThrowableExceptionState exceptionState;
+  ScriptState::Scope scope(scriptState);
+  V8ScriptValueSerializer serializer(scriptState);
+  return serializer.serialize(v8String(scriptState->isolate(), message),
+                              nullptr, exceptionState);
+}
+
+}  // namespace
+
 TEST_P(ParameterizedWebFrameTest, PostMessageThenDetach) {
   FrameTestHelpers::WebViewHelper webViewHelper;
   webViewHelper.initializeAndLoad("about:blank");
@@ -997,10 +1013,11 @@
   LocalFrame* frame =
       toLocalFrame(webViewHelper.webView()->page()->mainFrame());
   NonThrowableExceptionState exceptionState;
+  RefPtr<SerializedScriptValue> message =
+      serializeString("message", ScriptState::forMainWorld(frame));
   MessagePortArray messagePorts;
-  frame->domWindow()->postMessage(SerializedScriptValue::serialize("message"),
-                                  messagePorts, "*", frame->domWindow(),
-                                  exceptionState);
+  frame->domWindow()->postMessage(message, messagePorts, "*",
+                                  frame->domWindow(), exceptionState);
   webViewHelper.reset();
   EXPECT_FALSE(exceptionState.hadException());
 
diff --git a/third_party/WebKit/public/platform/WebMemoryCoordinator.h b/third_party/WebKit/public/platform/WebMemoryCoordinator.h
index 04f70a7..7b3588d 100644
--- a/third_party/WebKit/public/platform/WebMemoryCoordinator.h
+++ b/third_party/WebKit/public/platform/WebMemoryCoordinator.h
@@ -19,6 +19,8 @@
   BLINK_PLATFORM_EXPORT static void onMemoryPressure(WebMemoryPressureLevel);
 
   BLINK_PLATFORM_EXPORT static void onMemoryStateChange(MemoryState);
+
+  BLINK_PLATFORM_EXPORT static void onPurgeMemory();
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/WebViewScheduler.h b/third_party/WebKit/public/platform/WebViewScheduler.h
index 55f6184..77e003ee 100644
--- a/third_party/WebKit/public/platform/WebViewScheduler.h
+++ b/third_party/WebKit/public/platform/WebViewScheduler.h
@@ -79,6 +79,8 @@
   virtual void setVirtualTimePolicy(VirtualTimePolicy) = 0;
 
   virtual void audioStateChanged(bool isAudioPlaying) = 0;
+
+  virtual bool hasActiveConnectionForTest() const = 0;
 };
 
 }  // namespace blink
diff --git a/ui/base/ui_base_switches.cc b/ui/base/ui_base_switches.cc
index 2544b1a5..ae808387 100644
--- a/ui/base/ui_base_switches.cc
+++ b/ui/base/ui_base_switches.cc
@@ -34,18 +34,12 @@
 // Disables use of DWM composition for top level windows.
 const char kDisableDwmComposition[] = "disable-dwm-composition";
 
-// Disables large icons on the New Tab page.
-const char kDisableIconNtp[] = "disable-icon-ntp";
-
 // Disables touch adjustment.
 const char kDisableTouchAdjustment[] = "disable-touch-adjustment";
 
 // Disables touch event based drag and drop.
 const char kDisableTouchDragDrop[] = "disable-touch-drag-drop";
 
-// Enables large icons on the New Tab page.
-const char kEnableIconNtp[] = "enable-icon-ntp";
-
 // Enables touch event based drag and drop.
 const char kEnableTouchDragDrop[] = "enable-touch-drag-drop";
 
diff --git a/ui/base/ui_base_switches.h b/ui/base/ui_base_switches.h
index 353c9358..eb581ac 100644
--- a/ui/base/ui_base_switches.h
+++ b/ui/base/ui_base_switches.h
@@ -26,10 +26,8 @@
 #endif
 
 UI_BASE_EXPORT extern const char kDisableDwmComposition[];
-UI_BASE_EXPORT extern const char kDisableIconNtp[];
 UI_BASE_EXPORT extern const char kDisableTouchAdjustment[];
 UI_BASE_EXPORT extern const char kDisableTouchDragDrop[];
-UI_BASE_EXPORT extern const char kEnableIconNtp[];
 UI_BASE_EXPORT extern const char kEnableTouchDragDrop[];
 UI_BASE_EXPORT extern const char kLang[];
 UI_BASE_EXPORT extern const char kMaterialDesignInkDropAnimationSpeed[];
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.html b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.html
index 74ef004..2ed13112 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.html
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.html
@@ -13,10 +13,11 @@
     }
   </style>
   <template>
-    <iron-icon id="indicator" tabindex=0
+    <iron-icon id="indicator" tabindex=0 aria-describedby="tooltip"
         hidden$="[[!isIndicatorVisible(indicatorType)]]"
         icon="[[getPolicyIndicatorIcon(indicatorType)]]"></iron-icon>
-    <paper-tooltip for="indicator" position="top" fit-to-visible-bounds>
+    <paper-tooltip id="tooltip" for="indicator" position="top"
+        fit-to-visible-bounds>
       [[getTooltip_(indicatorType, pref)]]
     </paper-tooltip>
   </template>