diff --git a/DEPS b/DEPS
index 977b346..33053eb 100644
--- a/DEPS
+++ b/DEPS
@@ -643,7 +643,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd458ada06171a85af00367251a4ed55db7fe2018',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '0be3851088f81b462d0b0e29800fe9e49a9696f3', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + 'f6e0b1a420a32c4795f86e286806e0fe6da0dd75', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/chrome/browser/ui/views/harmony/harmony_typography_provider.cc b/chrome/browser/ui/views/harmony/harmony_typography_provider.cc
index 2357baa3..32c04305 100644
--- a/chrome/browser/ui/views/harmony/harmony_typography_provider.cc
+++ b/chrome/browser/ui/views/harmony/harmony_typography_provider.cc
@@ -140,7 +140,20 @@
       break;
   }
 
-  // Ignore |style| since it only affects color in the Harmony spec.
+  // Use a bold style for emphasized text in body contexts, and ignore |style|
+  // otherwise.
+  if (style == STYLE_EMPHASIZED) {
+    switch (context) {
+      case CONTEXT_BODY_TEXT_SMALL:
+      case CONTEXT_BODY_TEXT_LARGE:
+      case views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT:
+        font_weight = gfx::Font::Weight::BOLD;
+        break;
+
+      default:
+        break;
+    }
+  }
 
   return ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
       size_delta, gfx::Font::NORMAL, font_weight);
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 1efe718..4d193cf 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -129,7 +129,6 @@
   testonly = true
 
   sources = [
-    "../../ui/events/ozone/gamepad/gamepad_event.cc",
     "buffer_unittest.cc",
     "client_controlled_shell_surface_unittest.cc",
     "data_device_unittest.cc",
diff --git a/components/exo/gaming_seat.cc b/components/exo/gaming_seat.cc
index d5440c6..4a5ef0abc 100644
--- a/components/exo/gaming_seat.cc
+++ b/components/exo/gaming_seat.cc
@@ -90,16 +90,16 @@
 }
 
 void GamingSeat::OnGamepadEvent(const ui::GamepadEvent& event) {
-  auto it = gamepads_.find(event.device_id());
+  auto it = gamepads_.find(event.device_id);
   if (it == gamepads_.end())
     return;
 
-  switch (event.type()) {
+  switch (event.type) {
     case ui::GamepadEventType::BUTTON:
-      it->second->OnButton(event.code(), event.value(), event.value());
+      it->second->OnButton(event.code, event.value, event.value);
       break;
     case ui::GamepadEventType::AXIS:
-      it->second->OnAxis(event.code(), event.value());
+      it->second->OnAxis(event.code, event.value);
       break;
     case ui::GamepadEventType::FRAME:
       it->second->OnFrame();
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 2da5ca8..09fcfc8 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -854,6 +854,20 @@
   return offscreen;
 }
 
+std::set<int32_t> BrowserAccessibility::GetReverseRelations(
+    ui::AXIntAttribute attr,
+    int32_t dst_id) {
+  DCHECK(manager_);
+  return manager_->ax_tree()->GetReverseRelations(attr, dst_id);
+}
+
+std::set<int32_t> BrowserAccessibility::GetReverseRelations(
+    ui::AXIntListAttribute attr,
+    int32_t dst_id) {
+  DCHECK(manager_);
+  return manager_->ax_tree()->GetReverseRelations(attr, dst_id);
+}
+
 gfx::NativeViewAccessible BrowserAccessibility::GetNativeViewAccessible() {
   // TODO(703369) On Windows, where we have started to migrate to an
   // AXPlatformNode implementation, the BrowserAccessibilityWin subclass has
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index ac32ed4..c86fa3035 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -347,6 +347,10 @@
   bool AccessibilityPerformAction(const ui::AXActionData& data) override;
   bool ShouldIgnoreHoveredStateForTesting() override;
   bool IsOffscreen() const override;
+  std::set<int32_t> GetReverseRelations(ui::AXIntAttribute attr,
+                                        int32_t dst_id) override;
+  std::set<int32_t> GetReverseRelations(ui::AXIntListAttribute attr,
+                                        int32_t dst_id) override;
 
  protected:
   using BrowserAccessibilityPositionInstance =
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index 634188fd..56be8f7 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -1801,8 +1801,6 @@
       owner()->GetString16Attribute(ui::AX_ATTR_DESCRIPTION);
 
   win_attributes_->value = GetValue();
-
-  CalculateRelationships();
 }
 
 void BrowserAccessibilityComWin::UpdateStep2ComputeHypertext() {
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 9c49053..0d8594f3 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -282,7 +282,8 @@
   for (size_t i = 0; !eof; ++i) {
     const GpuFeatureData gpu_feature_data = GetGpuFeatureData(i, &eof);
     std::string status;
-    if (gpu_feature_data.disabled || gpu_access_blocked) {
+    if (gpu_feature_data.disabled || gpu_access_blocked ||
+        gpu_feature_data.status == gpu::kGpuFeatureStatusDisabled) {
       status = "disabled";
       if (gpu_feature_data.fallback_to_software)
         status += "_software";
diff --git a/content/browser/gpu/gpu_data_manager_impl.cc b/content/browser/gpu/gpu_data_manager_impl.cc
index ccb7c4d..269bb59 100644
--- a/content/browser/gpu/gpu_data_manager_impl.cc
+++ b/content/browser/gpu/gpu_data_manager_impl.cc
@@ -118,11 +118,6 @@
   private_->RequestVideoMemoryUsageStatsUpdate(callback);
 }
 
-bool GpuDataManagerImpl::ShouldUseSwiftShader() const {
-  base::AutoLock auto_lock(lock_);
-  return private_->ShouldUseSwiftShader();
-}
-
 void GpuDataManagerImpl::AddObserver(
     GpuDataManagerObserver* observer) {
   base::AutoLock auto_lock(lock_);
@@ -152,10 +147,14 @@
   private_->DisableHardwareAcceleration();
 }
 
+void GpuDataManagerImpl::DisableSwiftShader() {
+  base::AutoLock auto_lock(lock_);
+  private_->DisableSwiftShader();
+}
+
 bool GpuDataManagerImpl::HardwareAccelerationEnabled() const {
   base::AutoLock auto_lock(lock_);
-  return !private_->ShouldUseSwiftShader() &&
-         private_->GpuAccessAllowed(nullptr);
+  return private_->HardwareAccelerationEnabled();
 }
 
 void GpuDataManagerImpl::GetDisabledExtensions(
@@ -261,11 +260,6 @@
   private_->DisableDomainBlockingFor3DAPIsForTesting();
 }
 
-size_t GpuDataManagerImpl::GetBlacklistedFeatureCount() const {
-  base::AutoLock auto_lock(lock_);
-  return private_->GetBlacklistedFeatureCount();
-}
-
 bool GpuDataManagerImpl::UpdateActiveGpu(uint32_t vendor_id,
                                          uint32_t device_id) {
   base::AutoLock auto_lock(lock_);
diff --git a/content/browser/gpu/gpu_data_manager_impl.h b/content/browser/gpu/gpu_data_manager_impl.h
index 9f90dd0..84a85baf 100644
--- a/content/browser/gpu/gpu_data_manager_impl.h
+++ b/content/browser/gpu/gpu_data_manager_impl.h
@@ -73,7 +73,6 @@
   void RequestVideoMemoryUsageStatsUpdate(
       const base::Callback<void(const gpu::VideoMemoryUsageStats& stats)>&
           callback) const override;
-  bool ShouldUseSwiftShader() const override;
   // TODO(kbr): the threading model for the GpuDataManagerObservers is
   // not well defined, and it's impossible for callers to correctly
   // delete observers from anywhere except in one of the observer's
@@ -167,9 +166,6 @@
                           int render_frame_id,
                           ThreeDAPIType requester);
 
-  // Get number of features being blacklisted.
-  size_t GetBlacklistedFeatureCount() const;
-
   // Set the active gpu.
   // Return true if it's a different GPU from the previous active one.
   bool UpdateActiveGpu(uint32_t vendor_id, uint32_t device_id);
@@ -177,6 +173,8 @@
   // Called when GPU process initialization failed.
   void OnGpuProcessInitFailure();
 
+  void DisableSwiftShader();
+
  private:
   friend class GpuDataManagerImplPrivate;
   friend class GpuDataManagerImplPrivateTest;
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index ebbeb0a..974482b 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -285,11 +285,6 @@
   BLOCK_STATUS_MAX
 };
 
-bool ShouldDisableHardwareAcceleration() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kDisableGpu);
-}
-
 void OnVideoMemoryUsageStats(
     const base::Callback<void(const gpu::VideoMemoryUsageStats& stats)>&
         callback,
@@ -344,21 +339,21 @@
   }
 }
 
-size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
-  // SwiftShader blacklists all features
-  return use_swiftshader_ ? gpu::NUMBER_OF_GPU_FEATURE_TYPES
-                          : blacklisted_features_.size();
-}
-
 gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
   return gpu_info_;
 }
 
 bool GpuDataManagerImplPrivate::GpuAccessAllowed(
     std::string* reason) const {
-  if (use_swiftshader_)
-    return true;
-
+#if BUILDFLAG(ENABLE_SWIFTSHADER)
+  if (swiftshader_disabled_) {
+    if (reason) {
+      *reason = "GPU process crashed too many times with SwiftShader.";
+    }
+    return false;
+  }
+  return true;
+#else
   if (!gpu_process_accessible_) {
     if (reason) {
       *reason = "GPU process launch failed.";
@@ -369,7 +364,7 @@
   if (in_process_gpu_)
     return true;
 
-  if (card_blacklisted_) {
+  if (card_disabled_) {
     if (reason) {
       *reason = "GPU access is disabled ";
       base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -380,22 +375,8 @@
     }
     return false;
   }
-
-  if (blacklisted_features_.size() == gpu::NUMBER_OF_GPU_FEATURE_TYPES) {
-    // On Linux, we use cached GL strings to make blacklist decsions at browser
-    // startup time. We need to launch the GPU process to validate these
-    // strings even if all features are blacklisted. If all GPU features are
-    // disabled, the GPU process will only initialize GL bindings, create a GL
-    // context, and collect full GPU info.
-#if !defined(OS_LINUX)
-    if (reason) {
-      *reason = "All GPU features are blacklisted.";
-    }
-    return false;
-#endif
-  }
-
   return true;
+#endif
 }
 
 void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
@@ -423,8 +404,7 @@
 
 bool GpuDataManagerImplPrivate::IsEssentialGpuInfoAvailable() const {
   return (gpu_info_.basic_info_state != gpu::kCollectInfoNone &&
-          gpu_info_.context_info_state != gpu::kCollectInfoNone) ||
-         use_swiftshader_;
+          gpu_info_.context_info_state != gpu::kCollectInfoNone);
 }
 
 bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
@@ -454,10 +434,6 @@
                            base::Bind(&RequestVideoMemoryUsageStats, callback));
 }
 
-bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const {
-  return use_swiftshader_;
-}
-
 void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
   GpuDataManagerImpl::UnlockedSession session(owner_);
   observer_list_->AddObserver(observer);
@@ -635,10 +611,6 @@
 }
 
 void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
-  // No further update of gpu_info if falling back to SwiftShader.
-  if (use_swiftshader_)
-    return;
-
   bool was_info_available = IsCompleteGpuInfoAvailable();
   gpu::MergeGPUInfo(&gpu_info_, gpu_info);
   if (IsCompleteGpuInfoAvailable()) {
@@ -686,7 +658,9 @@
   std::string use_gl =
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kUseGL);
-  if (use_swiftshader_) {
+  if (card_disabled_ && !swiftshader_disabled_ &&
+      !base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableSoftwareRasterizer)) {
     command_line->AppendSwitchASCII(
         switches::kUseGL, gl::kGLImplementationSwiftShaderForWebGLName);
   } else if (!use_gl.empty()) {
@@ -780,18 +754,31 @@
                    base::Unretained(this)));
     return;
   }
-
-  card_blacklisted_ = true;
-  gpu::GpuFeatureInfo gpu_feature_info =
-      gpu::ComputeGpuFeatureInfoWithHardwareAccelerationDisabled();
-  UpdateGpuFeatureInfo(gpu_feature_info);
+  card_disabled_ = true;
+  bool reset_gpu_feature_info = true;
+#if BUILDFLAG(ENABLE_SWIFTSHADER)
+  if (!swiftshader_disabled_)
+    reset_gpu_feature_info = false;
+#endif
+  if (reset_gpu_feature_info) {
+    gpu::GpuFeatureInfo gpu_feature_info =
+        gpu::ComputeGpuFeatureInfoWithHardwareAccelerationDisabled();
+    UpdateGpuFeatureInfo(gpu_feature_info);
+  }
   for (int i = 0; i < gpu::NUMBER_OF_GPU_FEATURE_TYPES; ++i)
     blacklisted_features_.insert(i);
 
-  EnableSwiftShaderIfNecessary();
   NotifyGpuInfoUpdate();
 }
 
+bool GpuDataManagerImplPrivate::HardwareAccelerationEnabled() const {
+  return !card_disabled_;
+}
+
+void GpuDataManagerImplPrivate::DisableSwiftShader() {
+  swiftshader_disabled_ = true;
+}
+
 void GpuDataManagerImplPrivate::SetGpuInfo(const gpu::GPUInfo& gpu_info) {
   DCHECK(!is_initialized_);
   gpu_info_ = gpu_info;
@@ -951,8 +938,8 @@
 GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(GpuDataManagerImpl* owner)
     : complete_gpu_info_already_requested_(false),
       observer_list_(new GpuDataManagerObserverList),
-      use_swiftshader_(false),
-      card_blacklisted_(false),
+      card_disabled_(false),
+      swiftshader_disabled_(false),
       update_histograms_(true),
       domain_blocking_enabled_(true),
       owner_(owner),
@@ -963,7 +950,7 @@
   DCHECK(owner_);
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
-  if (ShouldDisableHardwareAcceleration())
+  if (command_line->HasSwitch(switches::kDisableGpu))
     DisableHardwareAcceleration();
 
   if (command_line->HasSwitch(switches::kSingleProcess) ||
@@ -1018,65 +1005,12 @@
 void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
     const std::set<int>& features) {
   blacklisted_features_ = features;
-
-  // Force disable using the GPU for these features, even if they would
-  // otherwise be allowed.
-  if (card_blacklisted_) {
-    blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING);
-    blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL);
-    blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL2);
-  }
-
-  EnableSwiftShaderIfNecessary();
 }
 
 void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
   observer_list_->Notify(FROM_HERE, &GpuDataManagerObserver::OnGpuInfoUpdate);
 }
 
-void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
-#if BUILDFLAG(ENABLE_SWIFTSHADER)
-  if ((!GpuAccessAllowed(nullptr) ||
-       blacklisted_features_.count(gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL)) &&
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableSoftwareRasterizer)) {
-    use_swiftshader_ = true;
-
-    // Adjust GPU info for SwiftShader. Most of this data only affects the
-    // chrome://gpu page, so it doesn't require querying the implementation.
-    // It is important to reset the video and image decode/encode capabilities,
-    // to prevent attempts to use them (crbug.com/702417).
-    gpu_info_.driver_vendor = "Google Inc.";
-    gpu_info_.driver_version = "3.3.0.2";
-    gpu_info_.driver_date = "2017/04/07";
-    gpu_info_.pixel_shader_version = "3.0";
-    gpu_info_.vertex_shader_version = "3.0";
-    gpu_info_.max_msaa_samples = "4";
-    gpu_info_.gl_version = "OpenGL ES 2.0 SwiftShader";
-    gpu_info_.gl_vendor = "Google Inc.";
-    gpu_info_.gl_renderer = "Google SwiftShader";
-    gpu_info_.gl_extensions = "";
-    gpu_info_.gl_reset_notification_strategy = 0;
-    gpu_info_.software_rendering = true;
-    gpu_info_.passthrough_cmd_decoder = false;
-    gpu_info_.direct_composition = false;
-    gpu_info_.supports_overlays = false;
-    gpu_info_.basic_info_state = gpu::kCollectInfoSuccess;
-    gpu_info_.context_info_state = gpu::kCollectInfoSuccess;
-    gpu_info_.video_decode_accelerator_capabilities = {};
-    gpu_info_.video_encode_accelerator_supported_profiles = {};
-    gpu_info_.jpeg_decode_accelerator_supported = false;
-
-    gpu_info_.gpu.active = false;
-    for (auto& secondary_gpu : gpu_info_.secondary_gpus)
-      secondary_gpu.active = false;
-
-    for (auto& status : gpu_feature_info_.status_values)
-      status = gpu::kGpuFeatureStatusBlacklisted;
-  }
-#endif
-}
-
 std::string GpuDataManagerImplPrivate::GetDomainFromURL(
     const GURL& url) const {
   // For the moment, we just use the host, or its IP address, as the
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h
index 83261b7..75197ff9 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.h
+++ b/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -52,7 +52,6 @@
   void RequestVideoMemoryUsageStatsUpdate(
       const base::Callback<void(const gpu::VideoMemoryUsageStats& stats)>&
           callback) const;
-  bool ShouldUseSwiftShader() const;
   void AddObserver(GpuDataManagerObserver* observer);
   void RemoveObserver(GpuDataManagerObserver* observer);
   void UnblockDomainFrom3DAPIs(const GURL& url);
@@ -60,6 +59,8 @@
                     const std::string& gl_renderer,
                     const std::string& gl_version);
   void DisableHardwareAcceleration();
+  bool HardwareAccelerationEnabled() const;
+  void DisableSwiftShader();
   void SetGpuInfo(const gpu::GPUInfo& gpu_info);
 
   void Initialize();
@@ -104,8 +105,6 @@
                           int render_frame_id,
                           ThreeDAPIType requester);
 
-  size_t GetBlacklistedFeatureCount() const;
-
   bool UpdateActiveGpu(uint32_t vendor_id, uint32_t device_id);
 
   void OnGpuProcessInitFailure();
@@ -116,22 +115,8 @@
   friend class GpuDataManagerImplPrivateTest;
 
   FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           GpuSideBlacklisting);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           GpuSideExceptions);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           DisableHardwareAcceleration);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           SwiftShaderRendering);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           SwiftShaderRendering2);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
                            GpuInfoUpdate);
   FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           NoGpuInfoUpdateWithSwiftShader);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           GPUVideoMemoryUsageStatsUpdate);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
                            BlockAllDomainsFrom3DAPIs);
   FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
                            UnblockGuiltyDomainFrom3DAPIs);
@@ -141,18 +126,6 @@
                            UnblockOtherDomainFrom3DAPIs);
   FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
                            UnblockThisDomainFrom3DAPIs);
-#if defined(OS_LINUX)
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           SetGLStrings);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           SetGLStringsNoEffects);
-#endif
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           GpuDriverBugListSingle);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           GpuDriverBugListMultiple);
-  FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
-                           BlacklistAllFeatures);
 
   struct DomainBlockEntry {
     GpuDataManagerImpl::DomainGuilt last_guilt;
@@ -190,9 +163,6 @@
   // Notify all observers whenever there is a GPU info update.
   void NotifyGpuInfoUpdate();
 
-  // Try to switch to SwiftShader rendering, if possible and necessary.
-  void EnableSwiftShaderIfNecessary();
-
   // Helper to extract the domain from a given URL.
   std::string GetDomainFromURL(const GURL& url) const;
 
@@ -220,11 +190,12 @@
 
   std::vector<LogMessage> log_messages_;
 
-  bool use_swiftshader_;
-
-  // Current card force-blacklisted due to GPU crashes, or disabled through
+  // Current card force-disabled due to GPU crashes, or disabled through
   // the --disable-gpu commandline switch.
-  bool card_blacklisted_;
+  bool card_disabled_;
+
+  // SwiftShader force-disabled due to GPU crashes using SwiftShader.
+  bool swiftshader_disabled_;
 
   // We disable histogram stuff in testing, especially in unit tests because
   // they cause random failures.
diff --git a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
index 61ff37b..252ca41c 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
@@ -127,27 +127,6 @@
 // We use new method instead of GetInstance() method because we want
 // each test to be independent of each other.
 
-TEST_F(GpuDataManagerImplPrivateTest, DisableHardwareAcceleration) {
-  ScopedGpuDataManagerImplPrivate manager;
-  const gpu::GpuControlListData kData;
-  manager->InitializeForTesting(kData, gpu::GPUInfo());
-  EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
-  std::string reason;
-  EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
-  EXPECT_TRUE(reason.empty());
-
-  manager->DisableHardwareAcceleration();
-  if (manager->ShouldUseSwiftShader()) {
-    EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
-    EXPECT_TRUE(reason.empty());
-  } else {
-    EXPECT_FALSE(manager->GpuAccessAllowed(&reason));
-    EXPECT_FALSE(reason.empty());
-  }
-  EXPECT_EQ(static_cast<size_t>(gpu::NUMBER_OF_GPU_FEATURE_TYPES),
-            manager->GetBlacklistedFeatureCount());
-}
-
 TEST_F(GpuDataManagerImplPrivateTest, GpuInfoUpdate) {
   ScopedGpuDataManagerImpl manager;
 
@@ -291,127 +270,4 @@
                 GetDomain2ForTesting(), JustBeforeExpiration(manager.get())));
 }
 
-TEST_F(GpuDataManagerImplPrivateTest, BlacklistAllFeatures) {
-  ScopedGpuDataManagerImplPrivate manager;
-  EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
-  std::string reason;
-  EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
-  EXPECT_TRUE(reason.empty());
-
-  const gpu::GpuControlList::Entry kEntries[] = {
-      gpu::kGpuDataManagerTestingEntries
-          [gpu::kGpuDataManagerImplPrivateTest_BlacklistAllFeatures],
-  };
-  const gpu::GpuControlListData kData(1, kEntries);
-
-  gpu::GPUInfo gpu_info;
-  gpu_info.gpu.vendor_id = 0x10de;
-  gpu_info.gpu.device_id = 0x0640;
-  manager->InitializeForTesting(kData, gpu_info);
-
-  EXPECT_EQ(static_cast<size_t>(gpu::NUMBER_OF_GPU_FEATURE_TYPES),
-            manager->GetBlacklistedFeatureCount());
-  if (manager->ShouldUseSwiftShader()) {
-    EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
-    EXPECT_TRUE(reason.empty());
-  }
-}
-
-TEST_F(GpuDataManagerImplPrivateTest, UpdateActiveGpu) {
-  ScopedGpuDataManagerImpl manager;
-
-  const gpu::GpuControlList::Entry kEntries[] = {
-      gpu::kGpuDataManagerTestingEntries
-          [gpu::kGpuDataManagerImplPrivateTest_UpdateActiveGpu],
-  };
-  const gpu::GpuControlListData kData(1, kEntries);
-
-  // Two GPUs, the secondary Intel GPU is active.
-  gpu::GPUInfo gpu_info;
-  gpu_info.gpu.vendor_id = 0x10de;
-  gpu_info.gpu.device_id = 0x0640;
-  gpu_info.gpu.active = false;
-  gpu::GPUInfo::GPUDevice intel_gpu;
-  intel_gpu.vendor_id = 0x8086;
-  intel_gpu.device_id = 0x04a1;
-  intel_gpu.active = true;
-  gpu_info.secondary_gpus.push_back(intel_gpu);
-
-  manager->InitializeForTesting(kData, gpu_info);
-  TestObserver observer;
-  manager->AddObserver(&observer);
-
-  if (manager->ShouldUseSwiftShader()) {
-    EXPECT_EQ(static_cast<size_t>(gpu::NUMBER_OF_GPU_FEATURE_TYPES),
-              manager->GetBlacklistedFeatureCount());
-
-    // Update to previous Intel GPU.
-    EXPECT_TRUE(manager->UpdateActiveGpu(0x8086, 0x04a1));
-    {
-      base::RunLoop run_loop;
-      run_loop.RunUntilIdle();
-    }
-    EXPECT_TRUE(observer.gpu_info_updated());
-    EXPECT_EQ(static_cast<size_t>(gpu::NUMBER_OF_GPU_FEATURE_TYPES),
-              manager->GetBlacklistedFeatureCount());
-  } else {
-    EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
-
-    // Update to previous Intel GPU.
-    EXPECT_FALSE(manager->UpdateActiveGpu(0x8086, 0x04a1));
-    {
-      base::RunLoop run_loop;
-      run_loop.RunUntilIdle();
-    }
-    EXPECT_FALSE(observer.gpu_info_updated());
-    EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
-  }
-
-  // Set NVIDIA GPU to be active.
-  EXPECT_TRUE(manager->UpdateActiveGpu(0x10de, 0x0640));
-  {
-    base::RunLoop run_loop;
-    run_loop.RunUntilIdle();
-  }
-  EXPECT_TRUE(observer.gpu_info_updated());
-  if (manager->ShouldUseSwiftShader()) {
-    EXPECT_EQ(static_cast<size_t>(gpu::NUMBER_OF_GPU_FEATURE_TYPES),
-              manager->GetBlacklistedFeatureCount());
-  } else {
-    EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
-  }
-
-  observer.Reset();
-  EXPECT_FALSE(observer.gpu_info_updated());
-
-  // Update to previous NVIDIA GPU.
-  EXPECT_FALSE(manager->UpdateActiveGpu(0x10de, 0x0640));
-  {
-    base::RunLoop run_loop;
-    run_loop.RunUntilIdle();
-  }
-  EXPECT_FALSE(observer.gpu_info_updated());
-
-  if (manager->ShouldUseSwiftShader()) {
-    EXPECT_EQ(static_cast<size_t>(gpu::NUMBER_OF_GPU_FEATURE_TYPES),
-              manager->GetBlacklistedFeatureCount());
-  } else {
-    EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
-  }
-
-  // Set Intel GPU to be active.
-  EXPECT_TRUE(manager->UpdateActiveGpu(0x8086, 0x04a1));
-  {
-    base::RunLoop run_loop;
-    run_loop.RunUntilIdle();
-  }
-  EXPECT_TRUE(observer.gpu_info_updated());
-  if (manager->ShouldUseSwiftShader()) {
-    EXPECT_EQ(static_cast<size_t>(gpu::NUMBER_OF_GPU_FEATURE_TYPES),
-              manager->GetBlacklistedFeatureCount());
-  } else {
-    EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
-  }
-}
-
 }  // namespace content
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 9dd62bae6..35845eb4 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -363,9 +363,7 @@
           switches::kSingleProcess) ||
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kInProcessGPU) ||
-      (host->valid_ &&
-       (host->swiftshader_rendering_ ||
-        !GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()))) {
+      host->valid_) {
     return true;
   }
 
@@ -1212,6 +1210,7 @@
           !disable_crash_limit) {
         // SwiftShader is too unstable to use. Disable it for current session.
         gpu_enabled_ = false;
+        GpuDataManagerImpl::GetInstance()->DisableSwiftShader();
       }
     } else {
       ++gpu_crash_count_;
diff --git a/content/public/browser/gpu_data_manager.h b/content/public/browser/gpu_data_manager.h
index 457410c2..5d6601b5f 100644
--- a/content/public/browser/gpu_data_manager.h
+++ b/content/public/browser/gpu_data_manager.h
@@ -60,9 +60,6 @@
       const base::Callback<void(const gpu::VideoMemoryUsageStats& stats)>&
           callback) const = 0;
 
-  // Returns true if SwiftShader should be used.
-  virtual bool ShouldUseSwiftShader() const = 0;
-
   // Registers/unregister |observer|.
   virtual void AddObserver(GpuDataManagerObserver* observer) = 0;
   virtual void RemoveObserver(GpuDataManagerObserver* observer) = 0;
@@ -77,7 +74,6 @@
                             const std::string& gl_renderer,
                             const std::string& gl_version) = 0;
 
-  // Turn off all hardware acceleration.
   virtual void DisableHardwareAcceleration() = 0;
 
   // Whether a GPU is in use (as opposed to a software renderer).
diff --git a/content/public/browser/gpu_utils.cc b/content/public/browser/gpu_utils.cc
index 06b7e88..008fdc6 100644
--- a/content/public/browser/gpu_utils.cc
+++ b/content/public/browser/gpu_utils.cc
@@ -80,6 +80,8 @@
   gpu_preferences.enable_nv12_dxgi_video =
       !command_line->HasSwitch(switches::kDisableNv12DxgiVideo);
 #endif
+  gpu_preferences.disable_software_rasterizer =
+      command_line->HasSwitch(switches::kDisableSoftwareRasterizer);
   gpu_preferences.compile_shader_always_succeeds =
       command_line->HasSwitch(switches::kCompileShaderAlwaysSucceeds);
   gpu_preferences.disable_gl_error_limit =
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 4ca7da2..a9a9e7e 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -410,17 +410,6 @@
   peer->OnCompletedRequest(renderer_status);
 }
 
-mojom::DownloadedTempFilePtr ResourceDispatcher::TakeDownloadedTempFile(
-    int request_id) {
-  PendingRequestMap::iterator it = pending_requests_.find(request_id);
-  if (it == pending_requests_.end())
-    return nullptr;
-  PendingRequestInfo* request_info = it->second.get();
-  if (!request_info->url_loader_client)
-    return nullptr;
-  return request_info->url_loader_client->TakeDownloadedTempFile();
-}
-
 bool ResourceDispatcher::RemovePendingRequest(int request_id) {
   PendingRequestMap::iterator it = pending_requests_.find(request_id);
   if (it == pending_requests_.end())
@@ -606,16 +595,14 @@
     SyncLoadResponse* response,
     blink::WebURLRequest::LoadingIPCType ipc_type,
     mojom::URLLoaderFactory* url_loader_factory,
-    std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
-    double timeout) {
+    std::vector<std::unique_ptr<URLLoaderThrottle>> throttles) {
   CheckSchemeForReferrerPolicy(*request);
 
   if (ipc_type == blink::WebURLRequest::LoadingIPCType::kMojo) {
     mojom::URLLoaderFactoryPtrInfo url_loader_factory_copy;
     url_loader_factory->Clone(mojo::MakeRequest(&url_loader_factory_copy));
-    base::WaitableEvent completed_event(
-        base::WaitableEvent::ResetPolicy::MANUAL,
-        base::WaitableEvent::InitialState::NOT_SIGNALED);
+    base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+                              base::WaitableEvent::InitialState::NOT_SIGNALED);
 
     // Prepare the configured throttles for use on a separate thread.
     for (const auto& throttle : throttles)
@@ -631,10 +618,9 @@
                        std::move(request), routing_id, frame_origin,
                        traffic_annotation, std::move(url_loader_factory_copy),
                        std::move(throttles), base::Unretained(response),
-                       base::Unretained(&completed_event),
-                       base::Unretained(terminate_sync_load_event_), timeout));
+                       base::Unretained(&event)));
 
-    completed_event.Wait();
+    event.Wait();
   } else {
     SyncLoadResult result;
     IPC::SyncMessage* msg = new ResourceHostMsg_SyncLoad(
@@ -648,18 +634,18 @@
 
     response->error_code = result.error_code;
     response->url = result.final_url;
-    response->info.headers = result.headers;
-    response->info.mime_type = result.mime_type;
-    response->info.charset = result.charset;
-    response->info.request_time = result.request_time;
-    response->info.response_time = result.response_time;
-    response->info.load_timing = result.load_timing;
-    response->info.devtools_info = result.devtools_info;
+    response->headers = result.headers;
+    response->mime_type = result.mime_type;
+    response->charset = result.charset;
+    response->request_time = result.request_time;
+    response->response_time = result.response_time;
+    response->load_timing = result.load_timing;
+    response->devtools_info = result.devtools_info;
     response->data.swap(result.data);
-    response->info.download_file_path = result.download_file_path;
-    response->info.socket_address = result.socket_address;
-    response->info.encoded_data_length = result.encoded_data_length;
-    response->info.encoded_body_length = result.encoded_body_length;
+    response->download_file_path = result.download_file_path;
+    response->socket_address = result.socket_address;
+    response->encoded_data_length = result.encoded_data_length;
+    response->encoded_body_length = result.encoded_body_length;
   }
 }
 
diff --git a/content/renderer/loader/resource_dispatcher.h b/content/renderer/loader/resource_dispatcher.h
index ce4a7ccb..c0f96e9 100644
--- a/content/renderer/loader/resource_dispatcher.h
+++ b/content/renderer/loader/resource_dispatcher.h
@@ -34,10 +34,6 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
-namespace base {
-class WaitableEvent;
-}
-
 namespace net {
 struct RedirectInfo;
 }
@@ -95,7 +91,6 @@
   //
   // |routing_id| is used to associated the bridge with a frame's network
   // context.
-  // |timeout| (in seconds) is used to abort the sync request on timeouts.
   virtual void StartSync(
       std::unique_ptr<ResourceRequest> request,
       int routing_id,
@@ -104,8 +99,7 @@
       SyncLoadResponse* response,
       blink::WebURLRequest::LoadingIPCType ipc_type,
       mojom::URLLoaderFactory* url_loader_factory,
-      std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
-      double timeout);
+      std::vector<std::unique_ptr<URLLoaderThrottle>> throttles);
 
   // Call this method to initiate the request. If this method succeeds, then
   // the peer's methods will be called asynchronously to report various events.
@@ -130,8 +124,6 @@
       std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
       mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints);
 
-  mojom::DownloadedTempFilePtr TakeDownloadedTempFile(int request_id);
-
   // Removes a request from the |pending_requests_| list, returning true if the
   // request was found and removed.
   bool RemovePendingRequest(int request_id);
@@ -179,15 +171,6 @@
 
   void OnTransferSizeUpdated(int request_id, int32_t transfer_size_diff);
 
-  // This is used only when |this| is created for a worker thread.
-  // Sets |terminate_sync_load_event_| which will be signaled from the main
-  // thread when the worker thread is being terminated so that the sync requests
-  // requested on the worker thread can be aborted.
-  void set_terminate_sync_load_event(
-      base::WaitableEvent* terminate_sync_load_event) {
-    terminate_sync_load_event_ = terminate_sync_load_event;
-  }
-
  private:
   friend class URLLoaderClientImpl;
   friend class URLResponseBodyConsumer;
@@ -313,8 +296,6 @@
   scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_;
   scoped_refptr<ResourceSchedulingFilter> resource_scheduling_filter_;
 
-  base::WaitableEvent* terminate_sync_load_event_ = nullptr;
-
   base::WeakPtrFactory<ResourceDispatcher> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourceDispatcher);
diff --git a/content/renderer/loader/sync_load_context.cc b/content/renderer/loader/sync_load_context.cc
index d3711f7e..898e358d 100644
--- a/content/renderer/loader/sync_load_context.cc
+++ b/content/renderer/loader/sync_load_context.cc
@@ -25,12 +25,9 @@
     mojom::URLLoaderFactoryPtrInfo url_loader_factory_pipe,
     std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
     SyncLoadResponse* response,
-    base::WaitableEvent* completed_event,
-    base::WaitableEvent* abort_event,
-    double timeout) {
-  auto* context =
-      new SyncLoadContext(request.get(), std::move(url_loader_factory_pipe),
-                          response, completed_event, abort_event, timeout);
+    base::WaitableEvent* event) {
+  auto* context = new SyncLoadContext(
+      request.get(), std::move(url_loader_factory_pipe), response, event);
 
   context->request_id_ = context->resource_dispatcher_->StartAsync(
       std::move(request), routing_id, nullptr, frame_origin, traffic_annotation,
@@ -44,19 +41,8 @@
     ResourceRequest* request,
     mojom::URLLoaderFactoryPtrInfo url_loader_factory,
     SyncLoadResponse* response,
-    base::WaitableEvent* completed_event,
-    base::WaitableEvent* abort_event,
-    double timeout)
-    : response_(response), completed_event_(completed_event) {
-  if (abort_event) {
-    abort_watcher_.StartWatching(
-        abort_event,
-        base::BindOnce(&SyncLoadContext::OnAbort, base::Unretained(this)));
-  }
-  if (timeout) {
-    timeout_timer_.Start(FROM_HERE, base::TimeDelta::FromSecondsD(timeout),
-                         this, &SyncLoadContext::OnTimeout);
-  }
+    base::WaitableEvent* event)
+    : response_(response), event_(event) {
   url_loader_factory_.Bind(std::move(url_loader_factory));
 
   // Constructs a new ResourceDispatcher specifically for this request.
@@ -74,13 +60,10 @@
 
 bool SyncLoadContext::OnReceivedRedirect(const net::RedirectInfo& redirect_info,
                                          const ResourceResponseInfo& info) {
-  DCHECK(!Completed());
   if (redirect_info.new_url.GetOrigin() != response_->url.GetOrigin()) {
     LOG(ERROR) << "Cross origin redirect denied";
     response_->error_code = net::ERR_ABORTED;
-    completed_event_->Signal();
-
-    CompleteRequest(false /* remove_pending_request */);
+    event_->Signal();
 
     // Returning false here will cause the request to be cancelled and this
     // object deleted.
@@ -92,17 +75,24 @@
 }
 
 void SyncLoadContext::OnReceivedResponse(const ResourceResponseInfo& info) {
-  DCHECK(!Completed());
-  response_->info = info;
+  response_->headers = info.headers;
+  response_->mime_type = info.mime_type;
+  response_->charset = info.charset;
+  response_->request_time = info.request_time;
+  response_->response_time = info.response_time;
+  response_->load_timing = info.load_timing;
+  response_->devtools_info = info.devtools_info;
+  response_->download_file_path = info.download_file_path;
+  response_->socket_address = info.socket_address;
 }
 
 void SyncLoadContext::OnDownloadedData(int len, int encoded_data_length) {
-  downloaded_file_length_ =
-      (downloaded_file_length_ ? *downloaded_file_length_ : 0) + len;
+  // This method is only called when RequestInfo::download_to_file is true which
+  // is not allowed when processing a synchronous request.
+  NOTREACHED();
 }
 
 void SyncLoadContext::OnReceivedData(std::unique_ptr<ReceivedData> data) {
-  DCHECK(!Completed());
   response_->data.append(data->payload(), data->length());
 }
 
@@ -110,54 +100,15 @@
 
 void SyncLoadContext::OnCompletedRequest(
     const network::URLLoaderCompletionStatus& status) {
-  DCHECK(!Completed());
   response_->error_code = status.error_code;
   if (status.cors_error_status)
     response_->cors_error = status.cors_error_status->cors_error;
-  response_->info.encoded_data_length = status.encoded_data_length;
-  response_->info.encoded_body_length = status.encoded_body_length;
-  response_->downloaded_file_length = downloaded_file_length_;
-  // Need to pass |downloaded_tmp_file| to the caller thread. Otherwise the blob
-  // creation in ResourceResponse::SetDownloadedFilePath() fails.
-  response_->downloaded_tmp_file =
-      resource_dispatcher_->TakeDownloadedTempFile(request_id_);
-  DCHECK_EQ(!response_->downloaded_file_length,
-            !response_->downloaded_tmp_file);
-  CompleteRequest(true /* remove_pending_request */);
-}
+  response_->encoded_data_length = status.encoded_data_length;
+  response_->encoded_body_length = status.encoded_body_length;
+  event_->Signal();
 
-void SyncLoadContext::OnAbort(base::WaitableEvent* event) {
-  DCHECK(!Completed());
-  response_->error_code = net::ERR_ABORTED;
-  CompleteRequest(true /* remove_pending_request */);
-}
-
-void SyncLoadContext::OnTimeout() {
-  // OnTimeout() must not be called after CompleteRequest() was called, because
-  // the OneShotTimer must have been stopped.
-  DCHECK(!Completed());
-  response_->error_code = net::ERR_TIMED_OUT;
-  CompleteRequest(true /* remove_pending_request */);
-}
-
-void SyncLoadContext::CompleteRequest(bool remove_pending_request) {
-  abort_watcher_.StopWatching();
-  timeout_timer_.AbandonAndStop();
-
-  completed_event_->Signal();
-
-  completed_event_ = nullptr;
-  response_ = nullptr;
-
-  if (remove_pending_request) {
-    // This will indirectly cause this object to be deleted.
-    resource_dispatcher_->RemovePendingRequest(request_id_);
-  }
-}
-
-bool SyncLoadContext::Completed() const {
-  DCHECK_EQ(!completed_event_, !response_);
-  return !response_;
+  // This will indirectly cause this object to be deleted.
+  resource_dispatcher_->RemovePendingRequest(request_id_);
 }
 
 }  // namespace content
diff --git a/content/renderer/loader/sync_load_context.h b/content/renderer/loader/sync_load_context.h
index 91fb6d0..d02549e 100644
--- a/content/renderer/loader/sync_load_context.h
+++ b/content/renderer/loader/sync_load_context.h
@@ -6,9 +6,6 @@
 #define CONTENT_RENDERER_LOADER_SYNC_LOAD_CONTEXT_H_
 
 #include "base/macros.h"
-#include "base/optional.h"
-#include "base/synchronization/waitable_event_watcher.h"
-#include "base/timer/timer.h"
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "content/public/renderer/request_peer.h"
 #include "content/renderer/loader/resource_dispatcher.h"
@@ -32,10 +29,8 @@
 class SyncLoadContext : public RequestPeer {
  public:
   // Begins a new asynchronous request on whatever sequence this method is
-  // called on. |completed_event| will be signalled when the request is complete
-  // and |response| will be populated with the response data. |abort_event|
-  // will be signalled from the main thread to abort the sync request on a
-  // worker thread when the worker thread is being terminated.
+  // called on. |event| will be signalled when the request is complete and
+  // |response| will be populated with the response data.
   static void StartAsyncWithWaitableEvent(
       std::unique_ptr<ResourceRequest> request,
       int routing_id,
@@ -44,19 +39,15 @@
       mojom::URLLoaderFactoryPtrInfo url_loader_factory_pipe,
       std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
       SyncLoadResponse* response,
-      base::WaitableEvent* completed_event,
-      base::WaitableEvent* abort_event,
-      double timeout);
+      base::WaitableEvent* event);
 
-  ~SyncLoadContext() override;
-
- private:
   SyncLoadContext(ResourceRequest* request,
                   mojom::URLLoaderFactoryPtrInfo url_loader_factory,
                   SyncLoadResponse* response,
-                  base::WaitableEvent* completed_event,
-                  base::WaitableEvent* abort_event,
-                  double timeout);
+                  base::WaitableEvent* event);
+  ~SyncLoadContext() override;
+
+ private:
   // RequestPeer implementation:
   void OnUploadProgress(uint64_t position, uint64_t size) override;
   bool OnReceivedRedirect(const net::RedirectInfo& redirect_info,
@@ -68,20 +59,12 @@
   void OnCompletedRequest(
       const network::URLLoaderCompletionStatus& status) override;
 
-  void OnAbort(base::WaitableEvent* event);
-  void OnTimeout();
-
-  void CompleteRequest(bool remove_pending_request);
-  bool Completed() const;
-
   // This raw pointer will remain valid for the lifetime of this object because
   // it remains on the stack until |event_| is signaled.
-  // Set to null after CompleteRequest() is called.
   SyncLoadResponse* response_;
 
   // This event is signaled when the request is complete.
-  // Set to null after CompleteRequest() is called.
-  base::WaitableEvent* completed_event_;
+  base::WaitableEvent* event_;
 
   // State necessary to run a request on an independent thread.
   mojom::URLLoaderFactoryPtr url_loader_factory_;
@@ -89,11 +72,6 @@
 
   int request_id_;
 
-  base::Optional<int64_t> downloaded_file_length_;
-
-  base::WaitableEventWatcher abort_watcher_;
-  base::OneShotTimer timeout_timer_;
-
   DISALLOW_COPY_AND_ASSIGN(SyncLoadContext);
 };
 
diff --git a/content/renderer/loader/sync_load_response.cc b/content/renderer/loader/sync_load_response.cc
index f509c5a..a9e8ee12 100644
--- a/content/renderer/loader/sync_load_response.cc
+++ b/content/renderer/loader/sync_load_response.cc
@@ -8,21 +8,6 @@
 
 SyncLoadResponse::SyncLoadResponse() {}
 
-SyncLoadResponse::SyncLoadResponse(SyncLoadResponse&& other) {
-  *this = std::move(other);
-}
-
 SyncLoadResponse::~SyncLoadResponse() {}
 
-SyncLoadResponse& SyncLoadResponse::operator=(SyncLoadResponse&& other) {
-  this->info = other.info;
-  this->error_code = other.error_code;
-  this->cors_error = other.cors_error;
-  this->url = std::move(other.url);
-  this->data = std::move(other.data);
-  this->downloaded_file_length = other.downloaded_file_length;
-  this->downloaded_tmp_file = std::move(other.downloaded_tmp_file);
-  return *this;
-}
-
 }  // namespace content
diff --git a/content/renderer/loader/sync_load_response.h b/content/renderer/loader/sync_load_response.h
index 202483b17..160d9bba2 100644
--- a/content/renderer/loader/sync_load_response.h
+++ b/content/renderer/loader/sync_load_response.h
@@ -10,7 +10,6 @@
 #include "base/optional.h"
 #include "content/common/content_export.h"
 #include "content/public/common/resource_response_info.h"
-#include "content/public/common/url_loader.mojom.h"
 #include "services/network/public/interfaces/cors.mojom.h"
 #include "url/gurl.h"
 
@@ -18,17 +17,12 @@
 
 // See the SyncLoad method. (The name of this struct is not
 // suffixed with "Info" because it also contains the response data.)
-struct CONTENT_EXPORT SyncLoadResponse {
+struct CONTENT_EXPORT SyncLoadResponse : ResourceResponseInfo {
   SyncLoadResponse();
-  SyncLoadResponse(SyncLoadResponse&& other);
   ~SyncLoadResponse();
 
-  SyncLoadResponse& operator=(SyncLoadResponse&& other);
-
-  ResourceResponseInfo info;
-
   // The response error code.
-  int error_code;
+  int error_code = 0;
 
   // Optional CORS error details.
   base::Optional<network::mojom::CORSError> cors_error;
@@ -39,10 +33,6 @@
 
   // The response data.
   std::string data;
-
-  // Used for blob response type XMLHttpRequest.
-  base::Optional<int64_t> downloaded_file_length;
-  mojom::DownloadedTempFilePtr downloaded_tmp_file;
 };
 
 }  // namespace content
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc
index 71f46ef..5d756db 100644
--- a/content/renderer/loader/url_loader_client_impl.cc
+++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -319,10 +319,6 @@
   body_consumer_->OnComplete(status);
 }
 
-mojom::DownloadedTempFilePtr URLLoaderClientImpl::TakeDownloadedTempFile() {
-  return std::move(downloaded_file_);
-}
-
 bool URLLoaderClientImpl::NeedsStoringMessage() const {
   return is_deferred_ || deferred_messages_.size() > 0;
 }
diff --git a/content/renderer/loader/url_loader_client_impl.h b/content/renderer/loader/url_loader_client_impl.h
index 54625ce2..26ce1d2 100644
--- a/content/renderer/loader/url_loader_client_impl.h
+++ b/content/renderer/loader/url_loader_client_impl.h
@@ -73,9 +73,6 @@
       mojo::ScopedDataPipeConsumerHandle body) override;
   void OnComplete(const network::URLLoaderCompletionStatus& status) override;
 
-  // Takes |downloaded_file_|.
-  mojom::DownloadedTempFilePtr TakeDownloadedTempFile();
-
  private:
   class DeferredMessage;
   class DeferredOnReceiveResponse;
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index b93842b..39994db 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -569,7 +569,7 @@
       // This is a sync load. Do the work now.
       sync_load_response->url = url_;
       sync_load_response->error_code =
-          GetInfoFromDataURL(sync_load_response->url, &sync_load_response->info,
+          GetInfoFromDataURL(sync_load_response->url, sync_load_response,
                              &sync_load_response->data);
     } else {
       task_runner_->PostTask(FROM_HERE,
@@ -694,7 +694,7 @@
         std::move(resource_request), request.RequestorID(),
         extra_data->frame_origin(), GetTrafficAnnotationTag(request),
         sync_load_response, request.GetLoadingIPCType(), url_loader_factory_,
-        extra_data->TakeURLLoaderThrottles(), request.TimeoutInterval());
+        extra_data->TakeURLLoaderThrottles());
     return;
   }
 
@@ -1243,14 +1243,12 @@
   }
 }
 
-void WebURLLoaderImpl::LoadSynchronously(
-    const WebURLRequest& request,
-    WebURLResponse& response,
-    base::Optional<WebURLError>& error,
-    WebData& data,
-    int64_t& encoded_data_length,
-    int64_t& encoded_body_length,
-    base::Optional<int64_t>& downloaded_file_length) {
+void WebURLLoaderImpl::LoadSynchronously(const WebURLRequest& request,
+                                         WebURLResponse& response,
+                                         base::Optional<WebURLError>& error,
+                                         WebData& data,
+                                         int64_t& encoded_data_length,
+                                         int64_t& encoded_body_length) {
   TRACE_EVENT0("loading", "WebURLLoaderImpl::loadSynchronously");
   SyncLoadResponse sync_load_response;
   context_->Start(request, &sync_load_response);
@@ -1279,11 +1277,10 @@
     return;
   }
 
-  PopulateURLResponse(final_url, sync_load_response.info, &response,
+  PopulateURLResponse(final_url, sync_load_response, &response,
                       request.ReportRawHeaders());
-  encoded_data_length = sync_load_response.info.encoded_data_length;
-  encoded_body_length = sync_load_response.info.encoded_body_length;
-  downloaded_file_length = sync_load_response.downloaded_file_length;
+  encoded_data_length = sync_load_response.encoded_data_length;
+  encoded_body_length = sync_load_response.encoded_body_length;
 
   data.Assign(sync_load_response.data.data(), sync_load_response.data.size());
 }
diff --git a/content/renderer/loader/web_url_loader_impl.h b/content/renderer/loader/web_url_loader_impl.h
index 530c2d7..3c049d6 100644
--- a/content/renderer/loader/web_url_loader_impl.h
+++ b/content/renderer/loader/web_url_loader_impl.h
@@ -91,14 +91,12 @@
                                   blink::WebURLResponse* response,
                                   bool report_security_info);
   // WebURLLoader methods:
-  void LoadSynchronously(
-      const blink::WebURLRequest& request,
-      blink::WebURLResponse& response,
-      base::Optional<blink::WebURLError>& error,
-      blink::WebData& data,
-      int64_t& encoded_data_length,
-      int64_t& encoded_body_length,
-      base::Optional<int64_t>& downloaded_file_length) override;
+  void LoadSynchronously(const blink::WebURLRequest& request,
+                         blink::WebURLResponse& response,
+                         base::Optional<blink::WebURLError>& error,
+                         blink::WebData& data,
+                         int64_t& encoded_data_length,
+                         int64_t& encoded_body_length) override;
   void LoadAsynchronously(const blink::WebURLRequest& request,
                           blink::WebURLLoaderClient* client) override;
   void Cancel() override;
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc
index 07c4c1e8..f59565e79 100644
--- a/content/renderer/loader/web_url_loader_impl_unittest.cc
+++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -73,16 +73,16 @@
 
   // TestDispatcher implementation:
 
-  void StartSync(std::unique_ptr<ResourceRequest> request,
-                 int routing_id,
-                 const url::Origin& frame_origin,
-                 const net::NetworkTrafficAnnotationTag& traffic_annotation,
-                 SyncLoadResponse* response,
-                 blink::WebURLRequest::LoadingIPCType ipc_type,
-                 mojom::URLLoaderFactory* url_loader_factory,
-                 std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
-                 double timeout) override {
-    *response = std::move(sync_load_response_);
+  void StartSync(
+      std::unique_ptr<ResourceRequest> request,
+      int routing_id,
+      const url::Origin& frame_origin,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation,
+      SyncLoadResponse* response,
+      blink::WebURLRequest::LoadingIPCType ipc_type,
+      mojom::URLLoaderFactory* url_loader_factory,
+      std::vector<std::unique_ptr<URLLoaderThrottle>> throttles) override {
+    *response = sync_load_response_;
   }
 
   int StartAsync(
@@ -98,7 +98,7 @@
       std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
       mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints) override {
     EXPECT_FALSE(peer_);
-    if (sync_load_response_.info.encoded_body_length != -1)
+    if (sync_load_response_.encoded_body_length != -1)
       EXPECT_TRUE(is_sync);
     peer_ = std::move(peer);
     url_ = request->url;
@@ -123,8 +123,8 @@
   }
   bool defers_loading() const { return defers_loading_; }
 
-  void set_sync_load_response(SyncLoadResponse&& sync_load_response) {
-    sync_load_response_ = std::move(sync_load_response);
+  void set_sync_load_response(const SyncLoadResponse& sync_load_response) {
+    sync_load_response_ = sync_load_response;
   }
 
  private:
@@ -772,23 +772,20 @@
   sync_load_response.url = url;
   sync_load_response.data = kBodyData;
   ASSERT_EQ(17u, sync_load_response.data.size());
-  sync_load_response.info.encoded_body_length = kEncodedBodyLength;
-  sync_load_response.info.encoded_data_length = kEncodedDataLength;
-  dispatcher()->set_sync_load_response(std::move(sync_load_response));
+  sync_load_response.encoded_body_length = kEncodedBodyLength;
+  sync_load_response.encoded_data_length = kEncodedDataLength;
+  dispatcher()->set_sync_load_response(sync_load_response);
 
   blink::WebURLResponse response;
   base::Optional<blink::WebURLError> error;
   blink::WebData data;
   int64_t encoded_data_length = 0;
   int64_t encoded_body_length = 0;
-  base::Optional<int64_t> downloaded_file_length;
   client()->loader()->LoadSynchronously(
-      request, response, error, data, encoded_data_length, encoded_body_length,
-      downloaded_file_length);
+      request, response, error, data, encoded_data_length, encoded_body_length);
 
   EXPECT_EQ(kEncodedBodyLength, encoded_body_length);
   EXPECT_EQ(kEncodedDataLength, encoded_data_length);
-  EXPECT_FALSE(downloaded_file_length);
 }
 
 }  // namespace
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.cc b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
index f22b82e..2e0afc7 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
@@ -19,24 +19,14 @@
     : worker_script_url_(worker_script_url),
       url_loader_factory_getter_info_(
           std::move(url_loader_factory_getter_info)),
-      service_worker_provider_id_(service_worker_provider_id),
-      terminate_sync_load_event_(
-          base::WaitableEvent::ResetPolicy::MANUAL,
-          base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+      service_worker_provider_id_(service_worker_provider_id) {}
 
 ServiceWorkerFetchContextImpl::~ServiceWorkerFetchContextImpl() {}
 
-base::WaitableEvent*
-ServiceWorkerFetchContextImpl::GetTerminateSyncLoadEvent() {
-  return &terminate_sync_load_event_;
-}
-
 void ServiceWorkerFetchContextImpl::InitializeOnWorkerThread(
     scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner) {
   resource_dispatcher_ = std::make_unique<ResourceDispatcher>(
       nullptr, std::move(loading_task_runner));
-  resource_dispatcher_->set_terminate_sync_load_event(
-      &terminate_sync_load_event_);
 
   url_loader_factory_getter_ = url_loader_factory_getter_info_.Bind();
 }
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.h b/content/renderer/service_worker/service_worker_fetch_context_impl.h
index 2a17cdb..58b9450 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.h
@@ -26,7 +26,6 @@
   ~ServiceWorkerFetchContextImpl() override;
 
   // blink::WebWorkerFetchContext implementation:
-  base::WaitableEvent* GetTerminateSyncLoadEvent() override;
   void InitializeOnWorkerThread(
       scoped_refptr<base::SingleThreadTaskRunner>) override;
   std::unique_ptr<blink::WebURLLoaderFactory> CreateURLLoaderFactory() override;
@@ -43,8 +42,6 @@
   // Initialized on the worker thread when InitializeOnWorkerThread() is called.
   std::unique_ptr<ResourceDispatcher> resource_dispatcher_;
   scoped_refptr<ChildURLLoaderFactoryGetter> url_loader_factory_getter_;
-
-  base::WaitableEvent terminate_sync_load_event_;
 };
 
 }  // namespace content
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.cc b/content/renderer/service_worker/worker_fetch_context_impl.cc
index c42e3d1..5ff6dc6 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/worker_fetch_context_impl.cc
@@ -103,10 +103,7 @@
           std::move(service_worker_container_host_info)),
       url_loader_factory_getter_info_(
           std::move(url_loader_factory_getter_info)),
-      thread_safe_sender_(ChildThreadImpl::current()->thread_safe_sender()),
-      terminate_sync_load_event_(
-          base::WaitableEvent::ResetPolicy::MANUAL,
-          base::WaitableEvent::InitialState::NOT_SIGNALED) {
+      thread_safe_sender_(ChildThreadImpl::current()->thread_safe_sender()) {
   if (ServiceWorkerUtils::IsServicificationEnabled()) {
     ChildThreadImpl::current()->GetConnector()->BindInterface(
         mojom::kBrowserServiceName,
@@ -116,10 +113,6 @@
 
 WorkerFetchContextImpl::~WorkerFetchContextImpl() {}
 
-base::WaitableEvent* WorkerFetchContextImpl::GetTerminateSyncLoadEvent() {
-  return &terminate_sync_load_event_;
-}
-
 void WorkerFetchContextImpl::InitializeOnWorkerThread(
     scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner) {
   DCHECK(loading_task_runner->RunsTasksInCurrentSequence());
@@ -127,8 +120,6 @@
   DCHECK(!binding_.is_bound());
   resource_dispatcher_ = std::make_unique<ResourceDispatcher>(
       nullptr, std::move(loading_task_runner));
-  resource_dispatcher_->set_terminate_sync_load_event(
-      &terminate_sync_load_event_);
 
   url_loader_factory_getter_ = url_loader_factory_getter_info_.Bind();
   if (service_worker_client_request_.is_pending())
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.h b/content/renderer/service_worker/worker_fetch_context_impl.h
index c57e4936..1464eba4 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/worker_fetch_context_impl.h
@@ -5,7 +5,6 @@
 #ifndef CONTENT_RENDERER_SERVICE_WORKER_WORKER_FETCH_CONTEXT_IMPL_H_
 #define CONTENT_RENDERER_SERVICE_WORKER_WORKER_FETCH_CONTEXT_IMPL_H_
 
-#include "base/synchronization/waitable_event.h"
 #include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/service_worker_modes.h"
@@ -47,7 +46,6 @@
   ~WorkerFetchContextImpl() override;
 
   // blink::WebWorkerFetchContext implementation:
-  base::WaitableEvent* GetTerminateSyncLoadEvent() override;
   void InitializeOnWorkerThread(
       scoped_refptr<base::SingleThreadTaskRunner>) override;
   std::unique_ptr<blink::WebURLLoaderFactory> CreateURLLoaderFactory() override;
@@ -136,8 +134,6 @@
   GURL origin_url_;
   int appcache_host_id_ = blink::WebApplicationCacheHost::kAppCacheNoHostId;
 
-  base::WaitableEvent terminate_sync_load_event_;
-
   // A weak ptr to blink::WebURLLoaderFactory which was created and passed to
   // Blink by CreateURLLoaderFactory().
   base::WeakPtr<URLLoaderFactoryImpl> url_loader_factory_;
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
index 619fd71..af2e26c 100644
--- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -458,12 +458,12 @@
     # process. On Windows, and eventually on other platforms where
     # SwiftShader is used, this test should pass.
     #
-    args_list = ([
+    args_list = (
       # Hit id 4 from kSoftwareRenderingListEntries.
-      '--gpu-testing-vendor-id=0x8086',
-      '--gpu-testing-device-id=0x27A2'],
+      ['--gpu-testing-vendor-id=0x8086',
+       '--gpu-testing-device-id=0x27A2'],
       # Explicitly disable GPU access.
-     ['--disable-gpu'])
+      ['--disable-gpu'])
     for args in args_list:
       self.RestartBrowserIfNecessaryWithArgs(args)
       self._NavigateAndWait(test_path)
diff --git a/gpu/command_buffer/service/gpu_preferences.h b/gpu/command_buffer/service/gpu_preferences.h
index cbfe520..c4c3015 100644
--- a/gpu/command_buffer/service/gpu_preferences.h
+++ b/gpu/command_buffer/service/gpu_preferences.h
@@ -78,6 +78,9 @@
   // quality of output. So this flag is disabled by default. Windows only.
   bool enable_media_foundation_vea_on_windows7 = false;
 
+  // Disables the use of a 3D software rasterizer, for example, SwiftShader.
+  bool disable_software_rasterizer = false;
+
   // ===================================
   // Settings from //gpu/command_buffer/service/gpu_switches.cc
 
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc
index 04da6f6..ad6da6d 100644
--- a/gpu/config/gpu_info_collector.cc
+++ b/gpu/config/gpu_info_collector.cc
@@ -232,6 +232,7 @@
   basic_gpu_info->gl_ws_extensions = context_gpu_info.gl_ws_extensions;
   basic_gpu_info->gl_reset_notification_strategy =
       context_gpu_info.gl_reset_notification_strategy;
+  basic_gpu_info->software_rendering = context_gpu_info.software_rendering;
 
   if (!context_gpu_info.driver_vendor.empty())
     basic_gpu_info->driver_vendor = context_gpu_info.driver_vendor;
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc
index b0e69ba..dea8fdb 100644
--- a/gpu/config/gpu_info_collector_win.cc
+++ b/gpu/config/gpu_info_collector_win.cc
@@ -16,7 +16,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/command_line.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -34,8 +33,6 @@
 #include "base/threading/thread.h"
 #include "base/trace_event/trace_event.h"
 #include "base/win/scoped_com_initializer.h"
-#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_surface_egl.h"
 
 namespace gpu {
 
@@ -235,18 +232,6 @@
 
   DCHECK(gpu_info);
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) {
-    std::string requested_implementation_name =
-        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-            switches::kUseGL);
-    if (requested_implementation_name ==
-        gl::kGLImplementationSwiftShaderForWebGLName) {
-      gpu_info->software_rendering = true;
-      gpu_info->context_info_state = kCollectInfoNonFatalFailure;
-      return kCollectInfoNonFatalFailure;
-    }
-  }
-
   CollectInfoResult result = CollectGraphicsInfoGL(gpu_info);
   if (result != kCollectInfoSuccess) {
     gpu_info->context_info_state = result;
@@ -353,11 +338,6 @@
                   const GPUInfo& context_gpu_info) {
   DCHECK(basic_gpu_info);
 
-  if (context_gpu_info.software_rendering) {
-    basic_gpu_info->software_rendering = true;
-    return;
-  }
-
   // Track D3D Shader Model (if available)
   const std::string& shader_version =
       context_gpu_info.vertex_shader_version;
diff --git a/gpu/config/gpu_util.cc b/gpu/config/gpu_util.cc
index 63e8a79..ee43a2a 100644
--- a/gpu/config/gpu_util.cc
+++ b/gpu/config/gpu_util.cc
@@ -69,9 +69,8 @@
 
 GpuFeatureStatus GetWebGLFeatureStatus(
     const std::set<int>& blacklisted_features,
-    bool use_swift_shader,
-    bool use_swift_shader_for_webgl) {
-  if (use_swift_shader || use_swift_shader_for_webgl)
+    bool use_swift_shader) {
+  if (use_swift_shader)
     return kGpuFeatureStatusSoftware;
   if (blacklisted_features.count(GPU_FEATURE_TYPE_ACCELERATED_WEBGL))
     return kGpuFeatureStatusBlacklisted;
@@ -80,9 +79,8 @@
 
 GpuFeatureStatus GetWebGL2FeatureStatus(
     const std::set<int>& blacklisted_features,
-    bool use_swift_shader,
-    bool use_swift_shader_for_webgl) {
-  if (use_swift_shader || use_swift_shader_for_webgl)
+    bool use_swift_shader) {
+  if (use_swift_shader)
     return kGpuFeatureStatusSoftware;
   if (blacklisted_features.count(GPU_FEATURE_TYPE_ACCELERATED_WEBGL2))
     return kGpuFeatureStatusBlacklisted;
@@ -91,15 +89,12 @@
 
 GpuFeatureStatus Get2DCanvasFeatureStatus(
     const std::set<int>& blacklisted_features,
-    bool use_swift_shader,
-    bool use_swift_shader_for_webgl) {
+    bool use_swift_shader) {
   if (use_swift_shader) {
     // This is for testing only. Chrome should exercise the GPU accelerated
     // path on top of SwiftShader driver.
     return kGpuFeatureStatusEnabled;
   }
-  if (use_swift_shader_for_webgl)
-    return kGpuFeatureStatusSoftware;
   if (blacklisted_features.count(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
     return kGpuFeatureStatusSoftware;
   return kGpuFeatureStatusEnabled;
@@ -107,15 +102,12 @@
 
 GpuFeatureStatus GetFlash3DFeatureStatus(
     const std::set<int>& blacklisted_features,
-    bool use_swift_shader,
-    bool use_swift_shader_for_webgl) {
+    bool use_swift_shader) {
   if (use_swift_shader) {
     // This is for testing only. Chrome should exercise the GPU accelerated
     // path on top of SwiftShader driver.
     return kGpuFeatureStatusEnabled;
   }
-  if (use_swift_shader_for_webgl)
-    return kGpuFeatureStatusDisabled;
   if (blacklisted_features.count(GPU_FEATURE_TYPE_FLASH3D))
     return kGpuFeatureStatusBlacklisted;
   return kGpuFeatureStatusEnabled;
@@ -123,15 +115,12 @@
 
 GpuFeatureStatus GetFlashStage3DFeatureStatus(
     const std::set<int>& blacklisted_features,
-    bool use_swift_shader,
-    bool use_swift_shader_for_webgl) {
+    bool use_swift_shader) {
   if (use_swift_shader) {
     // This is for testing only. Chrome should exercise the GPU accelerated
     // path on top of SwiftShader driver.
     return kGpuFeatureStatusEnabled;
   }
-  if (use_swift_shader_for_webgl)
-    return kGpuFeatureStatusDisabled;
   if (blacklisted_features.count(GPU_FEATURE_TYPE_FLASH_STAGE3D))
     return kGpuFeatureStatusBlacklisted;
   return kGpuFeatureStatusEnabled;
@@ -139,15 +128,12 @@
 
 GpuFeatureStatus GetFlashStage3DBaselineFeatureStatus(
     const std::set<int>& blacklisted_features,
-    bool use_swift_shader,
-    bool use_swift_shader_for_webgl) {
+    bool use_swift_shader) {
   if (use_swift_shader) {
     // This is for testing only. Chrome should exercise the GPU accelerated
     // path on top of SwiftShader driver.
     return kGpuFeatureStatusEnabled;
   }
-  if (use_swift_shader_for_webgl)
-    return kGpuFeatureStatusDisabled;
   if (blacklisted_features.count(GPU_FEATURE_TYPE_FLASH_STAGE3D) ||
       blacklisted_features.count(GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE))
     return kGpuFeatureStatusBlacklisted;
@@ -156,9 +142,8 @@
 
 GpuFeatureStatus GetAcceleratedVideoDecodeFeatureStatus(
     const std::set<int>& blacklisted_features,
-    bool use_swift_shader,
-    bool use_swift_shader_for_webgl) {
-  if (use_swift_shader || use_swift_shader_for_webgl)
+    bool use_swift_shader) {
+  if (use_swift_shader)
     return kGpuFeatureStatusDisabled;
   if (blacklisted_features.count(GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE))
     return kGpuFeatureStatusBlacklisted;
@@ -167,15 +152,12 @@
 
 GpuFeatureStatus GetGpuCompositingFeatureStatus(
     const std::set<int>& blacklisted_features,
-    bool use_swift_shader,
-    bool use_swift_shader_for_webgl) {
+    bool use_swift_shader) {
   if (use_swift_shader) {
     // This is for testing only. Chrome should exercise the GPU accelerated
     // path on top of SwiftShader driver.
     return kGpuFeatureStatusEnabled;
   }
-  if (use_swift_shader_for_webgl)
-    return kGpuFeatureStatusDisabled;
   if (blacklisted_features.count(GPU_FEATURE_TYPE_GPU_COMPOSITING))
     return kGpuFeatureStatusBlacklisted;
   return kGpuFeatureStatusEnabled;
@@ -329,16 +311,36 @@
   return gpu_feature_info;
 }
 
+GpuFeatureInfo ComputeGpuFeatureInfoForSwiftShader() {
+  GpuFeatureInfo gpu_feature_info;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS] =
+      kGpuFeatureStatusSoftware;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_GPU_COMPOSITING] =
+      kGpuFeatureStatusDisabled;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL] =
+      kGpuFeatureStatusSoftware;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_FLASH3D] =
+      kGpuFeatureStatusDisabled;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_FLASH_STAGE3D] =
+      kGpuFeatureStatusDisabled;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE] =
+      kGpuFeatureStatusDisabled;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE] =
+      kGpuFeatureStatusDisabled;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_GPU_RASTERIZATION] =
+      kGpuFeatureStatusDisabled;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL2] =
+      kGpuFeatureStatusSoftware;
+#if DCHECK_IS_ON()
+  for (int ii = 0; ii < NUMBER_OF_GPU_FEATURE_TYPES; ++ii) {
+    DCHECK_NE(kGpuFeatureStatusUndefined, gpu_feature_info.status_values[ii]);
+  }
+#endif
+  return gpu_feature_info;
+}
+
 GpuFeatureInfo ComputeGpuFeatureInfo(const GPUInfo& gpu_info,
                                      base::CommandLine* command_line) {
-  GpuFeatureInfo gpu_feature_info;
-  std::set<int> blacklisted_features;
-  if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist)) {
-    std::unique_ptr<GpuBlacklist> list(GpuBlacklist::Create());
-    blacklisted_features =
-        list->MakeDecision(GpuControlList::kOsAny, std::string(), gpu_info);
-  }
-
   bool use_swift_shader = false;
   bool use_swift_shader_for_webgl = false;
   if (command_line->HasSwitch(switches::kUseGL)) {
@@ -348,33 +350,37 @@
     else if (use_gl == gl::kGLImplementationSwiftShaderForWebGLName)
       use_swift_shader_for_webgl = true;
   }
+  if (use_swift_shader_for_webgl)
+    return ComputeGpuFeatureInfoForSwiftShader();
+
+  GpuFeatureInfo gpu_feature_info;
+  std::set<int> blacklisted_features;
+  if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist)) {
+    std::unique_ptr<GpuBlacklist> list(GpuBlacklist::Create());
+    blacklisted_features =
+        list->MakeDecision(GpuControlList::kOsAny, std::string(), gpu_info);
+  }
 
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_GPU_RASTERIZATION] =
       GetGpuRasterizationFeatureStatus(blacklisted_features, *command_line);
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL] =
-      GetWebGLFeatureStatus(blacklisted_features, use_swift_shader,
-                            use_swift_shader_for_webgl);
+      GetWebGLFeatureStatus(blacklisted_features, use_swift_shader);
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL2] =
-      GetWebGL2FeatureStatus(blacklisted_features, use_swift_shader,
-                             use_swift_shader_for_webgl);
+      GetWebGL2FeatureStatus(blacklisted_features, use_swift_shader);
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS] =
-      Get2DCanvasFeatureStatus(blacklisted_features, use_swift_shader,
-                               use_swift_shader_for_webgl);
+      Get2DCanvasFeatureStatus(blacklisted_features, use_swift_shader);
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_FLASH3D] =
-      GetFlash3DFeatureStatus(blacklisted_features, use_swift_shader,
-                              use_swift_shader_for_webgl);
+      GetFlash3DFeatureStatus(blacklisted_features, use_swift_shader);
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_FLASH_STAGE3D] =
-      GetFlashStage3DFeatureStatus(blacklisted_features, use_swift_shader,
-                                   use_swift_shader_for_webgl);
+      GetFlashStage3DFeatureStatus(blacklisted_features, use_swift_shader);
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE] =
-      GetFlashStage3DBaselineFeatureStatus(
-          blacklisted_features, use_swift_shader, use_swift_shader_for_webgl);
+      GetFlashStage3DBaselineFeatureStatus(blacklisted_features,
+                                           use_swift_shader);
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE] =
-      GetAcceleratedVideoDecodeFeatureStatus(
-          blacklisted_features, use_swift_shader, use_swift_shader_for_webgl);
+      GetAcceleratedVideoDecodeFeatureStatus(blacklisted_features,
+                                             use_swift_shader);
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_GPU_COMPOSITING] =
-      GetGpuCompositingFeatureStatus(blacklisted_features, use_swift_shader,
-                                     use_swift_shader_for_webgl);
+      GetGpuCompositingFeatureStatus(blacklisted_features, use_swift_shader);
 #if DCHECK_IS_ON()
   for (int ii = 0; ii < NUMBER_OF_GPU_FEATURE_TYPES; ++ii) {
     DCHECK_NE(kGpuFeatureStatusUndefined, gpu_feature_info.status_values[ii]);
diff --git a/gpu/config/gpu_util.h b/gpu/config/gpu_util.h
index 3115dbc1..f766d4e 100644
--- a/gpu/config/gpu_util.h
+++ b/gpu/config/gpu_util.h
@@ -33,6 +33,9 @@
 GPU_EXPORT GpuFeatureInfo
 ComputeGpuFeatureInfoWithHardwareAccelerationDisabled();
 
+// Set GPU feature status for SwiftShader.
+GPU_EXPORT GpuFeatureInfo ComputeGpuFeatureInfoForSwiftShader();
+
 // This function should only be called from the GPU process, or the Browser
 // process while using in-process GPU. This function is safe to call at any
 // point, and is not dependent on sandbox initialization.
diff --git a/gpu/ipc/common/gpu_preferences.mojom b/gpu/ipc/common/gpu_preferences.mojom
index ce7b269b..5f70088 100644
--- a/gpu/ipc/common/gpu_preferences.mojom
+++ b/gpu/ipc/common/gpu_preferences.mojom
@@ -33,6 +33,7 @@
   bool enable_zero_copy_dxgi_video;
   bool enable_nv12_dxgi_video;
   bool enable_media_foundation_vea_on_windows7;
+  bool disable_software_rasterizer;
 
   bool compile_shader_always_succeeds;
   bool disable_gl_error_limit;
diff --git a/gpu/ipc/common/gpu_preferences_struct_traits.h b/gpu/ipc/common/gpu_preferences_struct_traits.h
index fed6d70..a05f76a 100644
--- a/gpu/ipc/common/gpu_preferences_struct_traits.h
+++ b/gpu/ipc/common/gpu_preferences_struct_traits.h
@@ -70,6 +70,7 @@
     out->enable_nv12_dxgi_video = prefs.enable_nv12_dxgi_video();
     out->enable_media_foundation_vea_on_windows7 =
         prefs.enable_media_foundation_vea_on_windows7();
+    out->disable_software_rasterizer = prefs.disable_software_rasterizer();
     out->compile_shader_always_succeeds =
         prefs.compile_shader_always_succeeds();
     out->disable_gl_error_limit = prefs.disable_gl_error_limit();
@@ -147,6 +148,9 @@
       const gpu::GpuPreferences& prefs) {
     return prefs.enable_media_foundation_vea_on_windows7;
   }
+  static bool disable_software_rasterizer(const gpu::GpuPreferences& prefs) {
+    return prefs.disable_software_rasterizer;
+  }
   static bool compile_shader_always_succeeds(const gpu::GpuPreferences& prefs) {
     return prefs.compile_shader_always_succeeds;
   }
diff --git a/gpu/ipc/common/gpu_preferences_util_unittest.cc b/gpu/ipc/common/gpu_preferences_util_unittest.cc
index fd936ac..8a354c6 100644
--- a/gpu/ipc/common/gpu_preferences_util_unittest.cc
+++ b/gpu/ipc/common/gpu_preferences_util_unittest.cc
@@ -77,6 +77,7 @@
     GPU_PREFERENCES_FIELD(enable_zero_copy_dxgi_video, true)
     GPU_PREFERENCES_FIELD(enable_nv12_dxgi_video, true)
     GPU_PREFERENCES_FIELD(enable_media_foundation_vea_on_windows7, true)
+    GPU_PREFERENCES_FIELD(disable_software_rasterizer, true)
     GPU_PREFERENCES_FIELD(compile_shader_always_succeeds, true)
     GPU_PREFERENCES_FIELD(disable_gl_error_limit, true)
     GPU_PREFERENCES_FIELD(disable_glsl_translator, true)
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn
index 2946c237..0bef733 100644
--- a/gpu/ipc/service/BUILD.gn
+++ b/gpu/ipc/service/BUILD.gn
@@ -68,6 +68,7 @@
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/gl",
+    "//ui/gl:gl_features",
     "//ui/gl/init",
     "//url",
   ]
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index 95e107d..84477b9 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -20,6 +20,7 @@
 #include "gpu/ipc/service/gpu_watchdog_thread.h"
 #include "gpu/ipc/service/switches.h"
 #include "ui/gfx/switches.h"
+#include "ui/gl/gl_features.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_switches.h"
 #include "ui/gl/gl_utils.h"
@@ -133,11 +134,6 @@
     gpu::InitializeSwitchableGPUs(
         gpu_feature_info_.enabled_gpu_driver_bug_workarounds);
   }
-  if (kGpuFeatureStatusEnabled !=
-      gpu_feature_info_
-          .status_values[GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE]) {
-    gpu_preferences_.disable_accelerated_video_decode = true;
-  }
 #endif  // OS_ANDROID
   gpu_info_.in_process_gpu = false;
 
@@ -201,13 +197,17 @@
   ui::OzonePlatform::InitializeForGPU(params);
 #endif
 
+  bool use_swiftshader = ShouldEnableSwiftShader(command_line);
   // Load and initialize the GL implementation and locate the GL entry points if
   // needed. This initialization may have already happened if running in the
   // browser process, for example.
   bool gl_initialized = gl::GetGLImplementation() != gl::kGLImplementationNone;
+  if (gl_initialized && use_swiftshader) {
+    gl::init::ShutdownGL(true);
+    gl_initialized = false;
+  }
   if (!gl_initialized)
     gl_initialized = gl::init::InitializeGLNoExtensionsOneOff();
-
   if (!gl_initialized) {
     VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff failed";
     return false;
@@ -220,17 +220,32 @@
   // By skipping the following code on Mac, we don't really lose anything,
   // because the basic GPU information is passed down from the host process.
 #if !defined(OS_MACOSX)
-  CollectGraphicsInfo(&gpu_info_);
-  if (gpu_info_.context_info_state == gpu::kCollectInfoFatalFailure)
-    return false;
-  gpu::SetKeysForCrashLogging(gpu_info_);
-  gpu_feature_info_ = gpu::ComputeGpuFeatureInfo(gpu_info_, command_line);
+  if (!use_swiftshader) {
+    CollectGraphicsInfo(&gpu_info_);
+    if (gpu_info_.context_info_state == gpu::kCollectInfoFatalFailure)
+      return false;
+    gpu::SetKeysForCrashLogging(gpu_info_);
+    gpu_feature_info_ = gpu::ComputeGpuFeatureInfo(gpu_info_, command_line);
+    use_swiftshader = ShouldEnableSwiftShader(command_line);
+    if (use_swiftshader) {
+      gl::init::ShutdownGL(true);
+      gl_initialized = gl::init::InitializeGLNoExtensionsOneOff();
+      if (!gl_initialized) {
+        VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff with SwiftShader "
+                << "failed";
+        return false;
+      }
+    }
+  }
+#endif
+  if (use_swiftshader) {
+    AdjustInfoToSwiftShader();
+  }
   if (kGpuFeatureStatusEnabled !=
       gpu_feature_info_
           .status_values[GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE]) {
     gpu_preferences_.disable_accelerated_video_decode = true;
   }
-#endif
 
   if (!gpu_feature_info_.disabled_extensions.empty()) {
     gl::init::SetDisabledExtensionsPlatform(
@@ -249,7 +264,17 @@
 
   // Software GL is expected to run slowly, so disable the watchdog
   // in that case.
-  if (gl::GetGLImplementation() == gl::GetSoftwareGLImplementation()) {
+  // In SwiftShader case, the implementation is actually EGLGLES2.
+  if (!use_swiftshader && command_line->HasSwitch(switches::kUseGL)) {
+    std::string use_gl = command_line->GetSwitchValueASCII(switches::kUseGL);
+    if (use_gl == gl::kGLImplementationSwiftShaderName ||
+        use_gl == gl::kGLImplementationSwiftShaderForWebGLName) {
+      use_swiftshader = true;
+    }
+  }
+  if (use_swiftshader ||
+      gl::GetGLImplementation() == gl::GetSoftwareGLImplementation()) {
+    gpu_info_.software_rendering = true;
     if (watchdog_thread_)
       watchdog_thread_->Stop();
     watchdog_thread_ = nullptr;
@@ -303,13 +328,28 @@
         gpu_feature_info_.enabled_gpu_driver_bug_workarounds);
   }
 
+  bool use_swiftshader = ShouldEnableSwiftShader(command_line);
   if (!gl::init::InitializeGLNoExtensionsOneOff()) {
     VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff failed";
     return;
   }
 
-  gpu::CollectContextGraphicsInfo(&gpu_info_);
-  gpu_feature_info_ = gpu::ComputeGpuFeatureInfo(gpu_info_, command_line);
+  if (!use_swiftshader) {
+    gpu::CollectContextGraphicsInfo(&gpu_info_);
+    gpu_feature_info_ = gpu::ComputeGpuFeatureInfo(gpu_info_, command_line);
+    use_swiftshader = ShouldEnableSwiftShader(command_line);
+    if (use_swiftshader) {
+      gl::init::ShutdownGL(true);
+      if (!gl::init::InitializeGLNoExtensionsOneOff()) {
+        VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff failed "
+                << "with SwiftShader";
+        return;
+      }
+    }
+  }
+  if (use_swiftshader) {
+    AdjustInfoToSwiftShader();
+  }
   if (!gpu_feature_info_.disabled_extensions.empty()) {
     gl::init::SetDisabledExtensionsPlatform(
         gpu_feature_info_.disabled_extensions);
@@ -319,4 +359,31 @@
   }
 }
 
+bool GpuInit::ShouldEnableSwiftShader(base::CommandLine* command_line) {
+#if BUILDFLAG(ENABLE_SWIFTSHADER)
+  if (gpu_preferences_.disable_software_rasterizer)
+    return false;
+  // Don't overwrite user preference.
+  if (command_line->HasSwitch(switches::kUseGL))
+    return false;
+  if (gpu_feature_info_.status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL] !=
+      kGpuFeatureStatusEnabled) {
+    command_line->AppendSwitchASCII(
+        switches::kUseGL, gl::kGLImplementationSwiftShaderForWebGLName);
+    return true;
+  }
+  return false;
+#else
+  return false;
+#endif
+}
+
+void GpuInit::AdjustInfoToSwiftShader() {
+  gpu_feature_info_ = ComputeGpuFeatureInfoForSwiftShader();
+  gpu_info_.gl_vendor = "Google Inc. (" + gpu_info_.gl_vendor + ")";
+  gpu_info_.gl_renderer = "Google SwiftShader (" + gpu_info_.gl_renderer + ")";
+  gpu_info_.gl_version =
+      "OpenGL ES 2.0 SwiftShader (" + gpu_info_.gl_version + ")";
+}
+
 }  // namespace gpu
diff --git a/gpu/ipc/service/gpu_init.h b/gpu/ipc/service/gpu_init.h
index 173ca71..b7993947 100644
--- a/gpu/ipc/service/gpu_init.h
+++ b/gpu/ipc/service/gpu_init.h
@@ -64,6 +64,8 @@
   GpuPreferences gpu_preferences_;
   bool init_successful_ = false;
 
+  bool ShouldEnableSwiftShader(base::CommandLine* command_line);
+  void AdjustInfoToSwiftShader();
   DISALLOW_COPY_AND_ASSIGN(GpuInit);
 };
 
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 4cef0e3..7c1f4232 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -2176,7 +2176,6 @@
 crbug.com/591099 editing/style/remove-underline-across-paragraph-in-bold.html [ Crash Failure ]
 crbug.com/591099 editing/style/remove-underline-across-paragraph.html [ Crash Failure ]
 crbug.com/591099 editing/style/table-selection.html [ Failure ]
-crbug.com/714962 editing/surrounding-text/surrounding-text.html [ Failure ]
 crbug.com/591099 editing/text-iterator/findString-start-search-after-selection.html [ Failure ]
 crbug.com/591099 editing/text-iterator/findString.html [ Pass Timeout ]
 crbug.com/591099 editing/undo/crash-redo-with-iframes.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 93874c3..3ff79cf 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -94,7 +94,6 @@
 crbug.com/771643 virtual/spv175/paint/invalidation/svg/text-viewbox-rescale.html [ Failure ]
 crbug.com/771643 virtual/spv175/paint/invalidation/svg/use-clipped-hit.svg [ Failure ]
 crbug.com/771643 virtual/spv175/paint/invalidation/svg/zoom-coords-viewattr-01-b.svg [ Failure ]
-crbug.com/771643 virtual/spv175/paint/pagination/pagination-change-clip-crash.html [ Failure ]
 
 # spv175+root-layer-scrolls failures. They also fail with root-layer-scrolls without enable-slimming-paint-v175.
 crbug.com/417782 virtual/spv175/compositing/overflow/border-radius-composited-subframe.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text-detached-no-crash-expected.txt b/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text-detached-no-crash-expected.txt
deleted file mode 100644
index 8a136903..0000000
--- a/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text-detached-no-crash-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Calling textSurroundingNode() on a detached node without crashing
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS window.internals.textSurroundingNode(node, 0, 0, 0) is ""
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text-detached-no-crash.html b/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text-detached-no-crash.html
deleted file mode 100644
index 9e6d7264..0000000
--- a/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text-detached-no-crash.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/js-test.js"></script>
-<script>
-description('Calling textSurroundingNode() on a detached node without crashing');
-
-if (window.internals) {
-    var node = document.createElement("p");
-    shouldBeEmptyString('window.internals.textSurroundingNode(node, 0, 0, 0)');
-}
-</script>
diff --git a/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text-expected.txt b/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text-expected.txt
deleted file mode 100644
index 1752c27..0000000
--- a/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-Test the extraction of the text surrounding an element.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS surroundingText('<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>', 0, 100) is "12345 6789 12345 6789"
-PASS surroundingText('<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>', 5, 6) is "89 123"
-PASS surroundingText('<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>', 5, 0) is ""
-PASS surroundingText('<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>', 5, 1) is "1"
-PASS surroundingText('<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>', 6, 2) is "12"
-PASS surroundingText('<select>.</select><div>57th Street and Lake Shore Drive</div> <span>Chicago</span> <span id="here">IL</span> <span>60637</span><select>.</select>', 0, 100) is "57th Street and Lake Shore Drive Chicago IL 60637"
-PASS surroundingText('<fieldset>.</fieldset>12345<button>abc</button><p>6789<br id="here"/>12345</p>6789<textarea>abc</textarea>0123<fieldset>.</fieldset>', 0, 100) is "6789 12345 6789"
-PASS surroundingText('<button>.</button><div id="here">This is <!-- comment --!>a test <' + 'script language="javascript"><' + '/script>example<button>.</button>', 0, 100) is "This is a test example"
-PASS surroundingText('<button>.</button><div id="here">012345678901234567890123456789</div><button>.</button>', 15, 12) is "901234567890"
-PASS surroundingText('<option>.</option>12345<button id="here">test</button><option>.</option>', 1, 100) is ""
-PASS surroundingText('<option>.</option>12345<button>te<span id="here">st</span></button><option>.</option>', 1, 100) is ""
-PASS surroundingText('<p id="here">.</p>', 0, 2) is "."
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text.html b/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text.html
deleted file mode 100644
index 1ebfebf..0000000
--- a/third_party/WebKit/LayoutTests/editing/surrounding-text/surrounding-text.html
+++ /dev/null
@@ -1,70 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<script src="../../resources/js-test.js"></script>
-<div id="test">
-</div>
-<p id="description"></p>
-<div id="console"></div>
-<script>
-description('Test the extraction of the text surrounding an element.');
-
-function findOffsetCoordinates(node, offset) {
-    var nodeRange = document.createRange();
-    nodeRange.selectNode(node);
-
-    var offsetRange = document.createRange();
-    offsetRange.setStart(node, offset);
-    offsetRange.setEnd(node, offset + 1);
-
-    var nodeRect = nodeRange.getBoundingClientRect();
-    var offsetRect = offsetRange.getBoundingClientRect();
-    var x = (offsetRect.left + offsetRect.right) / 2 - nodeRect.left;
-    var y = (offsetRect.top + offsetRect.bottom) / 2 - nodeRect.top;
-
-    return { x: x, y: y };
-}
-
-function surroundingText(html, offset, maxLength) {
-    document.getElementById('test').innerHTML = html;
-
-    var here = document.getElementById('here');
-    if (here == null)
-        throw 'Test case needs an element with id "here"';
-
-    var node = here.hasChildNodes() ? here.firstChild : here.nextSibling;
-    if (node == null)
-        throw 'No node after "here" element';
-
-    var coords = findOffsetCoordinates(node, offset);
-    var text = window.internals.textSurroundingNode(node, coords.x, coords.y, maxLength);
-    return text.replace(/\s+|\ufffc/g, ' ').replace(/^\s*|\s*$/g, '');
-}
-
-function run() {
-    if (!window.internals)
-        return;
-
-    shouldBeEqualToString('surroundingText(\'<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>\', 0, 100)', '12345 6789 12345 6789');
-    shouldBeEqualToString('surroundingText(\'<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>\', 5, 6)', '89 123');
-    shouldBeEqualToString('surroundingText(\'<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>\', 5, 0)', '');
-    shouldBeEqualToString('surroundingText(\'<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>\', 5, 1)', '1');
-    shouldBeEqualToString('surroundingText(\'<button>.</button>12345<p id="here">6789 12345</p>6789<button>.</button>\', 6, 2)', '12');
-    shouldBeEqualToString('surroundingText(\'<select>.</select><div>57th Street and Lake Shore Drive</div> <span>Chicago</span> <span id="here">IL</span> <span>60637</span><select>.</select>\', 0, 100)', '57th Street and Lake Shore Drive Chicago IL 60637');
-    shouldBeEqualToString('surroundingText(\'<fieldset>.</fieldset>12345<button>abc</button><p>6789<br id="here"/>12345</p>6789<textarea>abc</textarea>0123<fieldset>.</fieldset>\', 0, 100)', '6789 12345 6789');
-    shouldBeEqualToString('surroundingText(\'<button>.</button><div id="here">This is <!-- comment --!>a test <\' + \'script language="javascript"><\' + \'/script>example<button>.</button>\', 0, 100)', 'This is a test example');
-    shouldBeEqualToString('surroundingText(\'<button>.</button><div id="here">012345678901234567890123456789</div><button>.</button>\', 15, 12)', '901234567890');
-    shouldBeEqualToString('surroundingText(\'<option>.</option>12345<button id="here">test</button><option>.</option>\', 1, 100)', '');
-    shouldBeEqualToString('surroundingText(\'<option>.</option>12345<button>te<span id="here">st</span></button><option>.</option>\', 1, 100)', '');
-    shouldBeEqualToString('surroundingText(\'<p id="here">.</p>\', 0, 2)', '.');
-
-    document.body.removeChild(document.getElementById('test'));
-    finishJSTest();
-}
-
-window.onload = run;
-window.jsTestIsAsync = true;
-window.successfullyParsed = true;
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-sync-response-event-order-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-sync-response-event-order-expected.txt
new file mode 100644
index 0000000..855a866
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-sync-response-event-order-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL XMLHttpRequest: The send() method: event order when synchronous flag is set assert_equals: expected "load(12,12,true)" but got "load(12,0,false)"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/change-column-rule-expected.html b/third_party/WebKit/LayoutTests/fast/multicol/change-column-rule-expected.html
index 9e7211a..12f9c9a 100644
--- a/third_party/WebKit/LayoutTests/fast/multicol/change-column-rule-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/multicol/change-column-rule-expected.html
@@ -1,7 +1,6 @@
 <!DOCTYPE html>
 <p>The rules below should be green, and there should be no assertion failures.</p>
-<p>Click to test if testing manually.</p>
-<div id="mc" style="-webkit-columns:3; line-height:100px; -webkit-column-rule:solid green;">
+<div id="mc" style="columns:3; line-height:100px; column-rule:solid green;">
     <br>
     <br>
     <br>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/change-column-rule.html b/third_party/WebKit/LayoutTests/fast/multicol/change-column-rule.html
index 07a19af..e114d92 100644
--- a/third_party/WebKit/LayoutTests/fast/multicol/change-column-rule.html
+++ b/third_party/WebKit/LayoutTests/fast/multicol/change-column-rule.html
@@ -1,23 +1,13 @@
 <!DOCTYPE html>
 <p>The rules below should be green, and there should be no assertion failures.</p>
-<p>Click to test if testing manually.</p>
-<div id="mc" style="-webkit-columns:3; line-height:100px; -webkit-column-rule:solid yellow;">
+<div id="mc" style="columns:3; line-height:100px; column-rule:solid yellow;">
     <br>
     <br>
     <br>
 </div>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
 <script>
-    if (window.testRunner)
-        testRunner.waitUntilDone();
-    function changeStyle() {
-        document.getElementById('mc').style.webkitColumnRuleColor = 'green';
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-    onclick = changeStyle; // for testing manually.
-    onload = function() {
-        // Force painting, then change style, which in turn will trigger another repaint.
-        if (window.testRunner)
-            testRunner.layoutAndPaintAsyncThen(changeStyle);
-    }
+runAfterLayoutAndPaint(function() {
+  mc.style.webkitColumnRuleColor = 'green';
+}, true);
 </script>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/column-rules-fixed-height-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/column-rules-fixed-height-expected.txt
index 346475f5..d70b2ea 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/column-rules-fixed-height-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/column-rules-fixed-height-expected.txt
@@ -10,36 +10,6 @@
           "object": "LayoutMultiColumnSet (anonymous)",
           "rect": [8, 52, 525, 315],
           "reason": "style change"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [110, 52, 106, 315],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [110, 52, 106, 315],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 0, 103, 367],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 0, 103, 367],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [215, 52, 103, 315],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [215, 52, 103, 315],
-          "reason": "chunk uncacheable"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/multicol-with-block-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/multicol-with-block-expected.txt
index 8ee40c3..6a2db090 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/multicol-with-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/multicol-with-block-expected.txt
@@ -9,7 +9,7 @@
         {
           "object": "LayoutMultiColumnFlowThread (anonymous)",
           "rect": [488, 8, 80, 20],
-          "reason": "chunk uncacheable"
+          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
index 8d1148b..a94f6377 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
@@ -7,34 +7,19 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "LayoutBlockFlow DIV id='elm'",
           "rect": [8, 8, 792, 167],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 8, 792, 167],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "LayoutBlockFlow DIV id='elm'",
           "rect": [0, 341, 508, 167],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [0, 341, 508, 167],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "LayoutBlockFlow DIV id='elm'",
           "rect": [8, 174, 500, 168],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 174, 500, 168],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/access-control-basic-get-fail-non-simple-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/access-control-basic-get-fail-non-simple-expected.txt
index c6c9460f..2351d41 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/access-control-basic-get-fail-non-simple-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/access-control-basic-get-fail-non-simple-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: line 37: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-basic-get-fail-non-simple.cgi: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access. The response had HTTP status code 403.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-basic-get-fail-non-simple.cgi: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access. The response had HTTP status code 403.
 GET should not trigger a preflight request from a worker unless it has non-simple headers.
 
 PASS: Cross-domain access allowed for simple get.
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
index 8bd184cc..e4a0621 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
@@ -1,14 +1,14 @@
-CONSOLE ERROR: line 20: Failed to load ftp://127.0.0.1/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Failed to load ftp://127.0.0.1/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 CONSOLE ERROR: line 1: Failed to load ftp://127.0.0.1/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 20: Failed to load ftp://127.0.0.1/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Failed to load ftp://127.0.0.1/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 CONSOLE ERROR: line 1: Failed to load ftp://127.0.0.1/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 20: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 CONSOLE ERROR: line 1: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 20: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 CONSOLE ERROR: line 1: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 20: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 CONSOLE ERROR: line 1: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 20: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 CONSOLE ERROR: line 1: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 [Worker] Test cross-origin XHRs to CORS-unsupported protocol schemes in the URL.
 
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/column-rules-fixed-height-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/column-rules-fixed-height-expected.txt
index 65a415d..e6013b8 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/column-rules-fixed-height-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/column-rules-fixed-height-expected.txt
@@ -20,36 +20,6 @@
           "object": "LayoutMultiColumnSet (anonymous)",
           "rect": [8, 52, 525, 315],
           "reason": "style change"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [110, 52, 106, 315],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [110, 52, 106, 315],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 0, 103, 367],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 0, 103, 367],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [215, 52, 103, 315],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [215, 52, 103, 315],
-          "reason": "chunk uncacheable"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-as-paint-container-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-as-paint-container-expected.txt
index 41c298c..dde2d870 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-as-paint-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-as-paint-container-expected.txt
@@ -23,24 +23,89 @@
       "backfaceVisibility": "hidden",
       "paintInvalidations": [
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "InlineTextBox 'Lorem ipsum'",
           "rect": [0, 0, 315, 180],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "InlineTextBox 'adipiscing'",
           "rect": [0, 0, 315, 180],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [315, 0, 310, 180],
-          "reason": "chunk uncacheable"
+          "object": "InlineTextBox 'consectetur'",
+          "rect": [0, 0, 315, 180],
+          "reason": "style change"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "InlineTextBox 'dolor sit amet,'",
+          "rect": [0, 0, 315, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'elit. Fusce'",
+          "rect": [0, 0, 315, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'eu fringilla'",
+          "rect": [0, 0, 315, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'pulvinar, ipsum'",
+          "rect": [0, 0, 315, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'sapien'",
+          "rect": [0, 0, 315, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'varius, metus'",
+          "rect": [0, 0, 315, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'eget, dapibus'",
           "rect": [315, 0, 310, 180],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'libero,'",
+          "rect": [315, 0, 310, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'non condimentum'",
+          "rect": [315, 0, 310, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'purus. Ut nisl'",
+          "rect": [315, 0, 310, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'quam est eu'",
+          "rect": [315, 0, 310, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'suscipit ut leo'",
+          "rect": [315, 0, 310, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'ultrices dolor.'",
+          "rect": [315, 0, 310, 180],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'ultricies arcu,'",
+          "rect": [315, 0, 310, 180],
+          "reason": "style change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-repaint-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-repaint-expected.txt
index 0bf00546..3b1345e 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-repaint-expected.txt
@@ -17,24 +17,24 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "InlineTextBox 'XXXXXX'",
           "rect": [209, 15, 325, 150],
-          "reason": "chunk uncacheable"
+          "reason": "appeared"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "InlineTextBox '\u00A0'",
           "rect": [9, 0, 200, 67],
-          "reason": "chunk uncacheable"
+          "reason": "appeared"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "InlineTextBox '\u00A0'",
           "rect": [9, 0, 200, 67],
-          "reason": "chunk uncacheable"
+          "reason": "disappeared"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "InlineTextBox 'x'",
           "rect": [209, 15, 75, 150],
-          "reason": "chunk uncacheable"
+          "reason": "disappeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-block-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-block-expected.txt
index 94bda0eb..30b45e7 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-block-expected.txt
@@ -19,7 +19,7 @@
         {
           "object": "LayoutMultiColumnFlowThread (anonymous)",
           "rect": [488, 8, 80, 20],
-          "reason": "chunk uncacheable"
+          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-inline-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-inline-expected.txt
index ec78379f..f23a87c0 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-inline-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-inline-expected.txt
@@ -19,7 +19,7 @@
         {
           "object": "LayoutMultiColumnFlowThread (anonymous)",
           "rect": [483, 8, 85, 80],
-          "reason": "chunk uncacheable"
+          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
index ceb628e..64d1e71 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
@@ -17,34 +17,19 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "LayoutBlockFlow DIV id='elm'",
           "rect": [8, 8, 792, 167],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 8, 792, 167],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "LayoutBlockFlow DIV id='elm'",
           "rect": [0, 341, 508, 167],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [0, 341, 508, 167],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
+          "object": "LayoutBlockFlow DIV id='elm'",
           "rect": [8, 174, 500, 168],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 174, 500, 168],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-text-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-text-expected.txt
index 6a36296..a66af61 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-text-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/multicol/multicol-with-text-expected.txt
@@ -19,7 +19,7 @@
         {
           "object": "LayoutMultiColumnFlowThread (anonymous)",
           "rect": [483, 8, 85, 80],
-          "reason": "chunk uncacheable"
+          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/overflow/paged-with-overflowing-block-rl-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/overflow/paged-with-overflowing-block-rl-expected.txt
index 6d86ac9e..158cd21f 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/overflow/paged-with-overflowing-block-rl-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/overflow/paged-with-overflowing-block-rl-expected.txt
@@ -17,14 +17,9 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutPagedFlowThread (anonymous)",
+          "object": "LayoutBlockFlow DIV id='elm'",
           "rect": [8, 8, 500, 485],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutPagedFlowThread (anonymous)",
-          "rect": [8, 8, 500, 485],
-          "reason": "chunk uncacheable"
+          "reason": "style change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/table/single-line-cells-repeating-thead-break-inside-on-thead-only-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/table/single-line-cells-repeating-thead-break-inside-on-thead-only-expected.txt
index bcb97d6..eca01df 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/table/single-line-cells-repeating-thead-break-inside-on-thead-only-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/table/single-line-cells-repeating-thead-break-inside-on-thead-only-expected.txt
@@ -38,16 +38,6 @@
         },
         {
           "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 72, 259, 185],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [8, 72, 259, 185],
-          "reason": "chunk uncacheable"
-        },
-        {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
           "rect": [799, 72, 88, 185],
           "reason": "chunk uncacheable"
         },
@@ -57,14 +47,44 @@
           "reason": "chunk uncacheable"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [10, 74, 75, 180],
-          "reason": "chunk uncacheable"
+          "object": "LayoutTableRow TR",
+          "rect": [8, 233, 79, 24],
+          "reason": "appeared"
         },
         {
-          "object": "LayoutMultiColumnFlowThread (anonymous)",
-          "rect": [10, 74, 75, 180],
-          "reason": "chunk uncacheable"
+          "object": "LayoutTableRow TR",
+          "rect": [8, 210, 79, 24],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 187, 79, 24],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 164, 79, 24],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 141, 79, 24],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 118, 79, 24],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 95, 79, 24],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableRow TR",
+          "rect": [8, 72, 79, 24],
+          "reason": "full"
         },
         {
           "object": "LayoutMultiColumnFlowThread (anonymous)",
@@ -95,6 +115,166 @@
           "object": "LayoutMultiColumnFlowThread (anonymous)",
           "rect": [799, 74, 63, 65],
           "reason": "chunk uncacheable"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [47, 233, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [47, 210, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [47, 187, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [47, 164, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [47, 141, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [47, 118, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [47, 95, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TH",
+          "rect": [47, 72, 39, 23],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 233, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 210, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 187, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 164, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 141, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 118, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TD",
+          "rect": [8, 95, 39, 23],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCell TH id='target'",
+          "rect": [8, 72, 39, 23],
+          "reason": "full"
+        },
+        {
+          "object": "InlineTextBox 'Col 2'",
+          "rect": [49, 74, 36, 19],
+          "reason": "full"
+        },
+        {
+          "object": "InlineTextBox 'Col 1'",
+          "rect": [10, 74, 36, 19],
+          "reason": "style change"
+        },
+        {
+          "object": "InlineTextBox 'Te'",
+          "rect": [10, 235, 16, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'Te'",
+          "rect": [10, 212, 16, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'Te'",
+          "rect": [10, 189, 16, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'Te'",
+          "rect": [10, 166, 16, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'Te'",
+          "rect": [10, 143, 16, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'Te'",
+          "rect": [10, 120, 16, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'Te'",
+          "rect": [10, 97, 16, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'xt'",
+          "rect": [49, 235, 13, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'xt'",
+          "rect": [49, 212, 13, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'xt'",
+          "rect": [49, 189, 13, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'xt'",
+          "rect": [49, 166, 13, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'xt'",
+          "rect": [49, 143, 13, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'xt'",
+          "rect": [49, 120, 13, 19],
+          "reason": "appeared"
+        },
+        {
+          "object": "InlineTextBox 'xt'",
+          "rect": [49, 97, 13, 19],
+          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/pagination/pagination-change-clip-crash-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/pagination/pagination-change-clip-crash-expected.txt
new file mode 100644
index 0000000..1c9aa55
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/pagination/pagination-change-clip-crash-expected.txt
@@ -0,0 +1,55 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [785, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [785, 736],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "Scrolling Contents Layer",
+          "rect": [0, 636, 785, 100],
+          "reason": "incremental"
+        }
+      ]
+    },
+    {
+      "name": "LayoutBlockFlow DIV id='background'",
+      "bounds": [769, 300],
+      "drawsContent": false,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 428, 0, 1]
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "Scrolling Contents Layer",
+      "reason": "incremental"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='background'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/Source/core/DEPS b/third_party/WebKit/Source/core/DEPS
index 7caee088..7e05d30 100644
--- a/third_party/WebKit/Source/core/DEPS
+++ b/third_party/WebKit/Source/core/DEPS
@@ -1,7 +1,6 @@
 include_rules = [
     "+base/atomic_sequence_num.h",
     "+base/memory/scoped_refptr.h",
-    "+base/synchronization/waitable_event.h",
     "+base/unguessable_token.h",
     "+bindings/core",
     "-bindings/modules",
diff --git a/third_party/WebKit/Source/core/editing/SurroundingTextTest.cpp b/third_party/WebKit/Source/core/editing/SurroundingTextTest.cpp
index 918310b..53a2669 100644
--- a/third_party/WebKit/Source/core/editing/SurroundingTextTest.cpp
+++ b/third_party/WebKit/Source/core/editing/SurroundingTextTest.cpp
@@ -315,4 +315,146 @@
   EXPECT_TRUE(surrounding_text.Content().IsEmpty());
 }
 
+TEST_F(SurroundingTextTest, ButtonsAndParagraph) {
+  SetHTML(
+      String("<button>.</button>12345"
+             "<p id='selection'>6789 12345</p>"
+             "6789<button>.</button>"));
+
+  {
+    EphemeralRange selection = Select(0);
+    SurroundingText surrounding_text(selection, 100);
+
+    EXPECT_EQ("12345\n6789 12345\n\n6789", surrounding_text.Content());
+    EXPECT_EQ(6u, surrounding_text.StartOffsetInContent());
+    EXPECT_EQ(6u, surrounding_text.EndOffsetInContent());
+  }
+
+  {
+    EphemeralRange selection = Select(5);
+    SurroundingText surrounding_text(selection, 6);
+
+    EXPECT_EQ("89 123", surrounding_text.Content());
+    EXPECT_EQ(3u, surrounding_text.StartOffsetInContent());
+    EXPECT_EQ(3u, surrounding_text.EndOffsetInContent());
+  }
+
+  {
+    EphemeralRange selection = Select(0);
+    SurroundingText surrounding_text(selection, 0);
+
+    EXPECT_TRUE(surrounding_text.Content().IsEmpty());
+  }
+
+  {
+    EphemeralRange selection = Select(5);
+    SurroundingText surrounding_text(selection, 1);
+
+    EXPECT_EQ("1", surrounding_text.Content());
+    EXPECT_EQ(0u, surrounding_text.StartOffsetInContent());
+    EXPECT_EQ(0u, surrounding_text.EndOffsetInContent());
+  }
+
+  {
+    EphemeralRange selection = Select(6);
+    SurroundingText surrounding_text(selection, 2);
+
+    EXPECT_EQ("12", surrounding_text.Content());
+    EXPECT_EQ(1u, surrounding_text.StartOffsetInContent());
+    EXPECT_EQ(1u, surrounding_text.EndOffsetInContent());
+  }
+}
+
+TEST_F(SurroundingTextTest, SelectElementAndText) {
+  SetHTML(String(
+      "<select>.</select>"
+      "<div>57th Street and Lake Shore Drive</div>"
+      " <span>Chicago</span> <span id='selection'>IL</span> <span>60637</span>"
+      "<select>.</select>"));
+
+  EphemeralRange selection = Select(0);
+  SurroundingText surrounding_text(selection, 100);
+
+  EXPECT_STREQ(
+      "\xEF\xBF\xBC\n57th Street and Lake Shore Drive\nChicago IL 60637",
+      surrounding_text.Content().Utf8().data());
+  EXPECT_EQ(43u, surrounding_text.StartOffsetInContent());
+  EXPECT_EQ(43u, surrounding_text.EndOffsetInContent());
+}
+
+TEST_F(SurroundingTextTest, FieldsetElementAndText) {
+  SetHTML(
+      String("<fieldset>.</fieldset>12345<button>abc</button>"
+             "<p>6789<br><span id='selection'>12345</span></p>"
+             "6789<textarea>abc</textarea>0123<fieldset>.</fieldset>"));
+
+  EphemeralRange selection = Select(0);
+  SurroundingText surrounding_text(selection, 100);
+
+  EXPECT_EQ("\n6789\n12345\n\n6789", surrounding_text.Content());
+  EXPECT_EQ(6u, surrounding_text.StartOffsetInContent());
+  EXPECT_EQ(6u, surrounding_text.EndOffsetInContent());
+}
+
+TEST_F(SurroundingTextTest, ButtonScriptAndComment) {
+  SetHTML(
+      String("<button>.</button>"
+             "<div id='selection'>This is <!-- comment --!>a test "
+             "<script language='javascript'></script>"
+             "example<button>.</button>"));
+
+  EphemeralRange selection = Select(0);
+  SurroundingText surrounding_text(selection, 100);
+
+  EXPECT_EQ("\nThis is a test example", surrounding_text.Content());
+  EXPECT_EQ(1u, surrounding_text.StartOffsetInContent());
+  EXPECT_EQ(1u, surrounding_text.EndOffsetInContent());
+}
+
+TEST_F(SurroundingTextTest, ButtonAndLongDiv) {
+  SetHTML(
+      String("<button>.</button>"
+             "<div id='selection'>012345678901234567890123456789</div>"
+             "<button>.</button>"));
+
+  EphemeralRange selection = Select(15);
+  SurroundingText surrounding_text(selection, 12);
+
+  EXPECT_EQ("901234567890", surrounding_text.Content());
+  EXPECT_EQ(6u, surrounding_text.StartOffsetInContent());
+  EXPECT_EQ(6u, surrounding_text.EndOffsetInContent());
+}
+
+TEST_F(SurroundingTextTest, EmptySurroundingTextInOptionsAndButton) {
+  SetHTML(
+      String("<option>.</option>12345"
+             "<button id='selection'>test</button>"
+             "<option>.</option>"));
+
+  {
+    EphemeralRange selection = Select(1);
+    SurroundingText surrounding_text(selection, 100);
+
+    EXPECT_TRUE(surrounding_text.Content().IsEmpty());
+  }
+
+  {
+    EphemeralRange selection = Select(3);
+    SurroundingText surrounding_text(selection, 100);
+
+    EXPECT_TRUE(surrounding_text.Content().IsEmpty());
+  }
+}
+
+TEST_F(SurroundingTextTest, SingleDotParagraph) {
+  SetHTML(String("<p id='selection'>.</p>"));
+
+  EphemeralRange selection = Select(0);
+  SurroundingText surrounding_text(selection, 2);
+
+  EXPECT_EQ("\n.", surrounding_text.Content());
+  EXPECT_EQ(1u, surrounding_text.StartOffsetInContent());
+  EXPECT_EQ(1u, surrounding_text.EndOffsetInContent());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index dae516b..c36ed9b 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -87,7 +87,6 @@
 #include "core/loader/DocumentThreadableLoaderClient.h"
 #include "core/loader/FrameLoadRequest.h"
 #include "core/loader/ThreadableLoader.h"
-#include "core/loader/ThreadableLoadingContext.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "core/page/ScopedPagePauser.h"
@@ -9903,16 +9902,14 @@
   request.SetFetchRequestMode(network::mojom::FetchRequestMode::kCORS);
   ResourceLoaderOptions resource_loader_options;
   DocumentThreadableLoader::LoadResourceSynchronously(
-      *ThreadableLoadingContext::Create(*frame->GetDocument()), request, client,
-      options, resource_loader_options);
+      *frame->GetDocument(), request, client, options, resource_loader_options);
   EXPECT_TRUE(client.Failed());
 
   client.Reset();
   // Try to load the request with cross origin access. Should succeed.
   request.SetFetchRequestMode(network::mojom::FetchRequestMode::kNoCORS);
   DocumentThreadableLoader::LoadResourceSynchronously(
-      *ThreadableLoadingContext::Create(*frame->GetDocument()), request, client,
-      options, resource_loader_options);
+      *frame->GetDocument(), request, client, options, resource_loader_options);
   EXPECT_FALSE(client.Failed());
 }
 
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index 7cbd8b9..cfe3ffa 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -118,13 +118,14 @@
 static const int kMaxCORSRedirects = 20;
 
 void DocumentThreadableLoader::LoadResourceSynchronously(
-    ThreadableLoadingContext& loading_context,
+    Document& document,
     const ResourceRequest& request,
     ThreadableLoaderClient& client,
     const ThreadableLoaderOptions& options,
     const ResourceLoaderOptions& resource_loader_options) {
-  (new DocumentThreadableLoader(loading_context, &client, kLoadSynchronously,
-                                options, resource_loader_options))
+  (new DocumentThreadableLoader(*ThreadableLoadingContext::Create(document),
+                                &client, kLoadSynchronously, options,
+                                resource_loader_options))
       ->Start(request);
 }
 
@@ -1244,14 +1245,9 @@
     ResourceLoaderOptions resource_loader_options) {
   FetchParameters fetch_params(request, resource_loader_options);
   if (request.GetFetchRequestMode() ==
-      network::mojom::FetchRequestMode::kNoCORS) {
+      network::mojom::FetchRequestMode::kNoCORS)
     fetch_params.SetOriginRestriction(FetchParameters::kNoOriginRestriction);
-  }
-  if (options_.timeout_milliseconds > 0) {
-    fetch_params.MutableResourceRequest().SetTimeoutInterval(
-        options_.timeout_milliseconds / 1000.0);
-  }
-  RawResource* resource = RawResource::FetchSynchronously(
+  Resource* resource = RawResource::FetchSynchronously(
       fetch_params, loading_context_->GetResourceFetcher());
   ResourceResponse response =
       resource ? resource->GetResponse() : ResourceResponse();
@@ -1316,12 +1312,6 @@
   if (!client_)
     return;
 
-  WTF::Optional<int64_t> downloaded_file_length =
-      resource->DownloadedFileLength();
-  if (downloaded_file_length) {
-    client_->DidDownloadData(*downloaded_file_length);
-  }
-
   HandleSuccessfulFinish(identifier, 0.0);
 }
 
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
index 2903c5d4..958c3f5 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -61,7 +61,7 @@
   USING_GARBAGE_COLLECTED_MIXIN(DocumentThreadableLoader);
 
  public:
-  static void LoadResourceSynchronously(ThreadableLoadingContext&,
+  static void LoadResourceSynchronously(Document&,
                                         const ResourceRequest&,
                                         ThreadableLoaderClient&,
                                         const ThreadableLoaderOptions&,
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp
index b5296c33..2238f73 100644
--- a/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp
@@ -67,15 +67,14 @@
     const ThreadableLoaderOptions& options,
     const ResourceLoaderOptions& resource_loader_options) {
   if (context.IsWorkerGlobalScope()) {
-    DocumentThreadableLoader::LoadResourceSynchronously(
-        *ThreadableLoadingContext::Create(*ToWorkerGlobalScope(&context)),
-        request, client, options, resource_loader_options);
+    WorkerThreadableLoader::LoadResourceSynchronously(
+        ToWorkerGlobalScope(context), request, client, options,
+        resource_loader_options);
     return;
   }
 
   DocumentThreadableLoader::LoadResourceSynchronously(
-      *ThreadableLoadingContext::Create(*ToDocument(&context)), request, client,
-      options, resource_loader_options);
+      ToDocument(context), request, client, options, resource_loader_options);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
index c6c47033..336b0e7 100644
--- a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
@@ -234,9 +234,6 @@
  public:
   WebWorkerFetchContextForTest(KURL site_for_cookies)
       : site_for_cookies_(site_for_cookies.Copy()) {}
-
-  base::WaitableEvent* GetTerminateSyncLoadEvent() override { return nullptr; }
-
   void InitializeOnWorkerThread(
       scoped_refptr<base::SingleThreadTaskRunner>) override {}
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index 3d981339..a11e2174 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -23,6 +23,7 @@
 #include "platform/graphics/paint/DrawingRecorder.h"
 #include "platform/graphics/paint/GeometryMapper.h"
 #include "platform/graphics/paint/PaintChunkProperties.h"
+#include "platform/graphics/paint/ScopedDisplayItemFragment.h"
 #include "platform/graphics/paint/ScopedPaintChunkProperties.h"
 #include "platform/graphics/paint/SubsequenceRecorder.h"
 #include "platform/graphics/paint/Transform3DDisplayItem.h"
@@ -743,6 +744,18 @@
   }
 }
 
+static void ForAllFragments(
+    GraphicsContext& context,
+    const PaintLayerFragments& fragments,
+    const std::function<void(const PaintLayerFragment&)> function) {
+  for (size_t i = 0; i < fragments.size(); ++i) {
+    Optional<ScopedDisplayItemFragment> scoped_display_item_fragment;
+    if (i)
+      scoped_display_item_fragment.emplace(context, i);
+    function(fragments[i]);
+  }
+}
+
 PaintResult PaintLayerPainter::PaintLayerWithTransform(
     GraphicsContext& context,
     const PaintLayerPaintingInfo& painting_info,
@@ -801,27 +814,33 @@
       result = kMayBeClippedByPaintDirtyRect;
   }
 
+  // We have to skip cache for fragments under transform because we will paint
+  // all the fragments of sublayers in each fragment like the following:
+  //  fragment 0 { sub-layer fragment 0; sub-layer fragment 1 }
+  //  fragment 1 { sub-layer fragment 0; sub-layer fragment 1 }
   Optional<DisplayItemCacheSkipper> cache_skipper;
   if (layer_fragments.size() > 1)
     cache_skipper.emplace(context);
 
-  for (const auto& fragment : layer_fragments) {
-    Optional<LayerClipRecorder> clip_recorder;
-    if (parent_layer && !RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
-      if (NeedsToClip(painting_info, fragment.background_rect, paint_flags,
-                      paint_layer_.GetLayoutObject())) {
-        clip_recorder.emplace(
-            context, *parent_layer, DisplayItem::kClipLayerParent,
-            fragment.background_rect, painting_info.root_layer,
-            fragment.pagination_offset, paint_flags,
-            paint_layer_.GetLayoutObject());
-      }
-    }
-    if (PaintFragmentByApplyingTransform(context, painting_info, paint_flags,
-                                         fragment) ==
-        kMayBeClippedByPaintDirtyRect)
-      result = kMayBeClippedByPaintDirtyRect;
-  }
+  ForAllFragments(
+      context, layer_fragments, [&](const PaintLayerFragment& fragment) {
+        Optional<LayerClipRecorder> clip_recorder;
+        if (parent_layer &&
+            !RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+          if (NeedsToClip(painting_info, fragment.background_rect, paint_flags,
+                          paint_layer_.GetLayoutObject())) {
+            clip_recorder.emplace(
+                context, *parent_layer, DisplayItem::kClipLayerParent,
+                fragment.background_rect, painting_info.root_layer,
+                fragment.pagination_offset, paint_flags,
+                paint_layer_.GetLayoutObject());
+          }
+        }
+        if (PaintFragmentByApplyingTransform(context, painting_info,
+                                             paint_flags, fragment) ==
+            kMayBeClippedByPaintDirtyRect)
+          result = kMayBeClippedByPaintDirtyRect;
+      });
   return result;
 }
 
@@ -944,52 +963,51 @@
   if (!scrollable_area)
     return;
 
-  Optional<DisplayItemCacheSkipper> cache_skipper;
-  if (layer_fragments.size() > 1)
-    cache_skipper.emplace(context);
+  ForAllFragments(
+      context, layer_fragments, [&](const PaintLayerFragment& fragment) {
+        Optional<ScopedPaintChunkProperties> fragment_paint_chunk_properties;
+        if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+          PaintChunkProperties properties(
+              *fragment.fragment_data->LocalBorderBoxProperties());
+          properties.backface_hidden =
+              paint_layer_.GetLayoutObject().HasHiddenBackface();
+          fragment_paint_chunk_properties.emplace(
+              context.GetPaintController(), properties, paint_layer_,
+              DisplayItem::kScrollOverflowControls);
+        }
 
-  for (auto& fragment : layer_fragments) {
-    Optional<ScopedPaintChunkProperties> fragment_paint_chunk_properties;
-    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
-      PaintChunkProperties properties(
-          *fragment.fragment_data->LocalBorderBoxProperties());
-      properties.backface_hidden =
-          paint_layer_.GetLayoutObject().HasHiddenBackface();
-      fragment_paint_chunk_properties.emplace(
-          context.GetPaintController(), properties, paint_layer_,
-          DisplayItem::kScrollOverflowControls);
-    }
+        // We need to apply the same clips and transforms that
+        // paintFragmentWithPhase would have.
+        LayoutRect cull_rect = fragment.background_rect.Rect();
 
-    // We need to apply the same clips and transforms that
-    // paintFragmentWithPhase would have.
-    LayoutRect cull_rect = fragment.background_rect.Rect();
+        Optional<LayerClipRecorder> clip_recorder;
+        if (NeedsToClip(local_painting_info, fragment.background_rect,
+                        paint_flags, paint_layer_.GetLayoutObject())) {
+          clip_recorder.emplace(
+              context, paint_layer_, DisplayItem::kClipLayerOverflowControls,
+              fragment.background_rect, local_painting_info.root_layer,
+              fragment.pagination_offset, paint_flags,
+              paint_layer_.GetLayoutObject());
+        }
 
-    Optional<LayerClipRecorder> clip_recorder;
-    if (NeedsToClip(local_painting_info, fragment.background_rect, paint_flags,
-                    paint_layer_.GetLayoutObject())) {
-      clip_recorder.emplace(
-          context, paint_layer_, DisplayItem::kClipLayerOverflowControls,
-          fragment.background_rect, local_painting_info.root_layer,
-          fragment.pagination_offset, paint_flags,
-          paint_layer_.GetLayoutObject());
-    }
+        Optional<ScrollRecorder> scroll_recorder;
+        if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+            !local_painting_info.scroll_offset_accumulation.IsZero()) {
+          cull_rect.Move(local_painting_info.scroll_offset_accumulation);
+          scroll_recorder.emplace(
+              context, paint_layer_.GetLayoutObject(),
+              DisplayItem::kScrollOverflowControls,
+              local_painting_info.scroll_offset_accumulation);
+        }
 
-    Optional<ScrollRecorder> scroll_recorder;
-    if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
-        !local_painting_info.scroll_offset_accumulation.IsZero()) {
-      cull_rect.Move(local_painting_info.scroll_offset_accumulation);
-      scroll_recorder.emplace(context, paint_layer_.GetLayoutObject(),
-                              DisplayItem::kScrollOverflowControls,
-                              local_painting_info.scroll_offset_accumulation);
-    }
-
-    // We pass IntPoint() as the paint offset here, because
-    // ScrollableArea::paintOverflowControls just ignores it and uses the
-    // offset found in a previous pass.
-    CullRect snapped_cull_rect(PixelSnappedIntRect(cull_rect));
-    ScrollableAreaPainter(*scrollable_area)
-        .PaintOverflowControls(context, IntPoint(), snapped_cull_rect, true);
-  }
+        // We pass IntPoint() as the paint offset here, because
+        // ScrollableArea::paintOverflowControls just ignores it and uses the
+        // offset found in a previous pass.
+        CullRect snapped_cull_rect(PixelSnappedIntRect(cull_rect));
+        ScrollableAreaPainter(*scrollable_area)
+            .PaintOverflowControls(context, IntPoint(), snapped_cull_rect,
+                                   true);
+      });
 }
 
 void PaintLayerPainter::PaintFragmentWithPhase(
@@ -1108,14 +1126,13 @@
     GraphicsContext& context,
     const PaintLayerPaintingInfo& local_painting_info,
     PaintLayerFlags paint_flags) {
-  Optional<DisplayItemCacheSkipper> cache_skipper;
-  if (layer_fragments.size() > 1)
-    cache_skipper.emplace(context);
-
-  for (auto& fragment : layer_fragments)
-    PaintFragmentWithPhase(PaintPhase::kSelfBlockBackgroundOnly, fragment,
-                           context, fragment.background_rect,
-                           local_painting_info, paint_flags, kHasNotClipped);
+  ForAllFragments(
+      context, layer_fragments, [&](const PaintLayerFragment& fragment) {
+        PaintFragmentWithPhase(PaintPhase::kSelfBlockBackgroundOnly, fragment,
+                               context, fragment.background_rect,
+                               local_painting_info, paint_flags,
+                               kHasNotClipped);
+      });
 }
 
 void PaintLayerPainter::PaintForegroundForFragments(
@@ -1211,15 +1228,14 @@
     const PaintLayerPaintingInfo& local_painting_info,
     PaintLayerFlags paint_flags,
     ClipState clip_state) {
-  Optional<DisplayItemCacheSkipper> cache_skipper;
-  if (layer_fragments.size() > 1)
-    cache_skipper.emplace(context);
-
-  for (auto& fragment : layer_fragments) {
-    if (!fragment.foreground_rect.IsEmpty())
-      PaintFragmentWithPhase(phase, fragment, context, fragment.foreground_rect,
-                             local_painting_info, paint_flags, clip_state);
-  }
+  ForAllFragments(
+      context, layer_fragments, [&](const PaintLayerFragment& fragment) {
+        if (!fragment.foreground_rect.IsEmpty()) {
+          PaintFragmentWithPhase(phase, fragment, context,
+                                 fragment.foreground_rect, local_painting_info,
+                                 paint_flags, clip_state);
+        }
+      });
 }
 
 void PaintLayerPainter::PaintSelfOutlineForFragments(
@@ -1227,16 +1243,15 @@
     GraphicsContext& context,
     const PaintLayerPaintingInfo& local_painting_info,
     PaintLayerFlags paint_flags) {
-  Optional<DisplayItemCacheSkipper> cache_skipper;
-  if (layer_fragments.size() > 1)
-    cache_skipper.emplace(context);
-
-  for (auto& fragment : layer_fragments) {
-    if (!fragment.background_rect.IsEmpty())
-      PaintFragmentWithPhase(PaintPhase::kSelfOutlineOnly, fragment, context,
-                             fragment.background_rect, local_painting_info,
-                             paint_flags, kHasNotClipped);
-  }
+  ForAllFragments(
+      context, layer_fragments, [&](const PaintLayerFragment& fragment) {
+        if (!fragment.background_rect.IsEmpty()) {
+          PaintFragmentWithPhase(PaintPhase::kSelfOutlineOnly, fragment,
+                                 context, fragment.background_rect,
+                                 local_painting_info, paint_flags,
+                                 kHasNotClipped);
+        }
+      });
 }
 
 void PaintLayerPainter::PaintMaskForFragments(
@@ -1244,15 +1259,12 @@
     GraphicsContext& context,
     const PaintLayerPaintingInfo& local_painting_info,
     PaintLayerFlags paint_flags) {
-  Optional<DisplayItemCacheSkipper> cache_skipper;
-  if (layer_fragments.size() > 1)
-    cache_skipper.emplace(context);
-
-  for (auto& fragment : layer_fragments) {
-    PaintFragmentWithPhase(PaintPhase::kMask, fragment, context,
-                           fragment.background_rect, local_painting_info,
-                           paint_flags, kHasNotClipped);
-  }
+  ForAllFragments(
+      context, layer_fragments, [&](const PaintLayerFragment& fragment) {
+        PaintFragmentWithPhase(PaintPhase::kMask, fragment, context,
+                               fragment.background_rect, local_painting_info,
+                               paint_flags, kHasNotClipped);
+      });
 }
 
 void PaintLayerPainter::PaintAncestorClippingMask(
@@ -1287,33 +1299,32 @@
     GraphicsContext& context,
     const PaintLayerPaintingInfo& local_painting_info,
     PaintLayerFlags paint_flags) {
-  Optional<DisplayItemCacheSkipper> cache_skipper;
-  if (layer_fragments.size() > 1)
-    cache_skipper.emplace(context);
-
   if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     const DisplayItemClient& client =
         *paint_layer_.GetCompositedLayerMapping()->ChildClippingMaskLayer();
-    for (auto& fragment : layer_fragments) {
-      auto state = fragment.fragment_data->ContentsProperties();
-      // This is a hack to incorporate mask-based clip-path.
-      // See CompositingLayerPropertyUpdater.cpp about ChildClippingMaskLayer.
-      state.SetEffect(fragment.fragment_data->PreFilter());
-      ScopedPaintChunkProperties fragment_paint_chunk_properties(
-          context.GetPaintController(), state, client,
-          DisplayItem::PaintPhaseToDrawingType(PaintPhase::kClippingMask));
-      ClipRect mask_rect = fragment.background_rect;
-      mask_rect.MoveBy(fragment.fragment_data->PaintOffset());
-      FillMaskingFragment(context, mask_rect, client);
-    }
+    ForAllFragments(
+        context, layer_fragments, [&](const PaintLayerFragment& fragment) {
+          auto state = fragment.fragment_data->ContentsProperties();
+          // This is a hack to incorporate mask-based clip-path.
+          // See CompositingLayerPropertyUpdater.cpp about
+          // ChildClippingMaskLayer.
+          state.SetEffect(fragment.fragment_data->PreFilter());
+          ScopedPaintChunkProperties fragment_paint_chunk_properties(
+              context.GetPaintController(), state, client,
+              DisplayItem::PaintPhaseToDrawingType(PaintPhase::kClippingMask));
+          ClipRect mask_rect = fragment.background_rect;
+          mask_rect.MoveBy(fragment.fragment_data->PaintOffset());
+          FillMaskingFragment(context, mask_rect, client);
+        });
     return;
   }
 
-  for (auto& fragment : layer_fragments) {
-    PaintFragmentWithPhase(PaintPhase::kClippingMask, fragment, context,
-                           fragment.foreground_rect, local_painting_info,
-                           paint_flags, kHasNotClipped);
-  }
+  ForAllFragments(
+      context, layer_fragments, [&](const PaintLayerFragment& fragment) {
+        PaintFragmentWithPhase(PaintPhase::kClippingMask, fragment, context,
+                               fragment.foreground_rect, local_painting_info,
+                               paint_flags, kHasNotClipped);
+      });
 }
 
 void PaintLayerPainter::PaintOverlayScrollbars(
diff --git a/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp b/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp
index 11bb6a7..376ecfc 100644
--- a/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp
@@ -17,6 +17,7 @@
 #include "core/paint/PaintInfo.h"
 #include "core/paint/TableCellPainter.h"
 #include "core/paint/TableRowPainter.h"
+#include "platform/graphics/paint/DisplayItemCacheSkipper.h"
 #include "platform/graphics/paint/DrawingRecorder.h"
 
 namespace blink {
@@ -34,6 +35,11 @@
   if (!table->IsPageLogicalHeightKnown())
     return;
 
+  // We may paint the header multiple times so can't uniquely identify each
+  // display item.
+  // TODO(wangxianzhu): Create multiple FragmentData for repeating headers.
+  DisplayItemCacheSkipper cache_skipper(paint_info.context);
+
   LayoutPoint pagination_offset = paint_offset;
   LayoutUnit page_height = table->PageLogicalHeightForOffset(LayoutUnit());
 
@@ -97,6 +103,11 @@
   if (!table->IsPageLogicalHeightKnown())
     return;
 
+  // We may paint the footer multiple times so can't uniquely identify each
+  // display item.
+  // TODO(wangxianzhu): Create multiple FragmentData for repeating footers.
+  DisplayItemCacheSkipper cache_skipper(paint_info.context);
+
   LayoutRect sections_rect(LayoutPoint(), table->Size());
   table->SubtractCaptionRect(sections_rect);
   LayoutUnit page_height = table->PageLogicalHeightForOffset(LayoutUnit());
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index d5abfd5..e14ba37f 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -63,7 +63,6 @@
 #include "core/editing/FrameSelection.h"
 #include "core/editing/PlainTextRange.h"
 #include "core/editing/SelectionTemplate.h"
-#include "core/editing/SurroundingText.h"
 #include "core/editing/VisiblePosition.h"
 #include "core/editing/iterators/TextIterator.h"
 #include "core/editing/markers/DocumentMarker.h"
@@ -3194,31 +3193,6 @@
   element->SetValueForUser(value);
 }
 
-String Internals::textSurroundingNode(Node* node,
-                                      int x,
-                                      int y,
-                                      unsigned long max_length) {
-  if (!node)
-    return String();
-
-  // VisiblePosition and SurroundingText must be created with clean layout.
-  node->GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
-  DocumentLifecycle::DisallowTransitionScope disallow_transition(
-      node->GetDocument().Lifecycle());
-
-  if (!node->GetLayoutObject())
-    return String();
-  blink::WebPoint point(x, y);
-  SurroundingText surrounding_text(
-      EphemeralRange(
-          CreateVisiblePosition(node->GetLayoutObject()->PositionForPoint(
-                                    static_cast<IntPoint>(point)))
-              .DeepEquivalent()
-              .ParentAnchoredEquivalent()),
-      max_length);
-  return surrounding_text.Content();
-}
-
 void Internals::setFocused(bool focused) {
   if (!GetFrame())
     return;
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h
index 1163b65..42c14150 100644
--- a/third_party/WebKit/Source/core/testing/Internals.h
+++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -495,8 +495,6 @@
 
   void setValueForUser(HTMLInputElement*, const String&);
 
-  String textSurroundingNode(Node*, int x, int y, unsigned long max_length);
-
   void setFocused(bool);
   void setInitialFocus(bool);
 
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index 460cc88b..80d2d77 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -321,8 +321,6 @@
 
     void setValueForUser(HTMLInputElement element, DOMString value);
 
-    DOMString textSurroundingNode(Node node, long x, long y, unsigned long maxLength);
-
     void setFocused(boolean focused);
     void setInitialFocus(boolean reverse);
 
diff --git a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.cpp b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.cpp
index 072059a..a6ed380 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.cpp
@@ -4,7 +4,6 @@
 
 #include "core/workers/ThreadedMessagingProxyBase.h"
 
-#include "base/synchronization/waitable_event.h"
 #include "bindings/core/v8/SourceLocation.h"
 #include "core/dom/Document.h"
 #include "core/frame/Deprecation.h"
@@ -49,8 +48,6 @@
     std::unique_ptr<WebWorkerFetchContext> web_worker_fetch_context =
         web_frame->Client()->CreateWorkerFetchContext();
     DCHECK(web_worker_fetch_context);
-    terminate_sync_load_event_ =
-        web_worker_fetch_context->GetTerminateSyncLoadEvent();
     web_worker_fetch_context->SetApplicationCacheHostID(
         document->Fetcher()->Context().ApplicationCacheHostID());
     web_worker_fetch_context->SetIsOnSubframe(
@@ -149,11 +146,6 @@
     return;
   asked_to_terminate_ = true;
 
-  if (terminate_sync_load_event_) {
-    terminate_sync_load_event_->Signal();
-    terminate_sync_load_event_ = nullptr;
-  }
-
   if (worker_thread_)
     worker_thread_->Terminate();
 
diff --git a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h
index 5870f670..68526c2 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h
+++ b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h
@@ -16,12 +16,6 @@
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/Optional.h"
 
-namespace base {
-
-class WaitableEvent;
-
-}  // namespace base
-
 namespace blink {
 
 class ExecutionContext;
@@ -109,8 +103,6 @@
 
   bool asked_to_terminate_;
 
-  base::WaitableEvent* terminate_sync_load_event_ = nullptr;
-
   // Used to keep this alive until the worker thread gets terminated. This is
   // necessary because the co-owner (i.e., Worker or Worklet object) can be
   // destroyed before thread termination.
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 8f42a446..644edb04 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1203,6 +1203,7 @@
     "graphics/paint/PropertyTreeState.h",
     "graphics/paint/RasterInvalidationTracking.cpp",
     "graphics/paint/RasterInvalidationTracking.h",
+    "graphics/paint/ScopedDisplayItemFragment.h",
     "graphics/paint/ScopedPaintChunkProperties.h",
     "graphics/paint/ScrollDisplayItem.cpp",
     "graphics/paint/ScrollDisplayItem.h",
diff --git a/third_party/WebKit/Source/platform/WaitableEvent.h b/third_party/WebKit/Source/platform/WaitableEvent.h
index 24d94f23..6fe0550 100644
--- a/third_party/WebKit/Source/platform/WaitableEvent.h
+++ b/third_party/WebKit/Source/platform/WaitableEvent.h
@@ -41,9 +41,6 @@
 
 namespace blink {
 
-// TODO(crbug.com/796799): Deprecate blink::WaitableEvent and use
-// base::WaitableEvent instead.
-//
 // Provides a thread synchronization that can be used to allow one thread to
 // wait until another thread to finish some work.
 class PLATFORM_EXPORT WaitableEvent {
diff --git a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
index 5861585f..0e2d50a 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
@@ -145,10 +145,6 @@
   resource_request_->SetCacheMode(cache_mode);
 }
 
-double WebURLRequest::TimeoutInterval() const {
-  return resource_request_->TimeoutInterval();
-}
-
 WebString WebURLRequest::HttpMethod() const {
   return resource_request_->HttpMethod();
 }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
index a06fcb1..bb4ac0d9 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
@@ -227,15 +227,24 @@
   if (IsTombstone())
     json.SetBoolean("ISTOMBSTONE", true);
 
-  json.SetString("client", String::Format("%p", &Client()));
+  json.SetString("id", GetId().ToString());
   json.SetString("visualRect", VisualRect().ToString());
   if (OutsetForRasterEffects())
     json.SetDouble("outset", OutsetForRasterEffects().ToDouble());
-  json.SetString("type", TypeAsDebugString(GetType()));
   if (skipped_cache_)
     json.SetBoolean("skippedCache", true);
 }
 
 #endif
 
+String DisplayItem::Id::ToString() const {
+#if DCHECK_IS_ON()
+  return String::Format("%p:%s:%d", &client,
+                        DisplayItem::TypeAsDebugString(type).Ascii().data(),
+                        fragment);
+#else
+  return String::Format("%p:%d:%d", &client, static_cast<int>(type), fragment);
+#endif
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
index 9b6894d..abd3c22 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
@@ -186,10 +186,11 @@
         outset_for_raster_effects_(client.VisualRectOutsetForRasterEffects()),
         type_(type),
         derived_size_(derived_size),
+        fragment_(0),
         skipped_cache_(false),
         is_tombstone_(false) {
-    // derivedSize must fit in m_derivedSize.
-    // If it doesn't, enlarge m_derivedSize and fix this assert.
+    // |derived_size| must fit in |derived_size_|.
+    // If it doesn't, enlarge |derived_size_| and fix this assert.
     SECURITY_DCHECK(derived_size < (1 << 8));
     SECURITY_DCHECK(derived_size >= sizeof(*this));
   }
@@ -199,14 +200,19 @@
   // Ids are for matching new DisplayItems with existing DisplayItems.
   struct Id {
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-    Id(const DisplayItemClient& client, const Type type)
-        : client(client), type(type) {}
+    Id(const DisplayItemClient& client, const Type type, unsigned fragment = 0)
+        : client(client), type(type), fragment(fragment) {}
+    Id(const Id& id, unsigned fragment)
+        : client(id.client), type(id.type), fragment(fragment) {}
+
+    String ToString() const;
 
     const DisplayItemClient& client;
     const Type type;
+    const unsigned fragment;
   };
 
-  Id GetId() const { return Id(*client_, GetType()); }
+  Id GetId() const { return Id(*client_, GetType(), fragment_); }
 
   virtual void Replay(GraphicsContext&) const {}
 
@@ -237,6 +243,14 @@
   // supply this to the DisplayItem constructor.
   size_t DerivedSize() const { return derived_size_; }
 
+  // The fragment is part of the id, to uniquely identify display items in
+  // different fragments for the same client and type.
+  unsigned Fragment() const { return fragment_; }
+  void SetFragment(unsigned fragment) {
+    DCHECK(fragment < (1 << 14));
+    fragment_ = fragment;
+  }
+
   // For PaintController only. Painters should use DisplayItemCacheSkipper
   // instead.
   void SetSkippedCache() { skipped_cache_ = true; }
@@ -329,6 +343,7 @@
     // Failure of this DCHECK would cause bad casts in subclasses.
     SECURITY_CHECK(!is_tombstone_);
     return client_ == other.client_ && type_ == other.type_ &&
+           fragment_ == other.fragment_ &&
            derived_size_ == other.derived_size_ &&
            skipped_cache_ == other.skipped_cache_;
   }
@@ -363,16 +378,16 @@
   LayoutRect visual_rect_;
   LayoutUnit outset_for_raster_effects_;
 
-  static_assert(kTypeLast < (1 << 16),
-                "DisplayItem::Type should fit in 16 bits");
-  unsigned type_ : 16;
+  static_assert(kTypeLast < (1 << 8), "DisplayItem::Type should fit in 8 bits");
+  unsigned type_ : 8;
   unsigned derived_size_ : 8;  // size of the actual derived class
+  unsigned fragment_ : 14;
   unsigned skipped_cache_ : 1;
   unsigned is_tombstone_ : 1;
 };
 
 inline bool operator==(const DisplayItem::Id& a, const DisplayItem::Id& b) {
-  return a.client == b.client && a.type == b.type;
+  return a.client == b.client && a.type == b.type && a.fragment == b.fragment;
 }
 
 inline bool operator!=(const DisplayItem::Id& a, const DisplayItem::Id& b) {
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintChunk.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintChunk.cpp
index 0b7b8da..7ab7ec9 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintChunk.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintChunk.cpp
@@ -10,23 +10,11 @@
 
 String PaintChunk::ToString() const {
   return String::Format(
-      "begin=%zu, end=%zu, id=%p:"
-#if DCHECK_IS_ON()
-      "%s "
-#else
-      "%d "
-#endif
-      "cacheable=%d props=(%s) bounds=%s known_to_be_opaque=%d "
-      "raster_invalidation_rects=%zu",
-      begin_index, end_index, &id.client,
-#if DCHECK_IS_ON()
-      DisplayItem::TypeAsDebugString(id.type).Ascii().data(),
-#else
-      static_cast<int>(id.type),
-#endif
-      is_cacheable, properties.ToString().Ascii().data(),
-      bounds.ToString().Ascii().data(), known_to_be_opaque,
-      raster_invalidation_rects.size());
+      "begin=%zu, end=%zu, id=%s cacheable=%d props=(%s) bounds=%s "
+      "known_to_be_opaque=%d raster_invalidation_rects=%zu",
+      begin_index, end_index, id.ToString().Ascii().data(), is_cacheable,
+      properties.ToString().Ascii().data(), bounds.ToString().Ascii().data(),
+      known_to_be_opaque, raster_invalidation_rects.size());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
index 57f7b7ae..2d737df7 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -68,9 +68,10 @@
     return false;
   }
 
-  size_t cached_item = FindCachedItem(DisplayItem::Id(client, type));
+  size_t cached_item =
+      FindCachedItem(DisplayItem::Id(client, type, current_fragment_));
   if (cached_item == kNotFound) {
-    NOTREACHED();
+    // See FindOutOfOrderCachedItemForward() for explanation of the situation.
     return false;
   }
 
@@ -299,19 +300,20 @@
       DCHECK(!display_item.IsEndAndPairedWith(begin_display_item.GetType()));
   }
 
-  size_t index = FindMatchingItemFromIndex(display_item.GetId(),
-                                           new_display_item_indices_by_client_,
-                                           new_display_item_list_);
-  if (index != kNotFound) {
-    ShowDebugData();
-    DLOG(INFO) << "DisplayItem " << display_item.AsDebugString()
-               << " has duplicated id with previous "
-               << new_display_item_list_[index].AsDebugString()
-               << " (index=" << index << ")";
-    NOTREACHED();
+  if (display_item.IsCacheable()) {
+    size_t index = FindMatchingItemFromIndex(
+        display_item.GetId(), new_display_item_indices_by_client_,
+        new_display_item_list_);
+    if (index != kNotFound) {
+      ShowDebugData();
+      NOTREACHED() << "DisplayItem " << display_item.AsDebugString()
+                   << " has duplicated id with previous "
+                   << new_display_item_list_[index].AsDebugString()
+                   << " (index=" << index << ")";
+    }
+    AddItemToIndexIfNeeded(display_item, new_display_item_list_.size() - 1,
+                           new_display_item_indices_by_client_);
   }
-  AddItemToIndexIfNeeded(display_item, new_display_item_list_.size() - 1,
-                         new_display_item_indices_by_client_);
 #endif  // DCHECK_IS_ON()
 
   if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled())
@@ -468,17 +470,19 @@
 
 #if DCHECK_IS_ON()
   ShowDebugData();
-  LOG(ERROR) << id.client.DebugName() << ":"
-             << DisplayItem::TypeAsDebugString(id.type);
+  LOG(ERROR) << id.client.DebugName() << " " << id.ToString();
 #endif
 
-  if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled())
-    CHECK(false) << "Can't find cached display item";
-
-  // We did not find the cached display item. This should be impossible, but may
-  // occur if there is a bug in the system, such as under-invalidation,
-  // incorrect cache checking or duplicate display ids. In this case, the caller
+  // The display item newly appears while the client is not invalidated. The
+  // situation alone (without other kinds of under-invalidations) won't corrupt
+  // rendering, but causes AddItemToIndexIfNeeded() for all remaining display
+  // item, which is not the best for performance. In this case, the caller
   // should fall back to repaint the display item.
+  if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) {
+    // Ensure our paint invalidation tests don't trigger the less performant
+    // situation which should be rare.
+    CHECK(false) << "Can't find cached display item";
+  }
   return kNotFound;
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
index 79a8f70f..10495494 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
@@ -76,7 +76,13 @@
   void UpdateCurrentPaintChunkProperties(
       const Optional<PaintChunk::Id>& id,
       const PaintChunkProperties& properties) {
-    new_paint_chunks_.UpdateCurrentPaintChunkProperties(id, properties);
+    if (id) {
+      new_paint_chunks_.UpdateCurrentPaintChunkProperties(
+          PaintChunk::Id(*id, current_fragment_), properties);
+    } else {
+      new_paint_chunks_.UpdateCurrentPaintChunkProperties(WTF::nullopt,
+                                                          properties);
+    }
   }
 
   const PaintChunkProperties& CurrentPaintChunkProperties() const {
@@ -98,6 +104,7 @@
     DisplayItemClass& display_item =
         new_display_item_list_.AllocateAndConstruct<DisplayItemClass>(
             std::forward<Args>(args)...);
+    display_item.SetFragment(current_fragment_);
     ProcessNewItem(display_item);
   }
 
@@ -203,6 +210,12 @@
   void BeginFrame(const void* frame);
   FrameFirstPaint EndFrame(const void* frame);
 
+  // The current fragment will be part of the ids of all display items and
+  // paint chunks, to uniquely identify display items in different fragments
+  // for the same client and type.
+  unsigned CurrentFragment() const { return current_fragment_; }
+  void SetCurrentFragment(unsigned fragment) { current_fragment_ = fragment; }
+
  protected:
   PaintController()
       : new_display_item_list_(0),
@@ -218,7 +231,8 @@
 #endif
         under_invalidation_checking_begin_(0),
         under_invalidation_checking_end_(0),
-        last_cached_subsequence_end_(0) {
+        last_cached_subsequence_end_(0),
+        current_fragment_(0) {
     ResetCurrentListIndices();
     // frame_first_paints_ should have one null frame since the beginning, so
     // that PaintController is robust even if it paints outside of BeginFrame
@@ -425,6 +439,8 @@
   CachedSubsequenceMap new_cached_subsequences_;
   size_t last_cached_subsequence_end_;
 
+  unsigned current_fragment_;
+
   class DisplayItemListAsJSON;
 };
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerDebugData.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerDebugData.cpp
index 4163e64..cbcd254 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerDebugData.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerDebugData.cpp
@@ -74,7 +74,9 @@
 
   auto json_object = JSONObject::Create();
 
-  json_object->SetString("subsequence", ClientName(*subsequence.client));
+  json_object->SetString("subsequence",
+                         String::Format("client: %p ", subsequence.client) +
+                             ClientName(*subsequence.client));
   json_object->SetArray(
       RuntimeEnabledFeatures::SlimmingPaintV175Enabled() ? "chunks"
                                                          : "displayItems",
@@ -127,12 +129,10 @@
     const auto& chunk = *current_chunk_;
     auto json_object = JSONObject::Create();
 
-    String chunk_name = ClientName(chunk.id.client);
-    if (chunk.id.type != DisplayItem::kUninitializedType) {
-      chunk_name.append(" type: ");
-      chunk_name.append(DisplayItem::TypeAsDebugString(chunk.id.type));
-    }
-    json_object->SetString("chunk", chunk_name);
+    json_object->SetString(
+        "chunk", ClientName(chunk.id.client) + " " + chunk.id.ToString());
+    if (flags_ & DisplayItemList::kShowPaintRecords)
+      json_object->SetString("chunkData", chunk.ToString());
 
     json_object->SetArray(
         "displayItems",
@@ -145,9 +145,8 @@
 
 String PaintController::DisplayItemListAsJSON::ClientName(
     const DisplayItemClient& client) const {
-  return String::Format("client: %p ", &client) +
-         DisplayItemClient::SafeDebugName(
-             client, flags_ & DisplayItemList::kClientKnownToBeAlive);
+  return DisplayItemClient::SafeDebugName(
+      client, flags_ & DisplayItemList::kClientKnownToBeAlive);
 }
 
 void PaintController::ShowDebugDataInternal(
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScopedDisplayItemFragment.h b/third_party/WebKit/Source/platform/graphics/paint/ScopedDisplayItemFragment.h
new file mode 100644
index 0000000..dd79261
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScopedDisplayItemFragment.h
@@ -0,0 +1,36 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ScopedDisplayItemFragment_h
+#define ScopedDisplayItemFragment_h
+
+#include "platform/graphics/GraphicsContext.h"
+#include "platform/graphics/paint/PaintController.h"
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Noncopyable.h"
+
+namespace blink {
+
+class ScopedDisplayItemFragment final {
+  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
+  WTF_MAKE_NONCOPYABLE(ScopedDisplayItemFragment);
+
+ public:
+  ScopedDisplayItemFragment(GraphicsContext& context, unsigned fragment)
+      : context_(context),
+        original_fragment_(context.GetPaintController().CurrentFragment()) {
+    context.GetPaintController().SetCurrentFragment(fragment);
+  }
+  ~ScopedDisplayItemFragment() {
+    context_.GetPaintController().SetCurrentFragment(original_fragment_);
+  }
+
+ private:
+  GraphicsContext& context_;
+  unsigned original_fragment_;
+};
+
+}  // namespace blink
+
+#endif  // ScopedDisplayItemFragment_h
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp b/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp
index c9e3ef21..5ec729e4 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp
@@ -122,9 +122,7 @@
   // Synchronous requests should always be max priority, lest they hang the
   // renderer.
   resource_request_.SetPriority(ResourceLoadPriority::kHighest);
-  if (resource_request_.TimeoutInterval() == INT_MAX) {
-    resource_request_.SetTimeoutInterval(10);
-  }
+  resource_request_.SetTimeoutInterval(10);
   options_.synchronous_policy = kRequestSynchronously;
 }
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
index 62bf707..3d636fc 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
@@ -231,8 +231,6 @@
 }
 
 void RawResource::DidDownloadData(int data_length) {
-  downloaded_file_length_ =
-      (downloaded_file_length_ ? *downloaded_file_length_ : 0) + data_length;
   ResourceClientWalker<RawResourceClient> w(Clients());
   while (RawResourceClient* c = w.Next())
     c->DataDownloaded(this, data_length);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
index 9b361f01..31646e0 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
@@ -30,7 +30,6 @@
 #include "platform/loader/fetch/Resource.h"
 #include "platform/loader/fetch/ResourceClient.h"
 #include "platform/loader/fetch/ResourceLoaderOptions.h"
-#include "platform/wtf/Optional.h"
 #include "public/platform/WebDataConsumerHandle.h"
 
 namespace blink {
@@ -81,10 +80,6 @@
   bool WillFollowRedirect(const ResourceRequest&,
                           const ResourceResponse&) override;
 
-  WTF::Optional<int64_t> DownloadedFileLength() const {
-    return downloaded_file_length_;
-  }
-
  private:
   class RawResourceFactory : public NonTextResourceFactory {
    public:
@@ -116,8 +111,6 @@
   bool MatchPreload(const FetchParameters&, WebTaskRunner*) override;
   void NotifyFinished() override;
 
-  WTF::Optional<int64_t> downloaded_file_length_;
-
   // Used for preload matching.
   std::unique_ptr<BufferingDataPipeWriter> data_pipe_writer_;
   std::unique_ptr<WebDataConsumerHandle> data_consumer_handle_;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
index d707d35..1b4b053 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
@@ -686,6 +686,8 @@
 }
 
 void ResourceLoader::RequestSynchronously(const ResourceRequest& request) {
+  // downloadToFile is not supported for synchronous requests.
+  DCHECK(!request.DownloadToFile());
   DCHECK(loader_);
   DCHECK_EQ(request.Priority(), ResourceLoadPriority::kHighest);
 
@@ -695,10 +697,8 @@
   WebData data_out;
   int64_t encoded_data_length = WebURLLoaderClient::kUnknownEncodedDataLength;
   int64_t encoded_body_length = 0;
-  base::Optional<int64_t> downloaded_file_length;
   loader_->LoadSynchronously(request_in, response_out, error_out, data_out,
-                             encoded_data_length, encoded_body_length,
-                             downloaded_file_length);
+                             encoded_data_length, encoded_body_length);
 
   // A message dispatched while synchronously fetching the resource
   // can bring about the cancellation of this load.
@@ -728,11 +728,6 @@
     });
     resource_->SetResourceBuffer(data_out);
   }
-
-  if (downloaded_file_length) {
-    DCHECK(request.DownloadToFile());
-    DidDownloadData(*downloaded_file_length, encoded_body_length);
-  }
   DidFinishLoading(CurrentTimeTicksInSeconds(), encoded_data_length,
                    encoded_body_length, decoded_body_length);
 }
diff --git a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
index d4044af..e174f92 100644
--- a/third_party/WebKit/Source/platform/runtime_enabled_features.json5
+++ b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
@@ -334,7 +334,7 @@
     },
     {
       name: "DisplayNoneIFrameCreatesNoLayoutObject",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "DocumentCookie",
diff --git a/third_party/WebKit/Source/platform/testing/weburl_loader_mock.cc b/third_party/WebKit/Source/platform/testing/weburl_loader_mock.cc
index e20f2f8d..85b0feb 100644
--- a/third_party/WebKit/Source/platform/testing/weburl_loader_mock.cc
+++ b/third_party/WebKit/Source/platform/testing/weburl_loader_mock.cc
@@ -101,14 +101,12 @@
   return redirect_url;
 }
 
-void WebURLLoaderMock::LoadSynchronously(
-    const WebURLRequest& request,
-    WebURLResponse& response,
-    base::Optional<WebURLError>& error,
-    WebData& data,
-    int64_t& encoded_data_length,
-    int64_t& encoded_body_length,
-    base::Optional<int64_t>& downloaded_file_length) {
+void WebURLLoaderMock::LoadSynchronously(const WebURLRequest& request,
+                                         WebURLResponse& response,
+                                         base::Optional<WebURLError>& error,
+                                         WebData& data,
+                                         int64_t& encoded_data_length,
+                                         int64_t& encoded_body_length) {
   if (factory_->IsMockedURL(request.Url())) {
     factory_->LoadSynchronously(request, &response, &error, &data,
                                 &encoded_data_length);
@@ -117,8 +115,7 @@
   AssertFallbackLoaderAvailability(request.Url(), default_loader_.get());
   using_default_loader_ = true;
   default_loader_->LoadSynchronously(request, response, error, data,
-                                     encoded_data_length, encoded_body_length,
-                                     downloaded_file_length);
+                                     encoded_data_length, encoded_body_length);
 }
 
 void WebURLLoaderMock::LoadAsynchronously(const WebURLRequest& request,
diff --git a/third_party/WebKit/Source/platform/testing/weburl_loader_mock.h b/third_party/WebKit/Source/platform/testing/weburl_loader_mock.h
index 9572e57d..1d049ea 100644
--- a/third_party/WebKit/Source/platform/testing/weburl_loader_mock.h
+++ b/third_party/WebKit/Source/platform/testing/weburl_loader_mock.h
@@ -45,14 +45,12 @@
                        const WebURLResponse& redirect_response);
 
   // WebURLLoader methods:
-  void LoadSynchronously(
-      const WebURLRequest& request,
-      WebURLResponse& response,
-      Optional<WebURLError>& error,
-      WebData& data,
-      int64_t& encoded_data_length,
-      int64_t& encoded_body_length,
-      base::Optional<int64_t>& downloaded_file_length) override;
+  void LoadSynchronously(const WebURLRequest& request,
+                         WebURLResponse& response,
+                         Optional<WebURLError>& error,
+                         WebData& data,
+                         int64_t& encoded_data_length,
+                         int64_t& encoded_body_length) override;
   void LoadAsynchronously(const WebURLRequest& request,
                           WebURLLoaderClient* client) override;
   void Cancel() override;
diff --git a/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py b/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py
index 6f97d640..0797088 100755
--- a/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py
+++ b/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py
@@ -56,9 +56,6 @@
             # //base/memory/ptr_util.h.
             'base::WrapUnique',
 
-            # //base/synchronization/waitable_event.h.
-            'base::WaitableEvent',
-
             # Debugging helpers from //base/debug are allowed everywhere.
             'base::debug::.+',
 
diff --git a/third_party/WebKit/public/platform/WebURLLoader.h b/third_party/WebKit/public/platform/WebURLLoader.h
index dc4b205..fbc751e 100644
--- a/third_party/WebKit/public/platform/WebURLLoader.h
+++ b/third_party/WebKit/public/platform/WebURLLoader.h
@@ -51,14 +51,12 @@
   // Load the request synchronously, returning results directly to the
   // caller upon completion.  There is no mechanism to interrupt a
   // synchronous load!!
-  virtual void LoadSynchronously(
-      const WebURLRequest&,
-      WebURLResponse&,
-      base::Optional<WebURLError>&,
-      WebData&,
-      int64_t& encoded_data_length,
-      int64_t& encoded_body_length,
-      base::Optional<int64_t>& downloaded_file_length) = 0;
+  virtual void LoadSynchronously(const WebURLRequest&,
+                                 WebURLResponse&,
+                                 base::Optional<WebURLError>&,
+                                 WebData&,
+                                 int64_t& encoded_data_length,
+                                 int64_t& encoded_body_length) = 0;
 
   // Load the request asynchronously, sending notifications to the given
   // client.  The client will receive no further notifications if the
diff --git a/third_party/WebKit/public/platform/WebURLRequest.h b/third_party/WebKit/public/platform/WebURLRequest.h
index 2b4515f..a298dcd 100644
--- a/third_party/WebKit/public/platform/WebURLRequest.h
+++ b/third_party/WebKit/public/platform/WebURLRequest.h
@@ -193,8 +193,6 @@
   BLINK_PLATFORM_EXPORT mojom::FetchCacheMode GetCacheMode() const;
   BLINK_PLATFORM_EXPORT void SetCacheMode(mojom::FetchCacheMode);
 
-  BLINK_PLATFORM_EXPORT double TimeoutInterval() const;
-
   BLINK_PLATFORM_EXPORT WebString HttpMethod() const;
   BLINK_PLATFORM_EXPORT void SetHTTPMethod(const WebString&);
 
diff --git a/third_party/WebKit/public/platform/WebWorkerFetchContext.h b/third_party/WebKit/public/platform/WebWorkerFetchContext.h
index 2df3d6b2..30cd20a0 100644
--- a/third_party/WebKit/public/platform/WebWorkerFetchContext.h
+++ b/third_party/WebKit/public/platform/WebWorkerFetchContext.h
@@ -14,8 +14,7 @@
 
 namespace base {
 class SingleThreadTaskRunner;
-class WaitableEvent;
-}  // namespace base
+}
 
 namespace blink {
 
@@ -32,13 +31,6 @@
  public:
   virtual ~WebWorkerFetchContext() = default;
 
-  // Returns a raw pointer of a WaitableEvent which will be signaled from the
-  // main thread when the worker's GlobalScope is terminated, which will
-  // terminate sync loading requests on the worker thread.
-  // The raw pointer is valid only while the WebWorkerFetchContext is alive
-  // which is supposed to have the same lifetime as the worker's GlobalScope.
-  virtual base::WaitableEvent* GetTerminateSyncLoadEvent() = 0;
-
   virtual void InitializeOnWorkerThread(
       scoped_refptr<base::SingleThreadTaskRunner>) = 0;
 
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index 4ceecce..495756c 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -71,6 +71,8 @@
       "platform/ax_platform_node_mac.mm",
       "platform/ax_platform_node_win.cc",
       "platform/ax_platform_node_win.h",
+      "platform/ax_platform_relation_win.cc",
+      "platform/ax_platform_relation_win.h",
       "platform/ax_system_caret_win.cc",
       "platform/ax_system_caret_win.h",
     ]
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index b854ad0b..3758d0b 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -284,15 +284,33 @@
 }
 
 std::set<int32_t> AXTree::GetReverseRelations(AXIntAttribute attr,
-                                              int32_t dst_id) {
+                                              int32_t dst_id) const {
   DCHECK(IsNodeIdIntAttribute(attr));
-  return int_reverse_relations_[attr][dst_id];
+
+  // Conceptually, this is the "const" version of:
+  //   return int_reverse_relations_[attr][dst_id];
+  const auto& attr_relations = int_reverse_relations_.find(attr);
+  if (attr_relations != int_reverse_relations_.end()) {
+    const auto& result = attr_relations->second.find(dst_id);
+    if (result != attr_relations->second.end())
+      return result->second;
+  }
+  return std::set<int32_t>();
 }
 
 std::set<int32_t> AXTree::GetReverseRelations(AXIntListAttribute attr,
-                                              int32_t dst_id) {
+                                              int32_t dst_id) const {
   DCHECK(IsNodeIdIntListAttribute(attr));
-  return intlist_reverse_relations_[attr][dst_id];
+
+  // Conceptually, this is the "const" version of:
+  //   return intlist_reverse_relations_[attr][dst_id];
+  const auto& attr_relations = intlist_reverse_relations_.find(attr);
+  if (attr_relations != intlist_reverse_relations_.end()) {
+    const auto& result = attr_relations->second.find(dst_id);
+    if (result != attr_relations->second.end())
+      return result->second;
+  }
+  return std::set<int32_t>();
 }
 
 bool AXTree::Unserialize(const AXTreeUpdate& update) {
diff --git a/ui/accessibility/ax_tree.h b/ui/accessibility/ax_tree.h
index 068ecad7..d733df9 100644
--- a/ui/accessibility/ax_tree.h
+++ b/ui/accessibility/ax_tree.h
@@ -204,14 +204,15 @@
   // Given a node ID attribute (one where IsNodeIdIntAttribute is true),
   // and a destination node ID, return a set of all source node IDs that
   // have that relationship attribute between them and the destination.
-  std::set<int32_t> GetReverseRelations(AXIntAttribute attr, int32_t dst_id);
+  std::set<int32_t> GetReverseRelations(AXIntAttribute attr,
+                                        int32_t dst_id) const;
 
   // Given a node ID list attribute (one where
   // IsNodeIdIntListAttribute is true), and a destination node ID,
   // return a set of all source node IDs that have that relationship
   // attribute between them and the destination.
   std::set<int32_t> GetReverseRelations(AXIntListAttribute attr,
-                                        int32_t dst_id);
+                                        int32_t dst_id) const;
 
   // Return a multi-line indented string representation, for logging.
   std::string ToString() const;
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index c4cb1da..b3a0eca 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -5,6 +5,8 @@
 #ifndef UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_DELEGATE_H_
 #define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_DELEGATE_H_
 
+#include <set>
+
 #include "ui/accessibility/ax_enums.h"
 #include "ui/accessibility/ax_export.h"
 #include "ui/gfx/geometry/vector2d.h"
@@ -81,6 +83,19 @@
 
   virtual AXPlatformNode* GetFromNodeID(int32_t id) = 0;
 
+  // Given a node ID attribute (one where IsNodeIdIntAttribute is true),
+  // and a destination node ID, return a set of all source node IDs that
+  // have that relationship attribute between them and the destination.
+  virtual std::set<int32_t> GetReverseRelations(AXIntAttribute attr,
+                                                int32_t dst_id) = 0;
+
+  // Given a node ID list attribute (one where
+  // IsNodeIdIntListAttribute is true), and a destination node ID,
+  // return a set of all source node IDs that have that relationship
+  // attribute between them and the destination.
+  virtual std::set<int32_t> GetReverseRelations(AXIntListAttribute attr,
+                                                int32_t dst_id) = 0;
+
   //
   // Events.
   //
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index f13a6cc..721c1d8 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -25,6 +25,7 @@
 #include "ui/accessibility/ax_text_utils.h"
 #include "ui/accessibility/ax_tree_data.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
+#include "ui/accessibility/platform/ax_platform_relation_win.h"
 #include "ui/accessibility/platform/ax_platform_unique_id.h"
 #include "ui/base/win/atl_module.h"
 #include "ui/gfx/geometry/rect_conversions.h"
@@ -156,10 +157,6 @@
   if (!target->delegate_)                                                    \
     return E_INVALIDARG;
 
-const WCHAR* const IA2_RELATION_DETAILS = L"details";
-const WCHAR* const IA2_RELATION_DETAILS_FOR = L"detailsFor";
-const WCHAR* const IA2_RELATION_ERROR_MESSAGE = L"errorMessage";
-
 namespace ui {
 
 namespace {
@@ -202,114 +199,6 @@
   return g_iaccessible2_usage_observer_list.Get();
 }
 
-AXPlatformNodeRelationWin::AXPlatformNodeRelationWin() {
-  win::CreateATLModuleIfNeeded();
-}
-
-AXPlatformNodeRelationWin::~AXPlatformNodeRelationWin() {}
-
-void AXPlatformNodeRelationWin::Initialize(AXPlatformNodeWin* owner,
-                                           const base::string16& type) {
-  owner_ = owner;
-  type_ = type;
-}
-
-void AXPlatformNodeRelationWin::AddTarget(int target_id) {
-  target_ids_.push_back(target_id);
-}
-
-void AXPlatformNodeRelationWin::RemoveTarget(int target_id) {
-  target_ids_.erase(
-      std::remove(target_ids_.begin(), target_ids_.end(), target_id),
-      target_ids_.end());
-}
-
-STDMETHODIMP AXPlatformNodeRelationWin::get_relationType(BSTR* relation_type) {
-  if (!relation_type)
-    return E_INVALIDARG;
-
-  if (!owner_->delegate_)
-    return E_FAIL;
-
-  *relation_type = SysAllocString(type_.c_str());
-  DCHECK(*relation_type);
-  return S_OK;
-}
-
-STDMETHODIMP AXPlatformNodeRelationWin::get_nTargets(LONG* n_targets) {
-  if (!n_targets)
-    return E_INVALIDARG;
-
-  if (!owner_->delegate_)
-    return E_FAIL;
-
-  *n_targets = static_cast<LONG>(target_ids_.size());
-
-  for (LONG i = *n_targets - 1; i >= 0; --i) {
-    AXPlatformNodeWin* result = static_cast<AXPlatformNodeWin*>(
-        owner_->delegate_->GetFromNodeID(target_ids_[i]));
-    if (!result || !result->delegate_) {
-      *n_targets = 0;
-      break;
-    }
-  }
-  return S_OK;
-}
-
-STDMETHODIMP AXPlatformNodeRelationWin::get_target(LONG target_index,
-                                                   IUnknown** target) {
-  if (!target)
-    return E_INVALIDARG;
-
-  if (!owner_->delegate_)
-    return E_FAIL;
-
-  if (target_index < 0 ||
-      target_index >= static_cast<LONG>(target_ids_.size())) {
-    return E_INVALIDARG;
-  }
-
-  AXPlatformNodeWin* result = static_cast<AXPlatformNodeWin*>(
-      owner_->delegate_->GetFromNodeID(target_ids_[target_index]));
-  if (!result || !result->delegate_)
-    return E_FAIL;
-
-  result->AddRef();
-  *target = static_cast<IAccessible*>(result);
-  return S_OK;
-}
-
-STDMETHODIMP AXPlatformNodeRelationWin::get_targets(LONG max_targets,
-                                                    IUnknown** targets,
-                                                    LONG* n_targets) {
-  if (!targets || !n_targets)
-    return E_INVALIDARG;
-
-  if (!owner_->delegate_)
-    return E_FAIL;
-
-  LONG count = static_cast<LONG>(target_ids_.size());
-  if (count > max_targets)
-    count = max_targets;
-
-  *n_targets = count;
-  if (count == 0)
-    return S_FALSE;
-
-  for (LONG i = 0; i < count; ++i) {
-    HRESULT result = get_target(i, &targets[i]);
-    if (result != S_OK)
-      return result;
-  }
-
-  return S_OK;
-}
-
-STDMETHODIMP
-AXPlatformNodeRelationWin::get_localizedRelationType(BSTR* relation_type) {
-  return E_NOTIMPL;
-}
-
 //
 // AXPlatformNode::Create
 //
@@ -361,8 +250,7 @@
 }
 
 AXPlatformNodeWin::~AXPlatformNodeWin() {
-  for (AXPlatformNodeRelationWin* relation : relations_)
-    relation->Release();
+  ClearOwnRelations();
   if (unique_id_)
     g_unique_id_map.Get().erase(unique_id_);
 }
@@ -374,158 +262,10 @@
 
 const base::char16 AXPlatformNodeWin::kEmbeddedCharacter = L'\xfffc';
 
-void AXPlatformNodeWin::CalculateRelationships() {
-  ClearOwnRelations();
-  AddBidirectionalRelations(IA2_RELATION_CONTROLLER_FOR,
-                            IA2_RELATION_CONTROLLED_BY, AX_ATTR_CONTROLS_IDS);
-  AddBidirectionalRelations(IA2_RELATION_DESCRIBED_BY,
-                            IA2_RELATION_DESCRIPTION_FOR,
-                            AX_ATTR_DESCRIBEDBY_IDS);
-  AddBidirectionalRelations(IA2_RELATION_FLOWS_TO, IA2_RELATION_FLOWS_FROM,
-                            AX_ATTR_FLOWTO_IDS);
-  AddBidirectionalRelations(IA2_RELATION_LABELLED_BY, IA2_RELATION_LABEL_FOR,
-                            AX_ATTR_LABELLEDBY_IDS);
-
-  int32_t details_id;
-  if (GetIntAttribute(AX_ATTR_DETAILS_ID, &details_id)) {
-    std::vector<int32_t> details_ids;
-    details_ids.push_back(details_id);
-    AddBidirectionalRelations(IA2_RELATION_DETAILS, IA2_RELATION_DETAILS_FOR,
-                              details_ids);
-  }
-
-  int member_of_id;
-  if (GetIntAttribute(AX_ATTR_MEMBER_OF_ID, &member_of_id))
-    AddRelation(IA2_RELATION_MEMBER_OF, member_of_id);
-
-  int error_message_id;
-  if (GetIntAttribute(AX_ATTR_ERRORMESSAGE_ID, &error_message_id))
-    AddRelation(IA2_RELATION_ERROR_MESSAGE, error_message_id);
-}
-
-void AXPlatformNodeWin::AddRelation(const base::string16& relation_type,
-                                    int target_id) {
-  // Reflexive relations don't need to be exposed through IA2.
-  if (target_id == GetData().id)
-    return;
-
-  CComObject<AXPlatformNodeRelationWin>* relation;
-  HRESULT hr = CComObject<AXPlatformNodeRelationWin>::CreateInstance(&relation);
-  DCHECK(SUCCEEDED(hr));
-  relation->AddRef();
-  relation->Initialize(this, relation_type);
-  relation->AddTarget(target_id);
-  relations_.push_back(relation);
-}
-
-void AXPlatformNodeWin::AddBidirectionalRelations(
-    const base::string16& relation_type,
-    const base::string16& reverse_relation_type,
-    AXIntListAttribute attribute) {
-  if (!HasIntListAttribute(attribute))
-    return;
-
-  const std::vector<int32_t>& target_ids = GetIntListAttribute(attribute);
-  AddBidirectionalRelations(relation_type, reverse_relation_type, target_ids);
-}
-
-void AXPlatformNodeWin::AddBidirectionalRelations(
-    const base::string16& relation_type,
-    const base::string16& reverse_relation_type,
-    const std::vector<int32_t>& target_ids) {
-  // Reflexive relations don't need to be exposed through IA2.
-  std::vector<int32_t> filtered_target_ids;
-  int32_t current_id = GetData().id;
-  std::copy_if(target_ids.begin(), target_ids.end(),
-               std::back_inserter(filtered_target_ids),
-               [current_id](int32_t id) { return id != current_id; });
-  if (filtered_target_ids.empty())
-    return;
-
-  CComObject<AXPlatformNodeRelationWin>* relation;
-  HRESULT hr = CComObject<AXPlatformNodeRelationWin>::CreateInstance(&relation);
-  DCHECK(SUCCEEDED(hr));
-  relation->AddRef();
-  relation->Initialize(this, relation_type);
-
-  for (int target_id : filtered_target_ids) {
-    AXPlatformNodeWin* target = static_cast<AXPlatformNodeWin*>(
-        delegate_->GetFromNodeID(static_cast<int32_t>(target_id)));
-
-    if (!target)
-      continue;
-    relation->AddTarget(target_id);
-    target->AddRelation(reverse_relation_type, GetData().id);
-  }
-
-  relations_.push_back(relation);
-}
-
-// Clears all the forward relations from this object to any other object and the
-// associated  reverse relations on the other objects, but leaves any reverse
-// relations on this object alone.
 void AXPlatformNodeWin::ClearOwnRelations() {
-  RemoveBidirectionalRelationsOfType(IA2_RELATION_CONTROLLER_FOR,
-                                     IA2_RELATION_CONTROLLED_BY);
-  RemoveBidirectionalRelationsOfType(IA2_RELATION_DESCRIBED_BY,
-                                     IA2_RELATION_DESCRIPTION_FOR);
-  RemoveBidirectionalRelationsOfType(IA2_RELATION_FLOWS_TO,
-                                     IA2_RELATION_FLOWS_FROM);
-  RemoveBidirectionalRelationsOfType(IA2_RELATION_LABELLED_BY,
-                                     IA2_RELATION_LABEL_FOR);
-
-  relations_.erase(
-      std::remove_if(relations_.begin(), relations_.end(),
-                     [](AXPlatformNodeRelationWin* relation) {
-                       if (relation->get_type() == IA2_RELATION_MEMBER_OF) {
-                         relation->Release();
-                         return true;
-                       }
-                       return false;
-                     }),
-      relations_.end());
-}
-
-void AXPlatformNodeWin::RemoveBidirectionalRelationsOfType(
-    const base::string16& relation_type,
-    const base::string16& reverse_relation_type) {
-  for (auto iter = relations_.begin(); iter != relations_.end();) {
-    AXPlatformNodeRelationWin* relation = *iter;
-    DCHECK(relation);
-    if (relation->get_type() == relation_type) {
-      for (int target_id : relation->get_target_ids()) {
-        AXPlatformNodeWin* target = static_cast<AXPlatformNodeWin*>(
-            delegate_->GetFromNodeID(static_cast<int32_t>(target_id)));
-        if (!target)
-          continue;
-        DCHECK_NE(target, this);
-        target->RemoveTargetFromRelation(reverse_relation_type, GetData().id);
-      }
-      iter = relations_.erase(iter);
-      relation->Release();
-    } else {
-      ++iter;
-    }
-  }
-}
-
-void AXPlatformNodeWin::RemoveTargetFromRelation(
-    const base::string16& relation_type,
-    int target_id) {
-  for (auto iter = relations_.begin(); iter != relations_.end();) {
-    AXPlatformNodeRelationWin* relation = *iter;
-    DCHECK(relation);
-    if (relation->get_type() == relation_type) {
-      // If |target_id| is not present, |RemoveTarget| will do nothing.
-      relation->RemoveTarget(target_id);
-    }
-    if (relation->get_target_ids().empty()) {
-      iter = relations_.erase(iter);
-      relation->Release();
-    } else {
-      ++iter;
-    }
-  }
+  for (size_t i = 0; i < relations_.size(); ++i)
+    relations_[i]->Invalidate();
+  relations_.clear();
 }
 
 // Static
@@ -1215,42 +955,68 @@
   *n_targets = 0;
   *targets = nullptr;
 
-  // Only respond to requests for relations of type "alerts".
+  // Special case for relations of type "alerts".
   base::string16 type(type_bstr);
-  if (type != L"alerts")
-    return S_FALSE;
+  if (type == L"alerts") {
+    // Collect all of the objects that have had an alert fired on them that
+    // are a descendant of this object.
+    std::vector<AXPlatformNodeWin*> alert_targets;
+    for (auto iter = g_alert_targets.Get().begin();
+         iter != g_alert_targets.Get().end(); ++iter) {
+      AXPlatformNodeWin* target = *iter;
+      if (IsDescendant(target))
+        alert_targets.push_back(target);
+    }
 
-  // Collect all of the objects that have had an alert fired on them that
-  // are a descendant of this object.
-  std::vector<AXPlatformNodeWin*> alert_targets;
-  for (auto iter = g_alert_targets.Get().begin();
-       iter != g_alert_targets.Get().end();
-       ++iter) {
-    AXPlatformNodeWin* target = *iter;
-    if (IsDescendant(target))
-      alert_targets.push_back(target);
+    LONG count = static_cast<LONG>(alert_targets.size());
+    if (count == 0)
+      return S_FALSE;
+
+    // Don't return more targets than max_targets - but note that the caller
+    // is allowed to specify max_targets=0 to mean no limit.
+    if (max_targets > 0 && count > max_targets)
+      count = max_targets;
+
+    // Return the number of targets.
+    *n_targets = count;
+
+    // Allocate COM memory for the result array and populate it.
+    *targets =
+        static_cast<IUnknown**>(CoTaskMemAlloc(count * sizeof(IUnknown*)));
+    for (LONG i = 0; i < count; ++i) {
+      (*targets)[i] = static_cast<IAccessible*>(alert_targets[i]);
+      (*targets)[i]->AddRef();
+    }
+    return S_OK;
   }
 
-  LONG count = static_cast<LONG>(alert_targets.size());
-  if (count == 0)
+  base::string16 relation_type;
+  std::set<int32_t> target_ids;
+  int found = AXPlatformRelationWin::EnumerateRelationships(
+      GetData(), delegate_, 0, type, &relation_type, &target_ids);
+  if (found == 0)
     return S_FALSE;
 
   // Don't return more targets than max_targets - but note that the caller
   // is allowed to specify max_targets=0 to mean no limit.
+  int count = static_cast<int>(target_ids.size());
   if (max_targets > 0 && count > max_targets)
     count = max_targets;
 
-  // Return the number of targets.
-  *n_targets = count;
-
   // Allocate COM memory for the result array and populate it.
-  *targets = static_cast<IUnknown**>(
-      CoTaskMemAlloc(count * sizeof(IUnknown*)));
-  for (LONG i = 0; i < count; ++i) {
-    (*targets)[i] = static_cast<IAccessible*>(alert_targets[i]);
-    (*targets)[i]->AddRef();
+  *targets = static_cast<IUnknown**>(CoTaskMemAlloc(count * sizeof(IUnknown*)));
+  int index = 0;
+  for (int target_id : target_ids) {
+    AXPlatformNodeWin* target =
+        static_cast<AXPlatformNodeWin*>(delegate_->GetFromNodeID(target_id));
+    if (target) {
+      (*targets)[index] = static_cast<IAccessible*>(target);
+      (*targets)[index]->AddRef();
+      index++;
+    }
   }
-  return S_OK;
+  *n_targets = index;
+  return index > 0 ? S_OK : S_FALSE;
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_attributes(BSTR* attributes) {
@@ -1286,7 +1052,10 @@
   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_N_RELATIONS);
   COM_OBJECT_VALIDATE_1_ARG(n_relations);
   AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
-  *n_relations = static_cast<LONG>(relations_.size());
+
+  int count = AXPlatformRelationWin::EnumerateRelationships(
+      GetData(), delegate_, -1, base::string16(), nullptr, nullptr);
+  *n_relations = count;
   return S_OK;
 }
 
@@ -1295,13 +1064,32 @@
   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_RELATION);
   COM_OBJECT_VALIDATE_1_ARG(relation);
   AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
-  if (relation_index < 0 ||
-      relation_index >= static_cast<LONG>(relations_.size())) {
+
+  base::string16 relation_type;
+  std::set<int32_t> targets;
+  int found = AXPlatformRelationWin::EnumerateRelationships(
+      GetData(), delegate_, relation_index, base::string16(), &relation_type,
+      &targets);
+  if (found == 0)
     return E_INVALIDARG;
+
+  CComObject<AXPlatformRelationWin>* relation_obj;
+  HRESULT hr = CComObject<AXPlatformRelationWin>::CreateInstance(&relation_obj);
+  DCHECK(SUCCEEDED(hr));
+  relation_obj->AddRef();
+  relation_obj->Initialize(relation_type);
+  for (int target_id : targets) {
+    AXPlatformNodeWin* target =
+        static_cast<AXPlatformNodeWin*>(delegate_->GetFromNodeID(target_id));
+    if (!target)
+      continue;
+    relation_obj->AddTarget(target);
   }
 
-  relations_[relation_index]->AddRef();
-  *relation = relations_[relation_index];
+  // Maintain references to all relations returned by this object.
+  // Every time this object changes state, invalidate them.
+  relations_.push_back(relation_obj);
+  *relation = relation_obj;
   return S_OK;
 }
 
@@ -1312,14 +1100,16 @@
   COM_OBJECT_VALIDATE_2_ARGS(relations, n_relations);
   AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
 
-  LONG count = static_cast<LONG>(relations_.size());
+  LONG count;
+  HRESULT hr = get_nRelations(&count);
+  if (!SUCCEEDED(hr))
+    return hr;
+  count = std::min(count, max_relations);
   *n_relations = count;
-  if (count == 0)
-    return S_FALSE;
-
-  for (LONG i = 0; i < count; ++i) {
-    relations_[i]->AddRef();
-    relations[i] = relations_[i];
+  for (LONG i = 0; i < count; i++) {
+    hr = get_relation(i, &relations[i]);
+    if (!SUCCEEDED(hr))
+      return hr;
   }
 
   return S_OK;
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index a5af545..9238fa9 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -192,6 +192,7 @@
 
 namespace ui {
 class AXPlatformNodeWin;
+class AXPlatformRelationWin;
 
 // A simple interface for a class that wants to be notified when IAccessible2
 // is used by a client, a strong indication that full accessibility support
@@ -226,45 +227,6 @@
 extern AX_EXPORT base::ObserverList<IAccessible2UsageObserver>&
     GetIAccessible2UsageObserverList();
 
-//
-// AXPlatformNodeRelationWin
-//
-// A simple implementation of IAccessibleRelation, used to represent
-// a relationship between two accessible nodes in the tree.
-//
-class AXPlatformNodeRelationWin : public CComObjectRootEx<CComMultiThreadModel>,
-                                  public IAccessibleRelation {
- public:
-  BEGIN_COM_MAP(AXPlatformNodeRelationWin)
-  COM_INTERFACE_ENTRY(IAccessibleRelation)
-  END_COM_MAP()
-
-  AXPlatformNodeRelationWin();
-  virtual ~AXPlatformNodeRelationWin();
-
-  void Initialize(AXPlatformNodeWin* owner, const base::string16& type);
-  void AddTarget(int target_id);
-  void RemoveTarget(int target_id);
-
-  // IAccessibleRelation methods.
-  STDMETHODIMP get_relationType(BSTR* relation_type) override;
-  STDMETHODIMP get_nTargets(LONG* n_targets) override;
-  STDMETHODIMP get_target(LONG target_index, IUnknown** target) override;
-  STDMETHODIMP get_targets(LONG max_targets,
-                           IUnknown** targets,
-                           LONG* n_targets) override;
-  STDMETHODIMP get_localizedRelationType(BSTR* relation_type) override;
-
-  // Accessors.
-  const base::string16& get_type() const { return type_; }
-  const std::vector<int>& get_target_ids() const { return target_ids_; }
-
- private:
-  base::string16 type_;
-  Microsoft::WRL::ComPtr<AXPlatformNodeWin> owner_;
-  std::vector<int> target_ids_;
-};
-
 class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
     AXPlatformNodeWin : public CComObjectRootEx<CComMultiThreadModel>,
                         public IDispatchImpl<IAccessible2_2,
@@ -300,8 +262,8 @@
   // position where a non-static text child object appears.
   static const base::char16 kEmbeddedCharacter;
 
-  // Clear node's current relationships and set them to the default values.
-  void CalculateRelationships();
+  // Clear any AXPlatformRelationWin nodes owned by this node.
+  void ClearOwnRelations();
   static AXPlatformNode* GetFromUniqueId(int32_t unique_id);
   int32_t unique_id() const { return unique_id_; }
 
@@ -678,7 +640,7 @@
   void Dispose() override;
 
   // Relationships between this node and other nodes.
-  std::vector<AXPlatformNodeRelationWin*> relations_;
+  std::vector<Microsoft::WRL::ComPtr<AXPlatformRelationWin>> relations_;
 
   AXHypertext old_hypertext_;
   AXHypertext hypertext_;
@@ -805,26 +767,6 @@
   // Returns true if this node is in a treegrid.
   bool IsInTreeGrid();
 
-  //
-  // For adding / removing IA2 relations.
-  //
-  void AddRelation(const base::string16& relation_type, int target_id);
-  void AddBidirectionalRelations(const base::string16& relation_type,
-                                 const base::string16& reverse_relation_type,
-                                 AXIntListAttribute attribute);
-  void AddBidirectionalRelations(const base::string16& relation_type,
-                                 const base::string16& reverse_relation_type,
-                                 const std::vector<int32_t>& target_ids);
-  // Clears all the forward relations from this object to any other object and
-  // the associated  reverse relations on the other objects, but leaves any
-  // reverse relations on this object alone.
-  void ClearOwnRelations();
-  void RemoveBidirectionalRelationsOfType(
-      const base::string16& relation_type,
-      const base::string16& reverse_relation_type);
-  void RemoveTargetFromRelation(const base::string16& relation_type,
-                                int target_id);
-
   // Helper method for returning selected indicies. It is expected that the
   // caller ensures that the input has been validated.
   HRESULT AllocateComArrayFromVector(std::vector<LONG>& results,
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index bbaf4a4..7a7ea0db 100644
--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -51,12 +51,6 @@
   }
 
  protected:
-  void BuildRelationships(ComPtr<IAccessible2> accessible) {
-    CHECK(accessible);
-    AXPlatformNodeWin* node = static_cast<AXPlatformNodeWin*>(accessible.Get());
-    node->CalculateRelationships();
-  }
-
   ComPtr<IAccessible> IAccessibleFromNode(AXNode* node) {
     TestAXNodeWrapper* wrapper =
         TestAXNodeWrapper::GetOrCreate(tree_.get(), node);
@@ -91,6 +85,16 @@
     return result;
   }
 
+  ComPtr<IAccessible2_2> ToIAccessible2_2(ComPtr<IAccessible> accessible) {
+    CHECK(accessible);
+    ComPtr<IServiceProvider> service_provider;
+    accessible.CopyTo(service_provider.GetAddressOf());
+    ComPtr<IAccessible2_2> result;
+    CHECK(SUCCEEDED(service_provider->QueryService(IID_IAccessible2_2,
+                                                   result.GetAddressOf())));
+    return result;
+  }
+
   void CheckVariantHasName(ScopedVariant& variant,
                            const wchar_t* expected_name) {
     ASSERT_NE(nullptr, variant.ptr());
@@ -1460,10 +1464,6 @@
   EXPECT_EQ(S_OK, result.CopyTo(ax_child2.GetAddressOf()));
   result.Reset();
 
-  BuildRelationships(root_iaccessible2);
-  BuildRelationships(ax_child1);
-  BuildRelationships(ax_child2);
-
   LONG n_relations = 0;
   LONG n_targets = 0;
   ScopedBstr relation_type;
@@ -1476,9 +1476,11 @@
 
   EXPECT_HRESULT_SUCCEEDED(
       root_iaccessible2->get_relation(0, describedby_relation.GetAddressOf()));
+
   EXPECT_HRESULT_SUCCEEDED(
       describedby_relation->get_relationType(relation_type.Receive()));
   EXPECT_EQ(L"describedBy", base::string16(relation_type));
+
   relation_type.Reset();
 
   EXPECT_HRESULT_SUCCEEDED(describedby_relation->get_nTargets(&n_targets));
@@ -1491,6 +1493,7 @@
   EXPECT_HRESULT_SUCCEEDED(
       describedby_relation->get_target(1, target.GetAddressOf()));
   target.Reset();
+
   describedby_relation.Reset();
 
   // Test the reverse relations.
@@ -1532,6 +1535,92 @@
   // TODO(dougt): Try adding one more relation.
 }
 
+TEST_F(AXPlatformNodeWinTest, TestRelationTargetsOfType) {
+  AXNodeData root;
+  root.id = 1;
+  root.role = AX_ROLE_ROOT_WEB_AREA;
+  root.AddIntAttribute(AX_ATTR_DETAILS_ID, 2);
+
+  AXNodeData child1;
+  child1.id = 2;
+  child1.role = AX_ROLE_STATIC_TEXT;
+
+  root.child_ids.push_back(2);
+
+  AXNodeData child2;
+  child2.id = 3;
+  child2.role = AX_ROLE_STATIC_TEXT;
+  std::vector<int32_t> labelledby_ids = {1, 4};
+  child2.AddIntListAttribute(AX_ATTR_LABELLEDBY_IDS, labelledby_ids);
+
+  root.child_ids.push_back(3);
+
+  AXNodeData child3;
+  child3.id = 4;
+  child3.role = AX_ROLE_STATIC_TEXT;
+  child3.AddIntAttribute(AX_ATTR_DETAILS_ID, 2);
+
+  root.child_ids.push_back(4);
+
+  Init(root, child1, child2, child3);
+  ComPtr<IAccessible> root_iaccessible(GetRootIAccessible());
+  ComPtr<IAccessible2_2> root_iaccessible2 = ToIAccessible2_2(root_iaccessible);
+
+  ComPtr<IDispatch> result;
+  EXPECT_EQ(S_OK, root_iaccessible2->get_accChild(ScopedVariant(1),
+                                                  result.GetAddressOf()));
+  ComPtr<IAccessible2_2> ax_child1;
+  EXPECT_EQ(S_OK, result.CopyTo(ax_child1.GetAddressOf()));
+  result.Reset();
+
+  EXPECT_EQ(S_OK, root_iaccessible2->get_accChild(ScopedVariant(2),
+                                                  result.GetAddressOf()));
+  ComPtr<IAccessible2_2> ax_child2;
+  EXPECT_EQ(S_OK, result.CopyTo(ax_child2.GetAddressOf()));
+  result.Reset();
+
+  EXPECT_EQ(S_OK, root_iaccessible2->get_accChild(ScopedVariant(3),
+                                                  result.GetAddressOf()));
+  ComPtr<IAccessible2_2> ax_child3;
+  EXPECT_EQ(S_OK, result.CopyTo(ax_child3.GetAddressOf()));
+  result.Reset();
+
+  {
+    ScopedBstr type(L"details");
+    IUnknown** targets;
+    LONG n_targets;
+    EXPECT_EQ(S_OK, root_iaccessible2->get_relationTargetsOfType(
+                        type, 0, &targets, &n_targets));
+    ASSERT_EQ(1, n_targets);
+    EXPECT_EQ(ax_child1.Get(), targets[0]);
+    CoTaskMemFree(targets);
+  }
+
+  {
+    ScopedBstr type(IA2_RELATION_LABELLED_BY);
+    IUnknown** targets;
+    LONG n_targets;
+    EXPECT_EQ(S_OK, ax_child2->get_relationTargetsOfType(type, 0, &targets,
+                                                         &n_targets));
+    ASSERT_EQ(2, n_targets);
+    EXPECT_EQ(root_iaccessible2.Get(), targets[0]);
+    EXPECT_EQ(ax_child3.Get(), targets[1]);
+    CoTaskMemFree(targets);
+  }
+
+  {
+    ScopedBstr type(L"detailsFor");
+    IUnknown** targets;
+    LONG n_targets;
+    EXPECT_EQ(S_OK, ax_child1->get_relationTargetsOfType(type, 0, &targets,
+                                                         &n_targets));
+    ASSERT_EQ(2, n_targets);
+    EXPECT_EQ(root_iaccessible2.Get(), targets[0]);
+    EXPECT_EQ(ax_child3.Get(), targets[1]);
+    CoTaskMemFree(targets);
+  }
+}
+
 TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedChildrenZero) {
   Init(Build3X3Table());
 
diff --git a/ui/accessibility/platform/ax_platform_relation_win.cc b/ui/accessibility/platform/ax_platform_relation_win.cc
new file mode 100644
index 0000000..8395ead
--- /dev/null
+++ b/ui/accessibility/platform/ax_platform_relation_win.cc
@@ -0,0 +1,303 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/platform/ax_platform_relation_win.h"
+
+#include <wrl/client.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/enum_variant.h"
+#include "base/win/scoped_variant.h"
+#include "third_party/iaccessible2/ia2_api_all.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_mode_observer.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_role_properties.h"
+#include "ui/accessibility/ax_text_utils.h"
+#include "ui/accessibility/ax_tree_data.h"
+#include "ui/accessibility/platform/ax_platform_node_delegate.h"
+#include "ui/accessibility/platform/ax_platform_unique_id.h"
+#include "ui/base/win/atl_module.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+
+const WCHAR* const IA2_RELATION_DETAILS = L"details";
+const WCHAR* const IA2_RELATION_DETAILS_FOR = L"detailsFor";
+const WCHAR* const IA2_RELATION_ERROR_MESSAGE = L"errorMessage";
+
+namespace ui {
+
+AXPlatformRelationWin::AXPlatformRelationWin() {
+  win::CreateATLModuleIfNeeded();
+}
+
+AXPlatformRelationWin::~AXPlatformRelationWin() {}
+
+base::string16 GetIA2RelationFromIntAttr(ui::AXIntAttribute attribute) {
+  switch (attribute) {
+    case AX_ATTR_DETAILS_ID:
+      return IA2_RELATION_DETAILS;
+    case AX_ATTR_MEMBER_OF_ID:
+      return IA2_RELATION_MEMBER_OF;
+    case AX_ATTR_ERRORMESSAGE_ID:
+      return IA2_RELATION_ERROR_MESSAGE;
+    default:
+      break;
+  }
+  return base::string16();
+}
+
+base::string16 GetIA2RelationFromIntListAttr(ui::AXIntListAttribute attribute) {
+  switch (attribute) {
+    case AX_ATTR_CONTROLS_IDS:
+      return IA2_RELATION_CONTROLLER_FOR;
+    case AX_ATTR_DESCRIBEDBY_IDS:
+      return IA2_RELATION_DESCRIBED_BY;
+    case AX_ATTR_FLOWTO_IDS:
+      return IA2_RELATION_FLOWS_TO;
+    case AX_ATTR_LABELLEDBY_IDS:
+      return IA2_RELATION_LABELLED_BY;
+    default:
+      break;
+  }
+  return base::string16();
+}
+
+base::string16 GetIA2ReverseRelationFromIntAttr(ui::AXIntAttribute attribute) {
+  switch (attribute) {
+    case AX_ATTR_DETAILS_ID:
+      return IA2_RELATION_DETAILS_FOR;
+    default:
+      break;
+  }
+  return base::string16();
+}
+
+base::string16 GetIA2ReverseRelationFromIntListAttr(
+    ui::AXIntListAttribute attribute) {
+  switch (attribute) {
+    case AX_ATTR_CONTROLS_IDS:
+      return IA2_RELATION_CONTROLLED_BY;
+    case AX_ATTR_DESCRIBEDBY_IDS:
+      return IA2_RELATION_DESCRIPTION_FOR;
+    case AX_ATTR_FLOWTO_IDS:
+      return IA2_RELATION_FLOWS_FROM;
+    case AX_ATTR_LABELLEDBY_IDS:
+      return IA2_RELATION_LABEL_FOR;
+    default:
+      break;
+  }
+  return base::string16();
+}
+
+// static
+int AXPlatformRelationWin::EnumerateRelationships(
+    const AXNodeData& node_data,
+    AXPlatformNodeDelegate* delegate,
+    int desired_index,
+    const base::string16& desired_ia2_relation,
+    base::string16* out_ia2_relation,
+    std::set<int32_t>* out_targets) {
+  // The first time this is called, populate vectors with all of the
+  // int attributes and intlist attributes that have reverse relations
+  // we care about on Windows. Computing these by calling
+  // GetIA2ReverseRelationFrom{Int|IntList}Attr on every possible attribute
+  // simplifies the work needed to support an additional relation
+  // attribute in the future.
+  static std::vector<AXIntAttribute> int_attributes_with_reverse_relations;
+  static std::vector<AXIntListAttribute>
+      intlist_attributes_with_reverse_relations;
+  static bool first_time = true;
+  if (first_time) {
+    for (int attr_index = AX_INT_ATTRIBUTE_NONE;
+         attr_index <= AX_INT_ATTRIBUTE_LAST; ++attr_index) {
+      auto attr = static_cast<AXIntAttribute>(attr_index);
+      if (!GetIA2ReverseRelationFromIntAttr(attr).empty())
+        int_attributes_with_reverse_relations.push_back(attr);
+    }
+    for (int attr_index = AX_INT_LIST_ATTRIBUTE_NONE;
+         attr_index <= AX_INT_LIST_ATTRIBUTE_LAST; ++attr_index) {
+      auto attr = static_cast<AXIntListAttribute>(attr_index);
+      if (!GetIA2ReverseRelationFromIntListAttr(attr).empty())
+        intlist_attributes_with_reverse_relations.push_back(attr);
+    }
+    first_time = false;
+  }
+
+  // Enumerate all of the relations and reverse relations that
+  // are exposed via IAccessible2 on Windows. We do this with a series
+  // of loops. Every time we encounter one, we check if the caller
+  // requested that particular relation by index, and return it.
+  // Otherwise we build up and return the total number of relations found.
+  int total_count = 0;
+
+  // Iterate over all int attributes on this node to check the ones
+  // that correspond to IAccessible2 relations.
+  for (size_t i = 0; i < node_data.int_attributes.size(); ++i) {
+    AXIntAttribute int_attribute = node_data.int_attributes[i].first;
+    base::string16 relation = GetIA2RelationFromIntAttr(int_attribute);
+    if (!relation.empty() &&
+        (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
+      // Skip reflexive relations
+      if (node_data.int_attributes[i].second == node_data.id)
+        continue;
+      if (desired_index == total_count) {
+        *out_ia2_relation = relation;
+        out_targets->insert(node_data.int_attributes[i].second);
+        return 1;
+      }
+      total_count++;
+    }
+  }
+
+  // Iterate over all of the int attributes that have reverse relations
+  // in IAccessible2, and query AXTree to see if the reverse relation exists.
+  for (AXIntAttribute int_attribute : int_attributes_with_reverse_relations) {
+    base::string16 relation = GetIA2ReverseRelationFromIntAttr(int_attribute);
+    std::set<int32_t> targets =
+        delegate->GetReverseRelations(int_attribute, node_data.id);
+    // Erase reflexive relations.
+    targets.erase(node_data.id);
+    if (targets.size()) {
+      if (!relation.empty() &&
+          (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
+        if (desired_index == total_count) {
+          *out_ia2_relation = relation;
+          *out_targets = targets;
+          return 1;
+        }
+        total_count++;
+      }
+    }
+  }
+
+  // Iterate over all intlist attributes on this node to check the ones
+  // that correspond to IAccessible2 relations.
+  for (size_t i = 0; i < node_data.intlist_attributes.size(); ++i) {
+    AXIntListAttribute intlist_attribute =
+        node_data.intlist_attributes[i].first;
+    base::string16 relation = GetIA2RelationFromIntListAttr(intlist_attribute);
+    if (!relation.empty() &&
+        (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
+      if (desired_index == total_count) {
+        *out_ia2_relation = relation;
+        for (int32_t target_id : node_data.intlist_attributes[i].second) {
+          // Skip reflexive relations
+          if (target_id == node_data.id)
+            continue;
+          out_targets->insert(target_id);
+        }
+        if (out_targets->size() == 0)
+          continue;
+        return 1;
+      }
+      total_count++;
+    }
+  }
+
+  // Iterate over all of the intlist attributes that have reverse relations
+  // in IAccessible2, and query AXTree to see if the reverse relation exists.
+  for (AXIntListAttribute intlist_attribute :
+       intlist_attributes_with_reverse_relations) {
+    base::string16 relation =
+        GetIA2ReverseRelationFromIntListAttr(intlist_attribute);
+    std::set<int32_t> targets =
+        delegate->GetReverseRelations(intlist_attribute, node_data.id);
+    // Erase reflexive relations.
+    targets.erase(node_data.id);
+    if (targets.size()) {
+      if (!relation.empty() &&
+          (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
+        if (desired_index == total_count) {
+          *out_ia2_relation = relation;
+          *out_targets = targets;
+          return 1;
+        }
+        total_count++;
+      }
+    }
+  }
+
+  return total_count;
+}
+
+void AXPlatformRelationWin::Initialize(const base::string16& type) {
+  type_ = type;
+}
+
+void AXPlatformRelationWin::Invalidate() {
+  targets_.clear();
+}
+
+void AXPlatformRelationWin::AddTarget(AXPlatformNodeWin* target) {
+  targets_.push_back(target);
+}
+
+STDMETHODIMP AXPlatformRelationWin::get_relationType(BSTR* relation_type) {
+  if (!relation_type)
+    return E_INVALIDARG;
+
+  *relation_type = SysAllocString(type_.c_str());
+  DCHECK(*relation_type);
+  return S_OK;
+}
+
+STDMETHODIMP AXPlatformRelationWin::get_nTargets(LONG* n_targets) {
+  if (!n_targets)
+    return E_INVALIDARG;
+
+  *n_targets = static_cast<LONG>(targets_.size());
+  return S_OK;
+}
+
+STDMETHODIMP AXPlatformRelationWin::get_target(LONG target_index,
+                                               IUnknown** target) {
+  if (!target)
+    return E_INVALIDARG;
+
+  if (target_index < 0 || target_index >= static_cast<LONG>(targets_.size())) {
+    return E_INVALIDARG;
+  }
+
+  *target = static_cast<IAccessible*>(targets_[target_index].Get());
+  (*target)->AddRef();
+  return S_OK;
+}
+
+STDMETHODIMP AXPlatformRelationWin::get_targets(LONG max_targets,
+                                                IUnknown** targets,
+                                                LONG* n_targets) {
+  if (!targets || !n_targets)
+    return E_INVALIDARG;
+
+  LONG count = static_cast<LONG>(targets_.size());
+  if (count > max_targets)
+    count = max_targets;
+
+  *n_targets = count;
+  if (count == 0)
+    return S_FALSE;
+
+  for (LONG i = 0; i < count; ++i) {
+    HRESULT result = get_target(i, &targets[i]);
+    if (result != S_OK)
+      return result;
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP
+AXPlatformRelationWin::get_localizedRelationType(BSTR* relation_type) {
+  return E_NOTIMPL;
+}
+
+}  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_relation_win.h b/ui/accessibility/platform/ax_platform_relation_win.h
new file mode 100644
index 0000000..668c4ec
--- /dev/null
+++ b/ui/accessibility/platform/ax_platform_relation_win.h
@@ -0,0 +1,83 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_RELATION_WIN_H_
+#define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_RELATION_WIN_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <oleacc.h>
+#include <wrl/client.h>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/observer_list.h"
+#include "third_party/iaccessible2/ia2_api_all.h"
+#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_text_utils.h"
+#include "ui/accessibility/platform/ax_platform_node_win.h"
+
+namespace ui {
+
+//
+// AXPlatformRelationWin
+//
+// A simple implementation of IAccessibleRelation, used to represent a
+// relationship between one accessible node in the tree and
+// potentially multiple target nodes. Also contains a utility function
+// to compute all of the possible IAccessible2 relations and reverse
+// relations given the internal relation id attributes.
+class AXPlatformRelationWin : public CComObjectRootEx<CComMultiThreadModel>,
+                              public IAccessibleRelation {
+ public:
+  BEGIN_COM_MAP(AXPlatformRelationWin)
+  COM_INTERFACE_ENTRY(IAccessibleRelation)
+  END_COM_MAP()
+
+  AXPlatformRelationWin();
+  virtual ~AXPlatformRelationWin();
+
+  // This is the main utility function that enumerates all of the possible
+  // IAccessible2 relations between one node and any other node in the tree.
+  // Forward relations come from the int_attributes and intlist_attributes
+  // in node_data. Reverse relations come from querying |delegate| for the
+  // reverse relations given |node_data.id|.
+  //
+  // If you pass -1 for |desired_index| and "" for |desired_ia2_relation|,
+  // it will return a count of all relations.
+  //
+  // If you pass either an index in |desired_index| or a specific relation
+  // in |desired_ia2_relation|, the first matching relation will be returned in
+  // |out_ia2_relation| and |out_targets| (both of which must not be null),
+  // and it will return 1 on success, and 0 if none were found matching that
+  // criteria.
+  static int EnumerateRelationships(const AXNodeData& node_data,
+                                    AXPlatformNodeDelegate* delegate,
+                                    int desired_index,
+                                    const base::string16& desired_ia2_relation,
+                                    base::string16* out_ia2_relation,
+                                    std::set<int32_t>* out_targets);
+
+  void Initialize(const base::string16& type);
+  void Invalidate();
+  void AddTarget(AXPlatformNodeWin* target);
+
+  // IAccessibleRelation methods.
+  STDMETHODIMP get_relationType(BSTR* relation_type) override;
+  STDMETHODIMP get_nTargets(LONG* n_targets) override;
+  STDMETHODIMP get_target(LONG target_index, IUnknown** target) override;
+  STDMETHODIMP get_targets(LONG max_targets,
+                           IUnknown** targets,
+                           LONG* n_targets) override;
+  STDMETHODIMP get_localizedRelationType(BSTR* relation_type) override;
+
+ private:
+  base::string16 type_;
+  std::vector<Microsoft::WRL::ComPtr<AXPlatformNodeWin>> targets_;
+};
+
+}  // namespace ui
+
+#endif  // UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_WIN_H_
diff --git a/ui/accessibility/platform/ax_system_caret_win.cc b/ui/accessibility/platform/ax_system_caret_win.cc
index 14275376b..2b146bd 100644
--- a/ui/accessibility/platform/ax_system_caret_win.cc
+++ b/ui/accessibility/platform/ax_system_caret_win.cc
@@ -134,4 +134,14 @@
   return false;
 }
 
+std::set<int32_t> AXSystemCaretWin::GetReverseRelations(AXIntAttribute attr,
+                                                        int32_t dst_id) {
+  return std::set<int32_t>();
+}
+
+std::set<int32_t> AXSystemCaretWin::GetReverseRelations(AXIntListAttribute attr,
+                                                        int32_t dst_id) {
+  return std::set<int32_t>();
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_system_caret_win.h b/ui/accessibility/platform/ax_system_caret_win.h
index 4e2d09a..02c2eb2d 100644
--- a/ui/accessibility/platform/ax_system_caret_win.h
+++ b/ui/accessibility/platform/ax_system_caret_win.h
@@ -49,6 +49,10 @@
   bool AccessibilityPerformAction(const AXActionData& data) override;
   bool ShouldIgnoreHoveredStateForTesting() override;
   bool IsOffscreen() const override;
+  std::set<int32_t> GetReverseRelations(AXIntAttribute attr,
+                                        int32_t dst_id) override;
+  std::set<int32_t> GetReverseRelations(AXIntListAttribute attr,
+                                        int32_t dst_id) override;
 
   AXPlatformNodeWin* caret_;
   gfx::AcceleratedWidget event_target_;
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index 8a9d7e0a..762bf30f 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -230,6 +230,17 @@
   return false;
 }
 
+std::set<int32_t> TestAXNodeWrapper::GetReverseRelations(AXIntAttribute attr,
+                                                         int32_t dst_id) {
+  return tree_->GetReverseRelations(attr, dst_id);
+}
+
+std::set<int32_t> TestAXNodeWrapper::GetReverseRelations(
+    AXIntListAttribute attr,
+    int32_t dst_id) {
+  return tree_->GetReverseRelations(attr, dst_id);
+}
+
 TestAXNodeWrapper::TestAXNodeWrapper(AXTree* tree, AXNode* node)
     : tree_(tree),
       node_(node),
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h
index 0f50c843..5b4496d 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.h
+++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -46,6 +46,10 @@
   bool AccessibilityPerformAction(const AXActionData& data) override;
   bool ShouldIgnoreHoveredStateForTesting() override;
   bool IsOffscreen() const override;
+  std::set<int32_t> GetReverseRelations(AXIntAttribute attr,
+                                        int32_t dst_id) override;
+  std::set<int32_t> GetReverseRelations(AXIntListAttribute attr,
+                                        int32_t dst_id) override;
 
  private:
   TestAXNodeWrapper(AXTree* tree, AXNode* node);
diff --git a/ui/events/ozone/BUILD.gn b/ui/events/ozone/BUILD.gn
index 613d448c..b21f0ab5 100644
--- a/ui/events/ozone/BUILD.gn
+++ b/ui/events/ozone/BUILD.gn
@@ -118,7 +118,6 @@
       "evdev/touch_filter/single_position_touch_noise_filter.cc",
       "evdev/touch_filter/single_position_touch_noise_filter.h",
       "evdev/touch_filter/touch_filter.h",
-      "gamepad/gamepad_event.cc",
       "gamepad/gamepad_event.h",
       "gamepad/gamepad_mapping.cc",
       "gamepad/gamepad_mapping.h",
diff --git a/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
index 94401e9..d64b1466 100644
--- a/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
+++ b/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
@@ -8,7 +8,6 @@
 #include <fcntl.h>
 #include <linux/input.h>
 #include <unistd.h>
-
 #include <memory>
 #include <queue>
 #include <utility>
@@ -168,9 +167,9 @@
   }
 
   for (unsigned i = 0; i < observer.events.size(); ++i) {
-    EXPECT_EQ(observer.events[i].type(), expected_events[i].type);
-    EXPECT_EQ(observer.events[i].code(), expected_events[i].code);
-    double d = observer.events[i].value() - expected_events[i].value;
+    EXPECT_EQ(observer.events[i].type, expected_events[i].type);
+    EXPECT_EQ(observer.events[i].code, expected_events[i].code);
+    double d = observer.events[i].value - expected_events[i].value;
     d = d > 0 ? d : -d;
     EXPECT_LT(d, axis_delta);
   }
@@ -251,9 +250,9 @@
   }
 
   for (unsigned i = 0; i < observer.events.size(); ++i) {
-    EXPECT_EQ(observer.events[i].type(), expected_events[i].type);
-    EXPECT_EQ(observer.events[i].code(), expected_events[i].code);
-    double d = observer.events[i].value() - expected_events[i].value;
+    EXPECT_EQ(observer.events[i].type, expected_events[i].type);
+    EXPECT_EQ(observer.events[i].code, expected_events[i].code);
+    double d = observer.events[i].value - expected_events[i].value;
     d = d > 0 ? d : -d;
     EXPECT_LT(d, axis_delta);
   }
diff --git a/ui/events/ozone/gamepad/gamepad_event.cc b/ui/events/ozone/gamepad/gamepad_event.cc
deleted file mode 100644
index e71aaa2..0000000
--- a/ui/events/ozone/gamepad/gamepad_event.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/gamepad/gamepad_event.h"
-
-namespace ui {
-
-GamepadEvent::GamepadEvent(int device_id,
-                           GamepadEventType type,
-                           uint16_t code,
-                           double value,
-                           base::TimeTicks timestamp)
-    : device_id_(device_id),
-      type_(type),
-      code_(code),
-      value_(value),
-      timestamp_(timestamp) {}
-
-}  // namespace ui
diff --git a/ui/events/ozone/gamepad/gamepad_event.h b/ui/events/ozone/gamepad/gamepad_event.h
index 61e32bd..87d4408 100644
--- a/ui/events/ozone/gamepad/gamepad_event.h
+++ b/ui/events/ozone/gamepad/gamepad_event.h
@@ -10,34 +10,27 @@
 
 namespace ui {
 
-class GamepadEvent {
- public:
+struct GamepadEvent {
   GamepadEvent(int device_id,
                GamepadEventType type,
                uint16_t code,
                double value,
-               base::TimeTicks timestamp);
+               base::TimeTicks timestamp)
+      : device_id(device_id),
+        type(type),
+        code(code),
+        value(value),
+        timestamp(timestamp) {}
 
-  int device_id() const { return device_id_; }
+  int device_id;
 
-  GamepadEventType type() const { return type_; }
+  GamepadEventType type;
 
-  uint16_t code() const { return code_; }
+  uint16_t code;
 
-  double value() const { return value_; }
+  double value;
 
-  base::TimeTicks timestamp() const { return timestamp_; }
-
- private:
-  int device_id_;
-
-  GamepadEventType type_;
-
-  uint16_t code_;
-
-  double value_;
-
-  base::TimeTicks timestamp_;
+  base::TimeTicks timestamp;
 };
 
 }  // namespace ui
diff --git a/ui/views/accessibility/native_view_accessibility_auralinux.cc b/ui/views/accessibility/native_view_accessibility_auralinux.cc
index ac7452f..b9af136 100644
--- a/ui/views/accessibility/native_view_accessibility_auralinux.cc
+++ b/ui/views/accessibility/native_view_accessibility_auralinux.cc
@@ -125,6 +125,16 @@
 
   bool ShouldIgnoreHoveredStateForTesting() override { return false; }
 
+  std::set<int32_t> GetReverseRelations(ui::AXIntAttribute attr,
+                                        int32_t dst_id) override {
+    return std::set<int32_t>();
+  }
+
+  std::set<int32_t> GetReverseRelations(ui::AXIntListAttribute attr,
+                                        int32_t dst_id) override {
+    return std::set<int32_t>();
+  }
+
  private:
   friend struct base::DefaultSingletonTraits<AuraLinuxApplication>;
 
diff --git a/ui/views/accessibility/native_view_accessibility_base.cc b/ui/views/accessibility/native_view_accessibility_base.cc
index 0f19b6b2..f06a463a 100644
--- a/ui/views/accessibility/native_view_accessibility_base.cc
+++ b/ui/views/accessibility/native_view_accessibility_base.cc
@@ -238,6 +238,18 @@
   return false;
 }
 
+std::set<int32_t> NativeViewAccessibilityBase::GetReverseRelations(
+    ui::AXIntAttribute attr,
+    int32_t dst_id) {
+  return std::set<int32_t>();
+}
+
+std::set<int32_t> NativeViewAccessibilityBase::GetReverseRelations(
+    ui::AXIntListAttribute attr,
+    int32_t dst_id) {
+  return std::set<int32_t>();
+}
+
 gfx::RectF NativeViewAccessibilityBase::GetBoundsInScreen() const {
   return gfx::RectF(view()->GetBoundsInScreen());
 }
diff --git a/ui/views/accessibility/native_view_accessibility_base.h b/ui/views/accessibility/native_view_accessibility_base.h
index a471a78cc..d8c7400 100644
--- a/ui/views/accessibility/native_view_accessibility_base.h
+++ b/ui/views/accessibility/native_view_accessibility_base.h
@@ -53,6 +53,10 @@
   bool AccessibilityPerformAction(const ui::AXActionData& data) override;
   bool ShouldIgnoreHoveredStateForTesting() override;
   bool IsOffscreen() const override;
+  std::set<int32_t> GetReverseRelations(ui::AXIntAttribute attr,
+                                        int32_t dst_id) override;
+  std::set<int32_t> GetReverseRelations(ui::AXIntListAttribute attr,
+                                        int32_t dst_id) override;
 
  protected:
   explicit NativeViewAccessibilityBase(View* view);